Skip to content

Commit e58f835

Browse files
committed
[Clang][CodeGen] Preserve alignment information for pointer arithmetics
1 parent 16f7036 commit e58f835

File tree

4 files changed

+73
-24
lines changed

4 files changed

+73
-24
lines changed

clang/lib/CodeGen/CGExpr.cpp

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

1317+
static CharUnits getArrayElementAlign(CharUnits arrayAlign, llvm::Value *idx,
1318+
CharUnits eltSize) {
1319+
// If we have a constant index, we can use the exact offset of the
1320+
// element we're accessing.
1321+
if (auto *constantIdx = dyn_cast<llvm::ConstantInt>(idx)) {
1322+
CharUnits offset = constantIdx->getZExtValue() * eltSize;
1323+
return arrayAlign.alignmentAtOffset(offset);
1324+
}
1325+
1326+
// Otherwise, use the worst-case alignment for any element.
1327+
return arrayAlign.alignmentOfArrayElement(eltSize);
1328+
}
1329+
1330+
/// Emit pointer + index arithmetic.
1331+
static Address emitPointerArithmetic(CodeGenFunction &CGF,
1332+
const BinaryOperator *BO,
1333+
LValueBaseInfo *BaseInfo,
1334+
TBAAAccessInfo *TBAAInfo,
1335+
KnownNonNull_t IsKnownNonNull) {
1336+
assert(BO->isAdditiveOp() && "Expect an addition or subtraction.");
1337+
Expr *pointerOperand = BO->getLHS();
1338+
Expr *indexOperand = BO->getRHS();
1339+
bool isSubtraction = BO->getOpcode() == BO_Sub;
1340+
1341+
Address BaseAddr = Address::invalid();
1342+
llvm::Value *index = nullptr;
1343+
// In a subtraction, the LHS is always the pointer.
1344+
// Note: do not change the evaluation order.
1345+
if (!isSubtraction && !pointerOperand->getType()->isAnyPointerType()) {
1346+
std::swap(pointerOperand, indexOperand);
1347+
index = CGF.EmitScalarExpr(indexOperand);
1348+
BaseAddr = CGF.EmitPointerWithAlignment(pointerOperand, BaseInfo, TBAAInfo,
1349+
NotKnownNonNull);
1350+
} else {
1351+
BaseAddr = CGF.EmitPointerWithAlignment(pointerOperand, BaseInfo, TBAAInfo,
1352+
NotKnownNonNull);
1353+
index = CGF.EmitScalarExpr(indexOperand);
1354+
}
1355+
1356+
llvm::Value *pointer = BaseAddr.getBasePointer();
1357+
llvm::Value *Res = CGF.EmitPointerArithmetic(
1358+
BO, pointerOperand, pointer, indexOperand, index, isSubtraction);
1359+
QualType PointeeTy = BO->getType()->getPointeeType();
1360+
CharUnits Align =
1361+
getArrayElementAlign(BaseAddr.getAlignment(), index,
1362+
CGF.getContext().getTypeSizeInChars(PointeeTy));
1363+
return Address(Res, CGF.ConvertTypeForMem(PointeeTy), Align,
1364+
CGF.CGM.getPointerAuthInfoForPointeeType(PointeeTy),
1365+
/*Offset=*/nullptr, IsKnownNonNull);
1366+
}
1367+
13171368
static Address EmitPointerWithAlignment(const Expr *E, LValueBaseInfo *BaseInfo,
13181369
TBAAAccessInfo *TBAAInfo,
13191370
KnownNonNull_t IsKnownNonNull,
@@ -1376,6 +1427,13 @@ static Address EmitPointerWithAlignment(const Expr *E, LValueBaseInfo *BaseInfo,
13761427
if (CE->getCastKind() == CK_AddressSpaceConversion)
13771428
Addr = CGF.Builder.CreateAddrSpaceCast(
13781429
Addr, CGF.ConvertType(E->getType()), ElemTy);
1430+
// Note: Workaround for PR114062. See also the special handling in
1431+
// ScalarExprEmitter::VisitCastExpr.
1432+
if (auto *A = dyn_cast<llvm::Argument>(Addr.getBasePointer());
1433+
A && A->hasStructRetAttr())
1434+
Addr = CGF.Builder.CreateAddrSpaceCast(
1435+
Addr, CGF.ConvertType(E->getType()), ElemTy);
1436+
13791437
return CGF.authPointerToPointerCast(Addr, CE->getSubExpr()->getType(),
13801438
CE->getType());
13811439
}
@@ -1436,6 +1494,12 @@ static Address EmitPointerWithAlignment(const Expr *E, LValueBaseInfo *BaseInfo,
14361494
}
14371495
}
14381496

1497+
// Pointer arithmetic: pointer +/- index.
1498+
if (auto *BO = dyn_cast<BinaryOperator>(E)) {
1499+
if (BO->isAdditiveOp())
1500+
return emitPointerArithmetic(CGF, BO, BaseInfo, TBAAInfo, IsKnownNonNull);
1501+
}
1502+
14391503
// TODO: conditional operators, comma.
14401504

14411505
// Otherwise, use the alignment of the type.
@@ -4222,21 +4286,6 @@ static Address emitArraySubscriptGEP(CodeGenFunction &CGF, Address addr,
42224286
}
42234287
}
42244288

4225-
static CharUnits getArrayElementAlign(CharUnits arrayAlign,
4226-
llvm::Value *idx,
4227-
CharUnits eltSize) {
4228-
// If we have a constant index, we can use the exact offset of the
4229-
// element we're accessing.
4230-
if (auto constantIdx = dyn_cast<llvm::ConstantInt>(idx)) {
4231-
CharUnits offset = constantIdx->getZExtValue() * eltSize;
4232-
return arrayAlign.alignmentAtOffset(offset);
4233-
4234-
// Otherwise, use the worst-case alignment for any element.
4235-
} else {
4236-
return arrayAlign.alignmentOfArrayElement(eltSize);
4237-
}
4238-
}
4239-
42404289
static QualType getFixedSizeElementType(const ASTContext &ctx,
42414290
const VariableArrayType *vla) {
42424291
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) {

clang/test/CodeGenCXX/sret_cast_with_nonzero_alloca_as.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ struct X { int z[17]; };
1919
// CHECK-NEXT: [[TMP1:%.*]] = load i8, ptr [[Y_ADDR_ASCAST]], align 1
2020
// CHECK-NEXT: [[AGG_RESULT_ASCAST1:%.*]] = addrspacecast ptr addrspace(5) [[AGG_RESULT]] to ptr
2121
// CHECK-NEXT: [[ADD_PTR2:%.*]] = getelementptr inbounds i8, ptr [[AGG_RESULT_ASCAST1]], i64 2
22-
// CHECK-NEXT: store i8 [[TMP1]], ptr [[ADD_PTR2]], align 1
22+
// CHECK-NEXT: store i8 [[TMP1]], ptr [[ADD_PTR2]], align 2
2323
// CHECK-NEXT: ret void
2424
//
2525
X foo(char x, char y) {

0 commit comments

Comments
 (0)