1 //===-- Target.cpp ----------------------------------------------*- C++ -*-===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
11 #include "MCTargetDesc/RISCVBaseInfo.h"
12 #include "MCTargetDesc/RISCVMCTargetDesc.h"
13 #include "MCTargetDesc/RISCVMatInt.h"
14 #include "RISCVInstrInfo.h"
16 // include computeAvailableFeatures and computeRequiredFeatures.
17 #define GET_AVAILABLE_OPCODE_CHECKER
18 #include "RISCVGenInstrInfo.inc"
20 #include "llvm/CodeGen/MachineInstrBuilder.h"
27 #include "RISCVGenExegesis.inc"
31 // Stores constant value to a general-purpose (integer) register.
32 static std::vector
<MCInst
> loadIntReg(const MCSubtargetInfo
&STI
,
33 MCRegister Reg
, const APInt
&Value
) {
34 SmallVector
<MCInst
, 8> MCInstSeq
;
35 MCRegister DestReg
= Reg
;
37 RISCVMatInt::generateMCInstSeq(Value
.getSExtValue(), STI
, DestReg
, MCInstSeq
);
39 std::vector
<MCInst
> MatIntInstrs(MCInstSeq
.begin(), MCInstSeq
.end());
43 const MCPhysReg ScratchIntReg
= RISCV::X30
; // t5
45 // Stores constant bits to a floating-point register.
46 static std::vector
<MCInst
> loadFPRegBits(const MCSubtargetInfo
&STI
,
47 MCRegister Reg
, const APInt
&Bits
,
49 std::vector
<MCInst
> Instrs
= loadIntReg(STI
, ScratchIntReg
, Bits
);
50 Instrs
.push_back(MCInstBuilder(FmvOpcode
).addReg(Reg
).addReg(ScratchIntReg
));
55 // we support APInt only if (represented as double) it has zero fractional
56 // part: 1.0, 2.0, 3.0, etc... then we can do the trick: write int to tmp reg t5
57 // and then do FCVT this is only reliable thing in 32-bit mode, otherwise we
58 // need to use __floatsidf
59 static std::vector
<MCInst
> loadFP64RegBits32(const MCSubtargetInfo
&STI
,
62 double D
= Bits
.bitsToDouble();
64 double FPart
= std::modf(D
, &IPart
);
66 if (std::abs(FPart
) > std::numeric_limits
<double>::epsilon()) {
67 errs() << "loadFP64RegBits32 is not implemented for doubles like " << D
68 << ", please remove fractional part\n";
72 std::vector
<MCInst
> Instrs
= loadIntReg(STI
, ScratchIntReg
, Bits
);
74 MCInstBuilder(RISCV::FCVT_D_W
).addReg(Reg
).addReg(ScratchIntReg
));
80 return MCInstBuilder(RISCV::ADDI
)
86 static bool isVectorRegList(MCRegister Reg
) {
87 return RISCV::VRM2RegClass
.contains(Reg
) ||
88 RISCV::VRM4RegClass
.contains(Reg
) ||
89 RISCV::VRM8RegClass
.contains(Reg
) ||
90 RISCV::VRN2M1RegClass
.contains(Reg
) ||
91 RISCV::VRN2M2RegClass
.contains(Reg
) ||
92 RISCV::VRN2M4RegClass
.contains(Reg
) ||
93 RISCV::VRN3M1RegClass
.contains(Reg
) ||
94 RISCV::VRN3M2RegClass
.contains(Reg
) ||
95 RISCV::VRN4M1RegClass
.contains(Reg
) ||
96 RISCV::VRN4M2RegClass
.contains(Reg
) ||
97 RISCV::VRN5M1RegClass
.contains(Reg
) ||
98 RISCV::VRN6M1RegClass
.contains(Reg
) ||
99 RISCV::VRN7M1RegClass
.contains(Reg
) ||
100 RISCV::VRN8M1RegClass
.contains(Reg
);
103 class ExegesisRISCVTarget
: public ExegesisTarget
{
105 ExegesisRISCVTarget();
107 bool matchesArch(Triple::ArchType Arch
) const override
;
109 std::vector
<MCInst
> setRegTo(const MCSubtargetInfo
&STI
, MCRegister Reg
,
110 const APInt
&Value
) const override
;
112 MCRegister
getDefaultLoopCounterRegister(const Triple
&) const override
;
114 void decrementLoopCounterAndJump(MachineBasicBlock
&MBB
,
115 MachineBasicBlock
&TargetMBB
,
116 const MCInstrInfo
&MII
,
117 MCRegister LoopRegister
) const override
;
119 MCRegister
getScratchMemoryRegister(const Triple
&TT
) const override
;
121 void fillMemoryOperands(InstructionTemplate
&IT
, MCRegister Reg
,
122 unsigned Offset
) const override
;
124 ArrayRef
<MCPhysReg
> getUnavailableRegisters() const override
;
126 bool allowAsBackToBack(const Instruction
&Instr
) const override
{
127 return !Instr
.Description
.isPseudo();
130 Error
randomizeTargetMCOperand(const Instruction
&Instr
, const Variable
&Var
,
131 MCOperand
&AssignedValue
,
132 const BitVector
&ForbiddenRegs
) const override
;
134 std::vector
<InstructionTemplate
>
135 generateInstructionVariants(const Instruction
&Instr
,
136 unsigned MaxConfigsPerOpcode
) const override
;
139 ExegesisRISCVTarget::ExegesisRISCVTarget()
140 : ExegesisTarget(RISCVCpuPfmCounters
, RISCV_MC::isOpcodeAvailable
) {}
142 bool ExegesisRISCVTarget::matchesArch(Triple::ArchType Arch
) const {
143 return Arch
== Triple::riscv32
|| Arch
== Triple::riscv64
;
146 std::vector
<MCInst
> ExegesisRISCVTarget::setRegTo(const MCSubtargetInfo
&STI
,
148 const APInt
&Value
) const {
149 if (RISCV::GPRRegClass
.contains(Reg
))
150 return loadIntReg(STI
, Reg
, Value
);
151 if (RISCV::FPR16RegClass
.contains(Reg
))
152 return loadFPRegBits(STI
, Reg
, Value
, RISCV::FMV_H_X
);
153 if (RISCV::FPR32RegClass
.contains(Reg
))
154 return loadFPRegBits(STI
, Reg
, Value
, RISCV::FMV_W_X
);
155 if (RISCV::FPR64RegClass
.contains(Reg
)) {
156 if (STI
.hasFeature(RISCV::Feature64Bit
))
157 return loadFPRegBits(STI
, Reg
, Value
, RISCV::FMV_D_X
);
158 return loadFP64RegBits32(STI
, Reg
, Value
);
160 if (Reg
== RISCV::FRM
|| Reg
== RISCV::VL
|| Reg
== RISCV::VLENB
||
161 Reg
== RISCV::VTYPE
|| RISCV::GPRPairRegClass
.contains(Reg
) ||
162 RISCV::VRRegClass
.contains(Reg
) || isVectorRegList(Reg
)) {
165 // - VL, VLENB, VTYPE
166 // - vector registers (and vector register lists)
168 // Generate 'NOP' so that exegesis treats such registers as initialized
169 // (it tries to initialize them with '0' anyway).
172 errs() << "setRegTo is not implemented for Reg " << Reg
173 << ", results will be unreliable\n";
177 const MCPhysReg DefaultLoopCounterReg
= RISCV::X31
; // t6
178 const MCPhysReg ScratchMemoryReg
= RISCV::X10
; // a0
181 ExegesisRISCVTarget::getDefaultLoopCounterRegister(const Triple
&) const {
182 return DefaultLoopCounterReg
;
185 void ExegesisRISCVTarget::decrementLoopCounterAndJump(
186 MachineBasicBlock
&MBB
, MachineBasicBlock
&TargetMBB
,
187 const MCInstrInfo
&MII
, MCRegister LoopRegister
) const {
188 BuildMI(&MBB
, DebugLoc(), MII
.get(RISCV::ADDI
))
189 .addDef(LoopRegister
)
190 .addUse(LoopRegister
)
192 BuildMI(&MBB
, DebugLoc(), MII
.get(RISCV::BNE
))
193 .addUse(LoopRegister
)
199 ExegesisRISCVTarget::getScratchMemoryRegister(const Triple
&TT
) const {
200 return ScratchMemoryReg
; // a0
203 void ExegesisRISCVTarget::fillMemoryOperands(InstructionTemplate
&IT
,
205 unsigned Offset
) const {
206 // TODO: for now we ignore Offset because have no way
207 // to detect it in instruction.
208 auto &I
= IT
.getInstr();
211 find_if(I
.Operands
, [](const Operand
&Op
) { return Op
.isMemory(); });
212 assert(MemOpIt
!= I
.Operands
.end() &&
213 "Instruction must have memory operands");
215 const Operand
&MemOp
= *MemOpIt
;
217 assert(MemOp
.isReg() && "Memory operand expected to be register");
219 IT
.getValueFor(MemOp
) = MCOperand::createReg(Reg
);
222 const MCPhysReg UnavailableRegisters
[4] = {RISCV::X0
, DefaultLoopCounterReg
,
223 ScratchIntReg
, ScratchMemoryReg
};
225 ArrayRef
<MCPhysReg
> ExegesisRISCVTarget::getUnavailableRegisters() const {
226 return UnavailableRegisters
;
229 Error
ExegesisRISCVTarget::randomizeTargetMCOperand(
230 const Instruction
&Instr
, const Variable
&Var
, MCOperand
&AssignedValue
,
231 const BitVector
&ForbiddenRegs
) const {
232 uint8_t OperandType
=
233 Instr
.getPrimaryOperand(Var
).getExplicitOperandInfo().OperandType
;
235 switch (OperandType
) {
236 case RISCVOp::OPERAND_FRMARG
:
237 AssignedValue
= MCOperand::createImm(RISCVFPRndMode::DYN
);
239 case RISCVOp::OPERAND_SIMM10_LSB0000_NONZERO
:
240 AssignedValue
= MCOperand::createImm(0b1 << 4);
242 case RISCVOp::OPERAND_SIMM6_NONZERO
:
243 case RISCVOp::OPERAND_UIMMLOG2XLEN_NONZERO
:
244 AssignedValue
= MCOperand::createImm(1);
247 if (OperandType
>= RISCVOp::OPERAND_FIRST_RISCV_IMM
&&
248 OperandType
<= RISCVOp::OPERAND_LAST_RISCV_IMM
)
249 AssignedValue
= MCOperand::createImm(0);
251 return Error::success();
254 std::vector
<InstructionTemplate
>
255 ExegesisRISCVTarget::generateInstructionVariants(
256 const Instruction
&Instr
, unsigned int MaxConfigsPerOpcode
) const {
257 InstructionTemplate IT
{&Instr
};
258 for (const Operand
&Op
: Instr
.Operands
)
260 IT
.getValueFor(Op
) = MCOperand::createReg(ScratchMemoryReg
);
265 } // anonymous namespace
267 static ExegesisTarget
*getTheRISCVExegesisTarget() {
268 static ExegesisRISCVTarget Target
;
272 void InitializeRISCVExegesisTarget() {
273 ExegesisTarget::registerTarget(getTheRISCVExegesisTarget());
276 } // namespace exegesis