https://github.com/dtcxzyw updated https://github.com/llvm/llvm-project/pull/152575
>From 16f7036fcf78d38bc1fc05b601c9a59653eb44cf Mon Sep 17 00:00:00 2001 From: Yingwei Zheng <dtcxzyw2...@gmail.com> Date: Fri, 8 Aug 2025 00:27:49 +0800 Subject: [PATCH 1/2] [Clang][CodeGen] Add pre-commit tests. NFC. --- clang/test/CodeGen/pointer-arithmetic-align.c | 83 +++++++++++++++++++ 1 file changed, 83 insertions(+) create mode 100644 clang/test/CodeGen/pointer-arithmetic-align.c diff --git a/clang/test/CodeGen/pointer-arithmetic-align.c b/clang/test/CodeGen/pointer-arithmetic-align.c new file mode 100644 index 0000000000000..3d3cceaaa21d0 --- /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 1, !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 1, !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 1, !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 1, !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 1, !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->block + idx) = 0; +} +//. +// CHECK: [[TBAA2]] = !{[[META3:![0-9]+]], [[META3]], i64 0} +// CHECK: [[META3]] = !{!"omnipotent char", [[META4:![0-9]+]], i64 0} +// CHECK: [[META4]] = !{!"Simple C/C++ TBAA"} +//. >From e58f8352e60c0f541b3a8f78f3d6e5c6b3529294 Mon Sep 17 00:00:00 2001 From: Yingwei Zheng <dtcxzyw2...@gmail.com> Date: Fri, 8 Aug 2025 21:47:36 +0800 Subject: [PATCH 2/2] [Clang][CodeGen] Preserve alignment information for pointer arithmetics --- clang/lib/CodeGen/CGExpr.cpp | 79 +++++++++++++++---- clang/test/CodeGen/packed-arrays.c | 6 +- clang/test/CodeGen/pointer-arithmetic-align.c | 10 +-- .../sret_cast_with_nonzero_alloca_as.cpp | 2 +- 4 files changed, 73 insertions(+), 24 deletions(-) diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index f1affef756df5..d71a1249ed620 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -1314,6 +1314,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, @@ -1376,6 +1427,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()); } @@ -1436,6 +1494,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. @@ -4222,21 +4286,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/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 index 3d3cceaaa21d0..745ab84635c1b 100644 --- a/clang/test/CodeGen/pointer-arithmetic-align.c +++ b/clang/test/CodeGen/pointer-arithmetic-align.c @@ -13,7 +13,7 @@ struct a { // 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 1, !tbaa [[TBAA2:![0-9]+]] +// CHECK-NEXT: store i8 0, ptr [[BLOCK]], align 8, !tbaa [[TBAA2:![0-9]+]] // CHECK-NEXT: ret void // void ptradd_0(struct a *ctx) { @@ -24,7 +24,7 @@ void ptradd_0(struct a *ctx) { // 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 1, !tbaa [[TBAA2]] +// CHECK-NEXT: store i8 0, ptr [[ADD_PTR]], align 4, !tbaa [[TBAA2]] // CHECK-NEXT: ret void // void ptradd_4(struct a *ctx) { @@ -35,7 +35,7 @@ void ptradd_4(struct a *ctx) { // 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 1, !tbaa [[TBAA2]] +// CHECK-NEXT: store i8 0, ptr [[ADD_PTR]], align 8, !tbaa [[TBAA2]] // CHECK-NEXT: ret void // void ptradd_8(struct a *ctx) { @@ -46,7 +46,7 @@ void ptradd_8(struct a *ctx) { // 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 1, !tbaa [[TBAA2]] +// CHECK-NEXT: store i8 0, ptr [[ADD_PTR]], align 8, !tbaa [[TBAA2]] // CHECK-NEXT: ret void // void ptradd_8_commuted(struct a *ctx) { @@ -57,7 +57,7 @@ void ptradd_8_commuted(struct a *ctx) { // 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 1, !tbaa [[TBAA2]] +// CHECK-NEXT: store i8 0, ptr [[ADD_PTR]], align 4, !tbaa [[TBAA2]] // CHECK-NEXT: ret void // void ptrsub_4(struct a *ctx) { diff --git a/clang/test/CodeGenCXX/sret_cast_with_nonzero_alloca_as.cpp b/clang/test/CodeGenCXX/sret_cast_with_nonzero_alloca_as.cpp index 320c712b665de..712aa69063382 100644 --- a/clang/test/CodeGenCXX/sret_cast_with_nonzero_alloca_as.cpp +++ b/clang/test/CodeGenCXX/sret_cast_with_nonzero_alloca_as.cpp @@ -19,7 +19,7 @@ struct X { int z[17]; }; // CHECK-NEXT: [[TMP1:%.*]] = load i8, ptr [[Y_ADDR_ASCAST]], align 1 // CHECK-NEXT: [[AGG_RESULT_ASCAST1:%.*]] = addrspacecast ptr addrspace(5) [[AGG_RESULT]] to ptr // CHECK-NEXT: [[ADD_PTR2:%.*]] = getelementptr inbounds i8, ptr [[AGG_RESULT_ASCAST1]], i64 2 -// CHECK-NEXT: store i8 [[TMP1]], ptr [[ADD_PTR2]], align 1 +// CHECK-NEXT: store i8 [[TMP1]], ptr [[ADD_PTR2]], align 2 // CHECK-NEXT: ret void // X foo(char x, char y) { _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits