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