[clang] [llvm] [Clang] Add `__builtin_stack_address` (PR #148281)
via llvm-commits
llvm-commits at lists.llvm.org
Wed Aug 27 12:42:22 PDT 2025
https://github.com/moorabbit updated https://github.com/llvm/llvm-project/pull/148281
>From 029d9fce6cdb75ea4819a107c7ed9f074bb36678 Mon Sep 17 00:00:00 2001
From: moorabbit <215698969+moorabbit at users.noreply.github.com>
Date: Mon, 7 Jul 2025 09:25:46 -0400
Subject: [PATCH 01/15] [Clang] Add `__builtin_stack_address`
Add support for `__builtin_stack_address` builtin. The semantics match those of
GCC's builtin with the same name.
`__builtin_stack_address` returns the starting address of the stack region that
may be used by called functions. This PR only adds support for the following
architectures: x86 - x86_64. Support for other architectures can be added in
future patches.
Fixes #82632
---
clang/docs/LanguageExtensions.rst | 33 +++++++++++++++++
clang/docs/ReleaseNotes.rst | 2 ++
clang/include/clang/Basic/Builtins.td | 6 ++++
clang/lib/CodeGen/CGBuiltin.cpp | 4 +++
clang/lib/Sema/SemaChecking.cpp | 9 +++++
clang/test/CodeGen/builtin-stackaddress.c | 14 ++++++++
.../test/CodeGenCXX/builtin-stackaddress.cpp | 36 +++++++++++++++++++
.../builtin-stackaddress-target-support.c | 16 +++++++++
clang/test/Sema/builtin-stackaddress.c | 5 +++
llvm/include/llvm/CodeGen/ISDOpcodes.h | 5 +++
llvm/include/llvm/IR/Intrinsics.td | 1 +
llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp | 1 +
.../SelectionDAG/SelectionDAGBuilder.cpp | 6 ++++
.../SelectionDAG/SelectionDAGDumper.cpp | 1 +
llvm/lib/Target/X86/X86ISelLowering.cpp | 8 +++++
llvm/lib/Target/X86/X86ISelLowering.h | 1 +
16 files changed, 148 insertions(+)
create mode 100644 clang/test/CodeGen/builtin-stackaddress.c
create mode 100644 clang/test/CodeGenCXX/builtin-stackaddress.cpp
create mode 100644 clang/test/Sema/builtin-stackaddress-target-support.c
diff --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst
index a42a546555716..5b78ae42559be 100644
--- a/clang/docs/LanguageExtensions.rst
+++ b/clang/docs/LanguageExtensions.rst
@@ -4189,6 +4189,39 @@ assignment can happen automatically.
to a variable, have its address taken, or passed into or returned from a
function, because doing so violates bounds safety conventions.
+.. _builtin_stack_address-doc:
+
+``__builtin_stack_address``
+---------------------------
+
+``__builtin_stack_address`` returns the address that separates the current
+function's (i.e. the one calling the builtin) stack space and the region of the
+stack that may be modified by called functions. The semantics match those of GCC's builtin of the same name.
+
+**Note:** Support for this builtin is currently limited to the following architectures: x86_64, x86.
+
+**Syntax**:
+
+.. code-block:: c++
+
+ void *__builtin_stack_address()
+
+**Example**:
+
+.. code-block:: c++
+
+ void *sp = __builtin_stack_address();
+
+**Description**:
+
+The address returned by ``__builtin_stack_address`` identifies the starting
+address of the stack region that may be used by called functions.
+
+On some architectures (e.g. x86), it's sufficient to return the value in the stack pointer register
+directly. On others (e.g. SPARCv9), adjustments are required to the value of the stack pointer
+register. ``__builtin_stack_address`` performs the necessary adjustments and returns the correct
+boundary address.
+
Multiprecision Arithmetic Builtins
----------------------------------
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 57a94242c9e61..ccf83eb2f16fa 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -172,6 +172,8 @@ Resolutions to C++ Defect Reports
C Language Changes
------------------
+- Clang now supports the :ref:`__builtin_stack_address <builtin_stack_address-doc>` () builtin.
+ The semantics match those of GCC's builtin with the same name.
- Clang now allows an ``inline`` specifier on a typedef declaration of a
function type in Microsoft compatibility mode. #GH124869
- Clang now allows ``restrict`` qualifier for array types with pointer elements (#GH92847).
diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td
index 5ebb82180521d..f2012c813c9a7 100644
--- a/clang/include/clang/Basic/Builtins.td
+++ b/clang/include/clang/Basic/Builtins.td
@@ -917,6 +917,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 48c91eb4a5b4f..641bbede4bae7 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -4673,6 +4673,10 @@ 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: {
+ return RValue::get(Builder.CreateCall(
+ CGM.getIntrinsic(Intrinsic::stackaddress, AllocaInt8PtrTy)));
+ }
case Builtin::BI__builtin_extract_return_addr: {
Value *Address = EmitScalarExpr(E->getArg(0));
Value *Result = getTargetHooks().decodeReturnAddress(*this, Address);
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index dd5b710d7e1d4..ca9371d6d2179 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -2958,6 +2958,15 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
break;
}
+ case Builtin::BI__builtin_stack_address: {
+ if (CheckBuiltinTargetInSupported(
+ *this, TheCall,
+ /*SupportedArchs=*/{llvm::Triple::x86_64, llvm::Triple::x86})) {
+ return ExprError();
+ }
+ break;
+ }
+
case Builtin::BI__builtin_nondeterministic_value: {
if (BuiltinNonDeterministicValue(TheCall))
return ExprError();
diff --git a/clang/test/CodeGen/builtin-stackaddress.c b/clang/test/CodeGen/builtin-stackaddress.c
new file mode 100644
index 0000000000000..a6b44b227947d
--- /dev/null
+++ b/clang/test/CodeGen/builtin-stackaddress.c
@@ -0,0 +1,14 @@
+// RUN: %clang -target x86_64 -S -emit-llvm %s -o - | FileCheck %s --check-prefix=llvm
+// RUN: %clang -target x86_64 -S %s -o - | FileCheck %s --check-prefix=x64
+
+extern void f(int, int, int, long, long, long, long, long, long, long, long);
+
+// llvm-LABEL: define {{[^@]+}} @a()
+// llvm: call {{[^@]+}} @llvm.stackaddress.p0()
+//
+// x64-LABEL: a:
+// x64: movq %rsp, %rax
+void *a() {
+ f(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11);
+ return __builtin_stack_address();
+}
diff --git a/clang/test/CodeGenCXX/builtin-stackaddress.cpp b/clang/test/CodeGenCXX/builtin-stackaddress.cpp
new file mode 100644
index 0000000000000..24a949e83d9e0
--- /dev/null
+++ b/clang/test/CodeGenCXX/builtin-stackaddress.cpp
@@ -0,0 +1,36 @@
+// RUN: %clang -target x86_64 -S -emit-llvm %s -o - | llvm-cxxfilt | FileCheck %s --check-prefix=llvm
+// RUN: %clang -target x86_64 -S %s -o - | llvm-cxxfilt | FileCheck %s --check-prefix=x64
+
+extern void f(int, int, int, long, long, long, long, long, long, long, long);
+
+struct S {
+ void *a();
+};
+
+// llvm-LABEL: define {{[^@]+}} @S::a()
+// llvm: call {{[^@]+}} @llvm.stackaddress.p0()
+//
+// x64-LABEL: S::a():
+// x64: movq %rsp, %rax
+void *S::a() {
+ void *p = __builtin_stack_address();
+ f(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11);
+ return p;
+}
+
+// llvm-LABEL: define {{[^@]+}} @two()
+// llvm: call {{[^@]+}} @"two()::$_0::operator()() const"
+//
+// llvm-LABEL: define {{[^@]+}} @"two()::$_0::operator()() const"
+// llvm: call {{[^@]+}} @llvm.stackaddress.p0()
+//
+// x64-LABEL: two()::$_0::operator()() const:
+// x64: movq %rsp, %rax
+void *two() {
+ auto l = []() {
+ void *p = __builtin_stack_address();
+ f(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11);
+ return p;
+ };
+ return l();
+}
diff --git a/clang/test/Sema/builtin-stackaddress-target-support.c b/clang/test/Sema/builtin-stackaddress-target-support.c
new file mode 100644
index 0000000000000..aab077ea558f8
--- /dev/null
+++ b/clang/test/Sema/builtin-stackaddress-target-support.c
@@ -0,0 +1,16 @@
+// RUN: %clang_cc1 -verify %s -triple x86_64-unknown-unknown -DTEST_x64
+// RUN: %clang_cc1 -verify %s -triple i386-unknown-unknown -DTEST_x86
+// RUN: %clang_cc1 -verify %s -triple riscv32-unknown-unknown -DTEST_riscv32
+// RUN: %clang_cc1 -verify %s -triple riscv64-unknown-unknown -DTEST_riscv64
+// RUN: %clang_cc1 -verify %s -triple aarch64-unknown-unknown -DTEST_aarch64
+
+#if defined(TEST_x64) || defined(TEST_x86)
+// expected-no-diagnostics
+void *a() {
+return __builtin_stack_address();
+}
+#else
+void *a() {
+return __builtin_stack_address(); // expected-error {{builtin is not supported on this target}}
+}
+#endif
diff --git a/clang/test/Sema/builtin-stackaddress.c b/clang/test/Sema/builtin-stackaddress.c
index ecdc64d899af5..03a0f5ef16714 100644
--- a/clang/test/Sema/builtin-stackaddress.c
+++ b/clang/test/Sema/builtin-stackaddress.c
@@ -36,3 +36,8 @@ void* h(unsigned x) {
// expected-error at +1 {{argument value 1048575 is outside the valid range [0, 65535]}}
return __builtin_frame_address(0xFFFFF);
}
+
+void *i() {
+// expected-error at +1 {{too many arguments to function call, expected 0, have 1}}
+return __builtin_stack_address(0);
+}
diff --git a/llvm/include/llvm/CodeGen/ISDOpcodes.h b/llvm/include/llvm/CodeGen/ISDOpcodes.h
index 465e4a0a9d0d8..916f277846a3f 100644
--- a/llvm/include/llvm/CodeGen/ISDOpcodes.h
+++ b/llvm/include/llvm/CodeGen/ISDOpcodes.h
@@ -121,6 +121,11 @@ enum NodeType {
/// function calling this intrinsic.
SPONENTRY,
+ /// STACKADDR - Represents the llvm.stackaddr intrinsic. Takes no argument
+ /// and returns the starting address of the stack region that may be used
+ /// by called functions.
+ STACKADDR,
+
/// LOCAL_RECOVER - Represents the llvm.localrecover intrinsic.
/// Materializes the offset from the local object pointer of another
/// function to a particular local object passed to llvm.localescape. The
diff --git a/llvm/include/llvm/IR/Intrinsics.td b/llvm/include/llvm/IR/Intrinsics.td
index bd6f94ac1286c..42f73e67e5896 100644
--- a/llvm/include/llvm/IR/Intrinsics.td
+++ b/llvm/include/llvm/IR/Intrinsics.td
@@ -853,6 +853,7 @@ def int_addressofreturnaddress : DefaultAttrsIntrinsic<[llvm_anyptr_ty], [], [In
def int_frameaddress : DefaultAttrsIntrinsic<[llvm_anyptr_ty], [llvm_i32_ty],
[IntrNoMem, ImmArg<ArgIndex<0>>]>;
def int_sponentry : DefaultAttrsIntrinsic<[llvm_anyptr_ty], [], [IntrNoMem]>;
+def int_stackaddress : DefaultAttrsIntrinsic<[llvm_anyptr_ty], [], []>;
def int_read_register : DefaultAttrsIntrinsic<[llvm_anyint_ty], [llvm_metadata_ty],
[IntrReadMem], "llvm.read_register">;
def int_write_register : Intrinsic<[], [llvm_metadata_ty, llvm_anyint_ty],
diff --git a/llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp
index 528136a55f14a..8ee85211da7bf 100644
--- a/llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp
@@ -1120,6 +1120,7 @@ void SelectionDAGLegalize::LegalizeOp(SDNode *Node) {
case ISD::ADJUST_TRAMPOLINE:
case ISD::FRAMEADDR:
case ISD::RETURNADDR:
+ case ISD::STACKADDR:
case ISD::ADDROFRETURNADDR:
case ISD::SPONENTRY:
// These operations lie about being legal: when they claim to be legal,
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
index ecd1ff87e7fbc..82548fb87abc5 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
@@ -6522,6 +6522,12 @@ void SelectionDAGBuilder::visitIntrinsicCall(const CallInst &I,
TLI.getFrameIndexTy(DAG.getDataLayout()),
getValue(I.getArgOperand(0))));
return;
+ case Intrinsic::stackaddress: {
+ setValue(&I,
+ DAG.getNode(ISD::STACKADDR, sdl,
+ TLI.getValueType(DAG.getDataLayout(), I.getType())));
+ return;
+ }
case Intrinsic::read_volatile_register:
case Intrinsic::read_register: {
Value *Reg = I.getArgOperand(0);
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp
index 7fc15581c17e4..d29f50319694c 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp
@@ -148,6 +148,7 @@ std::string SDNode::getOperationName(const SelectionDAG *G) const {
case ISD::ADDROFRETURNADDR: return "ADDROFRETURNADDR";
case ISD::FRAMEADDR: return "FRAMEADDR";
case ISD::SPONENTRY: return "SPONENTRY";
+ case ISD::STACKADDR: return "STACKADDR";
case ISD::LOCAL_RECOVER: return "LOCAL_RECOVER";
case ISD::READ_REGISTER: return "READ_REGISTER";
case ISD::WRITE_REGISTER: return "WRITE_REGISTER";
diff --git a/llvm/lib/Target/X86/X86ISelLowering.cpp b/llvm/lib/Target/X86/X86ISelLowering.cpp
index 347ba1262b66b..7d3938154ecbc 100644
--- a/llvm/lib/Target/X86/X86ISelLowering.cpp
+++ b/llvm/lib/Target/X86/X86ISelLowering.cpp
@@ -28274,6 +28274,13 @@ SDValue X86TargetLowering::LowerFRAMEADDR(SDValue Op, SelectionDAG &DAG) const {
return FrameAddr;
}
+SDValue X86TargetLowering::LowerSTACKADDR(SDValue Op, SelectionDAG &DAG) const {
+ SDLoc dl(Op);
+ return DAG.getCopyFromReg(DAG.getEntryNode(), dl,
+ Subtarget.getRegisterInfo()->getStackRegister(),
+ Op->getValueType(0));
+}
+
// FIXME? Maybe this could be a TableGen attribute on some registers and
// this table could be generated automatically from RegInfo.
Register X86TargetLowering::getRegisterByName(const char* RegName, LLT VT,
@@ -33637,6 +33644,7 @@ SDValue X86TargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const {
case ISD::RETURNADDR: return LowerRETURNADDR(Op, DAG);
case ISD::ADDROFRETURNADDR: return LowerADDROFRETURNADDR(Op, DAG);
case ISD::FRAMEADDR: return LowerFRAMEADDR(Op, DAG);
+ case ISD::STACKADDR: return LowerSTACKADDR(Op, DAG);
case ISD::FRAME_TO_ARGS_OFFSET:
return LowerFRAME_TO_ARGS_OFFSET(Op, DAG);
case ISD::DYNAMIC_STACKALLOC: return LowerDYNAMIC_STACKALLOC(Op, DAG);
diff --git a/llvm/lib/Target/X86/X86ISelLowering.h b/llvm/lib/Target/X86/X86ISelLowering.h
index 5cb6b3e493a32..f7856cc4f0fd7 100644
--- a/llvm/lib/Target/X86/X86ISelLowering.h
+++ b/llvm/lib/Target/X86/X86ISelLowering.h
@@ -1771,6 +1771,7 @@ namespace llvm {
SDValue LowerRETURNADDR(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerADDROFRETURNADDR(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerFRAMEADDR(SDValue Op, SelectionDAG &DAG) const;
+ SDValue LowerSTACKADDR(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerFRAME_TO_ARGS_OFFSET(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerEH_RETURN(SDValue Op, SelectionDAG &DAG) const;
SDValue lowerEH_SJLJ_SETJMP(SDValue Op, SelectionDAG &DAG) const;
>From 0b5e0edc061239d8ea99f1d64034f542ea17aeaf Mon Sep 17 00:00:00 2001
From: moorabbit <moorabbit at proton.me>
Date: Wed, 16 Jul 2025 16:07:59 -0400
Subject: [PATCH 02/15] [LLVM] Document 'llvm.stackaddress' Intrinsic
---
llvm/docs/LangRef.rst | 30 ++++++++++++++++++++++++++++++
1 file changed, 30 insertions(+)
diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst
index d2a1821efd698..ca8b5f40a3f9f 100644
--- a/llvm/docs/LangRef.rst
+++ b/llvm/docs/LangRef.rst
@@ -14295,6 +14295,36 @@ Semantics:
Note this intrinsic is only verified on AArch64 and ARM.
+'``llvm.stackaddress``' Intrinsic
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Syntax:
+"""""""
+
+::
+
+ declare ptr @llvm.stackaddress()
+
+Overview:
+"""""""""
+
+The '``llvm.stackaddress``' instrinsic returns the starting address of the stack region that may be
+used by called functions.
+
+Semantics:
+""""""""""
+
+This intrinsic returns the *logical* value of the stack pointer register, that is, the address
+separating the stack space of the current function from the stack space that may be modified by
+called functions.
+
+On certain targets (e.g. x86), the logical and actual (or physical) values of the stack pointer
+register are the same. However, on other architectures (e.g. SPARCv9), the logical value of the
+stack pointer register may differ from the physical value. '``llvm.stackaddress``' handles this
+discrepancy and returns the correct boundary address.
+
+**Note**: This intrinsic is currently only implemented for x86 and x86-64.
+
'``llvm.frameaddress``' Intrinsic
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>From 2b8084a029796b97749b16ed2adc6807a5ccdc67 Mon Sep 17 00:00:00 2001
From: moorabbit <moorabbit at proton.me>
Date: Thu, 17 Jul 2025 11:05:35 -0400
Subject: [PATCH 03/15] [LLVM] Correct minor typo in a comment
---
llvm/include/llvm/CodeGen/ISDOpcodes.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/llvm/include/llvm/CodeGen/ISDOpcodes.h b/llvm/include/llvm/CodeGen/ISDOpcodes.h
index 916f277846a3f..15f21d74bf5b5 100644
--- a/llvm/include/llvm/CodeGen/ISDOpcodes.h
+++ b/llvm/include/llvm/CodeGen/ISDOpcodes.h
@@ -121,7 +121,7 @@ enum NodeType {
/// function calling this intrinsic.
SPONENTRY,
- /// STACKADDR - Represents the llvm.stackaddr intrinsic. Takes no argument
+ /// STACKADDR - Represents the llvm.stackaddress intrinsic. Takes no argument
/// and returns the starting address of the stack region that may be used
/// by called functions.
STACKADDR,
>From 020909e04f8baf91e45863f405dd1d81449355e3 Mon Sep 17 00:00:00 2001
From: moorabbit <moorabbit at proton.me>
Date: Sat, 19 Jul 2025 11:21:38 -0400
Subject: [PATCH 04/15] [LLVM] Change SelectionDAG Opcode name
---
llvm/include/llvm/CodeGen/ISDOpcodes.h | 8 ++++----
llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp | 2 +-
llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp | 2 +-
llvm/lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp | 2 +-
llvm/lib/Target/X86/X86ISelLowering.cpp | 5 +++--
llvm/lib/Target/X86/X86ISelLowering.h | 2 +-
6 files changed, 11 insertions(+), 10 deletions(-)
diff --git a/llvm/include/llvm/CodeGen/ISDOpcodes.h b/llvm/include/llvm/CodeGen/ISDOpcodes.h
index 15f21d74bf5b5..4705710d035ff 100644
--- a/llvm/include/llvm/CodeGen/ISDOpcodes.h
+++ b/llvm/include/llvm/CodeGen/ISDOpcodes.h
@@ -121,10 +121,10 @@ enum NodeType {
/// function calling this intrinsic.
SPONENTRY,
- /// STACKADDR - Represents the llvm.stackaddress intrinsic. Takes no argument
- /// and returns the starting address of the stack region that may be used
- /// by called functions.
- STACKADDR,
+ /// STACKADDRESS - Represents the llvm.stackaddress intrinsic. Takes no
+ /// argument and returns the starting address of the stack region that may be
+ /// used by called functions.
+ STACKADDRESS,
/// LOCAL_RECOVER - Represents the llvm.localrecover intrinsic.
/// Materializes the offset from the local object pointer of another
diff --git a/llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp
index 8ee85211da7bf..8fbdd73923de9 100644
--- a/llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp
@@ -1120,7 +1120,7 @@ void SelectionDAGLegalize::LegalizeOp(SDNode *Node) {
case ISD::ADJUST_TRAMPOLINE:
case ISD::FRAMEADDR:
case ISD::RETURNADDR:
- case ISD::STACKADDR:
+ case ISD::STACKADDRESS:
case ISD::ADDROFRETURNADDR:
case ISD::SPONENTRY:
// These operations lie about being legal: when they claim to be legal,
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
index 82548fb87abc5..54f530e3ea397 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
@@ -6524,7 +6524,7 @@ void SelectionDAGBuilder::visitIntrinsicCall(const CallInst &I,
return;
case Intrinsic::stackaddress: {
setValue(&I,
- DAG.getNode(ISD::STACKADDR, sdl,
+ DAG.getNode(ISD::STACKADDRESS, sdl,
TLI.getValueType(DAG.getDataLayout(), I.getType())));
return;
}
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp
index d29f50319694c..3a62bf835f5b6 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp
@@ -148,7 +148,7 @@ std::string SDNode::getOperationName(const SelectionDAG *G) const {
case ISD::ADDROFRETURNADDR: return "ADDROFRETURNADDR";
case ISD::FRAMEADDR: return "FRAMEADDR";
case ISD::SPONENTRY: return "SPONENTRY";
- case ISD::STACKADDR: return "STACKADDR";
+ case ISD::STACKADDRESS: return "STACKADDRESS";
case ISD::LOCAL_RECOVER: return "LOCAL_RECOVER";
case ISD::READ_REGISTER: return "READ_REGISTER";
case ISD::WRITE_REGISTER: return "WRITE_REGISTER";
diff --git a/llvm/lib/Target/X86/X86ISelLowering.cpp b/llvm/lib/Target/X86/X86ISelLowering.cpp
index 7d3938154ecbc..099ae4b8dfffc 100644
--- a/llvm/lib/Target/X86/X86ISelLowering.cpp
+++ b/llvm/lib/Target/X86/X86ISelLowering.cpp
@@ -28274,7 +28274,8 @@ SDValue X86TargetLowering::LowerFRAMEADDR(SDValue Op, SelectionDAG &DAG) const {
return FrameAddr;
}
-SDValue X86TargetLowering::LowerSTACKADDR(SDValue Op, SelectionDAG &DAG) const {
+SDValue X86TargetLowering::LowerSTACKADDRESS(SDValue Op,
+ SelectionDAG &DAG) const {
SDLoc dl(Op);
return DAG.getCopyFromReg(DAG.getEntryNode(), dl,
Subtarget.getRegisterInfo()->getStackRegister(),
@@ -33644,7 +33645,7 @@ SDValue X86TargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const {
case ISD::RETURNADDR: return LowerRETURNADDR(Op, DAG);
case ISD::ADDROFRETURNADDR: return LowerADDROFRETURNADDR(Op, DAG);
case ISD::FRAMEADDR: return LowerFRAMEADDR(Op, DAG);
- case ISD::STACKADDR: return LowerSTACKADDR(Op, DAG);
+ case ISD::STACKADDRESS: return LowerSTACKADDRESS(Op, DAG);
case ISD::FRAME_TO_ARGS_OFFSET:
return LowerFRAME_TO_ARGS_OFFSET(Op, DAG);
case ISD::DYNAMIC_STACKALLOC: return LowerDYNAMIC_STACKALLOC(Op, DAG);
diff --git a/llvm/lib/Target/X86/X86ISelLowering.h b/llvm/lib/Target/X86/X86ISelLowering.h
index f7856cc4f0fd7..b08ba58cd4a78 100644
--- a/llvm/lib/Target/X86/X86ISelLowering.h
+++ b/llvm/lib/Target/X86/X86ISelLowering.h
@@ -1771,7 +1771,7 @@ namespace llvm {
SDValue LowerRETURNADDR(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerADDROFRETURNADDR(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerFRAMEADDR(SDValue Op, SelectionDAG &DAG) const;
- SDValue LowerSTACKADDR(SDValue Op, SelectionDAG &DAG) const;
+ SDValue LowerSTACKADDRESS(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerFRAME_TO_ARGS_OFFSET(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerEH_RETURN(SDValue Op, SelectionDAG &DAG) const;
SDValue lowerEH_SJLJ_SETJMP(SDValue Op, SelectionDAG &DAG) const;
>From 88db438e9f35cde48f1799126f8fe2127eefb950 Mon Sep 17 00:00:00 2001
From: moorabbit <moorabbit at proton.me>
Date: Sun, 20 Jul 2025 19:36:49 -0400
Subject: [PATCH 05/15] [Clang] Refactor test case
---
.../Sema/builtin-stackaddress-target-support.c | 18 ++++++------------
1 file changed, 6 insertions(+), 12 deletions(-)
diff --git a/clang/test/Sema/builtin-stackaddress-target-support.c b/clang/test/Sema/builtin-stackaddress-target-support.c
index aab077ea558f8..2732fd310998c 100644
--- a/clang/test/Sema/builtin-stackaddress-target-support.c
+++ b/clang/test/Sema/builtin-stackaddress-target-support.c
@@ -1,16 +1,10 @@
-// RUN: %clang_cc1 -verify %s -triple x86_64-unknown-unknown -DTEST_x64
-// RUN: %clang_cc1 -verify %s -triple i386-unknown-unknown -DTEST_x86
-// RUN: %clang_cc1 -verify %s -triple riscv32-unknown-unknown -DTEST_riscv32
-// RUN: %clang_cc1 -verify %s -triple riscv64-unknown-unknown -DTEST_riscv64
-// RUN: %clang_cc1 -verify %s -triple aarch64-unknown-unknown -DTEST_aarch64
+// RUN: %clang_cc1 -verify=x86 %s -triple x86_64-unknown-unknown
+// RUN: %clang_cc1 -verify=x86 %s -triple i386-unknown-unknown
+// RUN: %clang_cc1 -verify %s -triple riscv32-unknown-unknown
+// RUN: %clang_cc1 -verify %s -triple riscv64-unknown-unknown
+// RUN: %clang_cc1 -verify %s -triple aarch64-unknown-unknown
-#if defined(TEST_x64) || defined(TEST_x86)
-// expected-no-diagnostics
-void *a() {
-return __builtin_stack_address();
-}
-#else
void *a() {
return __builtin_stack_address(); // expected-error {{builtin is not supported on this target}}
+ // x86-no-diagnostics
}
-#endif
>From 06691801bd44ef5c57c1250ffb9a97394fb0247d Mon Sep 17 00:00:00 2001
From: moorabbit <moorabbit at proton.me>
Date: Sun, 20 Jul 2025 19:45:19 -0400
Subject: [PATCH 06/15] [Clang] Code formatting
---
clang/test/Sema/builtin-stackaddress-target-support.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang/test/Sema/builtin-stackaddress-target-support.c b/clang/test/Sema/builtin-stackaddress-target-support.c
index 2732fd310998c..f7c8acb77c8ae 100644
--- a/clang/test/Sema/builtin-stackaddress-target-support.c
+++ b/clang/test/Sema/builtin-stackaddress-target-support.c
@@ -4,7 +4,7 @@
// RUN: %clang_cc1 -verify %s -triple riscv64-unknown-unknown
// RUN: %clang_cc1 -verify %s -triple aarch64-unknown-unknown
+// x86-no-diagnostics
void *a() {
return __builtin_stack_address(); // expected-error {{builtin is not supported on this target}}
- // x86-no-diagnostics
}
>From 20d025914864248df4cc9a0e663556a2f20025c9 Mon Sep 17 00:00:00 2001
From: moorabbit <moorabbit at proton.me>
Date: Mon, 18 Aug 2025 08:07:40 -0400
Subject: [PATCH 07/15] Disable custom lowering of STACKADDRESS on x86
---
llvm/lib/Target/X86/X86ISelLowering.cpp | 9 ---------
llvm/lib/Target/X86/X86ISelLowering.h | 1 -
2 files changed, 10 deletions(-)
diff --git a/llvm/lib/Target/X86/X86ISelLowering.cpp b/llvm/lib/Target/X86/X86ISelLowering.cpp
index 9e5308a0f3bcd..7a816de53dbd3 100644
--- a/llvm/lib/Target/X86/X86ISelLowering.cpp
+++ b/llvm/lib/Target/X86/X86ISelLowering.cpp
@@ -28310,14 +28310,6 @@ SDValue X86TargetLowering::LowerFRAMEADDR(SDValue Op, SelectionDAG &DAG) const {
return FrameAddr;
}
-SDValue X86TargetLowering::LowerSTACKADDRESS(SDValue Op,
- SelectionDAG &DAG) const {
- SDLoc dl(Op);
- return DAG.getCopyFromReg(DAG.getEntryNode(), dl,
- Subtarget.getRegisterInfo()->getStackRegister(),
- Op->getValueType(0));
-}
-
// FIXME? Maybe this could be a TableGen attribute on some registers and
// this table could be generated automatically from RegInfo.
Register X86TargetLowering::getRegisterByName(const char* RegName, LLT VT,
@@ -33671,7 +33663,6 @@ SDValue X86TargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const {
case ISD::RETURNADDR: return LowerRETURNADDR(Op, DAG);
case ISD::ADDROFRETURNADDR: return LowerADDROFRETURNADDR(Op, DAG);
case ISD::FRAMEADDR: return LowerFRAMEADDR(Op, DAG);
- case ISD::STACKADDRESS: return LowerSTACKADDRESS(Op, DAG);
case ISD::FRAME_TO_ARGS_OFFSET:
return LowerFRAME_TO_ARGS_OFFSET(Op, DAG);
case ISD::DYNAMIC_STACKALLOC: return LowerDYNAMIC_STACKALLOC(Op, DAG);
diff --git a/llvm/lib/Target/X86/X86ISelLowering.h b/llvm/lib/Target/X86/X86ISelLowering.h
index 618f0389a05d1..3dd79b3249517 100644
--- a/llvm/lib/Target/X86/X86ISelLowering.h
+++ b/llvm/lib/Target/X86/X86ISelLowering.h
@@ -1774,7 +1774,6 @@ namespace llvm {
SDValue LowerRETURNADDR(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerADDROFRETURNADDR(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerFRAMEADDR(SDValue Op, SelectionDAG &DAG) const;
- SDValue LowerSTACKADDRESS(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerFRAME_TO_ARGS_OFFSET(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerEH_RETURN(SDValue Op, SelectionDAG &DAG) const;
SDValue lowerEH_SJLJ_SETJMP(SDValue Op, SelectionDAG &DAG) const;
>From da684903c5fd9b459d70a689da72860b5da9ac1f Mon Sep 17 00:00:00 2001
From: moorabbit <moorabbit at proton.me>
Date: Mon, 18 Aug 2025 08:26:27 -0400
Subject: [PATCH 08/15] Expand STACKADDRESS to STACKSAVE by default
---
llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp | 3 ++-
.../lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp | 12 +++++-------
llvm/lib/CodeGen/TargetLoweringBase.cpp | 4 ++++
3 files changed, 11 insertions(+), 8 deletions(-)
diff --git a/llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp
index a1b960ed51cbe..357cfc333b921 100644
--- a/llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp
@@ -1012,6 +1012,7 @@ void SelectionDAGLegalize::LegalizeOp(SDNode *Node) {
case ISD::INTRINSIC_WO_CHAIN:
case ISD::INTRINSIC_VOID:
case ISD::STACKSAVE:
+ case ISD::STACKADDRESS:
Action = TLI.getOperationAction(Node->getOpcode(), MVT::Other);
break;
case ISD::GET_DYNAMIC_AREA_OFFSET:
@@ -1127,7 +1128,6 @@ void SelectionDAGLegalize::LegalizeOp(SDNode *Node) {
case ISD::ADJUST_TRAMPOLINE:
case ISD::FRAMEADDR:
case ISD::RETURNADDR:
- case ISD::STACKADDRESS:
case ISD::ADDROFRETURNADDR:
case ISD::SPONENTRY:
// These operations lie about being legal: when they claim to be legal,
@@ -3681,6 +3681,7 @@ bool SelectionDAGLegalize::ExpandNode(SDNode *Node) {
Results.push_back(Tmp1);
break;
}
+ case ISD::STACKADDRESS:
case ISD::STACKSAVE:
// Expand to CopyFromReg if the target set
// StackPointerRegisterToSaveRestore.
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
index 18e17ff5f08e5..da3debc7575bb 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
@@ -6537,12 +6537,6 @@ void SelectionDAGBuilder::visitIntrinsicCall(const CallInst &I,
TLI.getFrameIndexTy(DAG.getDataLayout()),
getValue(I.getArgOperand(0))));
return;
- case Intrinsic::stackaddress: {
- setValue(&I,
- DAG.getNode(ISD::STACKADDRESS, sdl,
- TLI.getValueType(DAG.getDataLayout(), I.getType())));
- return;
- }
case Intrinsic::read_volatile_register:
case Intrinsic::read_register: {
Value *Reg = I.getArgOperand(0);
@@ -7332,10 +7326,14 @@ void SelectionDAGBuilder::visitIntrinsicCall(const CallInst &I,
setValue(&I, DAG.getNode(ISD::UCMP, sdl, DestVT, Op1, Op2));
break;
}
+ case Intrinsic::stackaddress:
case Intrinsic::stacksave: {
+ unsigned SDOpcode = Intrinsic == Intrinsic::stackaddress
+ ? ISD::STACKADDRESS
+ : ISD::STACKSAVE;
SDValue Op = getRoot();
EVT VT = TLI.getValueType(DAG.getDataLayout(), I.getType());
- Res = DAG.getNode(ISD::STACKSAVE, sdl, DAG.getVTList(VT, MVT::Other), Op);
+ Res = DAG.getNode(SDOpcode, sdl, DAG.getVTList(VT, MVT::Other), Op);
setValue(&I, Res);
DAG.setRoot(Res.getValue(1));
return;
diff --git a/llvm/lib/CodeGen/TargetLoweringBase.cpp b/llvm/lib/CodeGen/TargetLoweringBase.cpp
index 350948a92a3ae..6c9a17fd27fa0 100644
--- a/llvm/lib/CodeGen/TargetLoweringBase.cpp
+++ b/llvm/lib/CodeGen/TargetLoweringBase.cpp
@@ -956,6 +956,10 @@ void TargetLoweringBase::initActions() {
// This one by default will call __clear_cache unless the target
// wants something different.
setOperationAction(ISD::CLEAR_CACHE, MVT::Other, LibCall);
+
+ // By default, STACKADDRESS nodes are expanded to STACKSAVE nodes.
+ // On SPARC targets, custom lowering is required.
+ setOperationAction(ISD::STACKADDRESS, MVT::Other, Expand);
}
MVT TargetLoweringBase::getScalarShiftAmountTy(const DataLayout &DL,
>From 6cdcf583d7c26126de334d333aa1cc2df804890a Mon Sep 17 00:00:00 2001
From: moorabbit <moorabbit at proton.me>
Date: Mon, 18 Aug 2025 08:41:34 -0400
Subject: [PATCH 09/15] Custom lowering of STACKADDRESS on Sparc
---
llvm/lib/Target/Sparc/SparcISelLowering.cpp | 25 +++++++++++++++++++++
1 file changed, 25 insertions(+)
diff --git a/llvm/lib/Target/Sparc/SparcISelLowering.cpp b/llvm/lib/Target/Sparc/SparcISelLowering.cpp
index dd221327dbdc6..f0fe55cf1eb24 100644
--- a/llvm/lib/Target/Sparc/SparcISelLowering.cpp
+++ b/llvm/lib/Target/Sparc/SparcISelLowering.cpp
@@ -1861,6 +1861,7 @@ SparcTargetLowering::SparcTargetLowering(const TargetMachine &TM,
setOperationAction(ISD::STACKSAVE , MVT::Other, Expand);
setOperationAction(ISD::STACKRESTORE , MVT::Other, Expand);
setOperationAction(ISD::DYNAMIC_STACKALLOC, MVT::i32 , Custom);
+ setOperationAction(ISD::STACKADDRESS , MVT::Other, Custom);
setStackPointerRegisterToSaveRestore(SP::O6);
@@ -2720,6 +2721,29 @@ static SDValue LowerVAARG(SDValue Op, SelectionDAG &DAG) {
Align(std::min(PtrVT.getFixedSizeInBits(), VT.getFixedSizeInBits()) / 8));
}
+static SDValue LowerSTACKADDRESS(SDValue Op, SelectionDAG &DAG,
+ const SparcSubtarget *Subtarget) {
+ SDValue Chain = Op.getOperand(0);
+ EVT VT = Op->getValueType(0);
+ SDLoc DL(Op);
+ unsigned OffsetToStackStart = 0;
+
+ unsigned SPReg = SP::O6;
+ SDValue SP = DAG.getCopyFromReg(Chain, DL, SPReg, VT);
+
+ // Unbias the stack pointer register.
+ OffsetToStackStart += Subtarget->getStackPointerBias();
+ // Move past the register save area: 8 in registers + 8 local registers.
+ OffsetToStackStart += 16 * (Subtarget->is64Bit() ? 8 : 4);
+ // Move past the struct return address slot (4 bytes) on SPARC 32-bit.
+ if (!Subtarget->is64Bit()) {
+ OffsetToStackStart += 4;
+ }
+
+ SDValue StackAddr = DAG.getNode(ISD::ADD, DL, VT, SP, DAG.getConstant(OffsetToStackStart, DL, VT));
+ return DAG.getMergeValues({StackAddr, Chain}, DL);
+}
+
static SDValue LowerDYNAMIC_STACKALLOC(SDValue Op, SelectionDAG &DAG,
const SparcSubtarget *Subtarget) {
SDValue Chain = Op.getOperand(0);
@@ -3117,6 +3141,7 @@ LowerOperation(SDValue Op, SelectionDAG &DAG) const {
case ISD::VAARG: return LowerVAARG(Op, DAG);
case ISD::DYNAMIC_STACKALLOC: return LowerDYNAMIC_STACKALLOC(Op, DAG,
Subtarget);
+ case ISD::STACKADDRESS: return LowerSTACKADDRESS(Op, DAG, Subtarget);
case ISD::LOAD: return LowerLOAD(Op, DAG);
case ISD::STORE: return LowerSTORE(Op, DAG);
>From c56be289db54e78f38ccc72558c2bb58337450b8 Mon Sep 17 00:00:00 2001
From: moorabbit <moorabbit at proton.me>
Date: Mon, 18 Aug 2025 09:22:57 -0400
Subject: [PATCH 10/15] Remove Target check from Sema
---
clang/lib/Sema/SemaChecking.cpp | 9 ---------
1 file changed, 9 deletions(-)
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index cf0f7f2182f8a..2dc4ee74dc9df 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -2960,15 +2960,6 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
break;
}
- case Builtin::BI__builtin_stack_address: {
- if (CheckBuiltinTargetInSupported(
- *this, TheCall,
- /*SupportedArchs=*/{llvm::Triple::x86_64, llvm::Triple::x86})) {
- return ExprError();
- }
- break;
- }
-
case Builtin::BI__builtin_nondeterministic_value: {
if (BuiltinNonDeterministicValue(TheCall))
return ExprError();
>From 1ed8a5d4051ee95d6dcb79ae71b20bde2e6ecaca Mon Sep 17 00:00:00 2001
From: moorabbit <moorabbit at proton.me>
Date: Tue, 19 Aug 2025 07:04:33 -0400
Subject: [PATCH 11/15] clang-format
---
llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp | 5 ++---
llvm/lib/Target/Sparc/SparcISelLowering.cpp | 10 ++++++----
2 files changed, 8 insertions(+), 7 deletions(-)
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
index da3debc7575bb..fb276566036d9 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
@@ -7328,9 +7328,8 @@ void SelectionDAGBuilder::visitIntrinsicCall(const CallInst &I,
}
case Intrinsic::stackaddress:
case Intrinsic::stacksave: {
- unsigned SDOpcode = Intrinsic == Intrinsic::stackaddress
- ? ISD::STACKADDRESS
- : ISD::STACKSAVE;
+ unsigned SDOpcode = Intrinsic == Intrinsic::stackaddress ? ISD::STACKADDRESS
+ : ISD::STACKSAVE;
SDValue Op = getRoot();
EVT VT = TLI.getValueType(DAG.getDataLayout(), I.getType());
Res = DAG.getNode(SDOpcode, sdl, DAG.getVTList(VT, MVT::Other), Op);
diff --git a/llvm/lib/Target/Sparc/SparcISelLowering.cpp b/llvm/lib/Target/Sparc/SparcISelLowering.cpp
index f0fe55cf1eb24..ef5fc0154fbe0 100644
--- a/llvm/lib/Target/Sparc/SparcISelLowering.cpp
+++ b/llvm/lib/Target/Sparc/SparcISelLowering.cpp
@@ -1861,7 +1861,7 @@ SparcTargetLowering::SparcTargetLowering(const TargetMachine &TM,
setOperationAction(ISD::STACKSAVE , MVT::Other, Expand);
setOperationAction(ISD::STACKRESTORE , MVT::Other, Expand);
setOperationAction(ISD::DYNAMIC_STACKALLOC, MVT::i32 , Custom);
- setOperationAction(ISD::STACKADDRESS , MVT::Other, Custom);
+ setOperationAction(ISD::STACKADDRESS, MVT::Other, Custom);
setStackPointerRegisterToSaveRestore(SP::O6);
@@ -2734,13 +2734,14 @@ static SDValue LowerSTACKADDRESS(SDValue Op, SelectionDAG &DAG,
// Unbias the stack pointer register.
OffsetToStackStart += Subtarget->getStackPointerBias();
// Move past the register save area: 8 in registers + 8 local registers.
- OffsetToStackStart += 16 * (Subtarget->is64Bit() ? 8 : 4);
+ OffsetToStackStart += 16 * (Subtarget->is64Bit() ? 8 : 4);
// Move past the struct return address slot (4 bytes) on SPARC 32-bit.
if (!Subtarget->is64Bit()) {
OffsetToStackStart += 4;
}
- SDValue StackAddr = DAG.getNode(ISD::ADD, DL, VT, SP, DAG.getConstant(OffsetToStackStart, DL, VT));
+ SDValue StackAddr = DAG.getNode(ISD::ADD, DL, VT, SP,
+ DAG.getConstant(OffsetToStackStart, DL, VT));
return DAG.getMergeValues({StackAddr, Chain}, DL);
}
@@ -3141,7 +3142,8 @@ LowerOperation(SDValue Op, SelectionDAG &DAG) const {
case ISD::VAARG: return LowerVAARG(Op, DAG);
case ISD::DYNAMIC_STACKALLOC: return LowerDYNAMIC_STACKALLOC(Op, DAG,
Subtarget);
- case ISD::STACKADDRESS: return LowerSTACKADDRESS(Op, DAG, Subtarget);
+ case ISD::STACKADDRESS:
+ return LowerSTACKADDRESS(Op, DAG, Subtarget);
case ISD::LOAD: return LowerLOAD(Op, DAG);
case ISD::STORE: return LowerSTORE(Op, DAG);
>From 1339b31f58699119caaccf1976f4c502431fb7d3 Mon Sep 17 00:00:00 2001
From: moorabbit <moorabbit at proton.me>
Date: Tue, 19 Aug 2025 14:59:20 -0400
Subject: [PATCH 12/15] refactor test cases
---
clang/test/CodeGen/builtin-stackaddress.c | 13 ++----
.../test/CodeGenCXX/builtin-stackaddress.cpp | 40 +++++++------------
.../builtin-stackaddress-target-support.c | 10 -----
llvm/test/CodeGen/SPARC/stackaddress.ll | 16 ++++++++
4 files changed, 34 insertions(+), 45 deletions(-)
delete mode 100644 clang/test/Sema/builtin-stackaddress-target-support.c
create mode 100644 llvm/test/CodeGen/SPARC/stackaddress.ll
diff --git a/clang/test/CodeGen/builtin-stackaddress.c b/clang/test/CodeGen/builtin-stackaddress.c
index a6b44b227947d..6acc9c61d9d9b 100644
--- a/clang/test/CodeGen/builtin-stackaddress.c
+++ b/clang/test/CodeGen/builtin-stackaddress.c
@@ -1,14 +1,7 @@
-// RUN: %clang -target x86_64 -S -emit-llvm %s -o - | FileCheck %s --check-prefix=llvm
-// RUN: %clang -target x86_64 -S %s -o - | FileCheck %s --check-prefix=x64
+// RUN: %clang_cc1 -emit-llvm %s -o - | FileCheck %s
-extern void f(int, int, int, long, long, long, long, long, long, long, long);
-
-// llvm-LABEL: define {{[^@]+}} @a()
-// llvm: call {{[^@]+}} @llvm.stackaddress.p0()
-//
-// x64-LABEL: a:
-// x64: movq %rsp, %rax
+// CHECK-LABEL: define {{[^@]+}} @a()
+// CHECK: call {{[^@]+}} @llvm.stackaddress.p0()
void *a() {
- f(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11);
return __builtin_stack_address();
}
diff --git a/clang/test/CodeGenCXX/builtin-stackaddress.cpp b/clang/test/CodeGenCXX/builtin-stackaddress.cpp
index 24a949e83d9e0..ac29be44f098f 100644
--- a/clang/test/CodeGenCXX/builtin-stackaddress.cpp
+++ b/clang/test/CodeGenCXX/builtin-stackaddress.cpp
@@ -1,36 +1,26 @@
-// RUN: %clang -target x86_64 -S -emit-llvm %s -o - | llvm-cxxfilt | FileCheck %s --check-prefix=llvm
-// RUN: %clang -target x86_64 -S %s -o - | llvm-cxxfilt | FileCheck %s --check-prefix=x64
-
-extern void f(int, int, int, long, long, long, long, long, long, long, long);
+// RUN: %clang_cc1 -emit-llvm %s -o - | llvm-cxxfilt | FileCheck %s --check-prefixes=COMMON,NO-OPT
+// RUN: %clang_cc1 -emit-llvm %s -O3 -o - | llvm-cxxfilt | FileCheck %s --check-prefixes=COMMON,OPT
struct S {
void *a();
};
-// llvm-LABEL: define {{[^@]+}} @S::a()
-// llvm: call {{[^@]+}} @llvm.stackaddress.p0()
-//
-// x64-LABEL: S::a():
-// x64: movq %rsp, %rax
+// COMMON-LABEL: @S::a()
+// COMMON: call ptr @llvm.stackaddress.p0()
void *S::a() {
- void *p = __builtin_stack_address();
- f(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11);
- return p;
+ return __builtin_stack_address();
}
-// llvm-LABEL: define {{[^@]+}} @two()
-// llvm: call {{[^@]+}} @"two()::$_0::operator()() const"
-//
-// llvm-LABEL: define {{[^@]+}} @"two()::$_0::operator()() const"
-// llvm: call {{[^@]+}} @llvm.stackaddress.p0()
-//
-// x64-LABEL: two()::$_0::operator()() const:
-// x64: movq %rsp, %rax
+// COMMON-LABEL: define {{[^@]+}} @two()
void *two() {
- auto l = []() {
- void *p = __builtin_stack_address();
- f(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11);
- return p;
- };
+
+ // The compiler is allowed to inline a function calling `__builtin_stack_address`.
+ //
+ // OPT-NOT: define {{[^@]+}} @"two()::$_0::operator()() const"
+ // OPT: call {{[^@]+}} @llvm.stackaddress.p0()
+ //
+ // NO-OPT-DAG: define {{[^@]+}} @"two()::$_0::operator()() const"
+ // NO-OPT-DAG: call {{[^@]+}} @"two()::$_0::operator()() const"
+ auto l = []() { return __builtin_stack_address(); };
return l();
}
diff --git a/clang/test/Sema/builtin-stackaddress-target-support.c b/clang/test/Sema/builtin-stackaddress-target-support.c
deleted file mode 100644
index f7c8acb77c8ae..0000000000000
--- a/clang/test/Sema/builtin-stackaddress-target-support.c
+++ /dev/null
@@ -1,10 +0,0 @@
-// RUN: %clang_cc1 -verify=x86 %s -triple x86_64-unknown-unknown
-// RUN: %clang_cc1 -verify=x86 %s -triple i386-unknown-unknown
-// RUN: %clang_cc1 -verify %s -triple riscv32-unknown-unknown
-// RUN: %clang_cc1 -verify %s -triple riscv64-unknown-unknown
-// RUN: %clang_cc1 -verify %s -triple aarch64-unknown-unknown
-
-// x86-no-diagnostics
-void *a() {
-return __builtin_stack_address(); // expected-error {{builtin is not supported on this target}}
-}
diff --git a/llvm/test/CodeGen/SPARC/stackaddress.ll b/llvm/test/CodeGen/SPARC/stackaddress.ll
new file mode 100644
index 0000000000000..fce5f1cba8fb1
--- /dev/null
+++ b/llvm/test/CodeGen/SPARC/stackaddress.ll
@@ -0,0 +1,16 @@
+; RUN: llc < %s -mtriple=sparc | FileCheck --check-prefix=sparc32 %s
+; RUN: llc < %s -mtriple=sparcv9 | FileCheck --check-prefix=sparc64 %s
+
+declare ptr @llvm.stackaddress.p0()
+
+define ptr @test() {
+; sparc32: save %sp, -96, %sp
+; sparc32: ret
+; sparc32: restore %sp, 68, %o0
+;
+; sparc64: save %sp, -128, %sp
+; sparc64: ret
+; sparc64: restore %sp, 2175, %o0
+ %sp = call ptr @llvm.stackaddress.p0()
+ ret ptr %sp
+}
>From 64eb4ad819086079b8cdef89fb2d06a4970420c8 Mon Sep 17 00:00:00 2001
From: moorabbit <moorabbit at proton.me>
Date: Tue, 19 Aug 2025 15:01:54 -0400
Subject: [PATCH 13/15] AaronBallman's suggestion
Co-authored-by: Aaron Ballman <aaron at aaronballman.com>
---
clang/test/Sema/builtin-stackaddress.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/clang/test/Sema/builtin-stackaddress.c b/clang/test/Sema/builtin-stackaddress.c
index 03a0f5ef16714..f95751daf8a01 100644
--- a/clang/test/Sema/builtin-stackaddress.c
+++ b/clang/test/Sema/builtin-stackaddress.c
@@ -38,6 +38,6 @@ return __builtin_frame_address(0xFFFFF);
}
void *i() {
-// expected-error at +1 {{too many arguments to function call, expected 0, have 1}}
-return __builtin_stack_address(0);
+ // expected-error at +1 {{too many arguments to function call, expected 0, have 1}}
+ return __builtin_stack_address(0);
}
>From 7c3838178359f25376fce18f4051bf8ccc7176a5 Mon Sep 17 00:00:00 2001
From: moorabbit <moorabbit at proton.me>
Date: Tue, 19 Aug 2025 16:37:07 -0400
Subject: [PATCH 14/15] Fix windows CI failure
---
clang/test/CodeGenCXX/builtin-stackaddress.cpp | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/clang/test/CodeGenCXX/builtin-stackaddress.cpp b/clang/test/CodeGenCXX/builtin-stackaddress.cpp
index ac29be44f098f..20940d98a304e 100644
--- a/clang/test/CodeGenCXX/builtin-stackaddress.cpp
+++ b/clang/test/CodeGenCXX/builtin-stackaddress.cpp
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -emit-llvm %s -o - | llvm-cxxfilt | FileCheck %s --check-prefixes=COMMON,NO-OPT
-// RUN: %clang_cc1 -emit-llvm %s -O3 -o - | llvm-cxxfilt | FileCheck %s --check-prefixes=COMMON,OPT
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm %s -o - | llvm-cxxfilt | FileCheck %s --check-prefixes=COMMON,NO-OPT
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm %s -O3 -o - | llvm-cxxfilt | FileCheck %s --check-prefixes=COMMON,OPT
struct S {
void *a();
>From d47cb56c1acb5be138b18c00f144680e067a4c9c Mon Sep 17 00:00:00 2001
From: moorabbit <moorabbit at proton.me>
Date: Wed, 27 Aug 2025 15:40:43 -0400
Subject: [PATCH 15/15] efriedma-quic's comment
---
llvm/docs/LangRef.rst | 2 --
llvm/test/CodeGen/ARM/stackaddress.ll | 14 ++++++++++++++
llvm/test/CodeGen/X86/stackaddress.ll | 14 ++++++++++++++
3 files changed, 28 insertions(+), 2 deletions(-)
create mode 100644 llvm/test/CodeGen/ARM/stackaddress.ll
create mode 100644 llvm/test/CodeGen/X86/stackaddress.ll
diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst
index 753514f4f5559..1d1dd2a59c7aa 100644
--- a/llvm/docs/LangRef.rst
+++ b/llvm/docs/LangRef.rst
@@ -14417,8 +14417,6 @@ register are the same. However, on other architectures (e.g. SPARCv9), the logic
stack pointer register may differ from the physical value. '``llvm.stackaddress``' handles this
discrepancy and returns the correct boundary address.
-**Note**: This intrinsic is currently only implemented for x86 and x86-64.
-
'``llvm.frameaddress``' Intrinsic
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/llvm/test/CodeGen/ARM/stackaddress.ll b/llvm/test/CodeGen/ARM/stackaddress.ll
new file mode 100644
index 0000000000000..e2fc0926cd143
--- /dev/null
+++ b/llvm/test/CodeGen/ARM/stackaddress.ll
@@ -0,0 +1,14 @@
+; RUN: llc < %s -mtriple=armv7 | FileCheck %s --check-prefix=armv7
+; RUN: llc < %s -mtriple=aarch64 | FileCheck %s --check-prefix=aarch64
+
+declare ptr @llvm.stackaddress.p0()
+
+define ptr @test() {
+; armv7: mov r0, sp
+; armv7: bx lr
+
+; aarch64: mov x0, sp
+; aarch64: ret
+ %sp = call ptr @llvm.stackaddress.p0()
+ ret ptr %sp
+}
diff --git a/llvm/test/CodeGen/X86/stackaddress.ll b/llvm/test/CodeGen/X86/stackaddress.ll
new file mode 100644
index 0000000000000..6d73b2ec82c22
--- /dev/null
+++ b/llvm/test/CodeGen/X86/stackaddress.ll
@@ -0,0 +1,14 @@
+; RUN: llc < %s -mtriple=x86_64-linux-gnu -o - | FileCheck --check-prefix=x86_64 %s
+; RUN: llc < %s -mtriple=i386-linux-gnu -o - | FileCheck --check-prefix=i386 %s
+
+declare ptr @llvm.stackaddress.p0()
+
+define ptr @test() {
+; x86_64: movq %rsp, %rax
+; x86_64: retq
+
+; i386: movl %esp, %eax
+; i386: retl
+ %sp = call ptr @llvm.stackaddress.p0()
+ ret ptr %sp
+}
More information about the llvm-commits
mailing list