@@ -625,6 +625,11 @@ RISCVTargetLowering::RISCVTargetLowering(const TargetMachine &TM,
625625 setOperationAction(ISD::READSTEADYCOUNTER, MVT::i64,
626626 Subtarget.is64Bit() ? Legal : Custom);
627627
628+ if (Subtarget.is64Bit()) {
629+ setOperationAction(ISD::INIT_TRAMPOLINE, MVT::Other, Custom);
630+ setOperationAction(ISD::ADJUST_TRAMPOLINE, MVT::Other, Custom);
631+ }
632+
628633 setOperationAction({ISD::TRAP, ISD::DEBUGTRAP}, MVT::Other, Legal);
629634 setOperationAction(ISD::INTRINSIC_WO_CHAIN, MVT::Other, Custom);
630635 if (Subtarget.is64Bit())
@@ -7400,6 +7405,10 @@ SDValue RISCVTargetLowering::LowerOperation(SDValue Op,
74007405 return emitFlushICache(DAG, Op.getOperand(0), Op.getOperand(1),
74017406 Op.getOperand(2), Flags, DL);
74027407 }
7408+ case ISD::INIT_TRAMPOLINE:
7409+ return lowerINIT_TRAMPOLINE(Op, DAG);
7410+ case ISD::ADJUST_TRAMPOLINE:
7411+ return lowerADJUST_TRAMPOLINE(Op, DAG);
74037412 }
74047413}
74057414
@@ -7415,6 +7424,123 @@ SDValue RISCVTargetLowering::emitFlushICache(SelectionDAG &DAG, SDValue InChain,
74157424 return CallResult.second;
74167425}
74177426
7427+ SDValue RISCVTargetLowering::lowerINIT_TRAMPOLINE(SDValue Op,
7428+ SelectionDAG &DAG) const {
7429+ if (!Subtarget.is64Bit())
7430+ llvm::report_fatal_error("Trampolines only implemented for RV64");
7431+
7432+ SDValue Root = Op.getOperand(0);
7433+ SDValue Trmp = Op.getOperand(1); // trampoline
7434+ SDLoc dl(Op);
7435+
7436+ const Value *TrmpAddr = cast<SrcValueSDNode>(Op.getOperand(4))->getValue();
7437+
7438+ // We store in the trampoline buffer the following instructions and data.
7439+ // Offset:
7440+ // 0: auipc t2, 0
7441+ // 4: ld t0, 24(t2)
7442+ // 8: ld t2, 16(t2)
7443+ // 12: jalr t0
7444+ // 16: <StaticChainOffset>
7445+ // 24: <FunctionAddressOffset>
7446+ // 32:
7447+
7448+ // Constants shamelessly taken from GCC.
7449+ constexpr unsigned Opcode_AUIPC = 0x17;
7450+ constexpr unsigned Opcode_LD = 0x3003;
7451+ constexpr unsigned Opcode_JALR = 0x67;
7452+ constexpr unsigned ShiftField_RD = 7;
7453+ constexpr unsigned ShiftField_RS1 = 15;
7454+ constexpr unsigned ShiftField_IMM = 20;
7455+ constexpr unsigned Reg_X5 = 0x5; // x5/t0 (holds the address to the function)
7456+ constexpr unsigned Reg_X7 = 0x7; // x7/t2 (holds the static chain)
7457+
7458+ constexpr unsigned StaticChainOffset = 16;
7459+ constexpr unsigned FunctionAddressOffset = 24;
7460+
7461+ SDValue OutChains[6];
7462+ SDValue Addr = Trmp;
7463+
7464+ // auipc t2, 0
7465+ // Loads the current PC into t2.
7466+ constexpr uint32_t AUIPC_X7_0 =
7467+ Opcode_AUIPC | (Reg_X7 << ShiftField_RD);
7468+ OutChains[0] =
7469+ DAG.getTruncStore(Root, dl, DAG.getConstant(AUIPC_X7_0, dl, MVT::i64),
7470+ Addr, MachinePointerInfo(TrmpAddr), MVT::i32);
7471+
7472+ // ld t0, 24(t2)
7473+ // Loads the function address into t0. Note that we are using offsets
7474+ // pc-relative to the first instruction of the trampoline.
7475+ const uint32_t LD_X5_TargetFunctionOffset =
7476+ Opcode_LD | (Reg_X5 << ShiftField_RD) |
7477+ (Reg_X7 << ShiftField_RS1) | (FunctionAddressOffset << ShiftField_IMM);
7478+ Addr = DAG.getNode(ISD::ADD, dl, MVT::i64, Trmp,
7479+ DAG.getConstant(4, dl, MVT::i64));
7480+ OutChains[1] = DAG.getTruncStore(
7481+ Root, dl,
7482+ DAG.getConstant(LD_X5_TargetFunctionOffset, dl, MVT::i64), Addr,
7483+ MachinePointerInfo(TrmpAddr, 4), MVT::i32);
7484+
7485+ // ld t2, 16(t2)
7486+ // Load the value of the static chain.
7487+ const uint32_t LD_X7_StaticChainOffset =
7488+ Opcode_LD | (Reg_X7 << ShiftField_RD) |
7489+ (Reg_X7 << ShiftField_RS1) | (StaticChainOffset << ShiftField_IMM);
7490+ Addr = DAG.getNode(ISD::ADD, dl, MVT::i64, Trmp,
7491+ DAG.getConstant(8, dl, MVT::i64));
7492+ OutChains[2] = DAG.getTruncStore(
7493+ Root, dl, DAG.getConstant(LD_X7_StaticChainOffset, dl, MVT::i64),
7494+ Addr, MachinePointerInfo(TrmpAddr, 8), MVT::i32);
7495+
7496+ // jalr t0
7497+ // Jump to the function.
7498+ const uint32_t JALR_X5 =
7499+ Opcode_JALR | (Reg_X5 << ShiftField_RS1);
7500+ Addr = DAG.getNode(ISD::ADD, dl, MVT::i64, Trmp,
7501+ DAG.getConstant(12, dl, MVT::i64));
7502+ OutChains[3] =
7503+ DAG.getTruncStore(Root, dl, DAG.getConstant(JALR_X5, dl, MVT::i64), Addr,
7504+ MachinePointerInfo(TrmpAddr, 12), MVT::i32);
7505+
7506+ // Now store the variable part of the trampoline.
7507+ SDValue FunctionAddress = Op.getOperand(2);
7508+ SDValue StaticChain = Op.getOperand(3);
7509+
7510+ // Store the given static chain in the trampoline buffer.
7511+ Addr = DAG.getNode(ISD::ADD, dl, MVT::i64, Trmp,
7512+ DAG.getConstant(StaticChainOffset, dl, MVT::i64));
7513+ OutChains[4] = DAG.getStore(Root, dl, StaticChain, Addr,
7514+ MachinePointerInfo(TrmpAddr, StaticChainOffset));
7515+
7516+ // Store the given function address in the trampoline buffer.
7517+ Addr = DAG.getNode(ISD::ADD, dl, MVT::i64, Trmp,
7518+ DAG.getConstant(FunctionAddressOffset, dl, MVT::i64));
7519+ OutChains[5] =
7520+ DAG.getStore(Root, dl, FunctionAddress, Addr,
7521+ MachinePointerInfo(TrmpAddr, FunctionAddressOffset));
7522+
7523+ SDValue StoreToken = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, OutChains);
7524+
7525+ // Compute end of trampoline.
7526+ SDValue EndOfTrmp = DAG.getNode(ISD::ADD, dl, MVT::i64, Trmp,
7527+ DAG.getConstant(32, dl, MVT::i64));
7528+
7529+ // Call clear cache on the trampoline buffer.
7530+ SDValue Chain = DAG.getNode(ISD::CLEAR_CACHE, dl, MVT::Other, StoreToken,
7531+ Trmp, EndOfTrmp);
7532+
7533+ return Chain;
7534+ }
7535+
7536+ SDValue RISCVTargetLowering::lowerADJUST_TRAMPOLINE(SDValue Op,
7537+ SelectionDAG &DAG) const {
7538+ if (!Subtarget.is64Bit())
7539+ llvm::report_fatal_error("Trampolines only implemented for RV64");
7540+
7541+ return Op.getOperand(0);
7542+ }
7543+
74187544static SDValue getTargetNode(GlobalAddressSDNode *N, const SDLoc &DL, EVT Ty,
74197545 SelectionDAG &DAG, unsigned Flags) {
74207546 return DAG.getTargetGlobalAddress(N->getGlobal(), DL, Ty, 0, Flags);
0 commit comments