@@ -388,9 +388,26 @@ class ScalarExprEmitter : public StmtVisitor<ScalarExprEmitter, mlir::Value> {
388388 // NOTE(CIR): clang calls CreateAdd but folds this to a unary op
389389 value = emitUnaryOp (e, kind, input, /* nsw=*/ false );
390390 }
391- } else if (isa<PointerType>(type)) {
392- cgf.cgm .errorNYI (e->getSourceRange (), " Unary inc/dec pointer" );
393- return {};
391+ } else if (const PointerType *ptr = type->getAs <PointerType>()) {
392+ QualType type = ptr->getPointeeType ();
393+ if (cgf.getContext ().getAsVariableArrayType (type)) {
394+ // VLA types don't have constant size.
395+ cgf.cgm .errorNYI (e->getSourceRange (), " Pointer arithmetic on VLA" );
396+ return {};
397+ } else if (type->isFunctionType ()) {
398+ // Arithmetic on function pointers (!) is just +-1.
399+ cgf.cgm .errorNYI (e->getSourceRange (),
400+ " Pointer arithmetic on function pointer" );
401+ return {};
402+ } else {
403+ // For everything else, we can just do a simple increment.
404+ mlir::Location loc = cgf.getLoc (e->getSourceRange ());
405+ CIRGenBuilderTy &builder = cgf.getBuilder ();
406+ int amount = (isInc ? 1 : -1 );
407+ mlir::Value amt = builder.getSInt32 (amount, loc);
408+ assert (!cir::MissingFeatures::sanitizers ());
409+ value = builder.createPtrStride (loc, value, amt);
410+ }
394411 } else if (type->isVectorType ()) {
395412 cgf.cgm .errorNYI (e->getSourceRange (), " Unary inc/dec vector" );
396413 return {};
@@ -1152,8 +1169,78 @@ getUnwidenedIntegerType(const ASTContext &astContext, const Expr *e) {
11521169static mlir::Value emitPointerArithmetic (CIRGenFunction &cgf,
11531170 const BinOpInfo &op,
11541171 bool isSubtraction) {
1155- cgf.cgm .errorNYI (op.loc , " pointer arithmetic" );
1156- return {};
1172+ // Must have binary (not unary) expr here. Unary pointer
1173+ // increment/decrement doesn't use this path.
1174+ const BinaryOperator *expr = cast<BinaryOperator>(op.e );
1175+
1176+ mlir::Value pointer = op.lhs ;
1177+ Expr *pointerOperand = expr->getLHS ();
1178+ mlir::Value index = op.rhs ;
1179+ Expr *indexOperand = expr->getRHS ();
1180+
1181+ // In the case of subtraction, the FE has ensured that the LHS is always the
1182+ // pointer. However, addition can have the pointer on either side. We will
1183+ // always have a pointer operand and an integer operand, so if the LHS wasn't
1184+ // a pointer, we need to swap our values.
1185+ if (!isSubtraction && !mlir::isa<cir::PointerType>(pointer.getType ())) {
1186+ std::swap (pointer, index);
1187+ std::swap (pointerOperand, indexOperand);
1188+ }
1189+ assert (mlir::isa<cir::PointerType>(pointer.getType ()) &&
1190+ " Need a pointer operand" );
1191+ assert (mlir::isa<cir::IntType>(index.getType ()) && " Need an integer operand" );
1192+
1193+ // Some versions of glibc and gcc use idioms (particularly in their malloc
1194+ // routines) that add a pointer-sized integer (known to be a pointer value)
1195+ // to a null pointer in order to cast the value back to an integer or as
1196+ // part of a pointer alignment algorithm. This is undefined behavior, but
1197+ // we'd like to be able to compile programs that use it.
1198+ //
1199+ // Normally, we'd generate a GEP with a null-pointer base here in response
1200+ // to that code, but it's also UB to dereference a pointer created that
1201+ // way. Instead (as an acknowledged hack to tolerate the idiom) we will
1202+ // generate a direct cast of the integer value to a pointer.
1203+ //
1204+ // The idiom (p = nullptr + N) is not met if any of the following are true:
1205+ //
1206+ // The operation is subtraction.
1207+ // The index is not pointer-sized.
1208+ // The pointer type is not byte-sized.
1209+ //
1210+ if (BinaryOperator::isNullPointerArithmeticExtension (
1211+ cgf.getContext (), op.opcode , expr->getLHS (), expr->getRHS ()))
1212+ return cgf.getBuilder ().createIntToPtr (index, pointer.getType ());
1213+
1214+ // Differently from LLVM codegen, ABI bits for index sizes is handled during
1215+ // LLVM lowering.
1216+
1217+ // If this is subtraction, negate the index.
1218+ if (isSubtraction)
1219+ index = cgf.getBuilder ().createNeg (index);
1220+
1221+ assert (!cir::MissingFeatures::sanitizers ());
1222+
1223+ const PointerType *pointerType =
1224+ pointerOperand->getType ()->getAs <PointerType>();
1225+ if (!pointerType) {
1226+ cgf.cgm .errorNYI (" Objective-C:pointer arithmetic with non-pointer type" );
1227+ return nullptr ;
1228+ }
1229+
1230+ QualType elementType = pointerType->getPointeeType ();
1231+ if (cgf.getContext ().getAsVariableArrayType (elementType)) {
1232+ cgf.cgm .errorNYI (" variable array type" );
1233+ return nullptr ;
1234+ }
1235+
1236+ if (elementType->isVoidType () || elementType->isFunctionType ()) {
1237+ cgf.cgm .errorNYI (" void* or function pointer arithmetic" );
1238+ return nullptr ;
1239+ }
1240+
1241+ assert (!cir::MissingFeatures::sanitizers ());
1242+ return cgf.getBuilder ().create <cir::PtrStrideOp>(
1243+ cgf.getLoc (op.e ->getExprLoc ()), pointer.getType (), pointer, index);
11571244}
11581245
11591246mlir::Value ScalarExprEmitter::emitMul (const BinOpInfo &ops) {
0 commit comments