https://github.com/aalhwc updated https://github.com/llvm/llvm-project/pull/121332
>From f247c1ab9fa89ca09476ed0a398a4c4385e75193 Mon Sep 17 00:00:00 2001 From: aalhwc <aal...@gmail.com> Date: Mon, 30 Dec 2024 05:03:59 -0500 Subject: [PATCH 1/3] [Clang] Add GCC's __builtin_stack_address() to Clang (#82632). This new builtin returns the value of the stack pointer register, mirroring GCC's __builtin_stack_address(). This implementation initially supports only the x86 and x86_64 architectures. Support for other architectures can be added in future patches. --- clang/include/clang/Basic/Builtins.td | 6 + clang/lib/CodeGen/CGBuiltin.cpp | 163 ++++++++++++---------- clang/test/CodeGen/builtin-stackaddress.c | 13 ++ 3 files changed, 107 insertions(+), 75 deletions(-) create mode 100644 clang/test/CodeGen/builtin-stackaddress.c diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td index b5b47ae2746011..69aed2e6b2f0ca 100644 --- a/clang/include/clang/Basic/Builtins.td +++ b/clang/include/clang/Basic/Builtins.td @@ -899,6 +899,12 @@ def FrameAddress : Builtin { let Prototype = "void*(_Constant unsigned int)"; } +def StackAddress : Builtin { + let Spellings = ["__builtin_stack_address"]; + let Attributes = [NoThrow]; + let Prototype = "void*()"; +} + def ClearCache : Builtin { let Spellings = ["__builtin___clear_cache"]; let Attributes = [NoThrow]; diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index 4d4b7428abd505..263d77d8e10ecd 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -2764,6 +2764,81 @@ static RValue EmitHipStdParUnsupportedBuiltin(CodeGenFunction *CGF, return RValue::get(CGF->Builder.CreateCall(UBF, Args)); } +enum SpecialRegisterAccessKind { + NormalRead, + VolatileRead, + Write, +}; + +// Generates the IR for the read/write special register builtin, +// ValueType is the type of the value that is to be written or read, +// RegisterType is the type of the register being written to or read from. +static Value *EmitSpecialRegisterBuiltin(CodeGenFunction &CGF, + const CallExpr *E, + llvm::Type *RegisterType, + llvm::Type *ValueType, + SpecialRegisterAccessKind AccessKind, + StringRef SysReg = "") { + // write and register intrinsics only support 32, 64 and 128 bit operations. + assert((RegisterType->isIntegerTy(32) || RegisterType->isIntegerTy(64) || + RegisterType->isIntegerTy(128)) && + "Unsupported size for register."); + + CodeGen::CGBuilderTy &Builder = CGF.Builder; + CodeGen::CodeGenModule &CGM = CGF.CGM; + LLVMContext &Context = CGM.getLLVMContext(); + + if (SysReg.empty()) { + const Expr *SysRegStrExpr = E->getArg(0)->IgnoreParenCasts(); + SysReg = cast<clang::StringLiteral>(SysRegStrExpr)->getString(); + } + + llvm::Metadata *Ops[] = {llvm::MDString::get(Context, SysReg)}; + llvm::MDNode *RegName = llvm::MDNode::get(Context, Ops); + llvm::Value *Metadata = llvm::MetadataAsValue::get(Context, RegName); + + llvm::Type *Types[] = {RegisterType}; + + bool MixedTypes = RegisterType->isIntegerTy(64) && ValueType->isIntegerTy(32); + assert(!(RegisterType->isIntegerTy(32) && ValueType->isIntegerTy(64)) && + "Can't fit 64-bit value in 32-bit register"); + + if (AccessKind != Write) { + assert(AccessKind == NormalRead || AccessKind == VolatileRead); + llvm::Function *F = CGM.getIntrinsic( + AccessKind == VolatileRead ? llvm::Intrinsic::read_volatile_register + : llvm::Intrinsic::read_register, + Types); + llvm::Value *Call = Builder.CreateCall(F, Metadata); + + if (MixedTypes) + // Read into 64 bit register and then truncate result to 32 bit. + return Builder.CreateTrunc(Call, ValueType); + + if (ValueType->isPointerTy()) + // Have i32/i64 result (Call) but want to return a VoidPtrTy (i8*). + return Builder.CreateIntToPtr(Call, ValueType); + + return Call; + } + + llvm::Function *F = CGM.getIntrinsic(llvm::Intrinsic::write_register, Types); + llvm::Value *ArgValue = CGF.EmitScalarExpr(E->getArg(1)); + if (MixedTypes) { + // Extend 32 bit write value to 64 bit to pass to write. + ArgValue = Builder.CreateZExt(ArgValue, RegisterType); + return Builder.CreateCall(F, {Metadata, ArgValue}); + } + + if (ValueType->isPointerTy()) { + // Have VoidPtrTy ArgValue but want to return an i32/i64. + ArgValue = Builder.CreatePtrToInt(ArgValue, RegisterType); + return Builder.CreateCall(F, {Metadata, ArgValue}); + } + + return Builder.CreateCall(F, {Metadata, ArgValue}); +} + RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, const CallExpr *E, ReturnValueSlot ReturnValue) { @@ -4782,6 +4857,19 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, Function *F = CGM.getIntrinsic(Intrinsic::frameaddress, AllocaInt8PtrTy); return RValue::get(Builder.CreateCall(F, Depth)); } + case Builtin::BI__builtin_stack_address: { + switch (getTarget().getTriple().getArch()) { + case Triple::x86: + return RValue::get(EmitSpecialRegisterBuiltin( + *this, E, Int32Ty, VoidPtrTy, NormalRead, "esp")); + case Triple::x86_64: + return RValue::get(EmitSpecialRegisterBuiltin( + *this, E, Int64Ty, VoidPtrTy, NormalRead, "rsp")); + default: + ErrorUnsupported(E, "__builtin_stack_address"); + return GetUndefRValue(E->getType()); + } + } case Builtin::BI__builtin_extract_return_addr: { Value *Address = EmitScalarExpr(E->getArg(0)); Value *Result = getTargetHooks().decodeReturnAddress(*this, Address); @@ -8897,12 +8985,6 @@ Value *CodeGenFunction::GetValueForARMHint(unsigned BuiltinID) { llvm::ConstantInt::get(Int32Ty, Value)); } -enum SpecialRegisterAccessKind { - NormalRead, - VolatileRead, - Write, -}; - // Generates the IR for __builtin_read_exec_*. // Lowers the builtin to amdgcn_ballot intrinsic. static Value *EmitAMDGCNBallotForExec(CodeGenFunction &CGF, const CallExpr *E, @@ -8923,75 +9005,6 @@ static Value *EmitAMDGCNBallotForExec(CodeGenFunction &CGF, const CallExpr *E, return Call; } -// Generates the IR for the read/write special register builtin, -// ValueType is the type of the value that is to be written or read, -// RegisterType is the type of the register being written to or read from. -static Value *EmitSpecialRegisterBuiltin(CodeGenFunction &CGF, - const CallExpr *E, - llvm::Type *RegisterType, - llvm::Type *ValueType, - SpecialRegisterAccessKind AccessKind, - StringRef SysReg = "") { - // write and register intrinsics only support 32, 64 and 128 bit operations. - assert((RegisterType->isIntegerTy(32) || RegisterType->isIntegerTy(64) || - RegisterType->isIntegerTy(128)) && - "Unsupported size for register."); - - CodeGen::CGBuilderTy &Builder = CGF.Builder; - CodeGen::CodeGenModule &CGM = CGF.CGM; - LLVMContext &Context = CGM.getLLVMContext(); - - if (SysReg.empty()) { - const Expr *SysRegStrExpr = E->getArg(0)->IgnoreParenCasts(); - SysReg = cast<clang::StringLiteral>(SysRegStrExpr)->getString(); - } - - llvm::Metadata *Ops[] = { llvm::MDString::get(Context, SysReg) }; - llvm::MDNode *RegName = llvm::MDNode::get(Context, Ops); - llvm::Value *Metadata = llvm::MetadataAsValue::get(Context, RegName); - - llvm::Type *Types[] = { RegisterType }; - - bool MixedTypes = RegisterType->isIntegerTy(64) && ValueType->isIntegerTy(32); - assert(!(RegisterType->isIntegerTy(32) && ValueType->isIntegerTy(64)) - && "Can't fit 64-bit value in 32-bit register"); - - if (AccessKind != Write) { - assert(AccessKind == NormalRead || AccessKind == VolatileRead); - llvm::Function *F = CGM.getIntrinsic( - AccessKind == VolatileRead ? llvm::Intrinsic::read_volatile_register - : llvm::Intrinsic::read_register, - Types); - llvm::Value *Call = Builder.CreateCall(F, Metadata); - - if (MixedTypes) - // Read into 64 bit register and then truncate result to 32 bit. - return Builder.CreateTrunc(Call, ValueType); - - if (ValueType->isPointerTy()) - // Have i32/i64 result (Call) but want to return a VoidPtrTy (i8*). - return Builder.CreateIntToPtr(Call, ValueType); - - return Call; - } - - llvm::Function *F = CGM.getIntrinsic(llvm::Intrinsic::write_register, Types); - llvm::Value *ArgValue = CGF.EmitScalarExpr(E->getArg(1)); - if (MixedTypes) { - // Extend 32 bit write value to 64 bit to pass to write. - ArgValue = Builder.CreateZExt(ArgValue, RegisterType); - return Builder.CreateCall(F, { Metadata, ArgValue }); - } - - if (ValueType->isPointerTy()) { - // Have VoidPtrTy ArgValue but want to return an i32/i64. - ArgValue = Builder.CreatePtrToInt(ArgValue, RegisterType); - return Builder.CreateCall(F, { Metadata, ArgValue }); - } - - return Builder.CreateCall(F, { Metadata, ArgValue }); -} - /// Return true if BuiltinID is an overloaded Neon intrinsic with an extra /// argument that specifies the vector type. static bool HasExtraNeonArgument(unsigned BuiltinID) { diff --git a/clang/test/CodeGen/builtin-stackaddress.c b/clang/test/CodeGen/builtin-stackaddress.c new file mode 100644 index 00000000000000..e7f37a56e3acea --- /dev/null +++ b/clang/test/CodeGen/builtin-stackaddress.c @@ -0,0 +1,13 @@ +// RUN: %clang_cc1 -triple i686-unknown-unknown -emit-llvm -o - %s | FileCheck -check-prefix=X86 %s +// RUN: %clang_cc1 -triple x86_64-unknown-unknown -emit-llvm -o - %s | FileCheck -check-prefix=X86_64 %s + +void* a() { + // X86_64: [[INT_SP:%.*]] = call i64 @llvm.read_register.i64(metadata [[SPREG:![0-9]+]]) + // X86_64: inttoptr i64 [[INT_SP]] + // X86_64: [[SPREG]] = !{!"rsp"} + // + // X86: [[INT_SP:%.*]] = call i32 @llvm.read_register.i32(metadata [[SPREG:![0-9]+]]) + // X86: inttoptr i32 [[INT_SP]] + // X86: [[SPREG]] = !{!"esp"} + return __builtin_stack_address(); +} >From b1dd634a8d1f8cb9e3c6c3a68f2446194a247960 Mon Sep 17 00:00:00 2001 From: aalhwc <aal...@gmail.com> Date: Sat, 4 Jan 2025 05:34:46 -0500 Subject: [PATCH 2/3] [Clang] Add RISCV support for `__builtin_stack_address`. Read the 'sp' register, replicating GCC's implementation of `__builtin_stack_address` on RISCV: https://godbolt.org/z/fGraxYoxd --- clang/lib/CodeGen/CGBuiltin.cpp | 8 ++++++++ clang/test/CodeGen/builtin-stackaddress.c | 10 ++++++++++ 2 files changed, 18 insertions(+) diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index 263d77d8e10ecd..53a047e6553fd9 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -4865,6 +4865,14 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, case Triple::x86_64: return RValue::get(EmitSpecialRegisterBuiltin( *this, E, Int64Ty, VoidPtrTy, NormalRead, "rsp")); + case Triple::riscv32: + case Triple::riscv64: { + llvm::IntegerType *SPRegIntTy = + getTarget().getTriple().getArchPointerBitWidth() == 64 ? Int64Ty + : Int32Ty; + return RValue::get(EmitSpecialRegisterBuiltin( + *this, E, SPRegIntTy, VoidPtrTy, NormalRead, "sp")); + } default: ErrorUnsupported(E, "__builtin_stack_address"); return GetUndefRValue(E->getType()); diff --git a/clang/test/CodeGen/builtin-stackaddress.c b/clang/test/CodeGen/builtin-stackaddress.c index e7f37a56e3acea..40247294daa5b9 100644 --- a/clang/test/CodeGen/builtin-stackaddress.c +++ b/clang/test/CodeGen/builtin-stackaddress.c @@ -1,5 +1,7 @@ // RUN: %clang_cc1 -triple i686-unknown-unknown -emit-llvm -o - %s | FileCheck -check-prefix=X86 %s // RUN: %clang_cc1 -triple x86_64-unknown-unknown -emit-llvm -o - %s | FileCheck -check-prefix=X86_64 %s +// RUN: %clang_cc1 -triple riscv32-unknown-unknown -emit-llvm -o - %s | FileCheck -check-prefix=RISCV_32 %s +// RUN: %clang_cc1 -triple riscv64-unknown-unknown -emit-llvm -o - %s | FileCheck -check-prefix=RISCV_64 %s void* a() { // X86_64: [[INT_SP:%.*]] = call i64 @llvm.read_register.i64(metadata [[SPREG:![0-9]+]]) @@ -9,5 +11,13 @@ void* a() { // X86: [[INT_SP:%.*]] = call i32 @llvm.read_register.i32(metadata [[SPREG:![0-9]+]]) // X86: inttoptr i32 [[INT_SP]] // X86: [[SPREG]] = !{!"esp"} + // + // RISCV_32: [[INT_SP:%.*]] = call i32 @llvm.read_register.i32(metadata [[SPREG:![0-9]+]]) + // RISCV_32: inttoptr i32 [[INT_SP]] + // RISCV_32: [[SPREG]] = !{!"sp"} + // + // RISCV_64: [[INT_SP:%.*]] = call i64 @llvm.read_register.i64(metadata [[SPREG:![0-9]+]]) + // RISCV_64: inttoptr i64 [[INT_SP]] + // RISCV_64: [[SPREG]] = !{!"sp"} return __builtin_stack_address(); } >From 075fa8a134b306f7d3f8b061865c0002eaf8ef51 Mon Sep 17 00:00:00 2001 From: aalhwc <aal...@gmail.com> Date: Sun, 5 Jan 2025 08:56:04 -0500 Subject: [PATCH 3/3] [Clang] Add ARM support for `__builtin_stack_address`. Read the 'sp' register, replicating GCC's implementation of `__builtin_stack_address` on ARM: https://godbolt.org/z/4EY531j89 --- clang/lib/CodeGen/CGBuiltin.cpp | 7 +++++++ clang/test/CodeGen/builtin-stackaddress.c | 18 ++++++++++-------- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index 53a047e6553fd9..185eeb5ec8a68b 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -4865,6 +4865,13 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, case Triple::x86_64: return RValue::get(EmitSpecialRegisterBuiltin( *this, E, Int64Ty, VoidPtrTy, NormalRead, "rsp")); + case Triple::arm: + case Triple::armeb: + case Triple::thumb: + case Triple::thumbeb: + case Triple::aarch64: + case Triple::aarch64_be: + case Triple::aarch64_32: case Triple::riscv32: case Triple::riscv64: { llvm::IntegerType *SPRegIntTy = diff --git a/clang/test/CodeGen/builtin-stackaddress.c b/clang/test/CodeGen/builtin-stackaddress.c index 40247294daa5b9..210e4eba93b428 100644 --- a/clang/test/CodeGen/builtin-stackaddress.c +++ b/clang/test/CodeGen/builtin-stackaddress.c @@ -1,7 +1,9 @@ // RUN: %clang_cc1 -triple i686-unknown-unknown -emit-llvm -o - %s | FileCheck -check-prefix=X86 %s // RUN: %clang_cc1 -triple x86_64-unknown-unknown -emit-llvm -o - %s | FileCheck -check-prefix=X86_64 %s -// RUN: %clang_cc1 -triple riscv32-unknown-unknown -emit-llvm -o - %s | FileCheck -check-prefix=RISCV_32 %s -// RUN: %clang_cc1 -triple riscv64-unknown-unknown -emit-llvm -o - %s | FileCheck -check-prefix=RISCV_64 %s +// RUN: %clang_cc1 -triple riscv32-unknown-unknown -emit-llvm -o - %s | FileCheck -check-prefix=RISCV_ARM_32 %s +// RUN: %clang_cc1 -triple riscv64-unknown-unknown -emit-llvm -o - %s | FileCheck -check-prefix=RISCV_ARM_64 %s +// RUN: %clang_cc1 -triple arm-unknown-unknown -emit-llvm -o - %s | FileCheck -check-prefix=RISCV_ARM_32 %s +// RUN: %clang_cc1 -triple arm64-unknown-unknown -emit-llvm -o - %s | FileCheck -check-prefix=RISCV_ARM_64 %s void* a() { // X86_64: [[INT_SP:%.*]] = call i64 @llvm.read_register.i64(metadata [[SPREG:![0-9]+]]) @@ -12,12 +14,12 @@ void* a() { // X86: inttoptr i32 [[INT_SP]] // X86: [[SPREG]] = !{!"esp"} // - // RISCV_32: [[INT_SP:%.*]] = call i32 @llvm.read_register.i32(metadata [[SPREG:![0-9]+]]) - // RISCV_32: inttoptr i32 [[INT_SP]] - // RISCV_32: [[SPREG]] = !{!"sp"} + // RISCV_ARM_32: [[INT_SP:%.*]] = call i32 @llvm.read_register.i32(metadata [[SPREG:![0-9]+]]) + // RISCV_ARM_32: inttoptr i32 [[INT_SP]] + // RISCV_ARM_32: [[SPREG]] = !{!"sp"} // - // RISCV_64: [[INT_SP:%.*]] = call i64 @llvm.read_register.i64(metadata [[SPREG:![0-9]+]]) - // RISCV_64: inttoptr i64 [[INT_SP]] - // RISCV_64: [[SPREG]] = !{!"sp"} + // RISCV_ARM_64: [[INT_SP:%.*]] = call i64 @llvm.read_register.i64(metadata [[SPREG:![0-9]+]]) + // RISCV_ARM_64: inttoptr i64 [[INT_SP]] + // RISCV_ARM_64: [[SPREG]] = !{!"sp"} return __builtin_stack_address(); } _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits