Skip to content

Commit b65fab2

Browse files
committed
[Clang][CodeGen] Preserve alignment information for pointer arithmetics
1 parent e29fec0 commit b65fab2

File tree

3 files changed

+72
-23
lines changed

3 files changed

+72
-23
lines changed

clang/lib/CodeGen/CGExpr.cpp

Lines changed: 64 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1325,6 +1325,57 @@ void CodeGenModule::EmitExplicitCastExprType(const ExplicitCastExpr *E,
13251325
// LValue Expression Emission
13261326
//===----------------------------------------------------------------------===//
13271327

1328+
static CharUnits getArrayElementAlign(CharUnits arrayAlign, llvm::Value *idx,
1329+
CharUnits eltSize) {
1330+
// If we have a constant index, we can use the exact offset of the
1331+
// element we're accessing.
1332+
if (auto *constantIdx = dyn_cast<llvm::ConstantInt>(idx)) {
1333+
CharUnits offset = constantIdx->getZExtValue() * eltSize;
1334+
return arrayAlign.alignmentAtOffset(offset);
1335+
}
1336+
1337+
// Otherwise, use the worst-case alignment for any element.
1338+
return arrayAlign.alignmentOfArrayElement(eltSize);
1339+
}
1340+
1341+
/// Emit pointer + index arithmetic.
1342+
static Address emitPointerArithmetic(CodeGenFunction &CGF,
1343+
const BinaryOperator *BO,
1344+
LValueBaseInfo *BaseInfo,
1345+
TBAAAccessInfo *TBAAInfo,
1346+
KnownNonNull_t IsKnownNonNull) {
1347+
assert(BO->isAdditiveOp() && "Expect an addition or subtraction.");
1348+
Expr *pointerOperand = BO->getLHS();
1349+
Expr *indexOperand = BO->getRHS();
1350+
bool isSubtraction = BO->getOpcode() == BO_Sub;
1351+
1352+
Address BaseAddr = Address::invalid();
1353+
llvm::Value *index = nullptr;
1354+
// In a subtraction, the LHS is always the pointer.
1355+
// Note: do not change the evaluation order.
1356+
if (!isSubtraction && !pointerOperand->getType()->isAnyPointerType()) {
1357+
std::swap(pointerOperand, indexOperand);
1358+
index = CGF.EmitScalarExpr(indexOperand);
1359+
BaseAddr = CGF.EmitPointerWithAlignment(pointerOperand, BaseInfo, TBAAInfo,
1360+
NotKnownNonNull);
1361+
} else {
1362+
BaseAddr = CGF.EmitPointerWithAlignment(pointerOperand, BaseInfo, TBAAInfo,
1363+
NotKnownNonNull);
1364+
index = CGF.EmitScalarExpr(indexOperand);
1365+
}
1366+
1367+
llvm::Value *pointer = BaseAddr.getBasePointer();
1368+
llvm::Value *Res = CGF.EmitPointerArithmetic(
1369+
BO, pointerOperand, pointer, indexOperand, index, isSubtraction);
1370+
QualType PointeeTy = BO->getType()->getPointeeType();
1371+
CharUnits Align =
1372+
getArrayElementAlign(BaseAddr.getAlignment(), index,
1373+
CGF.getContext().getTypeSizeInChars(PointeeTy));
1374+
return Address(Res, CGF.ConvertTypeForMem(PointeeTy), Align,
1375+
CGF.CGM.getPointerAuthInfoForPointeeType(PointeeTy),
1376+
/*Offset=*/nullptr, IsKnownNonNull);
1377+
}
1378+
13281379
static Address EmitPointerWithAlignment(const Expr *E, LValueBaseInfo *BaseInfo,
13291380
TBAAAccessInfo *TBAAInfo,
13301381
KnownNonNull_t IsKnownNonNull,
@@ -1387,6 +1438,13 @@ static Address EmitPointerWithAlignment(const Expr *E, LValueBaseInfo *BaseInfo,
13871438
if (CE->getCastKind() == CK_AddressSpaceConversion)
13881439
Addr = CGF.Builder.CreateAddrSpaceCast(
13891440
Addr, CGF.ConvertType(E->getType()), ElemTy);
1441+
// Note: Workaround for PR114062. See also the special handling in
1442+
// ScalarExprEmitter::VisitCastExpr.
1443+
if (auto *A = dyn_cast<llvm::Argument>(Addr.getBasePointer());
1444+
A && A->hasStructRetAttr())
1445+
Addr = CGF.Builder.CreateAddrSpaceCast(
1446+
Addr, CGF.ConvertType(E->getType()), ElemTy);
1447+
13901448
return CGF.authPointerToPointerCast(Addr, CE->getSubExpr()->getType(),
13911449
CE->getType());
13921450
}
@@ -1447,6 +1505,12 @@ static Address EmitPointerWithAlignment(const Expr *E, LValueBaseInfo *BaseInfo,
14471505
}
14481506
}
14491507

1508+
// Pointer arithmetic: pointer +/- index.
1509+
if (auto *BO = dyn_cast<BinaryOperator>(E)) {
1510+
if (BO->isAdditiveOp())
1511+
return emitPointerArithmetic(CGF, BO, BaseInfo, TBAAInfo, IsKnownNonNull);
1512+
}
1513+
14501514
// TODO: conditional operators, comma.
14511515

14521516
// Otherwise, use the alignment of the type.
@@ -4236,21 +4300,6 @@ static Address emitArraySubscriptGEP(CodeGenFunction &CGF, Address addr,
42364300
}
42374301
}
42384302

4239-
static CharUnits getArrayElementAlign(CharUnits arrayAlign,
4240-
llvm::Value *idx,
4241-
CharUnits eltSize) {
4242-
// If we have a constant index, we can use the exact offset of the
4243-
// element we're accessing.
4244-
if (auto constantIdx = dyn_cast<llvm::ConstantInt>(idx)) {
4245-
CharUnits offset = constantIdx->getZExtValue() * eltSize;
4246-
return arrayAlign.alignmentAtOffset(offset);
4247-
4248-
// Otherwise, use the worst-case alignment for any element.
4249-
} else {
4250-
return arrayAlign.alignmentOfArrayElement(eltSize);
4251-
}
4252-
}
4253-
42544303
static QualType getFixedSizeElementType(const ASTContext &ctx,
42554304
const VariableArrayType *vla) {
42564305
QualType eltType;

clang/test/CodeGen/packed-arrays.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ int align3_x0 = __alignof(((struct s3*) 0)->x[0]);
5555
// CHECK: load i32, ptr %{{.*}}, align 1
5656
// CHECK: }
5757
// CHECK-LABEL: define{{.*}} i32 @f0_b
58-
// CHECK: load i32, ptr %{{.*}}, align 4
58+
// CHECK: load i32, ptr %{{.*}}, align 1
5959
// CHECK: }
6060
int f0_a(struct s0 *a) {
6161
return a->x[1];
@@ -100,7 +100,7 @@ int f1_d(struct s1 *a) {
100100
// CHECK: load i32, ptr %{{.*}}, align 1
101101
// CHECK: }
102102
// CHECK-LABEL: define{{.*}} i32 @f2_b
103-
// CHECK: load i32, ptr %{{.*}}, align 4
103+
// CHECK: load i32, ptr %{{.*}}, align 1
104104
// CHECK: }
105105
// CHECK-LABEL: define{{.*}} i32 @f2_c
106106
// CHECK: load i32, ptr %{{.*}}, align 1
@@ -125,7 +125,7 @@ int f2_d(struct s2 *a) {
125125
// CHECK: load i32, ptr %{{.*}}, align 1
126126
// CHECK: }
127127
// CHECK-LABEL: define{{.*}} i32 @f3_b
128-
// CHECK: load i32, ptr %{{.*}}, align 4
128+
// CHECK: load i32, ptr %{{.*}}, align 1
129129
// CHECK: }
130130
// CHECK-LABEL: define{{.*}} i32 @f3_c
131131
// CHECK: load i32, ptr %{{.*}}, align 1

clang/test/CodeGen/pointer-arithmetic-align.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ struct a {
1313
// CHECK-SAME: ptr noundef writeonly captures(none) initializes((8, 9)) [[CTX:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] {
1414
// CHECK-NEXT: [[ENTRY:.*:]]
1515
// CHECK-NEXT: [[BLOCK:%.*]] = getelementptr inbounds nuw i8, ptr [[CTX]], i64 8
16-
// CHECK-NEXT: store i8 0, ptr [[BLOCK]], align 1, !tbaa [[TBAA2:![0-9]+]]
16+
// CHECK-NEXT: store i8 0, ptr [[BLOCK]], align 8, !tbaa [[TBAA2:![0-9]+]]
1717
// CHECK-NEXT: ret void
1818
//
1919
void ptradd_0(struct a *ctx) {
@@ -24,7 +24,7 @@ void ptradd_0(struct a *ctx) {
2424
// CHECK-SAME: ptr noundef writeonly captures(none) initializes((12, 13)) [[CTX:%.*]]) local_unnamed_addr #[[ATTR0]] {
2525
// CHECK-NEXT: [[ENTRY:.*:]]
2626
// CHECK-NEXT: [[ADD_PTR:%.*]] = getelementptr inbounds nuw i8, ptr [[CTX]], i64 12
27-
// CHECK-NEXT: store i8 0, ptr [[ADD_PTR]], align 1, !tbaa [[TBAA2]]
27+
// CHECK-NEXT: store i8 0, ptr [[ADD_PTR]], align 4, !tbaa [[TBAA2]]
2828
// CHECK-NEXT: ret void
2929
//
3030
void ptradd_4(struct a *ctx) {
@@ -35,7 +35,7 @@ void ptradd_4(struct a *ctx) {
3535
// CHECK-SAME: ptr noundef writeonly captures(none) initializes((16, 17)) [[CTX:%.*]]) local_unnamed_addr #[[ATTR0]] {
3636
// CHECK-NEXT: [[ENTRY:.*:]]
3737
// CHECK-NEXT: [[ADD_PTR:%.*]] = getelementptr inbounds nuw i8, ptr [[CTX]], i64 16
38-
// CHECK-NEXT: store i8 0, ptr [[ADD_PTR]], align 1, !tbaa [[TBAA2]]
38+
// CHECK-NEXT: store i8 0, ptr [[ADD_PTR]], align 8, !tbaa [[TBAA2]]
3939
// CHECK-NEXT: ret void
4040
//
4141
void ptradd_8(struct a *ctx) {
@@ -46,7 +46,7 @@ void ptradd_8(struct a *ctx) {
4646
// CHECK-SAME: ptr noundef writeonly captures(none) initializes((16, 17)) [[CTX:%.*]]) local_unnamed_addr #[[ATTR0]] {
4747
// CHECK-NEXT: [[ENTRY:.*:]]
4848
// CHECK-NEXT: [[ADD_PTR:%.*]] = getelementptr inbounds nuw i8, ptr [[CTX]], i64 16
49-
// CHECK-NEXT: store i8 0, ptr [[ADD_PTR]], align 1, !tbaa [[TBAA2]]
49+
// CHECK-NEXT: store i8 0, ptr [[ADD_PTR]], align 8, !tbaa [[TBAA2]]
5050
// CHECK-NEXT: ret void
5151
//
5252
void ptradd_8_commuted(struct a *ctx) {
@@ -57,7 +57,7 @@ void ptradd_8_commuted(struct a *ctx) {
5757
// CHECK-SAME: ptr noundef writeonly captures(none) initializes((8, 9)) [[CTX:%.*]]) local_unnamed_addr #[[ATTR0]] {
5858
// CHECK-NEXT: [[ENTRY:.*:]]
5959
// CHECK-NEXT: [[ADD_PTR:%.*]] = getelementptr inbounds nuw i8, ptr [[CTX]], i64 8
60-
// CHECK-NEXT: store i8 0, ptr [[ADD_PTR]], align 1, !tbaa [[TBAA2]]
60+
// CHECK-NEXT: store i8 0, ptr [[ADD_PTR]], align 4, !tbaa [[TBAA2]]
6161
// CHECK-NEXT: ret void
6262
//
6363
void ptrsub_4(struct a *ctx) {

0 commit comments

Comments
 (0)