@@ -388,9 +388,26 @@ class ScalarExprEmitter : public StmtVisitor<ScalarExprEmitter, mlir::Value> {
388
388
// NOTE(CIR): clang calls CreateAdd but folds this to a unary op
389
389
value = emitUnaryOp (e, kind, input, /* nsw=*/ false );
390
390
}
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
+ }
394
411
} else if (type->isVectorType ()) {
395
412
cgf.cgm .errorNYI (e->getSourceRange (), " Unary inc/dec vector" );
396
413
return {};
@@ -1152,8 +1169,78 @@ getUnwidenedIntegerType(const ASTContext &astContext, const Expr *e) {
1152
1169
static mlir::Value emitPointerArithmetic (CIRGenFunction &cgf,
1153
1170
const BinOpInfo &op,
1154
1171
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);
1157
1244
}
1158
1245
1159
1246
mlir::Value ScalarExprEmitter::emitMul (const BinOpInfo &ops) {
0 commit comments