blob: ccf56594f24950a59749066ebf1d4a2bd79dc640 [file] [log] [blame]
Jim Stichnoth6da4cef2015-06-11 13:26:33 -07001//
2// The Subzero Code Generator
3//
4// This file is distributed under the University of Illinois Open Source
5// License. See LICENSE.TXT for details.
6//
7//===----------------------------------------------------------------------===//
Andrew Scull9612d322015-07-06 14:53:25 -07008///
9/// \file
Jim Stichnoth92a6e5b2015-12-02 16:52:44 -080010/// \brief Implements the TargetLoweringMIPS32 class, which consists almost
Andrew Scull9612d322015-07-06 14:53:25 -070011/// entirely of the lowering sequence for each high-level instruction.
12///
Jim Stichnoth6da4cef2015-06-11 13:26:33 -070013//===----------------------------------------------------------------------===//
14
John Porto67f8de92015-06-25 10:14:17 -070015#include "IceTargetLoweringMIPS32.h"
Jim Stichnoth6da4cef2015-06-11 13:26:33 -070016
17#include "IceCfg.h"
18#include "IceCfgNode.h"
19#include "IceClFlags.h"
20#include "IceDefs.h"
21#include "IceELFObjectWriter.h"
22#include "IceGlobalInits.h"
23#include "IceInstMIPS32.h"
Sagar Thakur5cce7612016-05-24 06:25:50 -070024#include "IceInstVarIter.h"
Jim Stichnoth6da4cef2015-06-11 13:26:33 -070025#include "IceLiveness.h"
26#include "IceOperand.h"
Jim Stichnothac8da5c2015-10-21 06:57:46 -070027#include "IcePhiLoweringImpl.h"
Jim Stichnoth6da4cef2015-06-11 13:26:33 -070028#include "IceRegistersMIPS32.h"
29#include "IceTargetLoweringMIPS32.def"
Jim Stichnoth6da4cef2015-06-11 13:26:33 -070030#include "IceUtils.h"
John Porto67f8de92015-06-25 10:14:17 -070031#include "llvm/Support/MathExtras.h"
Jim Stichnoth6da4cef2015-06-11 13:26:33 -070032
John Porto53611e22015-12-30 07:30:10 -080033namespace MIPS32 {
34std::unique_ptr<::Ice::TargetLowering> createTargetLowering(::Ice::Cfg *Func) {
John Porto4a566862016-01-04 09:33:41 -080035 return ::Ice::MIPS32::TargetMIPS32::create(Func);
John Porto53611e22015-12-30 07:30:10 -080036}
37
38std::unique_ptr<::Ice::TargetDataLowering>
39createTargetDataLowering(::Ice::GlobalContext *Ctx) {
John Porto4a566862016-01-04 09:33:41 -080040 return ::Ice::MIPS32::TargetDataMIPS32::create(Ctx);
John Porto53611e22015-12-30 07:30:10 -080041}
42
43std::unique_ptr<::Ice::TargetHeaderLowering>
44createTargetHeaderLowering(::Ice::GlobalContext *Ctx) {
John Porto4a566862016-01-04 09:33:41 -080045 return ::Ice::MIPS32::TargetHeaderMIPS32::create(Ctx);
John Porto53611e22015-12-30 07:30:10 -080046}
47
Karl Schimpf5403f5d2016-01-15 11:07:46 -080048void staticInit(::Ice::GlobalContext *Ctx) {
49 ::Ice::MIPS32::TargetMIPS32::staticInit(Ctx);
Jim Stichnoth8ff4b282016-01-04 15:39:06 -080050}
Jim Stichnoth467ffe52016-03-29 15:01:06 -070051
52bool shouldBePooled(const ::Ice::Constant *C) {
53 return ::Ice::MIPS32::TargetMIPS32::shouldBePooled(C);
54}
Nicolas Capens32f9cce2016-10-19 01:24:27 -040055
56::Ice::Type getPointerType() {
57 return ::Ice::MIPS32::TargetMIPS32::getPointerType();
58}
59
John Porto53611e22015-12-30 07:30:10 -080060} // end of namespace MIPS32
61
Jim Stichnoth6da4cef2015-06-11 13:26:33 -070062namespace Ice {
John Porto4a566862016-01-04 09:33:41 -080063namespace MIPS32 {
Jim Stichnoth6da4cef2015-06-11 13:26:33 -070064
Jim Stichnothac8da5c2015-10-21 06:57:46 -070065using llvm::isInt;
66
67namespace {
68
69// The maximum number of arguments to pass in GPR registers.
70constexpr uint32_t MIPS32_MAX_GPR_ARG = 4;
71
Mohit Bhakkadf90118a2016-06-13 00:28:13 -070072std::array<RegNumT, MIPS32_MAX_GPR_ARG> GPRArgInitializer;
73std::array<RegNumT, MIPS32_MAX_GPR_ARG / 2> I64ArgInitializer;
74
75constexpr uint32_t MIPS32_MAX_FP_ARG = 2;
76
77std::array<RegNumT, MIPS32_MAX_FP_ARG> FP32ArgInitializer;
78std::array<RegNumT, MIPS32_MAX_FP_ARG> FP64ArgInitializer;
79
Jim Stichnoth467ffe52016-03-29 15:01:06 -070080const char *getRegClassName(RegClass C) {
Jim Stichnoth2544d4d2016-01-22 13:07:46 -080081 auto ClassNum = static_cast<RegClassMIPS32>(C);
82 assert(ClassNum < RCMIPS32_NUM);
83 switch (ClassNum) {
84 default:
85 assert(C < RC_Target);
86 return regClassString(C);
87 // Add handling of new register classes below.
88 }
89}
90
Sagar Thakura49fce02016-06-13 05:55:00 -070091// Stack alignment
Sagar Thakurccbb6d12016-09-14 06:09:26 -070092constexpr uint32_t MIPS32_STACK_ALIGNMENT_BYTES = 16;
Sagar Thakura49fce02016-06-13 05:55:00 -070093
94// Value is in bytes. Return Value adjusted to the next highest multiple of the
95// stack alignment required for the given type.
96uint32_t applyStackAlignmentTy(uint32_t Value, Type Ty) {
97 size_t typeAlignInBytes = typeWidthInBytes(Ty);
Jaydeep Patil958ddb72016-10-03 07:52:48 -070098 // Vectors are stored on stack with the same alignment as that of int type
Sagar Thakura49fce02016-06-13 05:55:00 -070099 if (isVectorType(Ty))
Jaydeep Patil2bbda7f2017-01-10 21:48:58 -0800100 typeAlignInBytes = typeWidthInBytes(IceType_i64);
Sagar Thakura49fce02016-06-13 05:55:00 -0700101 return Utils::applyAlignment(Value, typeAlignInBytes);
102}
103
Mohit Bhakkad9b4c3c32016-06-22 05:44:05 -0700104// Value is in bytes. Return Value adjusted to the next highest multiple of the
105// stack alignment.
106uint32_t applyStackAlignment(uint32_t Value) {
107 return Utils::applyAlignment(Value, MIPS32_STACK_ALIGNMENT_BYTES);
108}
109
Jim Stichnothac8da5c2015-10-21 06:57:46 -0700110} // end of anonymous namespace
111
Stefan Maksimovic6e033432016-11-09 17:31:51 -0800112TargetMIPS32::TargetMIPS32(Cfg *Func)
113 : TargetLowering(Func), NeedSandboxing(SandboxingType == ST_NaCl) {}
Jim Stichnothac8da5c2015-10-21 06:57:46 -0700114
Sagar Thakur752e59f2016-07-21 06:12:09 -0700115void TargetMIPS32::assignVarStackSlots(VarList &SortedSpilledVariables,
116 size_t SpillAreaPaddingBytes,
117 size_t SpillAreaSizeBytes,
118 size_t GlobalsAndSubsequentPaddingSize) {
119 const VariablesMetadata *VMetadata = Func->getVMetadata();
120 size_t GlobalsSpaceUsed = SpillAreaPaddingBytes;
121 size_t NextStackOffset = SpillAreaPaddingBytes;
122 CfgVector<size_t> LocalsSize(Func->getNumNodes());
123 const bool SimpleCoalescing = !callsReturnsTwice();
Sagar Thakur752e59f2016-07-21 06:12:09 -0700124 for (Variable *Var : SortedSpilledVariables) {
125 size_t Increment = typeWidthInBytesOnStack(Var->getType());
126 if (SimpleCoalescing && VMetadata->isTracked(Var)) {
127 if (VMetadata->isMultiBlock(Var)) {
128 GlobalsSpaceUsed += Increment;
129 NextStackOffset = GlobalsSpaceUsed;
130 } else {
131 SizeT NodeIndex = VMetadata->getLocalUseNode(Var)->getIndex();
132 LocalsSize[NodeIndex] += Increment;
133 NextStackOffset = SpillAreaPaddingBytes +
134 GlobalsAndSubsequentPaddingSize +
135 LocalsSize[NodeIndex];
136 }
137 } else {
138 NextStackOffset += Increment;
139 }
140 Var->setStackOffset(SpillAreaSizeBytes - NextStackOffset);
141 }
142}
143
Karl Schimpf5403f5d2016-01-15 11:07:46 -0800144void TargetMIPS32::staticInit(GlobalContext *Ctx) {
145 (void)Ctx;
Jim Stichnoth8aa39662016-02-10 11:20:30 -0800146 RegNumT::setLimit(RegMIPS32::Reg_NUM);
John Portoe82b5602016-02-24 15:58:55 -0800147 SmallBitVector IntegerRegisters(RegMIPS32::Reg_NUM);
148 SmallBitVector I64PairRegisters(RegMIPS32::Reg_NUM);
149 SmallBitVector Float32Registers(RegMIPS32::Reg_NUM);
150 SmallBitVector Float64Registers(RegMIPS32::Reg_NUM);
151 SmallBitVector VectorRegisters(RegMIPS32::Reg_NUM);
152 SmallBitVector InvalidRegisters(RegMIPS32::Reg_NUM);
Jim Stichnoth6da4cef2015-06-11 13:26:33 -0700153#define X(val, encode, name, scratch, preserved, stackptr, frameptr, isInt, \
Jim Stichnothac8da5c2015-10-21 06:57:46 -0700154 isI64Pair, isFP32, isFP64, isVec128, alias_init) \
Jim Stichnoth6da4cef2015-06-11 13:26:33 -0700155 IntegerRegisters[RegMIPS32::val] = isInt; \
Jim Stichnothac8da5c2015-10-21 06:57:46 -0700156 I64PairRegisters[RegMIPS32::val] = isI64Pair; \
157 Float32Registers[RegMIPS32::val] = isFP32; \
158 Float64Registers[RegMIPS32::val] = isFP64; \
159 VectorRegisters[RegMIPS32::val] = isVec128; \
John Portobb0a5fe2015-09-04 11:23:41 -0700160 RegisterAliases[RegMIPS32::val].resize(RegMIPS32::Reg_NUM); \
Jim Stichnothac8da5c2015-10-21 06:57:46 -0700161 for (SizeT RegAlias : alias_init) { \
162 assert(!RegisterAliases[RegMIPS32::val][RegAlias] && \
163 "Duplicate alias for " #val); \
164 RegisterAliases[RegMIPS32::val].set(RegAlias); \
165 } \
166 RegisterAliases[RegMIPS32::val].resize(RegMIPS32::Reg_NUM); \
Jim Stichnoth29d15fd2016-01-19 10:25:37 -0800167 assert(RegisterAliases[RegMIPS32::val][RegMIPS32::val]);
Jim Stichnoth6da4cef2015-06-11 13:26:33 -0700168 REGMIPS32_TABLE;
169#undef X
Mohit Bhakkadf90118a2016-06-13 00:28:13 -0700170
171 // TODO(mohit.bhakkad): Change these inits once we provide argument related
172 // field in register tables
173 for (size_t i = 0; i < MIPS32_MAX_GPR_ARG; i++)
174 GPRArgInitializer[i] = RegNumT::fixme(RegMIPS32::Reg_A0 + i);
175
176 for (size_t i = 0; i < MIPS32_MAX_GPR_ARG / 2; i++)
177 I64ArgInitializer[i] = RegNumT::fixme(RegMIPS32::Reg_A0A1 + i);
178
179 for (size_t i = 0; i < MIPS32_MAX_FP_ARG; i++) {
180 FP32ArgInitializer[i] = RegNumT::fixme(RegMIPS32::Reg_F12 + i * 2);
181 FP64ArgInitializer[i] = RegNumT::fixme(RegMIPS32::Reg_F12F13 + i);
182 }
183
Jim Stichnoth6da4cef2015-06-11 13:26:33 -0700184 TypeToRegisterSet[IceType_void] = InvalidRegisters;
185 TypeToRegisterSet[IceType_i1] = IntegerRegisters;
186 TypeToRegisterSet[IceType_i8] = IntegerRegisters;
187 TypeToRegisterSet[IceType_i16] = IntegerRegisters;
188 TypeToRegisterSet[IceType_i32] = IntegerRegisters;
189 TypeToRegisterSet[IceType_i64] = IntegerRegisters;
Jim Stichnothac8da5c2015-10-21 06:57:46 -0700190 TypeToRegisterSet[IceType_f32] = Float32Registers;
191 TypeToRegisterSet[IceType_f64] = Float64Registers;
Jim Stichnoth6da4cef2015-06-11 13:26:33 -0700192 TypeToRegisterSet[IceType_v4i1] = VectorRegisters;
193 TypeToRegisterSet[IceType_v8i1] = VectorRegisters;
194 TypeToRegisterSet[IceType_v16i1] = VectorRegisters;
195 TypeToRegisterSet[IceType_v16i8] = VectorRegisters;
196 TypeToRegisterSet[IceType_v8i16] = VectorRegisters;
197 TypeToRegisterSet[IceType_v4i32] = VectorRegisters;
198 TypeToRegisterSet[IceType_v4f32] = VectorRegisters;
Karl Schimpf5403f5d2016-01-15 11:07:46 -0800199
Jim Stichnothb40595a2016-01-29 06:14:31 -0800200 for (size_t i = 0; i < llvm::array_lengthof(TypeToRegisterSet); ++i)
201 TypeToRegisterSetUnfiltered[i] = TypeToRegisterSet[i];
202
Karl Schimpf5403f5d2016-01-15 11:07:46 -0800203 filterTypeToRegisterSet(Ctx, RegMIPS32::Reg_NUM, TypeToRegisterSet,
Jim Stichnoth2544d4d2016-01-22 13:07:46 -0800204 llvm::array_lengthof(TypeToRegisterSet),
205 RegMIPS32::getRegName, getRegClassName);
Jim Stichnoth6da4cef2015-06-11 13:26:33 -0700206}
207
Sagar Thakur1afb4832016-06-16 15:30:24 -0700208void TargetMIPS32::unsetIfNonLeafFunc() {
209 for (CfgNode *Node : Func->getNodes()) {
210 for (Inst &Instr : Node->getInsts()) {
211 if (llvm::isa<InstCall>(&Instr)) {
212 // Unset MaybeLeafFunc if call instruction exists.
213 MaybeLeafFunc = false;
214 return;
215 }
216 }
217 }
218}
219
220uint32_t TargetMIPS32::getStackAlignment() const {
221 return MIPS32_STACK_ALIGNMENT_BYTES;
222}
223
Sagar Thakur46832372016-10-16 07:20:44 -0700224uint32_t TargetMIPS32::getCallStackArgumentsSizeBytes(const InstCall *Call) {
225 TargetMIPS32::CallingConv CC;
226 RegNumT DummyReg;
227 size_t OutArgsSizeBytes = 0;
Jaydeep Patil8be69752016-11-28 06:57:27 -0800228 Variable *Dest = Call->getDest();
229 bool PartialOnStack = false;
230 if (Dest != nullptr && isVectorFloatingType(Dest->getType())) {
231 CC.discardReg(RegMIPS32::Reg_A0);
232 // Next vector is partially on stack
233 PartialOnStack = true;
234 }
Sagar Thakur46832372016-10-16 07:20:44 -0700235 for (SizeT i = 0, NumArgs = Call->getNumArgs(); i < NumArgs; ++i) {
236 Operand *Arg = legalizeUndef(Call->getArg(i));
237 const Type Ty = Arg->getType();
238 RegNumT RegNum;
239 if (CC.argInReg(Ty, i, &RegNum)) {
Jaydeep Patil8be69752016-11-28 06:57:27 -0800240 // If PartialOnStack is true and if this is a vector type then last two
241 // elements are on stack
242 if (PartialOnStack && isVectorType(Ty)) {
Jaydeep Patil2bbda7f2017-01-10 21:48:58 -0800243 OutArgsSizeBytes = applyStackAlignmentTy(OutArgsSizeBytes, IceType_i64);
Jaydeep Patil8be69752016-11-28 06:57:27 -0800244 OutArgsSizeBytes += typeWidthInBytesOnStack(IceType_i32) * 2;
245 }
Sagar Thakur46832372016-10-16 07:20:44 -0700246 continue;
247 }
Sagar Thakur46832372016-10-16 07:20:44 -0700248 OutArgsSizeBytes = applyStackAlignmentTy(OutArgsSizeBytes, Ty);
249 OutArgsSizeBytes += typeWidthInBytesOnStack(Ty);
250 }
Jaydeep Patil8be69752016-11-28 06:57:27 -0800251 // Add size of argument save area
252 constexpr int BytesPerStackArg = 4;
253 OutArgsSizeBytes += MIPS32_MAX_GPR_ARG * BytesPerStackArg;
Sagar Thakur46832372016-10-16 07:20:44 -0700254 return applyStackAlignment(OutArgsSizeBytes);
255}
256
Sagar Thakurbecb85f2016-11-18 12:15:46 -0800257namespace {
258inline uint64_t getConstantMemoryOrder(Operand *Opnd) {
259 if (auto *Integer = llvm::dyn_cast<ConstantInteger32>(Opnd))
260 return Integer->getValue();
261 return Intrinsics::MemoryOrderInvalid;
262}
263}
264
Srdjan Obucinab85cde12016-09-09 09:39:52 -0700265void TargetMIPS32::genTargetHelperCallFor(Inst *Instr) {
266 constexpr bool NoTailCall = false;
267 constexpr bool IsTargetHelperCall = true;
Jaydeep Patil3a01f332016-10-17 06:33:50 -0700268 Variable *Dest = Instr->getDest();
269 const Type DestTy = Dest ? Dest->getType() : IceType_void;
Srdjan Obucinab85cde12016-09-09 09:39:52 -0700270
271 switch (Instr->getKind()) {
272 default:
273 return;
Jaydeep Patil3a01f332016-10-17 06:33:50 -0700274 case Inst::Select: {
275 if (isVectorType(DestTy)) {
276 Operand *SrcT = llvm::cast<InstSelect>(Instr)->getTrueOperand();
277 Operand *SrcF = llvm::cast<InstSelect>(Instr)->getFalseOperand();
278 Operand *Cond = llvm::cast<InstSelect>(Instr)->getCondition();
279 Variable *T = Func->makeVariable(DestTy);
280 auto *Undef = ConstantUndef::create(Ctx, DestTy);
281 Context.insert<InstAssign>(T, Undef);
282 auto *VarVecOn32 = llvm::cast<VariableVecOn32>(T);
283 VarVecOn32->initVecElement(Func);
284 for (SizeT I = 0; I < typeNumElements(DestTy); ++I) {
285 auto *Index = Ctx->getConstantInt32(I);
286 auto *OpC = Func->makeVariable(typeElementType(Cond->getType()));
287 Context.insert<InstExtractElement>(OpC, Cond, Index);
288 auto *OpT = Func->makeVariable(typeElementType(DestTy));
289 Context.insert<InstExtractElement>(OpT, SrcT, Index);
290 auto *OpF = Func->makeVariable(typeElementType(DestTy));
291 Context.insert<InstExtractElement>(OpF, SrcF, Index);
292 auto *Dst = Func->makeVariable(typeElementType(DestTy));
293 Variable *DestT = Func->makeVariable(DestTy);
294 Context.insert<InstSelect>(Dst, OpC, OpT, OpF);
295 Context.insert<InstInsertElement>(DestT, T, Dst, Index);
296 T = DestT;
297 }
298 Context.insert<InstAssign>(Dest, T);
299 Instr->setDeleted();
300 }
301 return;
302 }
303 case Inst::Fcmp: {
304 if (isVectorType(DestTy)) {
305 InstFcmp::FCond Cond = llvm::cast<InstFcmp>(Instr)->getCondition();
306 Operand *Src0 = Instr->getSrc(0);
307 Operand *Src1 = Instr->getSrc(1);
308 Variable *T = Func->makeVariable(IceType_v4f32);
309 auto *Undef = ConstantUndef::create(Ctx, IceType_v4f32);
310 Context.insert<InstAssign>(T, Undef);
311 auto *VarVecOn32 = llvm::cast<VariableVecOn32>(T);
312 VarVecOn32->initVecElement(Func);
313 for (SizeT I = 0; I < typeNumElements(IceType_v4f32); ++I) {
314 auto *Index = Ctx->getConstantInt32(I);
315 auto *Op0 = Func->makeVariable(IceType_f32);
316 Context.insert<InstExtractElement>(Op0, Src0, Index);
317 auto *Op1 = Func->makeVariable(IceType_f32);
318 Context.insert<InstExtractElement>(Op1, Src1, Index);
319 auto *Dst = Func->makeVariable(IceType_f32);
320 Variable *DestT = Func->makeVariable(IceType_v4f32);
321 Context.insert<InstFcmp>(Cond, Dst, Op0, Op1);
322 Context.insert<InstInsertElement>(DestT, T, Dst, Index);
323 T = DestT;
324 }
325 Context.insert<InstAssign>(Dest, T);
326 Instr->setDeleted();
327 }
328 return;
329 }
330 case Inst::Icmp: {
331 if (isVectorType(DestTy)) {
332 InstIcmp::ICond Cond = llvm::cast<InstIcmp>(Instr)->getCondition();
333 Operand *Src0 = Instr->getSrc(0);
334 Operand *Src1 = Instr->getSrc(1);
335 const Type SrcType = Src0->getType();
336 Variable *T = Func->makeVariable(DestTy);
337 auto *Undef = ConstantUndef::create(Ctx, DestTy);
338 Context.insert<InstAssign>(T, Undef);
339 auto *VarVecOn32 = llvm::cast<VariableVecOn32>(T);
340 VarVecOn32->initVecElement(Func);
341 for (SizeT I = 0; I < typeNumElements(SrcType); ++I) {
342 auto *Index = Ctx->getConstantInt32(I);
343 auto *Op0 = Func->makeVariable(typeElementType(SrcType));
344 Context.insert<InstExtractElement>(Op0, Src0, Index);
345 auto *Op1 = Func->makeVariable(typeElementType(SrcType));
346 Context.insert<InstExtractElement>(Op1, Src1, Index);
347 auto *Dst = Func->makeVariable(typeElementType(DestTy));
348 Variable *DestT = Func->makeVariable(DestTy);
349 Context.insert<InstIcmp>(Cond, Dst, Op0, Op1);
350 Context.insert<InstInsertElement>(DestT, T, Dst, Index);
351 T = DestT;
352 }
353 Context.insert<InstAssign>(Dest, T);
354 Instr->setDeleted();
355 }
356 return;
357 }
Srdjan Obucinab85cde12016-09-09 09:39:52 -0700358 case Inst::Arithmetic: {
Srdjan Obucinab85cde12016-09-09 09:39:52 -0700359 const InstArithmetic::OpKind Op =
360 llvm::cast<InstArithmetic>(Instr)->getOp();
361 if (isVectorType(DestTy)) {
Jaydeep Patil958ddb72016-10-03 07:52:48 -0700362 scalarizeArithmetic(Op, Dest, Instr->getSrc(0), Instr->getSrc(1));
363 Instr->setDeleted();
364 return;
Srdjan Obucinab85cde12016-09-09 09:39:52 -0700365 }
366 switch (DestTy) {
367 default:
368 return;
369 case IceType_i64: {
370 RuntimeHelper HelperID = RuntimeHelper::H_Num;
371 switch (Op) {
372 default:
373 return;
374 case InstArithmetic::Udiv:
375 HelperID = RuntimeHelper::H_udiv_i64;
376 break;
377 case InstArithmetic::Sdiv:
378 HelperID = RuntimeHelper::H_sdiv_i64;
379 break;
380 case InstArithmetic::Urem:
381 HelperID = RuntimeHelper::H_urem_i64;
382 break;
383 case InstArithmetic::Srem:
384 HelperID = RuntimeHelper::H_srem_i64;
385 break;
386 }
387
388 if (HelperID == RuntimeHelper::H_Num) {
389 return;
390 }
391
392 Operand *TargetHelper = Ctx->getRuntimeHelperFunc(HelperID);
393 constexpr SizeT MaxArgs = 2;
394 auto *Call = Context.insert<InstCall>(MaxArgs, Dest, TargetHelper,
395 NoTailCall, IsTargetHelperCall);
396 Call->addArg(Instr->getSrc(0));
397 Call->addArg(Instr->getSrc(1));
398 Instr->setDeleted();
399 return;
400 }
Srdjan Obucinab85cde12016-09-09 09:39:52 -0700401 case IceType_f32:
402 case IceType_f64: {
403 if (Op != InstArithmetic::Frem) {
404 return;
405 }
406 constexpr SizeT MaxArgs = 2;
407 Operand *TargetHelper = Ctx->getRuntimeHelperFunc(
408 DestTy == IceType_f32 ? RuntimeHelper::H_frem_f32
409 : RuntimeHelper::H_frem_f64);
410 auto *Call = Context.insert<InstCall>(MaxArgs, Dest, TargetHelper,
411 NoTailCall, IsTargetHelperCall);
412 Call->addArg(Instr->getSrc(0));
413 Call->addArg(Instr->getSrc(1));
414 Instr->setDeleted();
415 return;
416 }
417 }
418 llvm::report_fatal_error("Control flow should never have reached here.");
419 }
420 case Inst::Cast: {
Srdjan Obucinab85cde12016-09-09 09:39:52 -0700421 Operand *Src0 = Instr->getSrc(0);
Srdjan Obucinab85cde12016-09-09 09:39:52 -0700422 const Type SrcTy = Src0->getType();
423 auto *CastInstr = llvm::cast<InstCast>(Instr);
424 const InstCast::OpKind CastKind = CastInstr->getCastKind();
Jaydeep Patil3a01f332016-10-17 06:33:50 -0700425
426 if (isVectorType(DestTy)) {
427 Variable *T = Func->makeVariable(DestTy);
428 auto *VarVecOn32 = llvm::cast<VariableVecOn32>(T);
429 VarVecOn32->initVecElement(Func);
430 auto *Undef = ConstantUndef::create(Ctx, DestTy);
431 Context.insert<InstAssign>(T, Undef);
432 for (SizeT I = 0; I < typeNumElements(DestTy); ++I) {
433 auto *Index = Ctx->getConstantInt32(I);
434 auto *Op = Func->makeVariable(typeElementType(SrcTy));
435 Context.insert<InstExtractElement>(Op, Src0, Index);
436 auto *Dst = Func->makeVariable(typeElementType(DestTy));
437 Variable *DestT = Func->makeVariable(DestTy);
438 Context.insert<InstCast>(CastKind, Dst, Op);
439 Context.insert<InstInsertElement>(DestT, T, Dst, Index);
440 T = DestT;
441 }
442 Context.insert<InstAssign>(Dest, T);
443 Instr->setDeleted();
444 return;
445 }
446
Srdjan Obucinab85cde12016-09-09 09:39:52 -0700447 switch (CastKind) {
448 default:
449 return;
450 case InstCast::Fptosi:
451 case InstCast::Fptoui: {
Srdjan Obucina4c49b102016-09-26 20:12:17 -0700452 if ((DestTy != IceType_i32) && (DestTy != IceType_i64)) {
Srdjan Obucinab85cde12016-09-09 09:39:52 -0700453 return;
454 }
Srdjan Obucina4c49b102016-09-26 20:12:17 -0700455 const bool DestIs32 = DestTy == IceType_i32;
Srdjan Obucinab85cde12016-09-09 09:39:52 -0700456 const bool DestIsSigned = CastKind == InstCast::Fptosi;
457 const bool Src0IsF32 = isFloat32Asserting32Or64(SrcTy);
Srdjan Obucina4c49b102016-09-26 20:12:17 -0700458 RuntimeHelper RTHFunc = RuntimeHelper::H_Num;
459 if (DestIsSigned) {
460 if (DestIs32) {
461 return;
462 }
463 RTHFunc = Src0IsF32 ? RuntimeHelper::H_fptosi_f32_i64
464 : RuntimeHelper::H_fptosi_f64_i64;
465 } else {
466 RTHFunc = Src0IsF32 ? (DestIs32 ? RuntimeHelper::H_fptoui_f32_i32
467 : RuntimeHelper::H_fptoui_f32_i64)
468 : (DestIs32 ? RuntimeHelper::H_fptoui_f64_i32
469 : RuntimeHelper::H_fptoui_f64_i64);
470 }
471 Operand *TargetHelper = Ctx->getRuntimeHelperFunc(RTHFunc);
Srdjan Obucinab85cde12016-09-09 09:39:52 -0700472 static constexpr SizeT MaxArgs = 1;
473 auto *Call = Context.insert<InstCall>(MaxArgs, Dest, TargetHelper,
474 NoTailCall, IsTargetHelperCall);
475 Call->addArg(Src0);
476 Instr->setDeleted();
477 return;
478 }
479 case InstCast::Sitofp:
480 case InstCast::Uitofp: {
Srdjan Obucina4c49b102016-09-26 20:12:17 -0700481 if ((SrcTy != IceType_i32) && (SrcTy != IceType_i64)) {
Srdjan Obucinab85cde12016-09-09 09:39:52 -0700482 return;
483 }
Srdjan Obucina4c49b102016-09-26 20:12:17 -0700484 const bool SourceIs32 = SrcTy == IceType_i32;
Srdjan Obucinab85cde12016-09-09 09:39:52 -0700485 const bool SourceIsSigned = CastKind == InstCast::Sitofp;
Jaydeep Patil3a01f332016-10-17 06:33:50 -0700486 const bool DestIsF32 = isFloat32Asserting32Or64(DestTy);
Srdjan Obucina4c49b102016-09-26 20:12:17 -0700487 RuntimeHelper RTHFunc = RuntimeHelper::H_Num;
488 if (SourceIsSigned) {
489 if (SourceIs32) {
490 return;
491 }
492 RTHFunc = DestIsF32 ? RuntimeHelper::H_sitofp_i64_f32
493 : RuntimeHelper::H_sitofp_i64_f64;
494 } else {
495 RTHFunc = DestIsF32 ? (SourceIs32 ? RuntimeHelper::H_uitofp_i32_f32
496 : RuntimeHelper::H_uitofp_i64_f32)
497 : (SourceIs32 ? RuntimeHelper::H_uitofp_i32_f64
498 : RuntimeHelper::H_uitofp_i64_f64);
499 }
500 Operand *TargetHelper = Ctx->getRuntimeHelperFunc(RTHFunc);
Srdjan Obucinab85cde12016-09-09 09:39:52 -0700501 static constexpr SizeT MaxArgs = 1;
502 auto *Call = Context.insert<InstCall>(MaxArgs, Dest, TargetHelper,
503 NoTailCall, IsTargetHelperCall);
504 Call->addArg(Src0);
505 Instr->setDeleted();
506 return;
507 }
508 case InstCast::Bitcast: {
509 if (DestTy == SrcTy) {
510 return;
511 }
512 Variable *CallDest = Dest;
513 RuntimeHelper HelperID = RuntimeHelper::H_Num;
514 switch (DestTy) {
515 default:
516 return;
517 case IceType_i8:
518 assert(SrcTy == IceType_v8i1);
519 HelperID = RuntimeHelper::H_bitcast_8xi1_i8;
520 CallDest = Func->makeVariable(IceType_i32);
521 break;
522 case IceType_i16:
523 assert(SrcTy == IceType_v16i1);
524 HelperID = RuntimeHelper::H_bitcast_16xi1_i16;
525 CallDest = Func->makeVariable(IceType_i32);
526 break;
527 case IceType_v8i1: {
528 assert(SrcTy == IceType_i8);
529 HelperID = RuntimeHelper::H_bitcast_i8_8xi1;
530 Variable *Src0AsI32 = Func->makeVariable(stackSlotType());
531 // Arguments to functions are required to be at least 32 bits wide.
532 Context.insert<InstCast>(InstCast::Zext, Src0AsI32, Src0);
533 Src0 = Src0AsI32;
534 } break;
535 case IceType_v16i1: {
536 assert(SrcTy == IceType_i16);
537 HelperID = RuntimeHelper::H_bitcast_i16_16xi1;
538 Variable *Src0AsI32 = Func->makeVariable(stackSlotType());
539 // Arguments to functions are required to be at least 32 bits wide.
540 Context.insert<InstCast>(InstCast::Zext, Src0AsI32, Src0);
541 Src0 = Src0AsI32;
542 } break;
543 }
544 constexpr SizeT MaxSrcs = 1;
545 InstCall *Call = makeHelperCall(HelperID, CallDest, MaxSrcs);
546 Call->addArg(Src0);
547 Context.insert(Call);
548 // The PNaCl ABI disallows i8/i16 return types, so truncate the helper
549 // call result to the appropriate type as necessary.
Jaydeep Patil3a01f332016-10-17 06:33:50 -0700550 if (CallDest->getType() != DestTy)
Srdjan Obucinab85cde12016-09-09 09:39:52 -0700551 Context.insert<InstCast>(InstCast::Trunc, Dest, CallDest);
552 Instr->setDeleted();
553 return;
554 }
555 case InstCast::Trunc: {
556 if (DestTy == SrcTy) {
557 return;
558 }
559 if (!isVectorType(SrcTy)) {
560 return;
561 }
562 assert(typeNumElements(DestTy) == typeNumElements(SrcTy));
563 assert(typeElementType(DestTy) == IceType_i1);
564 assert(isVectorIntegerType(SrcTy));
565 return;
566 }
567 case InstCast::Sext:
568 case InstCast::Zext: {
569 if (DestTy == SrcTy) {
570 return;
571 }
572 if (!isVectorType(DestTy)) {
573 return;
574 }
575 assert(typeNumElements(DestTy) == typeNumElements(SrcTy));
576 assert(typeElementType(SrcTy) == IceType_i1);
577 assert(isVectorIntegerType(DestTy));
578 return;
579 }
580 }
581 llvm::report_fatal_error("Control flow should never have reached here.");
582 }
583 case Inst::IntrinsicCall: {
Srdjan Obucinab85cde12016-09-09 09:39:52 -0700584 auto *IntrinsicCall = llvm::cast<InstIntrinsicCall>(Instr);
585 Intrinsics::IntrinsicID ID = IntrinsicCall->getIntrinsicInfo().ID;
Jaydeep Patil3a01f332016-10-17 06:33:50 -0700586 if (isVectorType(DestTy) && ID == Intrinsics::Fabs) {
Jaydeep Patil958ddb72016-10-03 07:52:48 -0700587 Operand *Src0 = IntrinsicCall->getArg(0);
588 GlobalString FabsFloat = Ctx->getGlobalString("llvm.fabs.f32");
589 Operand *CallTarget = Ctx->getConstantExternSym(FabsFloat);
590 GlobalString FabsVec = Ctx->getGlobalString("llvm.fabs.v4f32");
591 bool BadIntrinsic = false;
592 const Intrinsics::FullIntrinsicInfo *FullInfo =
593 Ctx->getIntrinsicsInfo().find(FabsVec, BadIntrinsic);
594 Intrinsics::IntrinsicInfo Info = FullInfo->Info;
595
596 Variable *T = Func->makeVariable(IceType_v4f32);
Jaydeep Patil3a01f332016-10-17 06:33:50 -0700597 auto *Undef = ConstantUndef::create(Ctx, IceType_v4f32);
598 Context.insert<InstAssign>(T, Undef);
599 auto *VarVecOn32 = llvm::cast<VariableVecOn32>(T);
Jaydeep Patil958ddb72016-10-03 07:52:48 -0700600 VarVecOn32->initVecElement(Func);
Jaydeep Patil958ddb72016-10-03 07:52:48 -0700601
Jaydeep Patil3a01f332016-10-17 06:33:50 -0700602 for (SizeT i = 0; i < typeNumElements(IceType_v4f32); ++i) {
Jaydeep Patil958ddb72016-10-03 07:52:48 -0700603 auto *Index = Ctx->getConstantInt32(i);
604 auto *Op = Func->makeVariable(IceType_f32);
605 Context.insert<InstExtractElement>(Op, Src0, Index);
606 auto *Res = Func->makeVariable(IceType_f32);
607 Variable *DestT = Func->makeVariable(IceType_v4f32);
608 auto *Call =
609 Context.insert<InstIntrinsicCall>(1, Res, CallTarget, Info);
610 Call->addArg(Op);
611 Context.insert<InstInsertElement>(DestT, T, Res, Index);
612 T = DestT;
613 }
614
615 Context.insert<InstAssign>(Dest, T);
616
617 Instr->setDeleted();
618 return;
619 }
Srdjan Obucinab85cde12016-09-09 09:39:52 -0700620 switch (ID) {
621 default:
622 return;
Jaydeep Patil71f6c8d2017-02-10 06:45:40 -0800623 case Intrinsics::AtomicLoad: {
624 if (DestTy != IceType_i64)
625 return;
626 if (!Intrinsics::isMemoryOrderValid(
627 ID, getConstantMemoryOrder(IntrinsicCall->getArg(1)))) {
628 Func->setError("Unexpected memory ordering for AtomicLoad");
629 return;
630 }
631 Operand *Addr = IntrinsicCall->getArg(0);
632 Operand *TargetHelper = Ctx->getConstantExternSym(
633 Ctx->getGlobalString("__sync_val_compare_and_swap_8"));
634 static constexpr SizeT MaxArgs = 3;
635 auto *_0 = Ctx->getConstantZero(IceType_i64);
636 auto *Call = Context.insert<InstCall>(MaxArgs, Dest, TargetHelper,
637 NoTailCall, IsTargetHelperCall);
638 Call->addArg(Addr);
639 Call->addArg(_0);
640 Call->addArg(_0);
641 Context.insert<InstMIPS32Sync>();
642 Instr->setDeleted();
643 return;
644 }
645 case Intrinsics::AtomicStore: {
646 Operand *Val = IntrinsicCall->getArg(0);
647 if (Val->getType() != IceType_i64)
648 return;
649 if (!Intrinsics::isMemoryOrderValid(
650 ID, getConstantMemoryOrder(IntrinsicCall->getArg(2)))) {
651 Func->setError("Unexpected memory ordering for AtomicStore");
652 return;
653 }
654 Operand *Addr = IntrinsicCall->getArg(1);
655 Variable *NoDest = nullptr;
656 Operand *TargetHelper = Ctx->getConstantExternSym(
657 Ctx->getGlobalString("__sync_lock_test_and_set_8"));
658 Context.insert<InstMIPS32Sync>();
659 static constexpr SizeT MaxArgs = 2;
660 auto *Call = Context.insert<InstCall>(MaxArgs, NoDest, TargetHelper,
661 NoTailCall, IsTargetHelperCall);
662 Call->addArg(Addr);
663 Call->addArg(Val);
664 Context.insert<InstMIPS32Sync>();
665 Instr->setDeleted();
666 return;
667 }
668 case Intrinsics::AtomicCmpxchg: {
669 if (DestTy != IceType_i64)
670 return;
671 if (!Intrinsics::isMemoryOrderValid(
672 ID, getConstantMemoryOrder(IntrinsicCall->getArg(3)),
673 getConstantMemoryOrder(IntrinsicCall->getArg(4)))) {
674 Func->setError("Unexpected memory ordering for AtomicCmpxchg");
675 return;
676 }
677 Operand *Addr = IntrinsicCall->getArg(0);
678 Operand *Oldval = IntrinsicCall->getArg(1);
679 Operand *Newval = IntrinsicCall->getArg(2);
680 Operand *TargetHelper = Ctx->getConstantExternSym(
681 Ctx->getGlobalString("__sync_val_compare_and_swap_8"));
682 Context.insert<InstMIPS32Sync>();
683 static constexpr SizeT MaxArgs = 3;
684 auto *Call = Context.insert<InstCall>(MaxArgs, Dest, TargetHelper,
685 NoTailCall, IsTargetHelperCall);
686 Call->addArg(Addr);
687 Call->addArg(Oldval);
688 Call->addArg(Newval);
689 Context.insert<InstMIPS32Sync>();
690 Instr->setDeleted();
691 return;
692 }
693 case Intrinsics::AtomicRMW: {
694 if (DestTy != IceType_i64)
695 return;
696 if (!Intrinsics::isMemoryOrderValid(
697 ID, getConstantMemoryOrder(IntrinsicCall->getArg(3)))) {
698 Func->setError("Unexpected memory ordering for AtomicRMW");
699 return;
700 }
701 auto Operation = static_cast<Intrinsics::AtomicRMWOperation>(
702 llvm::cast<ConstantInteger32>(IntrinsicCall->getArg(0))->getValue());
703 auto *Addr = IntrinsicCall->getArg(1);
704 auto *Newval = IntrinsicCall->getArg(2);
705 Operand *TargetHelper;
706 switch (Operation) {
707 case Intrinsics::AtomicAdd:
708 TargetHelper = Ctx->getConstantExternSym(
709 Ctx->getGlobalString("__sync_fetch_and_add_8"));
710 break;
711 case Intrinsics::AtomicSub:
712 TargetHelper = Ctx->getConstantExternSym(
713 Ctx->getGlobalString("__sync_fetch_and_sub_8"));
714 break;
715 case Intrinsics::AtomicOr:
716 TargetHelper = Ctx->getConstantExternSym(
717 Ctx->getGlobalString("__sync_fetch_and_or_8"));
718 break;
719 case Intrinsics::AtomicAnd:
720 TargetHelper = Ctx->getConstantExternSym(
721 Ctx->getGlobalString("__sync_fetch_and_and_8"));
722 break;
723 case Intrinsics::AtomicXor:
724 TargetHelper = Ctx->getConstantExternSym(
725 Ctx->getGlobalString("__sync_fetch_and_xor_8"));
726 break;
727 case Intrinsics::AtomicExchange:
728 TargetHelper = Ctx->getConstantExternSym(
729 Ctx->getGlobalString("__sync_lock_test_and_set_8"));
730 break;
731 default:
732 llvm::report_fatal_error("Unknown AtomicRMW operation");
733 return;
734 }
735 Context.insert<InstMIPS32Sync>();
736 static constexpr SizeT MaxArgs = 2;
737 auto *Call = Context.insert<InstCall>(MaxArgs, Dest, TargetHelper,
738 NoTailCall, IsTargetHelperCall);
739 Call->addArg(Addr);
740 Call->addArg(Newval);
741 Context.insert<InstMIPS32Sync>();
742 Instr->setDeleted();
743 return;
744 }
Srdjan Obucinab85cde12016-09-09 09:39:52 -0700745 case Intrinsics::Ctpop: {
746 Operand *Src0 = IntrinsicCall->getArg(0);
747 Operand *TargetHelper =
748 Ctx->getRuntimeHelperFunc(isInt32Asserting32Or64(Src0->getType())
749 ? RuntimeHelper::H_call_ctpop_i32
750 : RuntimeHelper::H_call_ctpop_i64);
751 static constexpr SizeT MaxArgs = 1;
752 auto *Call = Context.insert<InstCall>(MaxArgs, Dest, TargetHelper,
753 NoTailCall, IsTargetHelperCall);
754 Call->addArg(Src0);
755 Instr->setDeleted();
756 return;
757 }
758 case Intrinsics::Longjmp: {
759 static constexpr SizeT MaxArgs = 2;
760 static constexpr Variable *NoDest = nullptr;
761 Operand *TargetHelper =
762 Ctx->getRuntimeHelperFunc(RuntimeHelper::H_call_longjmp);
763 auto *Call = Context.insert<InstCall>(MaxArgs, NoDest, TargetHelper,
764 NoTailCall, IsTargetHelperCall);
765 Call->addArg(IntrinsicCall->getArg(0));
766 Call->addArg(IntrinsicCall->getArg(1));
767 Instr->setDeleted();
768 return;
769 }
770 case Intrinsics::Memcpy: {
771 static constexpr SizeT MaxArgs = 3;
772 static constexpr Variable *NoDest = nullptr;
773 Operand *TargetHelper =
774 Ctx->getRuntimeHelperFunc(RuntimeHelper::H_call_memcpy);
775 auto *Call = Context.insert<InstCall>(MaxArgs, NoDest, TargetHelper,
776 NoTailCall, IsTargetHelperCall);
777 Call->addArg(IntrinsicCall->getArg(0));
778 Call->addArg(IntrinsicCall->getArg(1));
779 Call->addArg(IntrinsicCall->getArg(2));
780 Instr->setDeleted();
781 return;
782 }
783 case Intrinsics::Memmove: {
784 static constexpr SizeT MaxArgs = 3;
785 static constexpr Variable *NoDest = nullptr;
786 Operand *TargetHelper =
787 Ctx->getRuntimeHelperFunc(RuntimeHelper::H_call_memmove);
788 auto *Call = Context.insert<InstCall>(MaxArgs, NoDest, TargetHelper,
789 NoTailCall, IsTargetHelperCall);
790 Call->addArg(IntrinsicCall->getArg(0));
791 Call->addArg(IntrinsicCall->getArg(1));
792 Call->addArg(IntrinsicCall->getArg(2));
793 Instr->setDeleted();
794 return;
795 }
796 case Intrinsics::Memset: {
797 Operand *ValOp = IntrinsicCall->getArg(1);
798 assert(ValOp->getType() == IceType_i8);
799 Variable *ValExt = Func->makeVariable(stackSlotType());
800 Context.insert<InstCast>(InstCast::Zext, ValExt, ValOp);
801
802 static constexpr SizeT MaxArgs = 3;
803 static constexpr Variable *NoDest = nullptr;
804 Operand *TargetHelper =
805 Ctx->getRuntimeHelperFunc(RuntimeHelper::H_call_memset);
806 auto *Call = Context.insert<InstCall>(MaxArgs, NoDest, TargetHelper,
807 NoTailCall, IsTargetHelperCall);
808 Call->addArg(IntrinsicCall->getArg(0));
809 Call->addArg(ValExt);
810 Call->addArg(IntrinsicCall->getArg(2));
811 Instr->setDeleted();
812 return;
813 }
814 case Intrinsics::NaClReadTP: {
815 if (SandboxingType == ST_NaCl) {
816 return;
817 }
818 static constexpr SizeT MaxArgs = 0;
819 assert(SandboxingType != ST_Nonsfi);
820 Operand *TargetHelper =
821 Ctx->getRuntimeHelperFunc(RuntimeHelper::H_call_read_tp);
822 Context.insert<InstCall>(MaxArgs, Dest, TargetHelper, NoTailCall,
823 IsTargetHelperCall);
824 Instr->setDeleted();
825 return;
826 }
827 case Intrinsics::Setjmp: {
828 static constexpr SizeT MaxArgs = 1;
829 Operand *TargetHelper =
830 Ctx->getRuntimeHelperFunc(RuntimeHelper::H_call_setjmp);
831 auto *Call = Context.insert<InstCall>(MaxArgs, Dest, TargetHelper,
832 NoTailCall, IsTargetHelperCall);
833 Call->addArg(IntrinsicCall->getArg(0));
834 Instr->setDeleted();
835 return;
836 }
837 }
838 llvm::report_fatal_error("Control flow should never have reached here.");
839 }
840 }
841}
842
Sagar Thakura49fce02016-06-13 05:55:00 -0700843void TargetMIPS32::findMaxStackOutArgsSize() {
844 // MinNeededOutArgsBytes should be updated if the Target ever creates a
845 // high-level InstCall that requires more stack bytes.
Sagar Thakur1afb4832016-06-16 15:30:24 -0700846 size_t MinNeededOutArgsBytes = 0;
847 if (!MaybeLeafFunc)
848 MinNeededOutArgsBytes = MIPS32_MAX_GPR_ARG * 4;
Sagar Thakura49fce02016-06-13 05:55:00 -0700849 MaxOutArgsSizeBytes = MinNeededOutArgsBytes;
850 for (CfgNode *Node : Func->getNodes()) {
851 Context.init(Node);
852 while (!Context.atEnd()) {
853 PostIncrLoweringContext PostIncrement(Context);
854 Inst *CurInstr = iteratorToInst(Context.getCur());
855 if (auto *Call = llvm::dyn_cast<InstCall>(CurInstr)) {
856 SizeT OutArgsSizeBytes = getCallStackArgumentsSizeBytes(Call);
857 MaxOutArgsSizeBytes = std::max(MaxOutArgsSizeBytes, OutArgsSizeBytes);
858 }
859 }
860 }
Sagar Thakur46832372016-10-16 07:20:44 -0700861 CurrentAllocaOffset = MaxOutArgsSizeBytes;
Sagar Thakura49fce02016-06-13 05:55:00 -0700862}
863
Jim Stichnoth6da4cef2015-06-11 13:26:33 -0700864void TargetMIPS32::translateO2() {
865 TimerMarker T(TimerStack::TT_O2, Func);
866
867 // TODO(stichnot): share passes with X86?
868 // https://code.google.com/p/nativeclient/issues/detail?id=4094
John Porto5e0a8a72015-11-20 13:50:36 -0800869 genTargetHelperCalls();
Jim Stichnoth6da4cef2015-06-11 13:26:33 -0700870
Sagar Thakur1afb4832016-06-16 15:30:24 -0700871 unsetIfNonLeafFunc();
872
Sagar Thakura49fce02016-06-13 05:55:00 -0700873 findMaxStackOutArgsSize();
874
David Sehr4318a412015-11-11 15:01:55 -0800875 // Merge Alloca instructions, and lay out the stack.
Sagar Thakur1afb4832016-06-16 15:30:24 -0700876 static constexpr bool SortAndCombineAllocas = true;
David Sehr4318a412015-11-11 15:01:55 -0800877 Func->processAllocas(SortAndCombineAllocas);
878 Func->dump("After Alloca processing");
879
Karl Schimpfd4699942016-04-02 09:55:31 -0700880 if (!getFlags().getEnablePhiEdgeSplit()) {
Jim Stichnoth6da4cef2015-06-11 13:26:33 -0700881 // Lower Phi instructions.
882 Func->placePhiLoads();
883 if (Func->hasError())
884 return;
885 Func->placePhiStores();
886 if (Func->hasError())
887 return;
888 Func->deletePhis();
889 if (Func->hasError())
890 return;
891 Func->dump("After Phi lowering");
892 }
893
894 // Address mode optimization.
895 Func->getVMetadata()->init(VMK_SingleDefs);
896 Func->doAddressOpt();
897
898 // Argument lowering
899 Func->doArgLowering();
900
Andrew Scull57e12682015-09-16 11:30:19 -0700901 // Target lowering. This requires liveness analysis for some parts of the
902 // lowering decisions, such as compare/branch fusing. If non-lightweight
903 // liveness analysis is used, the instructions need to be renumbered first.
904 // TODO: This renumbering should only be necessary if we're actually
905 // calculating live intervals, which we only do for register allocation.
Jim Stichnoth6da4cef2015-06-11 13:26:33 -0700906 Func->renumberInstructions();
907 if (Func->hasError())
908 return;
909
Andrew Scull57e12682015-09-16 11:30:19 -0700910 // TODO: It should be sufficient to use the fastest liveness calculation,
911 // i.e. livenessLightweight(). However, for some reason that slows down the
912 // rest of the translation. Investigate.
Jim Stichnoth6da4cef2015-06-11 13:26:33 -0700913 Func->liveness(Liveness_Basic);
914 if (Func->hasError())
915 return;
916 Func->dump("After MIPS32 address mode opt");
917
918 Func->genCode();
919 if (Func->hasError())
920 return;
921 Func->dump("After MIPS32 codegen");
922
Andrew Scull57e12682015-09-16 11:30:19 -0700923 // Register allocation. This requires instruction renumbering and full
924 // liveness analysis.
Jim Stichnoth6da4cef2015-06-11 13:26:33 -0700925 Func->renumberInstructions();
926 if (Func->hasError())
927 return;
928 Func->liveness(Liveness_Intervals);
929 if (Func->hasError())
930 return;
Andrew Scull57e12682015-09-16 11:30:19 -0700931 // The post-codegen dump is done here, after liveness analysis and associated
932 // cleanup, to make the dump cleaner and more useful.
Jim Stichnoth6da4cef2015-06-11 13:26:33 -0700933 Func->dump("After initial MIPS32 codegen");
Mohit Bhakkad6b44fb02016-06-22 05:47:29 -0700934 // Validate the live range computations. The expensive validation call is
935 // deliberately only made when assertions are enabled.
936 assert(Func->validateLiveness());
Jim Stichnoth6da4cef2015-06-11 13:26:33 -0700937 Func->getVMetadata()->init(VMK_All);
938 regAlloc(RAK_Global);
939 if (Func->hasError())
940 return;
941 Func->dump("After linear scan regalloc");
942
Karl Schimpfd4699942016-04-02 09:55:31 -0700943 if (getFlags().getEnablePhiEdgeSplit()) {
Jim Stichnoth6da4cef2015-06-11 13:26:33 -0700944 Func->advancedPhiLowering();
945 Func->dump("After advanced Phi lowering");
946 }
947
948 // Stack frame mapping.
949 Func->genFrame();
950 if (Func->hasError())
951 return;
952 Func->dump("After stack frame mapping");
953
Sagar Thakur5674c912016-07-14 14:50:37 -0700954 postLowerLegalization();
955 if (Func->hasError())
956 return;
957 Func->dump("After postLowerLegalization");
958
Jim Stichnoth6da4cef2015-06-11 13:26:33 -0700959 Func->contractEmptyNodes();
960 Func->reorderNodes();
961
Andrew Scull57e12682015-09-16 11:30:19 -0700962 // Branch optimization. This needs to be done just before code emission. In
963 // particular, no transformations that insert or reorder CfgNodes should be
964 // done after branch optimization. We go ahead and do it before nop insertion
965 // to reduce the amount of work needed for searching for opportunities.
Jim Stichnoth6da4cef2015-06-11 13:26:33 -0700966 Func->doBranchOpt();
967 Func->dump("After branch optimization");
968
969 // Nop insertion
Karl Schimpfd4699942016-04-02 09:55:31 -0700970 if (getFlags().getShouldDoNopInsertion()) {
Jim Stichnoth6da4cef2015-06-11 13:26:33 -0700971 Func->doNopInsertion();
972 }
973}
974
975void TargetMIPS32::translateOm1() {
976 TimerMarker T(TimerStack::TT_Om1, Func);
977
978 // TODO: share passes with X86?
John Porto5e0a8a72015-11-20 13:50:36 -0800979 genTargetHelperCalls();
Jim Stichnoth6da4cef2015-06-11 13:26:33 -0700980
Sagar Thakur1afb4832016-06-16 15:30:24 -0700981 unsetIfNonLeafFunc();
982
Sagar Thakura49fce02016-06-13 05:55:00 -0700983 findMaxStackOutArgsSize();
984
David Sehr4318a412015-11-11 15:01:55 -0800985 // Do not merge Alloca instructions, and lay out the stack.
986 static constexpr bool SortAndCombineAllocas = false;
987 Func->processAllocas(SortAndCombineAllocas);
988 Func->dump("After Alloca processing");
989
Jim Stichnoth6da4cef2015-06-11 13:26:33 -0700990 Func->placePhiLoads();
991 if (Func->hasError())
992 return;
993 Func->placePhiStores();
994 if (Func->hasError())
995 return;
996 Func->deletePhis();
997 if (Func->hasError())
998 return;
999 Func->dump("After Phi lowering");
1000
1001 Func->doArgLowering();
1002
1003 Func->genCode();
1004 if (Func->hasError())
1005 return;
1006 Func->dump("After initial MIPS32 codegen");
1007
1008 regAlloc(RAK_InfOnly);
1009 if (Func->hasError())
1010 return;
1011 Func->dump("After regalloc of infinite-weight variables");
1012
1013 Func->genFrame();
1014 if (Func->hasError())
1015 return;
1016 Func->dump("After stack frame mapping");
1017
Jaydeep Patil1d0690b2016-09-04 07:19:08 -07001018 postLowerLegalization();
1019 if (Func->hasError())
1020 return;
1021 Func->dump("After postLowerLegalization");
1022
Jim Stichnoth6da4cef2015-06-11 13:26:33 -07001023 // Nop insertion
Karl Schimpfd4699942016-04-02 09:55:31 -07001024 if (getFlags().getShouldDoNopInsertion()) {
Jim Stichnoth6da4cef2015-06-11 13:26:33 -07001025 Func->doNopInsertion();
1026 }
1027}
1028
Reed Kotler04bca5a2016-02-03 14:40:47 -08001029bool TargetMIPS32::doBranchOpt(Inst *Instr, const CfgNode *NextNode) {
Jaydeep Patil13f0ca32016-08-26 13:27:40 -07001030 if (auto *Br = llvm::dyn_cast<InstMIPS32Br>(Instr)) {
1031 return Br->optimizeBranch(NextNode);
1032 }
Reed Kotlerd00d48d2015-07-08 09:49:07 -07001033 return false;
Jim Stichnoth6da4cef2015-06-11 13:26:33 -07001034}
1035
Karl Schimpf5403f5d2016-01-15 11:07:46 -08001036namespace {
1037
1038const char *RegNames[RegMIPS32::Reg_NUM] = {
Jan Voung0dab0322015-07-21 14:29:34 -07001039#define X(val, encode, name, scratch, preserved, stackptr, frameptr, isInt, \
Jim Stichnothac8da5c2015-10-21 06:57:46 -07001040 isI64Pair, isFP32, isFP64, isVec128, alias_init) \
Jan Voung0dab0322015-07-21 14:29:34 -07001041 name,
Karl Schimpf5403f5d2016-01-15 11:07:46 -08001042 REGMIPS32_TABLE
Jan Voung0dab0322015-07-21 14:29:34 -07001043#undef X
Karl Schimpf5403f5d2016-01-15 11:07:46 -08001044};
1045
1046} // end of anonymous namespace
1047
Jim Stichnoth8aa39662016-02-10 11:20:30 -08001048const char *RegMIPS32::getRegName(RegNumT RegNum) {
1049 RegNum.assertIsValid();
Jim Stichnoth6da4cef2015-06-11 13:26:33 -07001050 return RegNames[RegNum];
1051}
1052
Jim Stichnoth467ffe52016-03-29 15:01:06 -07001053const char *TargetMIPS32::getRegName(RegNumT RegNum, Type Ty) const {
Karl Schimpf5403f5d2016-01-15 11:07:46 -08001054 (void)Ty;
1055 return RegMIPS32::getRegName(RegNum);
1056}
1057
Jim Stichnoth8aa39662016-02-10 11:20:30 -08001058Variable *TargetMIPS32::getPhysicalRegister(RegNumT RegNum, Type Ty) {
Jim Stichnoth6da4cef2015-06-11 13:26:33 -07001059 if (Ty == IceType_void)
1060 Ty = IceType_i32;
1061 if (PhysicalRegisters[Ty].empty())
1062 PhysicalRegisters[Ty].resize(RegMIPS32::Reg_NUM);
Jim Stichnoth8aa39662016-02-10 11:20:30 -08001063 RegNum.assertIsValid();
Jim Stichnoth6da4cef2015-06-11 13:26:33 -07001064 Variable *Reg = PhysicalRegisters[Ty][RegNum];
1065 if (Reg == nullptr) {
1066 Reg = Func->makeVariable(Ty);
1067 Reg->setRegNum(RegNum);
1068 PhysicalRegisters[Ty][RegNum] = Reg;
Jim Stichnoth69660552015-09-18 06:41:02 -07001069 // Specially mark a named physical register as an "argument" so that it is
1070 // considered live upon function entry. Otherwise it's possible to get
1071 // liveness validation errors for saving callee-save registers.
1072 Func->addImplicitArg(Reg);
1073 // Don't bother tracking the live range of a named physical register.
1074 Reg->setIgnoreLiveness();
Jim Stichnoth6da4cef2015-06-11 13:26:33 -07001075 }
1076 return Reg;
1077}
1078
Andrew Scull86df4e92015-07-30 13:54:44 -07001079void TargetMIPS32::emitJumpTable(const Cfg *Func,
1080 const InstJumpTable *JumpTable) const {
Karl Schimpfd4699942016-04-02 09:55:31 -07001081 (void)Func;
Andrew Scull86df4e92015-07-30 13:54:44 -07001082 (void)JumpTable;
Karl Schimpfd4699942016-04-02 09:55:31 -07001083 UnimplementedError(getFlags());
Andrew Scull86df4e92015-07-30 13:54:44 -07001084}
1085
Jim Stichnothac8da5c2015-10-21 06:57:46 -07001086/// Provide a trivial wrapper to legalize() for this common usage.
Jim Stichnoth8aa39662016-02-10 11:20:30 -08001087Variable *TargetMIPS32::legalizeToReg(Operand *From, RegNumT RegNum) {
Jim Stichnothac8da5c2015-10-21 06:57:46 -07001088 return llvm::cast<Variable>(legalize(From, Legal_Reg, RegNum));
1089}
1090
1091/// Legalize undef values to concrete values.
Jim Stichnoth8aa39662016-02-10 11:20:30 -08001092Operand *TargetMIPS32::legalizeUndef(Operand *From, RegNumT RegNum) {
Jim Stichnothac8da5c2015-10-21 06:57:46 -07001093 (void)RegNum;
1094 Type Ty = From->getType();
1095 if (llvm::isa<ConstantUndef>(From)) {
1096 // Lower undefs to zero. Another option is to lower undefs to an
1097 // uninitialized register; however, using an uninitialized register
1098 // results in less predictable code.
1099 //
1100 // If in the future the implementation is changed to lower undef
1101 // values to uninitialized registers, a FakeDef will be needed:
1102 // Context.insert(InstFakeDef::create(Func, Reg));
1103 // This is in order to ensure that the live range of Reg is not
1104 // overestimated. If the constant being lowered is a 64 bit value,
1105 // then the result should be split and the lo and hi components will
1106 // need to go in uninitialized registers.
Jaydeep Patil958ddb72016-10-03 07:52:48 -07001107 if (isVectorType(Ty)) {
1108 Variable *Var = makeReg(Ty, RegNum);
1109 auto *Reg = llvm::cast<VariableVecOn32>(Var);
1110 Reg->initVecElement(Func);
1111 auto *Zero = getZero();
Jaydeep Patil958ddb72016-10-03 07:52:48 -07001112 for (Variable *Var : Reg->getContainers()) {
1113 _mov(Var, Zero);
1114 }
1115 return Reg;
1116 }
Jim Stichnothac8da5c2015-10-21 06:57:46 -07001117 return Ctx->getConstantZero(Ty);
1118 }
1119 return From;
1120}
1121
Jim Stichnoth8aa39662016-02-10 11:20:30 -08001122Variable *TargetMIPS32::makeReg(Type Type, RegNumT RegNum) {
Jim Stichnothac8da5c2015-10-21 06:57:46 -07001123 // There aren't any 64-bit integer registers for Mips32.
1124 assert(Type != IceType_i64);
1125 Variable *Reg = Func->makeVariable(Type);
Reed Kotler5fa0a5f2016-02-15 20:01:24 -08001126 if (RegNum.hasValue())
Jim Stichnothac8da5c2015-10-21 06:57:46 -07001127 Reg->setRegNum(RegNum);
Reed Kotler5fa0a5f2016-02-15 20:01:24 -08001128 else
1129 Reg->setMustHaveReg();
Jim Stichnothac8da5c2015-10-21 06:57:46 -07001130 return Reg;
1131}
1132
Mohit Bhakkadf3bc5cf2016-05-31 11:19:03 -07001133OperandMIPS32Mem *TargetMIPS32::formMemoryOperand(Operand *Operand, Type Ty) {
1134 // It may be the case that address mode optimization already creates an
1135 // OperandMIPS32Mem, so in that case it wouldn't need another level of
1136 // transformation.
1137 if (auto *Mem = llvm::dyn_cast<OperandMIPS32Mem>(Operand)) {
Jaydeep Patil1d0690b2016-09-04 07:19:08 -07001138 return llvm::cast<OperandMIPS32Mem>(legalize(Mem));
Mohit Bhakkadf3bc5cf2016-05-31 11:19:03 -07001139 }
1140
1141 // If we didn't do address mode optimization, then we only have a base/offset
1142 // to work with. MIPS always requires a base register, so just use that to
1143 // hold the operand.
Jaydeep Patil1d0690b2016-09-04 07:19:08 -07001144 auto *Base = llvm::cast<Variable>(
1145 legalize(Operand, Legal_Reg | Legal_Rematerializable));
Jim Stichnothfe62f0a2016-07-10 05:13:18 -07001146 const int32_t Offset = Base->hasStackOffset() ? Base->getStackOffset() : 0;
Mohit Bhakkadf3bc5cf2016-05-31 11:19:03 -07001147 return OperandMIPS32Mem::create(
Jim Stichnothfe62f0a2016-07-10 05:13:18 -07001148 Func, Ty, Base,
1149 llvm::cast<ConstantInteger32>(Ctx->getConstantInt32(Offset)));
Mohit Bhakkadf3bc5cf2016-05-31 11:19:03 -07001150}
1151
Jim Stichnoth6da4cef2015-06-11 13:26:33 -07001152void TargetMIPS32::emitVariable(const Variable *Var) const {
Jan Voung28068ad2015-07-31 12:58:46 -07001153 if (!BuildDefs::dump())
1154 return;
Jim Stichnoth6da4cef2015-06-11 13:26:33 -07001155 Ostream &Str = Ctx->getStrEmit();
Jim Stichnothac8da5c2015-10-21 06:57:46 -07001156 const Type FrameSPTy = IceType_i32;
1157 if (Var->hasReg()) {
1158 Str << '$' << getRegName(Var->getRegNum(), Var->getType());
Jaydeep Patil1d0690b2016-09-04 07:19:08 -07001159 return;
Jim Stichnothac8da5c2015-10-21 06:57:46 -07001160 }
Jaydeep Patil1d0690b2016-09-04 07:19:08 -07001161 if (Var->mustHaveReg()) {
1162 llvm::report_fatal_error("Infinite-weight Variable (" + Var->getName() +
1163 ") has no register assigned - function " +
1164 Func->getFunctionName());
1165 }
1166 const int32_t Offset = Var->getStackOffset();
1167 Str << Offset;
1168 Str << "($" << getRegName(getFrameOrStackReg(), FrameSPTy);
1169 Str << ")";
Jim Stichnoth6da4cef2015-06-11 13:26:33 -07001170}
1171
Mohit Bhakkadf90118a2016-06-13 00:28:13 -07001172TargetMIPS32::CallingConv::CallingConv()
1173 : GPRegsUsed(RegMIPS32::Reg_NUM),
1174 GPRArgs(GPRArgInitializer.rbegin(), GPRArgInitializer.rend()),
1175 I64Args(I64ArgInitializer.rbegin(), I64ArgInitializer.rend()),
1176 VFPRegsUsed(RegMIPS32::Reg_NUM),
1177 FP32Args(FP32ArgInitializer.rbegin(), FP32ArgInitializer.rend()),
1178 FP64Args(FP64ArgInitializer.rbegin(), FP64ArgInitializer.rend()) {}
1179
1180// In MIPS O32 abi FP argument registers can be used only if first argument is
1181// of type float/double. UseFPRegs flag is used to care of that. Also FP arg
1182// registers can be used only for first 2 arguments, so we require argument
1183// number to make register allocation decisions.
1184bool TargetMIPS32::CallingConv::argInReg(Type Ty, uint32_t ArgNo,
1185 RegNumT *Reg) {
Jaydeep Patil958ddb72016-10-03 07:52:48 -07001186 if (isScalarIntegerType(Ty) || isVectorType(Ty))
Mohit Bhakkadf90118a2016-06-13 00:28:13 -07001187 return argInGPR(Ty, Reg);
1188 if (isScalarFloatingType(Ty)) {
1189 if (ArgNo == 0) {
1190 UseFPRegs = true;
1191 return argInVFP(Ty, Reg);
1192 }
1193 if (UseFPRegs && ArgNo == 1) {
1194 UseFPRegs = false;
1195 return argInVFP(Ty, Reg);
1196 }
1197 return argInGPR(Ty, Reg);
1198 }
Sagar Thakurbecb85f2016-11-18 12:15:46 -08001199 llvm::report_fatal_error("argInReg: Invalid type.");
Mohit Bhakkadf90118a2016-06-13 00:28:13 -07001200 return false;
1201}
1202
1203bool TargetMIPS32::CallingConv::argInGPR(Type Ty, RegNumT *Reg) {
1204 CfgVector<RegNumT> *Source;
1205
1206 switch (Ty) {
1207 default: {
Sagar Thakurbecb85f2016-11-18 12:15:46 -08001208 llvm::report_fatal_error("argInGPR: Invalid type.");
Mohit Bhakkadf90118a2016-06-13 00:28:13 -07001209 return false;
1210 } break;
Jaydeep Patil958ddb72016-10-03 07:52:48 -07001211 case IceType_v4i1:
1212 case IceType_v8i1:
1213 case IceType_v16i1:
1214 case IceType_v16i8:
1215 case IceType_v8i16:
1216 case IceType_v4i32:
1217 case IceType_v4f32:
Mohit Bhakkadf90118a2016-06-13 00:28:13 -07001218 case IceType_i32:
1219 case IceType_f32: {
1220 Source = &GPRArgs;
1221 } break;
1222 case IceType_i64:
1223 case IceType_f64: {
1224 Source = &I64Args;
1225 } break;
1226 }
1227
1228 discardUnavailableGPRsAndTheirAliases(Source);
1229
Jaydeep Patil958ddb72016-10-03 07:52:48 -07001230 // If $4 is used for any scalar type (or returining v4f32) then the next
1231 // vector type if passed in $6:$7:stack:stack
1232 if (isVectorType(Ty)) {
1233 alignGPR(Source);
1234 }
1235
Mohit Bhakkadf90118a2016-06-13 00:28:13 -07001236 if (Source->empty()) {
1237 GPRegsUsed.set();
1238 return false;
1239 }
1240
1241 *Reg = Source->back();
1242 // Note that we don't Source->pop_back() here. This is intentional. Notice how
1243 // we mark all of Reg's aliases as Used. So, for the next argument,
1244 // Source->back() is marked as unavailable, and it is thus implicitly popped
1245 // from the stack.
1246 GPRegsUsed |= RegisterAliases[*Reg];
Jaydeep Patil958ddb72016-10-03 07:52:48 -07001247
1248 // All vector arguments irrespective of their base type are passed in GP
1249 // registers. First vector argument is passed in $4:$5:$6:$7 and 2nd
1250 // is passed in $6:$7:stack:stack. If it is 1st argument then discard
1251 // $4:$5:$6:$7 otherwise discard $6:$7 only.
1252 if (isVectorType(Ty)) {
1253 if (((unsigned)*Reg) == RegMIPS32::Reg_A0) {
1254 GPRegsUsed |= RegisterAliases[RegMIPS32::Reg_A1];
1255 GPRegsUsed |= RegisterAliases[RegMIPS32::Reg_A2];
1256 GPRegsUsed |= RegisterAliases[RegMIPS32::Reg_A3];
1257 } else {
1258 GPRegsUsed |= RegisterAliases[RegMIPS32::Reg_A3];
1259 }
1260 }
1261
Mohit Bhakkadf90118a2016-06-13 00:28:13 -07001262 return true;
1263}
1264
1265inline void TargetMIPS32::CallingConv::discardNextGPRAndItsAliases(
1266 CfgVector<RegNumT> *Regs) {
1267 GPRegsUsed |= RegisterAliases[Regs->back()];
1268 Regs->pop_back();
1269}
1270
Mohit Bhakkadbbb5fa72016-06-29 06:51:08 -07001271inline void TargetMIPS32::CallingConv::alignGPR(CfgVector<RegNumT> *Regs) {
1272 if (Regs->back() == RegMIPS32::Reg_A1 || Regs->back() == RegMIPS32::Reg_A3)
1273 discardNextGPRAndItsAliases(Regs);
1274}
1275
Mohit Bhakkadf90118a2016-06-13 00:28:13 -07001276// GPR are not packed when passing parameters. Thus, a function foo(i32, i64,
1277// i32) will have the first argument in a0, the second in a2-a3, and the third
1278// on the stack. To model this behavior, whenever we pop a register from Regs,
1279// we remove all of its aliases from the pool of available GPRs. This has the
1280// effect of computing the "closure" on the GPR registers.
1281void TargetMIPS32::CallingConv::discardUnavailableGPRsAndTheirAliases(
1282 CfgVector<RegNumT> *Regs) {
1283 while (!Regs->empty() && GPRegsUsed[Regs->back()]) {
1284 discardNextGPRAndItsAliases(Regs);
1285 }
1286}
1287
1288bool TargetMIPS32::CallingConv::argInVFP(Type Ty, RegNumT *Reg) {
1289 CfgVector<RegNumT> *Source;
1290
1291 switch (Ty) {
1292 default: {
Sagar Thakurbecb85f2016-11-18 12:15:46 -08001293 llvm::report_fatal_error("argInVFP: Invalid type.");
Mohit Bhakkadf90118a2016-06-13 00:28:13 -07001294 return false;
1295 } break;
1296 case IceType_f32: {
1297 Source = &FP32Args;
1298 } break;
1299 case IceType_f64: {
1300 Source = &FP64Args;
1301 } break;
1302 }
1303
1304 discardUnavailableVFPRegsAndTheirAliases(Source);
1305
1306 if (Source->empty()) {
1307 VFPRegsUsed.set();
1308 return false;
1309 }
1310
1311 *Reg = Source->back();
1312 VFPRegsUsed |= RegisterAliases[*Reg];
1313
1314 // In MIPS O32 abi if fun arguments are (f32, i32) then one can not use reg_a0
1315 // for second argument even though it's free. f32 arg goes in reg_f12, i32 arg
1316 // goes in reg_a1. Similarly if arguments are (f64, i32) second argument goes
1317 // in reg_a3 and a0, a1 are not used.
1318 Source = &GPRArgs;
1319 // Discard one GPR reg for f32(4 bytes), two for f64(4 + 4 bytes)
Mohit Bhakkadbbb5fa72016-06-29 06:51:08 -07001320 if (Ty == IceType_f64) {
1321 // In MIPS o32 abi, when we use GPR argument pairs to store F64 values, pair
1322 // must be aligned at even register. Similarly when we discard GPR registers
1323 // when some arguments from starting 16 bytes goes in FPR, we must take care
1324 // of alignment. For example if fun args are (f32, f64, f32), for first f32
1325 // we discard a0, now for f64 argument, which will go in F14F15, we must
1326 // first align GPR vector to even register by discarding a1, then discard
1327 // two GPRs a2 and a3. Now last f32 argument will go on stack.
1328 alignGPR(Source);
Mohit Bhakkadf90118a2016-06-13 00:28:13 -07001329 discardNextGPRAndItsAliases(Source);
Mohit Bhakkadbbb5fa72016-06-29 06:51:08 -07001330 }
1331 discardNextGPRAndItsAliases(Source);
Mohit Bhakkadf90118a2016-06-13 00:28:13 -07001332 return true;
1333}
1334
1335void TargetMIPS32::CallingConv::discardUnavailableVFPRegsAndTheirAliases(
1336 CfgVector<RegNumT> *Regs) {
1337 while (!Regs->empty() && VFPRegsUsed[Regs->back()]) {
1338 Regs->pop_back();
1339 }
1340}
1341
Jim Stichnoth6da4cef2015-06-11 13:26:33 -07001342void TargetMIPS32::lowerArguments() {
Reed Kotlerd00d48d2015-07-08 09:49:07 -07001343 VarList &Args = Func->getArgs();
Mohit Bhakkad7984b712016-06-13 06:06:35 -07001344 TargetMIPS32::CallingConv CC;
1345
1346 // For each register argument, replace Arg in the argument list with the home
1347 // register. Then generate an instruction in the prolog to copy the home
1348 // register to the assigned location of Arg.
Jim Stichnothac8da5c2015-10-21 06:57:46 -07001349 Context.init(Func->getEntryNode());
1350 Context.setInsertPoint(Context.getCur());
Mohit Bhakkad7984b712016-06-13 06:06:35 -07001351
Jaydeep Patil958ddb72016-10-03 07:52:48 -07001352 // v4f32 is returned through stack. $4 is setup by the caller and passed as
1353 // first argument implicitly. Callee then copies the return vector at $4.
Jaydeep Patil3a01f332016-10-17 06:33:50 -07001354 Variable *ImplicitRetVec = nullptr;
Jaydeep Patil958ddb72016-10-03 07:52:48 -07001355 if (isVectorFloatingType(Func->getReturnType())) {
Jaydeep Patil3a01f332016-10-17 06:33:50 -07001356 ImplicitRetVec = Func->makeVariable(IceType_i32);
Jaydeep Patil958ddb72016-10-03 07:52:48 -07001357 ImplicitRetVec->setName(Func, "ImplicitRet_v4f32");
1358 ImplicitRetVec->setIsArg();
1359 Args.insert(Args.begin(), ImplicitRetVec);
1360 setImplicitRet(ImplicitRetVec);
Jaydeep Patil958ddb72016-10-03 07:52:48 -07001361 }
1362
1363 for (SizeT i = 0, E = Args.size(); i < E; ++i) {
1364 Variable *Arg = Args[i];
Jim Stichnothac8da5c2015-10-21 06:57:46 -07001365 Type Ty = Arg->getType();
Mohit Bhakkad7984b712016-06-13 06:06:35 -07001366 RegNumT RegNum;
Jaydeep Patil958ddb72016-10-03 07:52:48 -07001367 if (!CC.argInReg(Ty, i, &RegNum)) {
Jim Stichnothac8da5c2015-10-21 06:57:46 -07001368 continue;
1369 }
Mohit Bhakkad7984b712016-06-13 06:06:35 -07001370 Variable *RegisterArg = Func->makeVariable(Ty);
1371 if (BuildDefs::dump()) {
1372 RegisterArg->setName(Func, "home_reg:" + Arg->getName());
Jim Stichnothac8da5c2015-10-21 06:57:46 -07001373 }
Mohit Bhakkad7984b712016-06-13 06:06:35 -07001374 RegisterArg->setIsArg();
1375 Arg->setIsArg(false);
Jaydeep Patil958ddb72016-10-03 07:52:48 -07001376 Args[i] = RegisterArg;
1377
1378 if (isVectorType(Ty)) {
1379 auto *RegisterArgVec = llvm::cast<VariableVecOn32>(RegisterArg);
1380 RegisterArgVec->initVecElement(Func);
1381 RegisterArgVec->getContainers()[0]->setRegNum(
1382 RegNumT::fixme((unsigned)RegNum + 0));
1383 RegisterArgVec->getContainers()[1]->setRegNum(
1384 RegNumT::fixme((unsigned)RegNum + 1));
1385 // First two elements of second vector argument are passed
1386 // in $6:$7 and remaining two on stack. Do not assign register
1387 // to this is second vector argument.
1388 if (i == 0) {
1389 RegisterArgVec->getContainers()[2]->setRegNum(
1390 RegNumT::fixme((unsigned)RegNum + 2));
1391 RegisterArgVec->getContainers()[3]->setRegNum(
1392 RegNumT::fixme((unsigned)RegNum + 3));
1393 } else {
1394 RegisterArgVec->getContainers()[2]->setRegNum(
1395 RegNumT::fixme(RegNumT()));
1396 RegisterArgVec->getContainers()[3]->setRegNum(
1397 RegNumT::fixme(RegNumT()));
1398 }
1399 } else {
1400 switch (Ty) {
1401 default: { RegisterArg->setRegNum(RegNum); } break;
1402 case IceType_i64: {
1403 auto *RegisterArg64 = llvm::cast<Variable64On32>(RegisterArg);
1404 RegisterArg64->initHiLo(Func);
1405 RegisterArg64->getLo()->setRegNum(
1406 RegNumT::fixme(RegMIPS32::get64PairFirstRegNum(RegNum)));
1407 RegisterArg64->getHi()->setRegNum(
1408 RegNumT::fixme(RegMIPS32::get64PairSecondRegNum(RegNum)));
1409 } break;
1410 }
Jim Stichnothac8da5c2015-10-21 06:57:46 -07001411 }
Mohit Bhakkad7984b712016-06-13 06:06:35 -07001412 Context.insert<InstAssign>(Arg, RegisterArg);
Jim Stichnothac8da5c2015-10-21 06:57:46 -07001413 }
Jaydeep Patil3a01f332016-10-17 06:33:50 -07001414
1415 // Insert fake use of ImplicitRet_v4f32 to keep it live
1416 if (ImplicitRetVec) {
1417 for (CfgNode *Node : Func->getNodes()) {
1418 for (Inst &Instr : Node->getInsts()) {
1419 if (llvm::isa<InstRet>(&Instr)) {
Jim Stichnothf8c695b2016-12-26 09:56:08 -08001420 Context.setInsertPoint(instToIterator(&Instr));
Jaydeep Patil3a01f332016-10-17 06:33:50 -07001421 Context.insert<InstFakeUse>(ImplicitRetVec);
1422 break;
1423 }
1424 }
1425 }
1426 }
Jim Stichnoth6da4cef2015-06-11 13:26:33 -07001427}
1428
1429Type TargetMIPS32::stackSlotType() { return IceType_i32; }
1430
Sagar Thakura49fce02016-06-13 05:55:00 -07001431// Helper function for addProlog().
1432//
1433// This assumes Arg is an argument passed on the stack. This sets the frame
1434// offset for Arg and updates InArgsSizeBytes according to Arg's width. For an
1435// I64 arg that has been split into Lo and Hi components, it calls itself
1436// recursively on the components, taking care to handle Lo first because of the
1437// little-endian architecture. Lastly, this function generates an instruction
1438// to copy Arg into its assigned register if applicable.
Jaydeep Patil958ddb72016-10-03 07:52:48 -07001439void TargetMIPS32::finishArgumentLowering(Variable *Arg, bool PartialOnStack,
1440 Variable *FramePtr,
Sagar Thakura49fce02016-06-13 05:55:00 -07001441 size_t BasicFrameOffset,
1442 size_t *InArgsSizeBytes) {
1443 const Type Ty = Arg->getType();
1444 *InArgsSizeBytes = applyStackAlignmentTy(*InArgsSizeBytes, Ty);
1445
Jaydeep Patil958ddb72016-10-03 07:52:48 -07001446 // If $4 is used for any scalar type (or returining v4f32) then the next
1447 // vector type if passed in $6:$7:stack:stack. Load 3nd and 4th element
1448 // from agument stack.
1449 if (auto *ArgVecOn32 = llvm::dyn_cast<VariableVecOn32>(Arg)) {
1450 if (PartialOnStack == false) {
1451 auto *Elem0 = ArgVecOn32->getContainers()[0];
1452 auto *Elem1 = ArgVecOn32->getContainers()[1];
1453 finishArgumentLowering(Elem0, PartialOnStack, FramePtr, BasicFrameOffset,
1454 InArgsSizeBytes);
1455 finishArgumentLowering(Elem1, PartialOnStack, FramePtr, BasicFrameOffset,
1456 InArgsSizeBytes);
1457 }
1458 auto *Elem2 = ArgVecOn32->getContainers()[2];
1459 auto *Elem3 = ArgVecOn32->getContainers()[3];
1460 finishArgumentLowering(Elem2, PartialOnStack, FramePtr, BasicFrameOffset,
1461 InArgsSizeBytes);
1462 finishArgumentLowering(Elem3, PartialOnStack, FramePtr, BasicFrameOffset,
1463 InArgsSizeBytes);
1464 return;
1465 }
1466
Sagar Thakura49fce02016-06-13 05:55:00 -07001467 if (auto *Arg64On32 = llvm::dyn_cast<Variable64On32>(Arg)) {
1468 Variable *const Lo = Arg64On32->getLo();
1469 Variable *const Hi = Arg64On32->getHi();
Jaydeep Patil958ddb72016-10-03 07:52:48 -07001470 finishArgumentLowering(Lo, PartialOnStack, FramePtr, BasicFrameOffset,
1471 InArgsSizeBytes);
1472 finishArgumentLowering(Hi, PartialOnStack, FramePtr, BasicFrameOffset,
1473 InArgsSizeBytes);
Sagar Thakura49fce02016-06-13 05:55:00 -07001474 return;
1475 }
Jaydeep Patil958ddb72016-10-03 07:52:48 -07001476
Sagar Thakura49fce02016-06-13 05:55:00 -07001477 assert(Ty != IceType_i64);
Jaydeep Patil958ddb72016-10-03 07:52:48 -07001478 assert(!isVectorType(Ty));
Sagar Thakura49fce02016-06-13 05:55:00 -07001479
1480 const int32_t ArgStackOffset = BasicFrameOffset + *InArgsSizeBytes;
1481 *InArgsSizeBytes += typeWidthInBytesOnStack(Ty);
1482
1483 if (!Arg->hasReg()) {
1484 Arg->setStackOffset(ArgStackOffset);
1485 return;
1486 }
1487
1488 // If the argument variable has been assigned a register, we need to copy the
1489 // value from the stack slot.
1490 Variable *Parameter = Func->makeVariable(Ty);
1491 Parameter->setMustNotHaveReg();
1492 Parameter->setStackOffset(ArgStackOffset);
1493 _mov(Arg, Parameter);
1494}
1495
Jim Stichnoth6da4cef2015-06-11 13:26:33 -07001496void TargetMIPS32::addProlog(CfgNode *Node) {
Sagar Thakura49fce02016-06-13 05:55:00 -07001497 // Stack frame layout:
1498 //
1499 // +------------------------+
1500 // | 1. preserved registers |
1501 // +------------------------+
1502 // | 2. padding |
1503 // +------------------------+
1504 // | 3. global spill area |
1505 // +------------------------+
1506 // | 4. padding |
1507 // +------------------------+
1508 // | 5. local spill area |
1509 // +------------------------+
1510 // | 6. padding |
1511 // +------------------------+
1512 // | 7. allocas |
1513 // +------------------------+
1514 // | 8. padding |
1515 // +------------------------+
Nicolas Capens4e679e52017-01-12 17:01:06 -05001516 // | 9. out args |
Sagar Thakura49fce02016-06-13 05:55:00 -07001517 // +------------------------+ <--- StackPointer
1518 //
1519 // The following variables record the size in bytes of the given areas:
1520 // * PreservedRegsSizeBytes: area 1
1521 // * SpillAreaPaddingBytes: area 2
1522 // * GlobalsSize: area 3
1523 // * GlobalsAndSubsequentPaddingSize: areas 3 - 4
1524 // * LocalsSpillAreaSize: area 5
1525 // * SpillAreaSizeBytes: areas 2 - 9
1526 // * maxOutArgsSizeBytes(): area 9
1527
1528 Context.init(Node);
1529 Context.setInsertPoint(Context.getCur());
1530
1531 SmallBitVector CalleeSaves = getRegisterSet(RegSet_CalleeSave, RegSet_None);
1532 RegsUsed = SmallBitVector(CalleeSaves.size());
1533
1534 VarList SortedSpilledVariables;
1535
1536 size_t GlobalsSize = 0;
1537 // If there is a separate locals area, this represents that area. Otherwise
1538 // it counts any variable not counted by GlobalsSize.
1539 SpillAreaSizeBytes = 0;
1540 // If there is a separate locals area, this specifies the alignment for it.
1541 uint32_t LocalsSlotsAlignmentBytes = 0;
1542 // The entire spill locations area gets aligned to largest natural alignment
1543 // of the variables that have a spill slot.
1544 uint32_t SpillAreaAlignmentBytes = 0;
1545 // For now, we don't have target-specific variables that need special
1546 // treatment (no stack-slot-linked SpillVariable type).
1547 std::function<bool(Variable *)> TargetVarHook = [](Variable *Var) {
1548 static constexpr bool AssignStackSlot = false;
1549 static constexpr bool DontAssignStackSlot = !AssignStackSlot;
1550 if (llvm::isa<Variable64On32>(Var)) {
1551 return DontAssignStackSlot;
1552 }
1553 return AssignStackSlot;
1554 };
1555
1556 // Compute the list of spilled variables and bounds for GlobalsSize, etc.
1557 getVarStackSlotParams(SortedSpilledVariables, RegsUsed, &GlobalsSize,
1558 &SpillAreaSizeBytes, &SpillAreaAlignmentBytes,
1559 &LocalsSlotsAlignmentBytes, TargetVarHook);
1560 uint32_t LocalsSpillAreaSize = SpillAreaSizeBytes;
1561 SpillAreaSizeBytes += GlobalsSize;
1562
1563 PreservedGPRs.reserve(CalleeSaves.size());
1564
1565 // Consider FP and RA as callee-save / used as needed.
1566 if (UsesFramePointer) {
1567 if (RegsUsed[RegMIPS32::Reg_FP]) {
1568 llvm::report_fatal_error("Frame pointer has been used.");
1569 }
1570 CalleeSaves[RegMIPS32::Reg_FP] = true;
1571 RegsUsed[RegMIPS32::Reg_FP] = true;
1572 }
1573 if (!MaybeLeafFunc) {
1574 CalleeSaves[RegMIPS32::Reg_RA] = true;
1575 RegsUsed[RegMIPS32::Reg_RA] = true;
1576 }
1577
1578 // Make two passes over the used registers. The first pass records all the
1579 // used registers -- and their aliases. Then, we figure out which GPR
1580 // registers should be saved.
1581 SmallBitVector ToPreserve(RegMIPS32::Reg_NUM);
1582 for (SizeT i = 0; i < CalleeSaves.size(); ++i) {
1583 if (CalleeSaves[i] && RegsUsed[i]) {
1584 ToPreserve |= RegisterAliases[i];
1585 }
1586 }
1587
1588 uint32_t NumCallee = 0;
Sagar Thakura49fce02016-06-13 05:55:00 -07001589
1590 // RegClasses is a tuple of
1591 //
1592 // <First Register in Class, Last Register in Class, Vector of Save Registers>
1593 //
1594 // We use this tuple to figure out which register we should save/restore
1595 // during
1596 // prolog/epilog.
1597 using RegClassType = std::tuple<uint32_t, uint32_t, VarList *>;
1598 const RegClassType RegClass = RegClassType(
Jaydeep Patil2bbda7f2017-01-10 21:48:58 -08001599 RegMIPS32::Reg_GPR_First, RegMIPS32::Reg_FPR_Last, &PreservedGPRs);
Sagar Thakura49fce02016-06-13 05:55:00 -07001600 const uint32_t FirstRegInClass = std::get<0>(RegClass);
1601 const uint32_t LastRegInClass = std::get<1>(RegClass);
1602 VarList *const PreservedRegsInClass = std::get<2>(RegClass);
1603 for (uint32_t Reg = LastRegInClass; Reg > FirstRegInClass; Reg--) {
1604 if (!ToPreserve[Reg]) {
1605 continue;
1606 }
1607 ++NumCallee;
1608 Variable *PhysicalRegister = getPhysicalRegister(RegNumT::fromInt(Reg));
1609 PreservedRegsSizeBytes +=
1610 typeWidthInBytesOnStack(PhysicalRegister->getType());
1611 PreservedRegsInClass->push_back(PhysicalRegister);
1612 }
1613
1614 Ctx->statsUpdateRegistersSaved(NumCallee);
1615
1616 // Align the variables area. SpillAreaPaddingBytes is the size of the region
1617 // after the preserved registers and before the spill areas.
1618 // LocalsSlotsPaddingBytes is the amount of padding between the globals and
1619 // locals area if they are separate.
1620 assert(SpillAreaAlignmentBytes <= MIPS32_STACK_ALIGNMENT_BYTES);
1621 (void)MIPS32_STACK_ALIGNMENT_BYTES;
1622 assert(LocalsSlotsAlignmentBytes <= SpillAreaAlignmentBytes);
1623 uint32_t SpillAreaPaddingBytes = 0;
1624 uint32_t LocalsSlotsPaddingBytes = 0;
1625 alignStackSpillAreas(PreservedRegsSizeBytes, SpillAreaAlignmentBytes,
1626 GlobalsSize, LocalsSlotsAlignmentBytes,
1627 &SpillAreaPaddingBytes, &LocalsSlotsPaddingBytes);
1628 SpillAreaSizeBytes += SpillAreaPaddingBytes + LocalsSlotsPaddingBytes;
1629 uint32_t GlobalsAndSubsequentPaddingSize =
1630 GlobalsSize + LocalsSlotsPaddingBytes;
1631
Sagar Thakura49fce02016-06-13 05:55:00 -07001632 // Adds the out args space to the stack, and align SP if necessary.
Sagar Thakur752e59f2016-07-21 06:12:09 -07001633 if (!NeedsStackAlignment) {
1634 SpillAreaSizeBytes += MaxOutArgsSizeBytes * (VariableAllocaUsed ? 0 : 1);
1635 } else {
Sagar Thakur89be8872016-10-18 07:32:21 -07001636 SpillAreaSizeBytes = applyStackAlignment(
1637 SpillAreaSizeBytes +
1638 (VariableAllocaUsed ? VariableAllocaAlignBytes : MaxOutArgsSizeBytes));
Sagar Thakur752e59f2016-07-21 06:12:09 -07001639 }
1640
1641 // Combine fixed alloca with SpillAreaSize.
1642 SpillAreaSizeBytes += FixedAllocaSizeBytes;
1643
Jaydeep Patil2bbda7f2017-01-10 21:48:58 -08001644 TotalStackSizeBytes =
1645 applyStackAlignment(PreservedRegsSizeBytes + SpillAreaSizeBytes);
Sagar Thakura49fce02016-06-13 05:55:00 -07001646
1647 // Generate "addiu sp, sp, -TotalStackSizeBytes"
1648 if (TotalStackSizeBytes) {
1649 // Use the scratch register if needed to legalize the immediate.
Stefan Maksimovic6e033432016-11-09 17:31:51 -08001650 Sandboxer(this).addiu_sp(-TotalStackSizeBytes);
Sagar Thakura49fce02016-06-13 05:55:00 -07001651 }
1652
1653 Ctx->statsUpdateFrameBytes(TotalStackSizeBytes);
1654
1655 if (!PreservedGPRs.empty()) {
1656 uint32_t StackOffset = TotalStackSizeBytes;
1657 for (Variable *Var : *PreservedRegsInClass) {
Jaydeep Patil2bbda7f2017-01-10 21:48:58 -08001658 Type RegType;
1659 if (RegMIPS32::isFPRReg(Var->getRegNum()))
1660 RegType = IceType_f32;
1661 else
1662 RegType = IceType_i32;
1663 auto *PhysicalRegister = makeReg(RegType, Var->getRegNum());
1664 StackOffset -= typeWidthInBytesOnStack(RegType);
Sagar Thakura49fce02016-06-13 05:55:00 -07001665 Variable *SP = getPhysicalRegister(RegMIPS32::Reg_SP);
1666 OperandMIPS32Mem *MemoryLocation = OperandMIPS32Mem::create(
Jaydeep Patil2bbda7f2017-01-10 21:48:58 -08001667 Func, RegType, SP,
Sagar Thakura49fce02016-06-13 05:55:00 -07001668 llvm::cast<ConstantInteger32>(Ctx->getConstantInt32(StackOffset)));
Stefan Maksimovic6e033432016-11-09 17:31:51 -08001669 Sandboxer(this).sw(PhysicalRegister, MemoryLocation);
Sagar Thakura49fce02016-06-13 05:55:00 -07001670 }
1671 }
1672
1673 Variable *FP = getPhysicalRegister(RegMIPS32::Reg_FP);
1674
1675 // Generate "mov FP, SP" if needed.
1676 if (UsesFramePointer) {
1677 Variable *SP = getPhysicalRegister(RegMIPS32::Reg_SP);
1678 _mov(FP, SP);
1679 // Keep FP live for late-stage liveness analysis (e.g. asm-verbose mode).
1680 Context.insert<InstFakeUse>(FP);
1681 }
1682
1683 // Fill in stack offsets for stack args, and copy args into registers for
1684 // those that were register-allocated. Args are pushed right to left, so
1685 // Arg[0] is closest to the stack/frame pointer.
1686 const VarList &Args = Func->getArgs();
Sagar Thakur1afb4832016-06-16 15:30:24 -07001687 size_t InArgsSizeBytes = MIPS32_MAX_GPR_ARG * 4;
Sagar Thakura49fce02016-06-13 05:55:00 -07001688 TargetMIPS32::CallingConv CC;
1689 uint32_t ArgNo = 0;
1690
1691 for (Variable *Arg : Args) {
1692 RegNumT DummyReg;
1693 const Type Ty = Arg->getType();
Jaydeep Patil958ddb72016-10-03 07:52:48 -07001694 bool PartialOnStack;
Sagar Thakura49fce02016-06-13 05:55:00 -07001695 // Skip arguments passed in registers.
1696 if (CC.argInReg(Ty, ArgNo, &DummyReg)) {
Jaydeep Patil958ddb72016-10-03 07:52:48 -07001697 // Load argument from stack:
1698 // 1. If this is first vector argument and return type is v4f32.
1699 // In this case $4 is used to pass stack address implicitly.
1700 // 3rd and 4th element of vector argument is passed through stack.
1701 // 2. If this is second vector argument.
1702 if (ArgNo != 0 && isVectorType(Ty)) {
1703 PartialOnStack = true;
1704 finishArgumentLowering(Arg, PartialOnStack, FP, TotalStackSizeBytes,
1705 &InArgsSizeBytes);
1706 }
Sagar Thakura49fce02016-06-13 05:55:00 -07001707 } else {
Jaydeep Patil958ddb72016-10-03 07:52:48 -07001708 PartialOnStack = false;
1709 finishArgumentLowering(Arg, PartialOnStack, FP, TotalStackSizeBytes,
1710 &InArgsSizeBytes);
Sagar Thakura49fce02016-06-13 05:55:00 -07001711 }
Jaydeep Patil958ddb72016-10-03 07:52:48 -07001712 ++ArgNo;
Sagar Thakura49fce02016-06-13 05:55:00 -07001713 }
1714
1715 // Fill in stack offsets for locals.
1716 assignVarStackSlots(SortedSpilledVariables, SpillAreaPaddingBytes,
Sagar Thakur752e59f2016-07-21 06:12:09 -07001717 SpillAreaSizeBytes, GlobalsAndSubsequentPaddingSize);
Sagar Thakura49fce02016-06-13 05:55:00 -07001718 this->HasComputedFrame = true;
1719
1720 if (BuildDefs::dump() && Func->isVerbose(IceV_Frame)) {
1721 OstreamLocker _(Func->getContext());
1722 Ostream &Str = Func->getContext()->getStrDump();
1723
1724 Str << "Stack layout:\n";
1725 uint32_t SPAdjustmentPaddingSize =
1726 SpillAreaSizeBytes - LocalsSpillAreaSize -
1727 GlobalsAndSubsequentPaddingSize - SpillAreaPaddingBytes -
1728 MaxOutArgsSizeBytes;
1729 Str << " in-args = " << InArgsSizeBytes << " bytes\n"
1730 << " preserved registers = " << PreservedRegsSizeBytes << " bytes\n"
1731 << " spill area padding = " << SpillAreaPaddingBytes << " bytes\n"
1732 << " globals spill area = " << GlobalsSize << " bytes\n"
1733 << " globals-locals spill areas intermediate padding = "
1734 << GlobalsAndSubsequentPaddingSize - GlobalsSize << " bytes\n"
1735 << " locals spill area = " << LocalsSpillAreaSize << " bytes\n"
1736 << " SP alignment padding = " << SPAdjustmentPaddingSize << " bytes\n";
1737
1738 Str << "Stack details:\n"
1739 << " SP adjustment = " << SpillAreaSizeBytes << " bytes\n"
1740 << " spill area alignment = " << SpillAreaAlignmentBytes << " bytes\n"
1741 << " outgoing args size = " << MaxOutArgsSizeBytes << " bytes\n"
1742 << " locals spill area alignment = " << LocalsSlotsAlignmentBytes
1743 << " bytes\n"
1744 << " is FP based = " << 1 << "\n";
1745 }
Jim Stichnothac8da5c2015-10-21 06:57:46 -07001746 return;
Jim Stichnoth6da4cef2015-06-11 13:26:33 -07001747}
1748
1749void TargetMIPS32::addEpilog(CfgNode *Node) {
Sagar Thakur633394c2016-06-25 08:34:10 -07001750 InstList &Insts = Node->getInsts();
1751 InstList::reverse_iterator RI, E;
1752 for (RI = Insts.rbegin(), E = Insts.rend(); RI != E; ++RI) {
1753 if (llvm::isa<InstMIPS32Ret>(*RI))
1754 break;
1755 }
1756 if (RI == E)
1757 return;
1758
1759 // Convert the reverse_iterator position into its corresponding (forward)
1760 // iterator position.
Jim Stichnoth7c9728f2016-08-31 13:42:00 -07001761 InstList::iterator InsertPoint = reverseToForwardIterator(RI);
Sagar Thakur633394c2016-06-25 08:34:10 -07001762 --InsertPoint;
1763 Context.init(Node);
1764 Context.setInsertPoint(InsertPoint);
1765
1766 Variable *SP = getPhysicalRegister(RegMIPS32::Reg_SP);
1767 if (UsesFramePointer) {
1768 Variable *FP = getPhysicalRegister(RegMIPS32::Reg_FP);
1769 // For late-stage liveness analysis (e.g. asm-verbose mode), adding a fake
1770 // use of SP before the assignment of SP=FP keeps previous SP adjustments
1771 // from being dead-code eliminated.
1772 Context.insert<InstFakeUse>(SP);
Stefan Maksimovic6e033432016-11-09 17:31:51 -08001773 Sandboxer(this).reset_sp(FP);
Sagar Thakur633394c2016-06-25 08:34:10 -07001774 }
1775
1776 VarList::reverse_iterator RIter, END;
1777
1778 if (!PreservedGPRs.empty()) {
1779 uint32_t StackOffset = TotalStackSizeBytes - PreservedRegsSizeBytes;
1780 for (RIter = PreservedGPRs.rbegin(), END = PreservedGPRs.rend();
1781 RIter != END; ++RIter) {
Jaydeep Patil2bbda7f2017-01-10 21:48:58 -08001782 Type RegType;
1783 if (RegMIPS32::isFPRReg((*RIter)->getRegNum()))
1784 RegType = IceType_f32;
1785 else
1786 RegType = IceType_i32;
1787 auto *PhysicalRegister = makeReg(RegType, (*RIter)->getRegNum());
Sagar Thakur633394c2016-06-25 08:34:10 -07001788 Variable *SP = getPhysicalRegister(RegMIPS32::Reg_SP);
1789 OperandMIPS32Mem *MemoryLocation = OperandMIPS32Mem::create(
Jaydeep Patil2bbda7f2017-01-10 21:48:58 -08001790 Func, RegType, SP,
Sagar Thakur633394c2016-06-25 08:34:10 -07001791 llvm::cast<ConstantInteger32>(Ctx->getConstantInt32(StackOffset)));
1792 _lw(PhysicalRegister, MemoryLocation);
1793 StackOffset += typeWidthInBytesOnStack(PhysicalRegister->getType());
1794 }
1795 }
1796
1797 if (TotalStackSizeBytes) {
Stefan Maksimovic6e033432016-11-09 17:31:51 -08001798 Sandboxer(this).addiu_sp(TotalStackSizeBytes);
Sagar Thakur633394c2016-06-25 08:34:10 -07001799 }
Stefan Maksimovic6e033432016-11-09 17:31:51 -08001800 if (!getFlags().getUseSandboxing())
1801 return;
Sagar Thakur633394c2016-06-25 08:34:10 -07001802
Stefan Maksimovic6e033432016-11-09 17:31:51 -08001803 Variable *RA = getPhysicalRegister(RegMIPS32::Reg_RA);
1804 Variable *RetValue = nullptr;
1805 if (RI->getSrcSize())
1806 RetValue = llvm::cast<Variable>(RI->getSrc(0));
1807
1808 Sandboxer(this).ret(RA, RetValue);
1809
1810 RI->setDeleted();
Jim Stichnoth6da4cef2015-06-11 13:26:33 -07001811}
1812
Sagar Thakur5674c912016-07-14 14:50:37 -07001813Variable *TargetMIPS32::PostLoweringLegalizer::newBaseRegister(
1814 Variable *Base, int32_t Offset, RegNumT ScratchRegNum) {
1815 // Legalize will likely need a lui/ori combination, but if the top bits are
1816 // all 0 from negating the offset and subtracting, we could use that instead.
1817 const bool ShouldSub = Offset != 0 && (-Offset & 0xFFFF0000) == 0;
1818 Variable *ScratchReg = Target->makeReg(IceType_i32, ScratchRegNum);
1819 if (ShouldSub) {
Jaydeep Patil130aca72016-10-28 05:30:54 -07001820 Target->_addi(ScratchReg, Base, -Offset);
Sagar Thakur5674c912016-07-14 14:50:37 -07001821 } else {
Jaydeep Patilec929172016-10-16 07:13:38 -07001822 constexpr bool SignExt = true;
1823 if (!OperandMIPS32Mem::canHoldOffset(Base->getType(), SignExt, Offset)) {
1824 const uint32_t UpperBits = (Offset >> 16) & 0xFFFF;
1825 const uint32_t LowerBits = Offset & 0xFFFF;
1826 Target->_lui(ScratchReg, Target->Ctx->getConstantInt32(UpperBits));
1827 if (LowerBits)
1828 Target->_ori(ScratchReg, ScratchReg, LowerBits);
1829 Target->_addu(ScratchReg, ScratchReg, Base);
1830 } else {
1831 Target->_addiu(ScratchReg, Base, Offset);
1832 }
Sagar Thakur5674c912016-07-14 14:50:37 -07001833 }
1834
1835 return ScratchReg;
1836}
1837
Jaydeep Patil2bbda7f2017-01-10 21:48:58 -08001838void TargetMIPS32::PostLoweringLegalizer::legalizeMovFp(
1839 InstMIPS32MovFP64ToI64 *MovInstr) {
1840 Variable *Dest = MovInstr->getDest();
1841 Operand *Src = MovInstr->getSrc(0);
1842 const Type SrcTy = Src->getType();
1843
1844 if (Dest != nullptr && SrcTy == IceType_f64) {
1845 int32_t Offset = Dest->getStackOffset();
1846 auto *Base = Target->getPhysicalRegister(Target->getFrameOrStackReg());
1847 OperandMIPS32Mem *TAddr = OperandMIPS32Mem::create(
1848 Target->Func, IceType_f32, Base,
1849 llvm::cast<ConstantInteger32>(Target->Ctx->getConstantInt32(Offset)));
1850 OperandMIPS32Mem *Addr = legalizeMemOperand(TAddr);
1851 auto *SrcV = llvm::cast<Variable>(Src);
1852 Variable *SrcR;
1853 if (MovInstr->getInt64Part() == Int64_Lo) {
1854 SrcR = Target->makeReg(
1855 IceType_f32, RegMIPS32::get64PairFirstRegNum(SrcV->getRegNum()));
1856 } else {
1857 SrcR = Target->makeReg(
1858 IceType_f32, RegMIPS32::get64PairSecondRegNum(SrcV->getRegNum()));
1859 }
1860 Sandboxer(Target).sw(SrcR, Addr);
1861 if (MovInstr->isDestRedefined()) {
1862 Target->_set_dest_redefined();
1863 }
1864 MovInstr->setDeleted();
1865 return;
1866 }
1867
1868 llvm::report_fatal_error("legalizeMovFp: Invalid operands");
1869}
1870
Sagar Thakur5674c912016-07-14 14:50:37 -07001871void TargetMIPS32::PostLoweringLegalizer::legalizeMov(InstMIPS32Mov *MovInstr) {
1872 Variable *Dest = MovInstr->getDest();
1873 assert(Dest != nullptr);
1874 const Type DestTy = Dest->getType();
Sagar Thakur5674c912016-07-14 14:50:37 -07001875 assert(DestTy != IceType_i64);
1876
1877 Operand *Src = MovInstr->getSrc(0);
1878 const Type SrcTy = Src->getType();
1879 (void)SrcTy;
1880 assert(SrcTy != IceType_i64);
1881
Sagar Thakur5674c912016-07-14 14:50:37 -07001882 bool Legalized = false;
Jaydeep Patild3297662016-09-13 22:52:27 -07001883 auto *SrcR = llvm::cast<Variable>(Src);
1884 if (Dest->hasReg() && SrcR->hasReg()) {
1885 // This might be a GP to/from FP move generated due to argument passing.
1886 // Use mtc1/mfc1 instead of mov.[s/d] if src and dst registers are of
1887 // different types.
1888 const bool IsDstGPR = RegMIPS32::isGPRReg(Dest->getRegNum());
1889 const bool IsSrcGPR = RegMIPS32::isGPRReg(SrcR->getRegNum());
1890 const RegNumT SRegNum = SrcR->getRegNum();
1891 const RegNumT DRegNum = Dest->getRegNum();
1892 if (IsDstGPR != IsSrcGPR) {
1893 if (IsDstGPR) {
1894 // Dest is GPR and SrcR is FPR. Use mfc1.
Sagar Thakurb001cc42016-10-11 23:36:01 -07001895 int32_t TypeWidth = typeWidthInBytes(DestTy);
1896 if (MovInstr->getDestHi() != nullptr)
1897 TypeWidth += typeWidthInBytes(MovInstr->getDestHi()->getType());
1898 if (TypeWidth == 8) {
Jaydeep Patild3297662016-09-13 22:52:27 -07001899 // Split it into two mfc1 instructions
1900 Variable *SrcGPRHi = Target->makeReg(
1901 IceType_f32, RegMIPS32::get64PairFirstRegNum(SRegNum));
1902 Variable *SrcGPRLo = Target->makeReg(
1903 IceType_f32, RegMIPS32::get64PairSecondRegNum(SRegNum));
Sagar Thakurb001cc42016-10-11 23:36:01 -07001904 Variable *DstFPRHi, *DstFPRLo;
1905 if (MovInstr->getDestHi() != nullptr && Dest != nullptr) {
1906 DstFPRHi = Target->makeReg(IceType_i32,
1907 MovInstr->getDestHi()->getRegNum());
1908 DstFPRLo = Target->makeReg(IceType_i32, Dest->getRegNum());
1909 } else {
1910 DstFPRHi = Target->makeReg(
1911 IceType_i32, RegMIPS32::get64PairFirstRegNum(DRegNum));
1912 DstFPRLo = Target->makeReg(
1913 IceType_i32, RegMIPS32::get64PairSecondRegNum(DRegNum));
1914 }
Jaydeep Patil2bbda7f2017-01-10 21:48:58 -08001915 Target->_mov(DstFPRHi, SrcGPRHi);
1916 Target->_mov(DstFPRLo, SrcGPRLo);
Jaydeep Patild3297662016-09-13 22:52:27 -07001917 Legalized = true;
1918 } else {
1919 Variable *SrcGPR = Target->makeReg(IceType_f32, SRegNum);
1920 Variable *DstFPR = Target->makeReg(IceType_i32, DRegNum);
1921 Target->_mov(DstFPR, SrcGPR);
1922 Legalized = true;
1923 }
1924 } else {
1925 // Dest is FPR and SrcR is GPR. Use mtc1.
Jaydeep Patilcf9c12f2016-09-20 08:38:11 -07001926 if (typeWidthInBytes(Dest->getType()) == 8) {
1927 Variable *SrcGPRHi, *SrcGPRLo;
1928 // SrcR could be $zero which is i32
1929 if (SRegNum == RegMIPS32::Reg_ZERO) {
1930 SrcGPRHi = Target->makeReg(IceType_i32, SRegNum);
1931 SrcGPRLo = SrcGPRHi;
1932 } else {
1933 // Split it into two mtc1 instructions
Sagar Thakurb001cc42016-10-11 23:36:01 -07001934 if (MovInstr->getSrcSize() == 2) {
1935 const auto FirstReg =
1936 (llvm::cast<Variable>(MovInstr->getSrc(0)))->getRegNum();
1937 const auto SecondReg =
1938 (llvm::cast<Variable>(MovInstr->getSrc(1)))->getRegNum();
1939 SrcGPRHi = Target->makeReg(IceType_i32, FirstReg);
1940 SrcGPRLo = Target->makeReg(IceType_i32, SecondReg);
1941 } else {
Sagar Thakurb001cc42016-10-11 23:36:01 -07001942 SrcGPRLo = Target->makeReg(
Jaydeep Patila7979bf2016-10-26 06:16:19 -07001943 IceType_i32, RegMIPS32::get64PairFirstRegNum(SRegNum));
1944 SrcGPRHi = Target->makeReg(
Sagar Thakurb001cc42016-10-11 23:36:01 -07001945 IceType_i32, RegMIPS32::get64PairSecondRegNum(SRegNum));
1946 }
Jaydeep Patilcf9c12f2016-09-20 08:38:11 -07001947 }
Jaydeep Patild3297662016-09-13 22:52:27 -07001948 Variable *DstFPRHi = Target->makeReg(
1949 IceType_f32, RegMIPS32::get64PairFirstRegNum(DRegNum));
1950 Variable *DstFPRLo = Target->makeReg(
1951 IceType_f32, RegMIPS32::get64PairSecondRegNum(DRegNum));
1952 Target->_mov(DstFPRHi, SrcGPRLo);
1953 Target->_mov(DstFPRLo, SrcGPRHi);
1954 Legalized = true;
1955 } else {
1956 Variable *SrcGPR = Target->makeReg(IceType_i32, SRegNum);
1957 Variable *DstFPR = Target->makeReg(IceType_f32, DRegNum);
1958 Target->_mov(DstFPR, SrcGPR);
1959 Legalized = true;
1960 }
1961 }
1962 }
1963 if (Legalized) {
1964 if (MovInstr->isDestRedefined()) {
1965 Target->_set_dest_redefined();
1966 }
1967 MovInstr->setDeleted();
1968 return;
1969 }
1970 }
1971
Jaydeep Patil1d0690b2016-09-04 07:19:08 -07001972 if (!Dest->hasReg()) {
1973 auto *SrcR = llvm::cast<Variable>(Src);
1974 assert(SrcR->hasReg());
1975 assert(!SrcR->isRematerializable());
Jaydeep Patila7979bf2016-10-26 06:16:19 -07001976 int32_t Offset = Dest->getStackOffset();
Sagar Thakur5674c912016-07-14 14:50:37 -07001977
Jaydeep Patil1d0690b2016-09-04 07:19:08 -07001978 // This is a _mov(Mem(), Variable), i.e., a store.
1979 auto *Base = Target->getPhysicalRegister(Target->getFrameOrStackReg());
Sagar Thakur5674c912016-07-14 14:50:37 -07001980
Jaydeep Patila7979bf2016-10-26 06:16:19 -07001981 OperandMIPS32Mem *TAddr = OperandMIPS32Mem::create(
Jaydeep Patil1d0690b2016-09-04 07:19:08 -07001982 Target->Func, DestTy, Base,
1983 llvm::cast<ConstantInteger32>(Target->Ctx->getConstantInt32(Offset)));
Jaydeep Patila7979bf2016-10-26 06:16:19 -07001984 OperandMIPS32Mem *TAddrHi = OperandMIPS32Mem::create(
1985 Target->Func, DestTy, Base,
1986 llvm::cast<ConstantInteger32>(
1987 Target->Ctx->getConstantInt32(Offset + 4)));
1988 OperandMIPS32Mem *Addr = legalizeMemOperand(TAddr);
Jaydeep Patil1d0690b2016-09-04 07:19:08 -07001989
1990 // FP arguments are passed in GP reg if first argument is in GP. In this
1991 // case type of the SrcR is still FP thus we need to explicitly generate sw
1992 // instead of swc1.
1993 const RegNumT RegNum = SrcR->getRegNum();
Jaydeep Patild3297662016-09-13 22:52:27 -07001994 const bool IsSrcGPReg = RegMIPS32::isGPRReg(SrcR->getRegNum());
Sagar Thakurb001cc42016-10-11 23:36:01 -07001995 if (SrcTy == IceType_f32 && IsSrcGPReg) {
Jaydeep Patil1d0690b2016-09-04 07:19:08 -07001996 Variable *SrcGPR = Target->makeReg(IceType_i32, RegNum);
Stefan Maksimovic6e033432016-11-09 17:31:51 -08001997 Sandboxer(Target).sw(SrcGPR, Addr);
Sagar Thakurb001cc42016-10-11 23:36:01 -07001998 } else if (SrcTy == IceType_f64 && IsSrcGPReg) {
Jaydeep Patild3297662016-09-13 22:52:27 -07001999 Variable *SrcGPRHi =
2000 Target->makeReg(IceType_i32, RegMIPS32::get64PairFirstRegNum(RegNum));
2001 Variable *SrcGPRLo = Target->makeReg(
2002 IceType_i32, RegMIPS32::get64PairSecondRegNum(RegNum));
Stefan Maksimovic6e033432016-11-09 17:31:51 -08002003 Sandboxer(Target).sw(SrcGPRHi, Addr);
Jaydeep Patila7979bf2016-10-26 06:16:19 -07002004 OperandMIPS32Mem *AddrHi = legalizeMemOperand(TAddrHi);
Stefan Maksimovic6e033432016-11-09 17:31:51 -08002005 Sandboxer(Target).sw(SrcGPRLo, AddrHi);
Sagar Thakurb001cc42016-10-11 23:36:01 -07002006 } else if (DestTy == IceType_f64 && IsSrcGPReg) {
2007 const auto FirstReg =
2008 (llvm::cast<Variable>(MovInstr->getSrc(0)))->getRegNum();
2009 const auto SecondReg =
2010 (llvm::cast<Variable>(MovInstr->getSrc(1)))->getRegNum();
Jaydeep Patila7979bf2016-10-26 06:16:19 -07002011 Variable *SrcGPRHi = Target->makeReg(IceType_i32, FirstReg);
2012 Variable *SrcGPRLo = Target->makeReg(IceType_i32, SecondReg);
Stefan Maksimovic6e033432016-11-09 17:31:51 -08002013 Sandboxer(Target).sw(SrcGPRLo, Addr);
Jaydeep Patila7979bf2016-10-26 06:16:19 -07002014 OperandMIPS32Mem *AddrHi = legalizeMemOperand(TAddrHi);
Stefan Maksimovic6e033432016-11-09 17:31:51 -08002015 Sandboxer(Target).sw(SrcGPRHi, AddrHi);
Jaydeep Patil1d0690b2016-09-04 07:19:08 -07002016 } else {
Stefan Maksimovic6e033432016-11-09 17:31:51 -08002017 Sandboxer(Target).sw(SrcR, Addr);
Jaydeep Patil1d0690b2016-09-04 07:19:08 -07002018 }
2019
2020 Target->Context.insert<InstFakeDef>(Dest);
2021 Legalized = true;
2022 } else if (auto *Var = llvm::dyn_cast<Variable>(Src)) {
2023 if (Var->isRematerializable()) {
2024 // This is equivalent to an x86 _lea(RematOffset(%esp/%ebp), Variable).
2025
Sagar Thakur46832372016-10-16 07:20:44 -07002026 // ExtraOffset is only needed for stack-pointer based frames as we have
Jaydeep Patil1d0690b2016-09-04 07:19:08 -07002027 // to account for spill storage.
Jaydeep Patil2bbda7f2017-01-10 21:48:58 -08002028 const int32_t ExtraOffset =
2029 (Var->getRegNum() == Target->getFrameOrStackReg())
2030 ? Target->getFrameFixedAllocaOffset()
2031 : 0;
Jaydeep Patil1d0690b2016-09-04 07:19:08 -07002032
2033 const int32_t Offset = Var->getStackOffset() + ExtraOffset;
2034 Variable *Base = Target->getPhysicalRegister(Var->getRegNum());
2035 Variable *T = newBaseRegister(Base, Offset, Dest->getRegNum());
2036 Target->_mov(Dest, T);
2037 Legalized = true;
2038 } else {
2039 if (!Var->hasReg()) {
2040 // This is a _mov(Variable, Mem()), i.e., a load.
2041 const int32_t Offset = Var->getStackOffset();
2042 auto *Base = Target->getPhysicalRegister(Target->getFrameOrStackReg());
Jaydeep Patila7979bf2016-10-26 06:16:19 -07002043 const RegNumT RegNum = Dest->getRegNum();
2044 const bool IsDstGPReg = RegMIPS32::isGPRReg(Dest->getRegNum());
2045 // If we are moving i64 to a double using stack then the address may
2046 // not be aligned to 8-byte boundary as we split i64 into Hi-Lo parts
2047 // and store them individually with 4-byte alignment. Load the Hi-Lo
2048 // parts in TmpReg and move them to the dest using mtc1.
2049 if (DestTy == IceType_f64 && !Utils::IsAligned(Offset, 8) &&
2050 !IsDstGPReg) {
2051 auto *Reg = Target->makeReg(IceType_i32, Target->getReservedTmpReg());
2052 const RegNumT RegNum = Dest->getRegNum();
2053 Variable *DestLo = Target->makeReg(
2054 IceType_f32, RegMIPS32::get64PairFirstRegNum(RegNum));
2055 Variable *DestHi = Target->makeReg(
2056 IceType_f32, RegMIPS32::get64PairSecondRegNum(RegNum));
2057 OperandMIPS32Mem *AddrLo = OperandMIPS32Mem::create(
2058 Target->Func, IceType_i32, Base,
2059 llvm::cast<ConstantInteger32>(
2060 Target->Ctx->getConstantInt32(Offset)));
2061 OperandMIPS32Mem *AddrHi = OperandMIPS32Mem::create(
2062 Target->Func, IceType_i32, Base,
2063 llvm::cast<ConstantInteger32>(
2064 Target->Ctx->getConstantInt32(Offset + 4)));
Stefan Maksimovic6e033432016-11-09 17:31:51 -08002065 Sandboxer(Target).lw(Reg, AddrLo);
Jaydeep Patila7979bf2016-10-26 06:16:19 -07002066 Target->_mov(DestLo, Reg);
Stefan Maksimovic6e033432016-11-09 17:31:51 -08002067 Sandboxer(Target).lw(Reg, AddrHi);
Jaydeep Patila7979bf2016-10-26 06:16:19 -07002068 Target->_mov(DestHi, Reg);
2069 } else {
2070 OperandMIPS32Mem *TAddr = OperandMIPS32Mem::create(
2071 Target->Func, DestTy, Base,
2072 llvm::cast<ConstantInteger32>(
2073 Target->Ctx->getConstantInt32(Offset)));
2074 OperandMIPS32Mem *Addr = legalizeMemOperand(TAddr);
2075 OperandMIPS32Mem *TAddrHi = OperandMIPS32Mem::create(
2076 Target->Func, DestTy, Base,
2077 llvm::cast<ConstantInteger32>(
2078 Target->Ctx->getConstantInt32(Offset + 4)));
2079 // FP arguments are passed in GP reg if first argument is in GP.
2080 // In this case type of the Dest is still FP thus we need to
2081 // explicitly generate lw instead of lwc1.
2082 if (DestTy == IceType_f32 && IsDstGPReg) {
2083 Variable *DstGPR = Target->makeReg(IceType_i32, RegNum);
Stefan Maksimovic6e033432016-11-09 17:31:51 -08002084 Sandboxer(Target).lw(DstGPR, Addr);
Jaydeep Patila7979bf2016-10-26 06:16:19 -07002085 } else if (DestTy == IceType_f64 && IsDstGPReg) {
2086 Variable *DstGPRHi = Target->makeReg(
2087 IceType_i32, RegMIPS32::get64PairFirstRegNum(RegNum));
2088 Variable *DstGPRLo = Target->makeReg(
2089 IceType_i32, RegMIPS32::get64PairSecondRegNum(RegNum));
Stefan Maksimovic6e033432016-11-09 17:31:51 -08002090 Sandboxer(Target).lw(DstGPRHi, Addr);
Jaydeep Patila7979bf2016-10-26 06:16:19 -07002091 OperandMIPS32Mem *AddrHi = legalizeMemOperand(TAddrHi);
Stefan Maksimovic6e033432016-11-09 17:31:51 -08002092 Sandboxer(Target).lw(DstGPRLo, AddrHi);
Jaydeep Patila7979bf2016-10-26 06:16:19 -07002093 } else if (DestTy == IceType_f64 && IsDstGPReg) {
2094 const auto FirstReg =
2095 (llvm::cast<Variable>(MovInstr->getSrc(0)))->getRegNum();
2096 const auto SecondReg =
2097 (llvm::cast<Variable>(MovInstr->getSrc(1)))->getRegNum();
2098 Variable *DstGPRHi = Target->makeReg(IceType_i32, FirstReg);
2099 Variable *DstGPRLo = Target->makeReg(IceType_i32, SecondReg);
Stefan Maksimovic6e033432016-11-09 17:31:51 -08002100 Sandboxer(Target).lw(DstGPRLo, Addr);
Jaydeep Patila7979bf2016-10-26 06:16:19 -07002101 OperandMIPS32Mem *AddrHi = legalizeMemOperand(TAddrHi);
Stefan Maksimovic6e033432016-11-09 17:31:51 -08002102 Sandboxer(Target).lw(DstGPRHi, AddrHi);
Jaydeep Patila7979bf2016-10-26 06:16:19 -07002103 } else {
Stefan Maksimovic6e033432016-11-09 17:31:51 -08002104 Sandboxer(Target).lw(Dest, Addr);
Jaydeep Patila7979bf2016-10-26 06:16:19 -07002105 }
2106 }
Sagar Thakur5674c912016-07-14 14:50:37 -07002107 Legalized = true;
Sagar Thakur5674c912016-07-14 14:50:37 -07002108 }
2109 }
Sagar Thakur5674c912016-07-14 14:50:37 -07002110 }
2111
2112 if (Legalized) {
2113 if (MovInstr->isDestRedefined()) {
2114 Target->_set_dest_redefined();
2115 }
2116 MovInstr->setDeleted();
2117 }
2118}
2119
Jaydeep Patilec929172016-10-16 07:13:38 -07002120OperandMIPS32Mem *
2121TargetMIPS32::PostLoweringLegalizer::legalizeMemOperand(OperandMIPS32Mem *Mem) {
2122 if (llvm::isa<ConstantRelocatable>(Mem->getOffset())) {
2123 return nullptr;
2124 }
2125 Variable *Base = Mem->getBase();
2126 auto *Ci32 = llvm::cast<ConstantInteger32>(Mem->getOffset());
2127 int32_t Offset = Ci32->getValue();
2128
2129 if (Base->isRematerializable()) {
2130 const int32_t ExtraOffset =
2131 (Base->getRegNum() == Target->getFrameOrStackReg())
2132 ? Target->getFrameFixedAllocaOffset()
2133 : 0;
2134 Offset += Base->getStackOffset() + ExtraOffset;
2135 Base = Target->getPhysicalRegister(Base->getRegNum());
2136 }
2137
2138 constexpr bool SignExt = true;
2139 if (!OperandMIPS32Mem::canHoldOffset(Mem->getType(), SignExt, Offset)) {
2140 Base = newBaseRegister(Base, Offset, Target->getReservedTmpReg());
2141 Offset = 0;
2142 }
2143
2144 return OperandMIPS32Mem::create(
2145 Target->Func, Mem->getType(), Base,
2146 llvm::cast<ConstantInteger32>(Target->Ctx->getConstantInt32(Offset)));
2147}
2148
Sagar Thakur89be8872016-10-18 07:32:21 -07002149Variable *TargetMIPS32::PostLoweringLegalizer::legalizeImmediate(int32_t Imm) {
2150 Variable *Reg = nullptr;
2151 if (!((std::numeric_limits<int16_t>::min() <= Imm) &&
2152 (Imm <= std::numeric_limits<int16_t>::max()))) {
2153 const uint32_t UpperBits = (Imm >> 16) & 0xFFFF;
2154 const uint32_t LowerBits = Imm & 0xFFFF;
2155 Variable *TReg = Target->makeReg(IceType_i32, Target->getReservedTmpReg());
2156 Reg = Target->makeReg(IceType_i32, Target->getReservedTmpReg());
2157 if (LowerBits) {
2158 Target->_lui(TReg, Target->Ctx->getConstantInt32(UpperBits));
2159 Target->_ori(Reg, TReg, LowerBits);
2160 } else {
2161 Target->_lui(Reg, Target->Ctx->getConstantInt32(UpperBits));
2162 }
2163 }
2164 return Reg;
2165}
2166
Sagar Thakur5674c912016-07-14 14:50:37 -07002167void TargetMIPS32::postLowerLegalization() {
2168 Func->dump("Before postLowerLegalization");
2169 assert(hasComputedFrame());
2170 for (CfgNode *Node : Func->getNodes()) {
2171 Context.init(Node);
2172 PostLoweringLegalizer Legalizer(this);
2173 while (!Context.atEnd()) {
2174 PostIncrLoweringContext PostIncrement(Context);
2175 Inst *CurInstr = iteratorToInst(Context.getCur());
Jaydeep Patilec929172016-10-16 07:13:38 -07002176 const SizeT NumSrcs = CurInstr->getSrcSize();
2177 Operand *Src0 = NumSrcs < 1 ? nullptr : CurInstr->getSrc(0);
2178 Operand *Src1 = NumSrcs < 2 ? nullptr : CurInstr->getSrc(1);
2179 auto *Src0V = llvm::dyn_cast_or_null<Variable>(Src0);
2180 auto *Src0M = llvm::dyn_cast_or_null<OperandMIPS32Mem>(Src0);
2181 auto *Src1M = llvm::dyn_cast_or_null<OperandMIPS32Mem>(Src1);
2182 Variable *Dst = CurInstr->getDest();
Sagar Thakur5674c912016-07-14 14:50:37 -07002183 if (auto *MovInstr = llvm::dyn_cast<InstMIPS32Mov>(CurInstr)) {
2184 Legalizer.legalizeMov(MovInstr);
Jaydeep Patilec929172016-10-16 07:13:38 -07002185 continue;
2186 }
Jaydeep Patil2bbda7f2017-01-10 21:48:58 -08002187 if (auto *MovInstr = llvm::dyn_cast<InstMIPS32MovFP64ToI64>(CurInstr)) {
2188 Legalizer.legalizeMovFp(MovInstr);
2189 continue;
2190 }
Jaydeep Patilec929172016-10-16 07:13:38 -07002191 if (llvm::isa<InstMIPS32Sw>(CurInstr)) {
2192 if (auto *LegalMem = Legalizer.legalizeMemOperand(Src1M)) {
Stefan Maksimovic6e033432016-11-09 17:31:51 -08002193 Sandboxer(this).sw(Src0V, LegalMem);
Jaydeep Patilec929172016-10-16 07:13:38 -07002194 CurInstr->setDeleted();
2195 }
2196 continue;
2197 }
2198 if (llvm::isa<InstMIPS32Swc1>(CurInstr)) {
2199 if (auto *LegalMem = Legalizer.legalizeMemOperand(Src1M)) {
2200 _swc1(Src0V, LegalMem);
2201 CurInstr->setDeleted();
2202 }
2203 continue;
2204 }
2205 if (llvm::isa<InstMIPS32Sdc1>(CurInstr)) {
2206 if (auto *LegalMem = Legalizer.legalizeMemOperand(Src1M)) {
2207 _sdc1(Src0V, LegalMem);
2208 CurInstr->setDeleted();
2209 }
2210 continue;
2211 }
2212 if (llvm::isa<InstMIPS32Lw>(CurInstr)) {
2213 if (auto *LegalMem = Legalizer.legalizeMemOperand(Src0M)) {
Stefan Maksimovic6e033432016-11-09 17:31:51 -08002214 Sandboxer(this).lw(Dst, LegalMem);
Jaydeep Patilec929172016-10-16 07:13:38 -07002215 CurInstr->setDeleted();
2216 }
2217 continue;
2218 }
2219 if (llvm::isa<InstMIPS32Lwc1>(CurInstr)) {
2220 if (auto *LegalMem = Legalizer.legalizeMemOperand(Src0M)) {
2221 _lwc1(Dst, LegalMem);
2222 CurInstr->setDeleted();
2223 }
2224 continue;
2225 }
2226 if (llvm::isa<InstMIPS32Ldc1>(CurInstr)) {
2227 if (auto *LegalMem = Legalizer.legalizeMemOperand(Src0M)) {
2228 _ldc1(Dst, LegalMem);
2229 CurInstr->setDeleted();
2230 }
2231 continue;
Sagar Thakur5674c912016-07-14 14:50:37 -07002232 }
Sagar Thakur89be8872016-10-18 07:32:21 -07002233 if (auto *AddiuInstr = llvm::dyn_cast<InstMIPS32Addiu>(CurInstr)) {
2234 if (auto *LegalImm = Legalizer.legalizeImmediate(
2235 static_cast<int32_t>(AddiuInstr->getImmediateValue()))) {
2236 _addu(Dst, Src0V, LegalImm);
2237 CurInstr->setDeleted();
2238 }
2239 continue;
2240 }
Sagar Thakur5674c912016-07-14 14:50:37 -07002241 }
2242 }
2243}
2244
Jim Stichnothac8da5c2015-10-21 06:57:46 -07002245Operand *TargetMIPS32::loOperand(Operand *Operand) {
2246 assert(Operand->getType() == IceType_i64);
2247 if (auto *Var64On32 = llvm::dyn_cast<Variable64On32>(Operand))
2248 return Var64On32->getLo();
2249 if (auto *Const = llvm::dyn_cast<ConstantInteger64>(Operand)) {
2250 return Ctx->getConstantInt32(static_cast<uint32_t>(Const->getValue()));
2251 }
2252 if (auto *Mem = llvm::dyn_cast<OperandMIPS32Mem>(Operand)) {
2253 // Conservatively disallow memory operands with side-effects (pre/post
2254 // increment) in case of duplication.
2255 assert(Mem->getAddrMode() == OperandMIPS32Mem::Offset);
2256 return OperandMIPS32Mem::create(Func, IceType_i32, Mem->getBase(),
2257 Mem->getOffset(), Mem->getAddrMode());
2258 }
2259 llvm_unreachable("Unsupported operand type");
2260 return nullptr;
2261}
2262
Jaydeep Patil958ddb72016-10-03 07:52:48 -07002263Operand *TargetMIPS32::getOperandAtIndex(Operand *Operand, Type BaseType,
2264 uint32_t Index) {
2265 if (!isVectorType(Operand->getType())) {
2266 llvm::report_fatal_error("getOperandAtIndex: Operand is not vector");
2267 return nullptr;
2268 }
2269
2270 if (auto *Mem = llvm::dyn_cast<OperandMIPS32Mem>(Operand)) {
2271 assert(Mem->getAddrMode() == OperandMIPS32Mem::Offset);
2272 Variable *Base = Mem->getBase();
2273 auto *Offset = llvm::cast<ConstantInteger32>(Mem->getOffset());
2274 assert(!Utils::WouldOverflowAdd(Offset->getValue(), 4));
2275 int32_t NextOffsetVal =
2276 Offset->getValue() + (Index * typeWidthInBytes(BaseType));
2277 constexpr bool NoSignExt = false;
2278 if (!OperandMIPS32Mem::canHoldOffset(BaseType, NoSignExt, NextOffsetVal)) {
2279 Constant *_4 = Ctx->getConstantInt32(4);
2280 Variable *NewBase = Func->makeVariable(Base->getType());
2281 lowerArithmetic(
2282 InstArithmetic::create(Func, InstArithmetic::Add, NewBase, Base, _4));
2283 Base = NewBase;
2284 } else {
2285 Offset =
2286 llvm::cast<ConstantInteger32>(Ctx->getConstantInt32(NextOffsetVal));
2287 }
2288 return OperandMIPS32Mem::create(Func, BaseType, Base, Offset,
2289 Mem->getAddrMode());
2290 }
2291
2292 if (auto *VarVecOn32 = llvm::dyn_cast<VariableVecOn32>(Operand))
2293 return VarVecOn32->getContainers()[Index];
2294
2295 llvm_unreachable("Unsupported operand type");
2296 return nullptr;
2297}
2298
Jim Stichnothac8da5c2015-10-21 06:57:46 -07002299Operand *TargetMIPS32::hiOperand(Operand *Operand) {
2300 assert(Operand->getType() == IceType_i64);
2301 if (Operand->getType() != IceType_i64)
2302 return Operand;
2303 if (auto *Var64On32 = llvm::dyn_cast<Variable64On32>(Operand))
2304 return Var64On32->getHi();
2305 if (auto *Const = llvm::dyn_cast<ConstantInteger64>(Operand)) {
2306 return Ctx->getConstantInt32(
2307 static_cast<uint32_t>(Const->getValue() >> 32));
2308 }
2309 if (auto *Mem = llvm::dyn_cast<OperandMIPS32Mem>(Operand)) {
2310 // Conservatively disallow memory operands with side-effects
2311 // in case of duplication.
2312 assert(Mem->getAddrMode() == OperandMIPS32Mem::Offset);
2313 const Type SplitType = IceType_i32;
2314 Variable *Base = Mem->getBase();
Mohit Bhakkadd1e97772016-07-07 05:07:35 -07002315 auto *Offset = llvm::cast<ConstantInteger32>(Mem->getOffset());
Jim Stichnothac8da5c2015-10-21 06:57:46 -07002316 assert(!Utils::WouldOverflowAdd(Offset->getValue(), 4));
2317 int32_t NextOffsetVal = Offset->getValue() + 4;
2318 constexpr bool SignExt = false;
2319 if (!OperandMIPS32Mem::canHoldOffset(SplitType, SignExt, NextOffsetVal)) {
2320 // We have to make a temp variable and add 4 to either Base or Offset.
2321 // If we add 4 to Offset, this will convert a non-RegReg addressing
2322 // mode into a RegReg addressing mode. Since NaCl sandboxing disallows
2323 // RegReg addressing modes, prefer adding to base and replacing instead.
2324 // Thus we leave the old offset alone.
2325 Constant *Four = Ctx->getConstantInt32(4);
2326 Variable *NewBase = Func->makeVariable(Base->getType());
2327 lowerArithmetic(InstArithmetic::create(Func, InstArithmetic::Add, NewBase,
2328 Base, Four));
2329 Base = NewBase;
2330 } else {
2331 Offset =
2332 llvm::cast<ConstantInteger32>(Ctx->getConstantInt32(NextOffsetVal));
2333 }
2334 return OperandMIPS32Mem::create(Func, SplitType, Base, Offset,
2335 Mem->getAddrMode());
2336 }
2337 llvm_unreachable("Unsupported operand type");
2338 return nullptr;
2339}
2340
John Portoe82b5602016-02-24 15:58:55 -08002341SmallBitVector TargetMIPS32::getRegisterSet(RegSetMask Include,
2342 RegSetMask Exclude) const {
2343 SmallBitVector Registers(RegMIPS32::Reg_NUM);
Jim Stichnoth6da4cef2015-06-11 13:26:33 -07002344
2345#define X(val, encode, name, scratch, preserved, stackptr, frameptr, isInt, \
Jim Stichnothac8da5c2015-10-21 06:57:46 -07002346 isI64Pair, isFP32, isFP64, isVec128, alias_init) \
Jim Stichnoth6da4cef2015-06-11 13:26:33 -07002347 if (scratch && (Include & RegSet_CallerSave)) \
2348 Registers[RegMIPS32::val] = true; \
2349 if (preserved && (Include & RegSet_CalleeSave)) \
2350 Registers[RegMIPS32::val] = true; \
2351 if (stackptr && (Include & RegSet_StackPointer)) \
2352 Registers[RegMIPS32::val] = true; \
2353 if (frameptr && (Include & RegSet_FramePointer)) \
2354 Registers[RegMIPS32::val] = true; \
2355 if (scratch && (Exclude & RegSet_CallerSave)) \
2356 Registers[RegMIPS32::val] = false; \
2357 if (preserved && (Exclude & RegSet_CalleeSave)) \
2358 Registers[RegMIPS32::val] = false; \
2359 if (stackptr && (Exclude & RegSet_StackPointer)) \
2360 Registers[RegMIPS32::val] = false; \
2361 if (frameptr && (Exclude & RegSet_FramePointer)) \
2362 Registers[RegMIPS32::val] = false;
2363
2364 REGMIPS32_TABLE
2365
2366#undef X
2367
Stefan Maksimovic6e033432016-11-09 17:31:51 -08002368 if (NeedSandboxing) {
2369 Registers[RegMIPS32::Reg_T6] = false;
2370 Registers[RegMIPS32::Reg_T7] = false;
2371 Registers[RegMIPS32::Reg_T8] = false;
2372 }
Jim Stichnoth6da4cef2015-06-11 13:26:33 -07002373 return Registers;
2374}
2375
Reed Kotler04bca5a2016-02-03 14:40:47 -08002376void TargetMIPS32::lowerAlloca(const InstAlloca *Instr) {
Andrew Scull57e12682015-09-16 11:30:19 -07002377 // Conservatively require the stack to be aligned. Some stack adjustment
2378 // operations implemented below assume that the stack is aligned before the
2379 // alloca. All the alloca code ensures that the stack alignment is preserved
2380 // after the alloca. The stack alignment restriction can be relaxed in some
2381 // cases.
Jim Stichnoth6da4cef2015-06-11 13:26:33 -07002382 NeedsStackAlignment = true;
Sagar Thakur1afb4832016-06-16 15:30:24 -07002383
2384 // For default align=0, set it to the real value 1, to avoid any
2385 // bit-manipulation problems below.
2386 const uint32_t AlignmentParam = std::max(1u, Instr->getAlignInBytes());
2387
2388 // LLVM enforces power of 2 alignment.
2389 assert(llvm::isPowerOf2_32(AlignmentParam));
2390 assert(llvm::isPowerOf2_32(MIPS32_STACK_ALIGNMENT_BYTES));
2391
2392 const uint32_t Alignment =
2393 std::max(AlignmentParam, MIPS32_STACK_ALIGNMENT_BYTES);
2394 const bool OverAligned = Alignment > MIPS32_STACK_ALIGNMENT_BYTES;
Jim Stichnoth386b52e2016-08-05 15:18:41 -07002395 const bool OptM1 = Func->getOptLevel() == Opt_m1;
Sagar Thakur1afb4832016-06-16 15:30:24 -07002396 const bool AllocaWithKnownOffset = Instr->getKnownFrameOffset();
2397 const bool UseFramePointer =
2398 hasFramePointer() || OverAligned || !AllocaWithKnownOffset || OptM1;
2399
2400 if (UseFramePointer)
2401 setHasFramePointer();
2402
2403 Variable *SP = getPhysicalRegister(RegMIPS32::Reg_SP);
2404
2405 Variable *Dest = Instr->getDest();
2406 Operand *TotalSize = Instr->getSizeInBytes();
2407
2408 if (const auto *ConstantTotalSize =
2409 llvm::dyn_cast<ConstantInteger32>(TotalSize)) {
2410 const uint32_t Value =
2411 Utils::applyAlignment(ConstantTotalSize->getValue(), Alignment);
2412 FixedAllocaSizeBytes += Value;
2413 // Constant size alloca.
2414 if (!UseFramePointer) {
2415 // If we don't need a Frame Pointer, this alloca has a known offset to the
2416 // stack pointer. We don't need adjust the stack pointer, nor assign any
2417 // value to Dest, as Dest is rematerializable.
2418 assert(Dest->isRematerializable());
2419 Context.insert<InstFakeDef>(Dest);
2420 return;
2421 }
Sagar Thakur46832372016-10-16 07:20:44 -07002422
2423 if (Alignment > MIPS32_STACK_ALIGNMENT_BYTES) {
2424 CurrentAllocaOffset =
2425 Utils::applyAlignment(CurrentAllocaOffset, Alignment);
2426 }
2427 auto *T = I32Reg();
2428 _addiu(T, SP, CurrentAllocaOffset);
2429 _mov(Dest, T);
2430 CurrentAllocaOffset += Value;
2431 return;
2432
Sagar Thakur1afb4832016-06-16 15:30:24 -07002433 } else {
Sagar Thakurc930d592016-07-12 04:06:44 -07002434 // Non-constant sizes need to be adjusted to the next highest multiple of
2435 // the required alignment at runtime.
2436 VariableAllocaUsed = true;
Sagar Thakur89be8872016-10-18 07:32:21 -07002437 VariableAllocaAlignBytes = AlignmentParam;
Sagar Thakurc930d592016-07-12 04:06:44 -07002438 Variable *AlignAmount;
2439 auto *TotalSizeR = legalizeToReg(TotalSize, Legal_Reg);
2440 auto *T1 = I32Reg();
2441 auto *T2 = I32Reg();
2442 auto *T3 = I32Reg();
2443 auto *T4 = I32Reg();
2444 auto *T5 = I32Reg();
2445 _addiu(T1, TotalSizeR, MIPS32_STACK_ALIGNMENT_BYTES - 1);
2446 _addiu(T2, getZero(), -MIPS32_STACK_ALIGNMENT_BYTES);
2447 _and(T3, T1, T2);
2448 _subu(T4, SP, T3);
2449 if (Instr->getAlignInBytes()) {
2450 AlignAmount =
2451 legalizeToReg(Ctx->getConstantInt32(-AlignmentParam), Legal_Reg);
2452 _and(T5, T4, AlignAmount);
2453 _mov(Dest, T5);
2454 } else {
2455 _mov(Dest, T4);
2456 }
Stefan Maksimovic6e033432016-11-09 17:31:51 -08002457 if (OptM1)
2458 _mov(SP, Dest);
2459 else
2460 Sandboxer(this).reset_sp(Dest);
Sagar Thakur1afb4832016-06-16 15:30:24 -07002461 return;
2462 }
Jim Stichnoth6da4cef2015-06-11 13:26:33 -07002463}
2464
Reed Kotler04bca5a2016-02-03 14:40:47 -08002465void TargetMIPS32::lowerInt64Arithmetic(const InstArithmetic *Instr,
Reed Kotler00e36042016-02-01 20:52:19 -08002466 Variable *Dest, Operand *Src0,
2467 Operand *Src1) {
Reed Kotler04bca5a2016-02-03 14:40:47 -08002468 InstArithmetic::OpKind Op = Instr->getOp();
Reed Kotler00e36042016-02-01 20:52:19 -08002469 auto *DestLo = llvm::cast<Variable>(loOperand(Dest));
2470 auto *DestHi = llvm::cast<Variable>(hiOperand(Dest));
Sagar Thakur86b60ef2016-09-23 11:55:46 -07002471 Variable *Src0LoR = nullptr;
2472 Variable *Src1LoR = nullptr;
2473 Variable *Src0HiR = nullptr;
2474 Variable *Src1HiR = nullptr;
Reed Kotler00e36042016-02-01 20:52:19 -08002475
2476 switch (Op) {
2477 case InstArithmetic::_num:
2478 llvm::report_fatal_error("Unknown arithmetic operator");
2479 return;
2480 case InstArithmetic::Add: {
Sagar Thakur86b60ef2016-09-23 11:55:46 -07002481 Src0LoR = legalizeToReg(loOperand(Src0));
2482 Src1LoR = legalizeToReg(loOperand(Src1));
2483 Src0HiR = legalizeToReg(hiOperand(Src0));
2484 Src1HiR = legalizeToReg(hiOperand(Src1));
Reed Kotler953568f2016-02-17 05:37:01 -08002485 auto *T_Carry = I32Reg(), *T_Lo = I32Reg(), *T_Hi = I32Reg(),
2486 *T_Hi2 = I32Reg();
Reed Kotler00e36042016-02-01 20:52:19 -08002487 _addu(T_Lo, Src0LoR, Src1LoR);
2488 _mov(DestLo, T_Lo);
2489 _sltu(T_Carry, T_Lo, Src0LoR);
2490 _addu(T_Hi, T_Carry, Src0HiR);
2491 _addu(T_Hi2, Src1HiR, T_Hi);
2492 _mov(DestHi, T_Hi2);
2493 return;
2494 }
2495 case InstArithmetic::And: {
Sagar Thakur86b60ef2016-09-23 11:55:46 -07002496 Src0LoR = legalizeToReg(loOperand(Src0));
2497 Src1LoR = legalizeToReg(loOperand(Src1));
2498 Src0HiR = legalizeToReg(hiOperand(Src0));
2499 Src1HiR = legalizeToReg(hiOperand(Src1));
Reed Kotler953568f2016-02-17 05:37:01 -08002500 auto *T_Lo = I32Reg(), *T_Hi = I32Reg();
Reed Kotler00e36042016-02-01 20:52:19 -08002501 _and(T_Lo, Src0LoR, Src1LoR);
2502 _mov(DestLo, T_Lo);
2503 _and(T_Hi, Src0HiR, Src1HiR);
2504 _mov(DestHi, T_Hi);
2505 return;
2506 }
2507 case InstArithmetic::Sub: {
Sagar Thakur86b60ef2016-09-23 11:55:46 -07002508 Src0LoR = legalizeToReg(loOperand(Src0));
2509 Src1LoR = legalizeToReg(loOperand(Src1));
2510 Src0HiR = legalizeToReg(hiOperand(Src0));
2511 Src1HiR = legalizeToReg(hiOperand(Src1));
Reed Kotler953568f2016-02-17 05:37:01 -08002512 auto *T_Borrow = I32Reg(), *T_Lo = I32Reg(), *T_Hi = I32Reg(),
2513 *T_Hi2 = I32Reg();
Reed Kotler00e36042016-02-01 20:52:19 -08002514 _subu(T_Lo, Src0LoR, Src1LoR);
2515 _mov(DestLo, T_Lo);
2516 _sltu(T_Borrow, Src0LoR, Src1LoR);
2517 _addu(T_Hi, T_Borrow, Src1HiR);
2518 _subu(T_Hi2, Src0HiR, T_Hi);
2519 _mov(DestHi, T_Hi2);
2520 return;
2521 }
2522 case InstArithmetic::Or: {
Sagar Thakur86b60ef2016-09-23 11:55:46 -07002523 Src0LoR = legalizeToReg(loOperand(Src0));
2524 Src1LoR = legalizeToReg(loOperand(Src1));
2525 Src0HiR = legalizeToReg(hiOperand(Src0));
2526 Src1HiR = legalizeToReg(hiOperand(Src1));
Reed Kotler953568f2016-02-17 05:37:01 -08002527 auto *T_Lo = I32Reg(), *T_Hi = I32Reg();
Reed Kotler00e36042016-02-01 20:52:19 -08002528 _or(T_Lo, Src0LoR, Src1LoR);
2529 _mov(DestLo, T_Lo);
2530 _or(T_Hi, Src0HiR, Src1HiR);
2531 _mov(DestHi, T_Hi);
2532 return;
2533 }
2534 case InstArithmetic::Xor: {
Sagar Thakur86b60ef2016-09-23 11:55:46 -07002535 Src0LoR = legalizeToReg(loOperand(Src0));
2536 Src1LoR = legalizeToReg(loOperand(Src1));
2537 Src0HiR = legalizeToReg(hiOperand(Src0));
2538 Src1HiR = legalizeToReg(hiOperand(Src1));
Reed Kotler953568f2016-02-17 05:37:01 -08002539 auto *T_Lo = I32Reg(), *T_Hi = I32Reg();
Reed Kotler00e36042016-02-01 20:52:19 -08002540 _xor(T_Lo, Src0LoR, Src1LoR);
2541 _mov(DestLo, T_Lo);
2542 _xor(T_Hi, Src0HiR, Src1HiR);
2543 _mov(DestHi, T_Hi);
2544 return;
2545 }
Reed Kotlera80cdbc2016-02-19 22:03:29 -08002546 case InstArithmetic::Mul: {
2547 // TODO(rkotler): Make sure that mul has the side effect of clobbering
2548 // LO, HI. Check for any other LO, HI quirkiness in this section.
Sagar Thakur86b60ef2016-09-23 11:55:46 -07002549 Src0LoR = legalizeToReg(loOperand(Src0));
2550 Src1LoR = legalizeToReg(loOperand(Src1));
2551 Src0HiR = legalizeToReg(hiOperand(Src0));
2552 Src1HiR = legalizeToReg(hiOperand(Src1));
Reed Kotlera80cdbc2016-02-19 22:03:29 -08002553 auto *T_Lo = I32Reg(RegMIPS32::Reg_LO), *T_Hi = I32Reg(RegMIPS32::Reg_HI);
2554 auto *T1 = I32Reg(), *T2 = I32Reg();
2555 auto *TM1 = I32Reg(), *TM2 = I32Reg(), *TM3 = I32Reg(), *TM4 = I32Reg();
2556 _multu(T_Lo, Src0LoR, Src1LoR);
2557 Context.insert<InstFakeDef>(T_Hi, T_Lo);
2558 _mflo(T1, T_Lo);
2559 _mfhi(T2, T_Hi);
2560 _mov(DestLo, T1);
2561 _mul(TM1, Src0HiR, Src1LoR);
2562 _mul(TM2, Src0LoR, Src1HiR);
2563 _addu(TM3, TM1, T2);
2564 _addu(TM4, TM3, TM2);
2565 _mov(DestHi, TM4);
2566 return;
2567 }
Sagar Thakur86b60ef2016-09-23 11:55:46 -07002568 case InstArithmetic::Shl: {
2569 auto *T_Lo = I32Reg();
2570 auto *T_Hi = I32Reg();
2571 auto *T1_Lo = I32Reg();
2572 auto *T1_Hi = I32Reg();
2573 auto *T1 = I32Reg();
2574 auto *T2 = I32Reg();
2575 auto *T3 = I32Reg();
2576 auto *T4 = I32Reg();
2577 auto *T5 = I32Reg();
2578
2579 if (auto *Const = llvm::dyn_cast<ConstantInteger64>(Src1)) {
2580 Src0LoR = legalizeToReg(loOperand(Src0));
2581 int64_t ShiftAmount = Const->getValue();
2582 if (ShiftAmount == 1) {
2583 Src0HiR = legalizeToReg(hiOperand(Src0));
2584 _addu(T_Lo, Src0LoR, Src0LoR);
2585 _sltu(T1, T_Lo, Src0LoR);
2586 _addu(T2, T1, Src0HiR);
2587 _addu(T_Hi, Src0HiR, T2);
2588 } else if (ShiftAmount < INT32_BITS) {
2589 Src0HiR = legalizeToReg(hiOperand(Src0));
2590 _srl(T1, Src0LoR, INT32_BITS - ShiftAmount);
2591 _sll(T2, Src0HiR, ShiftAmount);
2592 _or(T_Hi, T1, T2);
2593 _sll(T_Lo, Src0LoR, ShiftAmount);
2594 } else if (ShiftAmount == INT32_BITS) {
2595 _addiu(T_Lo, getZero(), 0);
2596 _mov(T_Hi, Src0LoR);
2597 } else if (ShiftAmount > INT32_BITS && ShiftAmount < 64) {
2598 _sll(T_Hi, Src0LoR, ShiftAmount - INT32_BITS);
2599 _addiu(T_Lo, getZero(), 0);
2600 }
2601 _mov(DestLo, T_Lo);
2602 _mov(DestHi, T_Hi);
2603 return;
2604 }
2605
2606 Src0LoR = legalizeToReg(loOperand(Src0));
2607 Src1LoR = legalizeToReg(loOperand(Src1));
2608 Src0HiR = legalizeToReg(hiOperand(Src0));
2609
2610 _sllv(T1, Src0HiR, Src1LoR);
2611 _not(T2, Src1LoR);
2612 _srl(T3, Src0LoR, 1);
2613 _srlv(T4, T3, T2);
2614 _or(T_Hi, T1, T4);
2615 _sllv(T_Lo, Src0LoR, Src1LoR);
2616
2617 _mov(T1_Hi, T_Hi);
2618 _mov(T1_Lo, T_Lo);
2619 _andi(T5, Src1LoR, INT32_BITS);
2620 _movn(T1_Hi, T_Lo, T5);
2621 _movn(T1_Lo, getZero(), T5);
2622 _mov(DestHi, T1_Hi);
2623 _mov(DestLo, T1_Lo);
2624 return;
2625 }
2626 case InstArithmetic::Lshr: {
2627
2628 auto *T_Lo = I32Reg();
2629 auto *T_Hi = I32Reg();
2630 auto *T1_Lo = I32Reg();
2631 auto *T1_Hi = I32Reg();
2632 auto *T1 = I32Reg();
2633 auto *T2 = I32Reg();
2634 auto *T3 = I32Reg();
2635 auto *T4 = I32Reg();
2636 auto *T5 = I32Reg();
2637
2638 if (auto *Const = llvm::dyn_cast<ConstantInteger64>(Src1)) {
2639 Src0HiR = legalizeToReg(hiOperand(Src0));
2640 int64_t ShiftAmount = Const->getValue();
2641 if (ShiftAmount < INT32_BITS) {
2642 Src0LoR = legalizeToReg(loOperand(Src0));
2643 _sll(T1, Src0HiR, INT32_BITS - ShiftAmount);
2644 _srl(T2, Src0LoR, ShiftAmount);
2645 _or(T_Lo, T1, T2);
2646 _srl(T_Hi, Src0HiR, ShiftAmount);
2647 } else if (ShiftAmount == INT32_BITS) {
2648 _mov(T_Lo, Src0HiR);
2649 _addiu(T_Hi, getZero(), 0);
2650 } else if (ShiftAmount > INT32_BITS && ShiftAmount < 64) {
2651 _srl(T_Lo, Src0HiR, ShiftAmount - INT32_BITS);
2652 _addiu(T_Hi, getZero(), 0);
2653 }
2654 _mov(DestLo, T_Lo);
2655 _mov(DestHi, T_Hi);
2656 return;
2657 }
2658
2659 Src0LoR = legalizeToReg(loOperand(Src0));
2660 Src1LoR = legalizeToReg(loOperand(Src1));
2661 Src0HiR = legalizeToReg(hiOperand(Src0));
2662
2663 _srlv(T1, Src0LoR, Src1LoR);
2664 _not(T2, Src1LoR);
2665 _sll(T3, Src0HiR, 1);
2666 _sllv(T4, T3, T2);
2667 _or(T_Lo, T1, T4);
2668 _srlv(T_Hi, Src0HiR, Src1LoR);
2669
2670 _mov(T1_Hi, T_Hi);
2671 _mov(T1_Lo, T_Lo);
2672 _andi(T5, Src1LoR, INT32_BITS);
2673 _movn(T1_Lo, T_Hi, T5);
2674 _movn(T1_Hi, getZero(), T5);
2675 _mov(DestHi, T1_Hi);
2676 _mov(DestLo, T1_Lo);
2677 return;
2678 }
2679 case InstArithmetic::Ashr: {
2680
2681 auto *T_Lo = I32Reg();
2682 auto *T_Hi = I32Reg();
2683 auto *T1_Lo = I32Reg();
2684 auto *T1_Hi = I32Reg();
2685 auto *T1 = I32Reg();
2686 auto *T2 = I32Reg();
2687 auto *T3 = I32Reg();
2688 auto *T4 = I32Reg();
2689 auto *T5 = I32Reg();
2690 auto *T6 = I32Reg();
2691
2692 if (auto *Const = llvm::dyn_cast<ConstantInteger64>(Src1)) {
2693 Src0HiR = legalizeToReg(hiOperand(Src0));
2694 int64_t ShiftAmount = Const->getValue();
2695 if (ShiftAmount < INT32_BITS) {
2696 Src0LoR = legalizeToReg(loOperand(Src0));
2697 _sll(T1, Src0HiR, INT32_BITS - ShiftAmount);
2698 _srl(T2, Src0LoR, ShiftAmount);
2699 _or(T_Lo, T1, T2);
2700 _sra(T_Hi, Src0HiR, ShiftAmount);
2701 } else if (ShiftAmount == INT32_BITS) {
2702 _sra(T_Hi, Src0HiR, INT32_BITS - 1);
2703 _mov(T_Lo, Src0HiR);
2704 } else if (ShiftAmount > INT32_BITS && ShiftAmount < 64) {
2705 _sra(T_Lo, Src0HiR, ShiftAmount - INT32_BITS);
2706 _sra(T_Hi, Src0HiR, INT32_BITS - 1);
2707 }
2708 _mov(DestLo, T_Lo);
2709 _mov(DestHi, T_Hi);
2710 return;
2711 }
2712
2713 Src0LoR = legalizeToReg(loOperand(Src0));
2714 Src1LoR = legalizeToReg(loOperand(Src1));
2715 Src0HiR = legalizeToReg(hiOperand(Src0));
2716
2717 _srlv(T1, Src0LoR, Src1LoR);
2718 _not(T2, Src1LoR);
2719 _sll(T3, Src0HiR, 1);
2720 _sllv(T4, T3, T2);
2721 _or(T_Lo, T1, T4);
2722 _srav(T_Hi, Src0HiR, Src1LoR);
2723
2724 _mov(T1_Hi, T_Hi);
2725 _mov(T1_Lo, T_Lo);
2726 _andi(T5, Src1LoR, INT32_BITS);
2727 _movn(T1_Lo, T_Hi, T5);
2728 _sra(T6, Src0HiR, INT32_BITS - 1);
2729 _movn(T1_Hi, T6, T5);
2730 _mov(DestHi, T1_Hi);
2731 _mov(DestLo, T1_Lo);
2732 return;
2733 }
Sagar Thakurbecb85f2016-11-18 12:15:46 -08002734 case InstArithmetic::Fadd:
2735 case InstArithmetic::Fsub:
2736 case InstArithmetic::Fmul:
2737 case InstArithmetic::Fdiv:
2738 case InstArithmetic::Frem:
2739 llvm::report_fatal_error("FP instruction with i64 type");
2740 return;
2741 case InstArithmetic::Udiv:
2742 case InstArithmetic::Sdiv:
2743 case InstArithmetic::Urem:
2744 case InstArithmetic::Srem:
2745 llvm::report_fatal_error("64-bit div and rem should have been prelowered");
Reed Kotler00e36042016-02-01 20:52:19 -08002746 return;
2747 }
2748}
2749
Reed Kotler04bca5a2016-02-03 14:40:47 -08002750void TargetMIPS32::lowerArithmetic(const InstArithmetic *Instr) {
2751 Variable *Dest = Instr->getDest();
Sagar Thakur46832372016-10-16 07:20:44 -07002752
2753 if (Dest->isRematerializable()) {
2754 Context.insert<InstFakeDef>(Dest);
2755 return;
2756 }
2757
Jim Stichnoth91c773e2016-01-19 09:52:22 -08002758 // We need to signal all the UnimplementedLoweringError errors before any
2759 // legalization into new variables, otherwise Om1 register allocation may fail
2760 // when it sees variables that are defined but not used.
Reed Kotler00e36042016-02-01 20:52:19 -08002761 Type DestTy = Dest->getType();
Reed Kotler04bca5a2016-02-03 14:40:47 -08002762 Operand *Src0 = legalizeUndef(Instr->getSrc(0));
2763 Operand *Src1 = legalizeUndef(Instr->getSrc(1));
Reed Kotler00e36042016-02-01 20:52:19 -08002764 if (DestTy == IceType_i64) {
Reed Kotler04bca5a2016-02-03 14:40:47 -08002765 lowerInt64Arithmetic(Instr, Instr->getDest(), Src0, Src1);
Reed Kotler37af5b02015-11-05 17:07:19 -08002766 return;
Jim Stichnoth6da4cef2015-06-11 13:26:33 -07002767 }
Reed Kotler37af5b02015-11-05 17:07:19 -08002768 if (isVectorType(Dest->getType())) {
Jaydeep Patil3a01f332016-10-17 06:33:50 -07002769 llvm::report_fatal_error("Arithmetic: Destination type is vector");
Reed Kotler37af5b02015-11-05 17:07:19 -08002770 return;
2771 }
Jim Stichnoth91c773e2016-01-19 09:52:22 -08002772
Reed Kotler37af5b02015-11-05 17:07:19 -08002773 Variable *T = makeReg(Dest->getType());
2774 Variable *Src0R = legalizeToReg(Src0);
Jaydeep Patil21f78bb2016-11-06 20:53:48 -08002775 Variable *Src1R = nullptr;
2776 uint32_t Value = 0;
2777 bool IsSrc1Imm16 = false;
2778
2779 switch (Instr->getOp()) {
2780 case InstArithmetic::Add:
Jaydeep Patil2bbda7f2017-01-10 21:48:58 -08002781 case InstArithmetic::Sub: {
2782 auto *Const32 = llvm::dyn_cast<ConstantInteger32>(Src1);
2783 if (Const32 != nullptr && isInt<16>(int32_t(Const32->getValue()))) {
2784 IsSrc1Imm16 = true;
2785 Value = Const32->getValue();
2786 } else {
2787 Src1R = legalizeToReg(Src1);
2788 }
2789 break;
2790 }
Jaydeep Patil21f78bb2016-11-06 20:53:48 -08002791 case InstArithmetic::And:
2792 case InstArithmetic::Or:
2793 case InstArithmetic::Xor:
Jaydeep Patil21f78bb2016-11-06 20:53:48 -08002794 case InstArithmetic::Shl:
2795 case InstArithmetic::Lshr:
2796 case InstArithmetic::Ashr: {
2797 auto *Const32 = llvm::dyn_cast<ConstantInteger32>(Src1);
Jaydeep Patil2bbda7f2017-01-10 21:48:58 -08002798 if (Const32 != nullptr && llvm::isUInt<16>(uint32_t(Const32->getValue()))) {
Jaydeep Patil21f78bb2016-11-06 20:53:48 -08002799 IsSrc1Imm16 = true;
2800 Value = Const32->getValue();
2801 } else {
2802 Src1R = legalizeToReg(Src1);
2803 }
2804 break;
2805 }
2806 default:
2807 Src1R = legalizeToReg(Src1);
2808 break;
2809 }
Jaydeep Patilcc6dea72016-09-19 16:48:34 -07002810 constexpr uint32_t DivideByZeroTrapCode = 7;
Jim Stichnoth91c773e2016-01-19 09:52:22 -08002811
Reed Kotler04bca5a2016-02-03 14:40:47 -08002812 switch (Instr->getOp()) {
Reed Kotler37af5b02015-11-05 17:07:19 -08002813 case InstArithmetic::_num:
2814 break;
Jaydeep Patil2bbda7f2017-01-10 21:48:58 -08002815 case InstArithmetic::Add: {
2816 auto *T0R = Src0R;
2817 auto *T1R = Src1R;
2818 if (Dest->getType() != IceType_i32) {
2819 T0R = makeReg(IceType_i32);
2820 lowerCast(InstCast::create(Func, InstCast::Sext, T0R, Src0R));
2821 if (!IsSrc1Imm16) {
2822 T1R = makeReg(IceType_i32);
2823 lowerCast(InstCast::create(Func, InstCast::Sext, T1R, Src1R));
2824 }
2825 }
Jaydeep Patil21f78bb2016-11-06 20:53:48 -08002826 if (IsSrc1Imm16) {
Jaydeep Patil2bbda7f2017-01-10 21:48:58 -08002827 _addiu(T, T0R, Value);
Jaydeep Patil21f78bb2016-11-06 20:53:48 -08002828 } else {
Jaydeep Patil2bbda7f2017-01-10 21:48:58 -08002829 _addu(T, T0R, T1R);
Jaydeep Patil21f78bb2016-11-06 20:53:48 -08002830 }
Reed Kotler37af5b02015-11-05 17:07:19 -08002831 _mov(Dest, T);
2832 return;
Jaydeep Patil2bbda7f2017-01-10 21:48:58 -08002833 }
Reed Kotler37af5b02015-11-05 17:07:19 -08002834 case InstArithmetic::And:
Jaydeep Patil21f78bb2016-11-06 20:53:48 -08002835 if (IsSrc1Imm16) {
2836 _andi(T, Src0R, Value);
2837 } else {
2838 _and(T, Src0R, Src1R);
2839 }
Reed Kotler37af5b02015-11-05 17:07:19 -08002840 _mov(Dest, T);
2841 return;
2842 case InstArithmetic::Or:
Jaydeep Patil21f78bb2016-11-06 20:53:48 -08002843 if (IsSrc1Imm16) {
2844 _ori(T, Src0R, Value);
2845 } else {
2846 _or(T, Src0R, Src1R);
2847 }
Reed Kotler37af5b02015-11-05 17:07:19 -08002848 _mov(Dest, T);
2849 return;
2850 case InstArithmetic::Xor:
Jaydeep Patil21f78bb2016-11-06 20:53:48 -08002851 if (IsSrc1Imm16) {
2852 _xori(T, Src0R, Value);
2853 } else {
2854 _xor(T, Src0R, Src1R);
2855 }
Reed Kotler37af5b02015-11-05 17:07:19 -08002856 _mov(Dest, T);
2857 return;
Jaydeep Patil2bbda7f2017-01-10 21:48:58 -08002858 case InstArithmetic::Sub: {
2859 auto *T0R = Src0R;
2860 auto *T1R = Src1R;
2861 if (Dest->getType() != IceType_i32) {
2862 T0R = makeReg(IceType_i32);
2863 lowerCast(InstCast::create(Func, InstCast::Sext, T0R, Src0R));
2864 if (!IsSrc1Imm16) {
2865 T1R = makeReg(IceType_i32);
2866 lowerCast(InstCast::create(Func, InstCast::Sext, T1R, Src1R));
2867 }
2868 }
Jaydeep Patil21f78bb2016-11-06 20:53:48 -08002869 if (IsSrc1Imm16) {
Jaydeep Patil2bbda7f2017-01-10 21:48:58 -08002870 _addiu(T, T0R, -Value);
Jaydeep Patil21f78bb2016-11-06 20:53:48 -08002871 } else {
Jaydeep Patil2bbda7f2017-01-10 21:48:58 -08002872 _subu(T, T0R, T1R);
Jaydeep Patil21f78bb2016-11-06 20:53:48 -08002873 }
Reed Kotler37af5b02015-11-05 17:07:19 -08002874 _mov(Dest, T);
2875 return;
Jaydeep Patil2bbda7f2017-01-10 21:48:58 -08002876 }
Reed Kotler37af5b02015-11-05 17:07:19 -08002877 case InstArithmetic::Mul: {
2878 _mul(T, Src0R, Src1R);
2879 _mov(Dest, T);
2880 return;
2881 }
Srdjan Obucinac2ee36a2016-05-17 13:16:02 -07002882 case InstArithmetic::Shl: {
Jaydeep Patil21f78bb2016-11-06 20:53:48 -08002883 if (IsSrc1Imm16) {
2884 _sll(T, Src0R, Value);
2885 } else {
2886 _sllv(T, Src0R, Src1R);
2887 }
Srdjan Obucinac2ee36a2016-05-17 13:16:02 -07002888 _mov(Dest, T);
2889 return;
2890 }
2891 case InstArithmetic::Lshr: {
Jaydeep Patila7979bf2016-10-26 06:16:19 -07002892 auto *T0R = Src0R;
2893 auto *T1R = Src1R;
2894 if (Dest->getType() != IceType_i32) {
2895 T0R = makeReg(IceType_i32);
2896 lowerCast(InstCast::create(Func, InstCast::Zext, T0R, Src0R));
Jaydeep Patil21f78bb2016-11-06 20:53:48 -08002897 if (!IsSrc1Imm16) {
2898 T1R = makeReg(IceType_i32);
2899 lowerCast(InstCast::create(Func, InstCast::Zext, T1R, Src1R));
2900 }
Jaydeep Patila7979bf2016-10-26 06:16:19 -07002901 }
Jaydeep Patil21f78bb2016-11-06 20:53:48 -08002902 if (IsSrc1Imm16) {
2903 _srl(T, T0R, Value);
2904 } else {
2905 _srlv(T, T0R, T1R);
2906 }
Srdjan Obucinac2ee36a2016-05-17 13:16:02 -07002907 _mov(Dest, T);
2908 return;
2909 }
2910 case InstArithmetic::Ashr: {
Jaydeep Patil2bbda7f2017-01-10 21:48:58 -08002911 auto *T0R = Src0R;
2912 auto *T1R = Src1R;
2913 if (Dest->getType() != IceType_i32) {
2914 T0R = makeReg(IceType_i32);
2915 lowerCast(InstCast::create(Func, InstCast::Sext, T0R, Src0R));
2916 if (!IsSrc1Imm16) {
2917 T1R = makeReg(IceType_i32);
2918 lowerCast(InstCast::create(Func, InstCast::Sext, T1R, Src1R));
2919 }
2920 }
Jaydeep Patil21f78bb2016-11-06 20:53:48 -08002921 if (IsSrc1Imm16) {
Jaydeep Patil2bbda7f2017-01-10 21:48:58 -08002922 _sra(T, T0R, Value);
Jaydeep Patil21f78bb2016-11-06 20:53:48 -08002923 } else {
Jaydeep Patil2bbda7f2017-01-10 21:48:58 -08002924 _srav(T, T0R, T1R);
Jaydeep Patil21f78bb2016-11-06 20:53:48 -08002925 }
Srdjan Obucinac2ee36a2016-05-17 13:16:02 -07002926 _mov(Dest, T);
2927 return;
2928 }
Srdjan Obucinaae93eee2016-05-18 11:31:15 -07002929 case InstArithmetic::Udiv: {
2930 auto *T_Zero = I32Reg(RegMIPS32::Reg_ZERO);
Jaydeep Patila7979bf2016-10-26 06:16:19 -07002931 auto *T0R = Src0R;
2932 auto *T1R = Src1R;
2933 if (Dest->getType() != IceType_i32) {
2934 T0R = makeReg(IceType_i32);
2935 lowerCast(InstCast::create(Func, InstCast::Zext, T0R, Src0R));
2936 T1R = makeReg(IceType_i32);
2937 lowerCast(InstCast::create(Func, InstCast::Zext, T1R, Src1R));
2938 }
2939 _divu(T_Zero, T0R, T1R);
2940 _teq(T1R, T_Zero, DivideByZeroTrapCode); // Trap if divide-by-zero
Srdjan Obucinaae93eee2016-05-18 11:31:15 -07002941 _mflo(T, T_Zero);
2942 _mov(Dest, T);
2943 return;
2944 }
2945 case InstArithmetic::Sdiv: {
2946 auto *T_Zero = I32Reg(RegMIPS32::Reg_ZERO);
Jaydeep Patil2bbda7f2017-01-10 21:48:58 -08002947 auto *T0R = Src0R;
2948 auto *T1R = Src1R;
2949 if (Dest->getType() != IceType_i32) {
2950 T0R = makeReg(IceType_i32);
2951 lowerCast(InstCast::create(Func, InstCast::Sext, T0R, Src0R));
2952 T1R = makeReg(IceType_i32);
2953 lowerCast(InstCast::create(Func, InstCast::Sext, T1R, Src1R));
2954 }
2955 _div(T_Zero, T0R, T1R);
2956 _teq(T1R, T_Zero, DivideByZeroTrapCode); // Trap if divide-by-zero
Srdjan Obucinaae93eee2016-05-18 11:31:15 -07002957 _mflo(T, T_Zero);
2958 _mov(Dest, T);
2959 return;
2960 }
2961 case InstArithmetic::Urem: {
2962 auto *T_Zero = I32Reg(RegMIPS32::Reg_ZERO);
Jaydeep Patila7979bf2016-10-26 06:16:19 -07002963 auto *T0R = Src0R;
2964 auto *T1R = Src1R;
2965 if (Dest->getType() != IceType_i32) {
2966 T0R = makeReg(IceType_i32);
2967 lowerCast(InstCast::create(Func, InstCast::Zext, T0R, Src0R));
2968 T1R = makeReg(IceType_i32);
2969 lowerCast(InstCast::create(Func, InstCast::Zext, T1R, Src1R));
2970 }
2971 _divu(T_Zero, T0R, T1R);
2972 _teq(T1R, T_Zero, DivideByZeroTrapCode); // Trap if divide-by-zero
Srdjan Obucinaae93eee2016-05-18 11:31:15 -07002973 _mfhi(T, T_Zero);
2974 _mov(Dest, T);
2975 return;
2976 }
2977 case InstArithmetic::Srem: {
2978 auto *T_Zero = I32Reg(RegMIPS32::Reg_ZERO);
Jaydeep Patil2bbda7f2017-01-10 21:48:58 -08002979 auto *T0R = Src0R;
2980 auto *T1R = Src1R;
2981 if (Dest->getType() != IceType_i32) {
2982 T0R = makeReg(IceType_i32);
2983 lowerCast(InstCast::create(Func, InstCast::Sext, T0R, Src0R));
2984 T1R = makeReg(IceType_i32);
2985 lowerCast(InstCast::create(Func, InstCast::Sext, T1R, Src1R));
2986 }
2987 _div(T_Zero, T0R, T1R);
2988 _teq(T1R, T_Zero, DivideByZeroTrapCode); // Trap if divide-by-zero
Srdjan Obucinaae93eee2016-05-18 11:31:15 -07002989 _mfhi(T, T_Zero);
2990 _mov(Dest, T);
2991 return;
2992 }
Srdjan Obucinaab6a04f2016-07-11 20:23:50 -07002993 case InstArithmetic::Fadd: {
2994 if (DestTy == IceType_f32) {
2995 _add_s(T, Src0R, Src1R);
2996 _mov(Dest, T);
2997 return;
2998 }
2999 if (DestTy == IceType_f64) {
3000 _add_d(T, Src0R, Src1R);
3001 _mov(Dest, T);
3002 return;
3003 }
Reed Kotler37af5b02015-11-05 17:07:19 -08003004 break;
Srdjan Obucinaab6a04f2016-07-11 20:23:50 -07003005 }
Reed Kotler37af5b02015-11-05 17:07:19 -08003006 case InstArithmetic::Fsub:
Srdjan Obucinaab6a04f2016-07-11 20:23:50 -07003007 if (DestTy == IceType_f32) {
3008 _sub_s(T, Src0R, Src1R);
3009 _mov(Dest, T);
3010 return;
3011 }
3012 if (DestTy == IceType_f64) {
3013 _sub_d(T, Src0R, Src1R);
3014 _mov(Dest, T);
3015 return;
3016 }
Reed Kotler37af5b02015-11-05 17:07:19 -08003017 break;
3018 case InstArithmetic::Fmul:
Srdjan Obucinaab6a04f2016-07-11 20:23:50 -07003019 if (DestTy == IceType_f32) {
3020 _mul_s(T, Src0R, Src1R);
3021 _mov(Dest, T);
3022 return;
3023 }
3024 if (DestTy == IceType_f64) {
3025 _mul_d(T, Src0R, Src1R);
3026 _mov(Dest, T);
3027 return;
3028 }
Reed Kotler37af5b02015-11-05 17:07:19 -08003029 break;
3030 case InstArithmetic::Fdiv:
Srdjan Obucinaab6a04f2016-07-11 20:23:50 -07003031 if (DestTy == IceType_f32) {
3032 _div_s(T, Src0R, Src1R);
3033 _mov(Dest, T);
3034 return;
3035 }
3036 if (DestTy == IceType_f64) {
3037 _div_d(T, Src0R, Src1R);
3038 _mov(Dest, T);
3039 return;
3040 }
Reed Kotler37af5b02015-11-05 17:07:19 -08003041 break;
3042 case InstArithmetic::Frem:
Srdjan Obucinaf5d8e092016-09-22 07:05:05 -07003043 llvm::report_fatal_error("frem should have been prelowered.");
Reed Kotler37af5b02015-11-05 17:07:19 -08003044 break;
3045 }
Sagar Thakurbecb85f2016-11-18 12:15:46 -08003046 llvm::report_fatal_error("Unknown arithmetic operator");
Jim Stichnoth6da4cef2015-06-11 13:26:33 -07003047}
3048
Reed Kotler04bca5a2016-02-03 14:40:47 -08003049void TargetMIPS32::lowerAssign(const InstAssign *Instr) {
3050 Variable *Dest = Instr->getDest();
Sagar Thakur5674c912016-07-14 14:50:37 -07003051
3052 if (Dest->isRematerializable()) {
3053 Context.insert<InstFakeDef>(Dest);
3054 return;
3055 }
3056
Jaydeep Patil3a01f332016-10-17 06:33:50 -07003057 // Source type may not be same as destination
3058 if (isVectorType(Dest->getType())) {
3059 Operand *Src0 = legalizeUndef(Instr->getSrc(0));
3060 auto *DstVec = llvm::dyn_cast<VariableVecOn32>(Dest);
3061 for (SizeT i = 0; i < DstVec->ContainersPerVector; ++i) {
3062 auto *DCont = DstVec->getContainers()[i];
3063 auto *SCont =
3064 legalize(getOperandAtIndex(Src0, IceType_i32, i), Legal_Reg);
3065 auto *TReg = makeReg(IceType_i32);
3066 _mov(TReg, SCont);
3067 _mov(DCont, TReg);
3068 }
3069 return;
3070 }
Reed Kotler04bca5a2016-02-03 14:40:47 -08003071 Operand *Src0 = Instr->getSrc(0);
Jim Stichnothac8da5c2015-10-21 06:57:46 -07003072 assert(Dest->getType() == Src0->getType());
3073 if (Dest->getType() == IceType_i64) {
3074 Src0 = legalizeUndef(Src0);
3075 Operand *Src0Lo = legalize(loOperand(Src0), Legal_Reg);
3076 Operand *Src0Hi = legalize(hiOperand(Src0), Legal_Reg);
Jim Stichnoth54f3d512015-12-11 09:53:00 -08003077 auto *DestLo = llvm::cast<Variable>(loOperand(Dest));
3078 auto *DestHi = llvm::cast<Variable>(hiOperand(Dest));
Reed Kotler953568f2016-02-17 05:37:01 -08003079 auto *T_Lo = I32Reg(), *T_Hi = I32Reg();
Jim Stichnothac8da5c2015-10-21 06:57:46 -07003080 _mov(T_Lo, Src0Lo);
3081 _mov(DestLo, T_Lo);
3082 _mov(T_Hi, Src0Hi);
3083 _mov(DestHi, T_Hi);
Jaydeep Patil958ddb72016-10-03 07:52:48 -07003084 return;
Jim Stichnothac8da5c2015-10-21 06:57:46 -07003085 }
Jaydeep Patil958ddb72016-10-03 07:52:48 -07003086 Operand *SrcR;
3087 if (Dest->hasReg()) {
3088 // If Dest already has a physical register, then legalize the Src operand
3089 // into a Variable with the same register assignment. This especially
3090 // helps allow the use of Flex operands.
3091 SrcR = legalize(Src0, Legal_Reg, Dest->getRegNum());
3092 } else {
3093 // Dest could be a stack operand. Since we could potentially need
3094 // to do a Store (and store can only have Register operands),
3095 // legalize this to a register.
3096 SrcR = legalize(Src0, Legal_Reg);
3097 }
3098 _mov(Dest, SrcR);
Jim Stichnoth6da4cef2015-06-11 13:26:33 -07003099}
3100
Reed Kotler04bca5a2016-02-03 14:40:47 -08003101void TargetMIPS32::lowerBr(const InstBr *Instr) {
Reed Kotler3fe4b572016-02-23 18:59:43 -08003102 if (Instr->isUnconditional()) {
3103 _br(Instr->getTargetUnconditional());
3104 return;
3105 }
Sagar Thakur5cce7612016-05-24 06:25:50 -07003106 CfgNode *TargetTrue = Instr->getTargetTrue();
3107 CfgNode *TargetFalse = Instr->getTargetFalse();
3108 Operand *Boolean = Instr->getCondition();
3109 const Inst *Producer = Computations.getProducerOf(Boolean);
3110 if (Producer == nullptr) {
3111 // Since we don't know the producer of this boolean we will assume its
3112 // producer will keep it in positive logic and just emit beqz with this
3113 // Boolean as an operand.
3114 auto *BooleanR = legalizeToReg(Boolean);
3115 _br(TargetTrue, TargetFalse, BooleanR, CondMIPS32::Cond::EQZ);
3116 return;
3117 }
3118 if (Producer->getKind() == Inst::Icmp) {
3119 const InstIcmp *CompareInst = llvm::cast<InstIcmp>(Producer);
3120 Operand *Src0 = CompareInst->getSrc(0);
3121 Operand *Src1 = CompareInst->getSrc(1);
3122 const Type Src0Ty = Src0->getType();
3123 assert(Src0Ty == Src1->getType());
Sagar Thakur93097562016-09-29 06:52:29 -07003124
3125 Variable *Src0R = nullptr;
3126 Variable *Src1R = nullptr;
3127 Variable *Src0HiR = nullptr;
3128 Variable *Src1HiR = nullptr;
Sagar Thakur5cce7612016-05-24 06:25:50 -07003129 if (Src0Ty == IceType_i64) {
Sagar Thakur93097562016-09-29 06:52:29 -07003130 Src0R = legalizeToReg(loOperand(Src0));
3131 Src1R = legalizeToReg(loOperand(Src1));
3132 Src0HiR = legalizeToReg(hiOperand(Src0));
3133 Src1HiR = legalizeToReg(hiOperand(Src1));
3134 } else {
Jaydeep Patil2bbda7f2017-01-10 21:48:58 -08003135 auto *Src0RT = legalizeToReg(Src0);
3136 auto *Src1RT = legalizeToReg(Src1);
3137 // Sign/Zero extend the source operands
3138 if (Src0Ty != IceType_i32) {
3139 InstCast::OpKind CastKind;
3140 switch (CompareInst->getCondition()) {
3141 case InstIcmp::Eq:
3142 case InstIcmp::Ne:
3143 case InstIcmp::Sgt:
3144 case InstIcmp::Sge:
3145 case InstIcmp::Slt:
3146 case InstIcmp::Sle:
3147 CastKind = InstCast::Sext;
3148 break;
3149 default:
3150 CastKind = InstCast::Zext;
3151 break;
3152 }
3153 Src0R = makeReg(IceType_i32);
3154 Src1R = makeReg(IceType_i32);
3155 lowerCast(InstCast::create(Func, CastKind, Src0R, Src0RT));
3156 lowerCast(InstCast::create(Func, CastKind, Src1R, Src1RT));
3157 } else {
3158 Src0R = Src0RT;
3159 Src1R = Src1RT;
3160 }
Sagar Thakur5cce7612016-05-24 06:25:50 -07003161 }
Sagar Thakur93097562016-09-29 06:52:29 -07003162 auto *DestT = makeReg(IceType_i32);
3163
Sagar Thakur5cce7612016-05-24 06:25:50 -07003164 switch (CompareInst->getCondition()) {
3165 default:
Sagar Thakur93097562016-09-29 06:52:29 -07003166 llvm_unreachable("unexpected condition");
3167 return;
Sagar Thakur5cce7612016-05-24 06:25:50 -07003168 case InstIcmp::Eq: {
Sagar Thakur93097562016-09-29 06:52:29 -07003169 if (Src0Ty == IceType_i64) {
3170 auto *T1 = I32Reg();
3171 auto *T2 = I32Reg();
3172 auto *T3 = I32Reg();
3173 _xor(T1, Src0HiR, Src1HiR);
3174 _xor(T2, Src0R, Src1R);
3175 _or(T3, T1, T2);
3176 _mov(DestT, T3);
3177 _br(TargetTrue, TargetFalse, DestT, CondMIPS32::Cond::NEZ);
3178 } else {
3179 _br(TargetTrue, TargetFalse, Src0R, Src1R, CondMIPS32::Cond::NE);
3180 }
3181 return;
Sagar Thakur5cce7612016-05-24 06:25:50 -07003182 }
3183 case InstIcmp::Ne: {
Sagar Thakur93097562016-09-29 06:52:29 -07003184 if (Src0Ty == IceType_i64) {
3185 auto *T1 = I32Reg();
3186 auto *T2 = I32Reg();
3187 auto *T3 = I32Reg();
3188 _xor(T1, Src0HiR, Src1HiR);
3189 _xor(T2, Src0R, Src1R);
3190 _or(T3, T1, T2);
3191 _mov(DestT, T3);
3192 _br(TargetTrue, TargetFalse, DestT, CondMIPS32::Cond::EQZ);
3193 } else {
3194 _br(TargetTrue, TargetFalse, Src0R, Src1R, CondMIPS32::Cond::EQ);
3195 }
3196 return;
Sagar Thakur5cce7612016-05-24 06:25:50 -07003197 }
3198 case InstIcmp::Ugt: {
Sagar Thakur93097562016-09-29 06:52:29 -07003199 if (Src0Ty == IceType_i64) {
3200 auto *T1 = I32Reg();
3201 auto *T2 = I32Reg();
3202 auto *T3 = I32Reg();
3203 auto *T4 = I32Reg();
3204 auto *T5 = I32Reg();
3205 _xor(T1, Src0HiR, Src1HiR);
3206 _sltu(T2, Src1HiR, Src0HiR);
3207 _xori(T3, T2, 1);
3208 _sltu(T4, Src1R, Src0R);
3209 _xori(T5, T4, 1);
3210 _movz(T3, T5, T1);
3211 _mov(DestT, T3);
3212 _br(TargetTrue, TargetFalse, DestT, CondMIPS32::Cond::NEZ);
3213 } else {
3214 _sltu(DestT, Src1R, Src0R);
3215 _br(TargetTrue, TargetFalse, DestT, CondMIPS32::Cond::EQZ);
3216 }
3217 return;
Sagar Thakur5cce7612016-05-24 06:25:50 -07003218 }
3219 case InstIcmp::Uge: {
Sagar Thakur93097562016-09-29 06:52:29 -07003220 if (Src0Ty == IceType_i64) {
3221 auto *T1 = I32Reg();
3222 auto *T2 = I32Reg();
3223 auto *T3 = I32Reg();
3224 _xor(T1, Src0HiR, Src1HiR);
3225 _sltu(T2, Src0HiR, Src1HiR);
3226 _sltu(T3, Src0R, Src1R);
3227 _movz(T2, T3, T1);
3228 _mov(DestT, T2);
3229 _br(TargetTrue, TargetFalse, DestT, CondMIPS32::Cond::NEZ);
3230 } else {
3231 _sltu(DestT, Src0R, Src1R);
3232 _br(TargetTrue, TargetFalse, DestT, CondMIPS32::Cond::NEZ);
3233 }
3234 return;
Sagar Thakur5cce7612016-05-24 06:25:50 -07003235 }
3236 case InstIcmp::Ult: {
Sagar Thakur93097562016-09-29 06:52:29 -07003237 if (Src0Ty == IceType_i64) {
3238 auto *T1 = I32Reg();
3239 auto *T2 = I32Reg();
3240 auto *T3 = I32Reg();
3241 auto *T4 = I32Reg();
3242 auto *T5 = I32Reg();
3243 _xor(T1, Src0HiR, Src1HiR);
3244 _sltu(T2, Src0HiR, Src1HiR);
3245 _xori(T3, T2, 1);
3246 _sltu(T4, Src0R, Src1R);
3247 _xori(T5, T4, 1);
3248 _movz(T3, T5, T1);
3249 _mov(DestT, T3);
3250 _br(TargetTrue, TargetFalse, DestT, CondMIPS32::Cond::NEZ);
3251 } else {
3252 _sltu(DestT, Src0R, Src1R);
3253 _br(TargetTrue, TargetFalse, DestT, CondMIPS32::Cond::EQZ);
3254 }
3255 return;
Sagar Thakur5cce7612016-05-24 06:25:50 -07003256 }
3257 case InstIcmp::Ule: {
Sagar Thakur93097562016-09-29 06:52:29 -07003258 if (Src0Ty == IceType_i64) {
3259 auto *T1 = I32Reg();
3260 auto *T2 = I32Reg();
3261 auto *T3 = I32Reg();
3262 _xor(T1, Src0HiR, Src1HiR);
3263 _sltu(T2, Src1HiR, Src0HiR);
3264 _sltu(T3, Src1R, Src0R);
3265 _movz(T2, T3, T1);
3266 _mov(DestT, T2);
3267 _br(TargetTrue, TargetFalse, DestT, CondMIPS32::Cond::NEZ);
3268 } else {
3269 _sltu(DestT, Src1R, Src0R);
3270 _br(TargetTrue, TargetFalse, DestT, CondMIPS32::Cond::NEZ);
3271 }
3272 return;
Sagar Thakur5cce7612016-05-24 06:25:50 -07003273 }
3274 case InstIcmp::Sgt: {
Sagar Thakur93097562016-09-29 06:52:29 -07003275 if (Src0Ty == IceType_i64) {
3276 auto *T1 = I32Reg();
3277 auto *T2 = I32Reg();
3278 auto *T3 = I32Reg();
3279 auto *T4 = I32Reg();
3280 auto *T5 = I32Reg();
3281 _xor(T1, Src0HiR, Src1HiR);
3282 _slt(T2, Src1HiR, Src0HiR);
3283 _xori(T3, T2, 1);
3284 _sltu(T4, Src1R, Src0R);
3285 _xori(T5, T4, 1);
3286 _movz(T3, T5, T1);
3287 _mov(DestT, T3);
3288 _br(TargetTrue, TargetFalse, DestT, CondMIPS32::Cond::NEZ);
3289 } else {
3290 _slt(DestT, Src1R, Src0R);
3291 _br(TargetTrue, TargetFalse, DestT, CondMIPS32::Cond::EQZ);
3292 }
3293 return;
Sagar Thakur5cce7612016-05-24 06:25:50 -07003294 }
3295 case InstIcmp::Sge: {
Sagar Thakur93097562016-09-29 06:52:29 -07003296 if (Src0Ty == IceType_i64) {
3297 auto *T1 = I32Reg();
3298 auto *T2 = I32Reg();
3299 auto *T3 = I32Reg();
3300 _xor(T1, Src0HiR, Src1HiR);
3301 _slt(T2, Src0HiR, Src1HiR);
3302 _sltu(T3, Src0R, Src1R);
3303 _movz(T2, T3, T1);
3304 _mov(DestT, T2);
3305 _br(TargetTrue, TargetFalse, DestT, CondMIPS32::Cond::NEZ);
3306 } else {
3307 _slt(DestT, Src0R, Src1R);
3308 _br(TargetTrue, TargetFalse, DestT, CondMIPS32::Cond::NEZ);
3309 }
3310 return;
Sagar Thakur5cce7612016-05-24 06:25:50 -07003311 }
3312 case InstIcmp::Slt: {
Sagar Thakur93097562016-09-29 06:52:29 -07003313 if (Src0Ty == IceType_i64) {
3314 auto *T1 = I32Reg();
3315 auto *T2 = I32Reg();
3316 auto *T3 = I32Reg();
3317 auto *T4 = I32Reg();
3318 auto *T5 = I32Reg();
3319 _xor(T1, Src0HiR, Src1HiR);
3320 _slt(T2, Src0HiR, Src1HiR);
3321 _xori(T3, T2, 1);
3322 _sltu(T4, Src0R, Src1R);
3323 _xori(T5, T4, 1);
3324 _movz(T3, T5, T1);
3325 _mov(DestT, T3);
3326 _br(TargetTrue, TargetFalse, DestT, CondMIPS32::Cond::NEZ);
3327 } else {
3328 _slt(DestT, Src0R, Src1R);
3329 _br(TargetTrue, TargetFalse, DestT, CondMIPS32::Cond::EQZ);
3330 }
3331 return;
Sagar Thakur5cce7612016-05-24 06:25:50 -07003332 }
3333 case InstIcmp::Sle: {
Sagar Thakur93097562016-09-29 06:52:29 -07003334 if (Src0Ty == IceType_i64) {
3335 auto *T1 = I32Reg();
3336 auto *T2 = I32Reg();
3337 auto *T3 = I32Reg();
3338 _xor(T1, Src0HiR, Src1HiR);
3339 _slt(T2, Src1HiR, Src0HiR);
3340 _sltu(T3, Src1R, Src0R);
3341 _movz(T2, T3, T1);
3342 _mov(DestT, T2);
3343 _br(TargetTrue, TargetFalse, DestT, CondMIPS32::Cond::NEZ);
3344 } else {
3345 _slt(DestT, Src1R, Src0R);
3346 _br(TargetTrue, TargetFalse, DestT, CondMIPS32::Cond::NEZ);
3347 }
3348 return;
Sagar Thakur5cce7612016-05-24 06:25:50 -07003349 }
3350 }
3351 }
Jim Stichnoth6da4cef2015-06-11 13:26:33 -07003352}
3353
Reed Kotler00e36042016-02-01 20:52:19 -08003354void TargetMIPS32::lowerCall(const InstCall *Instr) {
Jaydeep Patil958ddb72016-10-03 07:52:48 -07003355 CfgVector<Variable *> RegArgs;
Mohit Bhakkad9b4c3c32016-06-22 05:44:05 -07003356 NeedsStackAlignment = true;
3357
3358 // Assign arguments to registers and stack. Also reserve stack.
3359 TargetMIPS32::CallingConv CC;
3360
3361 // Pair of Arg Operand -> GPR number assignments.
3362 llvm::SmallVector<std::pair<Operand *, RegNumT>, MIPS32_MAX_GPR_ARG> GPRArgs;
3363 llvm::SmallVector<std::pair<Operand *, RegNumT>, MIPS32_MAX_FP_ARG> FPArgs;
3364 // Pair of Arg Operand -> stack offset.
3365 llvm::SmallVector<std::pair<Operand *, int32_t>, 8> StackArgs;
3366 size_t ParameterAreaSizeBytes = 16;
3367
3368 // Classify each argument operand according to the location where the
3369 // argument is passed.
3370
Jaydeep Patil958ddb72016-10-03 07:52:48 -07003371 // v4f32 is returned through stack. $4 is setup by the caller and passed as
3372 // first argument implicitly. Callee then copies the return vector at $4.
3373 SizeT ArgNum = 0;
3374 Variable *Dest = Instr->getDest();
3375 Variable *RetVecFloat = nullptr;
3376 if (Dest && isVectorFloatingType(Dest->getType())) {
3377 ArgNum = 1;
3378 CC.discardReg(RegMIPS32::Reg_A0);
3379 RetVecFloat = Func->makeVariable(IceType_i32);
3380 auto *ByteCount = ConstantInteger32::create(Ctx, IceType_i32, 16);
3381 constexpr SizeT Alignment = 4;
3382 lowerAlloca(InstAlloca::create(Func, RetVecFloat, ByteCount, Alignment));
3383 RegArgs.emplace_back(
3384 legalizeToReg(RetVecFloat, RegNumT::fixme(RegMIPS32::Reg_A0)));
3385 }
3386
Mohit Bhakkad9b4c3c32016-06-22 05:44:05 -07003387 for (SizeT i = 0, NumArgs = Instr->getNumArgs(); i < NumArgs; ++i) {
3388 Operand *Arg = legalizeUndef(Instr->getArg(i));
3389 const Type Ty = Arg->getType();
3390 bool InReg = false;
3391 RegNumT Reg;
3392
3393 InReg = CC.argInReg(Ty, i, &Reg);
3394
3395 if (!InReg) {
Jaydeep Patil958ddb72016-10-03 07:52:48 -07003396 if (isVectorType(Ty)) {
3397 auto *ArgVec = llvm::cast<VariableVecOn32>(Arg);
Jaydeep Patil2bbda7f2017-01-10 21:48:58 -08003398 ParameterAreaSizeBytes =
3399 applyStackAlignmentTy(ParameterAreaSizeBytes, IceType_i64);
Jaydeep Patil958ddb72016-10-03 07:52:48 -07003400 for (Variable *Elem : ArgVec->getContainers()) {
Jaydeep Patil958ddb72016-10-03 07:52:48 -07003401 StackArgs.push_back(std::make_pair(Elem, ParameterAreaSizeBytes));
3402 ParameterAreaSizeBytes += typeWidthInBytesOnStack(IceType_i32);
3403 }
3404 } else {
3405 ParameterAreaSizeBytes =
3406 applyStackAlignmentTy(ParameterAreaSizeBytes, Ty);
3407 StackArgs.push_back(std::make_pair(Arg, ParameterAreaSizeBytes));
3408 ParameterAreaSizeBytes += typeWidthInBytesOnStack(Ty);
3409 }
3410 ++ArgNum;
Mohit Bhakkad9b4c3c32016-06-22 05:44:05 -07003411 continue;
3412 }
3413
Jaydeep Patil958ddb72016-10-03 07:52:48 -07003414 if (isVectorType(Ty)) {
3415 auto *ArgVec = llvm::cast<VariableVecOn32>(Arg);
3416 Operand *Elem0 = ArgVec->getContainers()[0];
3417 Operand *Elem1 = ArgVec->getContainers()[1];
3418 GPRArgs.push_back(
3419 std::make_pair(Elem0, RegNumT::fixme((unsigned)Reg + 0)));
3420 GPRArgs.push_back(
3421 std::make_pair(Elem1, RegNumT::fixme((unsigned)Reg + 1)));
3422 Operand *Elem2 = ArgVec->getContainers()[2];
3423 Operand *Elem3 = ArgVec->getContainers()[3];
3424 // First argument is passed in $4:$5:$6:$7
3425 // Second and rest arguments are passed in $6:$7:stack:stack
3426 if (ArgNum == 0) {
3427 GPRArgs.push_back(
3428 std::make_pair(Elem2, RegNumT::fixme((unsigned)Reg + 2)));
3429 GPRArgs.push_back(
3430 std::make_pair(Elem3, RegNumT::fixme((unsigned)Reg + 3)));
3431 } else {
3432 ParameterAreaSizeBytes =
Jaydeep Patil2bbda7f2017-01-10 21:48:58 -08003433 applyStackAlignmentTy(ParameterAreaSizeBytes, IceType_i64);
Jaydeep Patil958ddb72016-10-03 07:52:48 -07003434 StackArgs.push_back(std::make_pair(Elem2, ParameterAreaSizeBytes));
3435 ParameterAreaSizeBytes += typeWidthInBytesOnStack(IceType_i32);
Jaydeep Patil958ddb72016-10-03 07:52:48 -07003436 StackArgs.push_back(std::make_pair(Elem3, ParameterAreaSizeBytes));
3437 ParameterAreaSizeBytes += typeWidthInBytesOnStack(IceType_i32);
3438 }
3439 } else if (Ty == IceType_i64) {
Mohit Bhakkad9b4c3c32016-06-22 05:44:05 -07003440 Operand *Lo = loOperand(Arg);
3441 Operand *Hi = hiOperand(Arg);
3442 GPRArgs.push_back(
Mohit Bhakkadeec56212016-08-02 05:55:11 -07003443 std::make_pair(Lo, RegMIPS32::get64PairFirstRegNum(Reg)));
Mohit Bhakkad9b4c3c32016-06-22 05:44:05 -07003444 GPRArgs.push_back(
Mohit Bhakkadeec56212016-08-02 05:55:11 -07003445 std::make_pair(Hi, RegMIPS32::get64PairSecondRegNum(Reg)));
Mohit Bhakkad9b4c3c32016-06-22 05:44:05 -07003446 } else if (isScalarIntegerType(Ty)) {
3447 GPRArgs.push_back(std::make_pair(Arg, Reg));
3448 } else {
3449 FPArgs.push_back(std::make_pair(Arg, Reg));
3450 }
Jaydeep Patil958ddb72016-10-03 07:52:48 -07003451 ++ArgNum;
Reed Kotler00e36042016-02-01 20:52:19 -08003452 }
Mohit Bhakkad9b4c3c32016-06-22 05:44:05 -07003453
3454 // Adjust the parameter area so that the stack is aligned. It is assumed that
3455 // the stack is already aligned at the start of the calling sequence.
3456 ParameterAreaSizeBytes = applyStackAlignment(ParameterAreaSizeBytes);
3457
3458 // Copy arguments that are passed on the stack to the appropriate stack
3459 // locations.
3460 Variable *SP = getPhysicalRegister(RegMIPS32::Reg_SP);
3461 for (auto &StackArg : StackArgs) {
3462 ConstantInteger32 *Loc =
3463 llvm::cast<ConstantInteger32>(Ctx->getConstantInt32(StackArg.second));
3464 Type Ty = StackArg.first->getType();
3465 OperandMIPS32Mem *Addr;
3466 constexpr bool SignExt = false;
3467 if (OperandMIPS32Mem::canHoldOffset(Ty, SignExt, StackArg.second)) {
3468 Addr = OperandMIPS32Mem::create(Func, Ty, SP, Loc);
3469 } else {
3470 Variable *NewBase = Func->makeVariable(SP->getType());
3471 lowerArithmetic(
3472 InstArithmetic::create(Func, InstArithmetic::Add, NewBase, SP, Loc));
3473 Addr = formMemoryOperand(NewBase, Ty);
3474 }
3475 lowerStore(InstStore::create(Func, StackArg.first, Addr));
3476 }
3477
Reed Kotler00e36042016-02-01 20:52:19 -08003478 // Generate the call instruction. Assign its result to a temporary with high
3479 // register allocation weight.
Jaydeep Patil958ddb72016-10-03 07:52:48 -07003480
Reed Kotler00e36042016-02-01 20:52:19 -08003481 // ReturnReg doubles as ReturnRegLo as necessary.
3482 Variable *ReturnReg = nullptr;
3483 Variable *ReturnRegHi = nullptr;
3484 if (Dest) {
3485 switch (Dest->getType()) {
3486 case IceType_NUM:
3487 llvm_unreachable("Invalid Call dest type");
3488 return;
3489 case IceType_void:
3490 break;
3491 case IceType_i1:
3492 case IceType_i8:
3493 case IceType_i16:
3494 case IceType_i32:
3495 ReturnReg = makeReg(Dest->getType(), RegMIPS32::Reg_V0);
3496 break;
3497 case IceType_i64:
Reed Kotler953568f2016-02-17 05:37:01 -08003498 ReturnReg = I32Reg(RegMIPS32::Reg_V0);
3499 ReturnRegHi = I32Reg(RegMIPS32::Reg_V1);
Reed Kotler00e36042016-02-01 20:52:19 -08003500 break;
3501 case IceType_f32:
Mohit Bhakkad135fbe52016-08-12 23:33:14 -07003502 ReturnReg = makeReg(Dest->getType(), RegMIPS32::Reg_F0);
3503 break;
Reed Kotler00e36042016-02-01 20:52:19 -08003504 case IceType_f64:
Srdjan Obucinab85cde12016-09-09 09:39:52 -07003505 ReturnReg = makeReg(IceType_f64, RegMIPS32::Reg_F0);
Mohit Bhakkad135fbe52016-08-12 23:33:14 -07003506 break;
Reed Kotler00e36042016-02-01 20:52:19 -08003507 case IceType_v4i1:
3508 case IceType_v8i1:
3509 case IceType_v16i1:
3510 case IceType_v16i8:
3511 case IceType_v8i16:
Jaydeep Patil958ddb72016-10-03 07:52:48 -07003512 case IceType_v4i32: {
3513 ReturnReg = makeReg(Dest->getType(), RegMIPS32::Reg_V0);
3514 auto *RetVec = llvm::dyn_cast<VariableVecOn32>(ReturnReg);
3515 RetVec->initVecElement(Func);
Jaydeep Patil3a01f332016-10-17 06:33:50 -07003516 for (SizeT i = 0; i < RetVec->ContainersPerVector; ++i) {
Jaydeep Patil958ddb72016-10-03 07:52:48 -07003517 auto *Var = RetVec->getContainers()[i];
3518 Var->setRegNum(RegNumT::fixme(RegMIPS32::Reg_V0 + i));
3519 }
3520 break;
3521 }
Reed Kotler00e36042016-02-01 20:52:19 -08003522 case IceType_v4f32:
Jaydeep Patil958ddb72016-10-03 07:52:48 -07003523 ReturnReg = makeReg(IceType_i32, RegMIPS32::Reg_V0);
3524 break;
Reed Kotler00e36042016-02-01 20:52:19 -08003525 }
3526 }
3527 Operand *CallTarget = Instr->getCallTarget();
3528 // Allow ConstantRelocatable to be left alone as a direct call,
3529 // but force other constants like ConstantInteger32 to be in
3530 // a register and make it an indirect call.
3531 if (!llvm::isa<ConstantRelocatable>(CallTarget)) {
3532 CallTarget = legalize(CallTarget, Legal_Reg);
3533 }
Mohit Bhakkad9b4c3c32016-06-22 05:44:05 -07003534
3535 // Copy arguments to be passed in registers to the appropriate registers.
Mohit Bhakkad9b4c3c32016-06-22 05:44:05 -07003536 for (auto &FPArg : FPArgs) {
3537 RegArgs.emplace_back(legalizeToReg(FPArg.first, FPArg.second));
3538 }
3539 for (auto &GPRArg : GPRArgs) {
3540 RegArgs.emplace_back(legalizeToReg(GPRArg.first, GPRArg.second));
3541 }
3542
3543 // Generate a FakeUse of register arguments so that they do not get dead code
3544 // eliminated as a result of the FakeKill of scratch registers after the call.
3545 // These fake-uses need to be placed here to avoid argument registers from
3546 // being used during the legalizeToReg() calls above.
3547 for (auto *RegArg : RegArgs) {
3548 Context.insert<InstFakeUse>(RegArg);
3549 }
3550
Sagar Thakurc930d592016-07-12 04:06:44 -07003551 // If variable alloca is used the extra 16 bytes for argument build area
3552 // will be allocated on stack before a call.
3553 if (VariableAllocaUsed)
Stefan Maksimovic6e033432016-11-09 17:31:51 -08003554 Sandboxer(this).addiu_sp(-MaxOutArgsSizeBytes);
Sagar Thakurc930d592016-07-12 04:06:44 -07003555
Jaydeep Patil958ddb72016-10-03 07:52:48 -07003556 Inst *NewCall;
3557
3558 // We don't need to define the return register if it is a vector.
3559 // We have inserted fake defs of it just after the call.
3560 if (ReturnReg && isVectorIntegerType(ReturnReg->getType())) {
3561 Variable *RetReg = nullptr;
3562 NewCall = InstMIPS32Call::create(Func, RetReg, CallTarget);
Stefan Maksimovic6e033432016-11-09 17:31:51 -08003563 Context.insert(NewCall);
Jaydeep Patil958ddb72016-10-03 07:52:48 -07003564 } else {
Stefan Maksimovic6e033432016-11-09 17:31:51 -08003565 NewCall = Sandboxer(this, InstBundleLock::Opt_AlignToEnd)
3566 .jal(ReturnReg, CallTarget);
Jaydeep Patil958ddb72016-10-03 07:52:48 -07003567 }
Sagar Thakurc930d592016-07-12 04:06:44 -07003568
3569 if (VariableAllocaUsed)
Stefan Maksimovic6e033432016-11-09 17:31:51 -08003570 Sandboxer(this).addiu_sp(MaxOutArgsSizeBytes);
Sagar Thakurc930d592016-07-12 04:06:44 -07003571
3572 // Insert a fake use of stack pointer to avoid dead code elimination of addiu
3573 // instruction.
3574 Context.insert<InstFakeUse>(SP);
3575
Reed Kotler00e36042016-02-01 20:52:19 -08003576 if (ReturnRegHi)
3577 Context.insert(InstFakeDef::create(Func, ReturnRegHi));
Jaydeep Patil958ddb72016-10-03 07:52:48 -07003578
3579 if (ReturnReg) {
3580 if (auto *RetVec = llvm::dyn_cast<VariableVecOn32>(ReturnReg)) {
3581 for (Variable *Var : RetVec->getContainers()) {
3582 Context.insert(InstFakeDef::create(Func, Var));
3583 }
3584 }
3585 }
3586
Reed Kotler00e36042016-02-01 20:52:19 -08003587 // Insert a register-kill pseudo instruction.
3588 Context.insert(InstFakeKill::create(Func, NewCall));
Jaydeep Patil958ddb72016-10-03 07:52:48 -07003589
Reed Kotler00e36042016-02-01 20:52:19 -08003590 // Generate a FakeUse to keep the call live if necessary.
3591 if (Instr->hasSideEffects() && ReturnReg) {
Jaydeep Patil958ddb72016-10-03 07:52:48 -07003592 if (auto *RetVec = llvm::dyn_cast<VariableVecOn32>(ReturnReg)) {
3593 for (Variable *Var : RetVec->getContainers()) {
3594 Context.insert<InstFakeUse>(Var);
3595 }
3596 } else {
3597 Context.insert<InstFakeUse>(ReturnReg);
3598 }
Reed Kotler00e36042016-02-01 20:52:19 -08003599 }
Jaydeep Patil958ddb72016-10-03 07:52:48 -07003600
Reed Kotler00e36042016-02-01 20:52:19 -08003601 if (Dest == nullptr)
3602 return;
3603
3604 // Assign the result of the call to Dest.
3605 if (ReturnReg) {
Jaydeep Patil958ddb72016-10-03 07:52:48 -07003606 if (RetVecFloat) {
3607 auto *DestVecOn32 = llvm::cast<VariableVecOn32>(Dest);
Jaydeep Patil0c4c07d2016-11-01 23:53:52 -07003608 auto *TBase = legalizeToReg(RetVecFloat);
Jaydeep Patil3a01f332016-10-17 06:33:50 -07003609 for (SizeT i = 0; i < DestVecOn32->ContainersPerVector; ++i) {
Jaydeep Patil958ddb72016-10-03 07:52:48 -07003610 auto *Var = DestVecOn32->getContainers()[i];
Jaydeep Patil0c4c07d2016-11-01 23:53:52 -07003611 auto *TVar = makeReg(IceType_i32);
Jaydeep Patil958ddb72016-10-03 07:52:48 -07003612 OperandMIPS32Mem *Mem = OperandMIPS32Mem::create(
Jaydeep Patil0c4c07d2016-11-01 23:53:52 -07003613 Func, IceType_i32, TBase,
Jaydeep Patil958ddb72016-10-03 07:52:48 -07003614 llvm::cast<ConstantInteger32>(Ctx->getConstantInt32(i * 4)));
Jaydeep Patil0c4c07d2016-11-01 23:53:52 -07003615 _lw(TVar, Mem);
3616 _mov(Var, TVar);
Jaydeep Patil958ddb72016-10-03 07:52:48 -07003617 }
3618 } else if (auto *RetVec = llvm::dyn_cast<VariableVecOn32>(ReturnReg)) {
3619 auto *DestVecOn32 = llvm::cast<VariableVecOn32>(Dest);
Jaydeep Patil3a01f332016-10-17 06:33:50 -07003620 for (SizeT i = 0; i < DestVecOn32->ContainersPerVector; ++i) {
Jaydeep Patil958ddb72016-10-03 07:52:48 -07003621 _mov(DestVecOn32->getContainers()[i], RetVec->getContainers()[i]);
3622 }
3623 } else if (ReturnRegHi) {
Reed Kotler00e36042016-02-01 20:52:19 -08003624 assert(Dest->getType() == IceType_i64);
3625 auto *Dest64On32 = llvm::cast<Variable64On32>(Dest);
3626 Variable *DestLo = Dest64On32->getLo();
3627 Variable *DestHi = Dest64On32->getHi();
3628 _mov(DestLo, ReturnReg);
3629 _mov(DestHi, ReturnRegHi);
3630 } else {
3631 assert(Dest->getType() == IceType_i32 || Dest->getType() == IceType_i16 ||
3632 Dest->getType() == IceType_i8 || Dest->getType() == IceType_i1 ||
Srdjan Obucinab85cde12016-09-09 09:39:52 -07003633 isScalarFloatingType(Dest->getType()) ||
Reed Kotler00e36042016-02-01 20:52:19 -08003634 isVectorType(Dest->getType()));
Jaydeep Patil958ddb72016-10-03 07:52:48 -07003635 _mov(Dest, ReturnReg);
Reed Kotler00e36042016-02-01 20:52:19 -08003636 }
3637 }
Jim Stichnoth6da4cef2015-06-11 13:26:33 -07003638}
3639
Reed Kotler04bca5a2016-02-03 14:40:47 -08003640void TargetMIPS32::lowerCast(const InstCast *Instr) {
3641 InstCast::OpKind CastKind = Instr->getCastKind();
Sagar Thakur38dcb592016-05-09 11:57:59 -07003642 Variable *Dest = Instr->getDest();
3643 Operand *Src0 = legalizeUndef(Instr->getSrc(0));
3644 const Type DestTy = Dest->getType();
3645 const Type Src0Ty = Src0->getType();
3646 const uint32_t ShiftAmount =
Sagar Thakure160ed92016-05-30 07:54:47 -07003647 (Src0Ty == IceType_i1
3648 ? INT32_BITS - 1
3649 : INT32_BITS - (CHAR_BITS * typeWidthInBytes(Src0Ty)));
3650 const uint32_t Mask =
3651 (Src0Ty == IceType_i1
3652 ? 1
3653 : (1 << (CHAR_BITS * typeWidthInBytes(Src0Ty))) - 1);
Sagar Thakur38dcb592016-05-09 11:57:59 -07003654
Sagar Thakure160ed92016-05-30 07:54:47 -07003655 if (isVectorType(DestTy)) {
Jaydeep Patil3a01f332016-10-17 06:33:50 -07003656 llvm::report_fatal_error("Cast: Destination type is vector");
Sagar Thakur38dcb592016-05-09 11:57:59 -07003657 return;
3658 }
Jim Stichnoth6da4cef2015-06-11 13:26:33 -07003659 switch (CastKind) {
3660 default:
3661 Func->setError("Cast type not supported");
3662 return;
3663 case InstCast::Sext: {
Sagar Thakur38dcb592016-05-09 11:57:59 -07003664 if (DestTy == IceType_i64) {
3665 auto *DestLo = llvm::cast<Variable>(loOperand(Dest));
3666 auto *DestHi = llvm::cast<Variable>(hiOperand(Dest));
3667 Variable *Src0R = legalizeToReg(Src0);
Sagar Thakure160ed92016-05-30 07:54:47 -07003668 Variable *T1_Lo = I32Reg();
3669 Variable *T2_Lo = I32Reg();
3670 Variable *T_Hi = I32Reg();
3671 if (Src0Ty == IceType_i1) {
3672 _sll(T1_Lo, Src0R, INT32_BITS - 1);
3673 _sra(T2_Lo, T1_Lo, INT32_BITS - 1);
3674 _mov(DestHi, T2_Lo);
3675 _mov(DestLo, T2_Lo);
Sagar Thakur38dcb592016-05-09 11:57:59 -07003676 } else if (Src0Ty == IceType_i8 || Src0Ty == IceType_i16) {
Sagar Thakure160ed92016-05-30 07:54:47 -07003677 _sll(T1_Lo, Src0R, ShiftAmount);
3678 _sra(T2_Lo, T1_Lo, ShiftAmount);
3679 _sra(T_Hi, T2_Lo, INT32_BITS - 1);
3680 _mov(DestHi, T_Hi);
3681 _mov(DestLo, T2_Lo);
3682 } else if (Src0Ty == IceType_i32) {
3683 _mov(T1_Lo, Src0R);
3684 _sra(T_Hi, T1_Lo, INT32_BITS - 1);
3685 _mov(DestHi, T_Hi);
3686 _mov(DestLo, T1_Lo);
Sagar Thakur38dcb592016-05-09 11:57:59 -07003687 }
Sagar Thakur38dcb592016-05-09 11:57:59 -07003688 } else {
3689 Variable *Src0R = legalizeToReg(Src0);
Sagar Thakure160ed92016-05-30 07:54:47 -07003690 Variable *T1 = makeReg(DestTy);
3691 Variable *T2 = makeReg(DestTy);
3692 if (Src0Ty == IceType_i1 || Src0Ty == IceType_i8 ||
3693 Src0Ty == IceType_i16) {
3694 _sll(T1, Src0R, ShiftAmount);
3695 _sra(T2, T1, ShiftAmount);
3696 _mov(Dest, T2);
Sagar Thakur38dcb592016-05-09 11:57:59 -07003697 }
3698 }
Jim Stichnoth6da4cef2015-06-11 13:26:33 -07003699 break;
3700 }
3701 case InstCast::Zext: {
Sagar Thakur38dcb592016-05-09 11:57:59 -07003702 if (DestTy == IceType_i64) {
3703 auto *DestLo = llvm::cast<Variable>(loOperand(Dest));
3704 auto *DestHi = llvm::cast<Variable>(hiOperand(Dest));
3705 Variable *Src0R = legalizeToReg(Src0);
Sagar Thakure160ed92016-05-30 07:54:47 -07003706 Variable *T_Lo = I32Reg();
3707 Variable *T_Hi = I32Reg();
Sagar Thakur38dcb592016-05-09 11:57:59 -07003708
Sagar Thakure160ed92016-05-30 07:54:47 -07003709 if (Src0Ty == IceType_i1 || Src0Ty == IceType_i8 || Src0Ty == IceType_i16)
3710 _andi(T_Lo, Src0R, Mask);
3711 else if (Src0Ty == IceType_i32)
3712 _mov(T_Lo, Src0R);
3713 else
3714 assert(Src0Ty != IceType_i64);
3715 _mov(DestLo, T_Lo);
Sagar Thakur38dcb592016-05-09 11:57:59 -07003716
3717 auto *Zero = getZero();
Sagar Thakure160ed92016-05-30 07:54:47 -07003718 _addiu(T_Hi, Zero, 0);
3719 _mov(DestHi, T_Hi);
Sagar Thakur38dcb592016-05-09 11:57:59 -07003720 } else {
3721 Variable *Src0R = legalizeToReg(Src0);
3722 Variable *T = makeReg(DestTy);
Sagar Thakure160ed92016-05-30 07:54:47 -07003723 if (Src0Ty == IceType_i1 || Src0Ty == IceType_i8 ||
3724 Src0Ty == IceType_i16) {
Sagar Thakur38dcb592016-05-09 11:57:59 -07003725 _andi(T, Src0R, Mask);
Sagar Thakure160ed92016-05-30 07:54:47 -07003726 _mov(Dest, T);
3727 }
Sagar Thakur38dcb592016-05-09 11:57:59 -07003728 }
Jim Stichnoth6da4cef2015-06-11 13:26:33 -07003729 break;
3730 }
3731 case InstCast::Trunc: {
Sagar Thakur38dcb592016-05-09 11:57:59 -07003732 if (Src0Ty == IceType_i64)
3733 Src0 = loOperand(Src0);
3734 Variable *Src0R = legalizeToReg(Src0);
3735 Variable *T = makeReg(DestTy);
Jaydeep Patil2bbda7f2017-01-10 21:48:58 -08003736 switch (DestTy) {
3737 case IceType_i1:
3738 _andi(T, Src0R, 0x1);
3739 break;
3740 case IceType_i8:
3741 _andi(T, Src0R, 0xff);
3742 break;
3743 case IceType_i16:
3744 _andi(T, Src0R, 0xffff);
3745 break;
3746 default:
3747 _mov(T, Src0R);
3748 break;
3749 }
Sagar Thakur38dcb592016-05-09 11:57:59 -07003750 _mov(Dest, T);
Jim Stichnoth6da4cef2015-06-11 13:26:33 -07003751 break;
3752 }
Srdjan Obucina5a9f7142016-09-11 07:08:30 -07003753 case InstCast::Fptrunc: {
3754 assert(Dest->getType() == IceType_f32);
3755 assert(Src0->getType() == IceType_f64);
3756 auto *DestR = legalizeToReg(Dest);
3757 auto *Src0R = legalizeToReg(Src0);
3758 _cvt_s_d(DestR, Src0R);
3759 _mov(Dest, DestR);
Jim Stichnoth6da4cef2015-06-11 13:26:33 -07003760 break;
3761 }
Srdjan Obucina5a9f7142016-09-11 07:08:30 -07003762 case InstCast::Fpext: {
3763 assert(Dest->getType() == IceType_f64);
3764 assert(Src0->getType() == IceType_f32);
3765 auto *DestR = legalizeToReg(Dest);
3766 auto *Src0R = legalizeToReg(Src0);
3767 _cvt_d_s(DestR, Src0R);
3768 _mov(Dest, DestR);
3769 break;
3770 }
Srdjan Obucina4c49b102016-09-26 20:12:17 -07003771 case InstCast::Fptosi:
3772 case InstCast::Fptoui: {
Srdjan Obucinaf5d8e092016-09-22 07:05:05 -07003773 if (llvm::isa<Variable64On32>(Dest)) {
3774 llvm::report_fatal_error("fp-to-i64 should have been prelowered.");
3775 return;
3776 }
Srdjan Obucina4c49b102016-09-26 20:12:17 -07003777 if (DestTy != IceType_i64) {
3778 if (Src0Ty == IceType_f32 && isScalarIntegerType(DestTy)) {
3779 Variable *Src0R = legalizeToReg(Src0);
3780 Variable *FTmp = makeReg(IceType_f32);
3781 _trunc_w_s(FTmp, Src0R);
3782 _mov(Dest, FTmp);
3783 return;
3784 }
3785 if (Src0Ty == IceType_f64 && isScalarIntegerType(DestTy)) {
3786 Variable *Src0R = legalizeToReg(Src0);
3787 Variable *FTmp = makeReg(IceType_f64);
3788 _trunc_w_d(FTmp, Src0R);
3789 _mov(Dest, FTmp);
3790 return;
3791 }
Srdjan Obucinaf5d8e092016-09-22 07:05:05 -07003792 }
Sagar Thakurbecb85f2016-11-18 12:15:46 -08003793 llvm::report_fatal_error("Destination is i64 in fp-to-i32");
Jim Stichnoth6da4cef2015-06-11 13:26:33 -07003794 break;
Jaydeep Patild3297662016-09-13 22:52:27 -07003795 }
Srdjan Obucina4c49b102016-09-26 20:12:17 -07003796 case InstCast::Sitofp:
Jim Stichnoth6da4cef2015-06-11 13:26:33 -07003797 case InstCast::Uitofp: {
Srdjan Obucinaf5d8e092016-09-22 07:05:05 -07003798 if (llvm::isa<Variable64On32>(Dest)) {
3799 llvm::report_fatal_error("i64-to-fp should have been prelowered.");
3800 return;
3801 }
Srdjan Obucina4c49b102016-09-26 20:12:17 -07003802 if (Src0Ty != IceType_i64) {
Jaydeep Patila7979bf2016-10-26 06:16:19 -07003803 Variable *Src0R = legalizeToReg(Src0);
3804 auto *T0R = Src0R;
Jaydeep Patil2bbda7f2017-01-10 21:48:58 -08003805 if (Src0Ty != IceType_i32) {
Jaydeep Patila7979bf2016-10-26 06:16:19 -07003806 T0R = makeReg(IceType_i32);
Jaydeep Patil2bbda7f2017-01-10 21:48:58 -08003807 if (CastKind == InstCast::Uitofp)
3808 lowerCast(InstCast::create(Func, InstCast::Zext, T0R, Src0R));
3809 else
3810 lowerCast(InstCast::create(Func, InstCast::Sext, T0R, Src0R));
Jaydeep Patila7979bf2016-10-26 06:16:19 -07003811 }
Srdjan Obucina4c49b102016-09-26 20:12:17 -07003812 if (isScalarIntegerType(Src0Ty) && DestTy == IceType_f32) {
Srdjan Obucina4c49b102016-09-26 20:12:17 -07003813 Variable *FTmp1 = makeReg(IceType_f32);
3814 Variable *FTmp2 = makeReg(IceType_f32);
Jaydeep Patila7979bf2016-10-26 06:16:19 -07003815 _mtc1(FTmp1, T0R);
Srdjan Obucina4c49b102016-09-26 20:12:17 -07003816 _cvt_s_w(FTmp2, FTmp1);
3817 _mov(Dest, FTmp2);
3818 return;
3819 }
3820 if (isScalarIntegerType(Src0Ty) && DestTy == IceType_f64) {
Srdjan Obucina4c49b102016-09-26 20:12:17 -07003821 Variable *FTmp1 = makeReg(IceType_f64);
3822 Variable *FTmp2 = makeReg(IceType_f64);
Jaydeep Patila7979bf2016-10-26 06:16:19 -07003823 _mtc1(FTmp1, T0R);
Srdjan Obucina4c49b102016-09-26 20:12:17 -07003824 _cvt_d_w(FTmp2, FTmp1);
3825 _mov(Dest, FTmp2);
3826 return;
3827 }
3828 }
Sagar Thakurbecb85f2016-11-18 12:15:46 -08003829 llvm::report_fatal_error("Source is i64 in i32-to-fp");
Jim Stichnoth6da4cef2015-06-11 13:26:33 -07003830 break;
3831 }
3832 case InstCast::Bitcast: {
Srdjan Obucina4c49b102016-09-26 20:12:17 -07003833 Operand *Src0 = Instr->getSrc(0);
3834 if (DestTy == Src0->getType()) {
3835 auto *Assign = InstAssign::create(Func, Dest, Src0);
3836 lowerAssign(Assign);
3837 return;
3838 }
Jaydeep Patil3a01f332016-10-17 06:33:50 -07003839 if (isVectorType(DestTy) || isVectorType(Src0->getType())) {
3840 llvm::report_fatal_error(
3841 "Bitcast: vector type should have been prelowered.");
3842 return;
3843 }
Srdjan Obucinaf5d8e092016-09-22 07:05:05 -07003844 switch (DestTy) {
3845 case IceType_NUM:
3846 case IceType_void:
3847 llvm::report_fatal_error("Unexpected bitcast.");
3848 case IceType_i1:
3849 UnimplementedLoweringError(this, Instr);
3850 break;
3851 case IceType_i8:
3852 assert(Src0->getType() == IceType_v8i1);
3853 llvm::report_fatal_error(
3854 "i8 to v8i1 conversion should have been prelowered.");
3855 break;
3856 case IceType_i16:
3857 assert(Src0->getType() == IceType_v16i1);
3858 llvm::report_fatal_error(
3859 "i16 to v16i1 conversion should have been prelowered.");
3860 break;
Sagar Thakurb001cc42016-10-11 23:36:01 -07003861 case IceType_i32:
3862 case IceType_f32: {
3863 Variable *Src0R = legalizeToReg(Src0);
3864 _mov(Dest, Src0R);
3865 break;
3866 }
3867 case IceType_i64: {
3868 assert(Src0->getType() == IceType_f64);
3869 Variable *Src0R = legalizeToReg(Src0);
Jaydeep Patila7979bf2016-10-26 06:16:19 -07003870 auto *T = llvm::cast<Variable64On32>(Func->makeVariable(IceType_i64));
3871 T->initHiLo(Func);
Jaydeep Patil2bbda7f2017-01-10 21:48:58 -08003872 T->getHi()->setMustNotHaveReg();
3873 T->getLo()->setMustNotHaveReg();
3874 Context.insert<InstFakeDef>(T->getHi());
3875 Context.insert<InstFakeDef>(T->getLo());
3876 _mov_fp64_to_i64(T->getHi(), Src0R, Int64_Hi);
3877 _mov_fp64_to_i64(T->getLo(), Src0R, Int64_Lo);
Jaydeep Patila7979bf2016-10-26 06:16:19 -07003878 lowerAssign(InstAssign::create(Func, Dest, T));
Sagar Thakurb001cc42016-10-11 23:36:01 -07003879 break;
3880 }
3881 case IceType_f64: {
3882 assert(Src0->getType() == IceType_i64);
3883 const uint32_t Mask = 0xFFFFFFFF;
3884 if (auto *C64 = llvm::dyn_cast<ConstantInteger64>(Src0)) {
3885 Variable *RegHi, *RegLo;
3886 const uint64_t Value = C64->getValue();
3887 uint64_t Upper32Bits = (Value >> INT32_BITS) & Mask;
3888 uint64_t Lower32Bits = Value & Mask;
3889 RegLo = legalizeToReg(Ctx->getConstantInt32(Lower32Bits));
3890 RegHi = legalizeToReg(Ctx->getConstantInt32(Upper32Bits));
3891 _mov(Dest, RegHi, RegLo);
3892 } else {
3893 auto *Var64On32 = llvm::cast<Variable64On32>(Src0);
3894 auto *RegLo = legalizeToReg(loOperand(Var64On32));
3895 auto *RegHi = legalizeToReg(hiOperand(Var64On32));
3896 _mov(Dest, RegHi, RegLo);
3897 }
3898 break;
3899 }
Srdjan Obucinaf5d8e092016-09-22 07:05:05 -07003900 default:
Sagar Thakurbecb85f2016-11-18 12:15:46 -08003901 llvm::report_fatal_error("Unexpected bitcast.");
Srdjan Obucinaf5d8e092016-09-22 07:05:05 -07003902 }
Jim Stichnoth6da4cef2015-06-11 13:26:33 -07003903 break;
3904 }
3905 }
3906}
3907
Reed Kotler04bca5a2016-02-03 14:40:47 -08003908void TargetMIPS32::lowerExtractElement(const InstExtractElement *Instr) {
Jaydeep Patil958ddb72016-10-03 07:52:48 -07003909 Variable *Dest = Instr->getDest();
3910 const Type DestTy = Dest->getType();
3911 Operand *Src1 = Instr->getSrc(1);
3912 if (const auto *Imm = llvm::dyn_cast<ConstantInteger32>(Src1)) {
3913 const uint32_t Index = Imm->getValue();
3914 Variable *TDest = makeReg(DestTy);
3915 Variable *TReg = makeReg(DestTy);
3916 auto *Src0 = legalizeUndef(Instr->getSrc(0));
3917 auto *Src0R = llvm::dyn_cast<VariableVecOn32>(Src0);
3918 // Number of elements in each container
3919 uint32_t ElemPerCont =
Jaydeep Patil3a01f332016-10-17 06:33:50 -07003920 typeNumElements(Src0->getType()) / Src0R->ContainersPerVector;
Jaydeep Patil0c4c07d2016-11-01 23:53:52 -07003921 auto *Src = Src0R->getContainers()[Index / ElemPerCont];
3922 auto *SrcE = legalizeToReg(Src);
Jaydeep Patil958ddb72016-10-03 07:52:48 -07003923 // Position of the element in the container
3924 uint32_t PosInCont = Index % ElemPerCont;
3925 if (ElemPerCont == 1) {
3926 _mov(TDest, SrcE);
3927 } else if (ElemPerCont == 2) {
3928 switch (PosInCont) {
3929 case 0:
3930 _andi(TDest, SrcE, 0xffff);
3931 break;
3932 case 1:
3933 _srl(TDest, SrcE, 16);
3934 break;
3935 default:
3936 llvm::report_fatal_error("ExtractElement: Invalid PosInCont");
3937 break;
3938 }
3939 } else if (ElemPerCont == 4) {
3940 switch (PosInCont) {
3941 case 0:
3942 _andi(TDest, SrcE, 0xff);
3943 break;
3944 case 1:
3945 _srl(TReg, SrcE, 8);
3946 _andi(TDest, TReg, 0xff);
3947 break;
3948 case 2:
3949 _srl(TReg, SrcE, 16);
3950 _andi(TDest, TReg, 0xff);
3951 break;
3952 case 3:
3953 _srl(TDest, SrcE, 24);
3954 break;
3955 default:
3956 llvm::report_fatal_error("ExtractElement: Invalid PosInCont");
3957 break;
3958 }
3959 }
3960 if (typeElementType(Src0R->getType()) == IceType_i1) {
Jaydeep Patil3a01f332016-10-17 06:33:50 -07003961 Variable *TReg1 = makeReg(DestTy);
3962 _andi(TReg1, TDest, 0x1);
3963 _mov(Dest, TReg1);
Jaydeep Patil958ddb72016-10-03 07:52:48 -07003964 } else {
3965 _mov(Dest, TDest);
3966 }
3967 return;
3968 }
3969 llvm::report_fatal_error("ExtractElement requires a constant index");
Jim Stichnoth6da4cef2015-06-11 13:26:33 -07003970}
3971
Reed Kotler04bca5a2016-02-03 14:40:47 -08003972void TargetMIPS32::lowerFcmp(const InstFcmp *Instr) {
Srdjan Obucinaf315f0d2016-09-13 05:46:30 -07003973 Variable *Dest = Instr->getDest();
3974 if (isVectorType(Dest->getType())) {
Jaydeep Patil3a01f332016-10-17 06:33:50 -07003975 llvm::report_fatal_error("Fcmp: Destination type is vector");
Srdjan Obucinaf315f0d2016-09-13 05:46:30 -07003976 return;
3977 }
3978
3979 auto *Src0 = Instr->getSrc(0);
3980 auto *Src1 = Instr->getSrc(1);
3981 auto *Zero = getZero();
3982
3983 InstFcmp::FCond Cond = Instr->getCondition();
Jaydeep Patil3a01f332016-10-17 06:33:50 -07003984 auto *DestR = makeReg(IceType_i32);
Srdjan Obucinaf315f0d2016-09-13 05:46:30 -07003985 auto *Src0R = legalizeToReg(Src0);
3986 auto *Src1R = legalizeToReg(Src1);
3987 const Type Src0Ty = Src0->getType();
3988
3989 Operand *FCC0 = OperandMIPS32FCC::create(getFunc(), OperandMIPS32FCC::FCC0);
3990
3991 switch (Cond) {
3992 default: {
Sagar Thakurbecb85f2016-11-18 12:15:46 -08003993 llvm::report_fatal_error("Unhandled fp comparison.");
Srdjan Obucinaf315f0d2016-09-13 05:46:30 -07003994 return;
3995 }
3996 case InstFcmp::False: {
3997 Context.insert<InstFakeUse>(Src0R);
3998 Context.insert<InstFakeUse>(Src1R);
3999 _addiu(DestR, Zero, 0);
4000 _mov(Dest, DestR);
4001 break;
4002 }
4003 case InstFcmp::Oeq: {
4004 if (Src0Ty == IceType_f32) {
4005 _c_eq_s(Src0R, Src1R);
4006 } else {
4007 _c_eq_d(Src0R, Src1R);
4008 }
Jaydeep Patild8954472016-09-21 06:24:41 -07004009 _addiu(DestR, Zero, 1);
Srdjan Obucinaf315f0d2016-09-13 05:46:30 -07004010 _movf(DestR, Zero, FCC0);
4011 _mov(Dest, DestR);
4012 break;
4013 }
4014 case InstFcmp::Ogt: {
4015 if (Src0Ty == IceType_f32) {
4016 _c_ule_s(Src0R, Src1R);
4017 } else {
4018 _c_ule_d(Src0R, Src1R);
4019 }
Jaydeep Patild8954472016-09-21 06:24:41 -07004020 _addiu(DestR, Zero, 1);
Srdjan Obucinaf315f0d2016-09-13 05:46:30 -07004021 _movt(DestR, Zero, FCC0);
4022 _mov(Dest, DestR);
4023 break;
4024 }
4025 case InstFcmp::Oge: {
4026 if (Src0Ty == IceType_f32) {
4027 _c_ult_s(Src0R, Src1R);
4028 } else {
4029 _c_ult_d(Src0R, Src1R);
4030 }
Jaydeep Patild8954472016-09-21 06:24:41 -07004031 _addiu(DestR, Zero, 1);
Srdjan Obucinaf315f0d2016-09-13 05:46:30 -07004032 _movt(DestR, Zero, FCC0);
4033 _mov(Dest, DestR);
4034 break;
4035 }
4036 case InstFcmp::Olt: {
4037 if (Src0Ty == IceType_f32) {
4038 _c_olt_s(Src0R, Src1R);
4039 } else {
4040 _c_olt_d(Src0R, Src1R);
4041 }
Jaydeep Patild8954472016-09-21 06:24:41 -07004042 _addiu(DestR, Zero, 1);
Srdjan Obucinaf315f0d2016-09-13 05:46:30 -07004043 _movf(DestR, Zero, FCC0);
4044 _mov(Dest, DestR);
4045 break;
4046 }
4047 case InstFcmp::Ole: {
4048 if (Src0Ty == IceType_f32) {
4049 _c_ole_s(Src0R, Src1R);
4050 } else {
4051 _c_ole_d(Src0R, Src1R);
4052 }
Jaydeep Patild8954472016-09-21 06:24:41 -07004053 _addiu(DestR, Zero, 1);
Srdjan Obucinaf315f0d2016-09-13 05:46:30 -07004054 _movf(DestR, Zero, FCC0);
4055 _mov(Dest, DestR);
4056 break;
4057 }
4058 case InstFcmp::One: {
4059 if (Src0Ty == IceType_f32) {
4060 _c_ueq_s(Src0R, Src1R);
4061 } else {
4062 _c_ueq_d(Src0R, Src1R);
4063 }
Jaydeep Patild8954472016-09-21 06:24:41 -07004064 _addiu(DestR, Zero, 1);
Srdjan Obucinaf315f0d2016-09-13 05:46:30 -07004065 _movt(DestR, Zero, FCC0);
4066 _mov(Dest, DestR);
4067 break;
4068 }
4069 case InstFcmp::Ord: {
4070 if (Src0Ty == IceType_f32) {
4071 _c_un_s(Src0R, Src1R);
4072 } else {
4073 _c_un_d(Src0R, Src1R);
4074 }
Jaydeep Patild8954472016-09-21 06:24:41 -07004075 _addiu(DestR, Zero, 1);
Srdjan Obucinaf315f0d2016-09-13 05:46:30 -07004076 _movt(DestR, Zero, FCC0);
4077 _mov(Dest, DestR);
4078 break;
4079 }
4080 case InstFcmp::Ueq: {
4081 if (Src0Ty == IceType_f32) {
4082 _c_ueq_s(Src0R, Src1R);
4083 } else {
4084 _c_ueq_d(Src0R, Src1R);
4085 }
Jaydeep Patild8954472016-09-21 06:24:41 -07004086 _addiu(DestR, Zero, 1);
Srdjan Obucinaf315f0d2016-09-13 05:46:30 -07004087 _movf(DestR, Zero, FCC0);
4088 _mov(Dest, DestR);
4089 break;
4090 }
4091 case InstFcmp::Ugt: {
4092 if (Src0Ty == IceType_f32) {
4093 _c_ole_s(Src0R, Src1R);
4094 } else {
4095 _c_ole_d(Src0R, Src1R);
4096 }
Jaydeep Patild8954472016-09-21 06:24:41 -07004097 _addiu(DestR, Zero, 1);
Srdjan Obucinaf315f0d2016-09-13 05:46:30 -07004098 _movt(DestR, Zero, FCC0);
4099 _mov(Dest, DestR);
4100 break;
4101 }
4102 case InstFcmp::Uge: {
4103 if (Src0Ty == IceType_f32) {
4104 _c_olt_s(Src0R, Src1R);
4105 } else {
4106 _c_olt_d(Src0R, Src1R);
4107 }
Jaydeep Patild8954472016-09-21 06:24:41 -07004108 _addiu(DestR, Zero, 1);
Srdjan Obucinaf315f0d2016-09-13 05:46:30 -07004109 _movt(DestR, Zero, FCC0);
4110 _mov(Dest, DestR);
4111 break;
4112 }
4113 case InstFcmp::Ult: {
4114 if (Src0Ty == IceType_f32) {
4115 _c_ult_s(Src0R, Src1R);
4116 } else {
4117 _c_ult_d(Src0R, Src1R);
4118 }
Jaydeep Patild8954472016-09-21 06:24:41 -07004119 _addiu(DestR, Zero, 1);
Srdjan Obucinaf315f0d2016-09-13 05:46:30 -07004120 _movf(DestR, Zero, FCC0);
4121 _mov(Dest, DestR);
4122 break;
4123 }
4124 case InstFcmp::Ule: {
4125 if (Src0Ty == IceType_f32) {
4126 _c_ule_s(Src0R, Src1R);
4127 } else {
4128 _c_ule_d(Src0R, Src1R);
4129 }
Jaydeep Patild8954472016-09-21 06:24:41 -07004130 _addiu(DestR, Zero, 1);
Srdjan Obucinaf315f0d2016-09-13 05:46:30 -07004131 _movf(DestR, Zero, FCC0);
4132 _mov(Dest, DestR);
4133 break;
4134 }
4135 case InstFcmp::Une: {
4136 if (Src0Ty == IceType_f32) {
4137 _c_eq_s(Src0R, Src1R);
4138 } else {
4139 _c_eq_d(Src0R, Src1R);
4140 }
Jaydeep Patild8954472016-09-21 06:24:41 -07004141 _addiu(DestR, Zero, 1);
Srdjan Obucinaf315f0d2016-09-13 05:46:30 -07004142 _movt(DestR, Zero, FCC0);
4143 _mov(Dest, DestR);
4144 break;
4145 }
4146 case InstFcmp::Uno: {
4147 if (Src0Ty == IceType_f32) {
4148 _c_un_s(Src0R, Src1R);
4149 } else {
4150 _c_un_d(Src0R, Src1R);
4151 }
Jaydeep Patild8954472016-09-21 06:24:41 -07004152 _addiu(DestR, Zero, 1);
Srdjan Obucinaf315f0d2016-09-13 05:46:30 -07004153 _movf(DestR, Zero, FCC0);
4154 _mov(Dest, DestR);
4155 break;
4156 }
4157 case InstFcmp::True: {
4158 Context.insert<InstFakeUse>(Src0R);
4159 Context.insert<InstFakeUse>(Src1R);
4160 _addiu(DestR, Zero, 1);
4161 _mov(Dest, DestR);
4162 break;
4163 }
4164 }
Jim Stichnoth6da4cef2015-06-11 13:26:33 -07004165}
4166
Sagar Thakur1a478b12016-04-25 08:39:19 -07004167void TargetMIPS32::lower64Icmp(const InstIcmp *Instr) {
Sagar Thakur70b6ed42016-09-28 06:36:47 -07004168 Operand *Src0 = legalize(Instr->getSrc(0));
4169 Operand *Src1 = legalize(Instr->getSrc(1));
4170 Variable *Dest = Instr->getDest();
4171 InstIcmp::ICond Condition = Instr->getCondition();
4172
4173 Variable *Src0LoR = legalizeToReg(loOperand(Src0));
4174 Variable *Src0HiR = legalizeToReg(hiOperand(Src0));
4175 Variable *Src1LoR = legalizeToReg(loOperand(Src1));
4176 Variable *Src1HiR = legalizeToReg(hiOperand(Src1));
4177
4178 switch (Condition) {
4179 default:
4180 llvm_unreachable("unexpected condition");
Sagar Thakur93097562016-09-29 06:52:29 -07004181 return;
Sagar Thakur70b6ed42016-09-28 06:36:47 -07004182 case InstIcmp::Eq: {
4183 auto *T1 = I32Reg();
4184 auto *T2 = I32Reg();
4185 auto *T3 = I32Reg();
4186 auto *T4 = I32Reg();
4187 _xor(T1, Src0HiR, Src1HiR);
4188 _xor(T2, Src0LoR, Src1LoR);
4189 _or(T3, T1, T2);
4190 _sltiu(T4, T3, 1);
4191 _mov(Dest, T4);
4192 return;
4193 }
4194 case InstIcmp::Ne: {
4195 auto *T1 = I32Reg();
4196 auto *T2 = I32Reg();
4197 auto *T3 = I32Reg();
4198 auto *T4 = I32Reg();
4199 _xor(T1, Src0HiR, Src1HiR);
4200 _xor(T2, Src0LoR, Src1LoR);
4201 _or(T3, T1, T2);
4202 _sltu(T4, getZero(), T3);
4203 _mov(Dest, T4);
4204 return;
4205 }
4206 case InstIcmp::Sgt: {
4207 auto *T1 = I32Reg();
4208 auto *T2 = I32Reg();
4209 auto *T3 = I32Reg();
4210 _xor(T1, Src0HiR, Src1HiR);
4211 _slt(T2, Src1HiR, Src0HiR);
4212 _sltu(T3, Src1LoR, Src0LoR);
4213 _movz(T2, T3, T1);
4214 _mov(Dest, T2);
4215 return;
4216 }
4217 case InstIcmp::Ugt: {
4218 auto *T1 = I32Reg();
4219 auto *T2 = I32Reg();
4220 auto *T3 = I32Reg();
4221 _xor(T1, Src0HiR, Src1HiR);
4222 _sltu(T2, Src1HiR, Src0HiR);
4223 _sltu(T3, Src1LoR, Src0LoR);
4224 _movz(T2, T3, T1);
4225 _mov(Dest, T2);
4226 return;
4227 }
4228 case InstIcmp::Sge: {
4229 auto *T1 = I32Reg();
4230 auto *T2 = I32Reg();
4231 auto *T3 = I32Reg();
4232 auto *T4 = I32Reg();
4233 auto *T5 = I32Reg();
4234 _xor(T1, Src0HiR, Src1HiR);
4235 _slt(T2, Src0HiR, Src1HiR);
4236 _xori(T3, T2, 1);
4237 _sltu(T4, Src0LoR, Src1LoR);
4238 _xori(T5, T4, 1);
4239 _movz(T3, T5, T1);
4240 _mov(Dest, T3);
4241 return;
4242 }
4243 case InstIcmp::Uge: {
4244 auto *T1 = I32Reg();
4245 auto *T2 = I32Reg();
4246 auto *T3 = I32Reg();
4247 auto *T4 = I32Reg();
4248 auto *T5 = I32Reg();
4249 _xor(T1, Src0HiR, Src1HiR);
4250 _sltu(T2, Src0HiR, Src1HiR);
4251 _xori(T3, T2, 1);
4252 _sltu(T4, Src0LoR, Src1LoR);
4253 _xori(T5, T4, 1);
4254 _movz(T3, T5, T1);
4255 _mov(Dest, T3);
4256 return;
4257 }
4258 case InstIcmp::Slt: {
4259 auto *T1 = I32Reg();
4260 auto *T2 = I32Reg();
4261 auto *T3 = I32Reg();
4262 _xor(T1, Src0HiR, Src1HiR);
4263 _slt(T2, Src0HiR, Src1HiR);
4264 _sltu(T3, Src0LoR, Src1LoR);
4265 _movz(T2, T3, T1);
4266 _mov(Dest, T2);
4267 return;
4268 }
4269 case InstIcmp::Ult: {
4270 auto *T1 = I32Reg();
4271 auto *T2 = I32Reg();
4272 auto *T3 = I32Reg();
4273 _xor(T1, Src0HiR, Src1HiR);
4274 _sltu(T2, Src0HiR, Src1HiR);
4275 _sltu(T3, Src0LoR, Src1LoR);
4276 _movz(T2, T3, T1);
4277 _mov(Dest, T2);
4278 return;
4279 }
4280 case InstIcmp::Sle: {
4281 auto *T1 = I32Reg();
4282 auto *T2 = I32Reg();
4283 auto *T3 = I32Reg();
4284 auto *T4 = I32Reg();
4285 auto *T5 = I32Reg();
4286 _xor(T1, Src0HiR, Src1HiR);
4287 _slt(T2, Src1HiR, Src0HiR);
4288 _xori(T3, T2, 1);
4289 _sltu(T4, Src1LoR, Src0LoR);
4290 _xori(T5, T4, 1);
4291 _movz(T3, T5, T1);
4292 _mov(Dest, T3);
4293 return;
4294 }
4295 case InstIcmp::Ule: {
4296 auto *T1 = I32Reg();
4297 auto *T2 = I32Reg();
4298 auto *T3 = I32Reg();
4299 auto *T4 = I32Reg();
4300 auto *T5 = I32Reg();
4301 _xor(T1, Src0HiR, Src1HiR);
4302 _sltu(T2, Src1HiR, Src0HiR);
4303 _xori(T3, T2, 1);
4304 _sltu(T4, Src1LoR, Src0LoR);
4305 _xori(T5, T4, 1);
4306 _movz(T3, T5, T1);
4307 _mov(Dest, T3);
4308 return;
4309 }
4310 }
Sagar Thakur1a478b12016-04-25 08:39:19 -07004311}
4312
4313void TargetMIPS32::lowerIcmp(const InstIcmp *Instr) {
4314 auto *Src0 = Instr->getSrc(0);
4315 auto *Src1 = Instr->getSrc(1);
4316 if (Src0->getType() == IceType_i64) {
4317 lower64Icmp(Instr);
4318 return;
4319 }
4320 Variable *Dest = Instr->getDest();
4321 if (isVectorType(Dest->getType())) {
Jaydeep Patil3a01f332016-10-17 06:33:50 -07004322 llvm::report_fatal_error("Icmp: Destination type is vector");
Sagar Thakur1a478b12016-04-25 08:39:19 -07004323 return;
4324 }
4325 InstIcmp::ICond Cond = Instr->getCondition();
4326 auto *Src0R = legalizeToReg(Src0);
4327 auto *Src1R = legalizeToReg(Src1);
Sagar Thakura393fd42016-06-01 12:36:50 -07004328 const Type Src0Ty = Src0R->getType();
4329 const uint32_t ShAmt = INT32_BITS - getScalarIntBitWidth(Src0->getType());
4330 Variable *Src0RT = I32Reg();
4331 Variable *Src1RT = I32Reg();
4332
4333 if (Src0Ty != IceType_i32) {
4334 _sll(Src0RT, Src0R, ShAmt);
4335 _sll(Src1RT, Src1R, ShAmt);
4336 } else {
4337 _mov(Src0RT, Src0R);
4338 _mov(Src1RT, Src1R);
4339 }
4340
Sagar Thakur1a478b12016-04-25 08:39:19 -07004341 switch (Cond) {
4342 case InstIcmp::Eq: {
4343 auto *DestT = I32Reg();
4344 auto *T = I32Reg();
Sagar Thakura393fd42016-06-01 12:36:50 -07004345 _xor(T, Src0RT, Src1RT);
Sagar Thakur1a478b12016-04-25 08:39:19 -07004346 _sltiu(DestT, T, 1);
4347 _mov(Dest, DestT);
4348 return;
4349 }
4350 case InstIcmp::Ne: {
4351 auto *DestT = I32Reg();
4352 auto *T = I32Reg();
4353 auto *Zero = getZero();
Sagar Thakura393fd42016-06-01 12:36:50 -07004354 _xor(T, Src0RT, Src1RT);
Sagar Thakur1a478b12016-04-25 08:39:19 -07004355 _sltu(DestT, Zero, T);
4356 _mov(Dest, DestT);
4357 return;
4358 }
4359 case InstIcmp::Ugt: {
4360 auto *DestT = I32Reg();
Sagar Thakura393fd42016-06-01 12:36:50 -07004361 _sltu(DestT, Src1RT, Src0RT);
Sagar Thakur1a478b12016-04-25 08:39:19 -07004362 _mov(Dest, DestT);
4363 return;
4364 }
4365 case InstIcmp::Uge: {
4366 auto *DestT = I32Reg();
4367 auto *T = I32Reg();
Sagar Thakura393fd42016-06-01 12:36:50 -07004368 _sltu(T, Src0RT, Src1RT);
Sagar Thakur1a478b12016-04-25 08:39:19 -07004369 _xori(DestT, T, 1);
4370 _mov(Dest, DestT);
4371 return;
4372 }
4373 case InstIcmp::Ult: {
4374 auto *DestT = I32Reg();
Sagar Thakura393fd42016-06-01 12:36:50 -07004375 _sltu(DestT, Src0RT, Src1RT);
Sagar Thakur1a478b12016-04-25 08:39:19 -07004376 _mov(Dest, DestT);
4377 return;
4378 }
4379 case InstIcmp::Ule: {
4380 auto *DestT = I32Reg();
4381 auto *T = I32Reg();
Sagar Thakura393fd42016-06-01 12:36:50 -07004382 _sltu(T, Src1RT, Src0RT);
Sagar Thakur1a478b12016-04-25 08:39:19 -07004383 _xori(DestT, T, 1);
4384 _mov(Dest, DestT);
4385 return;
4386 }
4387 case InstIcmp::Sgt: {
4388 auto *DestT = I32Reg();
Sagar Thakura393fd42016-06-01 12:36:50 -07004389 _slt(DestT, Src1RT, Src0RT);
Sagar Thakur1a478b12016-04-25 08:39:19 -07004390 _mov(Dest, DestT);
4391 return;
4392 }
4393 case InstIcmp::Sge: {
4394 auto *DestT = I32Reg();
4395 auto *T = I32Reg();
Sagar Thakura393fd42016-06-01 12:36:50 -07004396 _slt(T, Src0RT, Src1RT);
Sagar Thakur1a478b12016-04-25 08:39:19 -07004397 _xori(DestT, T, 1);
4398 _mov(Dest, DestT);
4399 return;
4400 }
4401 case InstIcmp::Slt: {
4402 auto *DestT = I32Reg();
Sagar Thakura393fd42016-06-01 12:36:50 -07004403 _slt(DestT, Src0RT, Src1RT);
Sagar Thakur1a478b12016-04-25 08:39:19 -07004404 _mov(Dest, DestT);
4405 return;
4406 }
4407 case InstIcmp::Sle: {
4408 auto *DestT = I32Reg();
4409 auto *T = I32Reg();
Sagar Thakura393fd42016-06-01 12:36:50 -07004410 _slt(T, Src1RT, Src0RT);
Sagar Thakur1a478b12016-04-25 08:39:19 -07004411 _xori(DestT, T, 1);
4412 _mov(Dest, DestT);
4413 return;
4414 }
4415 default:
4416 llvm_unreachable("Invalid ICmp operator");
4417 return;
4418 }
Jim Stichnoth6da4cef2015-06-11 13:26:33 -07004419}
4420
Reed Kotler04bca5a2016-02-03 14:40:47 -08004421void TargetMIPS32::lowerInsertElement(const InstInsertElement *Instr) {
Jaydeep Patil958ddb72016-10-03 07:52:48 -07004422 Variable *Dest = Instr->getDest();
4423 const Type DestTy = Dest->getType();
4424 Operand *Src2 = Instr->getSrc(2);
4425 if (const auto *Imm = llvm::dyn_cast<ConstantInteger32>(Src2)) {
4426 const uint32_t Index = Imm->getValue();
4427 // Vector to insert in
Jaydeep Patil3a01f332016-10-17 06:33:50 -07004428 auto *Src0 = legalizeUndef(Instr->getSrc(0));
Jaydeep Patil958ddb72016-10-03 07:52:48 -07004429 auto *Src0R = llvm::dyn_cast<VariableVecOn32>(Src0);
4430 // Number of elements in each container
4431 uint32_t ElemPerCont =
Jaydeep Patil3a01f332016-10-17 06:33:50 -07004432 typeNumElements(Src0->getType()) / Src0R->ContainersPerVector;
Jaydeep Patil958ddb72016-10-03 07:52:48 -07004433 // Source Element
Jaydeep Patil0c4c07d2016-11-01 23:53:52 -07004434 auto *Src = Src0R->getContainers()[Index / ElemPerCont];
4435 auto *SrcE = Src;
4436 if (ElemPerCont > 1)
4437 SrcE = legalizeToReg(Src);
Jaydeep Patil958ddb72016-10-03 07:52:48 -07004438 // Dest is a vector
4439 auto *VDest = llvm::dyn_cast<VariableVecOn32>(Dest);
4440 VDest->initVecElement(Func);
4441 // Temp vector variable
4442 auto *TDest = makeReg(DestTy);
4443 auto *TVDest = llvm::dyn_cast<VariableVecOn32>(TDest);
4444 TVDest->initVecElement(Func);
4445 // Destination element
4446 auto *DstE = TVDest->getContainers()[Index / ElemPerCont];
4447 // Element to insert
4448 auto *Src1R = legalizeToReg(Instr->getSrc(1));
Jaydeep Patil2bbda7f2017-01-10 21:48:58 -08004449 auto *TReg1 = makeReg(IceType_i32);
4450 auto *TReg2 = makeReg(IceType_i32);
4451 auto *TReg3 = makeReg(IceType_i32);
4452 auto *TReg4 = makeReg(IceType_i32);
4453 auto *TReg5 = makeReg(IceType_i32);
4454 auto *TDReg = makeReg(IceType_i32);
Jaydeep Patil958ddb72016-10-03 07:52:48 -07004455 // Position of the element in the container
4456 uint32_t PosInCont = Index % ElemPerCont;
4457 // Load source vector in a temporary vector
Jaydeep Patil3a01f332016-10-17 06:33:50 -07004458 for (SizeT i = 0; i < TVDest->ContainersPerVector; ++i) {
Jaydeep Patil958ddb72016-10-03 07:52:48 -07004459 auto *DCont = TVDest->getContainers()[i];
4460 // Do not define DstE as we are going to redefine it
4461 if (DCont == DstE)
4462 continue;
4463 auto *SCont = Src0R->getContainers()[i];
4464 auto *TReg = makeReg(IceType_i32);
4465 _mov(TReg, SCont);
4466 _mov(DCont, TReg);
4467 }
4468 // Insert the element
4469 if (ElemPerCont == 1) {
4470 _mov(DstE, Src1R);
4471 } else if (ElemPerCont == 2) {
4472 switch (PosInCont) {
4473 case 0:
4474 _andi(TReg1, Src1R, 0xffff); // Clear upper 16-bits of source
4475 _srl(TReg2, SrcE, 16);
4476 _sll(TReg3, TReg2, 16); // Clear lower 16-bits of element
Jaydeep Patil0c4c07d2016-11-01 23:53:52 -07004477 _or(TDReg, TReg1, TReg3);
4478 _mov(DstE, TDReg);
Jaydeep Patil958ddb72016-10-03 07:52:48 -07004479 break;
4480 case 1:
4481 _sll(TReg1, Src1R, 16); // Clear lower 16-bits of source
4482 _sll(TReg2, SrcE, 16);
4483 _srl(TReg3, TReg2, 16); // Clear upper 16-bits of element
Jaydeep Patil0c4c07d2016-11-01 23:53:52 -07004484 _or(TDReg, TReg1, TReg3);
4485 _mov(DstE, TDReg);
Jaydeep Patil958ddb72016-10-03 07:52:48 -07004486 break;
4487 default:
4488 llvm::report_fatal_error("InsertElement: Invalid PosInCont");
4489 break;
4490 }
4491 } else if (ElemPerCont == 4) {
4492 switch (PosInCont) {
4493 case 0:
4494 _andi(TReg1, Src1R, 0xff); // Clear bits[31:8] of source
4495 _srl(TReg2, SrcE, 8);
4496 _sll(TReg3, TReg2, 8); // Clear bits[7:0] of element
Jaydeep Patil0c4c07d2016-11-01 23:53:52 -07004497 _or(TDReg, TReg1, TReg3);
4498 _mov(DstE, TDReg);
Jaydeep Patil958ddb72016-10-03 07:52:48 -07004499 break;
4500 case 1:
4501 _andi(TReg1, Src1R, 0xff); // Clear bits[31:8] of source
4502 _sll(TReg5, TReg1, 8); // Position in the destination
4503 _lui(TReg2, Ctx->getConstantInt32(0xffff));
4504 _ori(TReg3, TReg2, 0x00ff);
4505 _and(TReg4, SrcE, TReg3); // Clear bits[15:8] of element
Jaydeep Patil0c4c07d2016-11-01 23:53:52 -07004506 _or(TDReg, TReg5, TReg4);
4507 _mov(DstE, TDReg);
Jaydeep Patil958ddb72016-10-03 07:52:48 -07004508 break;
4509 case 2:
4510 _andi(TReg1, Src1R, 0xff); // Clear bits[31:8] of source
4511 _sll(TReg5, TReg1, 16); // Position in the destination
4512 _lui(TReg2, Ctx->getConstantInt32(0xff00));
4513 _ori(TReg3, TReg2, 0xffff);
4514 _and(TReg4, SrcE, TReg3); // Clear bits[15:8] of element
Jaydeep Patil0c4c07d2016-11-01 23:53:52 -07004515 _or(TDReg, TReg5, TReg4);
4516 _mov(DstE, TDReg);
Jaydeep Patil958ddb72016-10-03 07:52:48 -07004517 break;
4518 case 3:
Jaydeep Patil2bbda7f2017-01-10 21:48:58 -08004519 _sll(TReg1, Src1R, 24); // Position in the destination
Jaydeep Patil958ddb72016-10-03 07:52:48 -07004520 _sll(TReg2, SrcE, 8);
4521 _srl(TReg3, TReg2, 8); // Clear bits[31:24] of element
Jaydeep Patil0c4c07d2016-11-01 23:53:52 -07004522 _or(TDReg, TReg1, TReg3);
4523 _mov(DstE, TDReg);
Jaydeep Patil958ddb72016-10-03 07:52:48 -07004524 break;
4525 default:
4526 llvm::report_fatal_error("InsertElement: Invalid PosInCont");
4527 break;
4528 }
4529 }
4530 // Write back temporary vector to the destination
4531 auto *Assign = InstAssign::create(Func, Dest, TDest);
4532 lowerAssign(Assign);
4533 return;
4534 }
4535 llvm::report_fatal_error("InsertElement requires a constant index");
Jim Stichnoth6da4cef2015-06-11 13:26:33 -07004536}
4537
Sagar Thakurbecb85f2016-11-18 12:15:46 -08004538void TargetMIPS32::createArithInst(Intrinsics::AtomicRMWOperation Operation,
4539 Variable *Dest, Variable *Src0,
4540 Variable *Src1) {
4541 switch (Operation) {
4542 default:
4543 llvm::report_fatal_error("Unknown AtomicRMW operation");
4544 case Intrinsics::AtomicExchange:
4545 llvm::report_fatal_error("Can't handle Atomic xchg operation");
4546 case Intrinsics::AtomicAdd:
4547 _addu(Dest, Src0, Src1);
4548 break;
4549 case Intrinsics::AtomicAnd:
4550 _and(Dest, Src0, Src1);
4551 break;
4552 case Intrinsics::AtomicSub:
4553 _subu(Dest, Src0, Src1);
4554 break;
4555 case Intrinsics::AtomicOr:
4556 _or(Dest, Src0, Src1);
4557 break;
4558 case Intrinsics::AtomicXor:
4559 _xor(Dest, Src0, Src1);
4560 break;
4561 }
4562}
4563
Jim Stichnoth6da4cef2015-06-11 13:26:33 -07004564void TargetMIPS32::lowerIntrinsicCall(const InstIntrinsicCall *Instr) {
Srdjan Obucina53d05682016-09-10 08:25:37 -07004565 Variable *Dest = Instr->getDest();
4566 Type DestTy = (Dest == nullptr) ? IceType_void : Dest->getType();
Sagar Thakurbecb85f2016-11-18 12:15:46 -08004567
4568 Intrinsics::IntrinsicID ID = Instr->getIntrinsicInfo().ID;
4569 switch (ID) {
4570 case Intrinsics::AtomicLoad: {
4571 assert(isScalarIntegerType(DestTy));
4572 // We require the memory address to be naturally aligned. Given that is the
4573 // case, then normal loads are atomic.
4574 if (!Intrinsics::isMemoryOrderValid(
4575 ID, getConstantMemoryOrder(Instr->getArg(1)))) {
4576 Func->setError("Unexpected memory ordering for AtomicLoad");
4577 return;
4578 }
4579 if (DestTy == IceType_i64) {
Jaydeep Patil71f6c8d2017-02-10 06:45:40 -08004580 llvm::report_fatal_error("AtomicLoad.i64 should have been prelowered.");
4581 return;
4582 } else if (DestTy == IceType_i32) {
4583 auto *T1 = makeReg(DestTy);
4584 auto *RegAt = getPhysicalRegister(RegMIPS32::Reg_AT);
Sagar Thakurbecb85f2016-11-18 12:15:46 -08004585 auto *Base = legalizeToReg(Instr->getArg(0));
Jaydeep Patil71f6c8d2017-02-10 06:45:40 -08004586 auto *Addr = formMemoryOperand(Base, DestTy);
4587 InstMIPS32Label *Retry = InstMIPS32Label::create(Func, this);
4588 InstMIPS32Label *Exit = InstMIPS32Label::create(Func, this);
4589 constexpr CfgNode *NoTarget = nullptr;
Sagar Thakurbecb85f2016-11-18 12:15:46 -08004590 _sync();
Jaydeep Patil71f6c8d2017-02-10 06:45:40 -08004591 Context.insert(Retry);
4592 Sandboxer(this).ll(T1, Addr);
4593 _br(NoTarget, NoTarget, T1, getZero(), Exit, CondMIPS32::Cond::NE);
4594 _addiu(RegAt, getZero(), 0); // Loaded value is zero here, writeback zero
4595 Sandboxer(this).sc(RegAt, Addr);
4596 _br(NoTarget, NoTarget, RegAt, getZero(), Retry, CondMIPS32::Cond::EQ);
4597 Context.insert(Exit);
4598 _sync();
4599 _mov(Dest, T1);
4600 Context.insert<InstFakeUse>(T1);
Sagar Thakurbecb85f2016-11-18 12:15:46 -08004601 } else {
Jaydeep Patil71f6c8d2017-02-10 06:45:40 -08004602 const uint32_t Mask = (1 << (CHAR_BITS * typeWidthInBytes(DestTy))) - 1;
Stefan Maksimovic298d14e2017-01-11 05:58:27 -08004603 auto *Base = legalizeToReg(Instr->getArg(0));
Jaydeep Patil71f6c8d2017-02-10 06:45:40 -08004604 auto *T1 = makeReg(IceType_i32);
4605 auto *T2 = makeReg(IceType_i32);
4606 auto *T3 = makeReg(IceType_i32);
4607 auto *T4 = makeReg(IceType_i32);
4608 auto *T5 = makeReg(IceType_i32);
4609 auto *T6 = makeReg(IceType_i32);
4610 auto *SrcMask = makeReg(IceType_i32);
4611 auto *Tdest = makeReg(IceType_i32);
4612 auto *RegAt = getPhysicalRegister(RegMIPS32::Reg_AT);
4613 InstMIPS32Label *Retry = InstMIPS32Label::create(Func, this);
4614 InstMIPS32Label *Exit = InstMIPS32Label::create(Func, this);
4615 constexpr CfgNode *NoTarget = nullptr;
Sagar Thakurbecb85f2016-11-18 12:15:46 -08004616 _sync();
Jaydeep Patil71f6c8d2017-02-10 06:45:40 -08004617 _addiu(T1, getZero(), -4); // Address mask 0xFFFFFFFC
4618 _andi(T2, Base, 3); // Last two bits of the address
4619 _and(T3, Base, T1); // Align the address
4620 _sll(T4, T2, 3);
4621 _ori(T5, getZero(), Mask);
4622 _sllv(SrcMask, T5, T4); // Source mask
4623 auto *Addr = formMemoryOperand(T3, IceType_i32);
4624 Context.insert(Retry);
4625 Sandboxer(this).ll(T6, Addr);
4626 _and(Tdest, T6, SrcMask);
4627 _br(NoTarget, NoTarget, T6, getZero(), Exit, CondMIPS32::Cond::NE);
4628 _addiu(RegAt, getZero(), 0); // Loaded value is zero here, writeback zero
4629 Sandboxer(this).sc(RegAt, Addr);
4630 _br(NoTarget, NoTarget, RegAt, getZero(), Retry, CondMIPS32::Cond::EQ);
4631 Context.insert(Exit);
4632 auto *T7 = makeReg(IceType_i32);
4633 auto *T8 = makeReg(IceType_i32);
4634 _srlv(T7, Tdest, T4);
4635 _andi(T8, T7, Mask);
4636 _sync();
4637 _mov(Dest, T8);
4638 Context.insert<InstFakeUse>(T6);
4639 Context.insert<InstFakeUse>(SrcMask);
Sagar Thakurbecb85f2016-11-18 12:15:46 -08004640 }
4641 return;
4642 }
4643 case Intrinsics::AtomicStore: {
4644 // We require the memory address to be naturally aligned. Given that is the
4645 // case, then normal stores are atomic.
4646 if (!Intrinsics::isMemoryOrderValid(
4647 ID, getConstantMemoryOrder(Instr->getArg(2)))) {
4648 Func->setError("Unexpected memory ordering for AtomicStore");
4649 return;
4650 }
4651 auto *Val = Instr->getArg(0);
4652 auto Ty = Val->getType();
4653 if (Ty == IceType_i64) {
Jaydeep Patil71f6c8d2017-02-10 06:45:40 -08004654 llvm::report_fatal_error("AtomicStore.i64 should have been prelowered.");
4655 return;
4656 } else if (Ty == IceType_i32) {
Sagar Thakurbecb85f2016-11-18 12:15:46 -08004657 auto *Val = legalizeToReg(Instr->getArg(0));
Stefan Maksimovic298d14e2017-01-11 05:58:27 -08004658 auto *Base = legalizeToReg(Instr->getArg(1));
Jaydeep Patil71f6c8d2017-02-10 06:45:40 -08004659 auto *Addr = formMemoryOperand(Base, Ty);
4660 InstMIPS32Label *Retry = InstMIPS32Label::create(Func, this);
4661 constexpr CfgNode *NoTarget = nullptr;
4662 auto *T1 = makeReg(IceType_i32);
4663 auto *RegAt = getPhysicalRegister(RegMIPS32::Reg_AT);
4664 _sync();
4665 Context.insert(Retry);
4666 Sandboxer(this).ll(T1, Addr);
4667 _mov(RegAt, Val);
4668 Sandboxer(this).sc(RegAt, Addr);
4669 _br(NoTarget, NoTarget, RegAt, getZero(), Retry, CondMIPS32::Cond::EQ);
4670 Context.insert<InstFakeUse>(T1); // To keep LL alive
4671 _sync();
4672 } else {
4673 auto *Val = legalizeToReg(Instr->getArg(0));
4674 auto *Base = legalizeToReg(Instr->getArg(1));
4675 InstMIPS32Label *Retry = InstMIPS32Label::create(Func, this);
4676 constexpr CfgNode *NoTarget = nullptr;
4677 auto *T1 = makeReg(IceType_i32);
4678 auto *T2 = makeReg(IceType_i32);
4679 auto *T3 = makeReg(IceType_i32);
4680 auto *T4 = makeReg(IceType_i32);
4681 auto *T5 = makeReg(IceType_i32);
4682 auto *T6 = makeReg(IceType_i32);
4683 auto *T7 = makeReg(IceType_i32);
4684 auto *RegAt = getPhysicalRegister(RegMIPS32::Reg_AT);
4685 auto *SrcMask = makeReg(IceType_i32);
4686 auto *DstMask = makeReg(IceType_i32);
4687 const uint32_t Mask = (1 << (CHAR_BITS * typeWidthInBytes(Ty))) - 1;
4688 _sync();
4689 _addiu(T1, getZero(), -4);
4690 _and(T7, Base, T1);
4691 auto *Addr = formMemoryOperand(T7, Ty);
4692 _andi(T2, Base, 3);
4693 _sll(T3, T2, 3);
4694 _ori(T4, getZero(), Mask);
4695 _sllv(T5, T4, T3);
4696 _sllv(T6, Val, T3);
4697 _nor(SrcMask, getZero(), T5);
4698 _and(DstMask, T6, T5);
4699 Context.insert(Retry);
4700 Sandboxer(this).ll(RegAt, Addr);
4701 _and(RegAt, RegAt, SrcMask);
4702 _or(RegAt, RegAt, DstMask);
4703 Sandboxer(this).sc(RegAt, Addr);
4704 _br(NoTarget, NoTarget, RegAt, getZero(), Retry, CondMIPS32::Cond::EQ);
4705 Context.insert<InstFakeUse>(SrcMask);
4706 Context.insert<InstFakeUse>(DstMask);
Sagar Thakurbecb85f2016-11-18 12:15:46 -08004707 _sync();
4708 }
4709 return;
4710 }
Jim Stichnoth6da4cef2015-06-11 13:26:33 -07004711 case Intrinsics::AtomicCmpxchg: {
Sagar Thakurbecb85f2016-11-18 12:15:46 -08004712 assert(isScalarIntegerType(DestTy));
4713 // We require the memory address to be naturally aligned. Given that is the
4714 // case, then normal loads are atomic.
4715 if (!Intrinsics::isMemoryOrderValid(
4716 ID, getConstantMemoryOrder(Instr->getArg(3)),
4717 getConstantMemoryOrder(Instr->getArg(4)))) {
4718 Func->setError("Unexpected memory ordering for AtomicCmpxchg");
4719 return;
4720 }
4721
4722 InstMIPS32Label *Exit = InstMIPS32Label::create(Func, this);
4723 InstMIPS32Label *Retry = InstMIPS32Label::create(Func, this);
4724 constexpr CfgNode *NoTarget = nullptr;
4725 auto *New = Instr->getArg(2);
4726 auto *Expected = Instr->getArg(1);
4727 auto *ActualAddress = Instr->getArg(0);
4728
4729 if (DestTy == IceType_i64) {
Jaydeep Patil71f6c8d2017-02-10 06:45:40 -08004730 llvm::report_fatal_error(
4731 "AtomicCmpxchg.i64 should have been prelowered.");
4732 return;
Sagar Thakurbecb85f2016-11-18 12:15:46 -08004733 } else if (DestTy == IceType_i8 || DestTy == IceType_i16) {
4734 auto *NewR = legalizeToReg(New);
4735 auto *ExpectedR = legalizeToReg(Expected);
4736 auto *ActualAddressR = legalizeToReg(ActualAddress);
4737 const uint32_t ShiftAmount =
4738 (INT32_BITS - CHAR_BITS * typeWidthInBytes(DestTy));
4739 const uint32_t Mask = (1 << (CHAR_BITS * typeWidthInBytes(DestTy))) - 1;
4740 auto *RegAt = getPhysicalRegister(RegMIPS32::Reg_AT);
4741 auto *T1 = I32Reg();
4742 auto *T2 = I32Reg();
4743 auto *T3 = I32Reg();
4744 auto *T4 = I32Reg();
4745 auto *T5 = I32Reg();
4746 auto *T6 = I32Reg();
4747 auto *T7 = I32Reg();
4748 auto *T8 = I32Reg();
4749 auto *T9 = I32Reg();
Sagar Thakurbecb85f2016-11-18 12:15:46 -08004750 _addiu(RegAt, getZero(), -4);
4751 _and(T1, ActualAddressR, RegAt);
Jaydeep Patil71f6c8d2017-02-10 06:45:40 -08004752 auto *Addr = formMemoryOperand(T1, DestTy);
Sagar Thakurbecb85f2016-11-18 12:15:46 -08004753 _andi(RegAt, ActualAddressR, 3);
4754 _sll(T2, RegAt, 3);
4755 _ori(RegAt, getZero(), Mask);
4756 _sllv(T3, RegAt, T2);
4757 _nor(T4, getZero(), T3);
4758 _andi(RegAt, ExpectedR, Mask);
4759 _sllv(T5, RegAt, T2);
4760 _andi(RegAt, NewR, Mask);
4761 _sllv(T6, RegAt, T2);
Jaydeep Patilfc8f6bf2017-01-25 22:53:08 -08004762 _sync();
Sagar Thakurbecb85f2016-11-18 12:15:46 -08004763 Context.insert(Retry);
Jaydeep Patil71f6c8d2017-02-10 06:45:40 -08004764 Sandboxer(this).ll(T7, Addr);
Sagar Thakurbecb85f2016-11-18 12:15:46 -08004765 _and(T8, T7, T3);
4766 _br(NoTarget, NoTarget, T8, T5, Exit, CondMIPS32::Cond::NE);
4767 _and(RegAt, T7, T4);
4768 _or(T9, RegAt, T6);
Jaydeep Patil71f6c8d2017-02-10 06:45:40 -08004769 Sandboxer(this).sc(T9, Addr);
Sagar Thakurbecb85f2016-11-18 12:15:46 -08004770 _br(NoTarget, NoTarget, getZero(), T9, Retry, CondMIPS32::Cond::EQ);
4771 Context.insert<InstFakeUse>(getZero());
4772 Context.insert(Exit);
4773 _srlv(RegAt, T8, T2);
4774 _sll(RegAt, RegAt, ShiftAmount);
4775 _sra(RegAt, RegAt, ShiftAmount);
4776 _mov(Dest, RegAt);
4777 _sync();
Jaydeep Patil71f6c8d2017-02-10 06:45:40 -08004778 Context.insert<InstFakeUse>(T3);
4779 Context.insert<InstFakeUse>(T4);
4780 Context.insert<InstFakeUse>(T5);
4781 Context.insert<InstFakeUse>(T6);
4782 Context.insert<InstFakeUse>(T8);
Sagar Thakurbecb85f2016-11-18 12:15:46 -08004783 Context.insert<InstFakeUse>(ExpectedR);
4784 Context.insert<InstFakeUse>(NewR);
4785 } else {
4786 auto *T1 = I32Reg();
Jaydeep Patilfc8f6bf2017-01-25 22:53:08 -08004787 auto *T2 = I32Reg();
Sagar Thakurbecb85f2016-11-18 12:15:46 -08004788 auto *NewR = legalizeToReg(New);
4789 auto *ExpectedR = legalizeToReg(Expected);
4790 auto *ActualAddressR = legalizeToReg(ActualAddress);
Jaydeep Patilfc8f6bf2017-01-25 22:53:08 -08004791 _sync();
4792 Context.insert(Retry);
Stefan Maksimovic298d14e2017-01-11 05:58:27 -08004793 Sandboxer(this).ll(T1, formMemoryOperand(ActualAddressR, DestTy));
Sagar Thakurbecb85f2016-11-18 12:15:46 -08004794 _br(NoTarget, NoTarget, T1, ExpectedR, Exit, CondMIPS32::Cond::NE);
Jaydeep Patilfc8f6bf2017-01-25 22:53:08 -08004795 _mov(T2, NewR);
4796 Sandboxer(this).sc(T2, formMemoryOperand(ActualAddressR, DestTy));
4797 _br(NoTarget, NoTarget, T2, getZero(), Retry, CondMIPS32::Cond::EQ);
Sagar Thakurbecb85f2016-11-18 12:15:46 -08004798 Context.insert<InstFakeUse>(getZero());
4799 Context.insert(Exit);
4800 _mov(Dest, T1);
4801 _sync();
4802 Context.insert<InstFakeUse>(ExpectedR);
4803 Context.insert<InstFakeUse>(NewR);
4804 }
4805 return;
4806 }
4807 case Intrinsics::AtomicRMW: {
4808 assert(isScalarIntegerType(DestTy));
4809 // We require the memory address to be naturally aligned. Given that is the
4810 // case, then normal loads are atomic.
4811 if (!Intrinsics::isMemoryOrderValid(
4812 ID, getConstantMemoryOrder(Instr->getArg(3)))) {
4813 Func->setError("Unexpected memory ordering for AtomicRMW");
4814 return;
4815 }
4816
4817 constexpr CfgNode *NoTarget = nullptr;
4818 InstMIPS32Label *Retry = InstMIPS32Label::create(Func, this);
4819 auto Operation = static_cast<Intrinsics::AtomicRMWOperation>(
4820 llvm::cast<ConstantInteger32>(Instr->getArg(0))->getValue());
4821 auto *New = Instr->getArg(2);
4822 auto *ActualAddress = Instr->getArg(1);
4823
4824 if (DestTy == IceType_i64) {
Jaydeep Patil71f6c8d2017-02-10 06:45:40 -08004825 llvm::report_fatal_error("AtomicRMW.i64 should have been prelowered.");
4826 return;
Sagar Thakurbecb85f2016-11-18 12:15:46 -08004827 } else if (DestTy == IceType_i8 || DestTy == IceType_i16) {
4828 const uint32_t ShiftAmount =
4829 INT32_BITS - (CHAR_BITS * typeWidthInBytes(DestTy));
4830 const uint32_t Mask = (1 << (CHAR_BITS * typeWidthInBytes(DestTy))) - 1;
4831 auto *NewR = legalizeToReg(New);
4832 auto *ActualAddressR = legalizeToReg(ActualAddress);
4833 auto *RegAt = getPhysicalRegister(RegMIPS32::Reg_AT);
4834 auto *T1 = I32Reg();
4835 auto *T2 = I32Reg();
4836 auto *T3 = I32Reg();
4837 auto *T4 = I32Reg();
4838 auto *T5 = I32Reg();
4839 auto *T6 = I32Reg();
4840 auto *T7 = I32Reg();
4841 _sync();
4842 _addiu(RegAt, getZero(), -4);
4843 _and(T1, ActualAddressR, RegAt);
4844 _andi(RegAt, ActualAddressR, 3);
4845 _sll(T2, RegAt, 3);
4846 _ori(RegAt, getZero(), Mask);
4847 _sllv(T3, RegAt, T2);
4848 _nor(T4, getZero(), T3);
4849 _sllv(T5, NewR, T2);
4850 Context.insert(Retry);
Stefan Maksimovic298d14e2017-01-11 05:58:27 -08004851 Sandboxer(this).ll(T6, formMemoryOperand(T1, DestTy));
Sagar Thakurbecb85f2016-11-18 12:15:46 -08004852 if (Operation != Intrinsics::AtomicExchange) {
4853 createArithInst(Operation, RegAt, T6, T5);
4854 _and(RegAt, RegAt, T3);
4855 }
4856 _and(T7, T6, T4);
4857 if (Operation == Intrinsics::AtomicExchange) {
4858 _or(RegAt, T7, T5);
4859 } else {
4860 _or(RegAt, T7, RegAt);
4861 }
Stefan Maksimovic298d14e2017-01-11 05:58:27 -08004862 Sandboxer(this).sc(RegAt, formMemoryOperand(T1, DestTy));
Sagar Thakurbecb85f2016-11-18 12:15:46 -08004863 _br(NoTarget, NoTarget, RegAt, getZero(), Retry, CondMIPS32::Cond::EQ);
4864 Context.insert<InstFakeUse>(getZero());
4865 _and(RegAt, T6, T3);
4866 _srlv(RegAt, RegAt, T2);
4867 _sll(RegAt, RegAt, ShiftAmount);
4868 _sra(RegAt, RegAt, ShiftAmount);
4869 _mov(Dest, RegAt);
4870 _sync();
4871 Context.insert<InstFakeUse>(NewR);
4872 Context.insert<InstFakeUse>(Dest);
4873 } else {
4874 auto *T1 = I32Reg();
4875 auto *T2 = I32Reg();
4876 auto *NewR = legalizeToReg(New);
4877 auto *ActualAddressR = legalizeToReg(ActualAddress);
4878 _sync();
4879 Context.insert(Retry);
Stefan Maksimovic298d14e2017-01-11 05:58:27 -08004880 Sandboxer(this).ll(T1, formMemoryOperand(ActualAddressR, DestTy));
Sagar Thakurbecb85f2016-11-18 12:15:46 -08004881 if (Operation == Intrinsics::AtomicExchange) {
4882 _mov(T2, NewR);
4883 } else {
4884 createArithInst(Operation, T2, T1, NewR);
4885 }
Stefan Maksimovic298d14e2017-01-11 05:58:27 -08004886 Sandboxer(this).sc(T2, formMemoryOperand(ActualAddressR, DestTy));
Sagar Thakurbecb85f2016-11-18 12:15:46 -08004887 _br(NoTarget, NoTarget, T2, getZero(), Retry, CondMIPS32::Cond::EQ);
4888 Context.insert<InstFakeUse>(getZero());
4889 _mov(Dest, T1);
4890 _sync();
4891 Context.insert<InstFakeUse>(NewR);
4892 Context.insert<InstFakeUse>(Dest);
4893 }
Jim Stichnoth6da4cef2015-06-11 13:26:33 -07004894 return;
4895 }
4896 case Intrinsics::AtomicFence:
Jim Stichnoth6da4cef2015-06-11 13:26:33 -07004897 case Intrinsics::AtomicFenceAll:
Sagar Thakurbecb85f2016-11-18 12:15:46 -08004898 assert(Dest == nullptr);
4899 _sync();
Jim Stichnoth6da4cef2015-06-11 13:26:33 -07004900 return;
4901 case Intrinsics::AtomicIsLockFree: {
Sagar Thakurbecb85f2016-11-18 12:15:46 -08004902 Operand *ByteSize = Instr->getArg(0);
4903 auto *CI = llvm::dyn_cast<ConstantInteger32>(ByteSize);
4904 auto *T = I32Reg();
4905 if (CI == nullptr) {
4906 // The PNaCl ABI requires the byte size to be a compile-time constant.
4907 Func->setError("AtomicIsLockFree byte size should be compile-time const");
4908 return;
4909 }
4910 static constexpr int32_t NotLockFree = 0;
4911 static constexpr int32_t LockFree = 1;
4912 int32_t Result = NotLockFree;
4913 switch (CI->getValue()) {
4914 case 1:
4915 case 2:
4916 case 4:
Sagar Thakurbecb85f2016-11-18 12:15:46 -08004917 Result = LockFree;
4918 break;
4919 }
4920 _addiu(T, getZero(), Result);
4921 _mov(Dest, T);
Jim Stichnoth6da4cef2015-06-11 13:26:33 -07004922 return;
4923 }
4924 case Intrinsics::Bswap: {
Srdjan Obucina175cb132016-09-27 07:00:17 -07004925 auto *Src = Instr->getArg(0);
4926 const Type SrcTy = Src->getType();
4927 assert(SrcTy == IceType_i16 || SrcTy == IceType_i32 ||
4928 SrcTy == IceType_i64);
4929 switch (SrcTy) {
4930 case IceType_i16: {
4931 auto *T1 = I32Reg();
4932 auto *T2 = I32Reg();
4933 auto *T3 = I32Reg();
4934 auto *T4 = I32Reg();
4935 auto *SrcR = legalizeToReg(Src);
4936 _sll(T1, SrcR, 8);
4937 _lui(T2, Ctx->getConstantInt32(255));
4938 _and(T1, T1, T2);
4939 _sll(T3, SrcR, 24);
4940 _or(T1, T3, T1);
4941 _srl(T4, T1, 16);
4942 _mov(Dest, T4);
4943 return;
4944 }
4945 case IceType_i32: {
4946 auto *T1 = I32Reg();
4947 auto *T2 = I32Reg();
4948 auto *T3 = I32Reg();
4949 auto *T4 = I32Reg();
4950 auto *T5 = I32Reg();
4951 auto *SrcR = legalizeToReg(Src);
4952 _srl(T1, SrcR, 24);
4953 _srl(T2, SrcR, 8);
4954 _andi(T2, T2, 0xFF00);
4955 _or(T1, T2, T1);
4956 _sll(T4, SrcR, 8);
4957 _lui(T3, Ctx->getConstantInt32(255));
4958 _and(T4, T4, T3);
4959 _sll(T5, SrcR, 24);
4960 _or(T4, T5, T4);
4961 _or(T4, T4, T1);
4962 _mov(Dest, T4);
4963 return;
4964 }
4965 case IceType_i64: {
4966 auto *T1 = I32Reg();
4967 auto *T2 = I32Reg();
4968 auto *T3 = I32Reg();
4969 auto *T4 = I32Reg();
4970 auto *T5 = I32Reg();
4971 auto *T6 = I32Reg();
4972 auto *T7 = I32Reg();
4973 auto *T8 = I32Reg();
4974 auto *T9 = I32Reg();
4975 auto *T10 = I32Reg();
4976 auto *T11 = I32Reg();
4977 auto *T12 = I32Reg();
4978 auto *T13 = I32Reg();
4979 auto *T14 = I32Reg();
4980 auto *T15 = I32Reg();
4981 auto *T16 = I32Reg();
4982 auto *T17 = I32Reg();
4983 auto *T18 = I32Reg();
4984 auto *DestLo = llvm::cast<Variable>(loOperand(Dest));
4985 auto *DestHi = llvm::cast<Variable>(hiOperand(Dest));
4986 Src = legalizeUndef(Src);
4987 auto *SrcLoR = legalizeToReg(loOperand(Src));
4988 auto *SrcHiR = legalizeToReg(hiOperand(Src));
4989 _sll(T1, SrcHiR, 8);
4990 _srl(T2, SrcHiR, 24);
4991 _srl(T3, SrcHiR, 8);
4992 _andi(T3, T3, 0xFF00);
4993 _lui(T4, Ctx->getConstantInt32(255));
4994 _or(T5, T3, T2);
4995 _and(T6, T1, T4);
4996 _sll(T7, SrcHiR, 24);
4997 _or(T8, T7, T6);
4998 _srl(T9, SrcLoR, 24);
4999 _srl(T10, SrcLoR, 8);
5000 _andi(T11, T10, 0xFF00);
5001 _or(T12, T8, T5);
5002 _or(T13, T11, T9);
5003 _sll(T14, SrcLoR, 8);
5004 _and(T15, T14, T4);
5005 _sll(T16, SrcLoR, 24);
5006 _or(T17, T16, T15);
5007 _or(T18, T17, T13);
5008 _mov(DestLo, T12);
5009 _mov(DestHi, T18);
5010 return;
5011 }
5012 default:
5013 llvm::report_fatal_error("Control flow should never have reached here.");
5014 }
Jim Stichnoth6da4cef2015-06-11 13:26:33 -07005015 return;
5016 }
5017 case Intrinsics::Ctpop: {
Srdjan Obucinaf5d8e092016-09-22 07:05:05 -07005018 llvm::report_fatal_error("Ctpop should have been prelowered.");
Jim Stichnoth6da4cef2015-06-11 13:26:33 -07005019 return;
5020 }
5021 case Intrinsics::Ctlz: {
Srdjan Obucinad27ce3d2016-09-22 12:56:12 -07005022 auto *Src = Instr->getArg(0);
5023 const Type SrcTy = Src->getType();
5024 assert(SrcTy == IceType_i32 || SrcTy == IceType_i64);
5025 switch (SrcTy) {
5026 case IceType_i32: {
5027 auto *T = I32Reg();
5028 auto *SrcR = legalizeToReg(Src);
5029 _clz(T, SrcR);
5030 _mov(Dest, T);
5031 break;
5032 }
5033 case IceType_i64: {
Srdjan Obucina6fd9c0e2016-09-26 20:58:17 -07005034 auto *T1 = I32Reg();
5035 auto *T2 = I32Reg();
5036 auto *T3 = I32Reg();
5037 auto *T4 = I32Reg();
5038 auto *DestLo = llvm::cast<Variable>(loOperand(Dest));
5039 auto *DestHi = llvm::cast<Variable>(hiOperand(Dest));
5040 Variable *SrcHiR = legalizeToReg(hiOperand(Src));
5041 Variable *SrcLoR = legalizeToReg(loOperand(Src));
5042 _clz(T1, SrcHiR);
5043 _clz(T2, SrcLoR);
5044 _addiu(T3, T2, 32);
5045 _movn(T3, T1, SrcHiR);
5046 _addiu(T4, getZero(), 0);
5047 _mov(DestHi, T4);
5048 _mov(DestLo, T3);
Srdjan Obucinad27ce3d2016-09-22 12:56:12 -07005049 break;
5050 }
5051 default:
5052 llvm::report_fatal_error("Control flow should never have reached here.");
5053 }
5054 break;
Jim Stichnoth6da4cef2015-06-11 13:26:33 -07005055 }
5056 case Intrinsics::Cttz: {
Srdjan Obucina0a7f99d2016-09-23 06:59:50 -07005057 auto *Src = Instr->getArg(0);
5058 const Type SrcTy = Src->getType();
5059 assert(SrcTy == IceType_i32 || SrcTy == IceType_i64);
5060 switch (SrcTy) {
5061 case IceType_i32: {
5062 auto *T1 = I32Reg();
5063 auto *T2 = I32Reg();
5064 auto *T3 = I32Reg();
5065 auto *T4 = I32Reg();
5066 auto *T5 = I32Reg();
5067 auto *T6 = I32Reg();
5068 auto *SrcR = legalizeToReg(Src);
5069 _addiu(T1, SrcR, -1);
5070 _not(T2, SrcR);
5071 _and(T3, T2, T1);
5072 _clz(T4, T3);
5073 _addiu(T5, getZero(), 32);
5074 _subu(T6, T5, T4);
5075 _mov(Dest, T6);
5076 break;
5077 }
5078 case IceType_i64: {
Srdjan Obucina6fd9c0e2016-09-26 20:58:17 -07005079 auto *THi1 = I32Reg();
5080 auto *THi2 = I32Reg();
5081 auto *THi3 = I32Reg();
5082 auto *THi4 = I32Reg();
5083 auto *THi5 = I32Reg();
5084 auto *THi6 = I32Reg();
5085 auto *TLo1 = I32Reg();
5086 auto *TLo2 = I32Reg();
5087 auto *TLo3 = I32Reg();
5088 auto *TLo4 = I32Reg();
5089 auto *TLo5 = I32Reg();
5090 auto *TLo6 = I32Reg();
5091 auto *TResHi = I32Reg();
5092 auto *DestLo = llvm::cast<Variable>(loOperand(Dest));
5093 auto *DestHi = llvm::cast<Variable>(hiOperand(Dest));
5094 Variable *SrcHiR = legalizeToReg(hiOperand(Src));
5095 Variable *SrcLoR = legalizeToReg(loOperand(Src));
5096 _addiu(THi1, SrcHiR, -1);
5097 _not(THi2, SrcHiR);
5098 _and(THi3, THi2, THi1);
5099 _clz(THi4, THi3);
5100 _addiu(THi5, getZero(), 64);
5101 _subu(THi6, THi5, THi4);
5102 _addiu(TLo1, SrcLoR, -1);
5103 _not(TLo2, SrcLoR);
5104 _and(TLo3, TLo2, TLo1);
5105 _clz(TLo4, TLo3);
5106 _addiu(TLo5, getZero(), 32);
5107 _subu(TLo6, TLo5, TLo4);
5108 _movn(THi6, TLo6, SrcLoR);
5109 _addiu(TResHi, getZero(), 0);
5110 _mov(DestHi, TResHi);
5111 _mov(DestLo, THi6);
Srdjan Obucina0a7f99d2016-09-23 06:59:50 -07005112 break;
5113 }
5114 default:
5115 llvm::report_fatal_error("Control flow should never have reached here.");
5116 }
Jim Stichnoth6da4cef2015-06-11 13:26:33 -07005117 return;
5118 }
5119 case Intrinsics::Fabs: {
Srdjan Obucina53d05682016-09-10 08:25:37 -07005120 if (isScalarFloatingType(DestTy)) {
5121 Variable *T = makeReg(DestTy);
5122 if (DestTy == IceType_f32) {
5123 _abs_s(T, legalizeToReg(Instr->getArg(0)));
5124 } else {
5125 _abs_d(T, legalizeToReg(Instr->getArg(0)));
5126 }
5127 _mov(Dest, T);
5128 }
Jim Stichnoth6da4cef2015-06-11 13:26:33 -07005129 return;
5130 }
5131 case Intrinsics::Longjmp: {
Srdjan Obucinaf5d8e092016-09-22 07:05:05 -07005132 llvm::report_fatal_error("longjmp should have been prelowered.");
Jim Stichnoth6da4cef2015-06-11 13:26:33 -07005133 return;
5134 }
5135 case Intrinsics::Memcpy: {
Srdjan Obucinaf5d8e092016-09-22 07:05:05 -07005136 llvm::report_fatal_error("memcpy should have been prelowered.");
Jim Stichnoth6da4cef2015-06-11 13:26:33 -07005137 return;
5138 }
5139 case Intrinsics::Memmove: {
Srdjan Obucinaf5d8e092016-09-22 07:05:05 -07005140 llvm::report_fatal_error("memmove should have been prelowered.");
Jim Stichnoth6da4cef2015-06-11 13:26:33 -07005141 return;
5142 }
5143 case Intrinsics::Memset: {
Srdjan Obucinaf5d8e092016-09-22 07:05:05 -07005144 llvm::report_fatal_error("memset should have been prelowered.");
Jim Stichnoth6da4cef2015-06-11 13:26:33 -07005145 return;
5146 }
5147 case Intrinsics::NaClReadTP: {
Stefan Maksimovic298d14e2017-01-11 05:58:27 -08005148 if (SandboxingType != ST_NaCl)
5149 llvm::report_fatal_error("nacl-read-tp should have been prelowered.");
5150 else {
5151 auto *T8 = makeReg(IceType_i32, RegMIPS32::Reg_T8);
5152 Context.insert<InstFakeDef>(T8);
5153 Variable *TP = legalizeToReg(OperandMIPS32Mem::create(
5154 Func, getPointerType(), T8,
5155 llvm::cast<ConstantInteger32>(Ctx->getConstantZero(IceType_i32))));
5156 _mov(Dest, TP);
Jim Stichnoth6da4cef2015-06-11 13:26:33 -07005157 }
5158 return;
5159 }
5160 case Intrinsics::Setjmp: {
Srdjan Obucinaf5d8e092016-09-22 07:05:05 -07005161 llvm::report_fatal_error("setjmp should have been prelowered.");
Jim Stichnoth6da4cef2015-06-11 13:26:33 -07005162 return;
5163 }
5164 case Intrinsics::Sqrt: {
Srdjan Obucina53d05682016-09-10 08:25:37 -07005165 if (isScalarFloatingType(DestTy)) {
5166 Variable *T = makeReg(DestTy);
5167 if (DestTy == IceType_f32) {
5168 _sqrt_s(T, legalizeToReg(Instr->getArg(0)));
5169 } else {
5170 _sqrt_d(T, legalizeToReg(Instr->getArg(0)));
5171 }
5172 _mov(Dest, T);
Nicolas Capens956cfd62016-10-31 14:28:09 -04005173 } else {
5174 assert(getFlags().getApplicationBinaryInterface() != ::Ice::ABI_PNaCl);
5175 UnimplementedLoweringError(this, Instr); // Not required for PNaCl
Srdjan Obucina53d05682016-09-10 08:25:37 -07005176 }
Jim Stichnoth6da4cef2015-06-11 13:26:33 -07005177 return;
5178 }
5179 case Intrinsics::Stacksave: {
Stefan Maksimovicf8c99772016-11-02 05:59:06 -07005180 Variable *SP = getPhysicalRegister(RegMIPS32::Reg_SP);
5181 _mov(Dest, SP);
Jim Stichnoth6da4cef2015-06-11 13:26:33 -07005182 return;
5183 }
5184 case Intrinsics::Stackrestore: {
Stefan Maksimovicf8c99772016-11-02 05:59:06 -07005185 Variable *Val = legalizeToReg(Instr->getArg(0));
Stefan Maksimovic6e033432016-11-09 17:31:51 -08005186 Sandboxer(this).reset_sp(Val);
Jim Stichnoth6da4cef2015-06-11 13:26:33 -07005187 return;
5188 }
Srdjan Obucina0465d022016-09-20 16:25:14 -07005189 case Intrinsics::Trap: {
5190 const uint32_t TrapCodeZero = 0;
5191 _teq(getZero(), getZero(), TrapCodeZero);
Jim Stichnoth6da4cef2015-06-11 13:26:33 -07005192 return;
Srdjan Obucina0465d022016-09-20 16:25:14 -07005193 }
Nicolas Capensacfb3df2016-10-03 10:46:30 -04005194 case Intrinsics::LoadSubVector: {
5195 UnimplementedLoweringError(this, Instr); // Not required for PNaCl
5196 return;
5197 }
5198 case Intrinsics::StoreSubVector: {
5199 UnimplementedLoweringError(this, Instr); // Not required for PNaCl
5200 return;
5201 }
Jim Stichnoth7145e692016-10-19 05:49:47 -07005202 default: // UnknownIntrinsic
5203 Func->setError("Unexpected intrinsic");
Jim Stichnoth6da4cef2015-06-11 13:26:33 -07005204 return;
5205 }
5206 return;
5207}
5208
Reed Kotler04bca5a2016-02-03 14:40:47 -08005209void TargetMIPS32::lowerLoad(const InstLoad *Instr) {
Jaydeep Patil1d0690b2016-09-04 07:19:08 -07005210 // A Load instruction can be treated the same as an Assign instruction, after
Srdjan Obucinab85cde12016-09-09 09:39:52 -07005211 // the source operand is transformed into an OperandMIPS32Mem operand.
Jaydeep Patil1d0690b2016-09-04 07:19:08 -07005212 Type Ty = Instr->getDest()->getType();
5213 Operand *Src0 = formMemoryOperand(Instr->getSourceAddress(), Ty);
5214 Variable *DestLoad = Instr->getDest();
5215 auto *Assign = InstAssign::create(Func, DestLoad, Src0);
5216 lowerAssign(Assign);
Jim Stichnoth6da4cef2015-06-11 13:26:33 -07005217}
5218
Jaydeep Patil47ef0be2016-09-13 06:09:48 -07005219namespace {
5220void dumpAddressOpt(const Cfg *Func, const Variable *Base, int32_t Offset,
5221 const Inst *Reason) {
5222 if (!BuildDefs::dump())
5223 return;
5224 if (!Func->isVerbose(IceV_AddrOpt))
5225 return;
5226 OstreamLocker _(Func->getContext());
5227 Ostream &Str = Func->getContext()->getStrDump();
5228 Str << "Instruction: ";
5229 Reason->dumpDecorated(Func);
5230 Str << " results in Base=";
5231 if (Base)
5232 Base->dump(Func);
5233 else
5234 Str << "<null>";
5235 Str << ", Offset=" << Offset << "\n";
5236}
5237
5238bool matchAssign(const VariablesMetadata *VMetadata, Variable **Var,
5239 int32_t *Offset, const Inst **Reason) {
5240 // Var originates from Var=SrcVar ==> set Var:=SrcVar
5241 if (*Var == nullptr)
5242 return false;
5243 const Inst *VarAssign = VMetadata->getSingleDefinition(*Var);
5244 if (!VarAssign)
5245 return false;
5246 assert(!VMetadata->isMultiDef(*Var));
5247 if (!llvm::isa<InstAssign>(VarAssign))
5248 return false;
5249
5250 Operand *SrcOp = VarAssign->getSrc(0);
5251 bool Optimized = false;
5252 if (auto *SrcVar = llvm::dyn_cast<Variable>(SrcOp)) {
5253 if (!VMetadata->isMultiDef(SrcVar) ||
5254 // TODO: ensure SrcVar stays single-BB
5255 false) {
5256 Optimized = true;
5257 *Var = SrcVar;
5258 } else if (auto *Const = llvm::dyn_cast<ConstantInteger32>(SrcOp)) {
5259 int32_t MoreOffset = Const->getValue();
5260 int32_t NewOffset = MoreOffset + *Offset;
5261 if (Utils::WouldOverflowAdd(*Offset, MoreOffset))
5262 return false;
5263 *Var = nullptr;
5264 *Offset += NewOffset;
5265 Optimized = true;
5266 }
5267 }
5268
5269 if (Optimized) {
5270 *Reason = VarAssign;
5271 }
5272
5273 return Optimized;
5274}
5275
5276bool isAddOrSub(const Inst *Instr, InstArithmetic::OpKind *Kind) {
5277 if (const auto *Arith = llvm::dyn_cast<InstArithmetic>(Instr)) {
5278 switch (Arith->getOp()) {
5279 default:
5280 return false;
5281 case InstArithmetic::Add:
5282 case InstArithmetic::Sub:
5283 *Kind = Arith->getOp();
5284 return true;
5285 }
5286 }
5287 return false;
5288}
5289
5290bool matchOffsetBase(const VariablesMetadata *VMetadata, Variable **Base,
5291 int32_t *Offset, const Inst **Reason) {
5292 // Base is Base=Var+Const || Base is Base=Const+Var ==>
5293 // set Base=Var, Offset+=Const
5294 // Base is Base=Var-Const ==>
5295 // set Base=Var, Offset-=Const
5296 if (*Base == nullptr)
5297 return false;
5298 const Inst *BaseInst = VMetadata->getSingleDefinition(*Base);
5299 if (BaseInst == nullptr) {
5300 return false;
5301 }
5302 assert(!VMetadata->isMultiDef(*Base));
5303
5304 auto *ArithInst = llvm::dyn_cast<const InstArithmetic>(BaseInst);
5305 if (ArithInst == nullptr)
5306 return false;
5307 InstArithmetic::OpKind Kind;
5308 if (!isAddOrSub(ArithInst, &Kind))
5309 return false;
5310 bool IsAdd = Kind == InstArithmetic::Add;
5311 Operand *Src0 = ArithInst->getSrc(0);
5312 Operand *Src1 = ArithInst->getSrc(1);
5313 auto *Var0 = llvm::dyn_cast<Variable>(Src0);
5314 auto *Var1 = llvm::dyn_cast<Variable>(Src1);
5315 auto *Const0 = llvm::dyn_cast<ConstantInteger32>(Src0);
5316 auto *Const1 = llvm::dyn_cast<ConstantInteger32>(Src1);
5317 Variable *NewBase = nullptr;
5318 int32_t NewOffset = *Offset;
5319
5320 if (Var0 == nullptr && Const0 == nullptr) {
5321 assert(llvm::isa<ConstantRelocatable>(Src0));
5322 return false;
5323 }
5324
5325 if (Var1 == nullptr && Const1 == nullptr) {
5326 assert(llvm::isa<ConstantRelocatable>(Src1));
5327 return false;
5328 }
5329
5330 if (Var0 && Var1)
5331 // TODO(jpp): merge base/index splitting into here.
5332 return false;
5333 if (!IsAdd && Var1)
5334 return false;
5335 if (Var0)
5336 NewBase = Var0;
5337 else if (Var1)
5338 NewBase = Var1;
5339 // Compute the updated constant offset.
5340 if (Const0) {
5341 int32_t MoreOffset = IsAdd ? Const0->getValue() : -Const0->getValue();
5342 if (Utils::WouldOverflowAdd(NewOffset, MoreOffset))
5343 return false;
5344 NewOffset += MoreOffset;
5345 }
5346 if (Const1) {
5347 int32_t MoreOffset = IsAdd ? Const1->getValue() : -Const1->getValue();
5348 if (Utils::WouldOverflowAdd(NewOffset, MoreOffset))
5349 return false;
5350 NewOffset += MoreOffset;
5351 }
5352
5353 // Update the computed address parameters once we are sure optimization
5354 // is valid.
5355 *Base = NewBase;
5356 *Offset = NewOffset;
5357 *Reason = BaseInst;
5358 return true;
5359}
5360} // end of anonymous namespace
5361
5362OperandMIPS32Mem *TargetMIPS32::formAddressingMode(Type Ty, Cfg *Func,
5363 const Inst *LdSt,
5364 Operand *Base) {
5365 assert(Base != nullptr);
5366 int32_t OffsetImm = 0;
5367
5368 Func->resetCurrentNode();
5369 if (Func->isVerbose(IceV_AddrOpt)) {
5370 OstreamLocker _(Func->getContext());
5371 Ostream &Str = Func->getContext()->getStrDump();
5372 Str << "\nAddress mode formation:\t";
5373 LdSt->dumpDecorated(Func);
5374 }
5375
5376 if (isVectorType(Ty)) {
Jaydeep Patil47ef0be2016-09-13 06:09:48 -07005377 return nullptr;
5378 }
5379
5380 auto *BaseVar = llvm::dyn_cast<Variable>(Base);
5381 if (BaseVar == nullptr)
5382 return nullptr;
5383
5384 const VariablesMetadata *VMetadata = Func->getVMetadata();
5385 const Inst *Reason = nullptr;
5386
5387 do {
5388 if (Reason != nullptr) {
5389 dumpAddressOpt(Func, BaseVar, OffsetImm, Reason);
5390 Reason = nullptr;
5391 }
5392
5393 if (matchAssign(VMetadata, &BaseVar, &OffsetImm, &Reason)) {
5394 continue;
5395 }
5396
5397 if (matchOffsetBase(VMetadata, &BaseVar, &OffsetImm, &Reason)) {
5398 continue;
5399 }
5400 } while (Reason);
5401
5402 if (BaseVar == nullptr) {
5403 // We need base register rather than just OffsetImm. Move the OffsetImm to
5404 // BaseVar and form 0(BaseVar) addressing.
5405 const Type PointerType = getPointerType();
5406 BaseVar = makeReg(PointerType);
5407 Context.insert<InstAssign>(BaseVar, Ctx->getConstantInt32(OffsetImm));
5408 OffsetImm = 0;
5409 } else if (OffsetImm != 0) {
5410 // If the OffsetImm is more than signed 16-bit value then add it in the
5411 // BaseVar and form 0(BaseVar) addressing.
5412 const int32_t PositiveOffset = OffsetImm > 0 ? OffsetImm : -OffsetImm;
5413 const InstArithmetic::OpKind Op =
5414 OffsetImm > 0 ? InstArithmetic::Add : InstArithmetic::Sub;
5415 constexpr bool ZeroExt = false;
5416 if (!OperandMIPS32Mem::canHoldOffset(Ty, ZeroExt, OffsetImm)) {
5417 const Type PointerType = getPointerType();
5418 Variable *T = makeReg(PointerType);
5419 Context.insert<InstArithmetic>(Op, T, BaseVar,
5420 Ctx->getConstantInt32(PositiveOffset));
5421 BaseVar = T;
5422 OffsetImm = 0;
5423 }
5424 }
5425
5426 assert(BaseVar != nullptr);
5427 assert(OffsetImm < 0 ? (-OffsetImm & 0x0000ffff) == -OffsetImm
5428 : (OffsetImm & 0x0000ffff) == OffsetImm);
5429
5430 return OperandMIPS32Mem::create(
5431 Func, Ty, BaseVar,
5432 llvm::cast<ConstantInteger32>(Ctx->getConstantInt32(OffsetImm)));
5433}
5434
5435void TargetMIPS32::doAddressOptLoad() {
5436 Inst *Instr = iteratorToInst(Context.getCur());
5437 assert(llvm::isa<InstLoad>(Instr));
5438 Variable *Dest = Instr->getDest();
5439 Operand *Addr = Instr->getSrc(0);
5440 if (OperandMIPS32Mem *Mem =
5441 formAddressingMode(Dest->getType(), Func, Instr, Addr)) {
5442 Instr->setDeleted();
5443 Context.insert<InstLoad>(Dest, Mem);
5444 }
5445}
Jim Stichnoth6da4cef2015-06-11 13:26:33 -07005446
Qining Luaee5fa82015-08-20 14:59:03 -07005447void TargetMIPS32::randomlyInsertNop(float Probability,
5448 RandomNumberGenerator &RNG) {
5449 RandomNumberGeneratorWrapper RNGW(RNG);
5450 if (RNGW.getTrueWithProbability(Probability)) {
Srdjan Obucina8fbddc62016-09-15 17:26:40 -07005451 _nop();
Jim Stichnoth6da4cef2015-06-11 13:26:33 -07005452 }
5453}
5454
Reed Kotler04bca5a2016-02-03 14:40:47 -08005455void TargetMIPS32::lowerPhi(const InstPhi * /*Instr*/) {
Jim Stichnoth6da4cef2015-06-11 13:26:33 -07005456 Func->setError("Phi found in regular instruction list");
5457}
5458
Reed Kotler04bca5a2016-02-03 14:40:47 -08005459void TargetMIPS32::lowerRet(const InstRet *Instr) {
Reed Kotlerd00d48d2015-07-08 09:49:07 -07005460 Variable *Reg = nullptr;
Reed Kotler04bca5a2016-02-03 14:40:47 -08005461 if (Instr->hasRetValue()) {
5462 Operand *Src0 = Instr->getRetValue();
Jim Stichnothac8da5c2015-10-21 06:57:46 -07005463 switch (Src0->getType()) {
Srdjan Obucinad57ed5f2016-09-14 06:06:24 -07005464 case IceType_f32: {
5465 Operand *Src0F = legalizeToReg(Src0);
5466 Reg = makeReg(Src0F->getType(), RegMIPS32::Reg_F0);
5467 _mov(Reg, Src0F);
5468 break;
5469 }
5470 case IceType_f64: {
5471 Operand *Src0F = legalizeToReg(Src0);
5472 Reg = makeReg(Src0F->getType(), RegMIPS32::Reg_F0F1);
5473 _mov(Reg, Src0F);
5474 break;
5475 }
Jim Stichnothac8da5c2015-10-21 06:57:46 -07005476 case IceType_i1:
5477 case IceType_i8:
5478 case IceType_i16:
5479 case IceType_i32: {
Srdjan Obucinad57ed5f2016-09-14 06:06:24 -07005480 Operand *Src0F = legalizeToReg(Src0);
Jim Stichnothac8da5c2015-10-21 06:57:46 -07005481 Reg = makeReg(Src0F->getType(), RegMIPS32::Reg_V0);
5482 _mov(Reg, Src0F);
5483 break;
5484 }
5485 case IceType_i64: {
5486 Src0 = legalizeUndef(Src0);
5487 Variable *R0 = legalizeToReg(loOperand(Src0), RegMIPS32::Reg_V0);
5488 Variable *R1 = legalizeToReg(hiOperand(Src0), RegMIPS32::Reg_V1);
5489 Reg = R0;
John Porto1d937a82015-12-17 06:19:34 -08005490 Context.insert<InstFakeUse>(R1);
Jim Stichnothac8da5c2015-10-21 06:57:46 -07005491 break;
5492 }
Jaydeep Patil958ddb72016-10-03 07:52:48 -07005493 case IceType_v4i1:
5494 case IceType_v8i1:
5495 case IceType_v16i1:
5496 case IceType_v16i8:
5497 case IceType_v8i16:
5498 case IceType_v4i32: {
Jaydeep Patil0c4c07d2016-11-01 23:53:52 -07005499 auto *SrcVec = llvm::dyn_cast<VariableVecOn32>(legalizeUndef(Src0));
Jaydeep Patil958ddb72016-10-03 07:52:48 -07005500 Variable *V0 =
5501 legalizeToReg(SrcVec->getContainers()[0], RegMIPS32::Reg_V0);
5502 Variable *V1 =
5503 legalizeToReg(SrcVec->getContainers()[1], RegMIPS32::Reg_V1);
5504 Variable *A0 =
5505 legalizeToReg(SrcVec->getContainers()[2], RegMIPS32::Reg_A0);
5506 Variable *A1 =
5507 legalizeToReg(SrcVec->getContainers()[3], RegMIPS32::Reg_A1);
5508 Reg = V0;
5509 Context.insert<InstFakeUse>(V1);
5510 Context.insert<InstFakeUse>(A0);
5511 Context.insert<InstFakeUse>(A1);
5512 break;
5513 }
5514 case IceType_v4f32: {
Jaydeep Patil0c4c07d2016-11-01 23:53:52 -07005515 auto *SrcVec = llvm::dyn_cast<VariableVecOn32>(legalizeUndef(Src0));
Jaydeep Patil958ddb72016-10-03 07:52:48 -07005516 Reg = getImplicitRet();
5517 auto *RegT = legalizeToReg(Reg);
5518 // Return the vector through buffer in implicit argument a0
Jaydeep Patil3a01f332016-10-17 06:33:50 -07005519 for (SizeT i = 0; i < SrcVec->ContainersPerVector; ++i) {
Jaydeep Patil958ddb72016-10-03 07:52:48 -07005520 OperandMIPS32Mem *Mem = OperandMIPS32Mem::create(
5521 Func, IceType_f32, RegT,
5522 llvm::cast<ConstantInteger32>(Ctx->getConstantInt32(i * 4)));
5523 Variable *Var = legalizeToReg(SrcVec->getContainers()[i]);
5524 _sw(Var, Mem);
5525 }
5526 Variable *V0 = makeReg(IceType_i32, RegMIPS32::Reg_V0);
5527 _mov(V0, Reg); // move v0,a0
5528 Context.insert<InstFakeUse>(Reg);
5529 Context.insert<InstFakeUse>(V0);
5530 break;
5531 }
Jim Stichnothac8da5c2015-10-21 06:57:46 -07005532 default:
Jaydeep Patil958ddb72016-10-03 07:52:48 -07005533 llvm::report_fatal_error("Ret: Invalid type.");
5534 break;
Jim Stichnothac8da5c2015-10-21 06:57:46 -07005535 }
5536 }
Reed Kotlerd00d48d2015-07-08 09:49:07 -07005537 _ret(getPhysicalRegister(RegMIPS32::Reg_RA), Reg);
Jim Stichnoth6da4cef2015-06-11 13:26:33 -07005538}
5539
Reed Kotler04bca5a2016-02-03 14:40:47 -08005540void TargetMIPS32::lowerSelect(const InstSelect *Instr) {
Srdjan Obucinad57ed5f2016-09-14 06:06:24 -07005541 Variable *Dest = Instr->getDest();
5542 const Type DestTy = Dest->getType();
5543
Srdjan Obucina98405d32016-09-25 10:32:19 -07005544 if (isVectorType(DestTy)) {
Jaydeep Patil3a01f332016-10-17 06:33:50 -07005545 llvm::report_fatal_error("Select: Destination type is vector");
Srdjan Obucinad57ed5f2016-09-14 06:06:24 -07005546 return;
5547 }
5548
Srdjan Obucina98405d32016-09-25 10:32:19 -07005549 Variable *DestR = nullptr;
5550 Variable *DestHiR = nullptr;
5551 Variable *SrcTR = nullptr;
5552 Variable *SrcTHiR = nullptr;
5553 Variable *SrcFR = nullptr;
5554 Variable *SrcFHiR = nullptr;
5555
5556 if (DestTy == IceType_i64) {
5557 DestR = llvm::cast<Variable>(loOperand(Dest));
5558 DestHiR = llvm::cast<Variable>(hiOperand(Dest));
Jaydeep Patil0c4c07d2016-11-01 23:53:52 -07005559 SrcTR = legalizeToReg(loOperand(legalizeUndef(Instr->getTrueOperand())));
5560 SrcTHiR = legalizeToReg(hiOperand(legalizeUndef(Instr->getTrueOperand())));
5561 SrcFR = legalizeToReg(loOperand(legalizeUndef(Instr->getFalseOperand())));
5562 SrcFHiR = legalizeToReg(hiOperand(legalizeUndef(Instr->getFalseOperand())));
Srdjan Obucina98405d32016-09-25 10:32:19 -07005563 } else {
Jaydeep Patil0c4c07d2016-11-01 23:53:52 -07005564 SrcTR = legalizeToReg(legalizeUndef(Instr->getTrueOperand()));
5565 SrcFR = legalizeToReg(legalizeUndef(Instr->getFalseOperand()));
Srdjan Obucina98405d32016-09-25 10:32:19 -07005566 }
Srdjan Obucinad57ed5f2016-09-14 06:06:24 -07005567
5568 Variable *ConditionR = legalizeToReg(Instr->getCondition());
5569
5570 assert(Instr->getCondition()->getType() == IceType_i1);
5571
5572 switch (DestTy) {
5573 case IceType_i1:
5574 case IceType_i8:
5575 case IceType_i16:
5576 case IceType_i32:
5577 _movn(SrcFR, SrcTR, ConditionR);
Srdjan Obucina98405d32016-09-25 10:32:19 -07005578 _mov(Dest, SrcFR);
5579 break;
5580 case IceType_i64:
5581 _movn(SrcFR, SrcTR, ConditionR);
5582 _movn(SrcFHiR, SrcTHiR, ConditionR);
Srdjan Obucinad57ed5f2016-09-14 06:06:24 -07005583 _mov(DestR, SrcFR);
Srdjan Obucina98405d32016-09-25 10:32:19 -07005584 _mov(DestHiR, SrcFHiR);
Srdjan Obucinad57ed5f2016-09-14 06:06:24 -07005585 break;
5586 case IceType_f32:
5587 _movn_s(SrcFR, SrcTR, ConditionR);
Srdjan Obucina98405d32016-09-25 10:32:19 -07005588 _mov(Dest, SrcFR);
Srdjan Obucinad57ed5f2016-09-14 06:06:24 -07005589 break;
5590 case IceType_f64:
5591 _movn_d(SrcFR, SrcTR, ConditionR);
Srdjan Obucina98405d32016-09-25 10:32:19 -07005592 _mov(Dest, SrcFR);
Srdjan Obucinad57ed5f2016-09-14 06:06:24 -07005593 break;
5594 default:
Sagar Thakurbecb85f2016-11-18 12:15:46 -08005595 llvm::report_fatal_error("Select: Invalid type.");
Srdjan Obucinad57ed5f2016-09-14 06:06:24 -07005596 }
Jim Stichnoth6da4cef2015-06-11 13:26:33 -07005597}
5598
John Portoa47c11c2016-04-21 05:53:42 -07005599void TargetMIPS32::lowerShuffleVector(const InstShuffleVector *Instr) {
5600 UnimplementedLoweringError(this, Instr);
5601}
5602
Reed Kotler04bca5a2016-02-03 14:40:47 -08005603void TargetMIPS32::lowerStore(const InstStore *Instr) {
Mohit Bhakkadf3bc5cf2016-05-31 11:19:03 -07005604 Operand *Value = Instr->getData();
5605 Operand *Addr = Instr->getAddr();
5606 OperandMIPS32Mem *NewAddr = formMemoryOperand(Addr, Value->getType());
5607 Type Ty = NewAddr->getType();
5608
5609 if (Ty == IceType_i64) {
5610 Value = legalizeUndef(Value);
5611 Variable *ValueHi = legalizeToReg(hiOperand(Value));
5612 Variable *ValueLo = legalizeToReg(loOperand(Value));
5613 _sw(ValueHi, llvm::cast<OperandMIPS32Mem>(hiOperand(NewAddr)));
5614 _sw(ValueLo, llvm::cast<OperandMIPS32Mem>(loOperand(NewAddr)));
Jaydeep Patil958ddb72016-10-03 07:52:48 -07005615 } else if (isVectorType(Value->getType())) {
5616 auto *DataVec = llvm::dyn_cast<VariableVecOn32>(Value);
Jaydeep Patil3a01f332016-10-17 06:33:50 -07005617 for (SizeT i = 0; i < DataVec->ContainersPerVector; ++i) {
Jaydeep Patil958ddb72016-10-03 07:52:48 -07005618 auto *DCont = legalizeToReg(DataVec->getContainers()[i]);
5619 auto *MCont = llvm::cast<OperandMIPS32Mem>(
5620 getOperandAtIndex(NewAddr, IceType_i32, i));
5621 _sw(DCont, MCont);
5622 }
Mohit Bhakkadf3bc5cf2016-05-31 11:19:03 -07005623 } else {
5624 Variable *ValueR = legalizeToReg(Value);
5625 _sw(ValueR, NewAddr);
5626 }
Jim Stichnoth6da4cef2015-06-11 13:26:33 -07005627}
5628
Jaydeep Patil47ef0be2016-09-13 06:09:48 -07005629void TargetMIPS32::doAddressOptStore() {
5630 Inst *Instr = iteratorToInst(Context.getCur());
5631 assert(llvm::isa<InstStore>(Instr));
5632 Operand *Src = Instr->getSrc(0);
5633 Operand *Addr = Instr->getSrc(1);
5634 if (OperandMIPS32Mem *Mem =
5635 formAddressingMode(Src->getType(), Func, Instr, Addr)) {
5636 Instr->setDeleted();
5637 Context.insert<InstStore>(Src, Mem);
5638 }
5639}
Jim Stichnoth6da4cef2015-06-11 13:26:33 -07005640
Reed Kotler04bca5a2016-02-03 14:40:47 -08005641void TargetMIPS32::lowerSwitch(const InstSwitch *Instr) {
Jaydeep Patil29823f12016-08-31 05:10:03 -07005642 Operand *Src = Instr->getComparison();
5643 SizeT NumCases = Instr->getNumCases();
5644 if (Src->getType() == IceType_i64) {
5645 Src = legalizeUndef(Src);
5646 Variable *Src0Lo = legalizeToReg(loOperand(Src));
5647 Variable *Src0Hi = legalizeToReg(hiOperand(Src));
5648 for (SizeT I = 0; I < NumCases; ++I) {
5649 Operand *ValueLo = Ctx->getConstantInt32(Instr->getValue(I));
5650 Operand *ValueHi = Ctx->getConstantInt32(Instr->getValue(I) >> 32);
5651 CfgNode *TargetTrue = Instr->getLabel(I);
5652 constexpr CfgNode *NoTarget = nullptr;
5653 ValueHi = legalizeToReg(ValueHi);
5654 InstMIPS32Label *IntraLabel = InstMIPS32Label::create(Func, this);
5655 _br(NoTarget, NoTarget, Src0Hi, ValueHi, IntraLabel,
5656 CondMIPS32::Cond::NE);
5657 ValueLo = legalizeToReg(ValueLo);
5658 _br(NoTarget, TargetTrue, Src0Lo, ValueLo, CondMIPS32::Cond::EQ);
5659 Context.insert(IntraLabel);
5660 }
5661 _br(Instr->getLabelDefault());
5662 return;
5663 }
5664 Variable *SrcVar = legalizeToReg(Src);
5665 assert(SrcVar->mustHaveReg());
5666 for (SizeT I = 0; I < NumCases; ++I) {
5667 Operand *Value = Ctx->getConstantInt32(Instr->getValue(I));
5668 CfgNode *TargetTrue = Instr->getLabel(I);
5669 constexpr CfgNode *NoTargetFalse = nullptr;
5670 Value = legalizeToReg(Value);
5671 _br(NoTargetFalse, TargetTrue, SrcVar, Value, CondMIPS32::Cond::EQ);
5672 }
5673 _br(Instr->getLabelDefault());
Jim Stichnoth6da4cef2015-06-11 13:26:33 -07005674}
5675
Eric Holk67c7c412016-04-15 13:05:37 -07005676void TargetMIPS32::lowerBreakpoint(const InstBreakpoint *Instr) {
5677 UnimplementedLoweringError(this, Instr);
5678}
5679
Srdjan Obucina3b61d702016-09-20 06:49:52 -07005680void TargetMIPS32::lowerUnreachable(const InstUnreachable *) {
5681 const uint32_t TrapCodeZero = 0;
5682 _teq(getZero(), getZero(), TrapCodeZero);
Jim Stichnoth6da4cef2015-06-11 13:26:33 -07005683}
5684
Jaydeep Patil71f6c8d2017-02-10 06:45:40 -08005685void TargetMIPS32::lowerOther(const Inst *Instr) {
5686 if (llvm::isa<InstMIPS32Sync>(Instr)) {
5687 _sync();
5688 } else {
5689 TargetLowering::lowerOther(Instr);
5690 }
5691}
5692
Andrew Scull57e12682015-09-16 11:30:19 -07005693// Turn an i64 Phi instruction into a pair of i32 Phi instructions, to preserve
5694// integrity of liveness analysis. Undef values are also turned into zeroes,
5695// since loOperand() and hiOperand() don't expect Undef input.
Jim Stichnoth6da4cef2015-06-11 13:26:33 -07005696void TargetMIPS32::prelowerPhis() {
Jim Stichnothac8da5c2015-10-21 06:57:46 -07005697 PhiLowering::prelowerPhis32Bit<TargetMIPS32>(this, Context.getNode(), Func);
Jim Stichnoth6da4cef2015-06-11 13:26:33 -07005698}
5699
Jim Stichnoth6da4cef2015-06-11 13:26:33 -07005700void TargetMIPS32::postLower() {
Jim Stichnoth386b52e2016-08-05 15:18:41 -07005701 if (Func->getOptLevel() == Opt_m1)
Jim Stichnoth6da4cef2015-06-11 13:26:33 -07005702 return;
Srdjan Obucina0a7f99d2016-09-23 06:59:50 -07005703 markRedefinitions();
5704 Context.availabilityUpdate();
Jim Stichnoth6da4cef2015-06-11 13:26:33 -07005705}
5706
5707void TargetMIPS32::makeRandomRegisterPermutation(
Jim Stichnoth8aa39662016-02-10 11:20:30 -08005708 llvm::SmallVectorImpl<RegNumT> &Permutation,
John Portoe82b5602016-02-24 15:58:55 -08005709 const SmallBitVector &ExcludeRegisters, uint64_t Salt) const {
Jim Stichnoth6da4cef2015-06-11 13:26:33 -07005710 (void)Permutation;
5711 (void)ExcludeRegisters;
Qining Luaee5fa82015-08-20 14:59:03 -07005712 (void)Salt;
Karl Schimpfd4699942016-04-02 09:55:31 -07005713 UnimplementedError(getFlags());
Jim Stichnoth6da4cef2015-06-11 13:26:33 -07005714}
5715
5716/* TODO(jvoung): avoid duplicate symbols with multiple targets.
5717void ConstantUndef::emitWithoutDollar(GlobalContext *) const {
5718 llvm_unreachable("Not expecting to emitWithoutDollar undef");
5719}
5720
5721void ConstantUndef::emit(GlobalContext *) const {
5722 llvm_unreachable("undef value encountered by emitter.");
5723}
5724*/
5725
5726TargetDataMIPS32::TargetDataMIPS32(GlobalContext *Ctx)
5727 : TargetDataLowering(Ctx) {}
5728
Jaydeep Patil3da9f652016-11-03 22:54:06 -07005729// Generate .MIPS.abiflags section. This section contains a versioned data
5730// structure with essential information required for loader to determine the
5731// requirements of the application.
5732void TargetDataMIPS32::emitTargetRODataSections() {
5733 struct MipsABIFlagsSection Flags;
5734 ELFObjectWriter *Writer = Ctx->getObjectWriter();
5735 const std::string Name = ".MIPS.abiflags";
5736 const llvm::ELF::Elf64_Word ShType = llvm::ELF::SHT_MIPS_ABIFLAGS;
5737 const llvm::ELF::Elf64_Xword ShFlags = llvm::ELF::SHF_ALLOC;
5738 const llvm::ELF::Elf64_Xword ShAddralign = 8;
5739 const llvm::ELF::Elf64_Xword ShEntsize = sizeof(Flags);
5740 Writer->writeTargetRODataSection(
5741 Name, ShType, ShFlags, ShAddralign, ShEntsize,
5742 llvm::StringRef(reinterpret_cast<const char *>(&Flags), sizeof(Flags)));
5743}
5744
John Porto8b1a7052015-06-17 13:20:08 -07005745void TargetDataMIPS32::lowerGlobals(const VariableDeclarationList &Vars,
Jim Stichnoth467ffe52016-03-29 15:01:06 -07005746 const std::string &SectionSuffix) {
Karl Schimpfd4699942016-04-02 09:55:31 -07005747 const bool IsPIC = getFlags().getUseNonsfi();
5748 switch (getFlags().getOutFileType()) {
Jim Stichnoth6da4cef2015-06-11 13:26:33 -07005749 case FT_Elf: {
5750 ELFObjectWriter *Writer = Ctx->getObjectWriter();
Jaydeep Patil130aca72016-10-28 05:30:54 -07005751 Writer->writeDataSection(Vars, llvm::ELF::R_MIPS_32, SectionSuffix, IsPIC);
Jim Stichnoth6da4cef2015-06-11 13:26:33 -07005752 } break;
5753 case FT_Asm:
5754 case FT_Iasm: {
Jim Stichnoth6da4cef2015-06-11 13:26:33 -07005755 OstreamLocker L(Ctx);
John Porto8b1a7052015-06-17 13:20:08 -07005756 for (const VariableDeclaration *Var : Vars) {
Jim Stichnothdd6dcfa2016-04-18 12:52:09 -07005757 if (getFlags().matchTranslateOnly(Var->getName(), 0)) {
John Porto8b1a7052015-06-17 13:20:08 -07005758 emitGlobal(*Var, SectionSuffix);
Jim Stichnoth6da4cef2015-06-11 13:26:33 -07005759 }
5760 }
5761 } break;
5762 }
5763}
5764
Jaydeep Patilcf9c12f2016-09-20 08:38:11 -07005765namespace {
5766template <typename T> struct ConstantPoolEmitterTraits;
5767
5768static_assert(sizeof(uint64_t) == 8,
5769 "uint64_t is supposed to be 8 bytes wide.");
5770
5771// TODO(jaydeep.patil): implement the following when implementing constant
5772// randomization:
5773// * template <> struct ConstantPoolEmitterTraits<uint8_t>
5774// * template <> struct ConstantPoolEmitterTraits<uint16_t>
5775// * template <> struct ConstantPoolEmitterTraits<uint32_t>
5776template <> struct ConstantPoolEmitterTraits<float> {
5777 using ConstantType = ConstantFloat;
5778 static constexpr Type IceType = IceType_f32;
5779 // AsmTag and TypeName can't be constexpr because llvm::StringRef is unhappy
5780 // about them being constexpr.
5781 static const char AsmTag[];
5782 static const char TypeName[];
5783 static uint64_t bitcastToUint64(float Value) {
5784 static_assert(sizeof(Value) == sizeof(uint32_t),
5785 "Float should be 4 bytes.");
5786 const uint32_t IntValue = Utils::bitCopy<uint32_t>(Value);
5787 return static_cast<uint64_t>(IntValue);
5788 }
5789};
5790const char ConstantPoolEmitterTraits<float>::AsmTag[] = ".word";
5791const char ConstantPoolEmitterTraits<float>::TypeName[] = "f32";
5792
5793template <> struct ConstantPoolEmitterTraits<double> {
5794 using ConstantType = ConstantDouble;
5795 static constexpr Type IceType = IceType_f64;
5796 static const char AsmTag[];
5797 static const char TypeName[];
5798 static uint64_t bitcastToUint64(double Value) {
5799 static_assert(sizeof(double) == sizeof(uint64_t),
5800 "Double should be 8 bytes.");
5801 return Utils::bitCopy<uint64_t>(Value);
5802 }
5803};
5804const char ConstantPoolEmitterTraits<double>::AsmTag[] = ".quad";
5805const char ConstantPoolEmitterTraits<double>::TypeName[] = "f64";
5806
5807template <typename T>
5808void emitConstant(
5809 Ostream &Str,
5810 const typename ConstantPoolEmitterTraits<T>::ConstantType *Const) {
5811 if (!BuildDefs::dump())
5812 return;
5813 using Traits = ConstantPoolEmitterTraits<T>;
5814 Str << Const->getLabelName();
5815 T Value = Const->getValue();
5816 Str << ":\n\t" << Traits::AsmTag << "\t0x";
5817 Str.write_hex(Traits::bitcastToUint64(Value));
5818 Str << "\t/* " << Traits::TypeName << " " << Value << " */\n";
5819}
5820
5821template <typename T> void emitConstantPool(GlobalContext *Ctx) {
5822 if (!BuildDefs::dump())
5823 return;
5824 using Traits = ConstantPoolEmitterTraits<T>;
5825 static constexpr size_t MinimumAlignment = 4;
5826 SizeT Align = std::max(MinimumAlignment, typeAlignInBytes(Traits::IceType));
5827 assert((Align % 4) == 0 && "Constants should be aligned");
5828 Ostream &Str = Ctx->getStrEmit();
5829 ConstantList Pool = Ctx->getConstantPool(Traits::IceType);
5830 Str << "\t.section\t.rodata.cst" << Align << ",\"aM\",%progbits," << Align
5831 << "\n"
5832 << "\t.align\t" << (Align == 4 ? 2 : 3) << "\n";
5833 if (getFlags().getReorderPooledConstants()) {
5834 // TODO(jaydeep.patil): add constant pooling.
5835 UnimplementedError(getFlags());
5836 }
5837 for (Constant *C : Pool) {
5838 if (!C->getShouldBePooled()) {
5839 continue;
5840 }
5841 emitConstant<T>(Str, llvm::dyn_cast<typename Traits::ConstantType>(C));
5842 }
5843}
5844} // end of anonymous namespace
5845
John Porto0f86d032015-06-15 07:44:27 -07005846void TargetDataMIPS32::lowerConstants() {
Karl Schimpfd4699942016-04-02 09:55:31 -07005847 if (getFlags().getDisableTranslation())
Jim Stichnoth6da4cef2015-06-11 13:26:33 -07005848 return;
Jaydeep Patilcf9c12f2016-09-20 08:38:11 -07005849 switch (getFlags().getOutFileType()) {
5850 case FT_Elf: {
5851 ELFObjectWriter *Writer = Ctx->getObjectWriter();
5852 Writer->writeConstantPool<ConstantFloat>(IceType_f32);
5853 Writer->writeConstantPool<ConstantDouble>(IceType_f64);
5854 } break;
5855 case FT_Asm:
5856 case FT_Iasm: {
5857 OstreamLocker _(Ctx);
5858 emitConstantPool<float>(Ctx);
5859 emitConstantPool<double>(Ctx);
5860 break;
5861 }
5862 }
Jim Stichnoth6da4cef2015-06-11 13:26:33 -07005863}
5864
Andrew Scull86df4e92015-07-30 13:54:44 -07005865void TargetDataMIPS32::lowerJumpTables() {
Karl Schimpfd4699942016-04-02 09:55:31 -07005866 if (getFlags().getDisableTranslation())
Andrew Scull86df4e92015-07-30 13:54:44 -07005867 return;
Andrew Scull86df4e92015-07-30 13:54:44 -07005868}
5869
Jim Stichnothac8da5c2015-10-21 06:57:46 -07005870// Helper for legalize() to emit the right code to lower an operand to a
5871// register of the appropriate type.
Jim Stichnoth8aa39662016-02-10 11:20:30 -08005872Variable *TargetMIPS32::copyToReg(Operand *Src, RegNumT RegNum) {
Jim Stichnothac8da5c2015-10-21 06:57:46 -07005873 Type Ty = Src->getType();
5874 Variable *Reg = makeReg(Ty, RegNum);
Mohit Bhakkadb684f2b2016-06-09 15:06:23 -07005875 if (isVectorType(Ty)) {
Jaydeep Patil958ddb72016-10-03 07:52:48 -07005876 llvm::report_fatal_error("Invalid copy from vector type.");
Jim Stichnothac8da5c2015-10-21 06:57:46 -07005877 } else {
Jaydeep Patil1d0690b2016-09-04 07:19:08 -07005878 if (auto *Mem = llvm::dyn_cast<OperandMIPS32Mem>(Src)) {
5879 _lw(Reg, Mem);
5880 } else {
5881 _mov(Reg, Src);
5882 }
Jim Stichnothac8da5c2015-10-21 06:57:46 -07005883 }
5884 return Reg;
5885}
5886
5887Operand *TargetMIPS32::legalize(Operand *From, LegalMask Allowed,
Jim Stichnoth8aa39662016-02-10 11:20:30 -08005888 RegNumT RegNum) {
Jim Stichnothac8da5c2015-10-21 06:57:46 -07005889 Type Ty = From->getType();
5890 // Assert that a physical register is allowed. To date, all calls
5891 // to legalize() allow a physical register. Legal_Flex converts
5892 // registers to the right type OperandMIPS32FlexReg as needed.
5893 assert(Allowed & Legal_Reg);
Jaydeep Patil1d0690b2016-09-04 07:19:08 -07005894
5895 if (RegNum.hasNoValue()) {
5896 if (Variable *Subst = getContext().availabilityGet(From)) {
5897 // At this point we know there is a potential substitution available.
5898 if (!Subst->isRematerializable() && Subst->mustHaveReg() &&
5899 !Subst->hasReg()) {
5900 // At this point we know the substitution will have a register.
5901 if (From->getType() == Subst->getType()) {
5902 // At this point we know the substitution's register is compatible.
5903 return Subst;
5904 }
5905 }
5906 }
5907 }
5908
Jim Stichnothac8da5c2015-10-21 06:57:46 -07005909 // Go through the various types of operands:
Reed Kotler37af5b02015-11-05 17:07:19 -08005910 // OperandMIPS32Mem, Constant, and Variable.
Jim Stichnothac8da5c2015-10-21 06:57:46 -07005911 // Given the above assertion, if type of operand is not legal
5912 // (e.g., OperandMIPS32Mem and !Legal_Mem), we can always copy
5913 // to a register.
Jaydeep Patil1d0690b2016-09-04 07:19:08 -07005914 if (auto *Mem = llvm::dyn_cast<OperandMIPS32Mem>(From)) {
5915 // Base must be in a physical register.
5916 Variable *Base = Mem->getBase();
5917 ConstantInteger32 *Offset = llvm::cast<ConstantInteger32>(Mem->getOffset());
5918 Variable *RegBase = nullptr;
5919 assert(Base);
5920
5921 RegBase = llvm::cast<Variable>(
5922 legalize(Base, Legal_Reg | Legal_Rematerializable));
5923
5924 if (Offset != nullptr && Offset->getValue() != 0) {
5925 static constexpr bool ZeroExt = false;
5926 if (!OperandMIPS32Mem::canHoldOffset(Ty, ZeroExt, Offset->getValue())) {
5927 llvm::report_fatal_error("Invalid memory offset.");
5928 }
5929 }
5930
5931 // Create a new operand if there was a change.
5932 if (Base != RegBase) {
5933 Mem = OperandMIPS32Mem::create(Func, Ty, RegBase, Offset,
5934 Mem->getAddrMode());
5935 }
5936
5937 if (Allowed & Legal_Mem) {
5938 From = Mem;
5939 } else {
5940 Variable *Reg = makeReg(Ty, RegNum);
5941 _lw(Reg, Mem);
5942 From = Reg;
5943 }
5944 return From;
5945 }
5946
Mohit Bhakkadd1e97772016-07-07 05:07:35 -07005947 if (llvm::isa<Constant>(From)) {
Jaydeep Patil958ddb72016-10-03 07:52:48 -07005948 if (llvm::isa<ConstantUndef>(From)) {
5949 From = legalizeUndef(From, RegNum);
5950 if (isVectorType(Ty))
5951 return From;
5952 }
Mohit Bhakkadd1e97772016-07-07 05:07:35 -07005953 if (auto *C = llvm::dyn_cast<ConstantRelocatable>(From)) {
Mohit Bhakkadd1e97772016-07-07 05:07:35 -07005954 Variable *Reg = makeReg(Ty, RegNum);
Jaydeep Patil45e4d5e2016-10-16 21:50:43 -07005955 Variable *TReg = makeReg(Ty, RegNum);
5956 _lui(TReg, C, RO_Hi);
5957 _addiu(Reg, TReg, C, RO_Lo);
Mohit Bhakkadd1e97772016-07-07 05:07:35 -07005958 return Reg;
5959 } else if (auto *C32 = llvm::dyn_cast<ConstantInteger32>(From)) {
5960 const uint32_t Value = C32->getValue();
Jaydeep Patil958ddb72016-10-03 07:52:48 -07005961 // Use addiu if the immediate is a 16bit value. Otherwise load it
5962 // using a lui-ori instructions.
5963 Variable *Reg = makeReg(Ty, RegNum);
Mohit Bhakkadd1e97772016-07-07 05:07:35 -07005964 if (isInt<16>(int32_t(Value))) {
Sagar Thakurbecb85f2016-11-18 12:15:46 -08005965 Variable *Zero = makeReg(Ty, RegMIPS32::Reg_ZERO);
Mohit Bhakkadd1e97772016-07-07 05:07:35 -07005966 Context.insert<InstFakeDef>(Zero);
5967 _addiu(Reg, Zero, Value);
5968 } else {
5969 uint32_t UpperBits = (Value >> 16) & 0xFFFF;
Mohit Bhakkadd1e97772016-07-07 05:07:35 -07005970 uint32_t LowerBits = Value & 0xFFFF;
Sagar Thakurc930d592016-07-12 04:06:44 -07005971 if (LowerBits) {
Jaydeep Patil2bbda7f2017-01-10 21:48:58 -08005972 Variable *TReg = makeReg(Ty, RegNum);
Sagar Thakurc930d592016-07-12 04:06:44 -07005973 _lui(TReg, Ctx->getConstantInt32(UpperBits));
5974 _ori(Reg, TReg, LowerBits);
5975 } else {
5976 _lui(Reg, Ctx->getConstantInt32(UpperBits));
5977 }
Mohit Bhakkadd1e97772016-07-07 05:07:35 -07005978 }
5979 return Reg;
5980 } else if (isScalarFloatingType(Ty)) {
Mohit Bhakkadd1e97772016-07-07 05:07:35 -07005981 auto *CFrom = llvm::cast<Constant>(From);
Jaydeep Patilcf9c12f2016-09-20 08:38:11 -07005982 Variable *TReg = makeReg(Ty);
5983 if (!CFrom->getShouldBePooled()) {
5984 // Float/Double constant 0 is not pooled.
5985 Context.insert<InstFakeDef>(TReg);
5986 _mov(TReg, getZero());
5987 } else {
5988 // Load floats/doubles from literal pool.
5989 Constant *Offset = Ctx->getConstantSym(0, CFrom->getLabelName());
5990 Variable *TReg1 = makeReg(getPointerType());
5991 _lui(TReg1, Offset, RO_Hi);
5992 OperandMIPS32Mem *Addr =
5993 OperandMIPS32Mem::create(Func, Ty, TReg1, Offset);
5994 if (Ty == IceType_f32)
Stefan Maksimovic6e033432016-11-09 17:31:51 -08005995 Sandboxer(this).lwc1(TReg, Addr, RO_Lo);
Jaydeep Patilcf9c12f2016-09-20 08:38:11 -07005996 else
Stefan Maksimovic6e033432016-11-09 17:31:51 -08005997 Sandboxer(this).ldc1(TReg, Addr, RO_Lo);
Jaydeep Patilcf9c12f2016-09-20 08:38:11 -07005998 }
5999 return copyToReg(TReg, RegNum);
Jim Stichnothac8da5c2015-10-21 06:57:46 -07006000 }
Jim Stichnothac8da5c2015-10-21 06:57:46 -07006001 }
Mohit Bhakkadd1e97772016-07-07 05:07:35 -07006002
Jim Stichnoth5bff61c2015-10-28 09:26:00 -07006003 if (auto *Var = llvm::dyn_cast<Variable>(From)) {
Jaydeep Patil1d0690b2016-09-04 07:19:08 -07006004 if (Var->isRematerializable()) {
6005 if (Allowed & Legal_Rematerializable) {
6006 return From;
6007 }
6008
6009 Variable *T = makeReg(Var->getType(), RegNum);
6010 _mov(T, Var);
6011 return T;
6012 }
Jim Stichnothac8da5c2015-10-21 06:57:46 -07006013 // Check if the variable is guaranteed a physical register. This
6014 // can happen either when the variable is pre-colored or when it is
6015 // assigned infinite weight.
6016 bool MustHaveRegister = (Var->hasReg() || Var->mustHaveReg());
6017 // We need a new physical register for the operand if:
6018 // Mem is not allowed and Var isn't guaranteed a physical
6019 // register, or
6020 // RegNum is required and Var->getRegNum() doesn't match.
6021 if ((!(Allowed & Legal_Mem) && !MustHaveRegister) ||
Reed Kotler5fa0a5f2016-02-15 20:01:24 -08006022 (RegNum.hasValue() && RegNum != Var->getRegNum())) {
Jim Stichnothac8da5c2015-10-21 06:57:46 -07006023 From = copyToReg(From, RegNum);
6024 }
6025 return From;
6026 }
6027 return From;
6028}
6029
Sagar Thakur5cce7612016-05-24 06:25:50 -07006030namespace BoolFolding {
6031// TODO(sagar.thakur): Add remaining instruction kinds to shouldTrackProducer()
6032// and isValidConsumer()
6033bool shouldTrackProducer(const Inst &Instr) {
6034 return Instr.getKind() == Inst::Icmp;
6035}
6036
6037bool isValidConsumer(const Inst &Instr) { return Instr.getKind() == Inst::Br; }
6038} // end of namespace BoolFolding
6039
6040void TargetMIPS32::ComputationTracker::recordProducers(CfgNode *Node) {
6041 for (Inst &Instr : Node->getInsts()) {
6042 if (Instr.isDeleted())
6043 continue;
6044 // Check whether Instr is a valid producer.
6045 Variable *Dest = Instr.getDest();
6046 if (Dest // only consider instructions with an actual dest var; and
6047 && Dest->getType() == IceType_i1 // only bool-type dest vars; and
6048 && BoolFolding::shouldTrackProducer(Instr)) { // white-listed instr.
6049 KnownComputations.emplace(Dest->getIndex(),
6050 ComputationEntry(&Instr, IceType_i1));
6051 }
6052 // Check each src variable against the map.
6053 FOREACH_VAR_IN_INST(Var, Instr) {
6054 SizeT VarNum = Var->getIndex();
6055 auto ComputationIter = KnownComputations.find(VarNum);
6056 if (ComputationIter == KnownComputations.end()) {
6057 continue;
6058 }
6059
6060 ++ComputationIter->second.NumUses;
6061 switch (ComputationIter->second.ComputationType) {
6062 default:
6063 KnownComputations.erase(VarNum);
6064 continue;
6065 case IceType_i1:
6066 if (!BoolFolding::isValidConsumer(Instr)) {
6067 KnownComputations.erase(VarNum);
6068 continue;
6069 }
6070 break;
6071 }
6072
6073 if (Instr.isLastUse(Var)) {
6074 ComputationIter->second.IsLiveOut = false;
6075 }
6076 }
6077 }
6078
6079 for (auto Iter = KnownComputations.begin(), End = KnownComputations.end();
6080 Iter != End;) {
6081 // Disable the folding if its dest may be live beyond this block.
6082 if (Iter->second.IsLiveOut || Iter->second.NumUses > 1) {
6083 Iter = KnownComputations.erase(Iter);
6084 continue;
6085 }
6086
6087 // Mark as "dead" rather than outright deleting. This is so that other
6088 // peephole style optimizations during or before lowering have access to
6089 // this instruction in undeleted form. See for example
6090 // tryOptimizedCmpxchgCmpBr().
6091 Iter->second.Instr->setDead();
6092 ++Iter;
6093 }
6094}
6095
Jan Voungfb792842015-06-11 15:27:50 -07006096TargetHeaderMIPS32::TargetHeaderMIPS32(GlobalContext *Ctx)
6097 : TargetHeaderLowering(Ctx) {}
6098
Jim Stichnothac8da5c2015-10-21 06:57:46 -07006099void TargetHeaderMIPS32::lower() {
Stefan Maksimovic8208e752016-11-22 10:25:37 -08006100 if (!BuildDefs::dump())
6101 return;
Jim Stichnothac8da5c2015-10-21 06:57:46 -07006102 OstreamLocker L(Ctx);
6103 Ostream &Str = Ctx->getStrEmit();
Jim Stichnoth6106df82015-12-16 06:17:58 -08006104 Str << "\t.set\t"
6105 << "nomicromips\n";
6106 Str << "\t.set\t"
6107 << "nomips16\n";
Jaydeep Patila7979bf2016-10-26 06:16:19 -07006108 Str << "\t.set\t"
6109 << "noat\n";
Stefan Maksimovic8208e752016-11-22 10:25:37 -08006110 if (getFlags().getUseSandboxing())
6111 Str << "\t.bundle_align_mode 4\n";
Jim Stichnothac8da5c2015-10-21 06:57:46 -07006112}
6113
John Portoe82b5602016-02-24 15:58:55 -08006114SmallBitVector TargetMIPS32::TypeToRegisterSet[RCMIPS32_NUM];
6115SmallBitVector TargetMIPS32::TypeToRegisterSetUnfiltered[RCMIPS32_NUM];
6116SmallBitVector TargetMIPS32::RegisterAliases[RegMIPS32::Reg_NUM];
Jim Stichnoth94844f12015-11-04 16:06:16 -08006117
Stefan Maksimovic6e033432016-11-09 17:31:51 -08006118TargetMIPS32::Sandboxer::Sandboxer(TargetMIPS32 *Target,
6119 InstBundleLock::Option BundleOption)
6120 : Target(Target), BundleOption(BundleOption) {}
6121
6122TargetMIPS32::Sandboxer::~Sandboxer() {}
6123
6124void TargetMIPS32::Sandboxer::createAutoBundle() {
6125 Bundler = makeUnique<AutoBundle>(Target, BundleOption);
6126}
6127
6128void TargetMIPS32::Sandboxer::addiu_sp(uint32_t StackOffset) {
6129 Variable *SP = Target->getPhysicalRegister(RegMIPS32::Reg_SP);
6130 if (!Target->NeedSandboxing) {
6131 Target->_addiu(SP, SP, StackOffset);
6132 return;
6133 }
Stefan Maksimovic298d14e2017-01-11 05:58:27 -08006134 auto *T7 = Target->makeReg(IceType_i32, RegMIPS32::Reg_T7);
6135 Target->Context.insert<InstFakeDef>(T7);
Stefan Maksimovic6e033432016-11-09 17:31:51 -08006136 createAutoBundle();
6137 Target->_addiu(SP, SP, StackOffset);
6138 Target->_and(SP, SP, T7);
6139}
6140
6141void TargetMIPS32::Sandboxer::lw(Variable *Dest, OperandMIPS32Mem *Mem) {
6142 Variable *Base = Mem->getBase();
Stefan Maksimovic298d14e2017-01-11 05:58:27 -08006143 if (Target->NeedSandboxing && (Target->getStackReg() != Base->getRegNum()) &&
6144 (RegMIPS32::Reg_T8 != Base->getRegNum())) {
6145 auto *T7 = Target->makeReg(IceType_i32, RegMIPS32::Reg_T7);
6146 Target->Context.insert<InstFakeDef>(T7);
Stefan Maksimovic6e033432016-11-09 17:31:51 -08006147 createAutoBundle();
6148 Target->_and(Base, Base, T7);
6149 }
6150 Target->_lw(Dest, Mem);
Stefan Maksimovic298d14e2017-01-11 05:58:27 -08006151 if (Target->NeedSandboxing && (Dest->getRegNum() == Target->getStackReg())) {
6152 auto *T7 = Target->makeReg(IceType_i32, RegMIPS32::Reg_T7);
6153 Target->Context.insert<InstFakeDef>(T7);
Stefan Maksimovic8208e752016-11-22 10:25:37 -08006154 Target->_and(Dest, Dest, T7);
Stefan Maksimovic298d14e2017-01-11 05:58:27 -08006155 }
6156}
6157
6158void TargetMIPS32::Sandboxer::ll(Variable *Dest, OperandMIPS32Mem *Mem) {
6159 Variable *Base = Mem->getBase();
6160 if (Target->NeedSandboxing && (Target->getStackReg() != Base->getRegNum())) {
6161 auto *T7 = Target->makeReg(IceType_i32, RegMIPS32::Reg_T7);
6162 Target->Context.insert<InstFakeDef>(T7);
6163 createAutoBundle();
6164 Target->_and(Base, Base, T7);
6165 }
6166 Target->_ll(Dest, Mem);
6167 if (Target->NeedSandboxing && (Dest->getRegNum() == Target->getStackReg())) {
6168 auto *T7 = Target->makeReg(IceType_i32, RegMIPS32::Reg_T7);
6169 Target->Context.insert<InstFakeDef>(T7);
6170 Target->_and(Dest, Dest, T7);
6171 }
6172}
6173
6174void TargetMIPS32::Sandboxer::sc(Variable *Dest, OperandMIPS32Mem *Mem) {
6175 Variable *Base = Mem->getBase();
6176 if (Target->NeedSandboxing && (Target->getStackReg() != Base->getRegNum())) {
6177 auto *T7 = Target->makeReg(IceType_i32, RegMIPS32::Reg_T7);
6178 Target->Context.insert<InstFakeDef>(T7);
6179 createAutoBundle();
6180 Target->_and(Base, Base, T7);
6181 }
6182 Target->_sc(Dest, Mem);
Stefan Maksimovic6e033432016-11-09 17:31:51 -08006183}
6184
6185void TargetMIPS32::Sandboxer::sw(Variable *Dest, OperandMIPS32Mem *Mem) {
6186 Variable *Base = Mem->getBase();
Stefan Maksimovic6e033432016-11-09 17:31:51 -08006187 if (Target->NeedSandboxing && (Target->getStackReg() != Base->getRegNum())) {
Stefan Maksimovic298d14e2017-01-11 05:58:27 -08006188 auto *T7 = Target->makeReg(IceType_i32, RegMIPS32::Reg_T7);
6189 Target->Context.insert<InstFakeDef>(T7);
Stefan Maksimovic6e033432016-11-09 17:31:51 -08006190 createAutoBundle();
6191 Target->_and(Base, Base, T7);
6192 }
6193 Target->_sw(Dest, Mem);
6194}
6195
6196void TargetMIPS32::Sandboxer::lwc1(Variable *Dest, OperandMIPS32Mem *Mem,
6197 RelocOp Reloc) {
6198 Variable *Base = Mem->getBase();
Stefan Maksimovic6e033432016-11-09 17:31:51 -08006199 if (Target->NeedSandboxing && (Target->getStackReg() != Base->getRegNum())) {
Stefan Maksimovic298d14e2017-01-11 05:58:27 -08006200 auto *T7 = Target->makeReg(IceType_i32, RegMIPS32::Reg_T7);
6201 Target->Context.insert<InstFakeDef>(T7);
Stefan Maksimovic6e033432016-11-09 17:31:51 -08006202 createAutoBundle();
6203 Target->_and(Base, Base, T7);
6204 }
6205 Target->_lwc1(Dest, Mem, Reloc);
Stefan Maksimovic298d14e2017-01-11 05:58:27 -08006206 if (Target->NeedSandboxing && (Dest->getRegNum() == Target->getStackReg())) {
6207 auto *T7 = Target->makeReg(IceType_i32, RegMIPS32::Reg_T7);
6208 Target->Context.insert<InstFakeDef>(T7);
Stefan Maksimovic6e033432016-11-09 17:31:51 -08006209 Target->_and(Dest, Dest, T7);
Stefan Maksimovic298d14e2017-01-11 05:58:27 -08006210 }
Stefan Maksimovic6e033432016-11-09 17:31:51 -08006211}
6212
6213void TargetMIPS32::Sandboxer::ldc1(Variable *Dest, OperandMIPS32Mem *Mem,
6214 RelocOp Reloc) {
6215 Variable *Base = Mem->getBase();
Stefan Maksimovic6e033432016-11-09 17:31:51 -08006216 if (Target->NeedSandboxing && (Target->getStackReg() != Base->getRegNum())) {
Stefan Maksimovic298d14e2017-01-11 05:58:27 -08006217 auto *T7 = Target->makeReg(IceType_i32, RegMIPS32::Reg_T7);
6218 Target->Context.insert<InstFakeDef>(T7);
Stefan Maksimovic6e033432016-11-09 17:31:51 -08006219 createAutoBundle();
6220 Target->_and(Base, Base, T7);
6221 }
6222 Target->_ldc1(Dest, Mem, Reloc);
Stefan Maksimovic298d14e2017-01-11 05:58:27 -08006223 if (Target->NeedSandboxing && (Dest->getRegNum() == Target->getStackReg())) {
6224 auto *T7 = Target->makeReg(IceType_i32, RegMIPS32::Reg_T7);
6225 Target->Context.insert<InstFakeDef>(T7);
Stefan Maksimovic6e033432016-11-09 17:31:51 -08006226 Target->_and(Dest, Dest, T7);
Stefan Maksimovic298d14e2017-01-11 05:58:27 -08006227 }
Stefan Maksimovic6e033432016-11-09 17:31:51 -08006228}
6229
6230void TargetMIPS32::Sandboxer::ret(Variable *RetAddr, Variable *RetValue) {
6231 if (!Target->NeedSandboxing) {
6232 Target->_ret(RetAddr, RetValue);
6233 }
Stefan Maksimovic298d14e2017-01-11 05:58:27 -08006234 auto *T6 = Target->makeReg(IceType_i32, RegMIPS32::Reg_T6);
6235 Target->Context.insert<InstFakeDef>(T6);
Stefan Maksimovic6e033432016-11-09 17:31:51 -08006236 createAutoBundle();
6237 Target->_and(RetAddr, RetAddr, T6);
6238 Target->_ret(RetAddr, RetValue);
6239}
6240
6241void TargetMIPS32::Sandboxer::reset_sp(Variable *Src) {
6242 Variable *SP = Target->getPhysicalRegister(RegMIPS32::Reg_SP);
6243 if (!Target->NeedSandboxing) {
6244 Target->_mov(SP, Src);
6245 return;
6246 }
Stefan Maksimovic298d14e2017-01-11 05:58:27 -08006247 auto *T7 = Target->makeReg(IceType_i32, RegMIPS32::Reg_T7);
6248 Target->Context.insert<InstFakeDef>(T7);
Stefan Maksimovic6e033432016-11-09 17:31:51 -08006249 createAutoBundle();
6250 Target->_mov(SP, Src);
6251 Target->_and(SP, SP, T7);
Stefan Maksimovic8208e752016-11-22 10:25:37 -08006252 Target->getContext().insert<InstFakeUse>(SP);
Stefan Maksimovic6e033432016-11-09 17:31:51 -08006253}
6254
6255InstMIPS32Call *TargetMIPS32::Sandboxer::jal(Variable *ReturnReg,
6256 Operand *CallTarget) {
Stefan Maksimovic8208e752016-11-22 10:25:37 -08006257 if (Target->NeedSandboxing) {
Stefan Maksimovic6e033432016-11-09 17:31:51 -08006258 createAutoBundle();
Stefan Maksimovic8208e752016-11-22 10:25:37 -08006259 if (auto *CallTargetR = llvm::dyn_cast<Variable>(CallTarget)) {
Stefan Maksimovic298d14e2017-01-11 05:58:27 -08006260 auto *T6 = Target->makeReg(IceType_i32, RegMIPS32::Reg_T6);
6261 Target->Context.insert<InstFakeDef>(T6);
Stefan Maksimovic8208e752016-11-22 10:25:37 -08006262 Target->_and(CallTargetR, CallTargetR, T6);
6263 }
6264 }
Stefan Maksimovic6e033432016-11-09 17:31:51 -08006265 return Target->Context.insert<InstMIPS32Call>(ReturnReg, CallTarget);
6266}
6267
John Porto4a566862016-01-04 09:33:41 -08006268} // end of namespace MIPS32
Jim Stichnoth6da4cef2015-06-11 13:26:33 -07006269} // end of namespace Ice