Skip to content

Commit be202cd

Browse files
committed
[Clang][CodeGen] Preserve alignment information for pointer arithmetic.
1 parent 288bf3e commit be202cd

File tree

6 files changed

+153
-92
lines changed

6 files changed

+153
-92
lines changed

clang/lib/CodeGen/CGExpr.cpp

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

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

1502+
// Pointer arithmetic: pointer +/- index.
1503+
if (auto *BO = dyn_cast<BinaryOperator>(E)) {
1504+
if (BO->isAdditiveOp())
1505+
return emitPointerArithmetic(CGF, BO, BaseInfo, TBAAInfo, IsKnownNonNull);
1506+
}
1507+
14441508
// TODO: conditional operators, comma.
14451509

14461510
// Otherwise, use the alignment of the type.
@@ -4210,21 +4274,6 @@ static Address emitArraySubscriptGEP(CodeGenFunction &CGF, Address addr,
42104274
}
42114275
}
42124276

4213-
static CharUnits getArrayElementAlign(CharUnits arrayAlign,
4214-
llvm::Value *idx,
4215-
CharUnits eltSize) {
4216-
// If we have a constant index, we can use the exact offset of the
4217-
// element we're accessing.
4218-
if (auto constantIdx = dyn_cast<llvm::ConstantInt>(idx)) {
4219-
CharUnits offset = constantIdx->getZExtValue() * eltSize;
4220-
return arrayAlign.alignmentAtOffset(offset);
4221-
4222-
// Otherwise, use the worst-case alignment for any element.
4223-
} else {
4224-
return arrayAlign.alignmentOfArrayElement(eltSize);
4225-
}
4226-
}
4227-
42284277
static QualType getFixedSizeElementType(const ASTContext &ctx,
42294278
const VariableArrayType *vla) {
42304279
QualType eltType;

clang/lib/CodeGen/CGExprScalar.cpp

Lines changed: 74 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -4184,29 +4184,14 @@ Value *ScalarExprEmitter::EmitOverflowCheckedBinOp(const BinOpInfo &Ops) {
41844184
}
41854185

41864186
/// Emit pointer + index arithmetic.
4187-
static Value *emitPointerArithmetic(CodeGenFunction &CGF,
4188-
const BinOpInfo &op,
4189-
bool isSubtraction) {
4190-
// Must have binary (not unary) expr here. Unary pointer
4191-
// increment/decrement doesn't use this path.
4192-
const BinaryOperator *expr = cast<BinaryOperator>(op.E);
4193-
4194-
Value *pointer = op.LHS;
4195-
Expr *pointerOperand = expr->getLHS();
4196-
Value *index = op.RHS;
4197-
Expr *indexOperand = expr->getRHS();
4198-
4199-
// In a subtraction, the LHS is always the pointer.
4200-
if (!isSubtraction && !pointer->getType()->isPointerTy()) {
4201-
std::swap(pointer, index);
4202-
std::swap(pointerOperand, indexOperand);
4203-
}
4204-
4187+
llvm::Value *CodeGenFunction::EmitPointerArithmetic(
4188+
const BinaryOperator *BO, Expr *pointerOperand, llvm::Value *pointer,
4189+
Expr *indexOperand, llvm::Value *index, bool isSubtraction) {
42054190
bool isSigned = indexOperand->getType()->isSignedIntegerOrEnumerationType();
42064191

42074192
unsigned width = cast<llvm::IntegerType>(index->getType())->getBitWidth();
4208-
auto &DL = CGF.CGM.getDataLayout();
4209-
auto PtrTy = cast<llvm::PointerType>(pointer->getType());
4193+
auto &DL = CGM.getDataLayout();
4194+
auto *PtrTy = cast<llvm::PointerType>(pointer->getType());
42104195

42114196
// Some versions of glibc and gcc use idioms (particularly in their malloc
42124197
// routines) that add a pointer-sized integer (known to be a pointer value)
@@ -4227,79 +4212,77 @@ static Value *emitPointerArithmetic(CodeGenFunction &CGF,
42274212
//
42284213
// Note that we do not suppress the pointer overflow check in this case.
42294214
if (BinaryOperator::isNullPointerArithmeticExtension(
4230-
CGF.getContext(), op.Opcode, expr->getLHS(), expr->getRHS())) {
4231-
Value *Ptr = CGF.Builder.CreateIntToPtr(index, pointer->getType());
4232-
if (CGF.getLangOpts().PointerOverflowDefined ||
4233-
!CGF.SanOpts.has(SanitizerKind::PointerOverflow) ||
4234-
NullPointerIsDefined(CGF.Builder.GetInsertBlock()->getParent(),
4215+
getContext(), BO->getOpcode(), BO->getLHS(), BO->getRHS())) {
4216+
llvm::Value *Ptr = Builder.CreateIntToPtr(index, pointer->getType());
4217+
if (getLangOpts().PointerOverflowDefined ||
4218+
!SanOpts.has(SanitizerKind::PointerOverflow) ||
4219+
NullPointerIsDefined(Builder.GetInsertBlock()->getParent(),
42354220
PtrTy->getPointerAddressSpace()))
42364221
return Ptr;
42374222
// The inbounds GEP of null is valid iff the index is zero.
42384223
auto CheckOrdinal = SanitizerKind::SO_PointerOverflow;
42394224
auto CheckHandler = SanitizerHandler::PointerOverflow;
4240-
SanitizerDebugLocation SanScope(&CGF, {CheckOrdinal}, CheckHandler);
4241-
Value *IsZeroIndex = CGF.Builder.CreateIsNull(index);
4242-
llvm::Constant *StaticArgs[] = {
4243-
CGF.EmitCheckSourceLocation(op.E->getExprLoc())};
4225+
SanitizerDebugLocation SanScope(this, {CheckOrdinal}, CheckHandler);
4226+
llvm::Value *IsZeroIndex = Builder.CreateIsNull(index);
4227+
llvm::Constant *StaticArgs[] = {EmitCheckSourceLocation(BO->getExprLoc())};
42444228
llvm::Type *IntPtrTy = DL.getIntPtrType(PtrTy);
4245-
Value *IntPtr = llvm::Constant::getNullValue(IntPtrTy);
4246-
Value *ComputedGEP = CGF.Builder.CreateZExtOrTrunc(index, IntPtrTy);
4247-
Value *DynamicArgs[] = {IntPtr, ComputedGEP};
4248-
CGF.EmitCheck({{IsZeroIndex, CheckOrdinal}}, CheckHandler, StaticArgs,
4249-
DynamicArgs);
4229+
llvm::Value *IntPtr = llvm::Constant::getNullValue(IntPtrTy);
4230+
llvm::Value *ComputedGEP = Builder.CreateZExtOrTrunc(index, IntPtrTy);
4231+
llvm::Value *DynamicArgs[] = {IntPtr, ComputedGEP};
4232+
EmitCheck({{IsZeroIndex, CheckOrdinal}}, CheckHandler, StaticArgs,
4233+
DynamicArgs);
42504234
return Ptr;
42514235
}
42524236

42534237
if (width != DL.getIndexTypeSizeInBits(PtrTy)) {
42544238
// Zero-extend or sign-extend the pointer value according to
42554239
// whether the index is signed or not.
4256-
index = CGF.Builder.CreateIntCast(index, DL.getIndexType(PtrTy), isSigned,
4257-
"idx.ext");
4240+
index = Builder.CreateIntCast(index, DL.getIndexType(PtrTy), isSigned,
4241+
"idx.ext");
42584242
}
42594243

42604244
// If this is subtraction, negate the index.
42614245
if (isSubtraction)
4262-
index = CGF.Builder.CreateNeg(index, "idx.neg");
4246+
index = Builder.CreateNeg(index, "idx.neg");
42634247

4264-
if (CGF.SanOpts.has(SanitizerKind::ArrayBounds))
4265-
CGF.EmitBoundsCheck(op.E, pointerOperand, index, indexOperand->getType(),
4266-
/*Accessed*/ false);
4248+
if (SanOpts.has(SanitizerKind::ArrayBounds))
4249+
EmitBoundsCheck(BO, pointerOperand, index, indexOperand->getType(),
4250+
/*Accessed*/ false);
42674251

4268-
const PointerType *pointerType
4269-
= pointerOperand->getType()->getAs<PointerType>();
4252+
const PointerType *pointerType =
4253+
pointerOperand->getType()->getAs<PointerType>();
42704254
if (!pointerType) {
42714255
QualType objectType = pointerOperand->getType()
4272-
->castAs<ObjCObjectPointerType>()
4273-
->getPointeeType();
4274-
llvm::Value *objectSize
4275-
= CGF.CGM.getSize(CGF.getContext().getTypeSizeInChars(objectType));
4256+
->castAs<ObjCObjectPointerType>()
4257+
->getPointeeType();
4258+
llvm::Value *objectSize =
4259+
CGM.getSize(getContext().getTypeSizeInChars(objectType));
42764260

4277-
index = CGF.Builder.CreateMul(index, objectSize);
4261+
index = Builder.CreateMul(index, objectSize);
42784262

4279-
Value *result =
4280-
CGF.Builder.CreateGEP(CGF.Int8Ty, pointer, index, "add.ptr");
4281-
return CGF.Builder.CreateBitCast(result, pointer->getType());
4263+
llvm::Value *result = Builder.CreateGEP(Int8Ty, pointer, index, "add.ptr");
4264+
return Builder.CreateBitCast(result, pointer->getType());
42824265
}
42834266

42844267
QualType elementType = pointerType->getPointeeType();
4285-
if (const VariableArrayType *vla
4286-
= CGF.getContext().getAsVariableArrayType(elementType)) {
4268+
if (const VariableArrayType *vla =
4269+
getContext().getAsVariableArrayType(elementType)) {
42874270
// The element count here is the total number of non-VLA elements.
4288-
llvm::Value *numElements = CGF.getVLASize(vla).NumElts;
4271+
llvm::Value *numElements = getVLASize(vla).NumElts;
42894272

42904273
// Effectively, the multiply by the VLA size is part of the GEP.
42914274
// GEP indexes are signed, and scaling an index isn't permitted to
42924275
// signed-overflow, so we use the same semantics for our explicit
42934276
// multiply. We suppress this if overflow is not undefined behavior.
4294-
llvm::Type *elemTy = CGF.ConvertTypeForMem(vla->getElementType());
4295-
if (CGF.getLangOpts().PointerOverflowDefined) {
4296-
index = CGF.Builder.CreateMul(index, numElements, "vla.index");
4297-
pointer = CGF.Builder.CreateGEP(elemTy, pointer, index, "add.ptr");
4277+
llvm::Type *elemTy = ConvertTypeForMem(vla->getElementType());
4278+
if (getLangOpts().PointerOverflowDefined) {
4279+
index = Builder.CreateMul(index, numElements, "vla.index");
4280+
pointer = Builder.CreateGEP(elemTy, pointer, index, "add.ptr");
42984281
} else {
4299-
index = CGF.Builder.CreateNSWMul(index, numElements, "vla.index");
4300-
pointer = CGF.EmitCheckedInBoundsGEP(
4301-
elemTy, pointer, index, isSigned, isSubtraction, op.E->getExprLoc(),
4302-
"add.ptr");
4282+
index = Builder.CreateNSWMul(index, numElements, "vla.index");
4283+
pointer =
4284+
EmitCheckedInBoundsGEP(elemTy, pointer, index, isSigned,
4285+
isSubtraction, BO->getExprLoc(), "add.ptr");
43034286
}
43044287
return pointer;
43054288
}
@@ -4309,16 +4292,39 @@ static Value *emitPointerArithmetic(CodeGenFunction &CGF,
43094292
// future proof.
43104293
llvm::Type *elemTy;
43114294
if (elementType->isVoidType() || elementType->isFunctionType())
4312-
elemTy = CGF.Int8Ty;
4295+
elemTy = Int8Ty;
43134296
else
4314-
elemTy = CGF.ConvertTypeForMem(elementType);
4297+
elemTy = ConvertTypeForMem(elementType);
43154298

4316-
if (CGF.getLangOpts().PointerOverflowDefined)
4317-
return CGF.Builder.CreateGEP(elemTy, pointer, index, "add.ptr");
4299+
if (getLangOpts().PointerOverflowDefined)
4300+
return Builder.CreateGEP(elemTy, pointer, index, "add.ptr");
4301+
4302+
return EmitCheckedInBoundsGEP(elemTy, pointer, index, isSigned, isSubtraction,
4303+
BO->getExprLoc(), "add.ptr");
4304+
}
4305+
4306+
/// BO_Add/BO_Sub are handled by EmitPointerWithAlignment to preserve alignment
4307+
/// information.
4308+
/// This is a fallback path for BO_AddAssign/BO_SubAssign.
4309+
static Value *emitPointerArithmetic(CodeGenFunction &CGF, const BinOpInfo &op,
4310+
bool isSubtraction) {
4311+
// Must have binary (not unary) expr here. Unary pointer
4312+
// increment/decrement doesn't use this path.
4313+
const BinaryOperator *expr = cast<BinaryOperator>(op.E);
4314+
4315+
Value *pointer = op.LHS;
4316+
Expr *pointerOperand = expr->getLHS();
4317+
Value *index = op.RHS;
4318+
Expr *indexOperand = expr->getRHS();
4319+
4320+
// In a subtraction, the LHS is always the pointer.
4321+
if (!isSubtraction && !pointer->getType()->isPointerTy()) {
4322+
std::swap(pointer, index);
4323+
std::swap(pointerOperand, indexOperand);
4324+
}
43184325

4319-
return CGF.EmitCheckedInBoundsGEP(
4320-
elemTy, pointer, index, isSigned, isSubtraction, op.E->getExprLoc(),
4321-
"add.ptr");
4326+
return CGF.EmitPointerArithmetic(expr, pointerOperand, pointer, indexOperand,
4327+
index, isSubtraction);
43224328
}
43234329

43244330
// Construct an fmuladd intrinsic to represent a fused mul-add of MulOp and

clang/lib/CodeGen/CodeGenFunction.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5220,6 +5220,12 @@ class CodeGenFunction : public CodeGenTypeCache {
52205220
/// operation is a subtraction.
52215221
enum { NotSubtraction = false, IsSubtraction = true };
52225222

5223+
/// Emit pointer + index arithmetic.
5224+
llvm::Value *EmitPointerArithmetic(const BinaryOperator *BO,
5225+
Expr *pointerOperand, llvm::Value *pointer,
5226+
Expr *indexOperand, llvm::Value *index,
5227+
bool isSubtraction);
5228+
52235229
/// Same as IRBuilder::CreateInBoundsGEP, but additionally emits a check to
52245230
/// detect undefined behavior when the pointer overflow sanitizer is enabled.
52255231
/// \p SignedIndices indicates whether any of the GEP indices are signed.

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)