@@ -633,6 +633,11 @@ RISCVTargetLowering::RISCVTargetLowering(const TargetMachine &TM,
633633 setOperationAction(ISD::READSTEADYCOUNTER, MVT::i64,
634634 Subtarget.is64Bit() ? Legal : Custom);
635635
636+ if (Subtarget.is64Bit()) {
637+ setOperationAction(ISD::INIT_TRAMPOLINE, MVT::Other, Custom);
638+ setOperationAction(ISD::ADJUST_TRAMPOLINE, MVT::Other, Custom);
639+ }
640+
636641 setOperationAction({ISD::TRAP, ISD::DEBUGTRAP}, MVT::Other, Legal);
637642 setOperationAction(ISD::INTRINSIC_WO_CHAIN, MVT::Other, Custom);
638643 if (Subtarget.is64Bit())
@@ -7263,6 +7268,10 @@ SDValue RISCVTargetLowering::LowerOperation(SDValue Op,
72637268 return emitFlushICache(DAG, Op.getOperand(0), Op.getOperand(1),
72647269 Op.getOperand(2), Flags, DL);
72657270 }
7271+ case ISD::INIT_TRAMPOLINE:
7272+ return lowerINIT_TRAMPOLINE(Op, DAG);
7273+ case ISD::ADJUST_TRAMPOLINE:
7274+ return lowerADJUST_TRAMPOLINE(Op, DAG);
72667275 }
72677276}
72687277
@@ -7278,6 +7287,123 @@ SDValue RISCVTargetLowering::emitFlushICache(SelectionDAG &DAG, SDValue InChain,
72787287 return CallResult.second;
72797288}
72807289
7290+ SDValue RISCVTargetLowering::lowerINIT_TRAMPOLINE(SDValue Op,
7291+ SelectionDAG &DAG) const {
7292+ if (!Subtarget.is64Bit())
7293+ llvm::report_fatal_error("Trampolines only implemented for RV64");
7294+
7295+ SDValue Root = Op.getOperand(0);
7296+ SDValue Trmp = Op.getOperand(1); // trampoline
7297+ SDLoc dl(Op);
7298+
7299+ const Value *TrmpAddr = cast<SrcValueSDNode>(Op.getOperand(4))->getValue();
7300+
7301+ // We store in the trampoline buffer the following instructions and data.
7302+ // Offset:
7303+ // 0: auipc t2, 0
7304+ // 4: ld t0, 24(t2)
7305+ // 8: ld t2, 16(t2)
7306+ // 12: jalr t0
7307+ // 16: <StaticChainOffset>
7308+ // 24: <FunctionAddressOffset>
7309+ // 32:
7310+
7311+ // Constants shamelessly taken from GCC.
7312+ constexpr unsigned Opcode_AUIPC = 0x17;
7313+ constexpr unsigned Opcode_LD = 0x3003;
7314+ constexpr unsigned Opcode_JALR = 0x67;
7315+ constexpr unsigned ShiftField_RD = 7;
7316+ constexpr unsigned ShiftField_RS1 = 15;
7317+ constexpr unsigned ShiftField_IMM = 20;
7318+ constexpr unsigned Reg_X5 = 0x5; // x5/t0 (holds the address to the function)
7319+ constexpr unsigned Reg_X7 = 0x7; // x7/t2 (holds the static chain)
7320+
7321+ constexpr unsigned StaticChainOffset = 16;
7322+ constexpr unsigned FunctionAddressOffset = 24;
7323+
7324+ SDValue OutChains[6];
7325+ SDValue Addr = Trmp;
7326+
7327+ // auipc t2, 0
7328+ // Loads the current PC into t2.
7329+ constexpr uint32_t AUIPC_X7_0 =
7330+ Opcode_AUIPC | (Reg_X7 << ShiftField_RD);
7331+ OutChains[0] =
7332+ DAG.getTruncStore(Root, dl, DAG.getConstant(AUIPC_X7_0, dl, MVT::i64),
7333+ Addr, MachinePointerInfo(TrmpAddr), MVT::i32);
7334+
7335+ // ld t0, 24(t2)
7336+ // Loads the function address into t0. Note that we are using offsets
7337+ // pc-relative to the first instruction of the trampoline.
7338+ const uint32_t LD_X5_TargetFunctionOffset =
7339+ Opcode_LD | (Reg_X5 << ShiftField_RD) |
7340+ (Reg_X7 << ShiftField_RS1) | (FunctionAddressOffset << ShiftField_IMM);
7341+ Addr = DAG.getNode(ISD::ADD, dl, MVT::i64, Trmp,
7342+ DAG.getConstant(4, dl, MVT::i64));
7343+ OutChains[1] = DAG.getTruncStore(
7344+ Root, dl,
7345+ DAG.getConstant(LD_X5_TargetFunctionOffset, dl, MVT::i64), Addr,
7346+ MachinePointerInfo(TrmpAddr, 4), MVT::i32);
7347+
7348+ // ld t2, 16(t2)
7349+ // Load the value of the static chain.
7350+ const uint32_t LD_X7_StaticChainOffset =
7351+ Opcode_LD | (Reg_X7 << ShiftField_RD) |
7352+ (Reg_X7 << ShiftField_RS1) | (StaticChainOffset << ShiftField_IMM);
7353+ Addr = DAG.getNode(ISD::ADD, dl, MVT::i64, Trmp,
7354+ DAG.getConstant(8, dl, MVT::i64));
7355+ OutChains[2] = DAG.getTruncStore(
7356+ Root, dl, DAG.getConstant(LD_X7_StaticChainOffset, dl, MVT::i64),
7357+ Addr, MachinePointerInfo(TrmpAddr, 8), MVT::i32);
7358+
7359+ // jalr t0
7360+ // Jump to the function.
7361+ const uint32_t JALR_X5 =
7362+ Opcode_JALR | (Reg_X5 << ShiftField_RS1);
7363+ Addr = DAG.getNode(ISD::ADD, dl, MVT::i64, Trmp,
7364+ DAG.getConstant(12, dl, MVT::i64));
7365+ OutChains[3] =
7366+ DAG.getTruncStore(Root, dl, DAG.getConstant(JALR_X5, dl, MVT::i64), Addr,
7367+ MachinePointerInfo(TrmpAddr, 12), MVT::i32);
7368+
7369+ // Now store the variable part of the trampoline.
7370+ SDValue FunctionAddress = Op.getOperand(2);
7371+ SDValue StaticChain = Op.getOperand(3);
7372+
7373+ // Store the given static chain in the trampoline buffer.
7374+ Addr = DAG.getNode(ISD::ADD, dl, MVT::i64, Trmp,
7375+ DAG.getConstant(StaticChainOffset, dl, MVT::i64));
7376+ OutChains[4] = DAG.getStore(Root, dl, StaticChain, Addr,
7377+ MachinePointerInfo(TrmpAddr, StaticChainOffset));
7378+
7379+ // Store the given function address in the trampoline buffer.
7380+ Addr = DAG.getNode(ISD::ADD, dl, MVT::i64, Trmp,
7381+ DAG.getConstant(FunctionAddressOffset, dl, MVT::i64));
7382+ OutChains[5] =
7383+ DAG.getStore(Root, dl, FunctionAddress, Addr,
7384+ MachinePointerInfo(TrmpAddr, FunctionAddressOffset));
7385+
7386+ SDValue StoreToken = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, OutChains);
7387+
7388+ // Compute end of trampoline.
7389+ SDValue EndOfTrmp = DAG.getNode(ISD::ADD, dl, MVT::i64, Trmp,
7390+ DAG.getConstant(32, dl, MVT::i64));
7391+
7392+ // Call clear cache on the trampoline buffer.
7393+ SDValue Chain = DAG.getNode(ISD::CLEAR_CACHE, dl, MVT::Other, StoreToken,
7394+ Trmp, EndOfTrmp);
7395+
7396+ return Chain;
7397+ }
7398+
7399+ SDValue RISCVTargetLowering::lowerADJUST_TRAMPOLINE(SDValue Op,
7400+ SelectionDAG &DAG) const {
7401+ if (!Subtarget.is64Bit())
7402+ llvm::report_fatal_error("Trampolines only implemented for RV64");
7403+
7404+ return Op.getOperand(0);
7405+ }
7406+
72817407static SDValue getTargetNode(GlobalAddressSDNode *N, const SDLoc &DL, EVT Ty,
72827408 SelectionDAG &DAG, unsigned Flags) {
72837409 return DAG.getTargetGlobalAddress(N->getGlobal(), DL, Ty, 0, Flags);
0 commit comments