1 //===-- Target.cpp ----------------------------------------------*- C++ -*-===// 2 // 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 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "../Target.h" 10 11 #include "MCTargetDesc/RISCVBaseInfo.h" 12 #include "MCTargetDesc/RISCVMCTargetDesc.h" 13 #include "MCTargetDesc/RISCVMatInt.h" 14 #include "RISCVInstrInfo.h" 15 16 // include computeAvailableFeatures and computeRequiredFeatures. 17 #define GET_AVAILABLE_OPCODE_CHECKER 18 #include "RISCVGenInstrInfo.inc" 19 20 #include "llvm/CodeGen/MachineInstrBuilder.h" 21 22 #include <vector> 23 24 namespace llvm { 25 namespace exegesis { 26 27 #include "RISCVGenExegesis.inc" 28 29 namespace { 30 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; 36 37 RISCVMatInt::generateMCInstSeq(Value.getSExtValue(), STI, DestReg, MCInstSeq); 38 39 std::vector<MCInst> MatIntInstrs(MCInstSeq.begin(), MCInstSeq.end()); 40 return MatIntInstrs; 41 } 42 43 const MCPhysReg ScratchIntReg = RISCV::X30; // t5 44 45 // Stores constant bits to a floating-point register. 46 static std::vector<MCInst> loadFPRegBits(const MCSubtargetInfo &STI, 47 MCRegister Reg, const APInt &Bits, 48 unsigned FmvOpcode) { 49 std::vector<MCInst> Instrs = loadIntReg(STI, ScratchIntReg, Bits); 50 Instrs.push_back(MCInstBuilder(FmvOpcode).addReg(Reg).addReg(ScratchIntReg)); 51 return Instrs; 52 } 53 54 // main idea is: 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, 60 MCRegister Reg, 61 const APInt &Bits) { 62 double D = Bits.bitsToDouble(); 63 double IPart; 64 double FPart = std::modf(D, &IPart); 65 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"; 69 return {}; 70 } 71 72 std::vector<MCInst> Instrs = loadIntReg(STI, ScratchIntReg, Bits); 73 Instrs.push_back( 74 MCInstBuilder(RISCV::FCVT_D_W).addReg(Reg).addReg(ScratchIntReg)); 75 return Instrs; 76 } 77 78 static MCInst nop() { 79 // ADDI X0, X0, 0 80 return MCInstBuilder(RISCV::ADDI) 81 .addReg(RISCV::X0) 82 .addReg(RISCV::X0) 83 .addImm(0); 84 } 85 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); 101 } 102 103 class ExegesisRISCVTarget : public ExegesisTarget { 104 public: 105 ExegesisRISCVTarget(); 106 107 bool matchesArch(Triple::ArchType Arch) const override; 108 109 std::vector<MCInst> setRegTo(const MCSubtargetInfo &STI, MCRegister Reg, 110 const APInt &Value) const override; 111 112 MCRegister getDefaultLoopCounterRegister(const Triple &) const override; 113 114 void decrementLoopCounterAndJump(MachineBasicBlock &MBB, 115 MachineBasicBlock &TargetMBB, 116 const MCInstrInfo &MII, 117 MCRegister LoopRegister) const override; 118 119 MCRegister getScratchMemoryRegister(const Triple &TT) const override; 120 121 void fillMemoryOperands(InstructionTemplate &IT, MCRegister Reg, 122 unsigned Offset) const override; 123 124 ArrayRef<MCPhysReg> getUnavailableRegisters() const override; 125 126 bool allowAsBackToBack(const Instruction &Instr) const override { 127 return !Instr.Description.isPseudo(); 128 } 129 130 Error randomizeTargetMCOperand(const Instruction &Instr, const Variable &Var, 131 MCOperand &AssignedValue, 132 const BitVector &ForbiddenRegs) const override; 133 134 std::vector<InstructionTemplate> 135 generateInstructionVariants(const Instruction &Instr, 136 unsigned MaxConfigsPerOpcode) const override; 137 }; 138 139 ExegesisRISCVTarget::ExegesisRISCVTarget() 140 : ExegesisTarget(RISCVCpuPfmCounters, RISCV_MC::isOpcodeAvailable) {} 141 142 bool ExegesisRISCVTarget::matchesArch(Triple::ArchType Arch) const { 143 return Arch == Triple::riscv32 || Arch == Triple::riscv64; 144 } 145 146 std::vector<MCInst> ExegesisRISCVTarget::setRegTo(const MCSubtargetInfo &STI, 147 MCRegister Reg, 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); 159 } 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)) { 163 // Don't initialize: 164 // - FRM 165 // - VL, VLENB, VTYPE 166 // - vector registers (and vector register lists) 167 // - Zfinx registers 168 // Generate 'NOP' so that exegesis treats such registers as initialized 169 // (it tries to initialize them with '0' anyway). 170 return {nop()}; 171 } 172 errs() << "setRegTo is not implemented for Reg " << Reg 173 << ", results will be unreliable\n"; 174 return {}; 175 } 176 177 const MCPhysReg DefaultLoopCounterReg = RISCV::X31; // t6 178 const MCPhysReg ScratchMemoryReg = RISCV::X10; // a0 179 180 MCRegister 181 ExegesisRISCVTarget::getDefaultLoopCounterRegister(const Triple &) const { 182 return DefaultLoopCounterReg; 183 } 184 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) 191 .addImm(-1); 192 BuildMI(&MBB, DebugLoc(), MII.get(RISCV::BNE)) 193 .addUse(LoopRegister) 194 .addUse(RISCV::X0) 195 .addMBB(&TargetMBB); 196 } 197 198 MCRegister 199 ExegesisRISCVTarget::getScratchMemoryRegister(const Triple &TT) const { 200 return ScratchMemoryReg; // a0 201 } 202 203 void ExegesisRISCVTarget::fillMemoryOperands(InstructionTemplate &IT, 204 MCRegister Reg, 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(); 209 210 auto MemOpIt = 211 find_if(I.Operands, [](const Operand &Op) { return Op.isMemory(); }); 212 assert(MemOpIt != I.Operands.end() && 213 "Instruction must have memory operands"); 214 215 const Operand &MemOp = *MemOpIt; 216 217 assert(MemOp.isReg() && "Memory operand expected to be register"); 218 219 IT.getValueFor(MemOp) = MCOperand::createReg(Reg); 220 } 221 222 const MCPhysReg UnavailableRegisters[4] = {RISCV::X0, DefaultLoopCounterReg, 223 ScratchIntReg, ScratchMemoryReg}; 224 225 ArrayRef<MCPhysReg> ExegesisRISCVTarget::getUnavailableRegisters() const { 226 return UnavailableRegisters; 227 } 228 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; 234 235 switch (OperandType) { 236 case RISCVOp::OPERAND_FRMARG: 237 AssignedValue = MCOperand::createImm(RISCVFPRndMode::DYN); 238 break; 239 case RISCVOp::OPERAND_SIMM10_LSB0000_NONZERO: 240 AssignedValue = MCOperand::createImm(0b1 << 4); 241 break; 242 case RISCVOp::OPERAND_SIMM6_NONZERO: 243 case RISCVOp::OPERAND_UIMMLOG2XLEN_NONZERO: 244 AssignedValue = MCOperand::createImm(1); 245 break; 246 default: 247 if (OperandType >= RISCVOp::OPERAND_FIRST_RISCV_IMM && 248 OperandType <= RISCVOp::OPERAND_LAST_RISCV_IMM) 249 AssignedValue = MCOperand::createImm(0); 250 } 251 return Error::success(); 252 } 253 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) 259 if (Op.isMemory()) { 260 IT.getValueFor(Op) = MCOperand::createReg(ScratchMemoryReg); 261 } 262 return {IT}; 263 } 264 265 } // anonymous namespace 266 267 static ExegesisTarget *getTheRISCVExegesisTarget() { 268 static ExegesisRISCVTarget Target; 269 return &Target; 270 } 271 272 void InitializeRISCVExegesisTarget() { 273 ExegesisTarget::registerTarget(getTheRISCVExegesisTarget()); 274 } 275 276 } // namespace exegesis 277 } // namespace llvm 278