@@ -637,6 +637,11 @@ RISCVTargetLowering::RISCVTargetLowering(const TargetMachine &TM,
637
637
setOperationAction(ISD::READSTEADYCOUNTER, MVT::i64,
638
638
Subtarget.is64Bit() ? Legal : Custom);
639
639
640
+ if (Subtarget.is64Bit()) {
641
+ setOperationAction(ISD::INIT_TRAMPOLINE, MVT::Other, Custom);
642
+ setOperationAction(ISD::ADJUST_TRAMPOLINE, MVT::Other, Custom);
643
+ }
644
+
640
645
setOperationAction({ISD::TRAP, ISD::DEBUGTRAP}, MVT::Other, Legal);
641
646
setOperationAction(ISD::INTRINSIC_WO_CHAIN, MVT::Other, Custom);
642
647
if (Subtarget.is64Bit())
@@ -7155,6 +7160,10 @@ SDValue RISCVTargetLowering::LowerOperation(SDValue Op,
7155
7160
return emitFlushICache(DAG, Op.getOperand(0), Op.getOperand(1),
7156
7161
Op.getOperand(2), Flags, DL);
7157
7162
}
7163
+ case ISD::INIT_TRAMPOLINE:
7164
+ return lowerINIT_TRAMPOLINE(Op, DAG);
7165
+ case ISD::ADJUST_TRAMPOLINE:
7166
+ return lowerADJUST_TRAMPOLINE(Op, DAG);
7158
7167
}
7159
7168
}
7160
7169
@@ -7170,6 +7179,123 @@ SDValue RISCVTargetLowering::emitFlushICache(SelectionDAG &DAG, SDValue InChain,
7170
7179
return CallResult.second;
7171
7180
}
7172
7181
7182
+ SDValue RISCVTargetLowering::lowerINIT_TRAMPOLINE(SDValue Op,
7183
+ SelectionDAG &DAG) const {
7184
+ if (!Subtarget.is64Bit())
7185
+ llvm::report_fatal_error("Trampolines only implemented for RV64");
7186
+
7187
+ SDValue Root = Op.getOperand(0);
7188
+ SDValue Trmp = Op.getOperand(1); // trampoline
7189
+ SDLoc dl(Op);
7190
+
7191
+ const Value *TrmpAddr = cast<SrcValueSDNode>(Op.getOperand(4))->getValue();
7192
+
7193
+ // We store in the trampoline buffer the following instructions and data.
7194
+ // Offset:
7195
+ // 0: auipc t2, 0
7196
+ // 4: ld t0, 24(t2)
7197
+ // 8: ld t2, 16(t2)
7198
+ // 12: jalr t0
7199
+ // 16: <StaticChainOffset>
7200
+ // 24: <FunctionAddressOffset>
7201
+ // 32:
7202
+
7203
+ // Constants shamelessly taken from GCC.
7204
+ constexpr unsigned Opcode_AUIPC = 0x17;
7205
+ constexpr unsigned Opcode_LD = 0x3003;
7206
+ constexpr unsigned Opcode_JALR = 0x67;
7207
+ constexpr unsigned ShiftField_RD = 7;
7208
+ constexpr unsigned ShiftField_RS1 = 15;
7209
+ constexpr unsigned ShiftField_IMM = 20;
7210
+ constexpr unsigned Reg_X5 = 0x5; // x5/t0 (holds the address to the function)
7211
+ constexpr unsigned Reg_X7 = 0x7; // x7/t2 (holds the static chain)
7212
+
7213
+ constexpr unsigned StaticChainOffset = 16;
7214
+ constexpr unsigned FunctionAddressOffset = 24;
7215
+
7216
+ SDValue OutChains[6];
7217
+ SDValue Addr = Trmp;
7218
+
7219
+ // auipc t2, 0
7220
+ // Loads the current PC into t2.
7221
+ constexpr uint32_t AUIPC_X7_0 =
7222
+ Opcode_AUIPC | (Reg_X7 << ShiftField_RD);
7223
+ OutChains[0] =
7224
+ DAG.getTruncStore(Root, dl, DAG.getConstant(AUIPC_X7_0, dl, MVT::i64),
7225
+ Addr, MachinePointerInfo(TrmpAddr), MVT::i32);
7226
+
7227
+ // ld t0, 24(t2)
7228
+ // Loads the function address into t0. Note that we are using offsets
7229
+ // pc-relative to the first instruction of the trampoline.
7230
+ const uint32_t LD_X5_TargetFunctionOffset =
7231
+ Opcode_LD | (Reg_X5 << ShiftField_RD) |
7232
+ (Reg_X7 << ShiftField_RS1) | (FunctionAddressOffset << ShiftField_IMM);
7233
+ Addr = DAG.getNode(ISD::ADD, dl, MVT::i64, Trmp,
7234
+ DAG.getConstant(4, dl, MVT::i64));
7235
+ OutChains[1] = DAG.getTruncStore(
7236
+ Root, dl,
7237
+ DAG.getConstant(LD_X5_TargetFunctionOffset, dl, MVT::i64), Addr,
7238
+ MachinePointerInfo(TrmpAddr, 4), MVT::i32);
7239
+
7240
+ // ld t2, 16(t2)
7241
+ // Load the value of the static chain.
7242
+ const uint32_t LD_X7_StaticChainOffset =
7243
+ Opcode_LD | (Reg_X7 << ShiftField_RD) |
7244
+ (Reg_X7 << ShiftField_RS1) | (StaticChainOffset << ShiftField_IMM);
7245
+ Addr = DAG.getNode(ISD::ADD, dl, MVT::i64, Trmp,
7246
+ DAG.getConstant(8, dl, MVT::i64));
7247
+ OutChains[2] = DAG.getTruncStore(
7248
+ Root, dl, DAG.getConstant(LD_X7_StaticChainOffset, dl, MVT::i64),
7249
+ Addr, MachinePointerInfo(TrmpAddr, 8), MVT::i32);
7250
+
7251
+ // jalr t0
7252
+ // Jump to the function.
7253
+ const uint32_t JALR_X5 =
7254
+ Opcode_JALR | (Reg_X5 << ShiftField_RS1);
7255
+ Addr = DAG.getNode(ISD::ADD, dl, MVT::i64, Trmp,
7256
+ DAG.getConstant(12, dl, MVT::i64));
7257
+ OutChains[3] =
7258
+ DAG.getTruncStore(Root, dl, DAG.getConstant(JALR_X5, dl, MVT::i64), Addr,
7259
+ MachinePointerInfo(TrmpAddr, 12), MVT::i32);
7260
+
7261
+ // Now store the variable part of the trampoline.
7262
+ SDValue FunctionAddress = Op.getOperand(2);
7263
+ SDValue StaticChain = Op.getOperand(3);
7264
+
7265
+ // Store the given static chain in the trampoline buffer.
7266
+ Addr = DAG.getNode(ISD::ADD, dl, MVT::i64, Trmp,
7267
+ DAG.getConstant(StaticChainOffset, dl, MVT::i64));
7268
+ OutChains[4] = DAG.getStore(Root, dl, StaticChain, Addr,
7269
+ MachinePointerInfo(TrmpAddr, StaticChainOffset));
7270
+
7271
+ // Store the given function address in the trampoline buffer.
7272
+ Addr = DAG.getNode(ISD::ADD, dl, MVT::i64, Trmp,
7273
+ DAG.getConstant(FunctionAddressOffset, dl, MVT::i64));
7274
+ OutChains[5] =
7275
+ DAG.getStore(Root, dl, FunctionAddress, Addr,
7276
+ MachinePointerInfo(TrmpAddr, FunctionAddressOffset));
7277
+
7278
+ SDValue StoreToken = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, OutChains);
7279
+
7280
+ // Compute end of trampoline.
7281
+ SDValue EndOfTrmp = DAG.getNode(ISD::ADD, dl, MVT::i64, Trmp,
7282
+ DAG.getConstant(32, dl, MVT::i64));
7283
+
7284
+ // Call clear cache on the trampoline buffer.
7285
+ SDValue Chain = DAG.getNode(ISD::CLEAR_CACHE, dl, MVT::Other, StoreToken,
7286
+ Trmp, EndOfTrmp);
7287
+
7288
+ return Chain;
7289
+ }
7290
+
7291
+ SDValue RISCVTargetLowering::lowerADJUST_TRAMPOLINE(SDValue Op,
7292
+ SelectionDAG &DAG) const {
7293
+ if (!Subtarget.is64Bit())
7294
+ llvm::report_fatal_error("Trampolines only implemented for RV64");
7295
+
7296
+ return Op.getOperand(0);
7297
+ }
7298
+
7173
7299
static SDValue getTargetNode(GlobalAddressSDNode *N, const SDLoc &DL, EVT Ty,
7174
7300
SelectionDAG &DAG, unsigned Flags) {
7175
7301
return DAG.getTargetGlobalAddress(N->getGlobal(), DL, Ty, 0, Flags);
0 commit comments