-
Notifications
You must be signed in to change notification settings - Fork 14.9k
[Clang] Add __builtin_stack_address
#148281
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
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 llvm#82632
Thank you for submitting a Pull Request (PR) to the LLVM Project! This PR will be automatically labeled and the relevant teams will be notified. If you wish to, you can add reviewers by using the "Reviewers" section on this page. If this is not working for you, it is probably because you do not have write permissions for the repository. In which case you can instead tag reviewers by name in a comment by using If you have received no comments on your PR for a week, you can request a review by "ping"ing the PR by adding a comment “Ping”. The common courtesy "ping" rate is once a week. Please remember that you are asking for valuable time from other developers. If you have further questions, they may be answered by the LLVM GitHub User Guide. You can also ask questions in a comment on this PR, on the LLVM Discord or on the forums. |
@llvm/pr-subscribers-backend-x86 @llvm/pr-subscribers-llvm-selectiondag Author: None (moorabbit) ChangesAdd support for
This PR only adds support for the following architectures: x86 - x86_64. Support for other architectures can be added in future patches. Fixes #82632 Full diff: https://github.com/llvm/llvm-project/pull/148281.diff 16 Files Affected:
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@+1 {{argument value 1048575 is outside the valid range [0, 65535]}}
return __builtin_frame_address(0xFFFFF);
}
+
+void *i() {
+// expected-error@+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;
|
|
/// 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, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Names don't match the actual intrinsic
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in a new commit, thanks.
Ping. |
1 similar comment
Ping. |
// expected-error@+1 {{too many arguments to function call, expected 0, have 1}} | ||
return __builtin_stack_address(0); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// expected-error@+1 {{too many arguments to function call, expected 0, have 1}} | |
return __builtin_stack_address(0); | |
// expected-error@+1 {{too many arguments to function call, expected 0, have 1}} | |
return __builtin_stack_address(0); |
Other test cases I would like to see are:
// As a global variable where there is no stack address to get.
// This should be diagnosed as an error?
void *ptr = __builtin_stack_address();
inline void *what() {
return __builtin_stack_address();
}
void func() {
void *ptr = what(); // Is this getting the stack address of? The inline function or is it getting the stack address of the caller? Or depends on optimization level?
}
Should we also have tests for what happens with naked functions or other kind of odd situations where the stack may be different from the normal case?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// As a global variable where there is no stack address to get.
// This should be diagnosed as an error?
void *ptr = __builtin_stack_address();
It looks like GCC doesn't diagnose this as an error (https://godbolt.org/z/x35e114de) and returns the stack address of the initialization function. I'm not sure if it's intended or not.
Should we still diagnose this as an error?
Should we also have tests for what happens with naked functions or other kind of odd situations where the stack may be different from the normal case?
Noted, will add them, thanks!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// As a global variable where there is no stack address to get.
// This should be diagnosed as an error?
void *ptr = __builtin_stack_address();It looks like GCC doesn't diagnose this as an error (https://godbolt.org/z/x35e114de) and returns the stack address of the initialization function. I'm not sure if it's intended or not. Should we still diagnose this as an error?
My intuition is that it's kinder to the user to reject trying to get a stack address when there's no stack involved, but I don't know that it's a strongly held opinion. CC @nikic @efriedma-quic for more opinions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can't evaluate this at compile-time, so we know this is running at runtime. And at runtime, we have a stack: the stack of __cxx_global_var_init(). So the semantics here seem fine, if maybe a little weird at first glance. And trying to restrict the set of builtins you can use from runtime init leads to weird questions, like what happens if you have a function static inline void* stackaddr() { return __builtin_stack_address(); }
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, that makes a lot more sense to me, thank you! Then I'm happy with the current behavior.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we also have tests for what happens with naked functions or other kind of odd situations where the stack may be different from the normal case?
I might need a little bit of help with this, it seems like you can't have non-ASM code inside an __attribute__((naked))
function, so you can't call __builtin_stack_address()
inside one.
I'm also not very sure about the odd situations where the stack may be different from the normal case. Are you referring to something similar to an interrupt handler (i.e. __attribute__((interrupt)) void isr(void*)
?
Using something like __attribute__((interrupt))
simply translates to an additional function attribute in the generated IR (e.g. x86_intrcc
). Is it more appropriate to test those scenarios in llvm/test/CodeGen/${Target}/
instead?
This makes for pretty bad UX. To the degree it is feasible, this should be supported on all arches from day one, at least if a Clang builtin is exported. Don't we already have the necessary logic for this for llvm.stacksave? There's a ISD::STACKSAVE opcode and targets call setStackPointerRegisterToSaveRestore() to specify the stack register. I'm not sure if there is any expected difference in behavior between STACKSAVE and STACKADDRESS, but we should at least be able to reuse something here. |
On most targets, the behavior is the same. SPARC is an exception.
Could we add a check for SPARC (i.e. an
That way, we could emit/reuse the |
Ping. |
@moorabbit You'd probably want to define STACKADDRESS with a default expansion to STACKSAVE, plus custom legalization on SPARC. There should be no direct triple checks. |
✅ With the latest revision this PR passed the C/C++ code formatter. |
Co-authored-by: Aaron Ballman <aaron@aaronballman.com>
Thx for the pointer @nikic , does this revision address your comment properly? |
Ping. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The backend code looks like what I expect. Needs a backend regression test for some non-SPARC target.
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. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix this note?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done! Thx for catching that!
@@ -0,0 +1,14 @@ | |||
; RUN: llc < %s -mtriple=armv7 | FileCheck %s --check-prefix=armv7 | |||
; RUN: llc < %s -mtriple=aarch64 | FileCheck %s --check-prefix=aarch64 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can't put aarch64 testcases in llvm/test/CodeGen/ARM/. They have to be in llvm/test/CodeGen/AArch64. (The backends are independent; this will cause a regression test failure if the "Arm" backend is enabled, but the "AArch64" backend is disabled.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see. Thanks clarifying.
Thinking about this again, the ARM test case seems redundant since it is testing the same code path as the x86 test case. What do you think about keeping the x86 test case and removing the ARM test case entirely?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I'd generally prefer more tests for stuff like this, but we do already have coverage for stacksave, so I don't feel strongly about it.
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. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also note here.
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. It may or may not include the space used for on-stack arguments passed to a callee (See GCC Bug/121013).This PR only adds support for the following architectures: x86 - x86_64. Support for other architectures can be added in future patches.
Fixes #82632