Skip to content

Commit 029d9fc

Browse files
committed
[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
1 parent dd54b8e commit 029d9fc

File tree

16 files changed

+148
-0
lines changed

16 files changed

+148
-0
lines changed

clang/docs/LanguageExtensions.rst

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4189,6 +4189,39 @@ assignment can happen automatically.
41894189
to a variable, have its address taken, or passed into or returned from a
41904190
function, because doing so violates bounds safety conventions.
41914191
4192+
.. _builtin_stack_address-doc:
4193+
4194+
``__builtin_stack_address``
4195+
---------------------------
4196+
4197+
``__builtin_stack_address`` returns the address that separates the current
4198+
function's (i.e. the one calling the builtin) stack space and the region of the
4199+
stack that may be modified by called functions. The semantics match those of GCC's builtin of the same name.
4200+
4201+
**Note:** Support for this builtin is currently limited to the following architectures: x86_64, x86.
4202+
4203+
**Syntax**:
4204+
4205+
.. code-block:: c++
4206+
4207+
void *__builtin_stack_address()
4208+
4209+
**Example**:
4210+
4211+
.. code-block:: c++
4212+
4213+
void *sp = __builtin_stack_address();
4214+
4215+
**Description**:
4216+
4217+
The address returned by ``__builtin_stack_address`` identifies the starting
4218+
address of the stack region that may be used by called functions.
4219+
4220+
On some architectures (e.g. x86), it's sufficient to return the value in the stack pointer register
4221+
directly. On others (e.g. SPARCv9), adjustments are required to the value of the stack pointer
4222+
register. ``__builtin_stack_address`` performs the necessary adjustments and returns the correct
4223+
boundary address.
4224+
41924225
Multiprecision Arithmetic Builtins
41934226
----------------------------------
41944227

clang/docs/ReleaseNotes.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,8 @@ Resolutions to C++ Defect Reports
172172
C Language Changes
173173
------------------
174174

175+
- Clang now supports the :ref:`__builtin_stack_address <builtin_stack_address-doc>` () builtin.
176+
The semantics match those of GCC's builtin with the same name.
175177
- Clang now allows an ``inline`` specifier on a typedef declaration of a
176178
function type in Microsoft compatibility mode. #GH124869
177179
- Clang now allows ``restrict`` qualifier for array types with pointer elements (#GH92847).

clang/include/clang/Basic/Builtins.td

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -917,6 +917,12 @@ def FrameAddress : Builtin {
917917
let Prototype = "void*(_Constant unsigned int)";
918918
}
919919

920+
def StackAddress : Builtin {
921+
let Spellings = ["__builtin_stack_address"];
922+
let Attributes = [NoThrow];
923+
let Prototype = "void*()";
924+
}
925+
920926
def ClearCache : Builtin {
921927
let Spellings = ["__builtin___clear_cache"];
922928
let Attributes = [NoThrow];

clang/lib/CodeGen/CGBuiltin.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4673,6 +4673,10 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
46734673
Function *F = CGM.getIntrinsic(Intrinsic::frameaddress, AllocaInt8PtrTy);
46744674
return RValue::get(Builder.CreateCall(F, Depth));
46754675
}
4676+
case Builtin::BI__builtin_stack_address: {
4677+
return RValue::get(Builder.CreateCall(
4678+
CGM.getIntrinsic(Intrinsic::stackaddress, AllocaInt8PtrTy)));
4679+
}
46764680
case Builtin::BI__builtin_extract_return_addr: {
46774681
Value *Address = EmitScalarExpr(E->getArg(0));
46784682
Value *Result = getTargetHooks().decodeReturnAddress(*this, Address);

clang/lib/Sema/SemaChecking.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2958,6 +2958,15 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
29582958
break;
29592959
}
29602960

2961+
case Builtin::BI__builtin_stack_address: {
2962+
if (CheckBuiltinTargetInSupported(
2963+
*this, TheCall,
2964+
/*SupportedArchs=*/{llvm::Triple::x86_64, llvm::Triple::x86})) {
2965+
return ExprError();
2966+
}
2967+
break;
2968+
}
2969+
29612970
case Builtin::BI__builtin_nondeterministic_value: {
29622971
if (BuiltinNonDeterministicValue(TheCall))
29632972
return ExprError();
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// RUN: %clang -target x86_64 -S -emit-llvm %s -o - | FileCheck %s --check-prefix=llvm
2+
// RUN: %clang -target x86_64 -S %s -o - | FileCheck %s --check-prefix=x64
3+
4+
extern void f(int, int, int, long, long, long, long, long, long, long, long);
5+
6+
// llvm-LABEL: define {{[^@]+}} @a()
7+
// llvm: call {{[^@]+}} @llvm.stackaddress.p0()
8+
//
9+
// x64-LABEL: a:
10+
// x64: movq %rsp, %rax
11+
void *a() {
12+
f(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11);
13+
return __builtin_stack_address();
14+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// RUN: %clang -target x86_64 -S -emit-llvm %s -o - | llvm-cxxfilt | FileCheck %s --check-prefix=llvm
2+
// RUN: %clang -target x86_64 -S %s -o - | llvm-cxxfilt | FileCheck %s --check-prefix=x64
3+
4+
extern void f(int, int, int, long, long, long, long, long, long, long, long);
5+
6+
struct S {
7+
void *a();
8+
};
9+
10+
// llvm-LABEL: define {{[^@]+}} @S::a()
11+
// llvm: call {{[^@]+}} @llvm.stackaddress.p0()
12+
//
13+
// x64-LABEL: S::a():
14+
// x64: movq %rsp, %rax
15+
void *S::a() {
16+
void *p = __builtin_stack_address();
17+
f(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11);
18+
return p;
19+
}
20+
21+
// llvm-LABEL: define {{[^@]+}} @two()
22+
// llvm: call {{[^@]+}} @"two()::$_0::operator()() const"
23+
//
24+
// llvm-LABEL: define {{[^@]+}} @"two()::$_0::operator()() const"
25+
// llvm: call {{[^@]+}} @llvm.stackaddress.p0()
26+
//
27+
// x64-LABEL: two()::$_0::operator()() const:
28+
// x64: movq %rsp, %rax
29+
void *two() {
30+
auto l = []() {
31+
void *p = __builtin_stack_address();
32+
f(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11);
33+
return p;
34+
};
35+
return l();
36+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// RUN: %clang_cc1 -verify %s -triple x86_64-unknown-unknown -DTEST_x64
2+
// RUN: %clang_cc1 -verify %s -triple i386-unknown-unknown -DTEST_x86
3+
// RUN: %clang_cc1 -verify %s -triple riscv32-unknown-unknown -DTEST_riscv32
4+
// RUN: %clang_cc1 -verify %s -triple riscv64-unknown-unknown -DTEST_riscv64
5+
// RUN: %clang_cc1 -verify %s -triple aarch64-unknown-unknown -DTEST_aarch64
6+
7+
#if defined(TEST_x64) || defined(TEST_x86)
8+
// expected-no-diagnostics
9+
void *a() {
10+
return __builtin_stack_address();
11+
}
12+
#else
13+
void *a() {
14+
return __builtin_stack_address(); // expected-error {{builtin is not supported on this target}}
15+
}
16+
#endif

clang/test/Sema/builtin-stackaddress.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,3 +36,8 @@ void* h(unsigned x) {
3636
// expected-error@+1 {{argument value 1048575 is outside the valid range [0, 65535]}}
3737
return __builtin_frame_address(0xFFFFF);
3838
}
39+
40+
void *i() {
41+
// expected-error@+1 {{too many arguments to function call, expected 0, have 1}}
42+
return __builtin_stack_address(0);
43+
}

llvm/include/llvm/CodeGen/ISDOpcodes.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,11 @@ enum NodeType {
121121
/// function calling this intrinsic.
122122
SPONENTRY,
123123

124+
/// STACKADDR - Represents the llvm.stackaddr intrinsic. Takes no argument
125+
/// and returns the starting address of the stack region that may be used
126+
/// by called functions.
127+
STACKADDR,
128+
124129
/// LOCAL_RECOVER - Represents the llvm.localrecover intrinsic.
125130
/// Materializes the offset from the local object pointer of another
126131
/// function to a particular local object passed to llvm.localescape. The

0 commit comments

Comments
 (0)