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