Skip to content

Commit ab40909

Browse files
authored
Implement the trampoline intrinsics and nest parameter for AIX. (#149388)
We can expand the init intrinsic to create a descriptor for the nested procedure by combining the entry point and TOC pointer from the global descriptor with the nest argument. The normal indirect call sequence then calls the nested procedure through the descriptor like all other calls. Patch also implements support for a nest parameter by mapping it to gpr 11.
1 parent 4c9bb65 commit ab40909

File tree

3 files changed

+93
-16
lines changed

3 files changed

+93
-16
lines changed

llvm/lib/Target/PowerPC/PPCISelLowering.cpp

Lines changed: 67 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3925,9 +3925,6 @@ SDValue PPCTargetLowering::LowerVACOPY(SDValue Op, SelectionDAG &DAG) const {
39253925

39263926
SDValue PPCTargetLowering::LowerADJUST_TRAMPOLINE(SDValue Op,
39273927
SelectionDAG &DAG) const {
3928-
if (Subtarget.isAIXABI())
3929-
report_fatal_error("ADJUST_TRAMPOLINE operation is not supported on AIX.");
3930-
39313928
return Op.getOperand(0);
39323929
}
39333930

@@ -3984,16 +3981,72 @@ SDValue PPCTargetLowering::LowerINLINEASM(SDValue Op, SelectionDAG &DAG) const {
39843981

39853982
SDValue PPCTargetLowering::LowerINIT_TRAMPOLINE(SDValue Op,
39863983
SelectionDAG &DAG) const {
3987-
if (Subtarget.isAIXABI())
3988-
report_fatal_error("INIT_TRAMPOLINE operation is not supported on AIX.");
3989-
39903984
SDValue Chain = Op.getOperand(0);
39913985
SDValue Trmp = Op.getOperand(1); // trampoline
39923986
SDValue FPtr = Op.getOperand(2); // nested function
39933987
SDValue Nest = Op.getOperand(3); // 'nest' parameter value
39943988
SDLoc dl(Op);
39953989

39963990
EVT PtrVT = getPointerTy(DAG.getDataLayout());
3991+
3992+
if (Subtarget.isAIXABI()) {
3993+
// On AIX we create a trampoline descriptor by combining the
3994+
// entry point and TOC from the global descriptor (FPtr) with the
3995+
// nest argument as the environment pointer.
3996+
uint64_t PointerSize = Subtarget.isPPC64() ? 8 : 4;
3997+
MaybeAlign PointerAlign(PointerSize);
3998+
auto MMOFlags = Subtarget.hasInvariantFunctionDescriptors()
3999+
? (MachineMemOperand::MODereferenceable |
4000+
MachineMemOperand::MOInvariant)
4001+
: MachineMemOperand::MONone;
4002+
4003+
uint64_t TOCPointerOffset = 1 * PointerSize;
4004+
uint64_t EnvPointerOffset = 2 * PointerSize;
4005+
SDValue SDTOCPtrOffset = DAG.getConstant(TOCPointerOffset, dl, PtrVT);
4006+
SDValue SDEnvPtrOffset = DAG.getConstant(EnvPointerOffset, dl, PtrVT);
4007+
4008+
const Value *TrampolineAddr =
4009+
cast<SrcValueSDNode>(Op.getOperand(4))->getValue();
4010+
const Function *Func =
4011+
cast<Function>(cast<SrcValueSDNode>(Op.getOperand(5))->getValue());
4012+
4013+
SDValue OutChains[3];
4014+
4015+
// Copy the entry point address from the global descriptor to the
4016+
// trampoline buffer.
4017+
SDValue LoadEntryPoint =
4018+
DAG.getLoad(PtrVT, dl, Chain, FPtr, MachinePointerInfo(Func, 0),
4019+
PointerAlign, MMOFlags);
4020+
SDValue EPLoadChain = LoadEntryPoint.getValue(1);
4021+
OutChains[0] = DAG.getStore(EPLoadChain, dl, LoadEntryPoint, Trmp,
4022+
MachinePointerInfo(TrampolineAddr, 0));
4023+
4024+
// Copy the TOC pointer from the global descriptor to the trampoline
4025+
// buffer.
4026+
SDValue TOCFromDescriptorPtr =
4027+
DAG.getNode(ISD::ADD, dl, PtrVT, FPtr, SDTOCPtrOffset);
4028+
SDValue TOCReg = DAG.getLoad(PtrVT, dl, Chain, TOCFromDescriptorPtr,
4029+
MachinePointerInfo(Func, TOCPointerOffset),
4030+
PointerAlign, MMOFlags);
4031+
SDValue TrampolineTOCPointer =
4032+
DAG.getNode(ISD::ADD, dl, PtrVT, Trmp, SDTOCPtrOffset);
4033+
SDValue TOCLoadChain = TOCReg.getValue(1);
4034+
OutChains[1] =
4035+
DAG.getStore(TOCLoadChain, dl, TOCReg, TrampolineTOCPointer,
4036+
MachinePointerInfo(TrampolineAddr, TOCPointerOffset));
4037+
4038+
// Store the nest argument into the environment pointer in the trampoline
4039+
// buffer.
4040+
SDValue EnvPointer = DAG.getNode(ISD::ADD, dl, PtrVT, Trmp, SDEnvPtrOffset);
4041+
OutChains[2] =
4042+
DAG.getStore(Chain, dl, Nest, EnvPointer,
4043+
MachinePointerInfo(TrampolineAddr, EnvPointerOffset));
4044+
4045+
SDValue TokenFactor =
4046+
DAG.getNode(ISD::TokenFactor, dl, MVT::Other, OutChains);
4047+
return TokenFactor;
4048+
}
4049+
39974050
bool isPPC64 = (PtrVT == MVT::i64);
39984051
Type *IntPtrTy = DAG.getDataLayout().getIntPtrType(*DAG.getContext());
39994052

@@ -6865,9 +6918,6 @@ static bool CC_AIX(unsigned ValNo, MVT ValVT, MVT LocVT,
68656918
if (ValVT == MVT::f128)
68666919
report_fatal_error("f128 is unimplemented on AIX.");
68676920

6868-
if (ArgFlags.isNest())
6869-
report_fatal_error("Nest arguments are unimplemented.");
6870-
68716921
static const MCPhysReg GPR_32[] = {// 32-bit registers.
68726922
PPC::R3, PPC::R4, PPC::R5, PPC::R6,
68736923
PPC::R7, PPC::R8, PPC::R9, PPC::R10};
@@ -6882,6 +6932,14 @@ static bool CC_AIX(unsigned ValNo, MVT ValVT, MVT LocVT,
68826932

68836933
const ArrayRef<MCPhysReg> GPRs = IsPPC64 ? GPR_64 : GPR_32;
68846934

6935+
if (ArgFlags.isNest()) {
6936+
MCRegister EnvReg = State.AllocateReg(IsPPC64 ? PPC::X11 : PPC::R11);
6937+
if (!EnvReg)
6938+
report_fatal_error("More then one nest argument.");
6939+
State.addLoc(CCValAssign::getReg(ValNo, ValVT, EnvReg, RegVT, LocInfo));
6940+
return false;
6941+
}
6942+
68856943
if (ArgFlags.isByVal()) {
68866944
const Align ByValAlign(ArgFlags.getNonZeroByValAlign());
68876945
if (ByValAlign > StackAlign)
Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
; RUN: not --crash llc -mtriple powerpc-ibm-aix-xcoff < %s 2>&1 | FileCheck %s
2-
; RUN: not --crash llc -mtriple powerpc64-ibm-aix-xcoff < %s 2>&1 | FileCheck %s
1+
; RUN: llc -mtriple powerpc-ibm-aix-xcoff < %s 2>&1 | FileCheck %s
2+
; RUN: llc -mtriple powerpc64-ibm-aix-xcoff < %s 2>&1 | FileCheck %s
33

44
define ptr @nest_receiver(ptr nest %arg) nounwind {
55
ret ptr %arg
@@ -9,5 +9,10 @@ define ptr @nest_caller(ptr %arg) nounwind {
99
%result = call ptr @nest_receiver(ptr nest %arg)
1010
ret ptr %result
1111
}
12+
; CHECK-LABEL: .nest_receiver:
13+
; CHECK: mr 3, 11
14+
; CHECK: blr
1215

13-
; CHECK: LLVM ERROR: Nest arguments are unimplemented.
16+
; CHECK-LABEL: .nest_caller:
17+
; CHECK: mr 11, 3
18+
; CHECK: bl .nest_receiver
Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
; RUN: not --crash llc -mtriple powerpc-ibm-aix-xcoff < %s 2>&1 | FileCheck %s
2-
; RUN: not --crash llc -mtriple powerpc64-ibm-aix-xcoff < %s 2>&1 | FileCheck %s
3-
4-
; CHECK: LLVM ERROR: INIT_TRAMPOLINE operation is not supported on AIX.
1+
; RUN: llc -mtriple powerpc-ibm-aix-xcoff < %s 2>&1 | \
2+
; RUN: FileCheck %s --check-prefix=32BIT
3+
; RUN: llc -mtriple powerpc64-ibm-aix-xcoff < %s 2>&1 -mattr=-altivec | \
4+
; RUN: FileCheck %s --check-prefix=64BIT
55

66
define void @create_trampoline(ptr %buffer, ptr %nval) nounwind {
77
entry:
@@ -12,3 +12,17 @@ entry:
1212
declare i32 @nested(i32);
1313

1414
declare void @llvm.init.trampoline(ptr, ptr, ptr) nounwind
15+
16+
; 32BIT: stw 4, 8(3)
17+
; 32BIT: lwz [[FuncDesc:[0-9]+]], L..C0(2)
18+
; 32BIT-DAG: lwz [[SCRATCH1:[0-9]+]], 0([[FuncDesc]])
19+
; 32BIT-DAG: lwz [[SCRATCH2:[0-9]+]], 4([[FuncDesc]])
20+
; 32BIT-DAG: stw [[SCRATCH1]], 0(3)
21+
; 32BIT-DAG: stw [[SCRATCH2]], 4(3)
22+
23+
; 64BIT: std 4, 16(3)
24+
; 64BIT-DAG: ld [[FuncDesc:[0-9]+]], L..C0(2)
25+
; 64BIT-DAG: ld [[SCRATCH1:[0-9]+]], 0([[FuncDesc]])
26+
; 64BIT-DAG: ld [[SCRATCH2:[0-9]+]], 8([[FuncDesc]])
27+
; 64BIT-DAG: std [[SCRATCH1]], 0(3)
28+
; 64BIT-DAG: std [[SCRATCH2]], 8(3)

0 commit comments

Comments
 (0)