[clang] [Clang][CodeGen] Preserve alignment information for pointer arithmetics (PR #152575)
via cfe-commits
cfe-commits at lists.llvm.org
Thu Aug 7 12:06:41 PDT 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang-codegen
Author: Yingwei Zheng (dtcxzyw)
<details>
<summary>Changes</summary>
Previously, the alignment of pointer arithmetics was inferred from the pointee type, losing the alignment information from its operands:
https://github.com/llvm/llvm-project/blob/503c0908c3450d228debd64baecf41df8f58476e/clang/lib/CodeGen/CGExpr.cpp#L1446-L1449
This patch preserves alignment information for pointer arithmetics `P +/- C`, to match the behavior of identical array subscript `&P[C]`: https://godbolt.org/z/xx1hfTrx4.
Closes https://github.com/llvm/llvm-project/issues/152330. Although the motivating case can be fixed by https://github.com/llvm/llvm-project/pull/145733, the alignment cannot be recovered without a dominating memory access with larger alignment.
---
Patch is 21.00 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/152575.diff
6 Files Affected:
- (modified) clang/lib/CodeGen/CGExpr.cpp (+64-15)
- (modified) clang/lib/CodeGen/CGExprScalar.cpp (+74-68)
- (modified) clang/lib/CodeGen/CodeGenFunction.h (+6)
- (modified) clang/test/CodeGen/packed-arrays.c (+3-3)
- (added) clang/test/CodeGen/pointer-arithmetic-align.c (+83)
- (modified) clang/test/CodeGenCXX/sret_cast_with_nonzero_alloca_as.cpp (+1-1)
``````````diff
diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp
index 5a3d4e447b229..ba10f2ab19d4e 100644
--- a/clang/lib/CodeGen/CGExpr.cpp
+++ b/clang/lib/CodeGen/CGExpr.cpp
@@ -1319,6 +1319,57 @@ void CodeGenModule::EmitExplicitCastExprType(const ExplicitCastExpr *E,
// LValue Expression Emission
//===----------------------------------------------------------------------===//
+static CharUnits getArrayElementAlign(CharUnits arrayAlign, llvm::Value *idx,
+ CharUnits eltSize) {
+ // If we have a constant index, we can use the exact offset of the
+ // element we're accessing.
+ if (auto *constantIdx = dyn_cast<llvm::ConstantInt>(idx)) {
+ CharUnits offset = constantIdx->getZExtValue() * eltSize;
+ return arrayAlign.alignmentAtOffset(offset);
+ }
+
+ // Otherwise, use the worst-case alignment for any element.
+ return arrayAlign.alignmentOfArrayElement(eltSize);
+}
+
+/// Emit pointer + index arithmetic.
+static Address emitPointerArithmetic(CodeGenFunction &CGF,
+ const BinaryOperator *BO,
+ LValueBaseInfo *BaseInfo,
+ TBAAAccessInfo *TBAAInfo,
+ KnownNonNull_t IsKnownNonNull) {
+ assert(BO->isAdditiveOp() && "Expect an addition or subtraction.");
+ Expr *pointerOperand = BO->getLHS();
+ Expr *indexOperand = BO->getRHS();
+ bool isSubtraction = BO->getOpcode() == BO_Sub;
+
+ Address BaseAddr = Address::invalid();
+ llvm::Value *index = nullptr;
+ // In a subtraction, the LHS is always the pointer.
+ // Note: do not change the evaluation order.
+ if (!isSubtraction && !pointerOperand->getType()->isAnyPointerType()) {
+ std::swap(pointerOperand, indexOperand);
+ index = CGF.EmitScalarExpr(indexOperand);
+ BaseAddr = CGF.EmitPointerWithAlignment(pointerOperand, BaseInfo, TBAAInfo,
+ NotKnownNonNull);
+ } else {
+ BaseAddr = CGF.EmitPointerWithAlignment(pointerOperand, BaseInfo, TBAAInfo,
+ NotKnownNonNull);
+ index = CGF.EmitScalarExpr(indexOperand);
+ }
+
+ llvm::Value *pointer = BaseAddr.getBasePointer();
+ llvm::Value *Res = CGF.EmitPointerArithmetic(
+ BO, pointerOperand, pointer, indexOperand, index, isSubtraction);
+ QualType PointeeTy = BO->getType()->getPointeeType();
+ CharUnits Align =
+ getArrayElementAlign(BaseAddr.getAlignment(), index,
+ CGF.getContext().getTypeSizeInChars(PointeeTy));
+ return Address(Res, CGF.ConvertTypeForMem(PointeeTy), Align,
+ CGF.CGM.getPointerAuthInfoForPointeeType(PointeeTy),
+ /*Offset=*/nullptr, IsKnownNonNull);
+}
+
static Address EmitPointerWithAlignment(const Expr *E, LValueBaseInfo *BaseInfo,
TBAAAccessInfo *TBAAInfo,
KnownNonNull_t IsKnownNonNull,
@@ -1381,6 +1432,13 @@ static Address EmitPointerWithAlignment(const Expr *E, LValueBaseInfo *BaseInfo,
if (CE->getCastKind() == CK_AddressSpaceConversion)
Addr = CGF.Builder.CreateAddrSpaceCast(
Addr, CGF.ConvertType(E->getType()), ElemTy);
+ // Note: Workaround for PR114062. See also the special handling in
+ // ScalarExprEmitter::VisitCastExpr.
+ if (auto *A = dyn_cast<llvm::Argument>(Addr.getBasePointer());
+ A && A->hasStructRetAttr())
+ Addr = CGF.Builder.CreateAddrSpaceCast(
+ Addr, CGF.ConvertType(E->getType()), ElemTy);
+
return CGF.authPointerToPointerCast(Addr, CE->getSubExpr()->getType(),
CE->getType());
}
@@ -1441,6 +1499,12 @@ static Address EmitPointerWithAlignment(const Expr *E, LValueBaseInfo *BaseInfo,
}
}
+ // Pointer arithmetic: pointer +/- index.
+ if (auto *BO = dyn_cast<BinaryOperator>(E)) {
+ if (BO->isAdditiveOp())
+ return emitPointerArithmetic(CGF, BO, BaseInfo, TBAAInfo, IsKnownNonNull);
+ }
+
// TODO: conditional operators, comma.
// Otherwise, use the alignment of the type.
@@ -4210,21 +4274,6 @@ static Address emitArraySubscriptGEP(CodeGenFunction &CGF, Address addr,
}
}
-static CharUnits getArrayElementAlign(CharUnits arrayAlign,
- llvm::Value *idx,
- CharUnits eltSize) {
- // If we have a constant index, we can use the exact offset of the
- // element we're accessing.
- if (auto constantIdx = dyn_cast<llvm::ConstantInt>(idx)) {
- CharUnits offset = constantIdx->getZExtValue() * eltSize;
- return arrayAlign.alignmentAtOffset(offset);
-
- // Otherwise, use the worst-case alignment for any element.
- } else {
- return arrayAlign.alignmentOfArrayElement(eltSize);
- }
-}
-
static QualType getFixedSizeElementType(const ASTContext &ctx,
const VariableArrayType *vla) {
QualType eltType;
diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp
index 44931d0481e26..9cd078bda4259 100644
--- a/clang/lib/CodeGen/CGExprScalar.cpp
+++ b/clang/lib/CodeGen/CGExprScalar.cpp
@@ -4184,29 +4184,14 @@ Value *ScalarExprEmitter::EmitOverflowCheckedBinOp(const BinOpInfo &Ops) {
}
/// Emit pointer + index arithmetic.
-static Value *emitPointerArithmetic(CodeGenFunction &CGF,
- const BinOpInfo &op,
- bool isSubtraction) {
- // Must have binary (not unary) expr here. Unary pointer
- // increment/decrement doesn't use this path.
- const BinaryOperator *expr = cast<BinaryOperator>(op.E);
-
- Value *pointer = op.LHS;
- Expr *pointerOperand = expr->getLHS();
- Value *index = op.RHS;
- Expr *indexOperand = expr->getRHS();
-
- // In a subtraction, the LHS is always the pointer.
- if (!isSubtraction && !pointer->getType()->isPointerTy()) {
- std::swap(pointer, index);
- std::swap(pointerOperand, indexOperand);
- }
-
+llvm::Value *CodeGenFunction::EmitPointerArithmetic(
+ const BinaryOperator *BO, Expr *pointerOperand, llvm::Value *pointer,
+ Expr *indexOperand, llvm::Value *index, bool isSubtraction) {
bool isSigned = indexOperand->getType()->isSignedIntegerOrEnumerationType();
unsigned width = cast<llvm::IntegerType>(index->getType())->getBitWidth();
- auto &DL = CGF.CGM.getDataLayout();
- auto PtrTy = cast<llvm::PointerType>(pointer->getType());
+ auto &DL = CGM.getDataLayout();
+ auto *PtrTy = cast<llvm::PointerType>(pointer->getType());
// Some versions of glibc and gcc use idioms (particularly in their malloc
// routines) that add a pointer-sized integer (known to be a pointer value)
@@ -4227,79 +4212,77 @@ static Value *emitPointerArithmetic(CodeGenFunction &CGF,
//
// Note that we do not suppress the pointer overflow check in this case.
if (BinaryOperator::isNullPointerArithmeticExtension(
- CGF.getContext(), op.Opcode, expr->getLHS(), expr->getRHS())) {
- Value *Ptr = CGF.Builder.CreateIntToPtr(index, pointer->getType());
- if (CGF.getLangOpts().PointerOverflowDefined ||
- !CGF.SanOpts.has(SanitizerKind::PointerOverflow) ||
- NullPointerIsDefined(CGF.Builder.GetInsertBlock()->getParent(),
+ getContext(), BO->getOpcode(), BO->getLHS(), BO->getRHS())) {
+ llvm::Value *Ptr = Builder.CreateIntToPtr(index, pointer->getType());
+ if (getLangOpts().PointerOverflowDefined ||
+ !SanOpts.has(SanitizerKind::PointerOverflow) ||
+ NullPointerIsDefined(Builder.GetInsertBlock()->getParent(),
PtrTy->getPointerAddressSpace()))
return Ptr;
// The inbounds GEP of null is valid iff the index is zero.
auto CheckOrdinal = SanitizerKind::SO_PointerOverflow;
auto CheckHandler = SanitizerHandler::PointerOverflow;
- SanitizerDebugLocation SanScope(&CGF, {CheckOrdinal}, CheckHandler);
- Value *IsZeroIndex = CGF.Builder.CreateIsNull(index);
- llvm::Constant *StaticArgs[] = {
- CGF.EmitCheckSourceLocation(op.E->getExprLoc())};
+ SanitizerDebugLocation SanScope(this, {CheckOrdinal}, CheckHandler);
+ llvm::Value *IsZeroIndex = Builder.CreateIsNull(index);
+ llvm::Constant *StaticArgs[] = {EmitCheckSourceLocation(BO->getExprLoc())};
llvm::Type *IntPtrTy = DL.getIntPtrType(PtrTy);
- Value *IntPtr = llvm::Constant::getNullValue(IntPtrTy);
- Value *ComputedGEP = CGF.Builder.CreateZExtOrTrunc(index, IntPtrTy);
- Value *DynamicArgs[] = {IntPtr, ComputedGEP};
- CGF.EmitCheck({{IsZeroIndex, CheckOrdinal}}, CheckHandler, StaticArgs,
- DynamicArgs);
+ llvm::Value *IntPtr = llvm::Constant::getNullValue(IntPtrTy);
+ llvm::Value *ComputedGEP = Builder.CreateZExtOrTrunc(index, IntPtrTy);
+ llvm::Value *DynamicArgs[] = {IntPtr, ComputedGEP};
+ EmitCheck({{IsZeroIndex, CheckOrdinal}}, CheckHandler, StaticArgs,
+ DynamicArgs);
return Ptr;
}
if (width != DL.getIndexTypeSizeInBits(PtrTy)) {
// Zero-extend or sign-extend the pointer value according to
// whether the index is signed or not.
- index = CGF.Builder.CreateIntCast(index, DL.getIndexType(PtrTy), isSigned,
- "idx.ext");
+ index = Builder.CreateIntCast(index, DL.getIndexType(PtrTy), isSigned,
+ "idx.ext");
}
// If this is subtraction, negate the index.
if (isSubtraction)
- index = CGF.Builder.CreateNeg(index, "idx.neg");
+ index = Builder.CreateNeg(index, "idx.neg");
- if (CGF.SanOpts.has(SanitizerKind::ArrayBounds))
- CGF.EmitBoundsCheck(op.E, pointerOperand, index, indexOperand->getType(),
- /*Accessed*/ false);
+ if (SanOpts.has(SanitizerKind::ArrayBounds))
+ EmitBoundsCheck(BO, pointerOperand, index, indexOperand->getType(),
+ /*Accessed*/ false);
- const PointerType *pointerType
- = pointerOperand->getType()->getAs<PointerType>();
+ const PointerType *pointerType =
+ pointerOperand->getType()->getAs<PointerType>();
if (!pointerType) {
QualType objectType = pointerOperand->getType()
- ->castAs<ObjCObjectPointerType>()
- ->getPointeeType();
- llvm::Value *objectSize
- = CGF.CGM.getSize(CGF.getContext().getTypeSizeInChars(objectType));
+ ->castAs<ObjCObjectPointerType>()
+ ->getPointeeType();
+ llvm::Value *objectSize =
+ CGM.getSize(getContext().getTypeSizeInChars(objectType));
- index = CGF.Builder.CreateMul(index, objectSize);
+ index = Builder.CreateMul(index, objectSize);
- Value *result =
- CGF.Builder.CreateGEP(CGF.Int8Ty, pointer, index, "add.ptr");
- return CGF.Builder.CreateBitCast(result, pointer->getType());
+ llvm::Value *result = Builder.CreateGEP(Int8Ty, pointer, index, "add.ptr");
+ return Builder.CreateBitCast(result, pointer->getType());
}
QualType elementType = pointerType->getPointeeType();
- if (const VariableArrayType *vla
- = CGF.getContext().getAsVariableArrayType(elementType)) {
+ if (const VariableArrayType *vla =
+ getContext().getAsVariableArrayType(elementType)) {
// The element count here is the total number of non-VLA elements.
- llvm::Value *numElements = CGF.getVLASize(vla).NumElts;
+ llvm::Value *numElements = getVLASize(vla).NumElts;
// Effectively, the multiply by the VLA size is part of the GEP.
// GEP indexes are signed, and scaling an index isn't permitted to
// signed-overflow, so we use the same semantics for our explicit
// multiply. We suppress this if overflow is not undefined behavior.
- llvm::Type *elemTy = CGF.ConvertTypeForMem(vla->getElementType());
- if (CGF.getLangOpts().PointerOverflowDefined) {
- index = CGF.Builder.CreateMul(index, numElements, "vla.index");
- pointer = CGF.Builder.CreateGEP(elemTy, pointer, index, "add.ptr");
+ llvm::Type *elemTy = ConvertTypeForMem(vla->getElementType());
+ if (getLangOpts().PointerOverflowDefined) {
+ index = Builder.CreateMul(index, numElements, "vla.index");
+ pointer = Builder.CreateGEP(elemTy, pointer, index, "add.ptr");
} else {
- index = CGF.Builder.CreateNSWMul(index, numElements, "vla.index");
- pointer = CGF.EmitCheckedInBoundsGEP(
- elemTy, pointer, index, isSigned, isSubtraction, op.E->getExprLoc(),
- "add.ptr");
+ index = Builder.CreateNSWMul(index, numElements, "vla.index");
+ pointer =
+ EmitCheckedInBoundsGEP(elemTy, pointer, index, isSigned,
+ isSubtraction, BO->getExprLoc(), "add.ptr");
}
return pointer;
}
@@ -4309,16 +4292,39 @@ static Value *emitPointerArithmetic(CodeGenFunction &CGF,
// future proof.
llvm::Type *elemTy;
if (elementType->isVoidType() || elementType->isFunctionType())
- elemTy = CGF.Int8Ty;
+ elemTy = Int8Ty;
else
- elemTy = CGF.ConvertTypeForMem(elementType);
+ elemTy = ConvertTypeForMem(elementType);
- if (CGF.getLangOpts().PointerOverflowDefined)
- return CGF.Builder.CreateGEP(elemTy, pointer, index, "add.ptr");
+ if (getLangOpts().PointerOverflowDefined)
+ return Builder.CreateGEP(elemTy, pointer, index, "add.ptr");
+
+ return EmitCheckedInBoundsGEP(elemTy, pointer, index, isSigned, isSubtraction,
+ BO->getExprLoc(), "add.ptr");
+}
+
+/// BO_Add/BO_Sub are handled by EmitPointerWithAlignment to preserve alignment
+/// information.
+/// This is a fallback path for BO_AddAssign/BO_SubAssign.
+static Value *emitPointerArithmetic(CodeGenFunction &CGF, const BinOpInfo &op,
+ bool isSubtraction) {
+ // Must have binary (not unary) expr here. Unary pointer
+ // increment/decrement doesn't use this path.
+ const BinaryOperator *expr = cast<BinaryOperator>(op.E);
+
+ Value *pointer = op.LHS;
+ Expr *pointerOperand = expr->getLHS();
+ Value *index = op.RHS;
+ Expr *indexOperand = expr->getRHS();
+
+ // In a subtraction, the LHS is always the pointer.
+ if (!isSubtraction && !pointer->getType()->isPointerTy()) {
+ std::swap(pointer, index);
+ std::swap(pointerOperand, indexOperand);
+ }
- return CGF.EmitCheckedInBoundsGEP(
- elemTy, pointer, index, isSigned, isSubtraction, op.E->getExprLoc(),
- "add.ptr");
+ return CGF.EmitPointerArithmetic(expr, pointerOperand, pointer, indexOperand,
+ index, isSubtraction);
}
// Construct an fmuladd intrinsic to represent a fused mul-add of MulOp and
diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h
index 6c32c98cec011..103c8113a79de 100644
--- a/clang/lib/CodeGen/CodeGenFunction.h
+++ b/clang/lib/CodeGen/CodeGenFunction.h
@@ -5220,6 +5220,12 @@ class CodeGenFunction : public CodeGenTypeCache {
/// operation is a subtraction.
enum { NotSubtraction = false, IsSubtraction = true };
+ /// Emit pointer + index arithmetic.
+ llvm::Value *EmitPointerArithmetic(const BinaryOperator *BO,
+ Expr *pointerOperand, llvm::Value *pointer,
+ Expr *indexOperand, llvm::Value *index,
+ bool isSubtraction);
+
/// Same as IRBuilder::CreateInBoundsGEP, but additionally emits a check to
/// detect undefined behavior when the pointer overflow sanitizer is enabled.
/// \p SignedIndices indicates whether any of the GEP indices are signed.
diff --git a/clang/test/CodeGen/packed-arrays.c b/clang/test/CodeGen/packed-arrays.c
index 097fa7fc0feb7..51629b66d0687 100644
--- a/clang/test/CodeGen/packed-arrays.c
+++ b/clang/test/CodeGen/packed-arrays.c
@@ -55,7 +55,7 @@ int align3_x0 = __alignof(((struct s3*) 0)->x[0]);
// CHECK: load i32, ptr %{{.*}}, align 1
// CHECK: }
// CHECK-LABEL: define{{.*}} i32 @f0_b
-// CHECK: load i32, ptr %{{.*}}, align 4
+// CHECK: load i32, ptr %{{.*}}, align 1
// CHECK: }
int f0_a(struct s0 *a) {
return a->x[1];
@@ -100,7 +100,7 @@ int f1_d(struct s1 *a) {
// CHECK: load i32, ptr %{{.*}}, align 1
// CHECK: }
// CHECK-LABEL: define{{.*}} i32 @f2_b
-// CHECK: load i32, ptr %{{.*}}, align 4
+// CHECK: load i32, ptr %{{.*}}, align 1
// CHECK: }
// CHECK-LABEL: define{{.*}} i32 @f2_c
// CHECK: load i32, ptr %{{.*}}, align 1
@@ -125,7 +125,7 @@ int f2_d(struct s2 *a) {
// CHECK: load i32, ptr %{{.*}}, align 1
// CHECK: }
// CHECK-LABEL: define{{.*}} i32 @f3_b
-// CHECK: load i32, ptr %{{.*}}, align 4
+// CHECK: load i32, ptr %{{.*}}, align 1
// CHECK: }
// CHECK-LABEL: define{{.*}} i32 @f3_c
// CHECK: load i32, ptr %{{.*}}, align 1
diff --git a/clang/test/CodeGen/pointer-arithmetic-align.c b/clang/test/CodeGen/pointer-arithmetic-align.c
new file mode 100644
index 0000000000000..745ab84635c1b
--- /dev/null
+++ b/clang/test/CodeGen/pointer-arithmetic-align.c
@@ -0,0 +1,83 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 5
+// RUN: %clang_cc1 -O1 -triple=x86_64-unknown-linux %s -emit-llvm -o - | FileCheck %s
+
+typedef unsigned char uint8_t;
+typedef unsigned long long uint64_t;
+
+struct a {
+ uint64_t b;
+ uint8_t block[16];
+};
+
+// CHECK-LABEL: define dso_local void @ptradd_0(
+// CHECK-SAME: ptr noundef writeonly captures(none) initializes((8, 9)) [[CTX:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[BLOCK:%.*]] = getelementptr inbounds nuw i8, ptr [[CTX]], i64 8
+// CHECK-NEXT: store i8 0, ptr [[BLOCK]], align 8, !tbaa [[TBAA2:![0-9]+]]
+// CHECK-NEXT: ret void
+//
+void ptradd_0(struct a *ctx) {
+ *(ctx->block + 0) = 0;
+}
+
+// CHECK-LABEL: define dso_local void @ptradd_4(
+// CHECK-SAME: ptr noundef writeonly captures(none) initializes((12, 13)) [[CTX:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[ADD_PTR:%.*]] = getelementptr inbounds nuw i8, ptr [[CTX]], i64 12
+// CHECK-NEXT: store i8 0, ptr [[ADD_PTR]], align 4, !tbaa [[TBAA2]]
+// CHECK-NEXT: ret void
+//
+void ptradd_4(struct a *ctx) {
+ *(ctx->block + 4) = 0;
+}
+
+// CHECK-LABEL: define dso_local void @ptradd_8(
+// CHECK-SAME: ptr noundef writeonly captures(none) initializes((16, 17)) [[CTX:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[ADD_PTR:%.*]] = getelementptr inbounds nuw i8, ptr [[CTX]], i64 16
+// CHECK-NEXT: store i8 0, ptr [[ADD_PTR]], align 8, !tbaa [[TBAA2]]
+// CHECK-NEXT: ret void
+//
+void ptradd_8(struct a *ctx) {
+ *(ctx->block + 8) = 0;
+}
+
+// CHECK-LABEL: define dso_local void @ptradd_8_commuted(
+// CHECK-SAME: ptr noundef writeonly captures(none) initializes((16, 17)) [[CTX:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[ADD_PTR:%.*]] = getelementptr inbounds nuw i8, ptr [[CTX]], i64 16
+// CHECK-NEXT: store i8 0, ptr [[ADD_PTR]], align 8, !tbaa [[TBAA2]]
+// CHECK-NEXT: ret void
+//
+void ptradd_8_commuted(struct a *ctx) {
+ *(8 + ctx->block) = 0;
+}
+
+// CHECK-LABEL: define dso_local void @ptrsub_4(
+// CHECK-SAME: ptr noundef writeonly captures(none) initializes((8, 9)) [[CTX:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[ADD_PTR:%.*]] = getelementptr inbounds nuw i8, ptr [[CTX]], i64 8
+// CHECK-NEXT: store i8 0, ptr [[ADD_PTR]], align 4, !tbaa [[TBAA2]]
+// CHECK-NEXT: ret void
+//
+void ptrsub_4(struct a *ctx) {
+ *(&ctx->block[4] - 4) = 0;
+}
+
+// CHECK-LABEL: define dso_local void @neg_ptradd_var_index(
+// CHECK-SAME: ptr noundef writeonly captures(none) [[CTX:%.*]], i8 noundef zeroext [[IDX:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[BLOCK:%.*]] = getelementptr inbounds nuw i8, ptr [[CTX]], i64 8
+// CHECK-NEXT: [[IDX_EXT:%.*]] = zext i8 [[IDX]] to i64
+// CHECK-NEXT: [[ADD_PTR:%.*]] = getelementptr inbounds nuw i8, ptr [[BLOCK]], i64 [[IDX_EXT]]
+// CHECK-NEXT: store i8 0, ptr [[ADD_PTR]], align 1, !tbaa [[TBAA2]]
+// CHECK-NEXT: ret void
+//
+void neg_ptradd_var_index(struct a *ctx, uint8_t idx) {
+ *(ctx-...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/152575
More information about the cfe-commits
mailing list