https://github.com/maryammo updated https://github.com/llvm/llvm-project/pull/168747
>From 962119bdda50304f82ffb4569a262594945951cd Mon Sep 17 00:00:00 2001 From: Maryam Moghadas <[email protected]> Date: Wed, 19 Nov 2025 16:46:34 +0000 Subject: [PATCH 1/2] [PowerPC] Add AMO load signed builtins This commit adds two Clang builtins for AMO load signed operations: __builtin_amo_lwat_st for 32-bit signed operations __builtin_amo_ldat_s for 64-bit signed operations --- clang/include/clang/Basic/BuiltinsPPC.def | 2 + clang/lib/CodeGen/TargetBuiltins/PPC.cpp | 15 ++++++ clang/lib/Headers/amo.h | 34 +++++++++++++ clang/lib/Sema/SemaPPC.cpp | 18 +++++-- clang/test/CodeGen/PowerPC/builtins-amo-err.c | 12 +++++ clang/test/CodeGen/PowerPC/builtins-ppc-amo.c | 40 ++++++++++++++++ clang/test/CodeGen/PowerPC/ppc-amo-header.c | 48 +++++++++++++++++++ llvm/test/CodeGen/PowerPC/amo-enable.ll | 41 +++++++++++++++- 8 files changed, 205 insertions(+), 5 deletions(-) diff --git a/clang/include/clang/Basic/BuiltinsPPC.def b/clang/include/clang/Basic/BuiltinsPPC.def index 216b5fdb69ff7..43ba793795d38 100644 --- a/clang/include/clang/Basic/BuiltinsPPC.def +++ b/clang/include/clang/Basic/BuiltinsPPC.def @@ -1004,6 +1004,8 @@ TARGET_BUILTIN(__builtin_pack_vector_int128, "V1LLLiULLiULLi", "", "vsx") // AMO builtins TARGET_BUILTIN(__builtin_amo_lwat, "UiUi*UiIi", "", "isa-v30-instructions") TARGET_BUILTIN(__builtin_amo_ldat, "ULiULi*ULiIi", "", "isa-v30-instructions") +TARGET_BUILTIN(__builtin_amo_lwat_s, "SiSi*SiIi", "", "isa-v30-instructions") +TARGET_BUILTIN(__builtin_amo_ldat_s, "SLiSLi*SLiIi", "", "isa-v30-instructions") // Set the floating point rounding mode BUILTIN(__builtin_setrnd, "di", "") diff --git a/clang/lib/CodeGen/TargetBuiltins/PPC.cpp b/clang/lib/CodeGen/TargetBuiltins/PPC.cpp index 44d5938e38724..1e1127350c301 100644 --- a/clang/lib/CodeGen/TargetBuiltins/PPC.cpp +++ b/clang/lib/CodeGen/TargetBuiltins/PPC.cpp @@ -1359,5 +1359,20 @@ Value *CodeGenFunction::EmitPPCBuiltinExpr(unsigned BuiltinID, {EmitScalarExpr(E->getArg(0))}); case PPC::BI__builtin_ppc_mffs: return Builder.CreateCall(CGM.getIntrinsic(Intrinsic::ppc_readflm)); + + case PPC::BI__builtin_amo_lwat_s: { + Value *Op0 = EmitScalarExpr(E->getArg(0)); + Value *Op1 = EmitScalarExpr(E->getArg(1)); + Value *Op2 = EmitScalarExpr(E->getArg(2)); + return Builder.CreateCall(CGM.getIntrinsic(Intrinsic::ppc_amo_lwat), + {Op0, Op1, Op2}); + } + case PPC::BI__builtin_amo_ldat_s: { + Value *Op0 = EmitScalarExpr(E->getArg(0)); + Value *Op1 = EmitScalarExpr(E->getArg(1)); + Value *Op2 = EmitScalarExpr(E->getArg(2)); + return Builder.CreateCall(CGM.getIntrinsic(Intrinsic::ppc_amo_ldat), + {Op0, Op1, Op2}); + } } } diff --git a/clang/lib/Headers/amo.h b/clang/lib/Headers/amo.h index fda2984b97626..bdb1ff23f161a 100644 --- a/clang/lib/Headers/amo.h +++ b/clang/lib/Headers/amo.h @@ -61,6 +61,23 @@ static inline uint32_t amo_lwat_swap(uint32_t *ptr, uint32_t val) { return __builtin_amo_lwat(ptr, val, _AMO_LD_SWAP); } +/* 32-bit signed AMO load operations */ +static inline int32_t amo_lwat_sadd(int32_t *ptr, int32_t val) { + return __builtin_amo_lwat_s(ptr, val, _AMO_LD_ADD); +} + +static inline int32_t amo_lwat_smax(int32_t *ptr, int32_t val) { + return __builtin_amo_lwat_s(ptr, val, _AMO_LD_SMAX); +} + +static inline int32_t amo_lwat_smin(int32_t *ptr, int32_t val) { + return __builtin_amo_lwat_s(ptr, val, _AMO_LD_SMIN); +} + +static inline int32_t amo_lwat_sswap(int32_t *ptr, int32_t val) { + return __builtin_amo_lwat_s(ptr, val, _AMO_LD_SWAP); +} + /* 64-bit unsigned AMO load operations */ static inline uint64_t amo_ldat_add(uint64_t *ptr, uint64_t val) { return __builtin_amo_ldat(ptr, val, _AMO_LD_ADD); @@ -90,6 +107,23 @@ static inline uint64_t amo_ldat_swap(uint64_t *ptr, uint64_t val) { return __builtin_amo_ldat(ptr, val, _AMO_LD_SWAP); } +/* 64-bit signed AMO load operations */ +static inline int64_t amo_ldat_sadd(int64_t *ptr, int64_t val) { + return __builtin_amo_ldat_s(ptr, val, _AMO_LD_ADD); +} + +static inline int64_t amo_ldat_smax(int64_t *ptr, int64_t val) { + return __builtin_amo_ldat_s(ptr, val, _AMO_LD_SMAX); +} + +static inline int64_t amo_ldat_smin(int64_t *ptr, int64_t val) { + return __builtin_amo_ldat_s(ptr, val, _AMO_LD_SMIN); +} + +static inline int64_t amo_ldat_sswap(int64_t *ptr, int64_t val) { + return __builtin_amo_ldat_s(ptr, val, _AMO_LD_SWAP); +} + #ifdef __cplusplus } #endif diff --git a/clang/lib/Sema/SemaPPC.cpp b/clang/lib/Sema/SemaPPC.cpp index 3d6615b6b5395..dfb423b7b36a4 100644 --- a/clang/lib/Sema/SemaPPC.cpp +++ b/clang/lib/Sema/SemaPPC.cpp @@ -256,17 +256,27 @@ bool SemaPPC::CheckPPCBuiltinFunctionCall(const TargetInfo &TI, return BuiltinPPCMMACall(TheCall, BuiltinID, Types); #include "clang/Basic/BuiltinsPPC.def" case PPC::BI__builtin_amo_lwat: - case PPC::BI__builtin_amo_ldat: { + case PPC::BI__builtin_amo_ldat: + case PPC::BI__builtin_amo_lwat_s: + case PPC::BI__builtin_amo_ldat_s: { llvm::APSInt Result; if (SemaRef.BuiltinConstantArg(TheCall, 2, Result)) return true; unsigned Val = Result.getZExtValue(); - static constexpr unsigned ValidFC[] = {0, 1, 2, 3, 4, 6, 8}; - if (llvm::is_contained(ValidFC, Val)) + + bool IsUnsigned = (BuiltinID == PPC::BI__builtin_amo_lwat || + BuiltinID == PPC::BI__builtin_amo_ldat); + + bool IsValid = IsUnsigned ? llvm::is_contained({0, 1, 2, 3, 4, 6, 8}, Val) + : llvm::is_contained({0, 5, 7, 8}, Val); + + if (IsValid) return false; + Expr *Arg = TheCall->getArg(2); return SemaRef.Diag(Arg->getBeginLoc(), diag::err_argument_invalid_range) - << toString(Result, 10) << "0-4, 6" << "8" << Arg->getSourceRange(); + << toString(Result, 10) << (IsUnsigned ? "0-4, 6" : "0, 5, 7") << "8" + << Arg->getSourceRange(); } } llvm_unreachable("must return from switch"); diff --git a/clang/test/CodeGen/PowerPC/builtins-amo-err.c b/clang/test/CodeGen/PowerPC/builtins-amo-err.c index cdc14ef7f7e04..217dd58f76736 100644 --- a/clang/test/CodeGen/PowerPC/builtins-amo-err.c +++ b/clang/test/CodeGen/PowerPC/builtins-amo-err.c @@ -15,4 +15,16 @@ void test_amo() { __builtin_amo_ldat(ptr2, value2, 3); // FC-ERROR: error: argument value 26 is outside the valid range [0-4, 6, 8] __builtin_amo_ldat(ptr2, value2, 26); + + signed int *ptr3, value3; + // AIX32-ERROR: error: this builtin is only available on 64-bit targets + __builtin_amo_lwat_s(ptr3, value3, 0); + // FC-ERROR: argument value 2 is outside the valid range [0, 5, 7, 8] + __builtin_amo_lwat_s(ptr3, value3, 2); + + unsigned long int *ptr4, value4; + // AIX32-ERROR: error: this builtin is only available on 64-bit targets + __builtin_amo_ldat_s(ptr4, value4, 3); + // FC-ERROR: error: argument value 6 is outside the valid range [0, 5, 7, 8] + __builtin_amo_ldat_s(ptr4, value4, 6); } diff --git a/clang/test/CodeGen/PowerPC/builtins-ppc-amo.c b/clang/test/CodeGen/PowerPC/builtins-ppc-amo.c index 2975b99786869..03e71429319b3 100644 --- a/clang/test/CodeGen/PowerPC/builtins-ppc-amo.c +++ b/clang/test/CodeGen/PowerPC/builtins-ppc-amo.c @@ -41,6 +41,46 @@ void test_unsigned_ldat(unsigned long int *ptr, unsigned long int value, unsigne unsigned long int res = __builtin_amo_ldat(ptr, value, 3); *resp = res; } + +// CHECK-LABEL: define dso_local void @test_signed_lwat( +// CHECK-SAME: ptr noundef [[PTR:%.*]], i32 noundef signext [[VALUE:%.*]], ptr noundef writeonly captures(none) initializes((0, 4)) [[RESP:%.*]]) local_unnamed_addr #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[TMP0:%.*]] = tail call i32 @llvm.ppc.amo.lwat(ptr [[PTR]], i32 [[VALUE]], i32 5) +// CHECK-NEXT: store i32 [[TMP0]], ptr [[RESP]], align 4, !tbaa [[INT_TBAA2]] +// CHECK-NEXT: ret void +// +// AIX-LABEL: define void @test_signed_lwat( +// AIX-SAME: ptr noundef [[PTR:%.*]], i32 noundef signext [[VALUE:%.*]], ptr noundef writeonly captures(none) initializes((0, 4)) [[RESP:%.*]]) local_unnamed_addr #[[ATTR0]] { +// AIX-NEXT: [[ENTRY:.*:]] +// AIX-NEXT: [[TMP0:%.*]] = tail call i32 @llvm.ppc.amo.lwat(ptr [[PTR]], i32 [[VALUE]], i32 5) +// AIX-NEXT: store i32 [[TMP0]], ptr [[RESP]], align 4, !tbaa [[INT_TBAA2]] +// AIX-NEXT: ret void +// +void test_signed_lwat(int *ptr, int value, int * resp) { + int res = __builtin_amo_lwat_s(ptr, value, 5); + *resp = res; +} + + +// CHECK-LABEL: define dso_local void @test_signed_ldat( +// CHECK-SAME: ptr noundef [[PTR:%.*]], i64 noundef [[VALUE:%.*]], ptr noundef writeonly captures(none) initializes((0, 8)) [[RESP:%.*]]) local_unnamed_addr #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[TMP0:%.*]] = tail call i64 @llvm.ppc.amo.ldat(ptr [[PTR]], i64 [[VALUE]], i32 8) +// CHECK-NEXT: store i64 [[TMP0]], ptr [[RESP]], align 8, !tbaa [[LONG_TBAA6]] +// CHECK-NEXT: ret void +// +// AIX-LABEL: define void @test_signed_ldat( +// AIX-SAME: ptr noundef [[PTR:%.*]], i64 noundef [[VALUE:%.*]], ptr noundef writeonly captures(none) initializes((0, 8)) [[RESP:%.*]]) local_unnamed_addr #[[ATTR0]] { +// AIX-NEXT: [[ENTRY:.*:]] +// AIX-NEXT: [[TMP0:%.*]] = tail call i64 @llvm.ppc.amo.ldat(ptr [[PTR]], i64 [[VALUE]], i32 8) +// AIX-NEXT: store i64 [[TMP0]], ptr [[RESP]], align 8, !tbaa [[LONG_TBAA6]] +// AIX-NEXT: ret void +// +void test_signed_ldat(long int *ptr, long int value, long int * resp) { + long int res = __builtin_amo_ldat_s(ptr, value, 8); + *resp = res; +} + //. // CHECK: [[INT_TBAA2]] = !{[[META3:![0-9]+]], [[META3]], i64 0} // CHECK: [[META3]] = !{!"int", [[META4:![0-9]+]], i64 0} diff --git a/clang/test/CodeGen/PowerPC/ppc-amo-header.c b/clang/test/CodeGen/PowerPC/ppc-amo-header.c index f544cdef1e7d0..ffc87561fa3c4 100644 --- a/clang/test/CodeGen/PowerPC/ppc-amo-header.c +++ b/clang/test/CodeGen/PowerPC/ppc-amo-header.c @@ -48,6 +48,30 @@ uint32_t test_lwat_swap(uint32_t *ptr, uint32_t val) { return amo_lwat_swap(ptr, val); } +int32_t test_lwat_sadd(int32_t *ptr, int32_t val) { + // CHECK-LABEL: @test_lwat_sadd + // CHECK: call i32 @llvm.ppc.amo.lwat(ptr %{{.*}}, i32 %{{.*}}, i32 0) + return amo_lwat_sadd(ptr, val); +} + +int32_t test_lwat_smax(int32_t *ptr, int32_t val) { + // CHECK-LABEL: @test_lwat_smax + // CHECK: call i32 @llvm.ppc.amo.lwat(ptr %{{.*}}, i32 %{{.*}}, i32 5) + return amo_lwat_smax(ptr, val); +} + +int32_t test_lwat_smin(int32_t *ptr, int32_t val) { + // CHECK-LABEL: @test_lwat_smin + // CHECK: call i32 @llvm.ppc.amo.lwat(ptr %{{.*}}, i32 %{{.*}}, i32 7) + return amo_lwat_smin(ptr, val); +} + +int32_t test_lwat_sswap(int32_t *ptr, int32_t val) { + // CHECK-LABEL: @test_lwat_sswap + // CHECK: call i32 @llvm.ppc.amo.lwat(ptr %{{.*}}, i32 %{{.*}}, i32 8) + return amo_lwat_sswap(ptr, val); +} + uint64_t test_ldat_add(uint64_t *ptr, uint64_t val) { // CHECK-LABEL: @test_ldat_add // CHECK: call i64 @llvm.ppc.amo.ldat(ptr %{{.*}}, i64 %{{.*}}, i32 0) @@ -89,3 +113,27 @@ uint64_t test_ldat_swap(uint64_t *ptr, uint64_t val) { // CHECK: call i64 @llvm.ppc.amo.ldat(ptr %{{.*}}, i64 %{{.*}}, i32 8) return amo_ldat_swap(ptr, val); } + +int64_t test_ldat_sadd(int64_t *ptr, int64_t val) { + // CHECK-LABEL: @test_ldat_sadd + // CHECK: call i64 @llvm.ppc.amo.ldat(ptr %{{.*}}, i64 %{{.*}}, i32 0) + return amo_ldat_sadd(ptr, val); +} + +int64_t test_ldat_smax(int64_t *ptr, int64_t val) { + // CHECK-LABEL: @test_ldat_smax + // CHECK: call i64 @llvm.ppc.amo.ldat(ptr %{{.*}}, i64 %{{.*}}, i32 5) + return amo_ldat_smax(ptr, val); +} + +int64_t test_ldat_smin(int64_t *ptr, int64_t val) { + // CHECK-LABEL: @test_ldat_smin + // CHECK: call i64 @llvm.ppc.amo.ldat(ptr %{{.*}}, i64 %{{.*}}, i32 7) + return amo_ldat_smin(ptr, val); +} + +int64_t test_ldat_sswap(int64_t *ptr, int64_t val) { + // CHECK-LABEL: @test_ldat_sswap + // CHECK: call i64 @llvm.ppc.amo.ldat(ptr %{{.*}}, i64 %{{.*}}, i32 8) + return amo_ldat_sswap(ptr, val); +} diff --git a/llvm/test/CodeGen/PowerPC/amo-enable.ll b/llvm/test/CodeGen/PowerPC/amo-enable.ll index 33739cca12492..37c91e2ff5505 100644 --- a/llvm/test/CodeGen/PowerPC/amo-enable.ll +++ b/llvm/test/CodeGen/PowerPC/amo-enable.ll @@ -46,6 +46,45 @@ entry: ret void } +define void @test_s_lwat(ptr noundef %ptr, i32 noundef %value, ptr nocapture %resp) { +; CHECK-LABEL: test_s_lwat: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: mr r7, r4 +; CHECK-NEXT: lwat r6, r3, 0 +; CHECK-NEXT: stw r6, 0(r5) +; CHECK-NEXT: blr +; +; CHECK-BE-LABEL: test_s_lwat: +; CHECK-BE: # %bb.0: # %entry +; CHECK-BE-NEXT: mr r7, r4 +; CHECK-BE-NEXT: lwat r6, r3, 0 +; CHECK-BE-NEXT: stw r6, 0(r5) +; CHECK-BE-NEXT: blr +entry: + %0 = tail call i32 @llvm.ppc.amo.lwat(ptr %ptr, i32 %value, i32 0) + store i32 %0, ptr %resp, align 4 + ret void +} + +define void @test_s_ldat(ptr noundef %ptr, i64 noundef %value, ptr nocapture %resp) { +; CHECK-LABEL: test_s_ldat: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: mr r7, r4 +; CHECK-NEXT: ldat r6, r3, 5 +; CHECK-NEXT: std r6, 0(r5) +; CHECK-NEXT: blr +; +; CHECK-BE-LABEL: test_s_ldat: +; CHECK-BE: # %bb.0: # %entry +; CHECK-BE-NEXT: mr r7, r4 +; CHECK-BE-NEXT: ldat r6, r3, 5 +; CHECK-BE-NEXT: std r6, 0(r5) +; CHECK-BE-NEXT: blr +entry: + %0 = tail call i64 @llvm.ppc.amo.ldat(ptr %ptr, i64 %value, i32 5) + store i64 %0, ptr %resp, align 8 + ret void +} + declare i64 @llvm.ppc.amo.ldat(ptr, i64, i32 immarg) declare i32 @llvm.ppc.amo.lwat(ptr, i32, i32 immarg) - >From 5a7467aeb9928abc8c440ebfee935a31811c5739 Mon Sep 17 00:00:00 2001 From: Maryam Moghadas <[email protected]> Date: Wed, 19 Nov 2025 19:04:22 +0000 Subject: [PATCH 2/2] Use unsigned literals for FC value checking --- clang/lib/Sema/SemaPPC.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/clang/lib/Sema/SemaPPC.cpp b/clang/lib/Sema/SemaPPC.cpp index dfb423b7b36a4..e9266319f4b06 100644 --- a/clang/lib/Sema/SemaPPC.cpp +++ b/clang/lib/Sema/SemaPPC.cpp @@ -267,8 +267,9 @@ bool SemaPPC::CheckPPCBuiltinFunctionCall(const TargetInfo &TI, bool IsUnsigned = (BuiltinID == PPC::BI__builtin_amo_lwat || BuiltinID == PPC::BI__builtin_amo_ldat); - bool IsValid = IsUnsigned ? llvm::is_contained({0, 1, 2, 3, 4, 6, 8}, Val) - : llvm::is_contained({0, 5, 7, 8}, Val); + bool IsValid = IsUnsigned + ? llvm::is_contained({0u, 1u, 2u, 3u, 4u, 6u, 8u}, Val) + : llvm::is_contained({0u, 5u, 7u, 8u}, Val); if (IsValid) return false; _______________________________________________ llvm-branch-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
