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 | unsigned getScratchMemoryRegister(const Triple &TT) const override; |
62 | unsigned getMaxMemoryAccessSize() const override { return 64; } |
63 | void fillMemoryOperands(InstructionTemplate &IT, unsigned Reg, |
64 | unsigned Offset) const override; |
65 | |
66 | std::vector<MCInst> setRegTo(const MCSubtargetInfo &STI, unsigned 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(unsigned 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(N: 16)) { |
93 | return {MCInstBuilder(ORi) |
94 | .addReg(Reg) |
95 | .addReg(Reg: ZeroReg) |
96 | .addImm(Val: Value.getZExtValue())}; |
97 | } |
98 | |
99 | std::vector<MCInst> Instructions; |
100 | if (Value.isIntN(N: 32)) { |
101 | const uint16_t HiBits = Value.getHiBits(numBits: 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 | x: MCInstBuilder(ORi) |
107 | .addReg(Reg) |
108 | .addReg(Reg: ZeroReg) |
109 | .addImm(Val: HiBits)); |
110 | Instructions.push_back( |
111 | x: MCInstBuilder(SLL) |
112 | .addReg(Reg) |
113 | .addReg(Reg) |
114 | .addImm(Val: 16)); |
115 | } else { |
116 | Instructions.push_back( |
117 | x: MCInstBuilder(LUi) |
118 | .addReg(Reg) |
119 | .addImm(Val: HiBits)); |
120 | } |
121 | |
122 | const uint16_t LoBits = Value.getLoBits(numBits: 16).getZExtValue(); |
123 | if (LoBits) { |
124 | Instructions.push_back( |
125 | x: MCInstBuilder(ORi) |
126 | .addReg(Reg) |
127 | .addReg(Reg: ZeroReg) |
128 | .addImm(Val: LoBits)); |
129 | } |
130 | |
131 | return Instructions; |
132 | } |
133 | |
134 | llvm_unreachable("Not implemented for values wider than 32 bits" ); |
135 | } |
136 | |
137 | unsigned ExegesisMipsTarget::getScratchMemoryRegister(const Triple &TT) const { |
138 | return TT.isArch64Bit() ? Mips::A0_64 : Mips::A0; |
139 | } |
140 | |
141 | void ExegesisMipsTarget::fillMemoryOperands(InstructionTemplate &IT, |
142 | unsigned Reg, |
143 | unsigned Offset) const { |
144 | assert(!isInvalidMemoryInstr(IT.getInstr()) && |
145 | "fillMemoryOperands requires a valid memory instruction" ); |
146 | setMemOp(IT, OpIdx: 0, OpVal: MCOperand::createReg(Reg: 0)); // IndexReg |
147 | setMemOp(IT, OpIdx: 1, OpVal: MCOperand::createReg(Reg)); // BaseReg |
148 | setMemOp(IT, OpIdx: 2, OpVal: MCOperand::createImm(Val: Offset)); // Disp |
149 | } |
150 | |
151 | std::vector<MCInst> ExegesisMipsTarget::setRegTo(const MCSubtargetInfo &STI, |
152 | unsigned Reg, |
153 | const APInt &Value) const { |
154 | if (Mips::GPR32RegClass.contains(Reg)) |
155 | return loadImmediate(Reg, IsGPR32: true, Value); |
156 | if (Mips::GPR64RegClass.contains(Reg)) |
157 | return loadImmediate(Reg, IsGPR32: false, Value); |
158 | errs() << "setRegTo is not implemented, results will be unreliable\n" ; |
159 | return {}; |
160 | } |
161 | |
162 | static ExegesisTarget *getTheExegesisMipsTarget() { |
163 | static ExegesisMipsTarget Target; |
164 | return &Target; |
165 | } |
166 | |
167 | void InitializeMipsExegesisTarget() { |
168 | ExegesisTarget::registerTarget(T: getTheExegesisMipsTarget()); |
169 | } |
170 | |
171 | } // namespace exegesis |
172 | } // namespace llvm |
173 | |