| //===-- 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 |