[llvm] [RISCV] Implement trampolines for rv64 (PR #96309)
Jessica Clarke via llvm-commits
llvm-commits at lists.llvm.org
Fri Aug 2 08:00:45 PDT 2024
Roger Ferrer =?utf-8?q?Ibáñez?= <rofirrim at gmail.com>,Roger Ferrer
Ibanez <roger.ferrer at bsc.es>,Roger Ferrer Ibanez <roger.ferrer at bsc.es>,Roger
Ferrer Ibanez <roger.ferrer at bsc.es>
Message-ID:
In-Reply-To: <llvm.org/llvm/llvm-project/pull/96309 at github.com>
================
@@ -7279,6 +7290,122 @@ SDValue RISCVTargetLowering::emitFlushICache(SelectionDAG &DAG, SDValue InChain,
return CallResult.second;
}
+SDValue RISCVTargetLowering::lowerINIT_TRAMPOLINE(SDValue Op,
+ SelectionDAG &DAG) const {
+ if (!Subtarget.is64Bit())
+ llvm::report_fatal_error("Trampolines only implemented for RV64");
+
+ // Create an MCCodeEmitter to encode instructions.
+ TargetLoweringObjectFile *TLO = getTargetMachine().getObjFileLowering();
+ assert(TLO);
+ MCContext &MCCtx = TLO->getContext();
+
+ std::unique_ptr<MCCodeEmitter> CodeEmitter(
+ createRISCVMCCodeEmitter(*getTargetMachine().getMCInstrInfo(), MCCtx));
+
+ SDValue Root = Op.getOperand(0);
+ SDValue Trmp = Op.getOperand(1); // trampoline
+ SDLoc dl(Op);
+
+ const Value *TrmpAddr = cast<SrcValueSDNode>(Op.getOperand(4))->getValue();
+
+ // We store in the trampoline buffer the following instructions and data.
+ // Offset:
+ // 0: auipc t2, 0
+ // 4: ld t0, 24(t2)
+ // 8: ld t2, 16(t2)
+ // 12: jalr t0
+ // 16: <StaticChainOffset>
+ // 24: <FunctionAddressOffset>
+ // 32:
+
+ constexpr unsigned StaticChainOffset = 16;
+ constexpr unsigned FunctionAddressOffset = 24;
+
+ auto GetEncoding = [&](const MCInst &MC) {
+ SmallVector<char, 4> CB;
+ SmallVector<MCFixup> Fixups;
+ const MCSubtargetInfo *STI = getTargetMachine().getMCSubtargetInfo();
+ assert(STI);
+ CodeEmitter->encodeInstruction(MC, CB, Fixups, *STI);
+ assert(CB.size() == 4);
+ assert(Fixups.empty());
+ uint32_t Encoding = support::endian::read32le(CB.data());
+ return Encoding;
+ };
+
+ SDValue OutChains[6];
+
+ uint32_t Encodings[] = {
+ // auipc t2, 0
+ // Loads the current PC into t2.
+ GetEncoding(MCInstBuilder(RISCV::AUIPC).addReg(RISCV::X7).addImm(0)),
+ // ld t0, 24(t2)
+ // Loads the function address into t0. Note that we are using offsets
+ // pc-relative to the first instruction of the trampoline.
+ GetEncoding(
+ MCInstBuilder(RISCV::LD).addReg(RISCV::X5).addReg(RISCV::X7).addImm(
+ FunctionAddressOffset)),
+ // ld t2, 16(t2)
+ // Load the value of the static chain.
+ GetEncoding(
+ MCInstBuilder(RISCV::LD).addReg(RISCV::X7).addReg(RISCV::X7).addImm(
+ StaticChainOffset)),
+ // jalr t0
+ // Jump to the function.
+ GetEncoding(MCInstBuilder(RISCV::JALR)
+ .addReg(RISCV::X0)
+ .addReg(RISCV::X5)
+ .addImm(0))};
+
+ // Store encoded instructions.
+ for (auto [Idx, Encoding] : llvm::enumerate(Encodings)) {
+ SDValue Addr = Idx > 0 ? DAG.getNode(ISD::ADD, dl, MVT::i64, Trmp,
+ DAG.getConstant(Idx * 4, dl, MVT::i64))
+ : Trmp;
+ OutChains[Idx] = DAG.getTruncStore(
+ Root, dl, DAG.getConstant(Encoding, dl, MVT::i64), Addr,
+ MachinePointerInfo(TrmpAddr, Idx * 4), MVT::i32);
+ }
+
+ // Now store the variable part of the trampoline.
+ SDValue FunctionAddress = Op.getOperand(2);
+ SDValue StaticChain = Op.getOperand(3);
+
+ // Store the given static chain in the trampoline buffer.
+ SDValue Addr = DAG.getNode(ISD::ADD, dl, MVT::i64, Trmp,
+ DAG.getConstant(StaticChainOffset, dl, MVT::i64));
+ OutChains[4] = DAG.getStore(Root, dl, StaticChain, Addr,
+ MachinePointerInfo(TrmpAddr, StaticChainOffset));
+
+ // Store the given function address in the trampoline buffer.
+ Addr = DAG.getNode(ISD::ADD, dl, MVT::i64, Trmp,
+ DAG.getConstant(FunctionAddressOffset, dl, MVT::i64));
+ OutChains[5] =
+ DAG.getStore(Root, dl, FunctionAddress, Addr,
+ MachinePointerInfo(TrmpAddr, FunctionAddressOffset));
+
+ SDValue StoreToken = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, OutChains);
+
+ // Compute end of trampoline.
+ SDValue EndOfTrmp = DAG.getNode(ISD::ADD, dl, MVT::i64, Trmp,
+ DAG.getConstant(32, dl, MVT::i64));
+
+ // Call clear cache on the trampoline buffer.
+ SDValue Chain = DAG.getNode(ISD::CLEAR_CACHE, dl, MVT::Other, StoreToken,
----------------
jrtc27 wrote:
I guess the intent is to ensure both I$ and D$ see non-stale data on any hart for the code and written pointers respectively? Were just the I$ relevant, you wouldn't need to cover all 32 bytes.
https://github.com/llvm/llvm-project/pull/96309
More information about the llvm-commits
mailing list