Skip to content

Commit 99dead3

Browse files
committed
[AArch64] Implement INIT/ADJUST_TRAMPOLINE
Add support for llvm.init.trampoline and llvm.adjust.trampoline intrinsics for AArch64. Fixes #65573 Updates #27174 Updates #66157
1 parent 6cc363e commit 99dead3

File tree

4 files changed

+88
-0
lines changed

4 files changed

+88
-0
lines changed

compiler-rt/lib/builtins/README.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,11 @@ switch32
272272
switch8
273273
switchu8
274274

275+
// This function generates a custom trampoline function with the specific
276+
// realFunc and localsPtr values.
277+
void __trampoline_setup(uint32_t* trampOnStack, int trampSizeAllocated,
278+
const void* realFunc, void* localsPtr);
279+
275280
// There is no C interface to the *_vfp_d8_d15_regs functions. There are
276281
// called in the prolog and epilog of Thumb1 functions. When the C++ ABI use
277282
// SJLJ for exceptions, each function with a catch clause or destructors needs

compiler-rt/lib/builtins/trampoline_setup.c

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,3 +41,30 @@ COMPILER_RT_ABI void __trampoline_setup(uint32_t *trampOnStack,
4141
__clear_cache(trampOnStack, &trampOnStack[10]);
4242
}
4343
#endif // __powerpc__ && !defined(__powerpc64__)
44+
45+
// The AArch64 compiler generates calls to __trampoline_setup() when creating
46+
// trampoline functions on the stack for use with nested functions.
47+
// This function creates a custom 20-byte trampoline function on the stack
48+
// which loads x18 with a pointer to the outer function's locals
49+
// and then jumps to the target nested function.
50+
51+
#if __aarch64__
52+
COMPILER_RT_ABI void __trampoline_setup(uint32_t *trampOnStack,
53+
int trampSizeAllocated,
54+
const void *realFunc, void *localsPtr) {
55+
// should never happen, but if compiler did not allocate
56+
// enough space on stack for the trampoline, abort
57+
if (trampSizeAllocated < 20)
58+
compilerrt_abort();
59+
60+
// create trampoline
61+
trampOnStack[0] = 0x580000b1; // ldr x17, realFunc
62+
trampOnStack[1] = 0x580000d2; // ldr x18, localsPtr
63+
trampOnStack[2] = 0xd61f0220; // br x17
64+
trampOnStack[3] = (uint32_t)realFunc;
65+
trampOnStack[4] = (uint32_t)localsPtr;
66+
67+
// clear instruction cache
68+
__clear_cache(trampOnStack, &trampOnStack[10]);
69+
}
70+
#endif // __aarch64__

llvm/lib/Target/AArch64/AArch64ISelLowering.cpp

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5946,6 +5946,56 @@ static SDValue LowerFLDEXP(SDValue Op, SelectionDAG &DAG) {
59465946
return Final;
59475947
}
59485948

5949+
SDValue AArch64TargetLowering::LowerADJUST_TRAMPOLINE(SDValue Op,
5950+
SelectionDAG &DAG) const {
5951+
// Note: x18 cannot be used for the Nest parameter on Windows and macOS.
5952+
if (Subtarget->isTargetDarwin() || Subtarget->isTargetWindows())
5953+
report_fatal_error(
5954+
"ADJUST_TRAMPOLINE operation is only supported on Linux.");
5955+
5956+
return Op.getOperand(0);
5957+
}
5958+
5959+
SDValue AArch64TargetLowering::LowerINIT_TRAMPOLINE(SDValue Op,
5960+
SelectionDAG &DAG) const {
5961+
5962+
// Note: x18 cannot be used for the Nest parameter on Windows and macOS.
5963+
if (Subtarget->isTargetDarwin() || Subtarget->isTargetWindows())
5964+
report_fatal_error("INIT_TRAMPOLINE operation is only supported on Linux.");
5965+
5966+
SDValue Chain = Op.getOperand(0);
5967+
SDValue Trmp = Op.getOperand(1); // trampoline
5968+
SDValue FPtr = Op.getOperand(2); // nested function
5969+
SDValue Nest = Op.getOperand(3); // 'nest' parameter value
5970+
SDLoc dl(Op);
5971+
5972+
EVT PtrVT = getPointerTy(DAG.getDataLayout());
5973+
Type *IntPtrTy = DAG.getDataLayout().getIntPtrType(*DAG.getContext());
5974+
5975+
TargetLowering::ArgListTy Args;
5976+
TargetLowering::ArgListEntry Entry;
5977+
5978+
Entry.Ty = IntPtrTy;
5979+
Entry.Node = Trmp;
5980+
Args.push_back(Entry);
5981+
Entry.Node = DAG.getConstant(20, dl, MVT::i64);
5982+
Args.push_back(Entry);
5983+
5984+
Entry.Node = FPtr;
5985+
Args.push_back(Entry);
5986+
Entry.Node = Nest;
5987+
Args.push_back(Entry);
5988+
5989+
// Lower to a call to __trampoline_setup(Trmp, TrampSize, FPtr, ctx_reg)
5990+
TargetLowering::CallLoweringInfo CLI(DAG);
5991+
CLI.setDebugLoc(dl).setChain(Chain).setLibCallee(
5992+
CallingConv::C, Type::getVoidTy(*DAG.getContext()),
5993+
DAG.getExternalSymbol("__trampoline_setup", PtrVT), std::move(Args));
5994+
5995+
std::pair<SDValue, SDValue> CallResult = LowerCallTo(CLI);
5996+
return CallResult.second;
5997+
}
5998+
59495999
SDValue AArch64TargetLowering::LowerOperation(SDValue Op,
59506000
SelectionDAG &DAG) const {
59516001
LLVM_DEBUG(dbgs() << "Custom lowering: ");
@@ -5961,6 +6011,10 @@ SDValue AArch64TargetLowering::LowerOperation(SDValue Op,
59616011
return LowerGlobalAddress(Op, DAG);
59626012
case ISD::GlobalTLSAddress:
59636013
return LowerGlobalTLSAddress(Op, DAG);
6014+
case ISD::ADJUST_TRAMPOLINE:
6015+
return LowerADJUST_TRAMPOLINE(Op, DAG);
6016+
case ISD::INIT_TRAMPOLINE:
6017+
return LowerINIT_TRAMPOLINE(Op, DAG);
59646018
case ISD::SETCC:
59656019
case ISD::STRICT_FSETCC:
59666020
case ISD::STRICT_FSETCCS:

llvm/lib/Target/AArch64/AArch64ISelLowering.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1045,6 +1045,8 @@ class AArch64TargetLowering : public TargetLowering {
10451045
SDValue LowerSELECT_CC(ISD::CondCode CC, SDValue LHS, SDValue RHS,
10461046
SDValue TVal, SDValue FVal, const SDLoc &dl,
10471047
SelectionDAG &DAG) const;
1048+
SDValue LowerINIT_TRAMPOLINE(SDValue Op, SelectionDAG &DAG) const;
1049+
SDValue LowerADJUST_TRAMPOLINE(SDValue Op, SelectionDAG &DAG) const;
10481050
SDValue LowerJumpTable(SDValue Op, SelectionDAG &DAG) const;
10491051
SDValue LowerBR_JT(SDValue Op, SelectionDAG &DAG) const;
10501052
SDValue LowerConstantPool(SDValue Op, SelectionDAG &DAG) const;

0 commit comments

Comments
 (0)