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 #include "../Error.h" 9 #include "../Target.h" 10 #include "MCTargetDesc/MipsBaseInfo.h" 11 #include "Mips.h" 12 #include "MipsRegisterInfo.h" 13 14 #define GET_AVAILABLE_OPCODE_CHECKER 15 #include "MipsGenInstrInfo.inc" 16 17 namespace llvm { 18 namespace exegesis { 19 20 #ifndef NDEBUG 21 // Returns an error if we cannot handle the memory references in this 22 // instruction. 23 static Error isInvalidMemoryInstr(const Instruction &Instr) { 24 switch (Instr.Description.TSFlags & MipsII::FormMask) { 25 default: 26 llvm_unreachable("Unknown FormMask value"); 27 // These have no memory access. 28 case MipsII::Pseudo: 29 case MipsII::FrmR: 30 case MipsII::FrmJ: 31 case MipsII::FrmFR: 32 return Error::success(); 33 // These access memory and are handled. 34 case MipsII::FrmI: 35 return Error::success(); 36 // These access memory and are not handled yet. 37 case MipsII::FrmFI: 38 case MipsII::FrmOther: 39 return make_error<Failure>("unsupported opcode: non uniform memory access"); 40 } 41 } 42 #endif 43 44 // Helper to fill a memory operand with a value. 45 static void setMemOp(InstructionTemplate &IT, int OpIdx, 46 const MCOperand &OpVal) { 47 const auto Op = IT.getInstr().Operands[OpIdx]; 48 assert(Op.isExplicit() && "invalid memory pattern"); 49 IT.getValueFor(Op) = OpVal; 50 } 51 52 #include "MipsGenExegesis.inc" 53 54 namespace { 55 class ExegesisMipsTarget : public ExegesisTarget { 56 public: 57 ExegesisMipsTarget() 58 : ExegesisTarget(MipsCpuPfmCounters, Mips_MC::isOpcodeAvailable) {} 59 60 private: 61 MCRegister getScratchMemoryRegister(const Triple &TT) const override; 62 unsigned getMaxMemoryAccessSize() const override { return 64; } 63 void fillMemoryOperands(InstructionTemplate &IT, MCRegister Reg, 64 unsigned Offset) const override; 65 66 std::vector<MCInst> setRegTo(const MCSubtargetInfo &STI, MCRegister Reg, 67 const APInt &Value) const override; 68 bool matchesArch(Triple::ArchType Arch) const override { 69 return Arch == Triple::mips || Arch == Triple::mipsel || 70 Arch == Triple::mips64 || Arch == Triple::mips64el; 71 } 72 }; 73 } // end anonymous namespace 74 75 // Generates instructions to load an immediate value into a register. 76 static std::vector<MCInst> loadImmediate(MCRegister Reg, bool IsGPR32, 77 const APInt &Value) { 78 unsigned ZeroReg; 79 unsigned ORi, LUi, SLL; 80 if (IsGPR32) { 81 ZeroReg = Mips::ZERO; 82 ORi = Mips::ORi; 83 SLL = Mips::SLL; 84 LUi = Mips::LUi; 85 } else { 86 ZeroReg = Mips::ZERO_64; 87 ORi = Mips::ORi64; 88 SLL = Mips::SLL64_64; 89 LUi = Mips::LUi64; 90 } 91 92 if (Value.isIntN(16)) { 93 return {MCInstBuilder(ORi) 94 .addReg(Reg) 95 .addReg(ZeroReg) 96 .addImm(Value.getZExtValue())}; 97 } 98 99 std::vector<MCInst> Instructions; 100 if (Value.isIntN(32)) { 101 const uint16_t HiBits = Value.getHiBits(16).getZExtValue(); 102 if (!IsGPR32 && Value.getActiveBits() == 32) { 103 // Expand to an ORi instead of a LUi to avoid sign-extending into the 104 // upper 32 bits. 105 Instructions.push_back( 106 MCInstBuilder(ORi) 107 .addReg(Reg) 108 .addReg(ZeroReg) 109 .addImm(HiBits)); 110 Instructions.push_back( 111 MCInstBuilder(SLL) 112 .addReg(Reg) 113 .addReg(Reg) 114 .addImm(16)); 115 } else { 116 Instructions.push_back( 117 MCInstBuilder(LUi) 118 .addReg(Reg) 119 .addImm(HiBits)); 120 } 121 122 const uint16_t LoBits = Value.getLoBits(16).getZExtValue(); 123 if (LoBits) { 124 Instructions.push_back( 125 MCInstBuilder(ORi) 126 .addReg(Reg) 127 .addReg(ZeroReg) 128 .addImm(LoBits)); 129 } 130 131 return Instructions; 132 } 133 134 llvm_unreachable("Not implemented for values wider than 32 bits"); 135 } 136 137 MCRegister 138 ExegesisMipsTarget::getScratchMemoryRegister(const Triple &TT) const { 139 return TT.isArch64Bit() ? Mips::A0_64 : Mips::A0; 140 } 141 142 void ExegesisMipsTarget::fillMemoryOperands(InstructionTemplate &IT, 143 MCRegister Reg, 144 unsigned Offset) const { 145 assert(!isInvalidMemoryInstr(IT.getInstr()) && 146 "fillMemoryOperands requires a valid memory instruction"); 147 setMemOp(IT, 0, MCOperand::createReg(0)); // IndexReg 148 setMemOp(IT, 1, MCOperand::createReg(Reg)); // BaseReg 149 setMemOp(IT, 2, MCOperand::createImm(Offset)); // Disp 150 } 151 152 std::vector<MCInst> ExegesisMipsTarget::setRegTo(const MCSubtargetInfo &STI, 153 MCRegister Reg, 154 const APInt &Value) const { 155 if (Mips::GPR32RegClass.contains(Reg)) 156 return loadImmediate(Reg, true, Value); 157 if (Mips::GPR64RegClass.contains(Reg)) 158 return loadImmediate(Reg, false, Value); 159 errs() << "setRegTo is not implemented, results will be unreliable\n"; 160 return {}; 161 } 162 163 static ExegesisTarget *getTheExegesisMipsTarget() { 164 static ExegesisMipsTarget Target; 165 return &Target; 166 } 167 168 void InitializeMipsExegesisTarget() { 169 ExegesisTarget::registerTarget(getTheExegesisMipsTarget()); 170 } 171 172 } // namespace exegesis 173 } // namespace llvm 174