174 lines · cpp
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-exception6//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_CHECKER15#include "MipsGenInstrInfo.inc"16 17namespace llvm {18namespace exegesis {19 20#ifndef NDEBUG21// Returns an error if we cannot handle the memory references in this22// instruction.23static 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#endif43 44// Helper to fill a memory operand with a value.45static 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 54namespace {55class ExegesisMipsTarget : public ExegesisTarget {56public:57 ExegesisMipsTarget()58 : ExegesisTarget(MipsCpuPfmCounters, Mips_MC::isOpcodeAvailable) {}59 60private: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 namespace74 75// Generates instructions to load an immediate value into a register.76static 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 the104 // 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 137MCRegister138ExegesisMipsTarget::getScratchMemoryRegister(const Triple &TT) const {139 return TT.isArch64Bit() ? Mips::A0_64 : Mips::A0;140}141 142void 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)); // IndexReg148 setMemOp(IT, 1, MCOperand::createReg(Reg)); // BaseReg149 setMemOp(IT, 2, MCOperand::createImm(Offset)); // Disp150}151 152std::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 163static ExegesisTarget *getTheExegesisMipsTarget() {164 static ExegesisMipsTarget Target;165 return &Target;166}167 168void InitializeMipsExegesisTarget() {169 ExegesisTarget::registerTarget(getTheExegesisMipsTarget());170}171 172} // namespace exegesis173} // namespace llvm174