|  | //===-- Target.cpp ----------------------------------------------*- C++ -*-===// | 
|  | // | 
|  | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | 
|  | // See https://llvm.org/LICENSE.txt for license information. | 
|  | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  | #include "../Error.h" | 
|  | #include "../Target.h" | 
|  | #include "MCTargetDesc/MipsBaseInfo.h" | 
|  | #include "Mips.h" | 
|  | #include "MipsRegisterInfo.h" | 
|  |  | 
|  | namespace llvm { | 
|  | namespace exegesis { | 
|  |  | 
|  | #ifndef NDEBUG | 
|  | // Returns an error if we cannot handle the memory references in this | 
|  | // instruction. | 
|  | static Error isInvalidMemoryInstr(const Instruction &Instr) { | 
|  | switch (Instr.Description.TSFlags & MipsII::FormMask) { | 
|  | default: | 
|  | llvm_unreachable("Unknown FormMask value"); | 
|  | // These have no memory access. | 
|  | case MipsII::Pseudo: | 
|  | case MipsII::FrmR: | 
|  | case MipsII::FrmJ: | 
|  | case MipsII::FrmFR: | 
|  | return Error::success(); | 
|  | // These access memory and are handled. | 
|  | case MipsII::FrmI: | 
|  | return Error::success(); | 
|  | // These access memory and are not handled yet. | 
|  | case MipsII::FrmFI: | 
|  | case MipsII::FrmOther: | 
|  | return make_error<Failure>("unsupported opcode: non uniform memory access"); | 
|  | } | 
|  | } | 
|  | #endif | 
|  |  | 
|  | // Helper to fill a memory operand with a value. | 
|  | static void setMemOp(InstructionTemplate &IT, int OpIdx, | 
|  | const MCOperand &OpVal) { | 
|  | const auto Op = IT.getInstr().Operands[OpIdx]; | 
|  | assert(Op.isExplicit() && "invalid memory pattern"); | 
|  | IT.getValueFor(Op) = OpVal; | 
|  | } | 
|  |  | 
|  | #include "MipsGenExegesis.inc" | 
|  |  | 
|  | namespace { | 
|  | class ExegesisMipsTarget : public ExegesisTarget { | 
|  | public: | 
|  | ExegesisMipsTarget() : ExegesisTarget(MipsCpuPfmCounters) {} | 
|  |  | 
|  | private: | 
|  | unsigned getScratchMemoryRegister(const llvm::Triple &TT) const override; | 
|  | unsigned getMaxMemoryAccessSize() const override { return 64; } | 
|  | void fillMemoryOperands(InstructionTemplate &IT, unsigned Reg, | 
|  | unsigned Offset) const override; | 
|  |  | 
|  | std::vector<MCInst> setRegTo(const MCSubtargetInfo &STI, unsigned Reg, | 
|  | const APInt &Value) const override; | 
|  | bool matchesArch(Triple::ArchType Arch) const override { | 
|  | return Arch == Triple::mips || Arch == Triple::mipsel || | 
|  | Arch == Triple::mips64 || Arch == Triple::mips64el; | 
|  | } | 
|  | }; | 
|  | } // end anonymous namespace | 
|  |  | 
|  | // Generates instructions to load an immediate value into a register. | 
|  | static std::vector<MCInst> loadImmediate(unsigned Reg, bool IsGPR32, | 
|  | const APInt &Value) { | 
|  | unsigned ZeroReg; | 
|  | unsigned ORi, LUi, SLL; | 
|  | if (IsGPR32) { | 
|  | ZeroReg = Mips::ZERO; | 
|  | ORi = Mips::ORi; | 
|  | SLL = Mips::SLL; | 
|  | LUi = Mips::LUi; | 
|  | } else { | 
|  | ZeroReg = Mips::ZERO_64; | 
|  | ORi = Mips::ORi64; | 
|  | SLL = Mips::SLL64_64; | 
|  | LUi = Mips::LUi64; | 
|  | } | 
|  |  | 
|  | if (Value.isIntN(16)) { | 
|  | return {MCInstBuilder(ORi) | 
|  | .addReg(Reg) | 
|  | .addReg(ZeroReg) | 
|  | .addImm(Value.getZExtValue())}; | 
|  | } | 
|  |  | 
|  | std::vector<MCInst> Instructions; | 
|  | if (Value.isIntN(32)) { | 
|  | const uint16_t HiBits = Value.getHiBits(16).getZExtValue(); | 
|  | if (!IsGPR32 && Value.getActiveBits() == 32) { | 
|  | // Expand to an ORi instead of a LUi to avoid sign-extending into the | 
|  | // upper 32 bits. | 
|  | Instructions.push_back( | 
|  | MCInstBuilder(ORi) | 
|  | .addReg(Reg) | 
|  | .addReg(ZeroReg) | 
|  | .addImm(HiBits)); | 
|  | Instructions.push_back( | 
|  | MCInstBuilder(SLL) | 
|  | .addReg(Reg) | 
|  | .addReg(Reg) | 
|  | .addImm(16)); | 
|  | } else { | 
|  | Instructions.push_back( | 
|  | MCInstBuilder(LUi) | 
|  | .addReg(Reg) | 
|  | .addImm(HiBits)); | 
|  | } | 
|  |  | 
|  | const uint16_t LoBits = Value.getLoBits(16).getZExtValue(); | 
|  | if (LoBits) { | 
|  | Instructions.push_back( | 
|  | MCInstBuilder(ORi) | 
|  | .addReg(Reg) | 
|  | .addReg(ZeroReg) | 
|  | .addImm(LoBits)); | 
|  | } | 
|  |  | 
|  | return Instructions; | 
|  | } | 
|  |  | 
|  | llvm_unreachable("Not implemented for values wider than 32 bits"); | 
|  | } | 
|  |  | 
|  | unsigned ExegesisMipsTarget::getScratchMemoryRegister(const Triple &TT) const { | 
|  | return TT.isArch64Bit() ? Mips::A0_64 : Mips::A0; | 
|  | } | 
|  |  | 
|  | void ExegesisMipsTarget::fillMemoryOperands(InstructionTemplate &IT, | 
|  | unsigned Reg, | 
|  | unsigned Offset) const { | 
|  | assert(!isInvalidMemoryInstr(IT.getInstr()) && | 
|  | "fillMemoryOperands requires a valid memory instruction"); | 
|  | setMemOp(IT, 0, MCOperand::createReg(0));      // IndexReg | 
|  | setMemOp(IT, 1, MCOperand::createReg(Reg));    // BaseReg | 
|  | setMemOp(IT, 2, MCOperand::createImm(Offset)); // Disp | 
|  | } | 
|  |  | 
|  | std::vector<MCInst> ExegesisMipsTarget::setRegTo(const MCSubtargetInfo &STI, | 
|  | unsigned Reg, | 
|  | const APInt &Value) const { | 
|  | if (Mips::GPR32RegClass.contains(Reg)) | 
|  | return loadImmediate(Reg, true, Value); | 
|  | if (Mips::GPR64RegClass.contains(Reg)) | 
|  | return loadImmediate(Reg, false, Value); | 
|  | errs() << "setRegTo is not implemented, results will be unreliable\n"; | 
|  | return {}; | 
|  | } | 
|  |  | 
|  | static ExegesisTarget *getTheExegesisMipsTarget() { | 
|  | static ExegesisMipsTarget Target; | 
|  | return &Target; | 
|  | } | 
|  |  | 
|  | void InitializeMipsExegesisTarget() { | 
|  | ExegesisTarget::registerTarget(getTheExegesisMipsTarget()); | 
|  | } | 
|  |  | 
|  | } // namespace exegesis | 
|  | } // namespace llvm |