1//===---- MipsABIInfo.cpp - Information about MIPS ABI's ------------------===//
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
9#include "MipsABIInfo.h"
10#include "Mips.h"
11#include "llvm/ADT/StringRef.h"
12#include "llvm/MC/MCTargetOptions.h"
13#include "llvm/Support/CommandLine.h"
14
15using namespace llvm;
16
17// Note: this option is defined here to be visible from libLLVMMipsAsmParser
18// and libLLVMMipsCodeGen
19cl::opt<bool>
20EmitJalrReloc("mips-jalr-reloc", cl::Hidden,
21 cl::desc("MIPS: Emit R_{MICRO}MIPS_JALR relocation with jalr"),
22 cl::init(Val: true));
23cl::opt<bool>
24 NoZeroDivCheck("mno-check-zero-division", cl::Hidden,
25 cl::desc("MIPS: Don't trap on integer division by zero."),
26 cl::init(Val: false));
27
28namespace {
29static constexpr MCPhysReg O32IntRegs[] = {Mips::A0, Mips::A1, Mips::A2,
30 Mips::A3};
31static constexpr MCPhysReg NABIIntRegs[] = {Mips::A0, Mips::A1, Mips::A2,
32 Mips::A3, Mips::T0, Mips::T1,
33 Mips::T2, Mips::T3};
34static constexpr MCPhysReg Mips64IntRegs[] = {
35 Mips::A0_64, Mips::A1_64, Mips::A2_64, Mips::A3_64,
36 Mips::T0_64, Mips::T1_64, Mips::T2_64, Mips::T3_64};
37
38struct GPR {
39 MCPhysReg Reg32;
40 MCPhysReg Reg64;
41};
42
43static constexpr GPR OABITempRegs[] = {
44 {.Reg32: Mips::T0, .Reg64: Mips::T0_64}, {.Reg32: Mips::T1, .Reg64: Mips::T1_64}, {.Reg32: Mips::T2, .Reg64: Mips::T2_64},
45 {.Reg32: Mips::T3, .Reg64: Mips::T3_64}, {.Reg32: Mips::T4, .Reg64: Mips::T4_64}, {.Reg32: Mips::T5, .Reg64: Mips::T5_64},
46 {.Reg32: Mips::T6, .Reg64: Mips::T6_64}, {.Reg32: Mips::T7, .Reg64: Mips::T7_64}, {.Reg32: Mips::T8, .Reg64: Mips::T8_64},
47 {.Reg32: Mips::T9, .Reg64: Mips::T9_64},
48};
49
50static constexpr GPR NABITempRegs[] = {
51 {.Reg32: Mips::T4, .Reg64: Mips::T4_64},
52 {.Reg32: Mips::T5, .Reg64: Mips::T5_64},
53 {.Reg32: Mips::T6, .Reg64: Mips::T6_64},
54 {.Reg32: Mips::T7, .Reg64: Mips::T7_64},
55 {.Reg32: Mips::NoRegister, .Reg64: Mips::NoRegister},
56 {.Reg32: Mips::NoRegister, .Reg64: Mips::NoRegister},
57 {.Reg32: Mips::NoRegister, .Reg64: Mips::NoRegister},
58 {.Reg32: Mips::NoRegister, .Reg64: Mips::NoRegister},
59 {.Reg32: Mips::T8, .Reg64: Mips::T8_64},
60 {.Reg32: Mips::T9, .Reg64: Mips::T9_64},
61};
62
63static constexpr GPR PABITempRegs[] = {
64 {.Reg32: Mips::T4, .Reg64: Mips::T4_64},
65 {.Reg32: Mips::T5, .Reg64: Mips::T5_64},
66 {.Reg32: Mips::T6, .Reg64: Mips::T6_64},
67 {.Reg32: Mips::T7, .Reg64: Mips::T7_64},
68 {.Reg32: Mips::V0, .Reg64: Mips::V0_64},
69 {.Reg32: Mips::V1, .Reg64: Mips::V1_64},
70 {.Reg32: Mips::NoRegister, .Reg64: Mips::NoRegister},
71 {.Reg32: Mips::NoRegister, .Reg64: Mips::NoRegister},
72 {.Reg32: Mips::T8, .Reg64: Mips::T8_64},
73 {.Reg32: Mips::T9, .Reg64: Mips::T9_64},
74};
75
76static constexpr GPR SavedRegs[] = {
77 {.Reg32: Mips::S0, .Reg64: Mips::S0_64}, {.Reg32: Mips::S1, .Reg64: Mips::S1_64}, {.Reg32: Mips::S2, .Reg64: Mips::S2_64},
78 {.Reg32: Mips::S3, .Reg64: Mips::S3_64}, {.Reg32: Mips::S4, .Reg64: Mips::S4_64}, {.Reg32: Mips::S5, .Reg64: Mips::S5_64},
79 {.Reg32: Mips::S6, .Reg64: Mips::S6_64}, {.Reg32: Mips::S7, .Reg64: Mips::S7_64},
80};
81
82static constexpr GPR ReturnRegs[] = {
83 {.Reg32: Mips::V0, .Reg64: Mips::V0_64},
84 {.Reg32: Mips::V1, .Reg64: Mips::V1_64},
85};
86
87MCRegister getReg(ArrayRef<GPR> Regs, unsigned I, bool Is64Bit) {
88 assert(I < Regs.size() && "Invalid ABI register index");
89 MCRegister Reg = Is64Bit ? Regs[I].Reg64 : Regs[I].Reg32;
90 assert(Reg && "Register name is not defined by this ABI");
91 return Reg;
92}
93} // namespace
94
95ArrayRef<MCPhysReg> MipsABIInfo::getArgRegs(bool Is64Bit) const {
96 assert(IsKnown() && "Unknown ABI");
97 if (Is64Bit)
98 return ArrayRef(Mips64IntRegs).take_front(N: IsO32() ? 4 : 8);
99 return IsO32() ? ArrayRef(O32IntRegs) : ArrayRef(NABIIntRegs);
100}
101
102ArrayRef<MCPhysReg> MipsABIInfo::GetByValArgRegs() const {
103 return getArgRegs(Is64Bit: AreGprs64bit());
104}
105
106unsigned MipsABIInfo::getRegAltNameIndex() const {
107 switch (ThisABI) {
108 case ABI::O32:
109 return Mips::OABIRegAltName;
110 case ABI::N32:
111 case ABI::N64:
112 return Mips::NABIRegAltName;
113 case ABI::Unknown:
114 llvm_unreachable("Unknown ABI");
115 }
116 llvm_unreachable("Unhandled ABI");
117}
118
119MCRegister MipsABIInfo::getArgReg(unsigned I, bool Is64Bit) const {
120 ArrayRef<MCPhysReg> Regs = getArgRegs(Is64Bit);
121 assert(I < Regs.size() && "Invalid argument register");
122 return Regs[I];
123}
124
125MCRegister MipsABIInfo::getTempReg(unsigned I, bool Is64Bit) const {
126 switch (getRegAltNameIndex()) {
127 case Mips::OABIRegAltName:
128 return getReg(Regs: OABITempRegs, I, Is64Bit);
129 case Mips::NABIRegAltName:
130 return getReg(Regs: NABITempRegs, I, Is64Bit);
131 case Mips::PABIRegAltName:
132 return getReg(Regs: PABITempRegs, I, Is64Bit);
133 default:
134 llvm_unreachable("Unknown register naming convention");
135 }
136}
137
138MCRegister MipsABIInfo::getSavedReg(unsigned I, bool Is64Bit) const {
139 assert(IsKnown() && "Unknown ABI");
140 return getReg(Regs: SavedRegs, I, Is64Bit);
141}
142
143MCRegister MipsABIInfo::getReturnReg(unsigned I, bool Is64Bit) const {
144 switch (ThisABI) {
145 case ABI::O32:
146 case ABI::N32:
147 case ABI::N64:
148 return getReg(Regs: ReturnRegs, I, Is64Bit);
149 case ABI::Unknown:
150 llvm_unreachable("Unknown ABI");
151 }
152 llvm_unreachable("Unhandled ABI");
153}
154
155ArrayRef<MCPhysReg> MipsABIInfo::getVarArgRegs(bool isGP64bit) const {
156 if (IsO32()) {
157 if (isGP64bit)
158 return ArrayRef(Mips64IntRegs);
159 else
160 return ArrayRef(O32IntRegs);
161 }
162 if (IsN32() || IsN64())
163 return ArrayRef(Mips64IntRegs);
164 llvm_unreachable("Unhandled ABI");
165}
166
167unsigned MipsABIInfo::GetCalleeAllocdArgSizeInBytes(CallingConv::ID CC) const {
168 if (IsO32())
169 return CC != CallingConv::Fast ? 16 : 0;
170 if (IsN32() || IsN64())
171 return 0;
172 llvm_unreachable("Unhandled ABI");
173}
174
175MipsABIInfo MipsABIInfo::computeTargetABI(const Triple &TT, StringRef ABIName) {
176 if (ABIName.starts_with(Prefix: "o32"))
177 return MipsABIInfo::O32();
178 if (ABIName.starts_with(Prefix: "n32"))
179 return MipsABIInfo::N32();
180 if (ABIName.starts_with(Prefix: "n64"))
181 return MipsABIInfo::N64();
182 if (TT.isABIN32())
183 return MipsABIInfo::N32();
184 assert(ABIName.empty() && "Unknown ABI option for MIPS");
185
186 if (TT.isMIPS64())
187 return MipsABIInfo::N64();
188 return MipsABIInfo::O32();
189}
190
191unsigned MipsABIInfo::GetStackPtr() const {
192 return ArePtrs64bit() ? Mips::SP_64 : Mips::SP;
193}
194
195unsigned MipsABIInfo::GetFramePtr() const {
196 return ArePtrs64bit() ? Mips::FP_64 : Mips::FP;
197}
198
199unsigned MipsABIInfo::GetBasePtr() const { return getSavedRegPtr(I: 7); }
200
201unsigned MipsABIInfo::GetGlobalPtr() const {
202 return ArePtrs64bit() ? Mips::GP_64 : Mips::GP;
203}
204
205unsigned MipsABIInfo::GetNullPtr() const {
206 return ArePtrs64bit() ? Mips::ZERO_64 : Mips::ZERO;
207}
208
209unsigned MipsABIInfo::GetZeroReg() const {
210 return AreGprs64bit() ? Mips::ZERO_64 : Mips::ZERO;
211}
212
213unsigned MipsABIInfo::GetPtrAdduOp() const {
214 return ArePtrs64bit() ? Mips::DADDu : Mips::ADDu;
215}
216
217unsigned MipsABIInfo::GetPtrAddiuOp() const {
218 return ArePtrs64bit() ? Mips::DADDiu : Mips::ADDiu;
219}
220
221unsigned MipsABIInfo::GetPtrSubuOp() const {
222 return ArePtrs64bit() ? Mips::DSUBu : Mips::SUBu;
223}
224
225unsigned MipsABIInfo::GetPtrAndOp() const {
226 return ArePtrs64bit() ? Mips::AND64 : Mips::AND;
227}
228
229unsigned MipsABIInfo::GetGPRMoveOp() const {
230 return ArePtrs64bit() ? Mips::OR64 : Mips::OR;
231}
232
233unsigned MipsABIInfo::GetEhDataReg(unsigned I) const {
234 assert(I < 4 && "Invalid EH data register");
235 return getArgRegPtr(I);
236}
237