xref: /aosp_15_r20/external/swiftshader/third_party/subzero/src/IceTargetLoweringMIPS32.cpp (revision 03ce13f70fcc45d86ee91b7ee4cab1936a95046e)
1*03ce13f7SAndroid Build Coastguard Worker //
2*03ce13f7SAndroid Build Coastguard Worker //                        The Subzero Code Generator
3*03ce13f7SAndroid Build Coastguard Worker //
4*03ce13f7SAndroid Build Coastguard Worker // This file is distributed under the University of Illinois Open Source
5*03ce13f7SAndroid Build Coastguard Worker // License. See LICENSE.TXT for details.
6*03ce13f7SAndroid Build Coastguard Worker //
7*03ce13f7SAndroid Build Coastguard Worker //===----------------------------------------------------------------------===//
8*03ce13f7SAndroid Build Coastguard Worker ///
9*03ce13f7SAndroid Build Coastguard Worker /// \file
10*03ce13f7SAndroid Build Coastguard Worker /// \brief Implements the TargetLoweringMIPS32 class, which consists almost
11*03ce13f7SAndroid Build Coastguard Worker /// entirely of the lowering sequence for each high-level instruction.
12*03ce13f7SAndroid Build Coastguard Worker ///
13*03ce13f7SAndroid Build Coastguard Worker //===----------------------------------------------------------------------===//
14*03ce13f7SAndroid Build Coastguard Worker 
15*03ce13f7SAndroid Build Coastguard Worker #include "IceTargetLoweringMIPS32.h"
16*03ce13f7SAndroid Build Coastguard Worker 
17*03ce13f7SAndroid Build Coastguard Worker #include "IceCfg.h"
18*03ce13f7SAndroid Build Coastguard Worker #include "IceCfgNode.h"
19*03ce13f7SAndroid Build Coastguard Worker #include "IceClFlags.h"
20*03ce13f7SAndroid Build Coastguard Worker #include "IceDefs.h"
21*03ce13f7SAndroid Build Coastguard Worker #include "IceELFObjectWriter.h"
22*03ce13f7SAndroid Build Coastguard Worker #include "IceGlobalInits.h"
23*03ce13f7SAndroid Build Coastguard Worker #include "IceInstMIPS32.h"
24*03ce13f7SAndroid Build Coastguard Worker #include "IceInstVarIter.h"
25*03ce13f7SAndroid Build Coastguard Worker #include "IceLiveness.h"
26*03ce13f7SAndroid Build Coastguard Worker #include "IceOperand.h"
27*03ce13f7SAndroid Build Coastguard Worker #include "IcePhiLoweringImpl.h"
28*03ce13f7SAndroid Build Coastguard Worker #include "IceRegistersMIPS32.h"
29*03ce13f7SAndroid Build Coastguard Worker #include "IceTargetLoweringMIPS32.def"
30*03ce13f7SAndroid Build Coastguard Worker #include "IceUtils.h"
31*03ce13f7SAndroid Build Coastguard Worker #include "llvm/Support/MathExtras.h"
32*03ce13f7SAndroid Build Coastguard Worker 
33*03ce13f7SAndroid Build Coastguard Worker namespace MIPS32 {
createTargetLowering(::Ice::Cfg * Func)34*03ce13f7SAndroid Build Coastguard Worker std::unique_ptr<::Ice::TargetLowering> createTargetLowering(::Ice::Cfg *Func) {
35*03ce13f7SAndroid Build Coastguard Worker   return ::Ice::MIPS32::TargetMIPS32::create(Func);
36*03ce13f7SAndroid Build Coastguard Worker }
37*03ce13f7SAndroid Build Coastguard Worker 
38*03ce13f7SAndroid Build Coastguard Worker std::unique_ptr<::Ice::TargetDataLowering>
createTargetDataLowering(::Ice::GlobalContext * Ctx)39*03ce13f7SAndroid Build Coastguard Worker createTargetDataLowering(::Ice::GlobalContext *Ctx) {
40*03ce13f7SAndroid Build Coastguard Worker   return ::Ice::MIPS32::TargetDataMIPS32::create(Ctx);
41*03ce13f7SAndroid Build Coastguard Worker }
42*03ce13f7SAndroid Build Coastguard Worker 
43*03ce13f7SAndroid Build Coastguard Worker std::unique_ptr<::Ice::TargetHeaderLowering>
createTargetHeaderLowering(::Ice::GlobalContext * Ctx)44*03ce13f7SAndroid Build Coastguard Worker createTargetHeaderLowering(::Ice::GlobalContext *Ctx) {
45*03ce13f7SAndroid Build Coastguard Worker   return ::Ice::MIPS32::TargetHeaderMIPS32::create(Ctx);
46*03ce13f7SAndroid Build Coastguard Worker }
47*03ce13f7SAndroid Build Coastguard Worker 
staticInit(::Ice::GlobalContext * Ctx)48*03ce13f7SAndroid Build Coastguard Worker void staticInit(::Ice::GlobalContext *Ctx) {
49*03ce13f7SAndroid Build Coastguard Worker   ::Ice::MIPS32::TargetMIPS32::staticInit(Ctx);
50*03ce13f7SAndroid Build Coastguard Worker }
51*03ce13f7SAndroid Build Coastguard Worker 
shouldBePooled(const::Ice::Constant * C)52*03ce13f7SAndroid Build Coastguard Worker bool shouldBePooled(const ::Ice::Constant *C) {
53*03ce13f7SAndroid Build Coastguard Worker   return ::Ice::MIPS32::TargetMIPS32::shouldBePooled(C);
54*03ce13f7SAndroid Build Coastguard Worker }
55*03ce13f7SAndroid Build Coastguard Worker 
getPointerType()56*03ce13f7SAndroid Build Coastguard Worker ::Ice::Type getPointerType() {
57*03ce13f7SAndroid Build Coastguard Worker   return ::Ice::MIPS32::TargetMIPS32::getPointerType();
58*03ce13f7SAndroid Build Coastguard Worker }
59*03ce13f7SAndroid Build Coastguard Worker 
60*03ce13f7SAndroid Build Coastguard Worker } // end of namespace MIPS32
61*03ce13f7SAndroid Build Coastguard Worker 
62*03ce13f7SAndroid Build Coastguard Worker namespace Ice {
63*03ce13f7SAndroid Build Coastguard Worker namespace MIPS32 {
64*03ce13f7SAndroid Build Coastguard Worker 
65*03ce13f7SAndroid Build Coastguard Worker using llvm::isInt;
66*03ce13f7SAndroid Build Coastguard Worker 
67*03ce13f7SAndroid Build Coastguard Worker namespace {
68*03ce13f7SAndroid Build Coastguard Worker 
69*03ce13f7SAndroid Build Coastguard Worker // The maximum number of arguments to pass in GPR registers.
70*03ce13f7SAndroid Build Coastguard Worker constexpr uint32_t MIPS32_MAX_GPR_ARG = 4;
71*03ce13f7SAndroid Build Coastguard Worker 
72*03ce13f7SAndroid Build Coastguard Worker std::array<RegNumT, MIPS32_MAX_GPR_ARG> GPRArgInitializer;
73*03ce13f7SAndroid Build Coastguard Worker std::array<RegNumT, MIPS32_MAX_GPR_ARG / 2> I64ArgInitializer;
74*03ce13f7SAndroid Build Coastguard Worker 
75*03ce13f7SAndroid Build Coastguard Worker constexpr uint32_t MIPS32_MAX_FP_ARG = 2;
76*03ce13f7SAndroid Build Coastguard Worker 
77*03ce13f7SAndroid Build Coastguard Worker std::array<RegNumT, MIPS32_MAX_FP_ARG> FP32ArgInitializer;
78*03ce13f7SAndroid Build Coastguard Worker std::array<RegNumT, MIPS32_MAX_FP_ARG> FP64ArgInitializer;
79*03ce13f7SAndroid Build Coastguard Worker 
getRegClassName(RegClass C)80*03ce13f7SAndroid Build Coastguard Worker const char *getRegClassName(RegClass C) {
81*03ce13f7SAndroid Build Coastguard Worker   auto ClassNum = static_cast<RegClassMIPS32>(C);
82*03ce13f7SAndroid Build Coastguard Worker   assert(ClassNum < RCMIPS32_NUM);
83*03ce13f7SAndroid Build Coastguard Worker   switch (ClassNum) {
84*03ce13f7SAndroid Build Coastguard Worker   default:
85*03ce13f7SAndroid Build Coastguard Worker     assert(C < RC_Target);
86*03ce13f7SAndroid Build Coastguard Worker     return regClassString(C);
87*03ce13f7SAndroid Build Coastguard Worker     // Add handling of new register classes below.
88*03ce13f7SAndroid Build Coastguard Worker   }
89*03ce13f7SAndroid Build Coastguard Worker }
90*03ce13f7SAndroid Build Coastguard Worker 
91*03ce13f7SAndroid Build Coastguard Worker // Stack alignment
92*03ce13f7SAndroid Build Coastguard Worker constexpr uint32_t MIPS32_STACK_ALIGNMENT_BYTES = 16;
93*03ce13f7SAndroid Build Coastguard Worker 
94*03ce13f7SAndroid Build Coastguard Worker // Value is in bytes. Return Value adjusted to the next highest multiple of the
95*03ce13f7SAndroid Build Coastguard Worker // stack alignment required for the given type.
applyStackAlignmentTy(uint32_t Value,Type Ty)96*03ce13f7SAndroid Build Coastguard Worker uint32_t applyStackAlignmentTy(uint32_t Value, Type Ty) {
97*03ce13f7SAndroid Build Coastguard Worker   size_t typeAlignInBytes = typeWidthInBytes(Ty);
98*03ce13f7SAndroid Build Coastguard Worker   // Vectors are stored on stack with the same alignment as that of int type
99*03ce13f7SAndroid Build Coastguard Worker   if (isVectorType(Ty))
100*03ce13f7SAndroid Build Coastguard Worker     typeAlignInBytes = typeWidthInBytes(IceType_i64);
101*03ce13f7SAndroid Build Coastguard Worker   return Utils::applyAlignment(Value, typeAlignInBytes);
102*03ce13f7SAndroid Build Coastguard Worker }
103*03ce13f7SAndroid Build Coastguard Worker 
104*03ce13f7SAndroid Build Coastguard Worker // Value is in bytes. Return Value adjusted to the next highest multiple of the
105*03ce13f7SAndroid Build Coastguard Worker // stack alignment.
applyStackAlignment(uint32_t Value)106*03ce13f7SAndroid Build Coastguard Worker uint32_t applyStackAlignment(uint32_t Value) {
107*03ce13f7SAndroid Build Coastguard Worker   return Utils::applyAlignment(Value, MIPS32_STACK_ALIGNMENT_BYTES);
108*03ce13f7SAndroid Build Coastguard Worker }
109*03ce13f7SAndroid Build Coastguard Worker 
110*03ce13f7SAndroid Build Coastguard Worker } // end of anonymous namespace
111*03ce13f7SAndroid Build Coastguard Worker 
TargetMIPS32(Cfg * Func)112*03ce13f7SAndroid Build Coastguard Worker TargetMIPS32::TargetMIPS32(Cfg *Func) : TargetLowering(Func) {}
113*03ce13f7SAndroid Build Coastguard Worker 
assignVarStackSlots(VarList & SortedSpilledVariables,size_t SpillAreaPaddingBytes,size_t SpillAreaSizeBytes,size_t GlobalsAndSubsequentPaddingSize)114*03ce13f7SAndroid Build Coastguard Worker void TargetMIPS32::assignVarStackSlots(VarList &SortedSpilledVariables,
115*03ce13f7SAndroid Build Coastguard Worker                                        size_t SpillAreaPaddingBytes,
116*03ce13f7SAndroid Build Coastguard Worker                                        size_t SpillAreaSizeBytes,
117*03ce13f7SAndroid Build Coastguard Worker                                        size_t GlobalsAndSubsequentPaddingSize) {
118*03ce13f7SAndroid Build Coastguard Worker   const VariablesMetadata *VMetadata = Func->getVMetadata();
119*03ce13f7SAndroid Build Coastguard Worker   size_t GlobalsSpaceUsed = SpillAreaPaddingBytes;
120*03ce13f7SAndroid Build Coastguard Worker   size_t NextStackOffset = SpillAreaPaddingBytes;
121*03ce13f7SAndroid Build Coastguard Worker   CfgVector<size_t> LocalsSize(Func->getNumNodes());
122*03ce13f7SAndroid Build Coastguard Worker   const bool SimpleCoalescing = !callsReturnsTwice();
123*03ce13f7SAndroid Build Coastguard Worker   for (Variable *Var : SortedSpilledVariables) {
124*03ce13f7SAndroid Build Coastguard Worker     size_t Increment = typeWidthInBytesOnStack(Var->getType());
125*03ce13f7SAndroid Build Coastguard Worker     if (SimpleCoalescing && VMetadata->isTracked(Var)) {
126*03ce13f7SAndroid Build Coastguard Worker       if (VMetadata->isMultiBlock(Var)) {
127*03ce13f7SAndroid Build Coastguard Worker         GlobalsSpaceUsed += Increment;
128*03ce13f7SAndroid Build Coastguard Worker         NextStackOffset = GlobalsSpaceUsed;
129*03ce13f7SAndroid Build Coastguard Worker       } else {
130*03ce13f7SAndroid Build Coastguard Worker         SizeT NodeIndex = VMetadata->getLocalUseNode(Var)->getIndex();
131*03ce13f7SAndroid Build Coastguard Worker         LocalsSize[NodeIndex] += Increment;
132*03ce13f7SAndroid Build Coastguard Worker         NextStackOffset = SpillAreaPaddingBytes +
133*03ce13f7SAndroid Build Coastguard Worker                           GlobalsAndSubsequentPaddingSize +
134*03ce13f7SAndroid Build Coastguard Worker                           LocalsSize[NodeIndex];
135*03ce13f7SAndroid Build Coastguard Worker       }
136*03ce13f7SAndroid Build Coastguard Worker     } else {
137*03ce13f7SAndroid Build Coastguard Worker       NextStackOffset += Increment;
138*03ce13f7SAndroid Build Coastguard Worker     }
139*03ce13f7SAndroid Build Coastguard Worker     Var->setStackOffset(SpillAreaSizeBytes - NextStackOffset);
140*03ce13f7SAndroid Build Coastguard Worker   }
141*03ce13f7SAndroid Build Coastguard Worker }
142*03ce13f7SAndroid Build Coastguard Worker 
staticInit(GlobalContext * Ctx)143*03ce13f7SAndroid Build Coastguard Worker void TargetMIPS32::staticInit(GlobalContext *Ctx) {
144*03ce13f7SAndroid Build Coastguard Worker   (void)Ctx;
145*03ce13f7SAndroid Build Coastguard Worker   RegNumT::setLimit(RegMIPS32::Reg_NUM);
146*03ce13f7SAndroid Build Coastguard Worker   SmallBitVector IntegerRegisters(RegMIPS32::Reg_NUM);
147*03ce13f7SAndroid Build Coastguard Worker   SmallBitVector I64PairRegisters(RegMIPS32::Reg_NUM);
148*03ce13f7SAndroid Build Coastguard Worker   SmallBitVector Float32Registers(RegMIPS32::Reg_NUM);
149*03ce13f7SAndroid Build Coastguard Worker   SmallBitVector Float64Registers(RegMIPS32::Reg_NUM);
150*03ce13f7SAndroid Build Coastguard Worker   SmallBitVector VectorRegisters(RegMIPS32::Reg_NUM);
151*03ce13f7SAndroid Build Coastguard Worker   SmallBitVector InvalidRegisters(RegMIPS32::Reg_NUM);
152*03ce13f7SAndroid Build Coastguard Worker #define X(val, encode, name, scratch, preserved, stackptr, frameptr, isInt,    \
153*03ce13f7SAndroid Build Coastguard Worker           isI64Pair, isFP32, isFP64, isVec128, alias_init)                     \
154*03ce13f7SAndroid Build Coastguard Worker   IntegerRegisters[RegMIPS32::val] = isInt;                                    \
155*03ce13f7SAndroid Build Coastguard Worker   I64PairRegisters[RegMIPS32::val] = isI64Pair;                                \
156*03ce13f7SAndroid Build Coastguard Worker   Float32Registers[RegMIPS32::val] = isFP32;                                   \
157*03ce13f7SAndroid Build Coastguard Worker   Float64Registers[RegMIPS32::val] = isFP64;                                   \
158*03ce13f7SAndroid Build Coastguard Worker   VectorRegisters[RegMIPS32::val] = isVec128;                                  \
159*03ce13f7SAndroid Build Coastguard Worker   RegisterAliases[RegMIPS32::val].resize(RegMIPS32::Reg_NUM);                  \
160*03ce13f7SAndroid Build Coastguard Worker   for (SizeT RegAlias : alias_init) {                                          \
161*03ce13f7SAndroid Build Coastguard Worker     assert(!RegisterAliases[RegMIPS32::val][RegAlias] &&                       \
162*03ce13f7SAndroid Build Coastguard Worker            "Duplicate alias for " #val);                                       \
163*03ce13f7SAndroid Build Coastguard Worker     RegisterAliases[RegMIPS32::val].set(RegAlias);                             \
164*03ce13f7SAndroid Build Coastguard Worker   }                                                                            \
165*03ce13f7SAndroid Build Coastguard Worker   RegisterAliases[RegMIPS32::val].resize(RegMIPS32::Reg_NUM);                  \
166*03ce13f7SAndroid Build Coastguard Worker   assert(RegisterAliases[RegMIPS32::val][RegMIPS32::val]);
167*03ce13f7SAndroid Build Coastguard Worker   REGMIPS32_TABLE;
168*03ce13f7SAndroid Build Coastguard Worker #undef X
169*03ce13f7SAndroid Build Coastguard Worker 
170*03ce13f7SAndroid Build Coastguard Worker   // TODO(mohit.bhakkad): Change these inits once we provide argument related
171*03ce13f7SAndroid Build Coastguard Worker   // field in register tables
172*03ce13f7SAndroid Build Coastguard Worker   for (size_t i = 0; i < MIPS32_MAX_GPR_ARG; i++)
173*03ce13f7SAndroid Build Coastguard Worker     GPRArgInitializer[i] = RegNumT::fixme(RegMIPS32::Reg_A0 + i);
174*03ce13f7SAndroid Build Coastguard Worker 
175*03ce13f7SAndroid Build Coastguard Worker   for (size_t i = 0; i < MIPS32_MAX_GPR_ARG / 2; i++)
176*03ce13f7SAndroid Build Coastguard Worker     I64ArgInitializer[i] = RegNumT::fixme(RegMIPS32::Reg_A0A1 + i);
177*03ce13f7SAndroid Build Coastguard Worker 
178*03ce13f7SAndroid Build Coastguard Worker   for (size_t i = 0; i < MIPS32_MAX_FP_ARG; i++) {
179*03ce13f7SAndroid Build Coastguard Worker     FP32ArgInitializer[i] = RegNumT::fixme(RegMIPS32::Reg_F12 + i * 2);
180*03ce13f7SAndroid Build Coastguard Worker     FP64ArgInitializer[i] = RegNumT::fixme(RegMIPS32::Reg_F12F13 + i);
181*03ce13f7SAndroid Build Coastguard Worker   }
182*03ce13f7SAndroid Build Coastguard Worker 
183*03ce13f7SAndroid Build Coastguard Worker   TypeToRegisterSet[IceType_void] = InvalidRegisters;
184*03ce13f7SAndroid Build Coastguard Worker   TypeToRegisterSet[IceType_i1] = IntegerRegisters;
185*03ce13f7SAndroid Build Coastguard Worker   TypeToRegisterSet[IceType_i8] = IntegerRegisters;
186*03ce13f7SAndroid Build Coastguard Worker   TypeToRegisterSet[IceType_i16] = IntegerRegisters;
187*03ce13f7SAndroid Build Coastguard Worker   TypeToRegisterSet[IceType_i32] = IntegerRegisters;
188*03ce13f7SAndroid Build Coastguard Worker   TypeToRegisterSet[IceType_i64] = IntegerRegisters;
189*03ce13f7SAndroid Build Coastguard Worker   TypeToRegisterSet[IceType_f32] = Float32Registers;
190*03ce13f7SAndroid Build Coastguard Worker   TypeToRegisterSet[IceType_f64] = Float64Registers;
191*03ce13f7SAndroid Build Coastguard Worker   TypeToRegisterSet[IceType_v4i1] = VectorRegisters;
192*03ce13f7SAndroid Build Coastguard Worker   TypeToRegisterSet[IceType_v8i1] = VectorRegisters;
193*03ce13f7SAndroid Build Coastguard Worker   TypeToRegisterSet[IceType_v16i1] = VectorRegisters;
194*03ce13f7SAndroid Build Coastguard Worker   TypeToRegisterSet[IceType_v16i8] = VectorRegisters;
195*03ce13f7SAndroid Build Coastguard Worker   TypeToRegisterSet[IceType_v8i16] = VectorRegisters;
196*03ce13f7SAndroid Build Coastguard Worker   TypeToRegisterSet[IceType_v4i32] = VectorRegisters;
197*03ce13f7SAndroid Build Coastguard Worker   TypeToRegisterSet[IceType_v4f32] = VectorRegisters;
198*03ce13f7SAndroid Build Coastguard Worker 
199*03ce13f7SAndroid Build Coastguard Worker   for (size_t i = 0; i < llvm::array_lengthof(TypeToRegisterSet); ++i)
200*03ce13f7SAndroid Build Coastguard Worker     TypeToRegisterSetUnfiltered[i] = TypeToRegisterSet[i];
201*03ce13f7SAndroid Build Coastguard Worker 
202*03ce13f7SAndroid Build Coastguard Worker   filterTypeToRegisterSet(Ctx, RegMIPS32::Reg_NUM, TypeToRegisterSet,
203*03ce13f7SAndroid Build Coastguard Worker                           llvm::array_lengthof(TypeToRegisterSet),
204*03ce13f7SAndroid Build Coastguard Worker                           RegMIPS32::getRegName, getRegClassName);
205*03ce13f7SAndroid Build Coastguard Worker }
206*03ce13f7SAndroid Build Coastguard Worker 
unsetIfNonLeafFunc()207*03ce13f7SAndroid Build Coastguard Worker void TargetMIPS32::unsetIfNonLeafFunc() {
208*03ce13f7SAndroid Build Coastguard Worker   for (CfgNode *Node : Func->getNodes()) {
209*03ce13f7SAndroid Build Coastguard Worker     for (Inst &Instr : Node->getInsts()) {
210*03ce13f7SAndroid Build Coastguard Worker       if (llvm::isa<InstCall>(&Instr)) {
211*03ce13f7SAndroid Build Coastguard Worker         // Unset MaybeLeafFunc if call instruction exists.
212*03ce13f7SAndroid Build Coastguard Worker         MaybeLeafFunc = false;
213*03ce13f7SAndroid Build Coastguard Worker         return;
214*03ce13f7SAndroid Build Coastguard Worker       }
215*03ce13f7SAndroid Build Coastguard Worker     }
216*03ce13f7SAndroid Build Coastguard Worker   }
217*03ce13f7SAndroid Build Coastguard Worker }
218*03ce13f7SAndroid Build Coastguard Worker 
getStackAlignment() const219*03ce13f7SAndroid Build Coastguard Worker uint32_t TargetMIPS32::getStackAlignment() const {
220*03ce13f7SAndroid Build Coastguard Worker   return MIPS32_STACK_ALIGNMENT_BYTES;
221*03ce13f7SAndroid Build Coastguard Worker }
222*03ce13f7SAndroid Build Coastguard Worker 
getCallStackArgumentsSizeBytes(const InstCall * Call)223*03ce13f7SAndroid Build Coastguard Worker uint32_t TargetMIPS32::getCallStackArgumentsSizeBytes(const InstCall *Call) {
224*03ce13f7SAndroid Build Coastguard Worker   TargetMIPS32::CallingConv CC;
225*03ce13f7SAndroid Build Coastguard Worker   size_t OutArgsSizeBytes = 0;
226*03ce13f7SAndroid Build Coastguard Worker   Variable *Dest = Call->getDest();
227*03ce13f7SAndroid Build Coastguard Worker   bool PartialOnStack = false;
228*03ce13f7SAndroid Build Coastguard Worker   if (Dest != nullptr && isVectorFloatingType(Dest->getType())) {
229*03ce13f7SAndroid Build Coastguard Worker     CC.discardReg(RegMIPS32::Reg_A0);
230*03ce13f7SAndroid Build Coastguard Worker     // Next vector is partially on stack
231*03ce13f7SAndroid Build Coastguard Worker     PartialOnStack = true;
232*03ce13f7SAndroid Build Coastguard Worker   }
233*03ce13f7SAndroid Build Coastguard Worker   for (SizeT i = 0, NumArgs = Call->getNumArgs(); i < NumArgs; ++i) {
234*03ce13f7SAndroid Build Coastguard Worker     Operand *Arg = legalizeUndef(Call->getArg(i));
235*03ce13f7SAndroid Build Coastguard Worker     const Type Ty = Arg->getType();
236*03ce13f7SAndroid Build Coastguard Worker     RegNumT RegNum;
237*03ce13f7SAndroid Build Coastguard Worker     if (CC.argInReg(Ty, i, &RegNum)) {
238*03ce13f7SAndroid Build Coastguard Worker       // If PartialOnStack is true and if this is a vector type then last two
239*03ce13f7SAndroid Build Coastguard Worker       // elements are on stack
240*03ce13f7SAndroid Build Coastguard Worker       if (PartialOnStack && isVectorType(Ty)) {
241*03ce13f7SAndroid Build Coastguard Worker         OutArgsSizeBytes = applyStackAlignmentTy(OutArgsSizeBytes, IceType_i64);
242*03ce13f7SAndroid Build Coastguard Worker         OutArgsSizeBytes += typeWidthInBytesOnStack(IceType_i32) * 2;
243*03ce13f7SAndroid Build Coastguard Worker       }
244*03ce13f7SAndroid Build Coastguard Worker       continue;
245*03ce13f7SAndroid Build Coastguard Worker     }
246*03ce13f7SAndroid Build Coastguard Worker     OutArgsSizeBytes = applyStackAlignmentTy(OutArgsSizeBytes, Ty);
247*03ce13f7SAndroid Build Coastguard Worker     OutArgsSizeBytes += typeWidthInBytesOnStack(Ty);
248*03ce13f7SAndroid Build Coastguard Worker   }
249*03ce13f7SAndroid Build Coastguard Worker   // Add size of argument save area
250*03ce13f7SAndroid Build Coastguard Worker   constexpr int BytesPerStackArg = 4;
251*03ce13f7SAndroid Build Coastguard Worker   OutArgsSizeBytes += MIPS32_MAX_GPR_ARG * BytesPerStackArg;
252*03ce13f7SAndroid Build Coastguard Worker   return applyStackAlignment(OutArgsSizeBytes);
253*03ce13f7SAndroid Build Coastguard Worker }
254*03ce13f7SAndroid Build Coastguard Worker 
255*03ce13f7SAndroid Build Coastguard Worker namespace {
getConstantMemoryOrder(Operand * Opnd)256*03ce13f7SAndroid Build Coastguard Worker inline uint64_t getConstantMemoryOrder(Operand *Opnd) {
257*03ce13f7SAndroid Build Coastguard Worker   if (auto *Integer = llvm::dyn_cast<ConstantInteger32>(Opnd))
258*03ce13f7SAndroid Build Coastguard Worker     return Integer->getValue();
259*03ce13f7SAndroid Build Coastguard Worker   return Intrinsics::MemoryOrderInvalid;
260*03ce13f7SAndroid Build Coastguard Worker }
261*03ce13f7SAndroid Build Coastguard Worker } // namespace
262*03ce13f7SAndroid Build Coastguard Worker 
genTargetHelperCallFor(Inst * Instr)263*03ce13f7SAndroid Build Coastguard Worker void TargetMIPS32::genTargetHelperCallFor(Inst *Instr) {
264*03ce13f7SAndroid Build Coastguard Worker   constexpr bool NoTailCall = false;
265*03ce13f7SAndroid Build Coastguard Worker   constexpr bool IsTargetHelperCall = true;
266*03ce13f7SAndroid Build Coastguard Worker   Variable *Dest = Instr->getDest();
267*03ce13f7SAndroid Build Coastguard Worker   const Type DestTy = Dest ? Dest->getType() : IceType_void;
268*03ce13f7SAndroid Build Coastguard Worker 
269*03ce13f7SAndroid Build Coastguard Worker   switch (Instr->getKind()) {
270*03ce13f7SAndroid Build Coastguard Worker   default:
271*03ce13f7SAndroid Build Coastguard Worker     return;
272*03ce13f7SAndroid Build Coastguard Worker   case Inst::Select: {
273*03ce13f7SAndroid Build Coastguard Worker     if (isVectorType(DestTy)) {
274*03ce13f7SAndroid Build Coastguard Worker       Operand *SrcT = llvm::cast<InstSelect>(Instr)->getTrueOperand();
275*03ce13f7SAndroid Build Coastguard Worker       Operand *SrcF = llvm::cast<InstSelect>(Instr)->getFalseOperand();
276*03ce13f7SAndroid Build Coastguard Worker       Operand *Cond = llvm::cast<InstSelect>(Instr)->getCondition();
277*03ce13f7SAndroid Build Coastguard Worker       Variable *T = Func->makeVariable(DestTy);
278*03ce13f7SAndroid Build Coastguard Worker       auto *Undef = ConstantUndef::create(Ctx, DestTy);
279*03ce13f7SAndroid Build Coastguard Worker       Context.insert<InstAssign>(T, Undef);
280*03ce13f7SAndroid Build Coastguard Worker       auto *VarVecOn32 = llvm::cast<VariableVecOn32>(T);
281*03ce13f7SAndroid Build Coastguard Worker       VarVecOn32->initVecElement(Func);
282*03ce13f7SAndroid Build Coastguard Worker       for (SizeT I = 0; I < typeNumElements(DestTy); ++I) {
283*03ce13f7SAndroid Build Coastguard Worker         auto *Index = Ctx->getConstantInt32(I);
284*03ce13f7SAndroid Build Coastguard Worker         auto *OpC = Func->makeVariable(typeElementType(Cond->getType()));
285*03ce13f7SAndroid Build Coastguard Worker         Context.insert<InstExtractElement>(OpC, Cond, Index);
286*03ce13f7SAndroid Build Coastguard Worker         auto *OpT = Func->makeVariable(typeElementType(DestTy));
287*03ce13f7SAndroid Build Coastguard Worker         Context.insert<InstExtractElement>(OpT, SrcT, Index);
288*03ce13f7SAndroid Build Coastguard Worker         auto *OpF = Func->makeVariable(typeElementType(DestTy));
289*03ce13f7SAndroid Build Coastguard Worker         Context.insert<InstExtractElement>(OpF, SrcF, Index);
290*03ce13f7SAndroid Build Coastguard Worker         auto *Dst = Func->makeVariable(typeElementType(DestTy));
291*03ce13f7SAndroid Build Coastguard Worker         Variable *DestT = Func->makeVariable(DestTy);
292*03ce13f7SAndroid Build Coastguard Worker         Context.insert<InstSelect>(Dst, OpC, OpT, OpF);
293*03ce13f7SAndroid Build Coastguard Worker         Context.insert<InstInsertElement>(DestT, T, Dst, Index);
294*03ce13f7SAndroid Build Coastguard Worker         T = DestT;
295*03ce13f7SAndroid Build Coastguard Worker       }
296*03ce13f7SAndroid Build Coastguard Worker       Context.insert<InstAssign>(Dest, T);
297*03ce13f7SAndroid Build Coastguard Worker       Instr->setDeleted();
298*03ce13f7SAndroid Build Coastguard Worker     }
299*03ce13f7SAndroid Build Coastguard Worker     return;
300*03ce13f7SAndroid Build Coastguard Worker   }
301*03ce13f7SAndroid Build Coastguard Worker   case Inst::Fcmp: {
302*03ce13f7SAndroid Build Coastguard Worker     if (isVectorType(DestTy)) {
303*03ce13f7SAndroid Build Coastguard Worker       InstFcmp::FCond Cond = llvm::cast<InstFcmp>(Instr)->getCondition();
304*03ce13f7SAndroid Build Coastguard Worker       Operand *Src0 = Instr->getSrc(0);
305*03ce13f7SAndroid Build Coastguard Worker       Operand *Src1 = Instr->getSrc(1);
306*03ce13f7SAndroid Build Coastguard Worker       Variable *T = Func->makeVariable(IceType_v4f32);
307*03ce13f7SAndroid Build Coastguard Worker       auto *Undef = ConstantUndef::create(Ctx, IceType_v4f32);
308*03ce13f7SAndroid Build Coastguard Worker       Context.insert<InstAssign>(T, Undef);
309*03ce13f7SAndroid Build Coastguard Worker       auto *VarVecOn32 = llvm::cast<VariableVecOn32>(T);
310*03ce13f7SAndroid Build Coastguard Worker       VarVecOn32->initVecElement(Func);
311*03ce13f7SAndroid Build Coastguard Worker       for (SizeT I = 0; I < typeNumElements(IceType_v4f32); ++I) {
312*03ce13f7SAndroid Build Coastguard Worker         auto *Index = Ctx->getConstantInt32(I);
313*03ce13f7SAndroid Build Coastguard Worker         auto *Op0 = Func->makeVariable(IceType_f32);
314*03ce13f7SAndroid Build Coastguard Worker         Context.insert<InstExtractElement>(Op0, Src0, Index);
315*03ce13f7SAndroid Build Coastguard Worker         auto *Op1 = Func->makeVariable(IceType_f32);
316*03ce13f7SAndroid Build Coastguard Worker         Context.insert<InstExtractElement>(Op1, Src1, Index);
317*03ce13f7SAndroid Build Coastguard Worker         auto *Dst = Func->makeVariable(IceType_f32);
318*03ce13f7SAndroid Build Coastguard Worker         Variable *DestT = Func->makeVariable(IceType_v4f32);
319*03ce13f7SAndroid Build Coastguard Worker         Context.insert<InstFcmp>(Cond, Dst, Op0, Op1);
320*03ce13f7SAndroid Build Coastguard Worker         Context.insert<InstInsertElement>(DestT, T, Dst, Index);
321*03ce13f7SAndroid Build Coastguard Worker         T = DestT;
322*03ce13f7SAndroid Build Coastguard Worker       }
323*03ce13f7SAndroid Build Coastguard Worker       Context.insert<InstAssign>(Dest, T);
324*03ce13f7SAndroid Build Coastguard Worker       Instr->setDeleted();
325*03ce13f7SAndroid Build Coastguard Worker     }
326*03ce13f7SAndroid Build Coastguard Worker     return;
327*03ce13f7SAndroid Build Coastguard Worker   }
328*03ce13f7SAndroid Build Coastguard Worker   case Inst::Icmp: {
329*03ce13f7SAndroid Build Coastguard Worker     if (isVectorType(DestTy)) {
330*03ce13f7SAndroid Build Coastguard Worker       InstIcmp::ICond Cond = llvm::cast<InstIcmp>(Instr)->getCondition();
331*03ce13f7SAndroid Build Coastguard Worker       Operand *Src0 = Instr->getSrc(0);
332*03ce13f7SAndroid Build Coastguard Worker       Operand *Src1 = Instr->getSrc(1);
333*03ce13f7SAndroid Build Coastguard Worker       const Type SrcType = Src0->getType();
334*03ce13f7SAndroid Build Coastguard Worker       Variable *T = Func->makeVariable(DestTy);
335*03ce13f7SAndroid Build Coastguard Worker       auto *Undef = ConstantUndef::create(Ctx, DestTy);
336*03ce13f7SAndroid Build Coastguard Worker       Context.insert<InstAssign>(T, Undef);
337*03ce13f7SAndroid Build Coastguard Worker       auto *VarVecOn32 = llvm::cast<VariableVecOn32>(T);
338*03ce13f7SAndroid Build Coastguard Worker       VarVecOn32->initVecElement(Func);
339*03ce13f7SAndroid Build Coastguard Worker       for (SizeT I = 0; I < typeNumElements(SrcType); ++I) {
340*03ce13f7SAndroid Build Coastguard Worker         auto *Index = Ctx->getConstantInt32(I);
341*03ce13f7SAndroid Build Coastguard Worker         auto *Op0 = Func->makeVariable(typeElementType(SrcType));
342*03ce13f7SAndroid Build Coastguard Worker         Context.insert<InstExtractElement>(Op0, Src0, Index);
343*03ce13f7SAndroid Build Coastguard Worker         auto *Op1 = Func->makeVariable(typeElementType(SrcType));
344*03ce13f7SAndroid Build Coastguard Worker         Context.insert<InstExtractElement>(Op1, Src1, Index);
345*03ce13f7SAndroid Build Coastguard Worker         auto *Dst = Func->makeVariable(typeElementType(DestTy));
346*03ce13f7SAndroid Build Coastguard Worker         Variable *DestT = Func->makeVariable(DestTy);
347*03ce13f7SAndroid Build Coastguard Worker         Context.insert<InstIcmp>(Cond, Dst, Op0, Op1);
348*03ce13f7SAndroid Build Coastguard Worker         Context.insert<InstInsertElement>(DestT, T, Dst, Index);
349*03ce13f7SAndroid Build Coastguard Worker         T = DestT;
350*03ce13f7SAndroid Build Coastguard Worker       }
351*03ce13f7SAndroid Build Coastguard Worker       Context.insert<InstAssign>(Dest, T);
352*03ce13f7SAndroid Build Coastguard Worker       Instr->setDeleted();
353*03ce13f7SAndroid Build Coastguard Worker     }
354*03ce13f7SAndroid Build Coastguard Worker     return;
355*03ce13f7SAndroid Build Coastguard Worker   }
356*03ce13f7SAndroid Build Coastguard Worker   case Inst::Arithmetic: {
357*03ce13f7SAndroid Build Coastguard Worker     const InstArithmetic::OpKind Op =
358*03ce13f7SAndroid Build Coastguard Worker         llvm::cast<InstArithmetic>(Instr)->getOp();
359*03ce13f7SAndroid Build Coastguard Worker     if (isVectorType(DestTy)) {
360*03ce13f7SAndroid Build Coastguard Worker       scalarizeArithmetic(Op, Dest, Instr->getSrc(0), Instr->getSrc(1));
361*03ce13f7SAndroid Build Coastguard Worker       Instr->setDeleted();
362*03ce13f7SAndroid Build Coastguard Worker       return;
363*03ce13f7SAndroid Build Coastguard Worker     }
364*03ce13f7SAndroid Build Coastguard Worker     switch (DestTy) {
365*03ce13f7SAndroid Build Coastguard Worker     default:
366*03ce13f7SAndroid Build Coastguard Worker       return;
367*03ce13f7SAndroid Build Coastguard Worker     case IceType_i64: {
368*03ce13f7SAndroid Build Coastguard Worker       RuntimeHelper HelperID = RuntimeHelper::H_Num;
369*03ce13f7SAndroid Build Coastguard Worker       switch (Op) {
370*03ce13f7SAndroid Build Coastguard Worker       default:
371*03ce13f7SAndroid Build Coastguard Worker         return;
372*03ce13f7SAndroid Build Coastguard Worker       case InstArithmetic::Udiv:
373*03ce13f7SAndroid Build Coastguard Worker         HelperID = RuntimeHelper::H_udiv_i64;
374*03ce13f7SAndroid Build Coastguard Worker         break;
375*03ce13f7SAndroid Build Coastguard Worker       case InstArithmetic::Sdiv:
376*03ce13f7SAndroid Build Coastguard Worker         HelperID = RuntimeHelper::H_sdiv_i64;
377*03ce13f7SAndroid Build Coastguard Worker         break;
378*03ce13f7SAndroid Build Coastguard Worker       case InstArithmetic::Urem:
379*03ce13f7SAndroid Build Coastguard Worker         HelperID = RuntimeHelper::H_urem_i64;
380*03ce13f7SAndroid Build Coastguard Worker         break;
381*03ce13f7SAndroid Build Coastguard Worker       case InstArithmetic::Srem:
382*03ce13f7SAndroid Build Coastguard Worker         HelperID = RuntimeHelper::H_srem_i64;
383*03ce13f7SAndroid Build Coastguard Worker         break;
384*03ce13f7SAndroid Build Coastguard Worker       }
385*03ce13f7SAndroid Build Coastguard Worker 
386*03ce13f7SAndroid Build Coastguard Worker       if (HelperID == RuntimeHelper::H_Num) {
387*03ce13f7SAndroid Build Coastguard Worker         return;
388*03ce13f7SAndroid Build Coastguard Worker       }
389*03ce13f7SAndroid Build Coastguard Worker 
390*03ce13f7SAndroid Build Coastguard Worker       Operand *TargetHelper = Ctx->getRuntimeHelperFunc(HelperID);
391*03ce13f7SAndroid Build Coastguard Worker       constexpr SizeT MaxArgs = 2;
392*03ce13f7SAndroid Build Coastguard Worker       auto *Call = Context.insert<InstCall>(MaxArgs, Dest, TargetHelper,
393*03ce13f7SAndroid Build Coastguard Worker                                             NoTailCall, IsTargetHelperCall);
394*03ce13f7SAndroid Build Coastguard Worker       Call->addArg(Instr->getSrc(0));
395*03ce13f7SAndroid Build Coastguard Worker       Call->addArg(Instr->getSrc(1));
396*03ce13f7SAndroid Build Coastguard Worker       Instr->setDeleted();
397*03ce13f7SAndroid Build Coastguard Worker       return;
398*03ce13f7SAndroid Build Coastguard Worker     }
399*03ce13f7SAndroid Build Coastguard Worker     case IceType_f32:
400*03ce13f7SAndroid Build Coastguard Worker     case IceType_f64: {
401*03ce13f7SAndroid Build Coastguard Worker       if (Op != InstArithmetic::Frem) {
402*03ce13f7SAndroid Build Coastguard Worker         return;
403*03ce13f7SAndroid Build Coastguard Worker       }
404*03ce13f7SAndroid Build Coastguard Worker       constexpr SizeT MaxArgs = 2;
405*03ce13f7SAndroid Build Coastguard Worker       Operand *TargetHelper = Ctx->getRuntimeHelperFunc(
406*03ce13f7SAndroid Build Coastguard Worker           DestTy == IceType_f32 ? RuntimeHelper::H_frem_f32
407*03ce13f7SAndroid Build Coastguard Worker                                 : RuntimeHelper::H_frem_f64);
408*03ce13f7SAndroid Build Coastguard Worker       auto *Call = Context.insert<InstCall>(MaxArgs, Dest, TargetHelper,
409*03ce13f7SAndroid Build Coastguard Worker                                             NoTailCall, IsTargetHelperCall);
410*03ce13f7SAndroid Build Coastguard Worker       Call->addArg(Instr->getSrc(0));
411*03ce13f7SAndroid Build Coastguard Worker       Call->addArg(Instr->getSrc(1));
412*03ce13f7SAndroid Build Coastguard Worker       Instr->setDeleted();
413*03ce13f7SAndroid Build Coastguard Worker       return;
414*03ce13f7SAndroid Build Coastguard Worker     }
415*03ce13f7SAndroid Build Coastguard Worker     }
416*03ce13f7SAndroid Build Coastguard Worker     llvm::report_fatal_error("Control flow should never have reached here.");
417*03ce13f7SAndroid Build Coastguard Worker   }
418*03ce13f7SAndroid Build Coastguard Worker   case Inst::Cast: {
419*03ce13f7SAndroid Build Coastguard Worker     Operand *Src0 = Instr->getSrc(0);
420*03ce13f7SAndroid Build Coastguard Worker     const Type SrcTy = Src0->getType();
421*03ce13f7SAndroid Build Coastguard Worker     auto *CastInstr = llvm::cast<InstCast>(Instr);
422*03ce13f7SAndroid Build Coastguard Worker     const InstCast::OpKind CastKind = CastInstr->getCastKind();
423*03ce13f7SAndroid Build Coastguard Worker 
424*03ce13f7SAndroid Build Coastguard Worker     if (isVectorType(DestTy)) {
425*03ce13f7SAndroid Build Coastguard Worker       Variable *T = Func->makeVariable(DestTy);
426*03ce13f7SAndroid Build Coastguard Worker       auto *VarVecOn32 = llvm::cast<VariableVecOn32>(T);
427*03ce13f7SAndroid Build Coastguard Worker       VarVecOn32->initVecElement(Func);
428*03ce13f7SAndroid Build Coastguard Worker       auto *Undef = ConstantUndef::create(Ctx, DestTy);
429*03ce13f7SAndroid Build Coastguard Worker       Context.insert<InstAssign>(T, Undef);
430*03ce13f7SAndroid Build Coastguard Worker       for (SizeT I = 0; I < typeNumElements(DestTy); ++I) {
431*03ce13f7SAndroid Build Coastguard Worker         auto *Index = Ctx->getConstantInt32(I);
432*03ce13f7SAndroid Build Coastguard Worker         auto *Op = Func->makeVariable(typeElementType(SrcTy));
433*03ce13f7SAndroid Build Coastguard Worker         Context.insert<InstExtractElement>(Op, Src0, Index);
434*03ce13f7SAndroid Build Coastguard Worker         auto *Dst = Func->makeVariable(typeElementType(DestTy));
435*03ce13f7SAndroid Build Coastguard Worker         Variable *DestT = Func->makeVariable(DestTy);
436*03ce13f7SAndroid Build Coastguard Worker         Context.insert<InstCast>(CastKind, Dst, Op);
437*03ce13f7SAndroid Build Coastguard Worker         Context.insert<InstInsertElement>(DestT, T, Dst, Index);
438*03ce13f7SAndroid Build Coastguard Worker         T = DestT;
439*03ce13f7SAndroid Build Coastguard Worker       }
440*03ce13f7SAndroid Build Coastguard Worker       Context.insert<InstAssign>(Dest, T);
441*03ce13f7SAndroid Build Coastguard Worker       Instr->setDeleted();
442*03ce13f7SAndroid Build Coastguard Worker       return;
443*03ce13f7SAndroid Build Coastguard Worker     }
444*03ce13f7SAndroid Build Coastguard Worker 
445*03ce13f7SAndroid Build Coastguard Worker     switch (CastKind) {
446*03ce13f7SAndroid Build Coastguard Worker     default:
447*03ce13f7SAndroid Build Coastguard Worker       return;
448*03ce13f7SAndroid Build Coastguard Worker     case InstCast::Fptosi:
449*03ce13f7SAndroid Build Coastguard Worker     case InstCast::Fptoui: {
450*03ce13f7SAndroid Build Coastguard Worker       if ((DestTy != IceType_i32) && (DestTy != IceType_i64)) {
451*03ce13f7SAndroid Build Coastguard Worker         return;
452*03ce13f7SAndroid Build Coastguard Worker       }
453*03ce13f7SAndroid Build Coastguard Worker       const bool DestIs32 = DestTy == IceType_i32;
454*03ce13f7SAndroid Build Coastguard Worker       const bool DestIsSigned = CastKind == InstCast::Fptosi;
455*03ce13f7SAndroid Build Coastguard Worker       const bool Src0IsF32 = isFloat32Asserting32Or64(SrcTy);
456*03ce13f7SAndroid Build Coastguard Worker       RuntimeHelper RTHFunc = RuntimeHelper::H_Num;
457*03ce13f7SAndroid Build Coastguard Worker       if (DestIsSigned) {
458*03ce13f7SAndroid Build Coastguard Worker         if (DestIs32) {
459*03ce13f7SAndroid Build Coastguard Worker           return;
460*03ce13f7SAndroid Build Coastguard Worker         }
461*03ce13f7SAndroid Build Coastguard Worker         RTHFunc = Src0IsF32 ? RuntimeHelper::H_fptosi_f32_i64
462*03ce13f7SAndroid Build Coastguard Worker                             : RuntimeHelper::H_fptosi_f64_i64;
463*03ce13f7SAndroid Build Coastguard Worker       } else {
464*03ce13f7SAndroid Build Coastguard Worker         RTHFunc = Src0IsF32 ? (DestIs32 ? RuntimeHelper::H_fptoui_f32_i32
465*03ce13f7SAndroid Build Coastguard Worker                                         : RuntimeHelper::H_fptoui_f32_i64)
466*03ce13f7SAndroid Build Coastguard Worker                             : (DestIs32 ? RuntimeHelper::H_fptoui_f64_i32
467*03ce13f7SAndroid Build Coastguard Worker                                         : RuntimeHelper::H_fptoui_f64_i64);
468*03ce13f7SAndroid Build Coastguard Worker       }
469*03ce13f7SAndroid Build Coastguard Worker       Operand *TargetHelper = Ctx->getRuntimeHelperFunc(RTHFunc);
470*03ce13f7SAndroid Build Coastguard Worker       static constexpr SizeT MaxArgs = 1;
471*03ce13f7SAndroid Build Coastguard Worker       auto *Call = Context.insert<InstCall>(MaxArgs, Dest, TargetHelper,
472*03ce13f7SAndroid Build Coastguard Worker                                             NoTailCall, IsTargetHelperCall);
473*03ce13f7SAndroid Build Coastguard Worker       Call->addArg(Src0);
474*03ce13f7SAndroid Build Coastguard Worker       Instr->setDeleted();
475*03ce13f7SAndroid Build Coastguard Worker       return;
476*03ce13f7SAndroid Build Coastguard Worker     }
477*03ce13f7SAndroid Build Coastguard Worker     case InstCast::Sitofp:
478*03ce13f7SAndroid Build Coastguard Worker     case InstCast::Uitofp: {
479*03ce13f7SAndroid Build Coastguard Worker       if ((SrcTy != IceType_i32) && (SrcTy != IceType_i64)) {
480*03ce13f7SAndroid Build Coastguard Worker         return;
481*03ce13f7SAndroid Build Coastguard Worker       }
482*03ce13f7SAndroid Build Coastguard Worker       const bool SourceIs32 = SrcTy == IceType_i32;
483*03ce13f7SAndroid Build Coastguard Worker       const bool SourceIsSigned = CastKind == InstCast::Sitofp;
484*03ce13f7SAndroid Build Coastguard Worker       const bool DestIsF32 = isFloat32Asserting32Or64(DestTy);
485*03ce13f7SAndroid Build Coastguard Worker       RuntimeHelper RTHFunc = RuntimeHelper::H_Num;
486*03ce13f7SAndroid Build Coastguard Worker       if (SourceIsSigned) {
487*03ce13f7SAndroid Build Coastguard Worker         if (SourceIs32) {
488*03ce13f7SAndroid Build Coastguard Worker           return;
489*03ce13f7SAndroid Build Coastguard Worker         }
490*03ce13f7SAndroid Build Coastguard Worker         RTHFunc = DestIsF32 ? RuntimeHelper::H_sitofp_i64_f32
491*03ce13f7SAndroid Build Coastguard Worker                             : RuntimeHelper::H_sitofp_i64_f64;
492*03ce13f7SAndroid Build Coastguard Worker       } else {
493*03ce13f7SAndroid Build Coastguard Worker         RTHFunc = DestIsF32 ? (SourceIs32 ? RuntimeHelper::H_uitofp_i32_f32
494*03ce13f7SAndroid Build Coastguard Worker                                           : RuntimeHelper::H_uitofp_i64_f32)
495*03ce13f7SAndroid Build Coastguard Worker                             : (SourceIs32 ? RuntimeHelper::H_uitofp_i32_f64
496*03ce13f7SAndroid Build Coastguard Worker                                           : RuntimeHelper::H_uitofp_i64_f64);
497*03ce13f7SAndroid Build Coastguard Worker       }
498*03ce13f7SAndroid Build Coastguard Worker       Operand *TargetHelper = Ctx->getRuntimeHelperFunc(RTHFunc);
499*03ce13f7SAndroid Build Coastguard Worker       static constexpr SizeT MaxArgs = 1;
500*03ce13f7SAndroid Build Coastguard Worker       auto *Call = Context.insert<InstCall>(MaxArgs, Dest, TargetHelper,
501*03ce13f7SAndroid Build Coastguard Worker                                             NoTailCall, IsTargetHelperCall);
502*03ce13f7SAndroid Build Coastguard Worker       Call->addArg(Src0);
503*03ce13f7SAndroid Build Coastguard Worker       Instr->setDeleted();
504*03ce13f7SAndroid Build Coastguard Worker       return;
505*03ce13f7SAndroid Build Coastguard Worker     }
506*03ce13f7SAndroid Build Coastguard Worker     case InstCast::Bitcast: {
507*03ce13f7SAndroid Build Coastguard Worker       if (DestTy == SrcTy) {
508*03ce13f7SAndroid Build Coastguard Worker         return;
509*03ce13f7SAndroid Build Coastguard Worker       }
510*03ce13f7SAndroid Build Coastguard Worker       Variable *CallDest = Dest;
511*03ce13f7SAndroid Build Coastguard Worker       RuntimeHelper HelperID = RuntimeHelper::H_Num;
512*03ce13f7SAndroid Build Coastguard Worker       switch (DestTy) {
513*03ce13f7SAndroid Build Coastguard Worker       default:
514*03ce13f7SAndroid Build Coastguard Worker         return;
515*03ce13f7SAndroid Build Coastguard Worker       case IceType_i8:
516*03ce13f7SAndroid Build Coastguard Worker         assert(SrcTy == IceType_v8i1);
517*03ce13f7SAndroid Build Coastguard Worker         HelperID = RuntimeHelper::H_bitcast_8xi1_i8;
518*03ce13f7SAndroid Build Coastguard Worker         CallDest = Func->makeVariable(IceType_i32);
519*03ce13f7SAndroid Build Coastguard Worker         break;
520*03ce13f7SAndroid Build Coastguard Worker       case IceType_i16:
521*03ce13f7SAndroid Build Coastguard Worker         assert(SrcTy == IceType_v16i1);
522*03ce13f7SAndroid Build Coastguard Worker         HelperID = RuntimeHelper::H_bitcast_16xi1_i16;
523*03ce13f7SAndroid Build Coastguard Worker         CallDest = Func->makeVariable(IceType_i32);
524*03ce13f7SAndroid Build Coastguard Worker         break;
525*03ce13f7SAndroid Build Coastguard Worker       case IceType_v8i1: {
526*03ce13f7SAndroid Build Coastguard Worker         assert(SrcTy == IceType_i8);
527*03ce13f7SAndroid Build Coastguard Worker         HelperID = RuntimeHelper::H_bitcast_i8_8xi1;
528*03ce13f7SAndroid Build Coastguard Worker         Variable *Src0AsI32 = Func->makeVariable(stackSlotType());
529*03ce13f7SAndroid Build Coastguard Worker         // Arguments to functions are required to be at least 32 bits wide.
530*03ce13f7SAndroid Build Coastguard Worker         Context.insert<InstCast>(InstCast::Zext, Src0AsI32, Src0);
531*03ce13f7SAndroid Build Coastguard Worker         Src0 = Src0AsI32;
532*03ce13f7SAndroid Build Coastguard Worker       } break;
533*03ce13f7SAndroid Build Coastguard Worker       case IceType_v16i1: {
534*03ce13f7SAndroid Build Coastguard Worker         assert(SrcTy == IceType_i16);
535*03ce13f7SAndroid Build Coastguard Worker         HelperID = RuntimeHelper::H_bitcast_i16_16xi1;
536*03ce13f7SAndroid Build Coastguard Worker         Variable *Src0AsI32 = Func->makeVariable(stackSlotType());
537*03ce13f7SAndroid Build Coastguard Worker         // Arguments to functions are required to be at least 32 bits wide.
538*03ce13f7SAndroid Build Coastguard Worker         Context.insert<InstCast>(InstCast::Zext, Src0AsI32, Src0);
539*03ce13f7SAndroid Build Coastguard Worker         Src0 = Src0AsI32;
540*03ce13f7SAndroid Build Coastguard Worker       } break;
541*03ce13f7SAndroid Build Coastguard Worker       }
542*03ce13f7SAndroid Build Coastguard Worker       constexpr SizeT MaxSrcs = 1;
543*03ce13f7SAndroid Build Coastguard Worker       InstCall *Call = makeHelperCall(HelperID, CallDest, MaxSrcs);
544*03ce13f7SAndroid Build Coastguard Worker       Call->addArg(Src0);
545*03ce13f7SAndroid Build Coastguard Worker       Context.insert(Call);
546*03ce13f7SAndroid Build Coastguard Worker       // The PNaCl ABI disallows i8/i16 return types, so truncate the helper
547*03ce13f7SAndroid Build Coastguard Worker       // call result to the appropriate type as necessary.
548*03ce13f7SAndroid Build Coastguard Worker       if (CallDest->getType() != DestTy)
549*03ce13f7SAndroid Build Coastguard Worker         Context.insert<InstCast>(InstCast::Trunc, Dest, CallDest);
550*03ce13f7SAndroid Build Coastguard Worker       Instr->setDeleted();
551*03ce13f7SAndroid Build Coastguard Worker       return;
552*03ce13f7SAndroid Build Coastguard Worker     }
553*03ce13f7SAndroid Build Coastguard Worker     case InstCast::Trunc: {
554*03ce13f7SAndroid Build Coastguard Worker       if (DestTy == SrcTy) {
555*03ce13f7SAndroid Build Coastguard Worker         return;
556*03ce13f7SAndroid Build Coastguard Worker       }
557*03ce13f7SAndroid Build Coastguard Worker       if (!isVectorType(SrcTy)) {
558*03ce13f7SAndroid Build Coastguard Worker         return;
559*03ce13f7SAndroid Build Coastguard Worker       }
560*03ce13f7SAndroid Build Coastguard Worker       assert(typeNumElements(DestTy) == typeNumElements(SrcTy));
561*03ce13f7SAndroid Build Coastguard Worker       assert(typeElementType(DestTy) == IceType_i1);
562*03ce13f7SAndroid Build Coastguard Worker       assert(isVectorIntegerType(SrcTy));
563*03ce13f7SAndroid Build Coastguard Worker       return;
564*03ce13f7SAndroid Build Coastguard Worker     }
565*03ce13f7SAndroid Build Coastguard Worker     case InstCast::Sext:
566*03ce13f7SAndroid Build Coastguard Worker     case InstCast::Zext: {
567*03ce13f7SAndroid Build Coastguard Worker       if (DestTy == SrcTy) {
568*03ce13f7SAndroid Build Coastguard Worker         return;
569*03ce13f7SAndroid Build Coastguard Worker       }
570*03ce13f7SAndroid Build Coastguard Worker       if (!isVectorType(DestTy)) {
571*03ce13f7SAndroid Build Coastguard Worker         return;
572*03ce13f7SAndroid Build Coastguard Worker       }
573*03ce13f7SAndroid Build Coastguard Worker       assert(typeNumElements(DestTy) == typeNumElements(SrcTy));
574*03ce13f7SAndroid Build Coastguard Worker       assert(typeElementType(SrcTy) == IceType_i1);
575*03ce13f7SAndroid Build Coastguard Worker       assert(isVectorIntegerType(DestTy));
576*03ce13f7SAndroid Build Coastguard Worker       return;
577*03ce13f7SAndroid Build Coastguard Worker     }
578*03ce13f7SAndroid Build Coastguard Worker     }
579*03ce13f7SAndroid Build Coastguard Worker     llvm::report_fatal_error("Control flow should never have reached here.");
580*03ce13f7SAndroid Build Coastguard Worker   }
581*03ce13f7SAndroid Build Coastguard Worker   case Inst::Intrinsic: {
582*03ce13f7SAndroid Build Coastguard Worker     auto *Intrinsic = llvm::cast<InstIntrinsic>(Instr);
583*03ce13f7SAndroid Build Coastguard Worker     Intrinsics::IntrinsicID ID = Intrinsic->getIntrinsicID();
584*03ce13f7SAndroid Build Coastguard Worker     if (isVectorType(DestTy) && ID == Intrinsics::Fabs) {
585*03ce13f7SAndroid Build Coastguard Worker       Operand *Src0 = Intrinsic->getArg(0);
586*03ce13f7SAndroid Build Coastguard Worker       Intrinsics::IntrinsicInfo Info = Intrinsic->getIntrinsicInfo();
587*03ce13f7SAndroid Build Coastguard Worker 
588*03ce13f7SAndroid Build Coastguard Worker       Variable *T = Func->makeVariable(IceType_v4f32);
589*03ce13f7SAndroid Build Coastguard Worker       auto *Undef = ConstantUndef::create(Ctx, IceType_v4f32);
590*03ce13f7SAndroid Build Coastguard Worker       Context.insert<InstAssign>(T, Undef);
591*03ce13f7SAndroid Build Coastguard Worker       auto *VarVecOn32 = llvm::cast<VariableVecOn32>(T);
592*03ce13f7SAndroid Build Coastguard Worker       VarVecOn32->initVecElement(Func);
593*03ce13f7SAndroid Build Coastguard Worker 
594*03ce13f7SAndroid Build Coastguard Worker       for (SizeT i = 0; i < typeNumElements(IceType_v4f32); ++i) {
595*03ce13f7SAndroid Build Coastguard Worker         auto *Index = Ctx->getConstantInt32(i);
596*03ce13f7SAndroid Build Coastguard Worker         auto *Op = Func->makeVariable(IceType_f32);
597*03ce13f7SAndroid Build Coastguard Worker         Context.insert<InstExtractElement>(Op, Src0, Index);
598*03ce13f7SAndroid Build Coastguard Worker         auto *Res = Func->makeVariable(IceType_f32);
599*03ce13f7SAndroid Build Coastguard Worker         Variable *DestT = Func->makeVariable(IceType_v4f32);
600*03ce13f7SAndroid Build Coastguard Worker         auto *Intrinsic = Context.insert<InstIntrinsic>(1, Res, Info);
601*03ce13f7SAndroid Build Coastguard Worker         Intrinsic->addArg(Op);
602*03ce13f7SAndroid Build Coastguard Worker         Context.insert<InstInsertElement>(DestT, T, Res, Index);
603*03ce13f7SAndroid Build Coastguard Worker         T = DestT;
604*03ce13f7SAndroid Build Coastguard Worker       }
605*03ce13f7SAndroid Build Coastguard Worker 
606*03ce13f7SAndroid Build Coastguard Worker       Context.insert<InstAssign>(Dest, T);
607*03ce13f7SAndroid Build Coastguard Worker 
608*03ce13f7SAndroid Build Coastguard Worker       Instr->setDeleted();
609*03ce13f7SAndroid Build Coastguard Worker       return;
610*03ce13f7SAndroid Build Coastguard Worker     }
611*03ce13f7SAndroid Build Coastguard Worker     switch (ID) {
612*03ce13f7SAndroid Build Coastguard Worker     default:
613*03ce13f7SAndroid Build Coastguard Worker       return;
614*03ce13f7SAndroid Build Coastguard Worker     case Intrinsics::AtomicLoad: {
615*03ce13f7SAndroid Build Coastguard Worker       if (DestTy != IceType_i64)
616*03ce13f7SAndroid Build Coastguard Worker         return;
617*03ce13f7SAndroid Build Coastguard Worker       if (!Intrinsics::isMemoryOrderValid(
618*03ce13f7SAndroid Build Coastguard Worker               ID, getConstantMemoryOrder(Intrinsic->getArg(1)))) {
619*03ce13f7SAndroid Build Coastguard Worker         Func->setError("Unexpected memory ordering for AtomicLoad");
620*03ce13f7SAndroid Build Coastguard Worker         return;
621*03ce13f7SAndroid Build Coastguard Worker       }
622*03ce13f7SAndroid Build Coastguard Worker       Operand *Addr = Intrinsic->getArg(0);
623*03ce13f7SAndroid Build Coastguard Worker       Operand *TargetHelper = Ctx->getConstantExternSym(
624*03ce13f7SAndroid Build Coastguard Worker           Ctx->getGlobalString("__sync_val_compare_and_swap_8"));
625*03ce13f7SAndroid Build Coastguard Worker       static constexpr SizeT MaxArgs = 3;
626*03ce13f7SAndroid Build Coastguard Worker       auto *_0 = Ctx->getConstantZero(IceType_i64);
627*03ce13f7SAndroid Build Coastguard Worker       auto *Call = Context.insert<InstCall>(MaxArgs, Dest, TargetHelper,
628*03ce13f7SAndroid Build Coastguard Worker                                             NoTailCall, IsTargetHelperCall);
629*03ce13f7SAndroid Build Coastguard Worker       Call->addArg(Addr);
630*03ce13f7SAndroid Build Coastguard Worker       Call->addArg(_0);
631*03ce13f7SAndroid Build Coastguard Worker       Call->addArg(_0);
632*03ce13f7SAndroid Build Coastguard Worker       Context.insert<InstMIPS32Sync>();
633*03ce13f7SAndroid Build Coastguard Worker       Instr->setDeleted();
634*03ce13f7SAndroid Build Coastguard Worker       return;
635*03ce13f7SAndroid Build Coastguard Worker     }
636*03ce13f7SAndroid Build Coastguard Worker     case Intrinsics::AtomicStore: {
637*03ce13f7SAndroid Build Coastguard Worker       Operand *Val = Intrinsic->getArg(0);
638*03ce13f7SAndroid Build Coastguard Worker       if (Val->getType() != IceType_i64)
639*03ce13f7SAndroid Build Coastguard Worker         return;
640*03ce13f7SAndroid Build Coastguard Worker       if (!Intrinsics::isMemoryOrderValid(
641*03ce13f7SAndroid Build Coastguard Worker               ID, getConstantMemoryOrder(Intrinsic->getArg(2)))) {
642*03ce13f7SAndroid Build Coastguard Worker         Func->setError("Unexpected memory ordering for AtomicStore");
643*03ce13f7SAndroid Build Coastguard Worker         return;
644*03ce13f7SAndroid Build Coastguard Worker       }
645*03ce13f7SAndroid Build Coastguard Worker       Operand *Addr = Intrinsic->getArg(1);
646*03ce13f7SAndroid Build Coastguard Worker       Variable *NoDest = nullptr;
647*03ce13f7SAndroid Build Coastguard Worker       Operand *TargetHelper = Ctx->getConstantExternSym(
648*03ce13f7SAndroid Build Coastguard Worker           Ctx->getGlobalString("__sync_lock_test_and_set_8"));
649*03ce13f7SAndroid Build Coastguard Worker       Context.insert<InstMIPS32Sync>();
650*03ce13f7SAndroid Build Coastguard Worker       static constexpr SizeT MaxArgs = 2;
651*03ce13f7SAndroid Build Coastguard Worker       auto *Call = Context.insert<InstCall>(MaxArgs, NoDest, TargetHelper,
652*03ce13f7SAndroid Build Coastguard Worker                                             NoTailCall, IsTargetHelperCall);
653*03ce13f7SAndroid Build Coastguard Worker       Call->addArg(Addr);
654*03ce13f7SAndroid Build Coastguard Worker       Call->addArg(Val);
655*03ce13f7SAndroid Build Coastguard Worker       Context.insert<InstMIPS32Sync>();
656*03ce13f7SAndroid Build Coastguard Worker       Instr->setDeleted();
657*03ce13f7SAndroid Build Coastguard Worker       return;
658*03ce13f7SAndroid Build Coastguard Worker     }
659*03ce13f7SAndroid Build Coastguard Worker     case Intrinsics::AtomicCmpxchg: {
660*03ce13f7SAndroid Build Coastguard Worker       if (DestTy != IceType_i64)
661*03ce13f7SAndroid Build Coastguard Worker         return;
662*03ce13f7SAndroid Build Coastguard Worker       if (!Intrinsics::isMemoryOrderValid(
663*03ce13f7SAndroid Build Coastguard Worker               ID, getConstantMemoryOrder(Intrinsic->getArg(3)),
664*03ce13f7SAndroid Build Coastguard Worker               getConstantMemoryOrder(Intrinsic->getArg(4)))) {
665*03ce13f7SAndroid Build Coastguard Worker         Func->setError("Unexpected memory ordering for AtomicCmpxchg");
666*03ce13f7SAndroid Build Coastguard Worker         return;
667*03ce13f7SAndroid Build Coastguard Worker       }
668*03ce13f7SAndroid Build Coastguard Worker       Operand *Addr = Intrinsic->getArg(0);
669*03ce13f7SAndroid Build Coastguard Worker       Operand *Oldval = Intrinsic->getArg(1);
670*03ce13f7SAndroid Build Coastguard Worker       Operand *Newval = Intrinsic->getArg(2);
671*03ce13f7SAndroid Build Coastguard Worker       Operand *TargetHelper = Ctx->getConstantExternSym(
672*03ce13f7SAndroid Build Coastguard Worker           Ctx->getGlobalString("__sync_val_compare_and_swap_8"));
673*03ce13f7SAndroid Build Coastguard Worker       Context.insert<InstMIPS32Sync>();
674*03ce13f7SAndroid Build Coastguard Worker       static constexpr SizeT MaxArgs = 3;
675*03ce13f7SAndroid Build Coastguard Worker       auto *Call = Context.insert<InstCall>(MaxArgs, Dest, TargetHelper,
676*03ce13f7SAndroid Build Coastguard Worker                                             NoTailCall, IsTargetHelperCall);
677*03ce13f7SAndroid Build Coastguard Worker       Call->addArg(Addr);
678*03ce13f7SAndroid Build Coastguard Worker       Call->addArg(Oldval);
679*03ce13f7SAndroid Build Coastguard Worker       Call->addArg(Newval);
680*03ce13f7SAndroid Build Coastguard Worker       Context.insert<InstMIPS32Sync>();
681*03ce13f7SAndroid Build Coastguard Worker       Instr->setDeleted();
682*03ce13f7SAndroid Build Coastguard Worker       return;
683*03ce13f7SAndroid Build Coastguard Worker     }
684*03ce13f7SAndroid Build Coastguard Worker     case Intrinsics::AtomicRMW: {
685*03ce13f7SAndroid Build Coastguard Worker       if (DestTy != IceType_i64)
686*03ce13f7SAndroid Build Coastguard Worker         return;
687*03ce13f7SAndroid Build Coastguard Worker       if (!Intrinsics::isMemoryOrderValid(
688*03ce13f7SAndroid Build Coastguard Worker               ID, getConstantMemoryOrder(Intrinsic->getArg(3)))) {
689*03ce13f7SAndroid Build Coastguard Worker         Func->setError("Unexpected memory ordering for AtomicRMW");
690*03ce13f7SAndroid Build Coastguard Worker         return;
691*03ce13f7SAndroid Build Coastguard Worker       }
692*03ce13f7SAndroid Build Coastguard Worker       auto Operation = static_cast<Intrinsics::AtomicRMWOperation>(
693*03ce13f7SAndroid Build Coastguard Worker           llvm::cast<ConstantInteger32>(Intrinsic->getArg(0))->getValue());
694*03ce13f7SAndroid Build Coastguard Worker       auto *Addr = Intrinsic->getArg(1);
695*03ce13f7SAndroid Build Coastguard Worker       auto *Newval = Intrinsic->getArg(2);
696*03ce13f7SAndroid Build Coastguard Worker       Operand *TargetHelper;
697*03ce13f7SAndroid Build Coastguard Worker       switch (Operation) {
698*03ce13f7SAndroid Build Coastguard Worker       case Intrinsics::AtomicAdd:
699*03ce13f7SAndroid Build Coastguard Worker         TargetHelper = Ctx->getConstantExternSym(
700*03ce13f7SAndroid Build Coastguard Worker             Ctx->getGlobalString("__sync_fetch_and_add_8"));
701*03ce13f7SAndroid Build Coastguard Worker         break;
702*03ce13f7SAndroid Build Coastguard Worker       case Intrinsics::AtomicSub:
703*03ce13f7SAndroid Build Coastguard Worker         TargetHelper = Ctx->getConstantExternSym(
704*03ce13f7SAndroid Build Coastguard Worker             Ctx->getGlobalString("__sync_fetch_and_sub_8"));
705*03ce13f7SAndroid Build Coastguard Worker         break;
706*03ce13f7SAndroid Build Coastguard Worker       case Intrinsics::AtomicOr:
707*03ce13f7SAndroid Build Coastguard Worker         TargetHelper = Ctx->getConstantExternSym(
708*03ce13f7SAndroid Build Coastguard Worker             Ctx->getGlobalString("__sync_fetch_and_or_8"));
709*03ce13f7SAndroid Build Coastguard Worker         break;
710*03ce13f7SAndroid Build Coastguard Worker       case Intrinsics::AtomicAnd:
711*03ce13f7SAndroid Build Coastguard Worker         TargetHelper = Ctx->getConstantExternSym(
712*03ce13f7SAndroid Build Coastguard Worker             Ctx->getGlobalString("__sync_fetch_and_and_8"));
713*03ce13f7SAndroid Build Coastguard Worker         break;
714*03ce13f7SAndroid Build Coastguard Worker       case Intrinsics::AtomicXor:
715*03ce13f7SAndroid Build Coastguard Worker         TargetHelper = Ctx->getConstantExternSym(
716*03ce13f7SAndroid Build Coastguard Worker             Ctx->getGlobalString("__sync_fetch_and_xor_8"));
717*03ce13f7SAndroid Build Coastguard Worker         break;
718*03ce13f7SAndroid Build Coastguard Worker       case Intrinsics::AtomicExchange:
719*03ce13f7SAndroid Build Coastguard Worker         TargetHelper = Ctx->getConstantExternSym(
720*03ce13f7SAndroid Build Coastguard Worker             Ctx->getGlobalString("__sync_lock_test_and_set_8"));
721*03ce13f7SAndroid Build Coastguard Worker         break;
722*03ce13f7SAndroid Build Coastguard Worker       default:
723*03ce13f7SAndroid Build Coastguard Worker         llvm::report_fatal_error("Unknown AtomicRMW operation");
724*03ce13f7SAndroid Build Coastguard Worker         return;
725*03ce13f7SAndroid Build Coastguard Worker       }
726*03ce13f7SAndroid Build Coastguard Worker       Context.insert<InstMIPS32Sync>();
727*03ce13f7SAndroid Build Coastguard Worker       static constexpr SizeT MaxArgs = 2;
728*03ce13f7SAndroid Build Coastguard Worker       auto *Call = Context.insert<InstCall>(MaxArgs, Dest, TargetHelper,
729*03ce13f7SAndroid Build Coastguard Worker                                             NoTailCall, IsTargetHelperCall);
730*03ce13f7SAndroid Build Coastguard Worker       Call->addArg(Addr);
731*03ce13f7SAndroid Build Coastguard Worker       Call->addArg(Newval);
732*03ce13f7SAndroid Build Coastguard Worker       Context.insert<InstMIPS32Sync>();
733*03ce13f7SAndroid Build Coastguard Worker       Instr->setDeleted();
734*03ce13f7SAndroid Build Coastguard Worker       return;
735*03ce13f7SAndroid Build Coastguard Worker     }
736*03ce13f7SAndroid Build Coastguard Worker     case Intrinsics::Ctpop: {
737*03ce13f7SAndroid Build Coastguard Worker       Operand *Src0 = Intrinsic->getArg(0);
738*03ce13f7SAndroid Build Coastguard Worker       Operand *TargetHelper =
739*03ce13f7SAndroid Build Coastguard Worker           Ctx->getRuntimeHelperFunc(isInt32Asserting32Or64(Src0->getType())
740*03ce13f7SAndroid Build Coastguard Worker                                         ? RuntimeHelper::H_call_ctpop_i32
741*03ce13f7SAndroid Build Coastguard Worker                                         : RuntimeHelper::H_call_ctpop_i64);
742*03ce13f7SAndroid Build Coastguard Worker       static constexpr SizeT MaxArgs = 1;
743*03ce13f7SAndroid Build Coastguard Worker       auto *Call = Context.insert<InstCall>(MaxArgs, Dest, TargetHelper,
744*03ce13f7SAndroid Build Coastguard Worker                                             NoTailCall, IsTargetHelperCall);
745*03ce13f7SAndroid Build Coastguard Worker       Call->addArg(Src0);
746*03ce13f7SAndroid Build Coastguard Worker       Instr->setDeleted();
747*03ce13f7SAndroid Build Coastguard Worker       return;
748*03ce13f7SAndroid Build Coastguard Worker     }
749*03ce13f7SAndroid Build Coastguard Worker     case Intrinsics::Longjmp: {
750*03ce13f7SAndroid Build Coastguard Worker       static constexpr SizeT MaxArgs = 2;
751*03ce13f7SAndroid Build Coastguard Worker       static constexpr Variable *NoDest = nullptr;
752*03ce13f7SAndroid Build Coastguard Worker       Operand *TargetHelper =
753*03ce13f7SAndroid Build Coastguard Worker           Ctx->getRuntimeHelperFunc(RuntimeHelper::H_call_longjmp);
754*03ce13f7SAndroid Build Coastguard Worker       auto *Call = Context.insert<InstCall>(MaxArgs, NoDest, TargetHelper,
755*03ce13f7SAndroid Build Coastguard Worker                                             NoTailCall, IsTargetHelperCall);
756*03ce13f7SAndroid Build Coastguard Worker       Call->addArg(Intrinsic->getArg(0));
757*03ce13f7SAndroid Build Coastguard Worker       Call->addArg(Intrinsic->getArg(1));
758*03ce13f7SAndroid Build Coastguard Worker       Instr->setDeleted();
759*03ce13f7SAndroid Build Coastguard Worker       return;
760*03ce13f7SAndroid Build Coastguard Worker     }
761*03ce13f7SAndroid Build Coastguard Worker     case Intrinsics::Memcpy: {
762*03ce13f7SAndroid Build Coastguard Worker       static constexpr SizeT MaxArgs = 3;
763*03ce13f7SAndroid Build Coastguard Worker       static constexpr Variable *NoDest = nullptr;
764*03ce13f7SAndroid Build Coastguard Worker       Operand *TargetHelper =
765*03ce13f7SAndroid Build Coastguard Worker           Ctx->getRuntimeHelperFunc(RuntimeHelper::H_call_memcpy);
766*03ce13f7SAndroid Build Coastguard Worker       auto *Call = Context.insert<InstCall>(MaxArgs, NoDest, TargetHelper,
767*03ce13f7SAndroid Build Coastguard Worker                                             NoTailCall, IsTargetHelperCall);
768*03ce13f7SAndroid Build Coastguard Worker       Call->addArg(Intrinsic->getArg(0));
769*03ce13f7SAndroid Build Coastguard Worker       Call->addArg(Intrinsic->getArg(1));
770*03ce13f7SAndroid Build Coastguard Worker       Call->addArg(Intrinsic->getArg(2));
771*03ce13f7SAndroid Build Coastguard Worker       Instr->setDeleted();
772*03ce13f7SAndroid Build Coastguard Worker       return;
773*03ce13f7SAndroid Build Coastguard Worker     }
774*03ce13f7SAndroid Build Coastguard Worker     case Intrinsics::Memmove: {
775*03ce13f7SAndroid Build Coastguard Worker       static constexpr SizeT MaxArgs = 3;
776*03ce13f7SAndroid Build Coastguard Worker       static constexpr Variable *NoDest = nullptr;
777*03ce13f7SAndroid Build Coastguard Worker       Operand *TargetHelper =
778*03ce13f7SAndroid Build Coastguard Worker           Ctx->getRuntimeHelperFunc(RuntimeHelper::H_call_memmove);
779*03ce13f7SAndroid Build Coastguard Worker       auto *Call = Context.insert<InstCall>(MaxArgs, NoDest, TargetHelper,
780*03ce13f7SAndroid Build Coastguard Worker                                             NoTailCall, IsTargetHelperCall);
781*03ce13f7SAndroid Build Coastguard Worker       Call->addArg(Intrinsic->getArg(0));
782*03ce13f7SAndroid Build Coastguard Worker       Call->addArg(Intrinsic->getArg(1));
783*03ce13f7SAndroid Build Coastguard Worker       Call->addArg(Intrinsic->getArg(2));
784*03ce13f7SAndroid Build Coastguard Worker       Instr->setDeleted();
785*03ce13f7SAndroid Build Coastguard Worker       return;
786*03ce13f7SAndroid Build Coastguard Worker     }
787*03ce13f7SAndroid Build Coastguard Worker     case Intrinsics::Memset: {
788*03ce13f7SAndroid Build Coastguard Worker       Operand *ValOp = Intrinsic->getArg(1);
789*03ce13f7SAndroid Build Coastguard Worker       assert(ValOp->getType() == IceType_i8);
790*03ce13f7SAndroid Build Coastguard Worker       Variable *ValExt = Func->makeVariable(stackSlotType());
791*03ce13f7SAndroid Build Coastguard Worker       Context.insert<InstCast>(InstCast::Zext, ValExt, ValOp);
792*03ce13f7SAndroid Build Coastguard Worker 
793*03ce13f7SAndroid Build Coastguard Worker       static constexpr SizeT MaxArgs = 3;
794*03ce13f7SAndroid Build Coastguard Worker       static constexpr Variable *NoDest = nullptr;
795*03ce13f7SAndroid Build Coastguard Worker       Operand *TargetHelper =
796*03ce13f7SAndroid Build Coastguard Worker           Ctx->getRuntimeHelperFunc(RuntimeHelper::H_call_memset);
797*03ce13f7SAndroid Build Coastguard Worker       auto *Call = Context.insert<InstCall>(MaxArgs, NoDest, TargetHelper,
798*03ce13f7SAndroid Build Coastguard Worker                                             NoTailCall, IsTargetHelperCall);
799*03ce13f7SAndroid Build Coastguard Worker       Call->addArg(Intrinsic->getArg(0));
800*03ce13f7SAndroid Build Coastguard Worker       Call->addArg(ValExt);
801*03ce13f7SAndroid Build Coastguard Worker       Call->addArg(Intrinsic->getArg(2));
802*03ce13f7SAndroid Build Coastguard Worker       Instr->setDeleted();
803*03ce13f7SAndroid Build Coastguard Worker       return;
804*03ce13f7SAndroid Build Coastguard Worker     }
805*03ce13f7SAndroid Build Coastguard Worker     case Intrinsics::Setjmp: {
806*03ce13f7SAndroid Build Coastguard Worker       static constexpr SizeT MaxArgs = 1;
807*03ce13f7SAndroid Build Coastguard Worker       Operand *TargetHelper =
808*03ce13f7SAndroid Build Coastguard Worker           Ctx->getRuntimeHelperFunc(RuntimeHelper::H_call_setjmp);
809*03ce13f7SAndroid Build Coastguard Worker       auto *Call = Context.insert<InstCall>(MaxArgs, Dest, TargetHelper,
810*03ce13f7SAndroid Build Coastguard Worker                                             NoTailCall, IsTargetHelperCall);
811*03ce13f7SAndroid Build Coastguard Worker       Call->addArg(Intrinsic->getArg(0));
812*03ce13f7SAndroid Build Coastguard Worker       Instr->setDeleted();
813*03ce13f7SAndroid Build Coastguard Worker       return;
814*03ce13f7SAndroid Build Coastguard Worker     }
815*03ce13f7SAndroid Build Coastguard Worker     }
816*03ce13f7SAndroid Build Coastguard Worker     llvm::report_fatal_error("Control flow should never have reached here.");
817*03ce13f7SAndroid Build Coastguard Worker   }
818*03ce13f7SAndroid Build Coastguard Worker   }
819*03ce13f7SAndroid Build Coastguard Worker }
820*03ce13f7SAndroid Build Coastguard Worker 
findMaxStackOutArgsSize()821*03ce13f7SAndroid Build Coastguard Worker void TargetMIPS32::findMaxStackOutArgsSize() {
822*03ce13f7SAndroid Build Coastguard Worker   // MinNeededOutArgsBytes should be updated if the Target ever creates a
823*03ce13f7SAndroid Build Coastguard Worker   // high-level InstCall that requires more stack bytes.
824*03ce13f7SAndroid Build Coastguard Worker   size_t MinNeededOutArgsBytes = 0;
825*03ce13f7SAndroid Build Coastguard Worker   if (!MaybeLeafFunc)
826*03ce13f7SAndroid Build Coastguard Worker     MinNeededOutArgsBytes = MIPS32_MAX_GPR_ARG * 4;
827*03ce13f7SAndroid Build Coastguard Worker   MaxOutArgsSizeBytes = MinNeededOutArgsBytes;
828*03ce13f7SAndroid Build Coastguard Worker   for (CfgNode *Node : Func->getNodes()) {
829*03ce13f7SAndroid Build Coastguard Worker     Context.init(Node);
830*03ce13f7SAndroid Build Coastguard Worker     while (!Context.atEnd()) {
831*03ce13f7SAndroid Build Coastguard Worker       PostIncrLoweringContext PostIncrement(Context);
832*03ce13f7SAndroid Build Coastguard Worker       Inst *CurInstr = iteratorToInst(Context.getCur());
833*03ce13f7SAndroid Build Coastguard Worker       if (auto *Call = llvm::dyn_cast<InstCall>(CurInstr)) {
834*03ce13f7SAndroid Build Coastguard Worker         SizeT OutArgsSizeBytes = getCallStackArgumentsSizeBytes(Call);
835*03ce13f7SAndroid Build Coastguard Worker         MaxOutArgsSizeBytes = std::max(MaxOutArgsSizeBytes, OutArgsSizeBytes);
836*03ce13f7SAndroid Build Coastguard Worker       }
837*03ce13f7SAndroid Build Coastguard Worker     }
838*03ce13f7SAndroid Build Coastguard Worker   }
839*03ce13f7SAndroid Build Coastguard Worker   CurrentAllocaOffset = MaxOutArgsSizeBytes;
840*03ce13f7SAndroid Build Coastguard Worker }
841*03ce13f7SAndroid Build Coastguard Worker 
translateO2()842*03ce13f7SAndroid Build Coastguard Worker void TargetMIPS32::translateO2() {
843*03ce13f7SAndroid Build Coastguard Worker   TimerMarker T(TimerStack::TT_O2, Func);
844*03ce13f7SAndroid Build Coastguard Worker 
845*03ce13f7SAndroid Build Coastguard Worker   // TODO(stichnot): share passes with X86?
846*03ce13f7SAndroid Build Coastguard Worker   // https://code.google.com/p/nativeclient/issues/detail?id=4094
847*03ce13f7SAndroid Build Coastguard Worker   genTargetHelperCalls();
848*03ce13f7SAndroid Build Coastguard Worker 
849*03ce13f7SAndroid Build Coastguard Worker   unsetIfNonLeafFunc();
850*03ce13f7SAndroid Build Coastguard Worker 
851*03ce13f7SAndroid Build Coastguard Worker   findMaxStackOutArgsSize();
852*03ce13f7SAndroid Build Coastguard Worker 
853*03ce13f7SAndroid Build Coastguard Worker   // Merge Alloca instructions, and lay out the stack.
854*03ce13f7SAndroid Build Coastguard Worker   static constexpr bool SortAndCombineAllocas = true;
855*03ce13f7SAndroid Build Coastguard Worker   Func->processAllocas(SortAndCombineAllocas);
856*03ce13f7SAndroid Build Coastguard Worker   Func->dump("After Alloca processing");
857*03ce13f7SAndroid Build Coastguard Worker 
858*03ce13f7SAndroid Build Coastguard Worker   if (!getFlags().getEnablePhiEdgeSplit()) {
859*03ce13f7SAndroid Build Coastguard Worker     // Lower Phi instructions.
860*03ce13f7SAndroid Build Coastguard Worker     Func->placePhiLoads();
861*03ce13f7SAndroid Build Coastguard Worker     if (Func->hasError())
862*03ce13f7SAndroid Build Coastguard Worker       return;
863*03ce13f7SAndroid Build Coastguard Worker     Func->placePhiStores();
864*03ce13f7SAndroid Build Coastguard Worker     if (Func->hasError())
865*03ce13f7SAndroid Build Coastguard Worker       return;
866*03ce13f7SAndroid Build Coastguard Worker     Func->deletePhis();
867*03ce13f7SAndroid Build Coastguard Worker     if (Func->hasError())
868*03ce13f7SAndroid Build Coastguard Worker       return;
869*03ce13f7SAndroid Build Coastguard Worker     Func->dump("After Phi lowering");
870*03ce13f7SAndroid Build Coastguard Worker   }
871*03ce13f7SAndroid Build Coastguard Worker 
872*03ce13f7SAndroid Build Coastguard Worker   // Address mode optimization.
873*03ce13f7SAndroid Build Coastguard Worker   Func->getVMetadata()->init(VMK_SingleDefs);
874*03ce13f7SAndroid Build Coastguard Worker   Func->doAddressOpt();
875*03ce13f7SAndroid Build Coastguard Worker 
876*03ce13f7SAndroid Build Coastguard Worker   // Argument lowering
877*03ce13f7SAndroid Build Coastguard Worker   Func->doArgLowering();
878*03ce13f7SAndroid Build Coastguard Worker 
879*03ce13f7SAndroid Build Coastguard Worker   // Target lowering. This requires liveness analysis for some parts of the
880*03ce13f7SAndroid Build Coastguard Worker   // lowering decisions, such as compare/branch fusing. If non-lightweight
881*03ce13f7SAndroid Build Coastguard Worker   // liveness analysis is used, the instructions need to be renumbered first.
882*03ce13f7SAndroid Build Coastguard Worker   // TODO: This renumbering should only be necessary if we're actually
883*03ce13f7SAndroid Build Coastguard Worker   // calculating live intervals, which we only do for register allocation.
884*03ce13f7SAndroid Build Coastguard Worker   Func->renumberInstructions();
885*03ce13f7SAndroid Build Coastguard Worker   if (Func->hasError())
886*03ce13f7SAndroid Build Coastguard Worker     return;
887*03ce13f7SAndroid Build Coastguard Worker 
888*03ce13f7SAndroid Build Coastguard Worker   // TODO: It should be sufficient to use the fastest liveness calculation,
889*03ce13f7SAndroid Build Coastguard Worker   // i.e. livenessLightweight(). However, for some reason that slows down the
890*03ce13f7SAndroid Build Coastguard Worker   // rest of the translation. Investigate.
891*03ce13f7SAndroid Build Coastguard Worker   Func->liveness(Liveness_Basic);
892*03ce13f7SAndroid Build Coastguard Worker   if (Func->hasError())
893*03ce13f7SAndroid Build Coastguard Worker     return;
894*03ce13f7SAndroid Build Coastguard Worker   Func->dump("After MIPS32 address mode opt");
895*03ce13f7SAndroid Build Coastguard Worker 
896*03ce13f7SAndroid Build Coastguard Worker   Func->genCode();
897*03ce13f7SAndroid Build Coastguard Worker   if (Func->hasError())
898*03ce13f7SAndroid Build Coastguard Worker     return;
899*03ce13f7SAndroid Build Coastguard Worker   Func->dump("After MIPS32 codegen");
900*03ce13f7SAndroid Build Coastguard Worker 
901*03ce13f7SAndroid Build Coastguard Worker   // Register allocation. This requires instruction renumbering and full
902*03ce13f7SAndroid Build Coastguard Worker   // liveness analysis.
903*03ce13f7SAndroid Build Coastguard Worker   Func->renumberInstructions();
904*03ce13f7SAndroid Build Coastguard Worker   if (Func->hasError())
905*03ce13f7SAndroid Build Coastguard Worker     return;
906*03ce13f7SAndroid Build Coastguard Worker   Func->liveness(Liveness_Intervals);
907*03ce13f7SAndroid Build Coastguard Worker   if (Func->hasError())
908*03ce13f7SAndroid Build Coastguard Worker     return;
909*03ce13f7SAndroid Build Coastguard Worker   // The post-codegen dump is done here, after liveness analysis and associated
910*03ce13f7SAndroid Build Coastguard Worker   // cleanup, to make the dump cleaner and more useful.
911*03ce13f7SAndroid Build Coastguard Worker   Func->dump("After initial MIPS32 codegen");
912*03ce13f7SAndroid Build Coastguard Worker   // Validate the live range computations. The expensive validation call is
913*03ce13f7SAndroid Build Coastguard Worker   // deliberately only made when assertions are enabled.
914*03ce13f7SAndroid Build Coastguard Worker   assert(Func->validateLiveness());
915*03ce13f7SAndroid Build Coastguard Worker   Func->getVMetadata()->init(VMK_All);
916*03ce13f7SAndroid Build Coastguard Worker   regAlloc(RAK_Global);
917*03ce13f7SAndroid Build Coastguard Worker   if (Func->hasError())
918*03ce13f7SAndroid Build Coastguard Worker     return;
919*03ce13f7SAndroid Build Coastguard Worker   Func->dump("After linear scan regalloc");
920*03ce13f7SAndroid Build Coastguard Worker 
921*03ce13f7SAndroid Build Coastguard Worker   if (getFlags().getEnablePhiEdgeSplit()) {
922*03ce13f7SAndroid Build Coastguard Worker     Func->advancedPhiLowering();
923*03ce13f7SAndroid Build Coastguard Worker     Func->dump("After advanced Phi lowering");
924*03ce13f7SAndroid Build Coastguard Worker   }
925*03ce13f7SAndroid Build Coastguard Worker 
926*03ce13f7SAndroid Build Coastguard Worker   // Stack frame mapping.
927*03ce13f7SAndroid Build Coastguard Worker   Func->genFrame();
928*03ce13f7SAndroid Build Coastguard Worker   if (Func->hasError())
929*03ce13f7SAndroid Build Coastguard Worker     return;
930*03ce13f7SAndroid Build Coastguard Worker   Func->dump("After stack frame mapping");
931*03ce13f7SAndroid Build Coastguard Worker 
932*03ce13f7SAndroid Build Coastguard Worker   postLowerLegalization();
933*03ce13f7SAndroid Build Coastguard Worker   if (Func->hasError())
934*03ce13f7SAndroid Build Coastguard Worker     return;
935*03ce13f7SAndroid Build Coastguard Worker   Func->dump("After postLowerLegalization");
936*03ce13f7SAndroid Build Coastguard Worker 
937*03ce13f7SAndroid Build Coastguard Worker   Func->contractEmptyNodes();
938*03ce13f7SAndroid Build Coastguard Worker   Func->reorderNodes();
939*03ce13f7SAndroid Build Coastguard Worker 
940*03ce13f7SAndroid Build Coastguard Worker   // Branch optimization. This needs to be done just before code emission. In
941*03ce13f7SAndroid Build Coastguard Worker   // particular, no transformations that insert or reorder CfgNodes should be
942*03ce13f7SAndroid Build Coastguard Worker   // done after branch optimization. We go ahead and do it before nop insertion
943*03ce13f7SAndroid Build Coastguard Worker   // to reduce the amount of work needed for searching for opportunities.
944*03ce13f7SAndroid Build Coastguard Worker   Func->doBranchOpt();
945*03ce13f7SAndroid Build Coastguard Worker   Func->dump("After branch optimization");
946*03ce13f7SAndroid Build Coastguard Worker }
947*03ce13f7SAndroid Build Coastguard Worker 
translateOm1()948*03ce13f7SAndroid Build Coastguard Worker void TargetMIPS32::translateOm1() {
949*03ce13f7SAndroid Build Coastguard Worker   TimerMarker T(TimerStack::TT_Om1, Func);
950*03ce13f7SAndroid Build Coastguard Worker 
951*03ce13f7SAndroid Build Coastguard Worker   // TODO: share passes with X86?
952*03ce13f7SAndroid Build Coastguard Worker   genTargetHelperCalls();
953*03ce13f7SAndroid Build Coastguard Worker 
954*03ce13f7SAndroid Build Coastguard Worker   unsetIfNonLeafFunc();
955*03ce13f7SAndroid Build Coastguard Worker 
956*03ce13f7SAndroid Build Coastguard Worker   findMaxStackOutArgsSize();
957*03ce13f7SAndroid Build Coastguard Worker 
958*03ce13f7SAndroid Build Coastguard Worker   // Do not merge Alloca instructions, and lay out the stack.
959*03ce13f7SAndroid Build Coastguard Worker   static constexpr bool SortAndCombineAllocas = false;
960*03ce13f7SAndroid Build Coastguard Worker   Func->processAllocas(SortAndCombineAllocas);
961*03ce13f7SAndroid Build Coastguard Worker   Func->dump("After Alloca processing");
962*03ce13f7SAndroid Build Coastguard Worker 
963*03ce13f7SAndroid Build Coastguard Worker   Func->placePhiLoads();
964*03ce13f7SAndroid Build Coastguard Worker   if (Func->hasError())
965*03ce13f7SAndroid Build Coastguard Worker     return;
966*03ce13f7SAndroid Build Coastguard Worker   Func->placePhiStores();
967*03ce13f7SAndroid Build Coastguard Worker   if (Func->hasError())
968*03ce13f7SAndroid Build Coastguard Worker     return;
969*03ce13f7SAndroid Build Coastguard Worker   Func->deletePhis();
970*03ce13f7SAndroid Build Coastguard Worker   if (Func->hasError())
971*03ce13f7SAndroid Build Coastguard Worker     return;
972*03ce13f7SAndroid Build Coastguard Worker   Func->dump("After Phi lowering");
973*03ce13f7SAndroid Build Coastguard Worker 
974*03ce13f7SAndroid Build Coastguard Worker   Func->doArgLowering();
975*03ce13f7SAndroid Build Coastguard Worker 
976*03ce13f7SAndroid Build Coastguard Worker   Func->genCode();
977*03ce13f7SAndroid Build Coastguard Worker   if (Func->hasError())
978*03ce13f7SAndroid Build Coastguard Worker     return;
979*03ce13f7SAndroid Build Coastguard Worker   Func->dump("After initial MIPS32 codegen");
980*03ce13f7SAndroid Build Coastguard Worker 
981*03ce13f7SAndroid Build Coastguard Worker   regAlloc(RAK_InfOnly);
982*03ce13f7SAndroid Build Coastguard Worker   if (Func->hasError())
983*03ce13f7SAndroid Build Coastguard Worker     return;
984*03ce13f7SAndroid Build Coastguard Worker   Func->dump("After regalloc of infinite-weight variables");
985*03ce13f7SAndroid Build Coastguard Worker 
986*03ce13f7SAndroid Build Coastguard Worker   Func->genFrame();
987*03ce13f7SAndroid Build Coastguard Worker   if (Func->hasError())
988*03ce13f7SAndroid Build Coastguard Worker     return;
989*03ce13f7SAndroid Build Coastguard Worker   Func->dump("After stack frame mapping");
990*03ce13f7SAndroid Build Coastguard Worker 
991*03ce13f7SAndroid Build Coastguard Worker   postLowerLegalization();
992*03ce13f7SAndroid Build Coastguard Worker   if (Func->hasError())
993*03ce13f7SAndroid Build Coastguard Worker     return;
994*03ce13f7SAndroid Build Coastguard Worker   Func->dump("After postLowerLegalization");
995*03ce13f7SAndroid Build Coastguard Worker }
996*03ce13f7SAndroid Build Coastguard Worker 
doBranchOpt(Inst * Instr,const CfgNode * NextNode)997*03ce13f7SAndroid Build Coastguard Worker bool TargetMIPS32::doBranchOpt(Inst *Instr, const CfgNode *NextNode) {
998*03ce13f7SAndroid Build Coastguard Worker   if (auto *Br = llvm::dyn_cast<InstMIPS32Br>(Instr)) {
999*03ce13f7SAndroid Build Coastguard Worker     return Br->optimizeBranch(NextNode);
1000*03ce13f7SAndroid Build Coastguard Worker   }
1001*03ce13f7SAndroid Build Coastguard Worker   return false;
1002*03ce13f7SAndroid Build Coastguard Worker }
1003*03ce13f7SAndroid Build Coastguard Worker 
1004*03ce13f7SAndroid Build Coastguard Worker namespace {
1005*03ce13f7SAndroid Build Coastguard Worker 
1006*03ce13f7SAndroid Build Coastguard Worker const char *RegNames[RegMIPS32::Reg_NUM] = {
1007*03ce13f7SAndroid Build Coastguard Worker #define X(val, encode, name, scratch, preserved, stackptr, frameptr, isInt,    \
1008*03ce13f7SAndroid Build Coastguard Worker           isI64Pair, isFP32, isFP64, isVec128, alias_init)                     \
1009*03ce13f7SAndroid Build Coastguard Worker   name,
1010*03ce13f7SAndroid Build Coastguard Worker     REGMIPS32_TABLE
1011*03ce13f7SAndroid Build Coastguard Worker #undef X
1012*03ce13f7SAndroid Build Coastguard Worker };
1013*03ce13f7SAndroid Build Coastguard Worker 
1014*03ce13f7SAndroid Build Coastguard Worker } // end of anonymous namespace
1015*03ce13f7SAndroid Build Coastguard Worker 
getRegName(RegNumT RegNum)1016*03ce13f7SAndroid Build Coastguard Worker const char *RegMIPS32::getRegName(RegNumT RegNum) {
1017*03ce13f7SAndroid Build Coastguard Worker   RegNum.assertIsValid();
1018*03ce13f7SAndroid Build Coastguard Worker   return RegNames[RegNum];
1019*03ce13f7SAndroid Build Coastguard Worker }
1020*03ce13f7SAndroid Build Coastguard Worker 
getRegName(RegNumT RegNum,Type Ty) const1021*03ce13f7SAndroid Build Coastguard Worker const char *TargetMIPS32::getRegName(RegNumT RegNum, Type Ty) const {
1022*03ce13f7SAndroid Build Coastguard Worker   (void)Ty;
1023*03ce13f7SAndroid Build Coastguard Worker   return RegMIPS32::getRegName(RegNum);
1024*03ce13f7SAndroid Build Coastguard Worker }
1025*03ce13f7SAndroid Build Coastguard Worker 
getPhysicalRegister(RegNumT RegNum,Type Ty)1026*03ce13f7SAndroid Build Coastguard Worker Variable *TargetMIPS32::getPhysicalRegister(RegNumT RegNum, Type Ty) {
1027*03ce13f7SAndroid Build Coastguard Worker   if (Ty == IceType_void)
1028*03ce13f7SAndroid Build Coastguard Worker     Ty = IceType_i32;
1029*03ce13f7SAndroid Build Coastguard Worker   if (PhysicalRegisters[Ty].empty())
1030*03ce13f7SAndroid Build Coastguard Worker     PhysicalRegisters[Ty].resize(RegMIPS32::Reg_NUM);
1031*03ce13f7SAndroid Build Coastguard Worker   RegNum.assertIsValid();
1032*03ce13f7SAndroid Build Coastguard Worker   Variable *Reg = PhysicalRegisters[Ty][RegNum];
1033*03ce13f7SAndroid Build Coastguard Worker   if (Reg == nullptr) {
1034*03ce13f7SAndroid Build Coastguard Worker     Reg = Func->makeVariable(Ty);
1035*03ce13f7SAndroid Build Coastguard Worker     Reg->setRegNum(RegNum);
1036*03ce13f7SAndroid Build Coastguard Worker     PhysicalRegisters[Ty][RegNum] = Reg;
1037*03ce13f7SAndroid Build Coastguard Worker     // Specially mark a named physical register as an "argument" so that it is
1038*03ce13f7SAndroid Build Coastguard Worker     // considered live upon function entry.  Otherwise it's possible to get
1039*03ce13f7SAndroid Build Coastguard Worker     // liveness validation errors for saving callee-save registers.
1040*03ce13f7SAndroid Build Coastguard Worker     Func->addImplicitArg(Reg);
1041*03ce13f7SAndroid Build Coastguard Worker     // Don't bother tracking the live range of a named physical register.
1042*03ce13f7SAndroid Build Coastguard Worker     Reg->setIgnoreLiveness();
1043*03ce13f7SAndroid Build Coastguard Worker   }
1044*03ce13f7SAndroid Build Coastguard Worker   return Reg;
1045*03ce13f7SAndroid Build Coastguard Worker }
1046*03ce13f7SAndroid Build Coastguard Worker 
emitJumpTable(const Cfg * Func,const InstJumpTable * JumpTable) const1047*03ce13f7SAndroid Build Coastguard Worker void TargetMIPS32::emitJumpTable(const Cfg *Func,
1048*03ce13f7SAndroid Build Coastguard Worker                                  const InstJumpTable *JumpTable) const {
1049*03ce13f7SAndroid Build Coastguard Worker   (void)Func;
1050*03ce13f7SAndroid Build Coastguard Worker   (void)JumpTable;
1051*03ce13f7SAndroid Build Coastguard Worker   UnimplementedError(getFlags());
1052*03ce13f7SAndroid Build Coastguard Worker }
1053*03ce13f7SAndroid Build Coastguard Worker 
1054*03ce13f7SAndroid Build Coastguard Worker /// Provide a trivial wrapper to legalize() for this common usage.
legalizeToReg(Operand * From,RegNumT RegNum)1055*03ce13f7SAndroid Build Coastguard Worker Variable *TargetMIPS32::legalizeToReg(Operand *From, RegNumT RegNum) {
1056*03ce13f7SAndroid Build Coastguard Worker   return llvm::cast<Variable>(legalize(From, Legal_Reg, RegNum));
1057*03ce13f7SAndroid Build Coastguard Worker }
1058*03ce13f7SAndroid Build Coastguard Worker 
1059*03ce13f7SAndroid Build Coastguard Worker /// Legalize undef values to concrete values.
legalizeUndef(Operand * From,RegNumT RegNum)1060*03ce13f7SAndroid Build Coastguard Worker Operand *TargetMIPS32::legalizeUndef(Operand *From, RegNumT RegNum) {
1061*03ce13f7SAndroid Build Coastguard Worker   (void)RegNum;
1062*03ce13f7SAndroid Build Coastguard Worker   Type Ty = From->getType();
1063*03ce13f7SAndroid Build Coastguard Worker   if (llvm::isa<ConstantUndef>(From)) {
1064*03ce13f7SAndroid Build Coastguard Worker     // Lower undefs to zero.  Another option is to lower undefs to an
1065*03ce13f7SAndroid Build Coastguard Worker     // uninitialized register; however, using an uninitialized register
1066*03ce13f7SAndroid Build Coastguard Worker     // results in less predictable code.
1067*03ce13f7SAndroid Build Coastguard Worker     //
1068*03ce13f7SAndroid Build Coastguard Worker     // If in the future the implementation is changed to lower undef
1069*03ce13f7SAndroid Build Coastguard Worker     // values to uninitialized registers, a FakeDef will be needed:
1070*03ce13f7SAndroid Build Coastguard Worker     //     Context.insert(InstFakeDef::create(Func, Reg));
1071*03ce13f7SAndroid Build Coastguard Worker     // This is in order to ensure that the live range of Reg is not
1072*03ce13f7SAndroid Build Coastguard Worker     // overestimated.  If the constant being lowered is a 64 bit value,
1073*03ce13f7SAndroid Build Coastguard Worker     // then the result should be split and the lo and hi components will
1074*03ce13f7SAndroid Build Coastguard Worker     // need to go in uninitialized registers.
1075*03ce13f7SAndroid Build Coastguard Worker     if (isVectorType(Ty)) {
1076*03ce13f7SAndroid Build Coastguard Worker       Variable *Var = makeReg(Ty, RegNum);
1077*03ce13f7SAndroid Build Coastguard Worker       auto *Reg = llvm::cast<VariableVecOn32>(Var);
1078*03ce13f7SAndroid Build Coastguard Worker       Reg->initVecElement(Func);
1079*03ce13f7SAndroid Build Coastguard Worker       auto *Zero = getZero();
1080*03ce13f7SAndroid Build Coastguard Worker       for (Variable *Var : Reg->getContainers()) {
1081*03ce13f7SAndroid Build Coastguard Worker         _mov(Var, Zero);
1082*03ce13f7SAndroid Build Coastguard Worker       }
1083*03ce13f7SAndroid Build Coastguard Worker       return Reg;
1084*03ce13f7SAndroid Build Coastguard Worker     }
1085*03ce13f7SAndroid Build Coastguard Worker     return Ctx->getConstantZero(Ty);
1086*03ce13f7SAndroid Build Coastguard Worker   }
1087*03ce13f7SAndroid Build Coastguard Worker   return From;
1088*03ce13f7SAndroid Build Coastguard Worker }
1089*03ce13f7SAndroid Build Coastguard Worker 
makeReg(Type Type,RegNumT RegNum)1090*03ce13f7SAndroid Build Coastguard Worker Variable *TargetMIPS32::makeReg(Type Type, RegNumT RegNum) {
1091*03ce13f7SAndroid Build Coastguard Worker   // There aren't any 64-bit integer registers for Mips32.
1092*03ce13f7SAndroid Build Coastguard Worker   assert(Type != IceType_i64);
1093*03ce13f7SAndroid Build Coastguard Worker   Variable *Reg = Func->makeVariable(Type);
1094*03ce13f7SAndroid Build Coastguard Worker   if (RegNum.hasValue())
1095*03ce13f7SAndroid Build Coastguard Worker     Reg->setRegNum(RegNum);
1096*03ce13f7SAndroid Build Coastguard Worker   else
1097*03ce13f7SAndroid Build Coastguard Worker     Reg->setMustHaveReg();
1098*03ce13f7SAndroid Build Coastguard Worker   return Reg;
1099*03ce13f7SAndroid Build Coastguard Worker }
1100*03ce13f7SAndroid Build Coastguard Worker 
formMemoryOperand(Operand * Operand,Type Ty)1101*03ce13f7SAndroid Build Coastguard Worker OperandMIPS32Mem *TargetMIPS32::formMemoryOperand(Operand *Operand, Type Ty) {
1102*03ce13f7SAndroid Build Coastguard Worker   // It may be the case that address mode optimization already creates an
1103*03ce13f7SAndroid Build Coastguard Worker   // OperandMIPS32Mem, so in that case it wouldn't need another level of
1104*03ce13f7SAndroid Build Coastguard Worker   // transformation.
1105*03ce13f7SAndroid Build Coastguard Worker   if (auto *Mem = llvm::dyn_cast<OperandMIPS32Mem>(Operand)) {
1106*03ce13f7SAndroid Build Coastguard Worker     return llvm::cast<OperandMIPS32Mem>(legalize(Mem));
1107*03ce13f7SAndroid Build Coastguard Worker   }
1108*03ce13f7SAndroid Build Coastguard Worker 
1109*03ce13f7SAndroid Build Coastguard Worker   // If we didn't do address mode optimization, then we only have a base/offset
1110*03ce13f7SAndroid Build Coastguard Worker   // to work with. MIPS always requires a base register, so just use that to
1111*03ce13f7SAndroid Build Coastguard Worker   // hold the operand.
1112*03ce13f7SAndroid Build Coastguard Worker   auto *Base = llvm::cast<Variable>(
1113*03ce13f7SAndroid Build Coastguard Worker       legalize(Operand, Legal_Reg | Legal_Rematerializable));
1114*03ce13f7SAndroid Build Coastguard Worker   const int32_t Offset = Base->hasStackOffset() ? Base->getStackOffset() : 0;
1115*03ce13f7SAndroid Build Coastguard Worker   return OperandMIPS32Mem::create(
1116*03ce13f7SAndroid Build Coastguard Worker       Func, Ty, Base,
1117*03ce13f7SAndroid Build Coastguard Worker       llvm::cast<ConstantInteger32>(Ctx->getConstantInt32(Offset)));
1118*03ce13f7SAndroid Build Coastguard Worker }
1119*03ce13f7SAndroid Build Coastguard Worker 
emitVariable(const Variable * Var) const1120*03ce13f7SAndroid Build Coastguard Worker void TargetMIPS32::emitVariable(const Variable *Var) const {
1121*03ce13f7SAndroid Build Coastguard Worker   if (!BuildDefs::dump())
1122*03ce13f7SAndroid Build Coastguard Worker     return;
1123*03ce13f7SAndroid Build Coastguard Worker   Ostream &Str = Ctx->getStrEmit();
1124*03ce13f7SAndroid Build Coastguard Worker   const Type FrameSPTy = IceType_i32;
1125*03ce13f7SAndroid Build Coastguard Worker   if (Var->hasReg()) {
1126*03ce13f7SAndroid Build Coastguard Worker     Str << '$' << getRegName(Var->getRegNum(), Var->getType());
1127*03ce13f7SAndroid Build Coastguard Worker     return;
1128*03ce13f7SAndroid Build Coastguard Worker   }
1129*03ce13f7SAndroid Build Coastguard Worker   if (Var->mustHaveReg()) {
1130*03ce13f7SAndroid Build Coastguard Worker     llvm::report_fatal_error("Infinite-weight Variable (" + Var->getName() +
1131*03ce13f7SAndroid Build Coastguard Worker                              ") has no register assigned - function " +
1132*03ce13f7SAndroid Build Coastguard Worker                              Func->getFunctionName());
1133*03ce13f7SAndroid Build Coastguard Worker   }
1134*03ce13f7SAndroid Build Coastguard Worker   const int32_t Offset = Var->getStackOffset();
1135*03ce13f7SAndroid Build Coastguard Worker   Str << Offset;
1136*03ce13f7SAndroid Build Coastguard Worker   Str << "($" << getRegName(getFrameOrStackReg(), FrameSPTy);
1137*03ce13f7SAndroid Build Coastguard Worker   Str << ")";
1138*03ce13f7SAndroid Build Coastguard Worker }
1139*03ce13f7SAndroid Build Coastguard Worker 
CallingConv()1140*03ce13f7SAndroid Build Coastguard Worker TargetMIPS32::CallingConv::CallingConv()
1141*03ce13f7SAndroid Build Coastguard Worker     : GPRegsUsed(RegMIPS32::Reg_NUM),
1142*03ce13f7SAndroid Build Coastguard Worker       GPRArgs(GPRArgInitializer.rbegin(), GPRArgInitializer.rend()),
1143*03ce13f7SAndroid Build Coastguard Worker       I64Args(I64ArgInitializer.rbegin(), I64ArgInitializer.rend()),
1144*03ce13f7SAndroid Build Coastguard Worker       VFPRegsUsed(RegMIPS32::Reg_NUM),
1145*03ce13f7SAndroid Build Coastguard Worker       FP32Args(FP32ArgInitializer.rbegin(), FP32ArgInitializer.rend()),
1146*03ce13f7SAndroid Build Coastguard Worker       FP64Args(FP64ArgInitializer.rbegin(), FP64ArgInitializer.rend()) {}
1147*03ce13f7SAndroid Build Coastguard Worker 
1148*03ce13f7SAndroid Build Coastguard Worker // In MIPS O32 abi FP argument registers can be used only if first argument is
1149*03ce13f7SAndroid Build Coastguard Worker // of type float/double. UseFPRegs flag is used to care of that. Also FP arg
1150*03ce13f7SAndroid Build Coastguard Worker // registers can be used only for first 2 arguments, so we require argument
1151*03ce13f7SAndroid Build Coastguard Worker // number to make register allocation decisions.
argInReg(Type Ty,uint32_t ArgNo,RegNumT * Reg)1152*03ce13f7SAndroid Build Coastguard Worker bool TargetMIPS32::CallingConv::argInReg(Type Ty, uint32_t ArgNo,
1153*03ce13f7SAndroid Build Coastguard Worker                                          RegNumT *Reg) {
1154*03ce13f7SAndroid Build Coastguard Worker   if (isScalarIntegerType(Ty) || isVectorType(Ty))
1155*03ce13f7SAndroid Build Coastguard Worker     return argInGPR(Ty, Reg);
1156*03ce13f7SAndroid Build Coastguard Worker   if (isScalarFloatingType(Ty)) {
1157*03ce13f7SAndroid Build Coastguard Worker     if (ArgNo == 0) {
1158*03ce13f7SAndroid Build Coastguard Worker       UseFPRegs = true;
1159*03ce13f7SAndroid Build Coastguard Worker       return argInVFP(Ty, Reg);
1160*03ce13f7SAndroid Build Coastguard Worker     }
1161*03ce13f7SAndroid Build Coastguard Worker     if (UseFPRegs && ArgNo == 1) {
1162*03ce13f7SAndroid Build Coastguard Worker       UseFPRegs = false;
1163*03ce13f7SAndroid Build Coastguard Worker       return argInVFP(Ty, Reg);
1164*03ce13f7SAndroid Build Coastguard Worker     }
1165*03ce13f7SAndroid Build Coastguard Worker     return argInGPR(Ty, Reg);
1166*03ce13f7SAndroid Build Coastguard Worker   }
1167*03ce13f7SAndroid Build Coastguard Worker   llvm::report_fatal_error("argInReg: Invalid type.");
1168*03ce13f7SAndroid Build Coastguard Worker   return false;
1169*03ce13f7SAndroid Build Coastguard Worker }
1170*03ce13f7SAndroid Build Coastguard Worker 
argInGPR(Type Ty,RegNumT * Reg)1171*03ce13f7SAndroid Build Coastguard Worker bool TargetMIPS32::CallingConv::argInGPR(Type Ty, RegNumT *Reg) {
1172*03ce13f7SAndroid Build Coastguard Worker   CfgVector<RegNumT> *Source;
1173*03ce13f7SAndroid Build Coastguard Worker 
1174*03ce13f7SAndroid Build Coastguard Worker   switch (Ty) {
1175*03ce13f7SAndroid Build Coastguard Worker   default: {
1176*03ce13f7SAndroid Build Coastguard Worker     llvm::report_fatal_error("argInGPR: Invalid type.");
1177*03ce13f7SAndroid Build Coastguard Worker     return false;
1178*03ce13f7SAndroid Build Coastguard Worker   } break;
1179*03ce13f7SAndroid Build Coastguard Worker   case IceType_v4i1:
1180*03ce13f7SAndroid Build Coastguard Worker   case IceType_v8i1:
1181*03ce13f7SAndroid Build Coastguard Worker   case IceType_v16i1:
1182*03ce13f7SAndroid Build Coastguard Worker   case IceType_v16i8:
1183*03ce13f7SAndroid Build Coastguard Worker   case IceType_v8i16:
1184*03ce13f7SAndroid Build Coastguard Worker   case IceType_v4i32:
1185*03ce13f7SAndroid Build Coastguard Worker   case IceType_v4f32:
1186*03ce13f7SAndroid Build Coastguard Worker   case IceType_i32:
1187*03ce13f7SAndroid Build Coastguard Worker   case IceType_f32: {
1188*03ce13f7SAndroid Build Coastguard Worker     Source = &GPRArgs;
1189*03ce13f7SAndroid Build Coastguard Worker   } break;
1190*03ce13f7SAndroid Build Coastguard Worker   case IceType_i64:
1191*03ce13f7SAndroid Build Coastguard Worker   case IceType_f64: {
1192*03ce13f7SAndroid Build Coastguard Worker     Source = &I64Args;
1193*03ce13f7SAndroid Build Coastguard Worker   } break;
1194*03ce13f7SAndroid Build Coastguard Worker   }
1195*03ce13f7SAndroid Build Coastguard Worker 
1196*03ce13f7SAndroid Build Coastguard Worker   discardUnavailableGPRsAndTheirAliases(Source);
1197*03ce13f7SAndroid Build Coastguard Worker 
1198*03ce13f7SAndroid Build Coastguard Worker   // If $4 is used for any scalar type (or returining v4f32) then the next
1199*03ce13f7SAndroid Build Coastguard Worker   // vector type if passed in $6:$7:stack:stack
1200*03ce13f7SAndroid Build Coastguard Worker   if (isVectorType(Ty)) {
1201*03ce13f7SAndroid Build Coastguard Worker     alignGPR(Source);
1202*03ce13f7SAndroid Build Coastguard Worker   }
1203*03ce13f7SAndroid Build Coastguard Worker 
1204*03ce13f7SAndroid Build Coastguard Worker   if (Source->empty()) {
1205*03ce13f7SAndroid Build Coastguard Worker     GPRegsUsed.set();
1206*03ce13f7SAndroid Build Coastguard Worker     return false;
1207*03ce13f7SAndroid Build Coastguard Worker   }
1208*03ce13f7SAndroid Build Coastguard Worker 
1209*03ce13f7SAndroid Build Coastguard Worker   *Reg = Source->back();
1210*03ce13f7SAndroid Build Coastguard Worker   // Note that we don't Source->pop_back() here. This is intentional. Notice how
1211*03ce13f7SAndroid Build Coastguard Worker   // we mark all of Reg's aliases as Used. So, for the next argument,
1212*03ce13f7SAndroid Build Coastguard Worker   // Source->back() is marked as unavailable, and it is thus implicitly popped
1213*03ce13f7SAndroid Build Coastguard Worker   // from the stack.
1214*03ce13f7SAndroid Build Coastguard Worker   GPRegsUsed |= RegisterAliases[*Reg];
1215*03ce13f7SAndroid Build Coastguard Worker 
1216*03ce13f7SAndroid Build Coastguard Worker   // All vector arguments irrespective of their base type are passed in GP
1217*03ce13f7SAndroid Build Coastguard Worker   // registers. First vector argument is passed in $4:$5:$6:$7 and 2nd
1218*03ce13f7SAndroid Build Coastguard Worker   // is passed in $6:$7:stack:stack. If it is 1st argument then discard
1219*03ce13f7SAndroid Build Coastguard Worker   // $4:$5:$6:$7 otherwise discard $6:$7 only.
1220*03ce13f7SAndroid Build Coastguard Worker   if (isVectorType(Ty)) {
1221*03ce13f7SAndroid Build Coastguard Worker     if (((unsigned)*Reg) == RegMIPS32::Reg_A0) {
1222*03ce13f7SAndroid Build Coastguard Worker       GPRegsUsed |= RegisterAliases[RegMIPS32::Reg_A1];
1223*03ce13f7SAndroid Build Coastguard Worker       GPRegsUsed |= RegisterAliases[RegMIPS32::Reg_A2];
1224*03ce13f7SAndroid Build Coastguard Worker       GPRegsUsed |= RegisterAliases[RegMIPS32::Reg_A3];
1225*03ce13f7SAndroid Build Coastguard Worker     } else {
1226*03ce13f7SAndroid Build Coastguard Worker       GPRegsUsed |= RegisterAliases[RegMIPS32::Reg_A3];
1227*03ce13f7SAndroid Build Coastguard Worker     }
1228*03ce13f7SAndroid Build Coastguard Worker   }
1229*03ce13f7SAndroid Build Coastguard Worker 
1230*03ce13f7SAndroid Build Coastguard Worker   return true;
1231*03ce13f7SAndroid Build Coastguard Worker }
1232*03ce13f7SAndroid Build Coastguard Worker 
discardNextGPRAndItsAliases(CfgVector<RegNumT> * Regs)1233*03ce13f7SAndroid Build Coastguard Worker inline void TargetMIPS32::CallingConv::discardNextGPRAndItsAliases(
1234*03ce13f7SAndroid Build Coastguard Worker     CfgVector<RegNumT> *Regs) {
1235*03ce13f7SAndroid Build Coastguard Worker   GPRegsUsed |= RegisterAliases[Regs->back()];
1236*03ce13f7SAndroid Build Coastguard Worker   Regs->pop_back();
1237*03ce13f7SAndroid Build Coastguard Worker }
1238*03ce13f7SAndroid Build Coastguard Worker 
alignGPR(CfgVector<RegNumT> * Regs)1239*03ce13f7SAndroid Build Coastguard Worker inline void TargetMIPS32::CallingConv::alignGPR(CfgVector<RegNumT> *Regs) {
1240*03ce13f7SAndroid Build Coastguard Worker   if (Regs->back() == RegMIPS32::Reg_A1 || Regs->back() == RegMIPS32::Reg_A3)
1241*03ce13f7SAndroid Build Coastguard Worker     discardNextGPRAndItsAliases(Regs);
1242*03ce13f7SAndroid Build Coastguard Worker }
1243*03ce13f7SAndroid Build Coastguard Worker 
1244*03ce13f7SAndroid Build Coastguard Worker // GPR are not packed when passing parameters. Thus, a function foo(i32, i64,
1245*03ce13f7SAndroid Build Coastguard Worker // i32) will have the first argument in a0, the second in a2-a3, and the third
1246*03ce13f7SAndroid Build Coastguard Worker // on the stack. To model this behavior, whenever we pop a register from Regs,
1247*03ce13f7SAndroid Build Coastguard Worker // we remove all of its aliases from the pool of available GPRs. This has the
1248*03ce13f7SAndroid Build Coastguard Worker // effect of computing the "closure" on the GPR registers.
discardUnavailableGPRsAndTheirAliases(CfgVector<RegNumT> * Regs)1249*03ce13f7SAndroid Build Coastguard Worker void TargetMIPS32::CallingConv::discardUnavailableGPRsAndTheirAliases(
1250*03ce13f7SAndroid Build Coastguard Worker     CfgVector<RegNumT> *Regs) {
1251*03ce13f7SAndroid Build Coastguard Worker   while (!Regs->empty() && GPRegsUsed[Regs->back()]) {
1252*03ce13f7SAndroid Build Coastguard Worker     discardNextGPRAndItsAliases(Regs);
1253*03ce13f7SAndroid Build Coastguard Worker   }
1254*03ce13f7SAndroid Build Coastguard Worker }
1255*03ce13f7SAndroid Build Coastguard Worker 
argInVFP(Type Ty,RegNumT * Reg)1256*03ce13f7SAndroid Build Coastguard Worker bool TargetMIPS32::CallingConv::argInVFP(Type Ty, RegNumT *Reg) {
1257*03ce13f7SAndroid Build Coastguard Worker   CfgVector<RegNumT> *Source;
1258*03ce13f7SAndroid Build Coastguard Worker 
1259*03ce13f7SAndroid Build Coastguard Worker   switch (Ty) {
1260*03ce13f7SAndroid Build Coastguard Worker   default: {
1261*03ce13f7SAndroid Build Coastguard Worker     llvm::report_fatal_error("argInVFP: Invalid type.");
1262*03ce13f7SAndroid Build Coastguard Worker     return false;
1263*03ce13f7SAndroid Build Coastguard Worker   } break;
1264*03ce13f7SAndroid Build Coastguard Worker   case IceType_f32: {
1265*03ce13f7SAndroid Build Coastguard Worker     Source = &FP32Args;
1266*03ce13f7SAndroid Build Coastguard Worker   } break;
1267*03ce13f7SAndroid Build Coastguard Worker   case IceType_f64: {
1268*03ce13f7SAndroid Build Coastguard Worker     Source = &FP64Args;
1269*03ce13f7SAndroid Build Coastguard Worker   } break;
1270*03ce13f7SAndroid Build Coastguard Worker   }
1271*03ce13f7SAndroid Build Coastguard Worker 
1272*03ce13f7SAndroid Build Coastguard Worker   discardUnavailableVFPRegsAndTheirAliases(Source);
1273*03ce13f7SAndroid Build Coastguard Worker 
1274*03ce13f7SAndroid Build Coastguard Worker   if (Source->empty()) {
1275*03ce13f7SAndroid Build Coastguard Worker     VFPRegsUsed.set();
1276*03ce13f7SAndroid Build Coastguard Worker     return false;
1277*03ce13f7SAndroid Build Coastguard Worker   }
1278*03ce13f7SAndroid Build Coastguard Worker 
1279*03ce13f7SAndroid Build Coastguard Worker   *Reg = Source->back();
1280*03ce13f7SAndroid Build Coastguard Worker   VFPRegsUsed |= RegisterAliases[*Reg];
1281*03ce13f7SAndroid Build Coastguard Worker 
1282*03ce13f7SAndroid Build Coastguard Worker   // In MIPS O32 abi if fun arguments are (f32, i32) then one can not use reg_a0
1283*03ce13f7SAndroid Build Coastguard Worker   // for second argument even though it's free. f32 arg goes in reg_f12, i32 arg
1284*03ce13f7SAndroid Build Coastguard Worker   // goes in reg_a1. Similarly if arguments are (f64, i32) second argument goes
1285*03ce13f7SAndroid Build Coastguard Worker   // in reg_a3 and a0, a1 are not used.
1286*03ce13f7SAndroid Build Coastguard Worker   Source = &GPRArgs;
1287*03ce13f7SAndroid Build Coastguard Worker   // Discard one GPR reg for f32(4 bytes), two for f64(4 + 4 bytes)
1288*03ce13f7SAndroid Build Coastguard Worker   if (Ty == IceType_f64) {
1289*03ce13f7SAndroid Build Coastguard Worker     // In MIPS o32 abi, when we use GPR argument pairs to store F64 values, pair
1290*03ce13f7SAndroid Build Coastguard Worker     // must be aligned at even register. Similarly when we discard GPR registers
1291*03ce13f7SAndroid Build Coastguard Worker     // when some arguments from starting 16 bytes goes in FPR, we must take care
1292*03ce13f7SAndroid Build Coastguard Worker     // of alignment. For example if fun args are (f32, f64, f32), for first f32
1293*03ce13f7SAndroid Build Coastguard Worker     // we discard a0, now for f64 argument, which will go in F14F15, we must
1294*03ce13f7SAndroid Build Coastguard Worker     // first align GPR vector to even register by discarding a1, then discard
1295*03ce13f7SAndroid Build Coastguard Worker     // two GPRs a2 and a3. Now last f32 argument will go on stack.
1296*03ce13f7SAndroid Build Coastguard Worker     alignGPR(Source);
1297*03ce13f7SAndroid Build Coastguard Worker     discardNextGPRAndItsAliases(Source);
1298*03ce13f7SAndroid Build Coastguard Worker   }
1299*03ce13f7SAndroid Build Coastguard Worker   discardNextGPRAndItsAliases(Source);
1300*03ce13f7SAndroid Build Coastguard Worker   return true;
1301*03ce13f7SAndroid Build Coastguard Worker }
1302*03ce13f7SAndroid Build Coastguard Worker 
discardUnavailableVFPRegsAndTheirAliases(CfgVector<RegNumT> * Regs)1303*03ce13f7SAndroid Build Coastguard Worker void TargetMIPS32::CallingConv::discardUnavailableVFPRegsAndTheirAliases(
1304*03ce13f7SAndroid Build Coastguard Worker     CfgVector<RegNumT> *Regs) {
1305*03ce13f7SAndroid Build Coastguard Worker   while (!Regs->empty() && VFPRegsUsed[Regs->back()]) {
1306*03ce13f7SAndroid Build Coastguard Worker     Regs->pop_back();
1307*03ce13f7SAndroid Build Coastguard Worker   }
1308*03ce13f7SAndroid Build Coastguard Worker }
1309*03ce13f7SAndroid Build Coastguard Worker 
lowerArguments()1310*03ce13f7SAndroid Build Coastguard Worker void TargetMIPS32::lowerArguments() {
1311*03ce13f7SAndroid Build Coastguard Worker   VarList &Args = Func->getArgs();
1312*03ce13f7SAndroid Build Coastguard Worker   TargetMIPS32::CallingConv CC;
1313*03ce13f7SAndroid Build Coastguard Worker 
1314*03ce13f7SAndroid Build Coastguard Worker   // For each register argument, replace Arg in the argument list with the home
1315*03ce13f7SAndroid Build Coastguard Worker   // register. Then generate an instruction in the prolog to copy the home
1316*03ce13f7SAndroid Build Coastguard Worker   // register to the assigned location of Arg.
1317*03ce13f7SAndroid Build Coastguard Worker   Context.init(Func->getEntryNode());
1318*03ce13f7SAndroid Build Coastguard Worker   Context.setInsertPoint(Context.getCur());
1319*03ce13f7SAndroid Build Coastguard Worker 
1320*03ce13f7SAndroid Build Coastguard Worker   // v4f32 is returned through stack. $4 is setup by the caller and passed as
1321*03ce13f7SAndroid Build Coastguard Worker   // first argument implicitly. Callee then copies the return vector at $4.
1322*03ce13f7SAndroid Build Coastguard Worker   Variable *ImplicitRetVec = nullptr;
1323*03ce13f7SAndroid Build Coastguard Worker   if (isVectorFloatingType(Func->getReturnType())) {
1324*03ce13f7SAndroid Build Coastguard Worker     ImplicitRetVec = Func->makeVariable(IceType_i32);
1325*03ce13f7SAndroid Build Coastguard Worker     ImplicitRetVec->setName(Func, "ImplicitRet_v4f32");
1326*03ce13f7SAndroid Build Coastguard Worker     ImplicitRetVec->setIsArg();
1327*03ce13f7SAndroid Build Coastguard Worker     Args.insert(Args.begin(), ImplicitRetVec);
1328*03ce13f7SAndroid Build Coastguard Worker     setImplicitRet(ImplicitRetVec);
1329*03ce13f7SAndroid Build Coastguard Worker   }
1330*03ce13f7SAndroid Build Coastguard Worker 
1331*03ce13f7SAndroid Build Coastguard Worker   for (SizeT i = 0, E = Args.size(); i < E; ++i) {
1332*03ce13f7SAndroid Build Coastguard Worker     Variable *Arg = Args[i];
1333*03ce13f7SAndroid Build Coastguard Worker     Type Ty = Arg->getType();
1334*03ce13f7SAndroid Build Coastguard Worker     RegNumT RegNum;
1335*03ce13f7SAndroid Build Coastguard Worker     if (!CC.argInReg(Ty, i, &RegNum)) {
1336*03ce13f7SAndroid Build Coastguard Worker       continue;
1337*03ce13f7SAndroid Build Coastguard Worker     }
1338*03ce13f7SAndroid Build Coastguard Worker     Variable *RegisterArg = Func->makeVariable(Ty);
1339*03ce13f7SAndroid Build Coastguard Worker     if (BuildDefs::dump()) {
1340*03ce13f7SAndroid Build Coastguard Worker       RegisterArg->setName(Func, "home_reg:" + Arg->getName());
1341*03ce13f7SAndroid Build Coastguard Worker     }
1342*03ce13f7SAndroid Build Coastguard Worker     RegisterArg->setIsArg();
1343*03ce13f7SAndroid Build Coastguard Worker     Arg->setIsArg(false);
1344*03ce13f7SAndroid Build Coastguard Worker     Args[i] = RegisterArg;
1345*03ce13f7SAndroid Build Coastguard Worker 
1346*03ce13f7SAndroid Build Coastguard Worker     if (isVectorType(Ty)) {
1347*03ce13f7SAndroid Build Coastguard Worker       auto *RegisterArgVec = llvm::cast<VariableVecOn32>(RegisterArg);
1348*03ce13f7SAndroid Build Coastguard Worker       RegisterArgVec->initVecElement(Func);
1349*03ce13f7SAndroid Build Coastguard Worker       RegisterArgVec->getContainers()[0]->setRegNum(
1350*03ce13f7SAndroid Build Coastguard Worker           RegNumT::fixme((unsigned)RegNum + 0));
1351*03ce13f7SAndroid Build Coastguard Worker       RegisterArgVec->getContainers()[1]->setRegNum(
1352*03ce13f7SAndroid Build Coastguard Worker           RegNumT::fixme((unsigned)RegNum + 1));
1353*03ce13f7SAndroid Build Coastguard Worker       // First two elements of second vector argument are passed
1354*03ce13f7SAndroid Build Coastguard Worker       // in $6:$7 and remaining two on stack. Do not assign register
1355*03ce13f7SAndroid Build Coastguard Worker       // to this is second vector argument.
1356*03ce13f7SAndroid Build Coastguard Worker       if (i == 0) {
1357*03ce13f7SAndroid Build Coastguard Worker         RegisterArgVec->getContainers()[2]->setRegNum(
1358*03ce13f7SAndroid Build Coastguard Worker             RegNumT::fixme((unsigned)RegNum + 2));
1359*03ce13f7SAndroid Build Coastguard Worker         RegisterArgVec->getContainers()[3]->setRegNum(
1360*03ce13f7SAndroid Build Coastguard Worker             RegNumT::fixme((unsigned)RegNum + 3));
1361*03ce13f7SAndroid Build Coastguard Worker       } else {
1362*03ce13f7SAndroid Build Coastguard Worker         RegisterArgVec->getContainers()[2]->setRegNum(
1363*03ce13f7SAndroid Build Coastguard Worker             RegNumT::fixme(RegNumT()));
1364*03ce13f7SAndroid Build Coastguard Worker         RegisterArgVec->getContainers()[3]->setRegNum(
1365*03ce13f7SAndroid Build Coastguard Worker             RegNumT::fixme(RegNumT()));
1366*03ce13f7SAndroid Build Coastguard Worker       }
1367*03ce13f7SAndroid Build Coastguard Worker     } else {
1368*03ce13f7SAndroid Build Coastguard Worker       switch (Ty) {
1369*03ce13f7SAndroid Build Coastguard Worker       default: {
1370*03ce13f7SAndroid Build Coastguard Worker         RegisterArg->setRegNum(RegNum);
1371*03ce13f7SAndroid Build Coastguard Worker       } break;
1372*03ce13f7SAndroid Build Coastguard Worker       case IceType_i64: {
1373*03ce13f7SAndroid Build Coastguard Worker         auto *RegisterArg64 = llvm::cast<Variable64On32>(RegisterArg);
1374*03ce13f7SAndroid Build Coastguard Worker         RegisterArg64->initHiLo(Func);
1375*03ce13f7SAndroid Build Coastguard Worker         RegisterArg64->getLo()->setRegNum(
1376*03ce13f7SAndroid Build Coastguard Worker             RegNumT::fixme(RegMIPS32::get64PairFirstRegNum(RegNum)));
1377*03ce13f7SAndroid Build Coastguard Worker         RegisterArg64->getHi()->setRegNum(
1378*03ce13f7SAndroid Build Coastguard Worker             RegNumT::fixme(RegMIPS32::get64PairSecondRegNum(RegNum)));
1379*03ce13f7SAndroid Build Coastguard Worker       } break;
1380*03ce13f7SAndroid Build Coastguard Worker       }
1381*03ce13f7SAndroid Build Coastguard Worker     }
1382*03ce13f7SAndroid Build Coastguard Worker     Context.insert<InstAssign>(Arg, RegisterArg);
1383*03ce13f7SAndroid Build Coastguard Worker   }
1384*03ce13f7SAndroid Build Coastguard Worker 
1385*03ce13f7SAndroid Build Coastguard Worker   // Insert fake use of ImplicitRet_v4f32 to keep it live
1386*03ce13f7SAndroid Build Coastguard Worker   if (ImplicitRetVec) {
1387*03ce13f7SAndroid Build Coastguard Worker     for (CfgNode *Node : Func->getNodes()) {
1388*03ce13f7SAndroid Build Coastguard Worker       for (Inst &Instr : Node->getInsts()) {
1389*03ce13f7SAndroid Build Coastguard Worker         if (llvm::isa<InstRet>(&Instr)) {
1390*03ce13f7SAndroid Build Coastguard Worker           Context.setInsertPoint(instToIterator(&Instr));
1391*03ce13f7SAndroid Build Coastguard Worker           Context.insert<InstFakeUse>(ImplicitRetVec);
1392*03ce13f7SAndroid Build Coastguard Worker           break;
1393*03ce13f7SAndroid Build Coastguard Worker         }
1394*03ce13f7SAndroid Build Coastguard Worker       }
1395*03ce13f7SAndroid Build Coastguard Worker     }
1396*03ce13f7SAndroid Build Coastguard Worker   }
1397*03ce13f7SAndroid Build Coastguard Worker }
1398*03ce13f7SAndroid Build Coastguard Worker 
stackSlotType()1399*03ce13f7SAndroid Build Coastguard Worker Type TargetMIPS32::stackSlotType() { return IceType_i32; }
1400*03ce13f7SAndroid Build Coastguard Worker 
1401*03ce13f7SAndroid Build Coastguard Worker // Helper function for addProlog().
1402*03ce13f7SAndroid Build Coastguard Worker //
1403*03ce13f7SAndroid Build Coastguard Worker // This assumes Arg is an argument passed on the stack. This sets the frame
1404*03ce13f7SAndroid Build Coastguard Worker // offset for Arg and updates InArgsSizeBytes according to Arg's width. For an
1405*03ce13f7SAndroid Build Coastguard Worker // I64 arg that has been split into Lo and Hi components, it calls itself
1406*03ce13f7SAndroid Build Coastguard Worker // recursively on the components, taking care to handle Lo first because of the
1407*03ce13f7SAndroid Build Coastguard Worker // little-endian architecture. Lastly, this function generates an instruction
1408*03ce13f7SAndroid Build Coastguard Worker // to copy Arg into its assigned register if applicable.
finishArgumentLowering(Variable * Arg,bool PartialOnStack,Variable * FramePtr,size_t BasicFrameOffset,size_t * InArgsSizeBytes)1409*03ce13f7SAndroid Build Coastguard Worker void TargetMIPS32::finishArgumentLowering(Variable *Arg, bool PartialOnStack,
1410*03ce13f7SAndroid Build Coastguard Worker                                           Variable *FramePtr,
1411*03ce13f7SAndroid Build Coastguard Worker                                           size_t BasicFrameOffset,
1412*03ce13f7SAndroid Build Coastguard Worker                                           size_t *InArgsSizeBytes) {
1413*03ce13f7SAndroid Build Coastguard Worker   const Type Ty = Arg->getType();
1414*03ce13f7SAndroid Build Coastguard Worker   *InArgsSizeBytes = applyStackAlignmentTy(*InArgsSizeBytes, Ty);
1415*03ce13f7SAndroid Build Coastguard Worker 
1416*03ce13f7SAndroid Build Coastguard Worker   // If $4 is used for any scalar type (or returining v4f32) then the next
1417*03ce13f7SAndroid Build Coastguard Worker   // vector type if passed in $6:$7:stack:stack. Load 3nd and 4th element
1418*03ce13f7SAndroid Build Coastguard Worker   // from agument stack.
1419*03ce13f7SAndroid Build Coastguard Worker   if (auto *ArgVecOn32 = llvm::dyn_cast<VariableVecOn32>(Arg)) {
1420*03ce13f7SAndroid Build Coastguard Worker     if (PartialOnStack == false) {
1421*03ce13f7SAndroid Build Coastguard Worker       auto *Elem0 = ArgVecOn32->getContainers()[0];
1422*03ce13f7SAndroid Build Coastguard Worker       auto *Elem1 = ArgVecOn32->getContainers()[1];
1423*03ce13f7SAndroid Build Coastguard Worker       finishArgumentLowering(Elem0, PartialOnStack, FramePtr, BasicFrameOffset,
1424*03ce13f7SAndroid Build Coastguard Worker                              InArgsSizeBytes);
1425*03ce13f7SAndroid Build Coastguard Worker       finishArgumentLowering(Elem1, PartialOnStack, FramePtr, BasicFrameOffset,
1426*03ce13f7SAndroid Build Coastguard Worker                              InArgsSizeBytes);
1427*03ce13f7SAndroid Build Coastguard Worker     }
1428*03ce13f7SAndroid Build Coastguard Worker     auto *Elem2 = ArgVecOn32->getContainers()[2];
1429*03ce13f7SAndroid Build Coastguard Worker     auto *Elem3 = ArgVecOn32->getContainers()[3];
1430*03ce13f7SAndroid Build Coastguard Worker     finishArgumentLowering(Elem2, PartialOnStack, FramePtr, BasicFrameOffset,
1431*03ce13f7SAndroid Build Coastguard Worker                            InArgsSizeBytes);
1432*03ce13f7SAndroid Build Coastguard Worker     finishArgumentLowering(Elem3, PartialOnStack, FramePtr, BasicFrameOffset,
1433*03ce13f7SAndroid Build Coastguard Worker                            InArgsSizeBytes);
1434*03ce13f7SAndroid Build Coastguard Worker     return;
1435*03ce13f7SAndroid Build Coastguard Worker   }
1436*03ce13f7SAndroid Build Coastguard Worker 
1437*03ce13f7SAndroid Build Coastguard Worker   if (auto *Arg64On32 = llvm::dyn_cast<Variable64On32>(Arg)) {
1438*03ce13f7SAndroid Build Coastguard Worker     Variable *const Lo = Arg64On32->getLo();
1439*03ce13f7SAndroid Build Coastguard Worker     Variable *const Hi = Arg64On32->getHi();
1440*03ce13f7SAndroid Build Coastguard Worker     finishArgumentLowering(Lo, PartialOnStack, FramePtr, BasicFrameOffset,
1441*03ce13f7SAndroid Build Coastguard Worker                            InArgsSizeBytes);
1442*03ce13f7SAndroid Build Coastguard Worker     finishArgumentLowering(Hi, PartialOnStack, FramePtr, BasicFrameOffset,
1443*03ce13f7SAndroid Build Coastguard Worker                            InArgsSizeBytes);
1444*03ce13f7SAndroid Build Coastguard Worker     return;
1445*03ce13f7SAndroid Build Coastguard Worker   }
1446*03ce13f7SAndroid Build Coastguard Worker 
1447*03ce13f7SAndroid Build Coastguard Worker   assert(Ty != IceType_i64);
1448*03ce13f7SAndroid Build Coastguard Worker   assert(!isVectorType(Ty));
1449*03ce13f7SAndroid Build Coastguard Worker 
1450*03ce13f7SAndroid Build Coastguard Worker   const int32_t ArgStackOffset = BasicFrameOffset + *InArgsSizeBytes;
1451*03ce13f7SAndroid Build Coastguard Worker   *InArgsSizeBytes += typeWidthInBytesOnStack(Ty);
1452*03ce13f7SAndroid Build Coastguard Worker 
1453*03ce13f7SAndroid Build Coastguard Worker   if (!Arg->hasReg()) {
1454*03ce13f7SAndroid Build Coastguard Worker     Arg->setStackOffset(ArgStackOffset);
1455*03ce13f7SAndroid Build Coastguard Worker     return;
1456*03ce13f7SAndroid Build Coastguard Worker   }
1457*03ce13f7SAndroid Build Coastguard Worker 
1458*03ce13f7SAndroid Build Coastguard Worker   // If the argument variable has been assigned a register, we need to copy the
1459*03ce13f7SAndroid Build Coastguard Worker   // value from the stack slot.
1460*03ce13f7SAndroid Build Coastguard Worker   Variable *Parameter = Func->makeVariable(Ty);
1461*03ce13f7SAndroid Build Coastguard Worker   Parameter->setMustNotHaveReg();
1462*03ce13f7SAndroid Build Coastguard Worker   Parameter->setStackOffset(ArgStackOffset);
1463*03ce13f7SAndroid Build Coastguard Worker   _mov(Arg, Parameter);
1464*03ce13f7SAndroid Build Coastguard Worker }
1465*03ce13f7SAndroid Build Coastguard Worker 
addProlog(CfgNode * Node)1466*03ce13f7SAndroid Build Coastguard Worker void TargetMIPS32::addProlog(CfgNode *Node) {
1467*03ce13f7SAndroid Build Coastguard Worker   // Stack frame layout:
1468*03ce13f7SAndroid Build Coastguard Worker   //
1469*03ce13f7SAndroid Build Coastguard Worker   // +------------------------+
1470*03ce13f7SAndroid Build Coastguard Worker   // | 1. preserved registers |
1471*03ce13f7SAndroid Build Coastguard Worker   // +------------------------+
1472*03ce13f7SAndroid Build Coastguard Worker   // | 2. padding             |
1473*03ce13f7SAndroid Build Coastguard Worker   // +------------------------+
1474*03ce13f7SAndroid Build Coastguard Worker   // | 3. global spill area   |
1475*03ce13f7SAndroid Build Coastguard Worker   // +------------------------+
1476*03ce13f7SAndroid Build Coastguard Worker   // | 4. padding             |
1477*03ce13f7SAndroid Build Coastguard Worker   // +------------------------+
1478*03ce13f7SAndroid Build Coastguard Worker   // | 5. local spill area    |
1479*03ce13f7SAndroid Build Coastguard Worker   // +------------------------+
1480*03ce13f7SAndroid Build Coastguard Worker   // | 6. padding             |
1481*03ce13f7SAndroid Build Coastguard Worker   // +------------------------+
1482*03ce13f7SAndroid Build Coastguard Worker   // | 7. allocas             |
1483*03ce13f7SAndroid Build Coastguard Worker   // +------------------------+
1484*03ce13f7SAndroid Build Coastguard Worker   // | 8. padding             |
1485*03ce13f7SAndroid Build Coastguard Worker   // +------------------------+
1486*03ce13f7SAndroid Build Coastguard Worker   // | 9. out args            |
1487*03ce13f7SAndroid Build Coastguard Worker   // +------------------------+ <--- StackPointer
1488*03ce13f7SAndroid Build Coastguard Worker   //
1489*03ce13f7SAndroid Build Coastguard Worker   // The following variables record the size in bytes of the given areas:
1490*03ce13f7SAndroid Build Coastguard Worker   //  * PreservedRegsSizeBytes: area 1
1491*03ce13f7SAndroid Build Coastguard Worker   //  * SpillAreaPaddingBytes:  area 2
1492*03ce13f7SAndroid Build Coastguard Worker   //  * GlobalsSize:            area 3
1493*03ce13f7SAndroid Build Coastguard Worker   //  * GlobalsAndSubsequentPaddingSize: areas 3 - 4
1494*03ce13f7SAndroid Build Coastguard Worker   //  * LocalsSpillAreaSize:    area 5
1495*03ce13f7SAndroid Build Coastguard Worker   //  * SpillAreaSizeBytes:     areas 2 - 9
1496*03ce13f7SAndroid Build Coastguard Worker   //  * maxOutArgsSizeBytes():  area 9
1497*03ce13f7SAndroid Build Coastguard Worker 
1498*03ce13f7SAndroid Build Coastguard Worker   Context.init(Node);
1499*03ce13f7SAndroid Build Coastguard Worker   Context.setInsertPoint(Context.getCur());
1500*03ce13f7SAndroid Build Coastguard Worker 
1501*03ce13f7SAndroid Build Coastguard Worker   SmallBitVector CalleeSaves = getRegisterSet(RegSet_CalleeSave, RegSet_None);
1502*03ce13f7SAndroid Build Coastguard Worker   RegsUsed = SmallBitVector(CalleeSaves.size());
1503*03ce13f7SAndroid Build Coastguard Worker 
1504*03ce13f7SAndroid Build Coastguard Worker   VarList SortedSpilledVariables;
1505*03ce13f7SAndroid Build Coastguard Worker 
1506*03ce13f7SAndroid Build Coastguard Worker   size_t GlobalsSize = 0;
1507*03ce13f7SAndroid Build Coastguard Worker   // If there is a separate locals area, this represents that area. Otherwise
1508*03ce13f7SAndroid Build Coastguard Worker   // it counts any variable not counted by GlobalsSize.
1509*03ce13f7SAndroid Build Coastguard Worker   SpillAreaSizeBytes = 0;
1510*03ce13f7SAndroid Build Coastguard Worker   // If there is a separate locals area, this specifies the alignment for it.
1511*03ce13f7SAndroid Build Coastguard Worker   uint32_t LocalsSlotsAlignmentBytes = 0;
1512*03ce13f7SAndroid Build Coastguard Worker   // The entire spill locations area gets aligned to largest natural alignment
1513*03ce13f7SAndroid Build Coastguard Worker   // of the variables that have a spill slot.
1514*03ce13f7SAndroid Build Coastguard Worker   uint32_t SpillAreaAlignmentBytes = 0;
1515*03ce13f7SAndroid Build Coastguard Worker   // For now, we don't have target-specific variables that need special
1516*03ce13f7SAndroid Build Coastguard Worker   // treatment (no stack-slot-linked SpillVariable type).
1517*03ce13f7SAndroid Build Coastguard Worker   std::function<bool(Variable *)> TargetVarHook = [](Variable *Var) {
1518*03ce13f7SAndroid Build Coastguard Worker     static constexpr bool AssignStackSlot = false;
1519*03ce13f7SAndroid Build Coastguard Worker     static constexpr bool DontAssignStackSlot = !AssignStackSlot;
1520*03ce13f7SAndroid Build Coastguard Worker     if (llvm::isa<Variable64On32>(Var)) {
1521*03ce13f7SAndroid Build Coastguard Worker       return DontAssignStackSlot;
1522*03ce13f7SAndroid Build Coastguard Worker     }
1523*03ce13f7SAndroid Build Coastguard Worker     return AssignStackSlot;
1524*03ce13f7SAndroid Build Coastguard Worker   };
1525*03ce13f7SAndroid Build Coastguard Worker 
1526*03ce13f7SAndroid Build Coastguard Worker   // Compute the list of spilled variables and bounds for GlobalsSize, etc.
1527*03ce13f7SAndroid Build Coastguard Worker   getVarStackSlotParams(SortedSpilledVariables, RegsUsed, &GlobalsSize,
1528*03ce13f7SAndroid Build Coastguard Worker                         &SpillAreaSizeBytes, &SpillAreaAlignmentBytes,
1529*03ce13f7SAndroid Build Coastguard Worker                         &LocalsSlotsAlignmentBytes, TargetVarHook);
1530*03ce13f7SAndroid Build Coastguard Worker   uint32_t LocalsSpillAreaSize = SpillAreaSizeBytes;
1531*03ce13f7SAndroid Build Coastguard Worker   SpillAreaSizeBytes += GlobalsSize;
1532*03ce13f7SAndroid Build Coastguard Worker 
1533*03ce13f7SAndroid Build Coastguard Worker   PreservedGPRs.reserve(CalleeSaves.size());
1534*03ce13f7SAndroid Build Coastguard Worker 
1535*03ce13f7SAndroid Build Coastguard Worker   // Consider FP and RA as callee-save / used as needed.
1536*03ce13f7SAndroid Build Coastguard Worker   if (UsesFramePointer) {
1537*03ce13f7SAndroid Build Coastguard Worker     if (RegsUsed[RegMIPS32::Reg_FP]) {
1538*03ce13f7SAndroid Build Coastguard Worker       llvm::report_fatal_error("Frame pointer has been used.");
1539*03ce13f7SAndroid Build Coastguard Worker     }
1540*03ce13f7SAndroid Build Coastguard Worker     CalleeSaves[RegMIPS32::Reg_FP] = true;
1541*03ce13f7SAndroid Build Coastguard Worker     RegsUsed[RegMIPS32::Reg_FP] = true;
1542*03ce13f7SAndroid Build Coastguard Worker   }
1543*03ce13f7SAndroid Build Coastguard Worker   if (!MaybeLeafFunc) {
1544*03ce13f7SAndroid Build Coastguard Worker     CalleeSaves[RegMIPS32::Reg_RA] = true;
1545*03ce13f7SAndroid Build Coastguard Worker     RegsUsed[RegMIPS32::Reg_RA] = true;
1546*03ce13f7SAndroid Build Coastguard Worker   }
1547*03ce13f7SAndroid Build Coastguard Worker 
1548*03ce13f7SAndroid Build Coastguard Worker   // Make two passes over the used registers. The first pass records all the
1549*03ce13f7SAndroid Build Coastguard Worker   // used registers -- and their aliases. Then, we figure out which GPR
1550*03ce13f7SAndroid Build Coastguard Worker   // registers should be saved.
1551*03ce13f7SAndroid Build Coastguard Worker   SmallBitVector ToPreserve(RegMIPS32::Reg_NUM);
1552*03ce13f7SAndroid Build Coastguard Worker   for (SizeT i = 0; i < CalleeSaves.size(); ++i) {
1553*03ce13f7SAndroid Build Coastguard Worker     if (CalleeSaves[i] && RegsUsed[i]) {
1554*03ce13f7SAndroid Build Coastguard Worker       ToPreserve |= RegisterAliases[i];
1555*03ce13f7SAndroid Build Coastguard Worker     }
1556*03ce13f7SAndroid Build Coastguard Worker   }
1557*03ce13f7SAndroid Build Coastguard Worker 
1558*03ce13f7SAndroid Build Coastguard Worker   uint32_t NumCallee = 0;
1559*03ce13f7SAndroid Build Coastguard Worker 
1560*03ce13f7SAndroid Build Coastguard Worker   // RegClasses is a tuple of
1561*03ce13f7SAndroid Build Coastguard Worker   //
1562*03ce13f7SAndroid Build Coastguard Worker   // <First Register in Class, Last Register in Class, Vector of Save Registers>
1563*03ce13f7SAndroid Build Coastguard Worker   //
1564*03ce13f7SAndroid Build Coastguard Worker   // We use this tuple to figure out which register we should save/restore
1565*03ce13f7SAndroid Build Coastguard Worker   // during
1566*03ce13f7SAndroid Build Coastguard Worker   // prolog/epilog.
1567*03ce13f7SAndroid Build Coastguard Worker   using RegClassType = std::tuple<uint32_t, uint32_t, VarList *>;
1568*03ce13f7SAndroid Build Coastguard Worker   const RegClassType RegClass = RegClassType(
1569*03ce13f7SAndroid Build Coastguard Worker       RegMIPS32::Reg_GPR_First, RegMIPS32::Reg_FPR_Last, &PreservedGPRs);
1570*03ce13f7SAndroid Build Coastguard Worker   const uint32_t FirstRegInClass = std::get<0>(RegClass);
1571*03ce13f7SAndroid Build Coastguard Worker   const uint32_t LastRegInClass = std::get<1>(RegClass);
1572*03ce13f7SAndroid Build Coastguard Worker   VarList *const PreservedRegsInClass = std::get<2>(RegClass);
1573*03ce13f7SAndroid Build Coastguard Worker   for (uint32_t Reg = LastRegInClass; Reg > FirstRegInClass; Reg--) {
1574*03ce13f7SAndroid Build Coastguard Worker     if (!ToPreserve[Reg]) {
1575*03ce13f7SAndroid Build Coastguard Worker       continue;
1576*03ce13f7SAndroid Build Coastguard Worker     }
1577*03ce13f7SAndroid Build Coastguard Worker     ++NumCallee;
1578*03ce13f7SAndroid Build Coastguard Worker     Variable *PhysicalRegister = getPhysicalRegister(RegNumT::fromInt(Reg));
1579*03ce13f7SAndroid Build Coastguard Worker     PreservedRegsSizeBytes +=
1580*03ce13f7SAndroid Build Coastguard Worker         typeWidthInBytesOnStack(PhysicalRegister->getType());
1581*03ce13f7SAndroid Build Coastguard Worker     PreservedRegsInClass->push_back(PhysicalRegister);
1582*03ce13f7SAndroid Build Coastguard Worker   }
1583*03ce13f7SAndroid Build Coastguard Worker 
1584*03ce13f7SAndroid Build Coastguard Worker   Ctx->statsUpdateRegistersSaved(NumCallee);
1585*03ce13f7SAndroid Build Coastguard Worker 
1586*03ce13f7SAndroid Build Coastguard Worker   // Align the variables area. SpillAreaPaddingBytes is the size of the region
1587*03ce13f7SAndroid Build Coastguard Worker   // after the preserved registers and before the spill areas.
1588*03ce13f7SAndroid Build Coastguard Worker   // LocalsSlotsPaddingBytes is the amount of padding between the globals and
1589*03ce13f7SAndroid Build Coastguard Worker   // locals area if they are separate.
1590*03ce13f7SAndroid Build Coastguard Worker   assert(SpillAreaAlignmentBytes <= MIPS32_STACK_ALIGNMENT_BYTES);
1591*03ce13f7SAndroid Build Coastguard Worker   (void)MIPS32_STACK_ALIGNMENT_BYTES;
1592*03ce13f7SAndroid Build Coastguard Worker   assert(LocalsSlotsAlignmentBytes <= SpillAreaAlignmentBytes);
1593*03ce13f7SAndroid Build Coastguard Worker   uint32_t SpillAreaPaddingBytes = 0;
1594*03ce13f7SAndroid Build Coastguard Worker   uint32_t LocalsSlotsPaddingBytes = 0;
1595*03ce13f7SAndroid Build Coastguard Worker   alignStackSpillAreas(PreservedRegsSizeBytes, SpillAreaAlignmentBytes,
1596*03ce13f7SAndroid Build Coastguard Worker                        GlobalsSize, LocalsSlotsAlignmentBytes,
1597*03ce13f7SAndroid Build Coastguard Worker                        &SpillAreaPaddingBytes, &LocalsSlotsPaddingBytes);
1598*03ce13f7SAndroid Build Coastguard Worker   SpillAreaSizeBytes += SpillAreaPaddingBytes + LocalsSlotsPaddingBytes;
1599*03ce13f7SAndroid Build Coastguard Worker   uint32_t GlobalsAndSubsequentPaddingSize =
1600*03ce13f7SAndroid Build Coastguard Worker       GlobalsSize + LocalsSlotsPaddingBytes;
1601*03ce13f7SAndroid Build Coastguard Worker 
1602*03ce13f7SAndroid Build Coastguard Worker   // Adds the out args space to the stack, and align SP if necessary.
1603*03ce13f7SAndroid Build Coastguard Worker   if (!NeedsStackAlignment) {
1604*03ce13f7SAndroid Build Coastguard Worker     SpillAreaSizeBytes += MaxOutArgsSizeBytes * (VariableAllocaUsed ? 0 : 1);
1605*03ce13f7SAndroid Build Coastguard Worker   } else {
1606*03ce13f7SAndroid Build Coastguard Worker     SpillAreaSizeBytes = applyStackAlignment(
1607*03ce13f7SAndroid Build Coastguard Worker         SpillAreaSizeBytes +
1608*03ce13f7SAndroid Build Coastguard Worker         (VariableAllocaUsed ? VariableAllocaAlignBytes : MaxOutArgsSizeBytes));
1609*03ce13f7SAndroid Build Coastguard Worker   }
1610*03ce13f7SAndroid Build Coastguard Worker 
1611*03ce13f7SAndroid Build Coastguard Worker   // Combine fixed alloca with SpillAreaSize.
1612*03ce13f7SAndroid Build Coastguard Worker   SpillAreaSizeBytes += FixedAllocaSizeBytes;
1613*03ce13f7SAndroid Build Coastguard Worker 
1614*03ce13f7SAndroid Build Coastguard Worker   TotalStackSizeBytes =
1615*03ce13f7SAndroid Build Coastguard Worker       applyStackAlignment(PreservedRegsSizeBytes + SpillAreaSizeBytes);
1616*03ce13f7SAndroid Build Coastguard Worker 
1617*03ce13f7SAndroid Build Coastguard Worker   // Generate "addiu sp, sp, -TotalStackSizeBytes"
1618*03ce13f7SAndroid Build Coastguard Worker   if (TotalStackSizeBytes) {
1619*03ce13f7SAndroid Build Coastguard Worker     // Use the scratch register if needed to legalize the immediate.
1620*03ce13f7SAndroid Build Coastguard Worker     Variable *SP = getPhysicalRegister(RegMIPS32::Reg_SP);
1621*03ce13f7SAndroid Build Coastguard Worker     _addiu(SP, SP, -TotalStackSizeBytes);
1622*03ce13f7SAndroid Build Coastguard Worker   }
1623*03ce13f7SAndroid Build Coastguard Worker 
1624*03ce13f7SAndroid Build Coastguard Worker   Ctx->statsUpdateFrameBytes(TotalStackSizeBytes);
1625*03ce13f7SAndroid Build Coastguard Worker 
1626*03ce13f7SAndroid Build Coastguard Worker   if (!PreservedGPRs.empty()) {
1627*03ce13f7SAndroid Build Coastguard Worker     uint32_t StackOffset = TotalStackSizeBytes;
1628*03ce13f7SAndroid Build Coastguard Worker     for (Variable *Var : *PreservedRegsInClass) {
1629*03ce13f7SAndroid Build Coastguard Worker       Type RegType;
1630*03ce13f7SAndroid Build Coastguard Worker       if (RegMIPS32::isFPRReg(Var->getRegNum()))
1631*03ce13f7SAndroid Build Coastguard Worker         RegType = IceType_f32;
1632*03ce13f7SAndroid Build Coastguard Worker       else
1633*03ce13f7SAndroid Build Coastguard Worker         RegType = IceType_i32;
1634*03ce13f7SAndroid Build Coastguard Worker       auto *PhysicalRegister = makeReg(RegType, Var->getRegNum());
1635*03ce13f7SAndroid Build Coastguard Worker       StackOffset -= typeWidthInBytesOnStack(RegType);
1636*03ce13f7SAndroid Build Coastguard Worker       Variable *SP = getPhysicalRegister(RegMIPS32::Reg_SP);
1637*03ce13f7SAndroid Build Coastguard Worker       OperandMIPS32Mem *MemoryLocation = OperandMIPS32Mem::create(
1638*03ce13f7SAndroid Build Coastguard Worker           Func, RegType, SP,
1639*03ce13f7SAndroid Build Coastguard Worker           llvm::cast<ConstantInteger32>(Ctx->getConstantInt32(StackOffset)));
1640*03ce13f7SAndroid Build Coastguard Worker       _sw(PhysicalRegister, MemoryLocation);
1641*03ce13f7SAndroid Build Coastguard Worker     }
1642*03ce13f7SAndroid Build Coastguard Worker   }
1643*03ce13f7SAndroid Build Coastguard Worker 
1644*03ce13f7SAndroid Build Coastguard Worker   Variable *FP = getPhysicalRegister(RegMIPS32::Reg_FP);
1645*03ce13f7SAndroid Build Coastguard Worker 
1646*03ce13f7SAndroid Build Coastguard Worker   // Generate "mov FP, SP" if needed.
1647*03ce13f7SAndroid Build Coastguard Worker   if (UsesFramePointer) {
1648*03ce13f7SAndroid Build Coastguard Worker     Variable *SP = getPhysicalRegister(RegMIPS32::Reg_SP);
1649*03ce13f7SAndroid Build Coastguard Worker     _mov(FP, SP);
1650*03ce13f7SAndroid Build Coastguard Worker     // Keep FP live for late-stage liveness analysis (e.g. asm-verbose mode).
1651*03ce13f7SAndroid Build Coastguard Worker     Context.insert<InstFakeUse>(FP);
1652*03ce13f7SAndroid Build Coastguard Worker   }
1653*03ce13f7SAndroid Build Coastguard Worker 
1654*03ce13f7SAndroid Build Coastguard Worker   // Fill in stack offsets for stack args, and copy args into registers for
1655*03ce13f7SAndroid Build Coastguard Worker   // those that were register-allocated. Args are pushed right to left, so
1656*03ce13f7SAndroid Build Coastguard Worker   // Arg[0] is closest to the stack/frame pointer.
1657*03ce13f7SAndroid Build Coastguard Worker   const VarList &Args = Func->getArgs();
1658*03ce13f7SAndroid Build Coastguard Worker   size_t InArgsSizeBytes = MIPS32_MAX_GPR_ARG * 4;
1659*03ce13f7SAndroid Build Coastguard Worker   TargetMIPS32::CallingConv CC;
1660*03ce13f7SAndroid Build Coastguard Worker   uint32_t ArgNo = 0;
1661*03ce13f7SAndroid Build Coastguard Worker 
1662*03ce13f7SAndroid Build Coastguard Worker   for (Variable *Arg : Args) {
1663*03ce13f7SAndroid Build Coastguard Worker     RegNumT DummyReg;
1664*03ce13f7SAndroid Build Coastguard Worker     const Type Ty = Arg->getType();
1665*03ce13f7SAndroid Build Coastguard Worker     bool PartialOnStack;
1666*03ce13f7SAndroid Build Coastguard Worker     // Skip arguments passed in registers.
1667*03ce13f7SAndroid Build Coastguard Worker     if (CC.argInReg(Ty, ArgNo, &DummyReg)) {
1668*03ce13f7SAndroid Build Coastguard Worker       // Load argument from stack:
1669*03ce13f7SAndroid Build Coastguard Worker       // 1. If this is first vector argument and return type is v4f32.
1670*03ce13f7SAndroid Build Coastguard Worker       //    In this case $4 is used to pass stack address implicitly.
1671*03ce13f7SAndroid Build Coastguard Worker       //    3rd and 4th element of vector argument is passed through stack.
1672*03ce13f7SAndroid Build Coastguard Worker       // 2. If this is second vector argument.
1673*03ce13f7SAndroid Build Coastguard Worker       if (ArgNo != 0 && isVectorType(Ty)) {
1674*03ce13f7SAndroid Build Coastguard Worker         PartialOnStack = true;
1675*03ce13f7SAndroid Build Coastguard Worker         finishArgumentLowering(Arg, PartialOnStack, FP, TotalStackSizeBytes,
1676*03ce13f7SAndroid Build Coastguard Worker                                &InArgsSizeBytes);
1677*03ce13f7SAndroid Build Coastguard Worker       }
1678*03ce13f7SAndroid Build Coastguard Worker     } else {
1679*03ce13f7SAndroid Build Coastguard Worker       PartialOnStack = false;
1680*03ce13f7SAndroid Build Coastguard Worker       finishArgumentLowering(Arg, PartialOnStack, FP, TotalStackSizeBytes,
1681*03ce13f7SAndroid Build Coastguard Worker                              &InArgsSizeBytes);
1682*03ce13f7SAndroid Build Coastguard Worker     }
1683*03ce13f7SAndroid Build Coastguard Worker     ++ArgNo;
1684*03ce13f7SAndroid Build Coastguard Worker   }
1685*03ce13f7SAndroid Build Coastguard Worker 
1686*03ce13f7SAndroid Build Coastguard Worker   // Fill in stack offsets for locals.
1687*03ce13f7SAndroid Build Coastguard Worker   assignVarStackSlots(SortedSpilledVariables, SpillAreaPaddingBytes,
1688*03ce13f7SAndroid Build Coastguard Worker                       SpillAreaSizeBytes, GlobalsAndSubsequentPaddingSize);
1689*03ce13f7SAndroid Build Coastguard Worker   this->HasComputedFrame = true;
1690*03ce13f7SAndroid Build Coastguard Worker 
1691*03ce13f7SAndroid Build Coastguard Worker   if (BuildDefs::dump() && Func->isVerbose(IceV_Frame)) {
1692*03ce13f7SAndroid Build Coastguard Worker     OstreamLocker _(Func->getContext());
1693*03ce13f7SAndroid Build Coastguard Worker     Ostream &Str = Func->getContext()->getStrDump();
1694*03ce13f7SAndroid Build Coastguard Worker 
1695*03ce13f7SAndroid Build Coastguard Worker     Str << "Stack layout:\n";
1696*03ce13f7SAndroid Build Coastguard Worker     uint32_t SPAdjustmentPaddingSize =
1697*03ce13f7SAndroid Build Coastguard Worker         SpillAreaSizeBytes - LocalsSpillAreaSize -
1698*03ce13f7SAndroid Build Coastguard Worker         GlobalsAndSubsequentPaddingSize - SpillAreaPaddingBytes -
1699*03ce13f7SAndroid Build Coastguard Worker         MaxOutArgsSizeBytes;
1700*03ce13f7SAndroid Build Coastguard Worker     Str << " in-args = " << InArgsSizeBytes << " bytes\n"
1701*03ce13f7SAndroid Build Coastguard Worker         << " preserved registers = " << PreservedRegsSizeBytes << " bytes\n"
1702*03ce13f7SAndroid Build Coastguard Worker         << " spill area padding = " << SpillAreaPaddingBytes << " bytes\n"
1703*03ce13f7SAndroid Build Coastguard Worker         << " globals spill area = " << GlobalsSize << " bytes\n"
1704*03ce13f7SAndroid Build Coastguard Worker         << " globals-locals spill areas intermediate padding = "
1705*03ce13f7SAndroid Build Coastguard Worker         << GlobalsAndSubsequentPaddingSize - GlobalsSize << " bytes\n"
1706*03ce13f7SAndroid Build Coastguard Worker         << " locals spill area = " << LocalsSpillAreaSize << " bytes\n"
1707*03ce13f7SAndroid Build Coastguard Worker         << " SP alignment padding = " << SPAdjustmentPaddingSize << " bytes\n";
1708*03ce13f7SAndroid Build Coastguard Worker 
1709*03ce13f7SAndroid Build Coastguard Worker     Str << "Stack details:\n"
1710*03ce13f7SAndroid Build Coastguard Worker         << " SP adjustment = " << SpillAreaSizeBytes << " bytes\n"
1711*03ce13f7SAndroid Build Coastguard Worker         << " spill area alignment = " << SpillAreaAlignmentBytes << " bytes\n"
1712*03ce13f7SAndroid Build Coastguard Worker         << " outgoing args size = " << MaxOutArgsSizeBytes << " bytes\n"
1713*03ce13f7SAndroid Build Coastguard Worker         << " locals spill area alignment = " << LocalsSlotsAlignmentBytes
1714*03ce13f7SAndroid Build Coastguard Worker         << " bytes\n"
1715*03ce13f7SAndroid Build Coastguard Worker         << " is FP based = " << 1 << "\n";
1716*03ce13f7SAndroid Build Coastguard Worker   }
1717*03ce13f7SAndroid Build Coastguard Worker   return;
1718*03ce13f7SAndroid Build Coastguard Worker }
1719*03ce13f7SAndroid Build Coastguard Worker 
addEpilog(CfgNode * Node)1720*03ce13f7SAndroid Build Coastguard Worker void TargetMIPS32::addEpilog(CfgNode *Node) {
1721*03ce13f7SAndroid Build Coastguard Worker   InstList &Insts = Node->getInsts();
1722*03ce13f7SAndroid Build Coastguard Worker   InstList::reverse_iterator RI, E;
1723*03ce13f7SAndroid Build Coastguard Worker   for (RI = Insts.rbegin(), E = Insts.rend(); RI != E; ++RI) {
1724*03ce13f7SAndroid Build Coastguard Worker     if (llvm::isa<InstMIPS32Ret>(*RI))
1725*03ce13f7SAndroid Build Coastguard Worker       break;
1726*03ce13f7SAndroid Build Coastguard Worker   }
1727*03ce13f7SAndroid Build Coastguard Worker   if (RI == E)
1728*03ce13f7SAndroid Build Coastguard Worker     return;
1729*03ce13f7SAndroid Build Coastguard Worker 
1730*03ce13f7SAndroid Build Coastguard Worker   // Convert the reverse_iterator position into its corresponding (forward)
1731*03ce13f7SAndroid Build Coastguard Worker   // iterator position.
1732*03ce13f7SAndroid Build Coastguard Worker   InstList::iterator InsertPoint = reverseToForwardIterator(RI);
1733*03ce13f7SAndroid Build Coastguard Worker   --InsertPoint;
1734*03ce13f7SAndroid Build Coastguard Worker   Context.init(Node);
1735*03ce13f7SAndroid Build Coastguard Worker   Context.setInsertPoint(InsertPoint);
1736*03ce13f7SAndroid Build Coastguard Worker 
1737*03ce13f7SAndroid Build Coastguard Worker   Variable *SP = getPhysicalRegister(RegMIPS32::Reg_SP);
1738*03ce13f7SAndroid Build Coastguard Worker   if (UsesFramePointer) {
1739*03ce13f7SAndroid Build Coastguard Worker     Variable *FP = getPhysicalRegister(RegMIPS32::Reg_FP);
1740*03ce13f7SAndroid Build Coastguard Worker     // For late-stage liveness analysis (e.g. asm-verbose mode), adding a fake
1741*03ce13f7SAndroid Build Coastguard Worker     // use of SP before the assignment of SP=FP keeps previous SP adjustments
1742*03ce13f7SAndroid Build Coastguard Worker     // from being dead-code eliminated.
1743*03ce13f7SAndroid Build Coastguard Worker     Context.insert<InstFakeUse>(SP);
1744*03ce13f7SAndroid Build Coastguard Worker     _mov(SP, FP);
1745*03ce13f7SAndroid Build Coastguard Worker   }
1746*03ce13f7SAndroid Build Coastguard Worker 
1747*03ce13f7SAndroid Build Coastguard Worker   VarList::reverse_iterator RIter, END;
1748*03ce13f7SAndroid Build Coastguard Worker 
1749*03ce13f7SAndroid Build Coastguard Worker   if (!PreservedGPRs.empty()) {
1750*03ce13f7SAndroid Build Coastguard Worker     uint32_t StackOffset = TotalStackSizeBytes - PreservedRegsSizeBytes;
1751*03ce13f7SAndroid Build Coastguard Worker     for (RIter = PreservedGPRs.rbegin(), END = PreservedGPRs.rend();
1752*03ce13f7SAndroid Build Coastguard Worker          RIter != END; ++RIter) {
1753*03ce13f7SAndroid Build Coastguard Worker       Type RegType;
1754*03ce13f7SAndroid Build Coastguard Worker       if (RegMIPS32::isFPRReg((*RIter)->getRegNum()))
1755*03ce13f7SAndroid Build Coastguard Worker         RegType = IceType_f32;
1756*03ce13f7SAndroid Build Coastguard Worker       else
1757*03ce13f7SAndroid Build Coastguard Worker         RegType = IceType_i32;
1758*03ce13f7SAndroid Build Coastguard Worker       auto *PhysicalRegister = makeReg(RegType, (*RIter)->getRegNum());
1759*03ce13f7SAndroid Build Coastguard Worker       Variable *SP = getPhysicalRegister(RegMIPS32::Reg_SP);
1760*03ce13f7SAndroid Build Coastguard Worker       OperandMIPS32Mem *MemoryLocation = OperandMIPS32Mem::create(
1761*03ce13f7SAndroid Build Coastguard Worker           Func, RegType, SP,
1762*03ce13f7SAndroid Build Coastguard Worker           llvm::cast<ConstantInteger32>(Ctx->getConstantInt32(StackOffset)));
1763*03ce13f7SAndroid Build Coastguard Worker       _lw(PhysicalRegister, MemoryLocation);
1764*03ce13f7SAndroid Build Coastguard Worker       StackOffset += typeWidthInBytesOnStack(PhysicalRegister->getType());
1765*03ce13f7SAndroid Build Coastguard Worker     }
1766*03ce13f7SAndroid Build Coastguard Worker   }
1767*03ce13f7SAndroid Build Coastguard Worker 
1768*03ce13f7SAndroid Build Coastguard Worker   if (TotalStackSizeBytes) {
1769*03ce13f7SAndroid Build Coastguard Worker     _addiu(SP, SP, TotalStackSizeBytes);
1770*03ce13f7SAndroid Build Coastguard Worker   }
1771*03ce13f7SAndroid Build Coastguard Worker }
1772*03ce13f7SAndroid Build Coastguard Worker 
newBaseRegister(Variable * Base,int32_t Offset,RegNumT ScratchRegNum)1773*03ce13f7SAndroid Build Coastguard Worker Variable *TargetMIPS32::PostLoweringLegalizer::newBaseRegister(
1774*03ce13f7SAndroid Build Coastguard Worker     Variable *Base, int32_t Offset, RegNumT ScratchRegNum) {
1775*03ce13f7SAndroid Build Coastguard Worker   // Legalize will likely need a lui/ori combination, but if the top bits are
1776*03ce13f7SAndroid Build Coastguard Worker   // all 0 from negating the offset and subtracting, we could use that instead.
1777*03ce13f7SAndroid Build Coastguard Worker   const bool ShouldSub = Offset != 0 && (-Offset & 0xFFFF0000) == 0;
1778*03ce13f7SAndroid Build Coastguard Worker   Variable *ScratchReg = Target->makeReg(IceType_i32, ScratchRegNum);
1779*03ce13f7SAndroid Build Coastguard Worker   if (ShouldSub) {
1780*03ce13f7SAndroid Build Coastguard Worker     Target->_addi(ScratchReg, Base, -Offset);
1781*03ce13f7SAndroid Build Coastguard Worker   } else {
1782*03ce13f7SAndroid Build Coastguard Worker     constexpr bool SignExt = true;
1783*03ce13f7SAndroid Build Coastguard Worker     if (!OperandMIPS32Mem::canHoldOffset(Base->getType(), SignExt, Offset)) {
1784*03ce13f7SAndroid Build Coastguard Worker       const uint32_t UpperBits = (Offset >> 16) & 0xFFFF;
1785*03ce13f7SAndroid Build Coastguard Worker       const uint32_t LowerBits = Offset & 0xFFFF;
1786*03ce13f7SAndroid Build Coastguard Worker       Target->_lui(ScratchReg, Target->Ctx->getConstantInt32(UpperBits));
1787*03ce13f7SAndroid Build Coastguard Worker       if (LowerBits)
1788*03ce13f7SAndroid Build Coastguard Worker         Target->_ori(ScratchReg, ScratchReg, LowerBits);
1789*03ce13f7SAndroid Build Coastguard Worker       Target->_addu(ScratchReg, ScratchReg, Base);
1790*03ce13f7SAndroid Build Coastguard Worker     } else {
1791*03ce13f7SAndroid Build Coastguard Worker       Target->_addiu(ScratchReg, Base, Offset);
1792*03ce13f7SAndroid Build Coastguard Worker     }
1793*03ce13f7SAndroid Build Coastguard Worker   }
1794*03ce13f7SAndroid Build Coastguard Worker 
1795*03ce13f7SAndroid Build Coastguard Worker   return ScratchReg;
1796*03ce13f7SAndroid Build Coastguard Worker }
1797*03ce13f7SAndroid Build Coastguard Worker 
legalizeMovFp(InstMIPS32MovFP64ToI64 * MovInstr)1798*03ce13f7SAndroid Build Coastguard Worker void TargetMIPS32::PostLoweringLegalizer::legalizeMovFp(
1799*03ce13f7SAndroid Build Coastguard Worker     InstMIPS32MovFP64ToI64 *MovInstr) {
1800*03ce13f7SAndroid Build Coastguard Worker   Variable *Dest = MovInstr->getDest();
1801*03ce13f7SAndroid Build Coastguard Worker   Operand *Src = MovInstr->getSrc(0);
1802*03ce13f7SAndroid Build Coastguard Worker   const Type SrcTy = Src->getType();
1803*03ce13f7SAndroid Build Coastguard Worker 
1804*03ce13f7SAndroid Build Coastguard Worker   if (Dest != nullptr && SrcTy == IceType_f64) {
1805*03ce13f7SAndroid Build Coastguard Worker     int32_t Offset = Dest->getStackOffset();
1806*03ce13f7SAndroid Build Coastguard Worker     auto *Base = Target->getPhysicalRegister(Target->getFrameOrStackReg());
1807*03ce13f7SAndroid Build Coastguard Worker     OperandMIPS32Mem *TAddr = OperandMIPS32Mem::create(
1808*03ce13f7SAndroid Build Coastguard Worker         Target->Func, IceType_f32, Base,
1809*03ce13f7SAndroid Build Coastguard Worker         llvm::cast<ConstantInteger32>(Target->Ctx->getConstantInt32(Offset)));
1810*03ce13f7SAndroid Build Coastguard Worker     OperandMIPS32Mem *Addr = legalizeMemOperand(TAddr);
1811*03ce13f7SAndroid Build Coastguard Worker     auto *SrcV = llvm::cast<Variable>(Src);
1812*03ce13f7SAndroid Build Coastguard Worker     Variable *SrcR;
1813*03ce13f7SAndroid Build Coastguard Worker     if (MovInstr->getInt64Part() == Int64_Lo) {
1814*03ce13f7SAndroid Build Coastguard Worker       SrcR = Target->makeReg(
1815*03ce13f7SAndroid Build Coastguard Worker           IceType_f32, RegMIPS32::get64PairFirstRegNum(SrcV->getRegNum()));
1816*03ce13f7SAndroid Build Coastguard Worker     } else {
1817*03ce13f7SAndroid Build Coastguard Worker       SrcR = Target->makeReg(
1818*03ce13f7SAndroid Build Coastguard Worker           IceType_f32, RegMIPS32::get64PairSecondRegNum(SrcV->getRegNum()));
1819*03ce13f7SAndroid Build Coastguard Worker     }
1820*03ce13f7SAndroid Build Coastguard Worker     Target->_sw(SrcR, Addr);
1821*03ce13f7SAndroid Build Coastguard Worker     if (MovInstr->isDestRedefined()) {
1822*03ce13f7SAndroid Build Coastguard Worker       Target->_set_dest_redefined();
1823*03ce13f7SAndroid Build Coastguard Worker     }
1824*03ce13f7SAndroid Build Coastguard Worker     MovInstr->setDeleted();
1825*03ce13f7SAndroid Build Coastguard Worker     return;
1826*03ce13f7SAndroid Build Coastguard Worker   }
1827*03ce13f7SAndroid Build Coastguard Worker 
1828*03ce13f7SAndroid Build Coastguard Worker   llvm::report_fatal_error("legalizeMovFp: Invalid operands");
1829*03ce13f7SAndroid Build Coastguard Worker }
1830*03ce13f7SAndroid Build Coastguard Worker 
legalizeMov(InstMIPS32Mov * MovInstr)1831*03ce13f7SAndroid Build Coastguard Worker void TargetMIPS32::PostLoweringLegalizer::legalizeMov(InstMIPS32Mov *MovInstr) {
1832*03ce13f7SAndroid Build Coastguard Worker   Variable *Dest = MovInstr->getDest();
1833*03ce13f7SAndroid Build Coastguard Worker   assert(Dest != nullptr);
1834*03ce13f7SAndroid Build Coastguard Worker   const Type DestTy = Dest->getType();
1835*03ce13f7SAndroid Build Coastguard Worker   assert(DestTy != IceType_i64);
1836*03ce13f7SAndroid Build Coastguard Worker 
1837*03ce13f7SAndroid Build Coastguard Worker   Operand *Src = MovInstr->getSrc(0);
1838*03ce13f7SAndroid Build Coastguard Worker   const Type SrcTy = Src->getType();
1839*03ce13f7SAndroid Build Coastguard Worker   (void)SrcTy;
1840*03ce13f7SAndroid Build Coastguard Worker   assert(SrcTy != IceType_i64);
1841*03ce13f7SAndroid Build Coastguard Worker 
1842*03ce13f7SAndroid Build Coastguard Worker   bool Legalized = false;
1843*03ce13f7SAndroid Build Coastguard Worker   auto *SrcR = llvm::cast<Variable>(Src);
1844*03ce13f7SAndroid Build Coastguard Worker   if (Dest->hasReg() && SrcR->hasReg()) {
1845*03ce13f7SAndroid Build Coastguard Worker     // This might be a GP to/from FP move generated due to argument passing.
1846*03ce13f7SAndroid Build Coastguard Worker     // Use mtc1/mfc1 instead of mov.[s/d] if src and dst registers are of
1847*03ce13f7SAndroid Build Coastguard Worker     // different types.
1848*03ce13f7SAndroid Build Coastguard Worker     const bool IsDstGPR = RegMIPS32::isGPRReg(Dest->getRegNum());
1849*03ce13f7SAndroid Build Coastguard Worker     const bool IsSrcGPR = RegMIPS32::isGPRReg(SrcR->getRegNum());
1850*03ce13f7SAndroid Build Coastguard Worker     const RegNumT SRegNum = SrcR->getRegNum();
1851*03ce13f7SAndroid Build Coastguard Worker     const RegNumT DRegNum = Dest->getRegNum();
1852*03ce13f7SAndroid Build Coastguard Worker     if (IsDstGPR != IsSrcGPR) {
1853*03ce13f7SAndroid Build Coastguard Worker       if (IsDstGPR) {
1854*03ce13f7SAndroid Build Coastguard Worker         // Dest is GPR and SrcR is FPR. Use mfc1.
1855*03ce13f7SAndroid Build Coastguard Worker         int32_t TypeWidth = typeWidthInBytes(DestTy);
1856*03ce13f7SAndroid Build Coastguard Worker         if (MovInstr->getDestHi() != nullptr)
1857*03ce13f7SAndroid Build Coastguard Worker           TypeWidth += typeWidthInBytes(MovInstr->getDestHi()->getType());
1858*03ce13f7SAndroid Build Coastguard Worker         if (TypeWidth == 8) {
1859*03ce13f7SAndroid Build Coastguard Worker           // Split it into two mfc1 instructions
1860*03ce13f7SAndroid Build Coastguard Worker           Variable *SrcGPRHi = Target->makeReg(
1861*03ce13f7SAndroid Build Coastguard Worker               IceType_f32, RegMIPS32::get64PairFirstRegNum(SRegNum));
1862*03ce13f7SAndroid Build Coastguard Worker           Variable *SrcGPRLo = Target->makeReg(
1863*03ce13f7SAndroid Build Coastguard Worker               IceType_f32, RegMIPS32::get64PairSecondRegNum(SRegNum));
1864*03ce13f7SAndroid Build Coastguard Worker           Variable *DstFPRHi, *DstFPRLo;
1865*03ce13f7SAndroid Build Coastguard Worker           if (MovInstr->getDestHi() != nullptr && Dest != nullptr) {
1866*03ce13f7SAndroid Build Coastguard Worker             DstFPRHi = Target->makeReg(IceType_i32,
1867*03ce13f7SAndroid Build Coastguard Worker                                        MovInstr->getDestHi()->getRegNum());
1868*03ce13f7SAndroid Build Coastguard Worker             DstFPRLo = Target->makeReg(IceType_i32, Dest->getRegNum());
1869*03ce13f7SAndroid Build Coastguard Worker           } else {
1870*03ce13f7SAndroid Build Coastguard Worker             DstFPRHi = Target->makeReg(
1871*03ce13f7SAndroid Build Coastguard Worker                 IceType_i32, RegMIPS32::get64PairFirstRegNum(DRegNum));
1872*03ce13f7SAndroid Build Coastguard Worker             DstFPRLo = Target->makeReg(
1873*03ce13f7SAndroid Build Coastguard Worker                 IceType_i32, RegMIPS32::get64PairSecondRegNum(DRegNum));
1874*03ce13f7SAndroid Build Coastguard Worker           }
1875*03ce13f7SAndroid Build Coastguard Worker           Target->_mov(DstFPRHi, SrcGPRHi);
1876*03ce13f7SAndroid Build Coastguard Worker           Target->_mov(DstFPRLo, SrcGPRLo);
1877*03ce13f7SAndroid Build Coastguard Worker           Legalized = true;
1878*03ce13f7SAndroid Build Coastguard Worker         } else {
1879*03ce13f7SAndroid Build Coastguard Worker           Variable *SrcGPR = Target->makeReg(IceType_f32, SRegNum);
1880*03ce13f7SAndroid Build Coastguard Worker           Variable *DstFPR = Target->makeReg(IceType_i32, DRegNum);
1881*03ce13f7SAndroid Build Coastguard Worker           Target->_mov(DstFPR, SrcGPR);
1882*03ce13f7SAndroid Build Coastguard Worker           Legalized = true;
1883*03ce13f7SAndroid Build Coastguard Worker         }
1884*03ce13f7SAndroid Build Coastguard Worker       } else {
1885*03ce13f7SAndroid Build Coastguard Worker         // Dest is FPR and SrcR is GPR. Use mtc1.
1886*03ce13f7SAndroid Build Coastguard Worker         if (typeWidthInBytes(Dest->getType()) == 8) {
1887*03ce13f7SAndroid Build Coastguard Worker           Variable *SrcGPRHi, *SrcGPRLo;
1888*03ce13f7SAndroid Build Coastguard Worker           // SrcR could be $zero which is i32
1889*03ce13f7SAndroid Build Coastguard Worker           if (SRegNum == RegMIPS32::Reg_ZERO) {
1890*03ce13f7SAndroid Build Coastguard Worker             SrcGPRHi = Target->makeReg(IceType_i32, SRegNum);
1891*03ce13f7SAndroid Build Coastguard Worker             SrcGPRLo = SrcGPRHi;
1892*03ce13f7SAndroid Build Coastguard Worker           } else {
1893*03ce13f7SAndroid Build Coastguard Worker             // Split it into two mtc1 instructions
1894*03ce13f7SAndroid Build Coastguard Worker             if (MovInstr->getSrcSize() == 2) {
1895*03ce13f7SAndroid Build Coastguard Worker               const auto FirstReg =
1896*03ce13f7SAndroid Build Coastguard Worker                   (llvm::cast<Variable>(MovInstr->getSrc(0)))->getRegNum();
1897*03ce13f7SAndroid Build Coastguard Worker               const auto SecondReg =
1898*03ce13f7SAndroid Build Coastguard Worker                   (llvm::cast<Variable>(MovInstr->getSrc(1)))->getRegNum();
1899*03ce13f7SAndroid Build Coastguard Worker               SrcGPRHi = Target->makeReg(IceType_i32, FirstReg);
1900*03ce13f7SAndroid Build Coastguard Worker               SrcGPRLo = Target->makeReg(IceType_i32, SecondReg);
1901*03ce13f7SAndroid Build Coastguard Worker             } else {
1902*03ce13f7SAndroid Build Coastguard Worker               SrcGPRLo = Target->makeReg(
1903*03ce13f7SAndroid Build Coastguard Worker                   IceType_i32, RegMIPS32::get64PairFirstRegNum(SRegNum));
1904*03ce13f7SAndroid Build Coastguard Worker               SrcGPRHi = Target->makeReg(
1905*03ce13f7SAndroid Build Coastguard Worker                   IceType_i32, RegMIPS32::get64PairSecondRegNum(SRegNum));
1906*03ce13f7SAndroid Build Coastguard Worker             }
1907*03ce13f7SAndroid Build Coastguard Worker           }
1908*03ce13f7SAndroid Build Coastguard Worker           Variable *DstFPRHi = Target->makeReg(
1909*03ce13f7SAndroid Build Coastguard Worker               IceType_f32, RegMIPS32::get64PairFirstRegNum(DRegNum));
1910*03ce13f7SAndroid Build Coastguard Worker           Variable *DstFPRLo = Target->makeReg(
1911*03ce13f7SAndroid Build Coastguard Worker               IceType_f32, RegMIPS32::get64PairSecondRegNum(DRegNum));
1912*03ce13f7SAndroid Build Coastguard Worker           Target->_mov(DstFPRHi, SrcGPRLo);
1913*03ce13f7SAndroid Build Coastguard Worker           Target->_mov(DstFPRLo, SrcGPRHi);
1914*03ce13f7SAndroid Build Coastguard Worker           Legalized = true;
1915*03ce13f7SAndroid Build Coastguard Worker         } else {
1916*03ce13f7SAndroid Build Coastguard Worker           Variable *SrcGPR = Target->makeReg(IceType_i32, SRegNum);
1917*03ce13f7SAndroid Build Coastguard Worker           Variable *DstFPR = Target->makeReg(IceType_f32, DRegNum);
1918*03ce13f7SAndroid Build Coastguard Worker           Target->_mov(DstFPR, SrcGPR);
1919*03ce13f7SAndroid Build Coastguard Worker           Legalized = true;
1920*03ce13f7SAndroid Build Coastguard Worker         }
1921*03ce13f7SAndroid Build Coastguard Worker       }
1922*03ce13f7SAndroid Build Coastguard Worker     }
1923*03ce13f7SAndroid Build Coastguard Worker     if (Legalized) {
1924*03ce13f7SAndroid Build Coastguard Worker       if (MovInstr->isDestRedefined()) {
1925*03ce13f7SAndroid Build Coastguard Worker         Target->_set_dest_redefined();
1926*03ce13f7SAndroid Build Coastguard Worker       }
1927*03ce13f7SAndroid Build Coastguard Worker       MovInstr->setDeleted();
1928*03ce13f7SAndroid Build Coastguard Worker       return;
1929*03ce13f7SAndroid Build Coastguard Worker     }
1930*03ce13f7SAndroid Build Coastguard Worker   }
1931*03ce13f7SAndroid Build Coastguard Worker 
1932*03ce13f7SAndroid Build Coastguard Worker   if (!Dest->hasReg()) {
1933*03ce13f7SAndroid Build Coastguard Worker     auto *SrcR = llvm::cast<Variable>(Src);
1934*03ce13f7SAndroid Build Coastguard Worker     assert(SrcR->hasReg());
1935*03ce13f7SAndroid Build Coastguard Worker     assert(!SrcR->isRematerializable());
1936*03ce13f7SAndroid Build Coastguard Worker     int32_t Offset = Dest->getStackOffset();
1937*03ce13f7SAndroid Build Coastguard Worker 
1938*03ce13f7SAndroid Build Coastguard Worker     // This is a _mov(Mem(), Variable), i.e., a store.
1939*03ce13f7SAndroid Build Coastguard Worker     auto *Base = Target->getPhysicalRegister(Target->getFrameOrStackReg());
1940*03ce13f7SAndroid Build Coastguard Worker 
1941*03ce13f7SAndroid Build Coastguard Worker     OperandMIPS32Mem *TAddr = OperandMIPS32Mem::create(
1942*03ce13f7SAndroid Build Coastguard Worker         Target->Func, DestTy, Base,
1943*03ce13f7SAndroid Build Coastguard Worker         llvm::cast<ConstantInteger32>(Target->Ctx->getConstantInt32(Offset)));
1944*03ce13f7SAndroid Build Coastguard Worker     OperandMIPS32Mem *TAddrHi = OperandMIPS32Mem::create(
1945*03ce13f7SAndroid Build Coastguard Worker         Target->Func, DestTy, Base,
1946*03ce13f7SAndroid Build Coastguard Worker         llvm::cast<ConstantInteger32>(
1947*03ce13f7SAndroid Build Coastguard Worker             Target->Ctx->getConstantInt32(Offset + 4)));
1948*03ce13f7SAndroid Build Coastguard Worker     OperandMIPS32Mem *Addr = legalizeMemOperand(TAddr);
1949*03ce13f7SAndroid Build Coastguard Worker 
1950*03ce13f7SAndroid Build Coastguard Worker     // FP arguments are passed in GP reg if first argument is in GP. In this
1951*03ce13f7SAndroid Build Coastguard Worker     // case type of the SrcR is still FP thus we need to explicitly generate sw
1952*03ce13f7SAndroid Build Coastguard Worker     // instead of swc1.
1953*03ce13f7SAndroid Build Coastguard Worker     const RegNumT RegNum = SrcR->getRegNum();
1954*03ce13f7SAndroid Build Coastguard Worker     const bool IsSrcGPReg = RegMIPS32::isGPRReg(SrcR->getRegNum());
1955*03ce13f7SAndroid Build Coastguard Worker     if (SrcTy == IceType_f32 && IsSrcGPReg) {
1956*03ce13f7SAndroid Build Coastguard Worker       Variable *SrcGPR = Target->makeReg(IceType_i32, RegNum);
1957*03ce13f7SAndroid Build Coastguard Worker       Target->_sw(SrcGPR, Addr);
1958*03ce13f7SAndroid Build Coastguard Worker     } else if (SrcTy == IceType_f64 && IsSrcGPReg) {
1959*03ce13f7SAndroid Build Coastguard Worker       Variable *SrcGPRHi =
1960*03ce13f7SAndroid Build Coastguard Worker           Target->makeReg(IceType_i32, RegMIPS32::get64PairFirstRegNum(RegNum));
1961*03ce13f7SAndroid Build Coastguard Worker       Variable *SrcGPRLo = Target->makeReg(
1962*03ce13f7SAndroid Build Coastguard Worker           IceType_i32, RegMIPS32::get64PairSecondRegNum(RegNum));
1963*03ce13f7SAndroid Build Coastguard Worker       Target->_sw(SrcGPRHi, Addr);
1964*03ce13f7SAndroid Build Coastguard Worker       OperandMIPS32Mem *AddrHi = legalizeMemOperand(TAddrHi);
1965*03ce13f7SAndroid Build Coastguard Worker       Target->_sw(SrcGPRLo, AddrHi);
1966*03ce13f7SAndroid Build Coastguard Worker     } else if (DestTy == IceType_f64 && IsSrcGPReg) {
1967*03ce13f7SAndroid Build Coastguard Worker       const auto FirstReg =
1968*03ce13f7SAndroid Build Coastguard Worker           (llvm::cast<Variable>(MovInstr->getSrc(0)))->getRegNum();
1969*03ce13f7SAndroid Build Coastguard Worker       const auto SecondReg =
1970*03ce13f7SAndroid Build Coastguard Worker           (llvm::cast<Variable>(MovInstr->getSrc(1)))->getRegNum();
1971*03ce13f7SAndroid Build Coastguard Worker       Variable *SrcGPRHi = Target->makeReg(IceType_i32, FirstReg);
1972*03ce13f7SAndroid Build Coastguard Worker       Variable *SrcGPRLo = Target->makeReg(IceType_i32, SecondReg);
1973*03ce13f7SAndroid Build Coastguard Worker       Target->_sw(SrcGPRLo, Addr);
1974*03ce13f7SAndroid Build Coastguard Worker       OperandMIPS32Mem *AddrHi = legalizeMemOperand(TAddrHi);
1975*03ce13f7SAndroid Build Coastguard Worker       Target->_sw(SrcGPRHi, AddrHi);
1976*03ce13f7SAndroid Build Coastguard Worker     } else {
1977*03ce13f7SAndroid Build Coastguard Worker       Target->_sw(SrcR, Addr);
1978*03ce13f7SAndroid Build Coastguard Worker     }
1979*03ce13f7SAndroid Build Coastguard Worker 
1980*03ce13f7SAndroid Build Coastguard Worker     Target->Context.insert<InstFakeDef>(Dest);
1981*03ce13f7SAndroid Build Coastguard Worker     Legalized = true;
1982*03ce13f7SAndroid Build Coastguard Worker   } else if (auto *Var = llvm::dyn_cast<Variable>(Src)) {
1983*03ce13f7SAndroid Build Coastguard Worker     if (Var->isRematerializable()) {
1984*03ce13f7SAndroid Build Coastguard Worker       // This is equivalent to an x86 _lea(RematOffset(%esp/%ebp), Variable).
1985*03ce13f7SAndroid Build Coastguard Worker 
1986*03ce13f7SAndroid Build Coastguard Worker       // ExtraOffset is only needed for stack-pointer based frames as we have
1987*03ce13f7SAndroid Build Coastguard Worker       // to account for spill storage.
1988*03ce13f7SAndroid Build Coastguard Worker       const int32_t ExtraOffset =
1989*03ce13f7SAndroid Build Coastguard Worker           (Var->getRegNum() == Target->getFrameOrStackReg())
1990*03ce13f7SAndroid Build Coastguard Worker               ? Target->getFrameFixedAllocaOffset()
1991*03ce13f7SAndroid Build Coastguard Worker               : 0;
1992*03ce13f7SAndroid Build Coastguard Worker 
1993*03ce13f7SAndroid Build Coastguard Worker       const int32_t Offset = Var->getStackOffset() + ExtraOffset;
1994*03ce13f7SAndroid Build Coastguard Worker       Variable *Base = Target->getPhysicalRegister(Var->getRegNum());
1995*03ce13f7SAndroid Build Coastguard Worker       Variable *T = newBaseRegister(Base, Offset, Dest->getRegNum());
1996*03ce13f7SAndroid Build Coastguard Worker       Target->_mov(Dest, T);
1997*03ce13f7SAndroid Build Coastguard Worker       Legalized = true;
1998*03ce13f7SAndroid Build Coastguard Worker     } else {
1999*03ce13f7SAndroid Build Coastguard Worker       if (!Var->hasReg()) {
2000*03ce13f7SAndroid Build Coastguard Worker         // This is a _mov(Variable, Mem()), i.e., a load.
2001*03ce13f7SAndroid Build Coastguard Worker         const int32_t Offset = Var->getStackOffset();
2002*03ce13f7SAndroid Build Coastguard Worker         auto *Base = Target->getPhysicalRegister(Target->getFrameOrStackReg());
2003*03ce13f7SAndroid Build Coastguard Worker         const RegNumT RegNum = Dest->getRegNum();
2004*03ce13f7SAndroid Build Coastguard Worker         const bool IsDstGPReg = RegMIPS32::isGPRReg(Dest->getRegNum());
2005*03ce13f7SAndroid Build Coastguard Worker         // If we are moving i64 to a double using stack then the address may
2006*03ce13f7SAndroid Build Coastguard Worker         // not be aligned to 8-byte boundary as we split i64 into Hi-Lo parts
2007*03ce13f7SAndroid Build Coastguard Worker         // and store them individually with 4-byte alignment. Load the Hi-Lo
2008*03ce13f7SAndroid Build Coastguard Worker         // parts in TmpReg and move them to the dest using mtc1.
2009*03ce13f7SAndroid Build Coastguard Worker         if (DestTy == IceType_f64 && !Utils::IsAligned(Offset, 8) &&
2010*03ce13f7SAndroid Build Coastguard Worker             !IsDstGPReg) {
2011*03ce13f7SAndroid Build Coastguard Worker           auto *Reg = Target->makeReg(IceType_i32, Target->getReservedTmpReg());
2012*03ce13f7SAndroid Build Coastguard Worker           const RegNumT RegNum = Dest->getRegNum();
2013*03ce13f7SAndroid Build Coastguard Worker           Variable *DestLo = Target->makeReg(
2014*03ce13f7SAndroid Build Coastguard Worker               IceType_f32, RegMIPS32::get64PairFirstRegNum(RegNum));
2015*03ce13f7SAndroid Build Coastguard Worker           Variable *DestHi = Target->makeReg(
2016*03ce13f7SAndroid Build Coastguard Worker               IceType_f32, RegMIPS32::get64PairSecondRegNum(RegNum));
2017*03ce13f7SAndroid Build Coastguard Worker           OperandMIPS32Mem *AddrLo = OperandMIPS32Mem::create(
2018*03ce13f7SAndroid Build Coastguard Worker               Target->Func, IceType_i32, Base,
2019*03ce13f7SAndroid Build Coastguard Worker               llvm::cast<ConstantInteger32>(
2020*03ce13f7SAndroid Build Coastguard Worker                   Target->Ctx->getConstantInt32(Offset)));
2021*03ce13f7SAndroid Build Coastguard Worker           OperandMIPS32Mem *AddrHi = OperandMIPS32Mem::create(
2022*03ce13f7SAndroid Build Coastguard Worker               Target->Func, IceType_i32, Base,
2023*03ce13f7SAndroid Build Coastguard Worker               llvm::cast<ConstantInteger32>(
2024*03ce13f7SAndroid Build Coastguard Worker                   Target->Ctx->getConstantInt32(Offset + 4)));
2025*03ce13f7SAndroid Build Coastguard Worker           Target->_lw(Reg, AddrLo);
2026*03ce13f7SAndroid Build Coastguard Worker           Target->_mov(DestLo, Reg);
2027*03ce13f7SAndroid Build Coastguard Worker           Target->_lw(Reg, AddrHi);
2028*03ce13f7SAndroid Build Coastguard Worker           Target->_mov(DestHi, Reg);
2029*03ce13f7SAndroid Build Coastguard Worker         } else {
2030*03ce13f7SAndroid Build Coastguard Worker           OperandMIPS32Mem *TAddr = OperandMIPS32Mem::create(
2031*03ce13f7SAndroid Build Coastguard Worker               Target->Func, DestTy, Base,
2032*03ce13f7SAndroid Build Coastguard Worker               llvm::cast<ConstantInteger32>(
2033*03ce13f7SAndroid Build Coastguard Worker                   Target->Ctx->getConstantInt32(Offset)));
2034*03ce13f7SAndroid Build Coastguard Worker           OperandMIPS32Mem *Addr = legalizeMemOperand(TAddr);
2035*03ce13f7SAndroid Build Coastguard Worker           OperandMIPS32Mem *TAddrHi = OperandMIPS32Mem::create(
2036*03ce13f7SAndroid Build Coastguard Worker               Target->Func, DestTy, Base,
2037*03ce13f7SAndroid Build Coastguard Worker               llvm::cast<ConstantInteger32>(
2038*03ce13f7SAndroid Build Coastguard Worker                   Target->Ctx->getConstantInt32(Offset + 4)));
2039*03ce13f7SAndroid Build Coastguard Worker           // FP arguments are passed in GP reg if first argument is in GP.
2040*03ce13f7SAndroid Build Coastguard Worker           // In this case type of the Dest is still FP thus we need to
2041*03ce13f7SAndroid Build Coastguard Worker           // explicitly generate lw instead of lwc1.
2042*03ce13f7SAndroid Build Coastguard Worker           if (DestTy == IceType_f32 && IsDstGPReg) {
2043*03ce13f7SAndroid Build Coastguard Worker             Variable *DstGPR = Target->makeReg(IceType_i32, RegNum);
2044*03ce13f7SAndroid Build Coastguard Worker             Target->_lw(DstGPR, Addr);
2045*03ce13f7SAndroid Build Coastguard Worker           } else if (DestTy == IceType_f64 && IsDstGPReg) {
2046*03ce13f7SAndroid Build Coastguard Worker             Variable *DstGPRHi = Target->makeReg(
2047*03ce13f7SAndroid Build Coastguard Worker                 IceType_i32, RegMIPS32::get64PairFirstRegNum(RegNum));
2048*03ce13f7SAndroid Build Coastguard Worker             Variable *DstGPRLo = Target->makeReg(
2049*03ce13f7SAndroid Build Coastguard Worker                 IceType_i32, RegMIPS32::get64PairSecondRegNum(RegNum));
2050*03ce13f7SAndroid Build Coastguard Worker             Target->_lw(DstGPRHi, Addr);
2051*03ce13f7SAndroid Build Coastguard Worker             OperandMIPS32Mem *AddrHi = legalizeMemOperand(TAddrHi);
2052*03ce13f7SAndroid Build Coastguard Worker             Target->_lw(DstGPRLo, AddrHi);
2053*03ce13f7SAndroid Build Coastguard Worker           } else if (DestTy == IceType_f64 && IsDstGPReg) {
2054*03ce13f7SAndroid Build Coastguard Worker             const auto FirstReg =
2055*03ce13f7SAndroid Build Coastguard Worker                 (llvm::cast<Variable>(MovInstr->getSrc(0)))->getRegNum();
2056*03ce13f7SAndroid Build Coastguard Worker             const auto SecondReg =
2057*03ce13f7SAndroid Build Coastguard Worker                 (llvm::cast<Variable>(MovInstr->getSrc(1)))->getRegNum();
2058*03ce13f7SAndroid Build Coastguard Worker             Variable *DstGPRHi = Target->makeReg(IceType_i32, FirstReg);
2059*03ce13f7SAndroid Build Coastguard Worker             Variable *DstGPRLo = Target->makeReg(IceType_i32, SecondReg);
2060*03ce13f7SAndroid Build Coastguard Worker             Target->_lw(DstGPRLo, Addr);
2061*03ce13f7SAndroid Build Coastguard Worker             OperandMIPS32Mem *AddrHi = legalizeMemOperand(TAddrHi);
2062*03ce13f7SAndroid Build Coastguard Worker             Target->_lw(DstGPRHi, AddrHi);
2063*03ce13f7SAndroid Build Coastguard Worker           } else {
2064*03ce13f7SAndroid Build Coastguard Worker             Target->_lw(Dest, Addr);
2065*03ce13f7SAndroid Build Coastguard Worker           }
2066*03ce13f7SAndroid Build Coastguard Worker         }
2067*03ce13f7SAndroid Build Coastguard Worker         Legalized = true;
2068*03ce13f7SAndroid Build Coastguard Worker       }
2069*03ce13f7SAndroid Build Coastguard Worker     }
2070*03ce13f7SAndroid Build Coastguard Worker   }
2071*03ce13f7SAndroid Build Coastguard Worker 
2072*03ce13f7SAndroid Build Coastguard Worker   if (Legalized) {
2073*03ce13f7SAndroid Build Coastguard Worker     if (MovInstr->isDestRedefined()) {
2074*03ce13f7SAndroid Build Coastguard Worker       Target->_set_dest_redefined();
2075*03ce13f7SAndroid Build Coastguard Worker     }
2076*03ce13f7SAndroid Build Coastguard Worker     MovInstr->setDeleted();
2077*03ce13f7SAndroid Build Coastguard Worker   }
2078*03ce13f7SAndroid Build Coastguard Worker }
2079*03ce13f7SAndroid Build Coastguard Worker 
2080*03ce13f7SAndroid Build Coastguard Worker OperandMIPS32Mem *
legalizeMemOperand(OperandMIPS32Mem * Mem)2081*03ce13f7SAndroid Build Coastguard Worker TargetMIPS32::PostLoweringLegalizer::legalizeMemOperand(OperandMIPS32Mem *Mem) {
2082*03ce13f7SAndroid Build Coastguard Worker   if (llvm::isa<ConstantRelocatable>(Mem->getOffset())) {
2083*03ce13f7SAndroid Build Coastguard Worker     return nullptr;
2084*03ce13f7SAndroid Build Coastguard Worker   }
2085*03ce13f7SAndroid Build Coastguard Worker   Variable *Base = Mem->getBase();
2086*03ce13f7SAndroid Build Coastguard Worker   auto *Ci32 = llvm::cast<ConstantInteger32>(Mem->getOffset());
2087*03ce13f7SAndroid Build Coastguard Worker   int32_t Offset = Ci32->getValue();
2088*03ce13f7SAndroid Build Coastguard Worker 
2089*03ce13f7SAndroid Build Coastguard Worker   if (Base->isRematerializable()) {
2090*03ce13f7SAndroid Build Coastguard Worker     const int32_t ExtraOffset =
2091*03ce13f7SAndroid Build Coastguard Worker         (Base->getRegNum() == Target->getFrameOrStackReg())
2092*03ce13f7SAndroid Build Coastguard Worker             ? Target->getFrameFixedAllocaOffset()
2093*03ce13f7SAndroid Build Coastguard Worker             : 0;
2094*03ce13f7SAndroid Build Coastguard Worker     Offset += Base->getStackOffset() + ExtraOffset;
2095*03ce13f7SAndroid Build Coastguard Worker     Base = Target->getPhysicalRegister(Base->getRegNum());
2096*03ce13f7SAndroid Build Coastguard Worker   }
2097*03ce13f7SAndroid Build Coastguard Worker 
2098*03ce13f7SAndroid Build Coastguard Worker   constexpr bool SignExt = true;
2099*03ce13f7SAndroid Build Coastguard Worker   if (!OperandMIPS32Mem::canHoldOffset(Mem->getType(), SignExt, Offset)) {
2100*03ce13f7SAndroid Build Coastguard Worker     Base = newBaseRegister(Base, Offset, Target->getReservedTmpReg());
2101*03ce13f7SAndroid Build Coastguard Worker     Offset = 0;
2102*03ce13f7SAndroid Build Coastguard Worker   }
2103*03ce13f7SAndroid Build Coastguard Worker 
2104*03ce13f7SAndroid Build Coastguard Worker   return OperandMIPS32Mem::create(
2105*03ce13f7SAndroid Build Coastguard Worker       Target->Func, Mem->getType(), Base,
2106*03ce13f7SAndroid Build Coastguard Worker       llvm::cast<ConstantInteger32>(Target->Ctx->getConstantInt32(Offset)));
2107*03ce13f7SAndroid Build Coastguard Worker }
2108*03ce13f7SAndroid Build Coastguard Worker 
legalizeImmediate(int32_t Imm)2109*03ce13f7SAndroid Build Coastguard Worker Variable *TargetMIPS32::PostLoweringLegalizer::legalizeImmediate(int32_t Imm) {
2110*03ce13f7SAndroid Build Coastguard Worker   Variable *Reg = nullptr;
2111*03ce13f7SAndroid Build Coastguard Worker   if (!((std::numeric_limits<int16_t>::min() <= Imm) &&
2112*03ce13f7SAndroid Build Coastguard Worker         (Imm <= std::numeric_limits<int16_t>::max()))) {
2113*03ce13f7SAndroid Build Coastguard Worker     const uint32_t UpperBits = (Imm >> 16) & 0xFFFF;
2114*03ce13f7SAndroid Build Coastguard Worker     const uint32_t LowerBits = Imm & 0xFFFF;
2115*03ce13f7SAndroid Build Coastguard Worker     Variable *TReg = Target->makeReg(IceType_i32, Target->getReservedTmpReg());
2116*03ce13f7SAndroid Build Coastguard Worker     Reg = Target->makeReg(IceType_i32, Target->getReservedTmpReg());
2117*03ce13f7SAndroid Build Coastguard Worker     if (LowerBits) {
2118*03ce13f7SAndroid Build Coastguard Worker       Target->_lui(TReg, Target->Ctx->getConstantInt32(UpperBits));
2119*03ce13f7SAndroid Build Coastguard Worker       Target->_ori(Reg, TReg, LowerBits);
2120*03ce13f7SAndroid Build Coastguard Worker     } else {
2121*03ce13f7SAndroid Build Coastguard Worker       Target->_lui(Reg, Target->Ctx->getConstantInt32(UpperBits));
2122*03ce13f7SAndroid Build Coastguard Worker     }
2123*03ce13f7SAndroid Build Coastguard Worker   }
2124*03ce13f7SAndroid Build Coastguard Worker   return Reg;
2125*03ce13f7SAndroid Build Coastguard Worker }
2126*03ce13f7SAndroid Build Coastguard Worker 
postLowerLegalization()2127*03ce13f7SAndroid Build Coastguard Worker void TargetMIPS32::postLowerLegalization() {
2128*03ce13f7SAndroid Build Coastguard Worker   Func->dump("Before postLowerLegalization");
2129*03ce13f7SAndroid Build Coastguard Worker   assert(hasComputedFrame());
2130*03ce13f7SAndroid Build Coastguard Worker   for (CfgNode *Node : Func->getNodes()) {
2131*03ce13f7SAndroid Build Coastguard Worker     Context.init(Node);
2132*03ce13f7SAndroid Build Coastguard Worker     PostLoweringLegalizer Legalizer(this);
2133*03ce13f7SAndroid Build Coastguard Worker     while (!Context.atEnd()) {
2134*03ce13f7SAndroid Build Coastguard Worker       PostIncrLoweringContext PostIncrement(Context);
2135*03ce13f7SAndroid Build Coastguard Worker       Inst *CurInstr = iteratorToInst(Context.getCur());
2136*03ce13f7SAndroid Build Coastguard Worker       const SizeT NumSrcs = CurInstr->getSrcSize();
2137*03ce13f7SAndroid Build Coastguard Worker       Operand *Src0 = NumSrcs < 1 ? nullptr : CurInstr->getSrc(0);
2138*03ce13f7SAndroid Build Coastguard Worker       Operand *Src1 = NumSrcs < 2 ? nullptr : CurInstr->getSrc(1);
2139*03ce13f7SAndroid Build Coastguard Worker       auto *Src0V = llvm::dyn_cast_or_null<Variable>(Src0);
2140*03ce13f7SAndroid Build Coastguard Worker       auto *Src0M = llvm::dyn_cast_or_null<OperandMIPS32Mem>(Src0);
2141*03ce13f7SAndroid Build Coastguard Worker       auto *Src1M = llvm::dyn_cast_or_null<OperandMIPS32Mem>(Src1);
2142*03ce13f7SAndroid Build Coastguard Worker       Variable *Dst = CurInstr->getDest();
2143*03ce13f7SAndroid Build Coastguard Worker       if (auto *MovInstr = llvm::dyn_cast<InstMIPS32Mov>(CurInstr)) {
2144*03ce13f7SAndroid Build Coastguard Worker         Legalizer.legalizeMov(MovInstr);
2145*03ce13f7SAndroid Build Coastguard Worker         continue;
2146*03ce13f7SAndroid Build Coastguard Worker       }
2147*03ce13f7SAndroid Build Coastguard Worker       if (auto *MovInstr = llvm::dyn_cast<InstMIPS32MovFP64ToI64>(CurInstr)) {
2148*03ce13f7SAndroid Build Coastguard Worker         Legalizer.legalizeMovFp(MovInstr);
2149*03ce13f7SAndroid Build Coastguard Worker         continue;
2150*03ce13f7SAndroid Build Coastguard Worker       }
2151*03ce13f7SAndroid Build Coastguard Worker       if (llvm::isa<InstMIPS32Sw>(CurInstr)) {
2152*03ce13f7SAndroid Build Coastguard Worker         if (auto *LegalMem = Legalizer.legalizeMemOperand(Src1M)) {
2153*03ce13f7SAndroid Build Coastguard Worker           _sw(Src0V, LegalMem);
2154*03ce13f7SAndroid Build Coastguard Worker           CurInstr->setDeleted();
2155*03ce13f7SAndroid Build Coastguard Worker         }
2156*03ce13f7SAndroid Build Coastguard Worker         continue;
2157*03ce13f7SAndroid Build Coastguard Worker       }
2158*03ce13f7SAndroid Build Coastguard Worker       if (llvm::isa<InstMIPS32Swc1>(CurInstr)) {
2159*03ce13f7SAndroid Build Coastguard Worker         if (auto *LegalMem = Legalizer.legalizeMemOperand(Src1M)) {
2160*03ce13f7SAndroid Build Coastguard Worker           _swc1(Src0V, LegalMem);
2161*03ce13f7SAndroid Build Coastguard Worker           CurInstr->setDeleted();
2162*03ce13f7SAndroid Build Coastguard Worker         }
2163*03ce13f7SAndroid Build Coastguard Worker         continue;
2164*03ce13f7SAndroid Build Coastguard Worker       }
2165*03ce13f7SAndroid Build Coastguard Worker       if (llvm::isa<InstMIPS32Sdc1>(CurInstr)) {
2166*03ce13f7SAndroid Build Coastguard Worker         if (auto *LegalMem = Legalizer.legalizeMemOperand(Src1M)) {
2167*03ce13f7SAndroid Build Coastguard Worker           _sdc1(Src0V, LegalMem);
2168*03ce13f7SAndroid Build Coastguard Worker           CurInstr->setDeleted();
2169*03ce13f7SAndroid Build Coastguard Worker         }
2170*03ce13f7SAndroid Build Coastguard Worker         continue;
2171*03ce13f7SAndroid Build Coastguard Worker       }
2172*03ce13f7SAndroid Build Coastguard Worker       if (llvm::isa<InstMIPS32Lw>(CurInstr)) {
2173*03ce13f7SAndroid Build Coastguard Worker         if (auto *LegalMem = Legalizer.legalizeMemOperand(Src0M)) {
2174*03ce13f7SAndroid Build Coastguard Worker           _lw(Dst, LegalMem);
2175*03ce13f7SAndroid Build Coastguard Worker           CurInstr->setDeleted();
2176*03ce13f7SAndroid Build Coastguard Worker         }
2177*03ce13f7SAndroid Build Coastguard Worker         continue;
2178*03ce13f7SAndroid Build Coastguard Worker       }
2179*03ce13f7SAndroid Build Coastguard Worker       if (llvm::isa<InstMIPS32Lwc1>(CurInstr)) {
2180*03ce13f7SAndroid Build Coastguard Worker         if (auto *LegalMem = Legalizer.legalizeMemOperand(Src0M)) {
2181*03ce13f7SAndroid Build Coastguard Worker           _lwc1(Dst, LegalMem);
2182*03ce13f7SAndroid Build Coastguard Worker           CurInstr->setDeleted();
2183*03ce13f7SAndroid Build Coastguard Worker         }
2184*03ce13f7SAndroid Build Coastguard Worker         continue;
2185*03ce13f7SAndroid Build Coastguard Worker       }
2186*03ce13f7SAndroid Build Coastguard Worker       if (llvm::isa<InstMIPS32Ldc1>(CurInstr)) {
2187*03ce13f7SAndroid Build Coastguard Worker         if (auto *LegalMem = Legalizer.legalizeMemOperand(Src0M)) {
2188*03ce13f7SAndroid Build Coastguard Worker           _ldc1(Dst, LegalMem);
2189*03ce13f7SAndroid Build Coastguard Worker           CurInstr->setDeleted();
2190*03ce13f7SAndroid Build Coastguard Worker         }
2191*03ce13f7SAndroid Build Coastguard Worker         continue;
2192*03ce13f7SAndroid Build Coastguard Worker       }
2193*03ce13f7SAndroid Build Coastguard Worker       if (auto *AddiuInstr = llvm::dyn_cast<InstMIPS32Addiu>(CurInstr)) {
2194*03ce13f7SAndroid Build Coastguard Worker         if (auto *LegalImm = Legalizer.legalizeImmediate(
2195*03ce13f7SAndroid Build Coastguard Worker                 static_cast<int32_t>(AddiuInstr->getImmediateValue()))) {
2196*03ce13f7SAndroid Build Coastguard Worker           _addu(Dst, Src0V, LegalImm);
2197*03ce13f7SAndroid Build Coastguard Worker           CurInstr->setDeleted();
2198*03ce13f7SAndroid Build Coastguard Worker         }
2199*03ce13f7SAndroid Build Coastguard Worker         continue;
2200*03ce13f7SAndroid Build Coastguard Worker       }
2201*03ce13f7SAndroid Build Coastguard Worker     }
2202*03ce13f7SAndroid Build Coastguard Worker   }
2203*03ce13f7SAndroid Build Coastguard Worker }
2204*03ce13f7SAndroid Build Coastguard Worker 
loOperand(Operand * Operand)2205*03ce13f7SAndroid Build Coastguard Worker Operand *TargetMIPS32::loOperand(Operand *Operand) {
2206*03ce13f7SAndroid Build Coastguard Worker   assert(Operand->getType() == IceType_i64);
2207*03ce13f7SAndroid Build Coastguard Worker   if (auto *Var64On32 = llvm::dyn_cast<Variable64On32>(Operand))
2208*03ce13f7SAndroid Build Coastguard Worker     return Var64On32->getLo();
2209*03ce13f7SAndroid Build Coastguard Worker   if (auto *Const = llvm::dyn_cast<ConstantInteger64>(Operand)) {
2210*03ce13f7SAndroid Build Coastguard Worker     return Ctx->getConstantInt32(static_cast<uint32_t>(Const->getValue()));
2211*03ce13f7SAndroid Build Coastguard Worker   }
2212*03ce13f7SAndroid Build Coastguard Worker   if (auto *Mem = llvm::dyn_cast<OperandMIPS32Mem>(Operand)) {
2213*03ce13f7SAndroid Build Coastguard Worker     // Conservatively disallow memory operands with side-effects (pre/post
2214*03ce13f7SAndroid Build Coastguard Worker     // increment) in case of duplication.
2215*03ce13f7SAndroid Build Coastguard Worker     assert(Mem->getAddrMode() == OperandMIPS32Mem::Offset);
2216*03ce13f7SAndroid Build Coastguard Worker     return OperandMIPS32Mem::create(Func, IceType_i32, Mem->getBase(),
2217*03ce13f7SAndroid Build Coastguard Worker                                     Mem->getOffset(), Mem->getAddrMode());
2218*03ce13f7SAndroid Build Coastguard Worker   }
2219*03ce13f7SAndroid Build Coastguard Worker   llvm_unreachable("Unsupported operand type");
2220*03ce13f7SAndroid Build Coastguard Worker   return nullptr;
2221*03ce13f7SAndroid Build Coastguard Worker }
2222*03ce13f7SAndroid Build Coastguard Worker 
getOperandAtIndex(Operand * Operand,Type BaseType,uint32_t Index)2223*03ce13f7SAndroid Build Coastguard Worker Operand *TargetMIPS32::getOperandAtIndex(Operand *Operand, Type BaseType,
2224*03ce13f7SAndroid Build Coastguard Worker                                          uint32_t Index) {
2225*03ce13f7SAndroid Build Coastguard Worker   if (!isVectorType(Operand->getType())) {
2226*03ce13f7SAndroid Build Coastguard Worker     llvm::report_fatal_error("getOperandAtIndex: Operand is not vector");
2227*03ce13f7SAndroid Build Coastguard Worker     return nullptr;
2228*03ce13f7SAndroid Build Coastguard Worker   }
2229*03ce13f7SAndroid Build Coastguard Worker 
2230*03ce13f7SAndroid Build Coastguard Worker   if (auto *Mem = llvm::dyn_cast<OperandMIPS32Mem>(Operand)) {
2231*03ce13f7SAndroid Build Coastguard Worker     assert(Mem->getAddrMode() == OperandMIPS32Mem::Offset);
2232*03ce13f7SAndroid Build Coastguard Worker     Variable *Base = Mem->getBase();
2233*03ce13f7SAndroid Build Coastguard Worker     auto *Offset = llvm::cast<ConstantInteger32>(Mem->getOffset());
2234*03ce13f7SAndroid Build Coastguard Worker     assert(!Utils::WouldOverflowAdd(Offset->getValue(), 4));
2235*03ce13f7SAndroid Build Coastguard Worker     int32_t NextOffsetVal =
2236*03ce13f7SAndroid Build Coastguard Worker         Offset->getValue() + (Index * typeWidthInBytes(BaseType));
2237*03ce13f7SAndroid Build Coastguard Worker     constexpr bool NoSignExt = false;
2238*03ce13f7SAndroid Build Coastguard Worker     if (!OperandMIPS32Mem::canHoldOffset(BaseType, NoSignExt, NextOffsetVal)) {
2239*03ce13f7SAndroid Build Coastguard Worker       Constant *_4 = Ctx->getConstantInt32(4);
2240*03ce13f7SAndroid Build Coastguard Worker       Variable *NewBase = Func->makeVariable(Base->getType());
2241*03ce13f7SAndroid Build Coastguard Worker       lowerArithmetic(
2242*03ce13f7SAndroid Build Coastguard Worker           InstArithmetic::create(Func, InstArithmetic::Add, NewBase, Base, _4));
2243*03ce13f7SAndroid Build Coastguard Worker       Base = NewBase;
2244*03ce13f7SAndroid Build Coastguard Worker     } else {
2245*03ce13f7SAndroid Build Coastguard Worker       Offset =
2246*03ce13f7SAndroid Build Coastguard Worker           llvm::cast<ConstantInteger32>(Ctx->getConstantInt32(NextOffsetVal));
2247*03ce13f7SAndroid Build Coastguard Worker     }
2248*03ce13f7SAndroid Build Coastguard Worker     return OperandMIPS32Mem::create(Func, BaseType, Base, Offset,
2249*03ce13f7SAndroid Build Coastguard Worker                                     Mem->getAddrMode());
2250*03ce13f7SAndroid Build Coastguard Worker   }
2251*03ce13f7SAndroid Build Coastguard Worker 
2252*03ce13f7SAndroid Build Coastguard Worker   if (auto *VarVecOn32 = llvm::dyn_cast<VariableVecOn32>(Operand))
2253*03ce13f7SAndroid Build Coastguard Worker     return VarVecOn32->getContainers()[Index];
2254*03ce13f7SAndroid Build Coastguard Worker 
2255*03ce13f7SAndroid Build Coastguard Worker   llvm_unreachable("Unsupported operand type");
2256*03ce13f7SAndroid Build Coastguard Worker   return nullptr;
2257*03ce13f7SAndroid Build Coastguard Worker }
2258*03ce13f7SAndroid Build Coastguard Worker 
hiOperand(Operand * Operand)2259*03ce13f7SAndroid Build Coastguard Worker Operand *TargetMIPS32::hiOperand(Operand *Operand) {
2260*03ce13f7SAndroid Build Coastguard Worker   assert(Operand->getType() == IceType_i64);
2261*03ce13f7SAndroid Build Coastguard Worker   if (Operand->getType() != IceType_i64)
2262*03ce13f7SAndroid Build Coastguard Worker     return Operand;
2263*03ce13f7SAndroid Build Coastguard Worker   if (auto *Var64On32 = llvm::dyn_cast<Variable64On32>(Operand))
2264*03ce13f7SAndroid Build Coastguard Worker     return Var64On32->getHi();
2265*03ce13f7SAndroid Build Coastguard Worker   if (auto *Const = llvm::dyn_cast<ConstantInteger64>(Operand)) {
2266*03ce13f7SAndroid Build Coastguard Worker     return Ctx->getConstantInt32(
2267*03ce13f7SAndroid Build Coastguard Worker         static_cast<uint32_t>(Const->getValue() >> 32));
2268*03ce13f7SAndroid Build Coastguard Worker   }
2269*03ce13f7SAndroid Build Coastguard Worker   if (auto *Mem = llvm::dyn_cast<OperandMIPS32Mem>(Operand)) {
2270*03ce13f7SAndroid Build Coastguard Worker     // Conservatively disallow memory operands with side-effects
2271*03ce13f7SAndroid Build Coastguard Worker     // in case of duplication.
2272*03ce13f7SAndroid Build Coastguard Worker     assert(Mem->getAddrMode() == OperandMIPS32Mem::Offset);
2273*03ce13f7SAndroid Build Coastguard Worker     const Type SplitType = IceType_i32;
2274*03ce13f7SAndroid Build Coastguard Worker     Variable *Base = Mem->getBase();
2275*03ce13f7SAndroid Build Coastguard Worker     auto *Offset = llvm::cast<ConstantInteger32>(Mem->getOffset());
2276*03ce13f7SAndroid Build Coastguard Worker     assert(!Utils::WouldOverflowAdd(Offset->getValue(), 4));
2277*03ce13f7SAndroid Build Coastguard Worker     int32_t NextOffsetVal = Offset->getValue() + 4;
2278*03ce13f7SAndroid Build Coastguard Worker     constexpr bool SignExt = false;
2279*03ce13f7SAndroid Build Coastguard Worker     if (!OperandMIPS32Mem::canHoldOffset(SplitType, SignExt, NextOffsetVal)) {
2280*03ce13f7SAndroid Build Coastguard Worker       // We have to make a temp variable and add 4 to either Base or Offset.
2281*03ce13f7SAndroid Build Coastguard Worker       // If we add 4 to Offset, this will convert a non-RegReg addressing
2282*03ce13f7SAndroid Build Coastguard Worker       // mode into a RegReg addressing mode. Since NaCl sandboxing disallows
2283*03ce13f7SAndroid Build Coastguard Worker       // RegReg addressing modes, prefer adding to base and replacing instead.
2284*03ce13f7SAndroid Build Coastguard Worker       // Thus we leave the old offset alone.
2285*03ce13f7SAndroid Build Coastguard Worker       Constant *Four = Ctx->getConstantInt32(4);
2286*03ce13f7SAndroid Build Coastguard Worker       Variable *NewBase = Func->makeVariable(Base->getType());
2287*03ce13f7SAndroid Build Coastguard Worker       lowerArithmetic(InstArithmetic::create(Func, InstArithmetic::Add, NewBase,
2288*03ce13f7SAndroid Build Coastguard Worker                                              Base, Four));
2289*03ce13f7SAndroid Build Coastguard Worker       Base = NewBase;
2290*03ce13f7SAndroid Build Coastguard Worker     } else {
2291*03ce13f7SAndroid Build Coastguard Worker       Offset =
2292*03ce13f7SAndroid Build Coastguard Worker           llvm::cast<ConstantInteger32>(Ctx->getConstantInt32(NextOffsetVal));
2293*03ce13f7SAndroid Build Coastguard Worker     }
2294*03ce13f7SAndroid Build Coastguard Worker     return OperandMIPS32Mem::create(Func, SplitType, Base, Offset,
2295*03ce13f7SAndroid Build Coastguard Worker                                     Mem->getAddrMode());
2296*03ce13f7SAndroid Build Coastguard Worker   }
2297*03ce13f7SAndroid Build Coastguard Worker   llvm_unreachable("Unsupported operand type");
2298*03ce13f7SAndroid Build Coastguard Worker   return nullptr;
2299*03ce13f7SAndroid Build Coastguard Worker }
2300*03ce13f7SAndroid Build Coastguard Worker 
getRegisterSet(RegSetMask Include,RegSetMask Exclude) const2301*03ce13f7SAndroid Build Coastguard Worker SmallBitVector TargetMIPS32::getRegisterSet(RegSetMask Include,
2302*03ce13f7SAndroid Build Coastguard Worker                                             RegSetMask Exclude) const {
2303*03ce13f7SAndroid Build Coastguard Worker   SmallBitVector Registers(RegMIPS32::Reg_NUM);
2304*03ce13f7SAndroid Build Coastguard Worker 
2305*03ce13f7SAndroid Build Coastguard Worker #define X(val, encode, name, scratch, preserved, stackptr, frameptr, isInt,    \
2306*03ce13f7SAndroid Build Coastguard Worker           isI64Pair, isFP32, isFP64, isVec128, alias_init)                     \
2307*03ce13f7SAndroid Build Coastguard Worker   if (scratch && (Include & RegSet_CallerSave))                                \
2308*03ce13f7SAndroid Build Coastguard Worker     Registers[RegMIPS32::val] = true;                                          \
2309*03ce13f7SAndroid Build Coastguard Worker   if (preserved && (Include & RegSet_CalleeSave))                              \
2310*03ce13f7SAndroid Build Coastguard Worker     Registers[RegMIPS32::val] = true;                                          \
2311*03ce13f7SAndroid Build Coastguard Worker   if (stackptr && (Include & RegSet_StackPointer))                             \
2312*03ce13f7SAndroid Build Coastguard Worker     Registers[RegMIPS32::val] = true;                                          \
2313*03ce13f7SAndroid Build Coastguard Worker   if (frameptr && (Include & RegSet_FramePointer))                             \
2314*03ce13f7SAndroid Build Coastguard Worker     Registers[RegMIPS32::val] = true;                                          \
2315*03ce13f7SAndroid Build Coastguard Worker   if (scratch && (Exclude & RegSet_CallerSave))                                \
2316*03ce13f7SAndroid Build Coastguard Worker     Registers[RegMIPS32::val] = false;                                         \
2317*03ce13f7SAndroid Build Coastguard Worker   if (preserved && (Exclude & RegSet_CalleeSave))                              \
2318*03ce13f7SAndroid Build Coastguard Worker     Registers[RegMIPS32::val] = false;                                         \
2319*03ce13f7SAndroid Build Coastguard Worker   if (stackptr && (Exclude & RegSet_StackPointer))                             \
2320*03ce13f7SAndroid Build Coastguard Worker     Registers[RegMIPS32::val] = false;                                         \
2321*03ce13f7SAndroid Build Coastguard Worker   if (frameptr && (Exclude & RegSet_FramePointer))                             \
2322*03ce13f7SAndroid Build Coastguard Worker     Registers[RegMIPS32::val] = false;
2323*03ce13f7SAndroid Build Coastguard Worker 
2324*03ce13f7SAndroid Build Coastguard Worker   REGMIPS32_TABLE
2325*03ce13f7SAndroid Build Coastguard Worker 
2326*03ce13f7SAndroid Build Coastguard Worker #undef X
2327*03ce13f7SAndroid Build Coastguard Worker 
2328*03ce13f7SAndroid Build Coastguard Worker   return Registers;
2329*03ce13f7SAndroid Build Coastguard Worker }
2330*03ce13f7SAndroid Build Coastguard Worker 
lowerAlloca(const InstAlloca * Instr)2331*03ce13f7SAndroid Build Coastguard Worker void TargetMIPS32::lowerAlloca(const InstAlloca *Instr) {
2332*03ce13f7SAndroid Build Coastguard Worker   // Conservatively require the stack to be aligned. Some stack adjustment
2333*03ce13f7SAndroid Build Coastguard Worker   // operations implemented below assume that the stack is aligned before the
2334*03ce13f7SAndroid Build Coastguard Worker   // alloca. All the alloca code ensures that the stack alignment is preserved
2335*03ce13f7SAndroid Build Coastguard Worker   // after the alloca. The stack alignment restriction can be relaxed in some
2336*03ce13f7SAndroid Build Coastguard Worker   // cases.
2337*03ce13f7SAndroid Build Coastguard Worker   NeedsStackAlignment = true;
2338*03ce13f7SAndroid Build Coastguard Worker 
2339*03ce13f7SAndroid Build Coastguard Worker   // For default align=0, set it to the real value 1, to avoid any
2340*03ce13f7SAndroid Build Coastguard Worker   // bit-manipulation problems below.
2341*03ce13f7SAndroid Build Coastguard Worker   const uint32_t AlignmentParam = std::max(1u, Instr->getAlignInBytes());
2342*03ce13f7SAndroid Build Coastguard Worker 
2343*03ce13f7SAndroid Build Coastguard Worker   // LLVM enforces power of 2 alignment.
2344*03ce13f7SAndroid Build Coastguard Worker   assert(llvm::isPowerOf2_32(AlignmentParam));
2345*03ce13f7SAndroid Build Coastguard Worker   assert(llvm::isPowerOf2_32(MIPS32_STACK_ALIGNMENT_BYTES));
2346*03ce13f7SAndroid Build Coastguard Worker 
2347*03ce13f7SAndroid Build Coastguard Worker   const uint32_t Alignment =
2348*03ce13f7SAndroid Build Coastguard Worker       std::max(AlignmentParam, MIPS32_STACK_ALIGNMENT_BYTES);
2349*03ce13f7SAndroid Build Coastguard Worker   const bool OverAligned = Alignment > MIPS32_STACK_ALIGNMENT_BYTES;
2350*03ce13f7SAndroid Build Coastguard Worker   const bool OptM1 = Func->getOptLevel() == Opt_m1;
2351*03ce13f7SAndroid Build Coastguard Worker   const bool AllocaWithKnownOffset = Instr->getKnownFrameOffset();
2352*03ce13f7SAndroid Build Coastguard Worker   const bool UseFramePointer =
2353*03ce13f7SAndroid Build Coastguard Worker       hasFramePointer() || OverAligned || !AllocaWithKnownOffset || OptM1;
2354*03ce13f7SAndroid Build Coastguard Worker 
2355*03ce13f7SAndroid Build Coastguard Worker   if (UseFramePointer)
2356*03ce13f7SAndroid Build Coastguard Worker     setHasFramePointer();
2357*03ce13f7SAndroid Build Coastguard Worker 
2358*03ce13f7SAndroid Build Coastguard Worker   Variable *SP = getPhysicalRegister(RegMIPS32::Reg_SP);
2359*03ce13f7SAndroid Build Coastguard Worker 
2360*03ce13f7SAndroid Build Coastguard Worker   Variable *Dest = Instr->getDest();
2361*03ce13f7SAndroid Build Coastguard Worker   Operand *TotalSize = Instr->getSizeInBytes();
2362*03ce13f7SAndroid Build Coastguard Worker 
2363*03ce13f7SAndroid Build Coastguard Worker   if (const auto *ConstantTotalSize =
2364*03ce13f7SAndroid Build Coastguard Worker           llvm::dyn_cast<ConstantInteger32>(TotalSize)) {
2365*03ce13f7SAndroid Build Coastguard Worker     const uint32_t Value =
2366*03ce13f7SAndroid Build Coastguard Worker         Utils::applyAlignment(ConstantTotalSize->getValue(), Alignment);
2367*03ce13f7SAndroid Build Coastguard Worker     FixedAllocaSizeBytes += Value;
2368*03ce13f7SAndroid Build Coastguard Worker     // Constant size alloca.
2369*03ce13f7SAndroid Build Coastguard Worker     if (!UseFramePointer) {
2370*03ce13f7SAndroid Build Coastguard Worker       // If we don't need a Frame Pointer, this alloca has a known offset to the
2371*03ce13f7SAndroid Build Coastguard Worker       // stack pointer. We don't need adjust the stack pointer, nor assign any
2372*03ce13f7SAndroid Build Coastguard Worker       // value to Dest, as Dest is rematerializable.
2373*03ce13f7SAndroid Build Coastguard Worker       assert(Dest->isRematerializable());
2374*03ce13f7SAndroid Build Coastguard Worker       Context.insert<InstFakeDef>(Dest);
2375*03ce13f7SAndroid Build Coastguard Worker       return;
2376*03ce13f7SAndroid Build Coastguard Worker     }
2377*03ce13f7SAndroid Build Coastguard Worker 
2378*03ce13f7SAndroid Build Coastguard Worker     if (Alignment > MIPS32_STACK_ALIGNMENT_BYTES) {
2379*03ce13f7SAndroid Build Coastguard Worker       CurrentAllocaOffset =
2380*03ce13f7SAndroid Build Coastguard Worker           Utils::applyAlignment(CurrentAllocaOffset, Alignment);
2381*03ce13f7SAndroid Build Coastguard Worker     }
2382*03ce13f7SAndroid Build Coastguard Worker     auto *T = I32Reg();
2383*03ce13f7SAndroid Build Coastguard Worker     _addiu(T, SP, CurrentAllocaOffset);
2384*03ce13f7SAndroid Build Coastguard Worker     _mov(Dest, T);
2385*03ce13f7SAndroid Build Coastguard Worker     CurrentAllocaOffset += Value;
2386*03ce13f7SAndroid Build Coastguard Worker     return;
2387*03ce13f7SAndroid Build Coastguard Worker 
2388*03ce13f7SAndroid Build Coastguard Worker   } else {
2389*03ce13f7SAndroid Build Coastguard Worker     // Non-constant sizes need to be adjusted to the next highest multiple of
2390*03ce13f7SAndroid Build Coastguard Worker     // the required alignment at runtime.
2391*03ce13f7SAndroid Build Coastguard Worker     VariableAllocaUsed = true;
2392*03ce13f7SAndroid Build Coastguard Worker     VariableAllocaAlignBytes = AlignmentParam;
2393*03ce13f7SAndroid Build Coastguard Worker     Variable *AlignAmount;
2394*03ce13f7SAndroid Build Coastguard Worker     auto *TotalSizeR = legalizeToReg(TotalSize, Legal_Reg);
2395*03ce13f7SAndroid Build Coastguard Worker     auto *T1 = I32Reg();
2396*03ce13f7SAndroid Build Coastguard Worker     auto *T2 = I32Reg();
2397*03ce13f7SAndroid Build Coastguard Worker     auto *T3 = I32Reg();
2398*03ce13f7SAndroid Build Coastguard Worker     auto *T4 = I32Reg();
2399*03ce13f7SAndroid Build Coastguard Worker     auto *T5 = I32Reg();
2400*03ce13f7SAndroid Build Coastguard Worker     _addiu(T1, TotalSizeR, MIPS32_STACK_ALIGNMENT_BYTES - 1);
2401*03ce13f7SAndroid Build Coastguard Worker     _addiu(T2, getZero(), -MIPS32_STACK_ALIGNMENT_BYTES);
2402*03ce13f7SAndroid Build Coastguard Worker     _and(T3, T1, T2);
2403*03ce13f7SAndroid Build Coastguard Worker     _subu(T4, SP, T3);
2404*03ce13f7SAndroid Build Coastguard Worker     if (Instr->getAlignInBytes()) {
2405*03ce13f7SAndroid Build Coastguard Worker       AlignAmount =
2406*03ce13f7SAndroid Build Coastguard Worker           legalizeToReg(Ctx->getConstantInt32(-AlignmentParam), Legal_Reg);
2407*03ce13f7SAndroid Build Coastguard Worker       _and(T5, T4, AlignAmount);
2408*03ce13f7SAndroid Build Coastguard Worker       _mov(Dest, T5);
2409*03ce13f7SAndroid Build Coastguard Worker     } else {
2410*03ce13f7SAndroid Build Coastguard Worker       _mov(Dest, T4);
2411*03ce13f7SAndroid Build Coastguard Worker     }
2412*03ce13f7SAndroid Build Coastguard Worker     _mov(SP, Dest);
2413*03ce13f7SAndroid Build Coastguard Worker     return;
2414*03ce13f7SAndroid Build Coastguard Worker   }
2415*03ce13f7SAndroid Build Coastguard Worker }
2416*03ce13f7SAndroid Build Coastguard Worker 
lowerInt64Arithmetic(const InstArithmetic * Instr,Variable * Dest,Operand * Src0,Operand * Src1)2417*03ce13f7SAndroid Build Coastguard Worker void TargetMIPS32::lowerInt64Arithmetic(const InstArithmetic *Instr,
2418*03ce13f7SAndroid Build Coastguard Worker                                         Variable *Dest, Operand *Src0,
2419*03ce13f7SAndroid Build Coastguard Worker                                         Operand *Src1) {
2420*03ce13f7SAndroid Build Coastguard Worker   InstArithmetic::OpKind Op = Instr->getOp();
2421*03ce13f7SAndroid Build Coastguard Worker   auto *DestLo = llvm::cast<Variable>(loOperand(Dest));
2422*03ce13f7SAndroid Build Coastguard Worker   auto *DestHi = llvm::cast<Variable>(hiOperand(Dest));
2423*03ce13f7SAndroid Build Coastguard Worker   Variable *Src0LoR = nullptr;
2424*03ce13f7SAndroid Build Coastguard Worker   Variable *Src1LoR = nullptr;
2425*03ce13f7SAndroid Build Coastguard Worker   Variable *Src0HiR = nullptr;
2426*03ce13f7SAndroid Build Coastguard Worker   Variable *Src1HiR = nullptr;
2427*03ce13f7SAndroid Build Coastguard Worker 
2428*03ce13f7SAndroid Build Coastguard Worker   switch (Op) {
2429*03ce13f7SAndroid Build Coastguard Worker   case InstArithmetic::_num:
2430*03ce13f7SAndroid Build Coastguard Worker     llvm::report_fatal_error("Unknown arithmetic operator");
2431*03ce13f7SAndroid Build Coastguard Worker     return;
2432*03ce13f7SAndroid Build Coastguard Worker   case InstArithmetic::Add: {
2433*03ce13f7SAndroid Build Coastguard Worker     Src0LoR = legalizeToReg(loOperand(Src0));
2434*03ce13f7SAndroid Build Coastguard Worker     Src1LoR = legalizeToReg(loOperand(Src1));
2435*03ce13f7SAndroid Build Coastguard Worker     Src0HiR = legalizeToReg(hiOperand(Src0));
2436*03ce13f7SAndroid Build Coastguard Worker     Src1HiR = legalizeToReg(hiOperand(Src1));
2437*03ce13f7SAndroid Build Coastguard Worker     auto *T_Carry = I32Reg(), *T_Lo = I32Reg(), *T_Hi = I32Reg(),
2438*03ce13f7SAndroid Build Coastguard Worker          *T_Hi2 = I32Reg();
2439*03ce13f7SAndroid Build Coastguard Worker     _addu(T_Lo, Src0LoR, Src1LoR);
2440*03ce13f7SAndroid Build Coastguard Worker     _mov(DestLo, T_Lo);
2441*03ce13f7SAndroid Build Coastguard Worker     _sltu(T_Carry, T_Lo, Src0LoR);
2442*03ce13f7SAndroid Build Coastguard Worker     _addu(T_Hi, T_Carry, Src0HiR);
2443*03ce13f7SAndroid Build Coastguard Worker     _addu(T_Hi2, Src1HiR, T_Hi);
2444*03ce13f7SAndroid Build Coastguard Worker     _mov(DestHi, T_Hi2);
2445*03ce13f7SAndroid Build Coastguard Worker     return;
2446*03ce13f7SAndroid Build Coastguard Worker   }
2447*03ce13f7SAndroid Build Coastguard Worker   case InstArithmetic::And: {
2448*03ce13f7SAndroid Build Coastguard Worker     Src0LoR = legalizeToReg(loOperand(Src0));
2449*03ce13f7SAndroid Build Coastguard Worker     Src1LoR = legalizeToReg(loOperand(Src1));
2450*03ce13f7SAndroid Build Coastguard Worker     Src0HiR = legalizeToReg(hiOperand(Src0));
2451*03ce13f7SAndroid Build Coastguard Worker     Src1HiR = legalizeToReg(hiOperand(Src1));
2452*03ce13f7SAndroid Build Coastguard Worker     auto *T_Lo = I32Reg(), *T_Hi = I32Reg();
2453*03ce13f7SAndroid Build Coastguard Worker     _and(T_Lo, Src0LoR, Src1LoR);
2454*03ce13f7SAndroid Build Coastguard Worker     _mov(DestLo, T_Lo);
2455*03ce13f7SAndroid Build Coastguard Worker     _and(T_Hi, Src0HiR, Src1HiR);
2456*03ce13f7SAndroid Build Coastguard Worker     _mov(DestHi, T_Hi);
2457*03ce13f7SAndroid Build Coastguard Worker     return;
2458*03ce13f7SAndroid Build Coastguard Worker   }
2459*03ce13f7SAndroid Build Coastguard Worker   case InstArithmetic::Sub: {
2460*03ce13f7SAndroid Build Coastguard Worker     Src0LoR = legalizeToReg(loOperand(Src0));
2461*03ce13f7SAndroid Build Coastguard Worker     Src1LoR = legalizeToReg(loOperand(Src1));
2462*03ce13f7SAndroid Build Coastguard Worker     Src0HiR = legalizeToReg(hiOperand(Src0));
2463*03ce13f7SAndroid Build Coastguard Worker     Src1HiR = legalizeToReg(hiOperand(Src1));
2464*03ce13f7SAndroid Build Coastguard Worker     auto *T_Borrow = I32Reg(), *T_Lo = I32Reg(), *T_Hi = I32Reg(),
2465*03ce13f7SAndroid Build Coastguard Worker          *T_Hi2 = I32Reg();
2466*03ce13f7SAndroid Build Coastguard Worker     _subu(T_Lo, Src0LoR, Src1LoR);
2467*03ce13f7SAndroid Build Coastguard Worker     _mov(DestLo, T_Lo);
2468*03ce13f7SAndroid Build Coastguard Worker     _sltu(T_Borrow, Src0LoR, Src1LoR);
2469*03ce13f7SAndroid Build Coastguard Worker     _addu(T_Hi, T_Borrow, Src1HiR);
2470*03ce13f7SAndroid Build Coastguard Worker     _subu(T_Hi2, Src0HiR, T_Hi);
2471*03ce13f7SAndroid Build Coastguard Worker     _mov(DestHi, T_Hi2);
2472*03ce13f7SAndroid Build Coastguard Worker     return;
2473*03ce13f7SAndroid Build Coastguard Worker   }
2474*03ce13f7SAndroid Build Coastguard Worker   case InstArithmetic::Or: {
2475*03ce13f7SAndroid Build Coastguard Worker     Src0LoR = legalizeToReg(loOperand(Src0));
2476*03ce13f7SAndroid Build Coastguard Worker     Src1LoR = legalizeToReg(loOperand(Src1));
2477*03ce13f7SAndroid Build Coastguard Worker     Src0HiR = legalizeToReg(hiOperand(Src0));
2478*03ce13f7SAndroid Build Coastguard Worker     Src1HiR = legalizeToReg(hiOperand(Src1));
2479*03ce13f7SAndroid Build Coastguard Worker     auto *T_Lo = I32Reg(), *T_Hi = I32Reg();
2480*03ce13f7SAndroid Build Coastguard Worker     _or(T_Lo, Src0LoR, Src1LoR);
2481*03ce13f7SAndroid Build Coastguard Worker     _mov(DestLo, T_Lo);
2482*03ce13f7SAndroid Build Coastguard Worker     _or(T_Hi, Src0HiR, Src1HiR);
2483*03ce13f7SAndroid Build Coastguard Worker     _mov(DestHi, T_Hi);
2484*03ce13f7SAndroid Build Coastguard Worker     return;
2485*03ce13f7SAndroid Build Coastguard Worker   }
2486*03ce13f7SAndroid Build Coastguard Worker   case InstArithmetic::Xor: {
2487*03ce13f7SAndroid Build Coastguard Worker     Src0LoR = legalizeToReg(loOperand(Src0));
2488*03ce13f7SAndroid Build Coastguard Worker     Src1LoR = legalizeToReg(loOperand(Src1));
2489*03ce13f7SAndroid Build Coastguard Worker     Src0HiR = legalizeToReg(hiOperand(Src0));
2490*03ce13f7SAndroid Build Coastguard Worker     Src1HiR = legalizeToReg(hiOperand(Src1));
2491*03ce13f7SAndroid Build Coastguard Worker     auto *T_Lo = I32Reg(), *T_Hi = I32Reg();
2492*03ce13f7SAndroid Build Coastguard Worker     _xor(T_Lo, Src0LoR, Src1LoR);
2493*03ce13f7SAndroid Build Coastguard Worker     _mov(DestLo, T_Lo);
2494*03ce13f7SAndroid Build Coastguard Worker     _xor(T_Hi, Src0HiR, Src1HiR);
2495*03ce13f7SAndroid Build Coastguard Worker     _mov(DestHi, T_Hi);
2496*03ce13f7SAndroid Build Coastguard Worker     return;
2497*03ce13f7SAndroid Build Coastguard Worker   }
2498*03ce13f7SAndroid Build Coastguard Worker   case InstArithmetic::Mul: {
2499*03ce13f7SAndroid Build Coastguard Worker     // TODO(rkotler): Make sure that mul has the side effect of clobbering
2500*03ce13f7SAndroid Build Coastguard Worker     // LO, HI. Check for any other LO, HI quirkiness in this section.
2501*03ce13f7SAndroid Build Coastguard Worker     Src0LoR = legalizeToReg(loOperand(Src0));
2502*03ce13f7SAndroid Build Coastguard Worker     Src1LoR = legalizeToReg(loOperand(Src1));
2503*03ce13f7SAndroid Build Coastguard Worker     Src0HiR = legalizeToReg(hiOperand(Src0));
2504*03ce13f7SAndroid Build Coastguard Worker     Src1HiR = legalizeToReg(hiOperand(Src1));
2505*03ce13f7SAndroid Build Coastguard Worker     auto *T_Lo = I32Reg(RegMIPS32::Reg_LO), *T_Hi = I32Reg(RegMIPS32::Reg_HI);
2506*03ce13f7SAndroid Build Coastguard Worker     auto *T1 = I32Reg(), *T2 = I32Reg();
2507*03ce13f7SAndroid Build Coastguard Worker     auto *TM1 = I32Reg(), *TM2 = I32Reg(), *TM3 = I32Reg(), *TM4 = I32Reg();
2508*03ce13f7SAndroid Build Coastguard Worker     _multu(T_Lo, Src0LoR, Src1LoR);
2509*03ce13f7SAndroid Build Coastguard Worker     Context.insert<InstFakeDef>(T_Hi, T_Lo);
2510*03ce13f7SAndroid Build Coastguard Worker     _mflo(T1, T_Lo);
2511*03ce13f7SAndroid Build Coastguard Worker     _mfhi(T2, T_Hi);
2512*03ce13f7SAndroid Build Coastguard Worker     _mov(DestLo, T1);
2513*03ce13f7SAndroid Build Coastguard Worker     _mul(TM1, Src0HiR, Src1LoR);
2514*03ce13f7SAndroid Build Coastguard Worker     _mul(TM2, Src0LoR, Src1HiR);
2515*03ce13f7SAndroid Build Coastguard Worker     _addu(TM3, TM1, T2);
2516*03ce13f7SAndroid Build Coastguard Worker     _addu(TM4, TM3, TM2);
2517*03ce13f7SAndroid Build Coastguard Worker     _mov(DestHi, TM4);
2518*03ce13f7SAndroid Build Coastguard Worker     return;
2519*03ce13f7SAndroid Build Coastguard Worker   }
2520*03ce13f7SAndroid Build Coastguard Worker   case InstArithmetic::Shl: {
2521*03ce13f7SAndroid Build Coastguard Worker     auto *T_Lo = I32Reg();
2522*03ce13f7SAndroid Build Coastguard Worker     auto *T_Hi = I32Reg();
2523*03ce13f7SAndroid Build Coastguard Worker     auto *T1_Lo = I32Reg();
2524*03ce13f7SAndroid Build Coastguard Worker     auto *T1_Hi = I32Reg();
2525*03ce13f7SAndroid Build Coastguard Worker     auto *T1 = I32Reg();
2526*03ce13f7SAndroid Build Coastguard Worker     auto *T2 = I32Reg();
2527*03ce13f7SAndroid Build Coastguard Worker     auto *T3 = I32Reg();
2528*03ce13f7SAndroid Build Coastguard Worker     auto *T4 = I32Reg();
2529*03ce13f7SAndroid Build Coastguard Worker     auto *T5 = I32Reg();
2530*03ce13f7SAndroid Build Coastguard Worker 
2531*03ce13f7SAndroid Build Coastguard Worker     if (auto *Const = llvm::dyn_cast<ConstantInteger64>(Src1)) {
2532*03ce13f7SAndroid Build Coastguard Worker       Src0LoR = legalizeToReg(loOperand(Src0));
2533*03ce13f7SAndroid Build Coastguard Worker       int64_t ShiftAmount = Const->getValue();
2534*03ce13f7SAndroid Build Coastguard Worker       if (ShiftAmount == 1) {
2535*03ce13f7SAndroid Build Coastguard Worker         Src0HiR = legalizeToReg(hiOperand(Src0));
2536*03ce13f7SAndroid Build Coastguard Worker         _addu(T_Lo, Src0LoR, Src0LoR);
2537*03ce13f7SAndroid Build Coastguard Worker         _sltu(T1, T_Lo, Src0LoR);
2538*03ce13f7SAndroid Build Coastguard Worker         _addu(T2, T1, Src0HiR);
2539*03ce13f7SAndroid Build Coastguard Worker         _addu(T_Hi, Src0HiR, T2);
2540*03ce13f7SAndroid Build Coastguard Worker       } else if (ShiftAmount < INT32_BITS) {
2541*03ce13f7SAndroid Build Coastguard Worker         Src0HiR = legalizeToReg(hiOperand(Src0));
2542*03ce13f7SAndroid Build Coastguard Worker         _srl(T1, Src0LoR, INT32_BITS - ShiftAmount);
2543*03ce13f7SAndroid Build Coastguard Worker         _sll(T2, Src0HiR, ShiftAmount);
2544*03ce13f7SAndroid Build Coastguard Worker         _or(T_Hi, T1, T2);
2545*03ce13f7SAndroid Build Coastguard Worker         _sll(T_Lo, Src0LoR, ShiftAmount);
2546*03ce13f7SAndroid Build Coastguard Worker       } else if (ShiftAmount == INT32_BITS) {
2547*03ce13f7SAndroid Build Coastguard Worker         _addiu(T_Lo, getZero(), 0);
2548*03ce13f7SAndroid Build Coastguard Worker         _mov(T_Hi, Src0LoR);
2549*03ce13f7SAndroid Build Coastguard Worker       } else if (ShiftAmount > INT32_BITS && ShiftAmount < 64) {
2550*03ce13f7SAndroid Build Coastguard Worker         _sll(T_Hi, Src0LoR, ShiftAmount - INT32_BITS);
2551*03ce13f7SAndroid Build Coastguard Worker         _addiu(T_Lo, getZero(), 0);
2552*03ce13f7SAndroid Build Coastguard Worker       }
2553*03ce13f7SAndroid Build Coastguard Worker       _mov(DestLo, T_Lo);
2554*03ce13f7SAndroid Build Coastguard Worker       _mov(DestHi, T_Hi);
2555*03ce13f7SAndroid Build Coastguard Worker       return;
2556*03ce13f7SAndroid Build Coastguard Worker     }
2557*03ce13f7SAndroid Build Coastguard Worker 
2558*03ce13f7SAndroid Build Coastguard Worker     Src0LoR = legalizeToReg(loOperand(Src0));
2559*03ce13f7SAndroid Build Coastguard Worker     Src1LoR = legalizeToReg(loOperand(Src1));
2560*03ce13f7SAndroid Build Coastguard Worker     Src0HiR = legalizeToReg(hiOperand(Src0));
2561*03ce13f7SAndroid Build Coastguard Worker 
2562*03ce13f7SAndroid Build Coastguard Worker     _sllv(T1, Src0HiR, Src1LoR);
2563*03ce13f7SAndroid Build Coastguard Worker     _not(T2, Src1LoR);
2564*03ce13f7SAndroid Build Coastguard Worker     _srl(T3, Src0LoR, 1);
2565*03ce13f7SAndroid Build Coastguard Worker     _srlv(T4, T3, T2);
2566*03ce13f7SAndroid Build Coastguard Worker     _or(T_Hi, T1, T4);
2567*03ce13f7SAndroid Build Coastguard Worker     _sllv(T_Lo, Src0LoR, Src1LoR);
2568*03ce13f7SAndroid Build Coastguard Worker 
2569*03ce13f7SAndroid Build Coastguard Worker     _mov(T1_Hi, T_Hi);
2570*03ce13f7SAndroid Build Coastguard Worker     _mov(T1_Lo, T_Lo);
2571*03ce13f7SAndroid Build Coastguard Worker     _andi(T5, Src1LoR, INT32_BITS);
2572*03ce13f7SAndroid Build Coastguard Worker     _movn(T1_Hi, T_Lo, T5);
2573*03ce13f7SAndroid Build Coastguard Worker     _movn(T1_Lo, getZero(), T5);
2574*03ce13f7SAndroid Build Coastguard Worker     _mov(DestHi, T1_Hi);
2575*03ce13f7SAndroid Build Coastguard Worker     _mov(DestLo, T1_Lo);
2576*03ce13f7SAndroid Build Coastguard Worker     return;
2577*03ce13f7SAndroid Build Coastguard Worker   }
2578*03ce13f7SAndroid Build Coastguard Worker   case InstArithmetic::Lshr: {
2579*03ce13f7SAndroid Build Coastguard Worker 
2580*03ce13f7SAndroid Build Coastguard Worker     auto *T_Lo = I32Reg();
2581*03ce13f7SAndroid Build Coastguard Worker     auto *T_Hi = I32Reg();
2582*03ce13f7SAndroid Build Coastguard Worker     auto *T1_Lo = I32Reg();
2583*03ce13f7SAndroid Build Coastguard Worker     auto *T1_Hi = I32Reg();
2584*03ce13f7SAndroid Build Coastguard Worker     auto *T1 = I32Reg();
2585*03ce13f7SAndroid Build Coastguard Worker     auto *T2 = I32Reg();
2586*03ce13f7SAndroid Build Coastguard Worker     auto *T3 = I32Reg();
2587*03ce13f7SAndroid Build Coastguard Worker     auto *T4 = I32Reg();
2588*03ce13f7SAndroid Build Coastguard Worker     auto *T5 = I32Reg();
2589*03ce13f7SAndroid Build Coastguard Worker 
2590*03ce13f7SAndroid Build Coastguard Worker     if (auto *Const = llvm::dyn_cast<ConstantInteger64>(Src1)) {
2591*03ce13f7SAndroid Build Coastguard Worker       Src0HiR = legalizeToReg(hiOperand(Src0));
2592*03ce13f7SAndroid Build Coastguard Worker       int64_t ShiftAmount = Const->getValue();
2593*03ce13f7SAndroid Build Coastguard Worker       if (ShiftAmount < INT32_BITS) {
2594*03ce13f7SAndroid Build Coastguard Worker         Src0LoR = legalizeToReg(loOperand(Src0));
2595*03ce13f7SAndroid Build Coastguard Worker         _sll(T1, Src0HiR, INT32_BITS - ShiftAmount);
2596*03ce13f7SAndroid Build Coastguard Worker         _srl(T2, Src0LoR, ShiftAmount);
2597*03ce13f7SAndroid Build Coastguard Worker         _or(T_Lo, T1, T2);
2598*03ce13f7SAndroid Build Coastguard Worker         _srl(T_Hi, Src0HiR, ShiftAmount);
2599*03ce13f7SAndroid Build Coastguard Worker       } else if (ShiftAmount == INT32_BITS) {
2600*03ce13f7SAndroid Build Coastguard Worker         _mov(T_Lo, Src0HiR);
2601*03ce13f7SAndroid Build Coastguard Worker         _addiu(T_Hi, getZero(), 0);
2602*03ce13f7SAndroid Build Coastguard Worker       } else if (ShiftAmount > INT32_BITS && ShiftAmount < 64) {
2603*03ce13f7SAndroid Build Coastguard Worker         _srl(T_Lo, Src0HiR, ShiftAmount - INT32_BITS);
2604*03ce13f7SAndroid Build Coastguard Worker         _addiu(T_Hi, getZero(), 0);
2605*03ce13f7SAndroid Build Coastguard Worker       }
2606*03ce13f7SAndroid Build Coastguard Worker       _mov(DestLo, T_Lo);
2607*03ce13f7SAndroid Build Coastguard Worker       _mov(DestHi, T_Hi);
2608*03ce13f7SAndroid Build Coastguard Worker       return;
2609*03ce13f7SAndroid Build Coastguard Worker     }
2610*03ce13f7SAndroid Build Coastguard Worker 
2611*03ce13f7SAndroid Build Coastguard Worker     Src0LoR = legalizeToReg(loOperand(Src0));
2612*03ce13f7SAndroid Build Coastguard Worker     Src1LoR = legalizeToReg(loOperand(Src1));
2613*03ce13f7SAndroid Build Coastguard Worker     Src0HiR = legalizeToReg(hiOperand(Src0));
2614*03ce13f7SAndroid Build Coastguard Worker 
2615*03ce13f7SAndroid Build Coastguard Worker     _srlv(T1, Src0LoR, Src1LoR);
2616*03ce13f7SAndroid Build Coastguard Worker     _not(T2, Src1LoR);
2617*03ce13f7SAndroid Build Coastguard Worker     _sll(T3, Src0HiR, 1);
2618*03ce13f7SAndroid Build Coastguard Worker     _sllv(T4, T3, T2);
2619*03ce13f7SAndroid Build Coastguard Worker     _or(T_Lo, T1, T4);
2620*03ce13f7SAndroid Build Coastguard Worker     _srlv(T_Hi, Src0HiR, Src1LoR);
2621*03ce13f7SAndroid Build Coastguard Worker 
2622*03ce13f7SAndroid Build Coastguard Worker     _mov(T1_Hi, T_Hi);
2623*03ce13f7SAndroid Build Coastguard Worker     _mov(T1_Lo, T_Lo);
2624*03ce13f7SAndroid Build Coastguard Worker     _andi(T5, Src1LoR, INT32_BITS);
2625*03ce13f7SAndroid Build Coastguard Worker     _movn(T1_Lo, T_Hi, T5);
2626*03ce13f7SAndroid Build Coastguard Worker     _movn(T1_Hi, getZero(), T5);
2627*03ce13f7SAndroid Build Coastguard Worker     _mov(DestHi, T1_Hi);
2628*03ce13f7SAndroid Build Coastguard Worker     _mov(DestLo, T1_Lo);
2629*03ce13f7SAndroid Build Coastguard Worker     return;
2630*03ce13f7SAndroid Build Coastguard Worker   }
2631*03ce13f7SAndroid Build Coastguard Worker   case InstArithmetic::Ashr: {
2632*03ce13f7SAndroid Build Coastguard Worker 
2633*03ce13f7SAndroid Build Coastguard Worker     auto *T_Lo = I32Reg();
2634*03ce13f7SAndroid Build Coastguard Worker     auto *T_Hi = I32Reg();
2635*03ce13f7SAndroid Build Coastguard Worker     auto *T1_Lo = I32Reg();
2636*03ce13f7SAndroid Build Coastguard Worker     auto *T1_Hi = I32Reg();
2637*03ce13f7SAndroid Build Coastguard Worker     auto *T1 = I32Reg();
2638*03ce13f7SAndroid Build Coastguard Worker     auto *T2 = I32Reg();
2639*03ce13f7SAndroid Build Coastguard Worker     auto *T3 = I32Reg();
2640*03ce13f7SAndroid Build Coastguard Worker     auto *T4 = I32Reg();
2641*03ce13f7SAndroid Build Coastguard Worker     auto *T5 = I32Reg();
2642*03ce13f7SAndroid Build Coastguard Worker     auto *T6 = I32Reg();
2643*03ce13f7SAndroid Build Coastguard Worker 
2644*03ce13f7SAndroid Build Coastguard Worker     if (auto *Const = llvm::dyn_cast<ConstantInteger64>(Src1)) {
2645*03ce13f7SAndroid Build Coastguard Worker       Src0HiR = legalizeToReg(hiOperand(Src0));
2646*03ce13f7SAndroid Build Coastguard Worker       int64_t ShiftAmount = Const->getValue();
2647*03ce13f7SAndroid Build Coastguard Worker       if (ShiftAmount < INT32_BITS) {
2648*03ce13f7SAndroid Build Coastguard Worker         Src0LoR = legalizeToReg(loOperand(Src0));
2649*03ce13f7SAndroid Build Coastguard Worker         _sll(T1, Src0HiR, INT32_BITS - ShiftAmount);
2650*03ce13f7SAndroid Build Coastguard Worker         _srl(T2, Src0LoR, ShiftAmount);
2651*03ce13f7SAndroid Build Coastguard Worker         _or(T_Lo, T1, T2);
2652*03ce13f7SAndroid Build Coastguard Worker         _sra(T_Hi, Src0HiR, ShiftAmount);
2653*03ce13f7SAndroid Build Coastguard Worker       } else if (ShiftAmount == INT32_BITS) {
2654*03ce13f7SAndroid Build Coastguard Worker         _sra(T_Hi, Src0HiR, INT32_BITS - 1);
2655*03ce13f7SAndroid Build Coastguard Worker         _mov(T_Lo, Src0HiR);
2656*03ce13f7SAndroid Build Coastguard Worker       } else if (ShiftAmount > INT32_BITS && ShiftAmount < 64) {
2657*03ce13f7SAndroid Build Coastguard Worker         _sra(T_Lo, Src0HiR, ShiftAmount - INT32_BITS);
2658*03ce13f7SAndroid Build Coastguard Worker         _sra(T_Hi, Src0HiR, INT32_BITS - 1);
2659*03ce13f7SAndroid Build Coastguard Worker       }
2660*03ce13f7SAndroid Build Coastguard Worker       _mov(DestLo, T_Lo);
2661*03ce13f7SAndroid Build Coastguard Worker       _mov(DestHi, T_Hi);
2662*03ce13f7SAndroid Build Coastguard Worker       return;
2663*03ce13f7SAndroid Build Coastguard Worker     }
2664*03ce13f7SAndroid Build Coastguard Worker 
2665*03ce13f7SAndroid Build Coastguard Worker     Src0LoR = legalizeToReg(loOperand(Src0));
2666*03ce13f7SAndroid Build Coastguard Worker     Src1LoR = legalizeToReg(loOperand(Src1));
2667*03ce13f7SAndroid Build Coastguard Worker     Src0HiR = legalizeToReg(hiOperand(Src0));
2668*03ce13f7SAndroid Build Coastguard Worker 
2669*03ce13f7SAndroid Build Coastguard Worker     _srlv(T1, Src0LoR, Src1LoR);
2670*03ce13f7SAndroid Build Coastguard Worker     _not(T2, Src1LoR);
2671*03ce13f7SAndroid Build Coastguard Worker     _sll(T3, Src0HiR, 1);
2672*03ce13f7SAndroid Build Coastguard Worker     _sllv(T4, T3, T2);
2673*03ce13f7SAndroid Build Coastguard Worker     _or(T_Lo, T1, T4);
2674*03ce13f7SAndroid Build Coastguard Worker     _srav(T_Hi, Src0HiR, Src1LoR);
2675*03ce13f7SAndroid Build Coastguard Worker 
2676*03ce13f7SAndroid Build Coastguard Worker     _mov(T1_Hi, T_Hi);
2677*03ce13f7SAndroid Build Coastguard Worker     _mov(T1_Lo, T_Lo);
2678*03ce13f7SAndroid Build Coastguard Worker     _andi(T5, Src1LoR, INT32_BITS);
2679*03ce13f7SAndroid Build Coastguard Worker     _movn(T1_Lo, T_Hi, T5);
2680*03ce13f7SAndroid Build Coastguard Worker     _sra(T6, Src0HiR, INT32_BITS - 1);
2681*03ce13f7SAndroid Build Coastguard Worker     _movn(T1_Hi, T6, T5);
2682*03ce13f7SAndroid Build Coastguard Worker     _mov(DestHi, T1_Hi);
2683*03ce13f7SAndroid Build Coastguard Worker     _mov(DestLo, T1_Lo);
2684*03ce13f7SAndroid Build Coastguard Worker     return;
2685*03ce13f7SAndroid Build Coastguard Worker   }
2686*03ce13f7SAndroid Build Coastguard Worker   case InstArithmetic::Fadd:
2687*03ce13f7SAndroid Build Coastguard Worker   case InstArithmetic::Fsub:
2688*03ce13f7SAndroid Build Coastguard Worker   case InstArithmetic::Fmul:
2689*03ce13f7SAndroid Build Coastguard Worker   case InstArithmetic::Fdiv:
2690*03ce13f7SAndroid Build Coastguard Worker   case InstArithmetic::Frem:
2691*03ce13f7SAndroid Build Coastguard Worker     llvm::report_fatal_error("FP instruction with i64 type");
2692*03ce13f7SAndroid Build Coastguard Worker     return;
2693*03ce13f7SAndroid Build Coastguard Worker   case InstArithmetic::Udiv:
2694*03ce13f7SAndroid Build Coastguard Worker   case InstArithmetic::Sdiv:
2695*03ce13f7SAndroid Build Coastguard Worker   case InstArithmetic::Urem:
2696*03ce13f7SAndroid Build Coastguard Worker   case InstArithmetic::Srem:
2697*03ce13f7SAndroid Build Coastguard Worker     llvm::report_fatal_error("64-bit div and rem should have been prelowered");
2698*03ce13f7SAndroid Build Coastguard Worker     return;
2699*03ce13f7SAndroid Build Coastguard Worker   }
2700*03ce13f7SAndroid Build Coastguard Worker }
2701*03ce13f7SAndroid Build Coastguard Worker 
lowerArithmetic(const InstArithmetic * Instr)2702*03ce13f7SAndroid Build Coastguard Worker void TargetMIPS32::lowerArithmetic(const InstArithmetic *Instr) {
2703*03ce13f7SAndroid Build Coastguard Worker   Variable *Dest = Instr->getDest();
2704*03ce13f7SAndroid Build Coastguard Worker 
2705*03ce13f7SAndroid Build Coastguard Worker   if (Dest->isRematerializable()) {
2706*03ce13f7SAndroid Build Coastguard Worker     Context.insert<InstFakeDef>(Dest);
2707*03ce13f7SAndroid Build Coastguard Worker     return;
2708*03ce13f7SAndroid Build Coastguard Worker   }
2709*03ce13f7SAndroid Build Coastguard Worker 
2710*03ce13f7SAndroid Build Coastguard Worker   // We need to signal all the UnimplementedLoweringError errors before any
2711*03ce13f7SAndroid Build Coastguard Worker   // legalization into new variables, otherwise Om1 register allocation may fail
2712*03ce13f7SAndroid Build Coastguard Worker   // when it sees variables that are defined but not used.
2713*03ce13f7SAndroid Build Coastguard Worker   Type DestTy = Dest->getType();
2714*03ce13f7SAndroid Build Coastguard Worker   Operand *Src0 = legalizeUndef(Instr->getSrc(0));
2715*03ce13f7SAndroid Build Coastguard Worker   Operand *Src1 = legalizeUndef(Instr->getSrc(1));
2716*03ce13f7SAndroid Build Coastguard Worker   if (DestTy == IceType_i64) {
2717*03ce13f7SAndroid Build Coastguard Worker     lowerInt64Arithmetic(Instr, Instr->getDest(), Src0, Src1);
2718*03ce13f7SAndroid Build Coastguard Worker     return;
2719*03ce13f7SAndroid Build Coastguard Worker   }
2720*03ce13f7SAndroid Build Coastguard Worker   if (isVectorType(Dest->getType())) {
2721*03ce13f7SAndroid Build Coastguard Worker     llvm::report_fatal_error("Arithmetic: Destination type is vector");
2722*03ce13f7SAndroid Build Coastguard Worker     return;
2723*03ce13f7SAndroid Build Coastguard Worker   }
2724*03ce13f7SAndroid Build Coastguard Worker 
2725*03ce13f7SAndroid Build Coastguard Worker   Variable *T = makeReg(Dest->getType());
2726*03ce13f7SAndroid Build Coastguard Worker   Variable *Src0R = legalizeToReg(Src0);
2727*03ce13f7SAndroid Build Coastguard Worker   Variable *Src1R = nullptr;
2728*03ce13f7SAndroid Build Coastguard Worker   uint32_t Value = 0;
2729*03ce13f7SAndroid Build Coastguard Worker   bool IsSrc1Imm16 = false;
2730*03ce13f7SAndroid Build Coastguard Worker 
2731*03ce13f7SAndroid Build Coastguard Worker   switch (Instr->getOp()) {
2732*03ce13f7SAndroid Build Coastguard Worker   case InstArithmetic::Add:
2733*03ce13f7SAndroid Build Coastguard Worker   case InstArithmetic::Sub: {
2734*03ce13f7SAndroid Build Coastguard Worker     auto *Const32 = llvm::dyn_cast<ConstantInteger32>(Src1);
2735*03ce13f7SAndroid Build Coastguard Worker     if (Const32 != nullptr && isInt<16>(int32_t(Const32->getValue()))) {
2736*03ce13f7SAndroid Build Coastguard Worker       IsSrc1Imm16 = true;
2737*03ce13f7SAndroid Build Coastguard Worker       Value = Const32->getValue();
2738*03ce13f7SAndroid Build Coastguard Worker     } else {
2739*03ce13f7SAndroid Build Coastguard Worker       Src1R = legalizeToReg(Src1);
2740*03ce13f7SAndroid Build Coastguard Worker     }
2741*03ce13f7SAndroid Build Coastguard Worker     break;
2742*03ce13f7SAndroid Build Coastguard Worker   }
2743*03ce13f7SAndroid Build Coastguard Worker   case InstArithmetic::And:
2744*03ce13f7SAndroid Build Coastguard Worker   case InstArithmetic::Or:
2745*03ce13f7SAndroid Build Coastguard Worker   case InstArithmetic::Xor:
2746*03ce13f7SAndroid Build Coastguard Worker   case InstArithmetic::Shl:
2747*03ce13f7SAndroid Build Coastguard Worker   case InstArithmetic::Lshr:
2748*03ce13f7SAndroid Build Coastguard Worker   case InstArithmetic::Ashr: {
2749*03ce13f7SAndroid Build Coastguard Worker     auto *Const32 = llvm::dyn_cast<ConstantInteger32>(Src1);
2750*03ce13f7SAndroid Build Coastguard Worker     if (Const32 != nullptr && llvm::isUInt<16>(uint32_t(Const32->getValue()))) {
2751*03ce13f7SAndroid Build Coastguard Worker       IsSrc1Imm16 = true;
2752*03ce13f7SAndroid Build Coastguard Worker       Value = Const32->getValue();
2753*03ce13f7SAndroid Build Coastguard Worker     } else {
2754*03ce13f7SAndroid Build Coastguard Worker       Src1R = legalizeToReg(Src1);
2755*03ce13f7SAndroid Build Coastguard Worker     }
2756*03ce13f7SAndroid Build Coastguard Worker     break;
2757*03ce13f7SAndroid Build Coastguard Worker   }
2758*03ce13f7SAndroid Build Coastguard Worker   default:
2759*03ce13f7SAndroid Build Coastguard Worker     Src1R = legalizeToReg(Src1);
2760*03ce13f7SAndroid Build Coastguard Worker     break;
2761*03ce13f7SAndroid Build Coastguard Worker   }
2762*03ce13f7SAndroid Build Coastguard Worker   constexpr uint32_t DivideByZeroTrapCode = 7;
2763*03ce13f7SAndroid Build Coastguard Worker 
2764*03ce13f7SAndroid Build Coastguard Worker   switch (Instr->getOp()) {
2765*03ce13f7SAndroid Build Coastguard Worker   case InstArithmetic::_num:
2766*03ce13f7SAndroid Build Coastguard Worker     break;
2767*03ce13f7SAndroid Build Coastguard Worker   case InstArithmetic::Add: {
2768*03ce13f7SAndroid Build Coastguard Worker     auto *T0R = Src0R;
2769*03ce13f7SAndroid Build Coastguard Worker     auto *T1R = Src1R;
2770*03ce13f7SAndroid Build Coastguard Worker     if (Dest->getType() != IceType_i32) {
2771*03ce13f7SAndroid Build Coastguard Worker       T0R = makeReg(IceType_i32);
2772*03ce13f7SAndroid Build Coastguard Worker       lowerCast(InstCast::create(Func, InstCast::Sext, T0R, Src0R));
2773*03ce13f7SAndroid Build Coastguard Worker       if (!IsSrc1Imm16) {
2774*03ce13f7SAndroid Build Coastguard Worker         T1R = makeReg(IceType_i32);
2775*03ce13f7SAndroid Build Coastguard Worker         lowerCast(InstCast::create(Func, InstCast::Sext, T1R, Src1R));
2776*03ce13f7SAndroid Build Coastguard Worker       }
2777*03ce13f7SAndroid Build Coastguard Worker     }
2778*03ce13f7SAndroid Build Coastguard Worker     if (IsSrc1Imm16) {
2779*03ce13f7SAndroid Build Coastguard Worker       _addiu(T, T0R, Value);
2780*03ce13f7SAndroid Build Coastguard Worker     } else {
2781*03ce13f7SAndroid Build Coastguard Worker       _addu(T, T0R, T1R);
2782*03ce13f7SAndroid Build Coastguard Worker     }
2783*03ce13f7SAndroid Build Coastguard Worker     _mov(Dest, T);
2784*03ce13f7SAndroid Build Coastguard Worker     return;
2785*03ce13f7SAndroid Build Coastguard Worker   }
2786*03ce13f7SAndroid Build Coastguard Worker   case InstArithmetic::And:
2787*03ce13f7SAndroid Build Coastguard Worker     if (IsSrc1Imm16) {
2788*03ce13f7SAndroid Build Coastguard Worker       _andi(T, Src0R, Value);
2789*03ce13f7SAndroid Build Coastguard Worker     } else {
2790*03ce13f7SAndroid Build Coastguard Worker       _and(T, Src0R, Src1R);
2791*03ce13f7SAndroid Build Coastguard Worker     }
2792*03ce13f7SAndroid Build Coastguard Worker     _mov(Dest, T);
2793*03ce13f7SAndroid Build Coastguard Worker     return;
2794*03ce13f7SAndroid Build Coastguard Worker   case InstArithmetic::Or:
2795*03ce13f7SAndroid Build Coastguard Worker     if (IsSrc1Imm16) {
2796*03ce13f7SAndroid Build Coastguard Worker       _ori(T, Src0R, Value);
2797*03ce13f7SAndroid Build Coastguard Worker     } else {
2798*03ce13f7SAndroid Build Coastguard Worker       _or(T, Src0R, Src1R);
2799*03ce13f7SAndroid Build Coastguard Worker     }
2800*03ce13f7SAndroid Build Coastguard Worker     _mov(Dest, T);
2801*03ce13f7SAndroid Build Coastguard Worker     return;
2802*03ce13f7SAndroid Build Coastguard Worker   case InstArithmetic::Xor:
2803*03ce13f7SAndroid Build Coastguard Worker     if (IsSrc1Imm16) {
2804*03ce13f7SAndroid Build Coastguard Worker       _xori(T, Src0R, Value);
2805*03ce13f7SAndroid Build Coastguard Worker     } else {
2806*03ce13f7SAndroid Build Coastguard Worker       _xor(T, Src0R, Src1R);
2807*03ce13f7SAndroid Build Coastguard Worker     }
2808*03ce13f7SAndroid Build Coastguard Worker     _mov(Dest, T);
2809*03ce13f7SAndroid Build Coastguard Worker     return;
2810*03ce13f7SAndroid Build Coastguard Worker   case InstArithmetic::Sub: {
2811*03ce13f7SAndroid Build Coastguard Worker     auto *T0R = Src0R;
2812*03ce13f7SAndroid Build Coastguard Worker     auto *T1R = Src1R;
2813*03ce13f7SAndroid Build Coastguard Worker     if (Dest->getType() != IceType_i32) {
2814*03ce13f7SAndroid Build Coastguard Worker       T0R = makeReg(IceType_i32);
2815*03ce13f7SAndroid Build Coastguard Worker       lowerCast(InstCast::create(Func, InstCast::Sext, T0R, Src0R));
2816*03ce13f7SAndroid Build Coastguard Worker       if (!IsSrc1Imm16) {
2817*03ce13f7SAndroid Build Coastguard Worker         T1R = makeReg(IceType_i32);
2818*03ce13f7SAndroid Build Coastguard Worker         lowerCast(InstCast::create(Func, InstCast::Sext, T1R, Src1R));
2819*03ce13f7SAndroid Build Coastguard Worker       }
2820*03ce13f7SAndroid Build Coastguard Worker     }
2821*03ce13f7SAndroid Build Coastguard Worker     if (IsSrc1Imm16) {
2822*03ce13f7SAndroid Build Coastguard Worker       _addiu(T, T0R, -Value);
2823*03ce13f7SAndroid Build Coastguard Worker     } else {
2824*03ce13f7SAndroid Build Coastguard Worker       _subu(T, T0R, T1R);
2825*03ce13f7SAndroid Build Coastguard Worker     }
2826*03ce13f7SAndroid Build Coastguard Worker     _mov(Dest, T);
2827*03ce13f7SAndroid Build Coastguard Worker     return;
2828*03ce13f7SAndroid Build Coastguard Worker   }
2829*03ce13f7SAndroid Build Coastguard Worker   case InstArithmetic::Mul: {
2830*03ce13f7SAndroid Build Coastguard Worker     _mul(T, Src0R, Src1R);
2831*03ce13f7SAndroid Build Coastguard Worker     _mov(Dest, T);
2832*03ce13f7SAndroid Build Coastguard Worker     return;
2833*03ce13f7SAndroid Build Coastguard Worker   }
2834*03ce13f7SAndroid Build Coastguard Worker   case InstArithmetic::Shl: {
2835*03ce13f7SAndroid Build Coastguard Worker     if (IsSrc1Imm16) {
2836*03ce13f7SAndroid Build Coastguard Worker       _sll(T, Src0R, Value);
2837*03ce13f7SAndroid Build Coastguard Worker     } else {
2838*03ce13f7SAndroid Build Coastguard Worker       _sllv(T, Src0R, Src1R);
2839*03ce13f7SAndroid Build Coastguard Worker     }
2840*03ce13f7SAndroid Build Coastguard Worker     _mov(Dest, T);
2841*03ce13f7SAndroid Build Coastguard Worker     return;
2842*03ce13f7SAndroid Build Coastguard Worker   }
2843*03ce13f7SAndroid Build Coastguard Worker   case InstArithmetic::Lshr: {
2844*03ce13f7SAndroid Build Coastguard Worker     auto *T0R = Src0R;
2845*03ce13f7SAndroid Build Coastguard Worker     auto *T1R = Src1R;
2846*03ce13f7SAndroid Build Coastguard Worker     if (Dest->getType() != IceType_i32) {
2847*03ce13f7SAndroid Build Coastguard Worker       T0R = makeReg(IceType_i32);
2848*03ce13f7SAndroid Build Coastguard Worker       lowerCast(InstCast::create(Func, InstCast::Zext, T0R, Src0R));
2849*03ce13f7SAndroid Build Coastguard Worker       if (!IsSrc1Imm16) {
2850*03ce13f7SAndroid Build Coastguard Worker         T1R = makeReg(IceType_i32);
2851*03ce13f7SAndroid Build Coastguard Worker         lowerCast(InstCast::create(Func, InstCast::Zext, T1R, Src1R));
2852*03ce13f7SAndroid Build Coastguard Worker       }
2853*03ce13f7SAndroid Build Coastguard Worker     }
2854*03ce13f7SAndroid Build Coastguard Worker     if (IsSrc1Imm16) {
2855*03ce13f7SAndroid Build Coastguard Worker       _srl(T, T0R, Value);
2856*03ce13f7SAndroid Build Coastguard Worker     } else {
2857*03ce13f7SAndroid Build Coastguard Worker       _srlv(T, T0R, T1R);
2858*03ce13f7SAndroid Build Coastguard Worker     }
2859*03ce13f7SAndroid Build Coastguard Worker     _mov(Dest, T);
2860*03ce13f7SAndroid Build Coastguard Worker     return;
2861*03ce13f7SAndroid Build Coastguard Worker   }
2862*03ce13f7SAndroid Build Coastguard Worker   case InstArithmetic::Ashr: {
2863*03ce13f7SAndroid Build Coastguard Worker     auto *T0R = Src0R;
2864*03ce13f7SAndroid Build Coastguard Worker     auto *T1R = Src1R;
2865*03ce13f7SAndroid Build Coastguard Worker     if (Dest->getType() != IceType_i32) {
2866*03ce13f7SAndroid Build Coastguard Worker       T0R = makeReg(IceType_i32);
2867*03ce13f7SAndroid Build Coastguard Worker       lowerCast(InstCast::create(Func, InstCast::Sext, T0R, Src0R));
2868*03ce13f7SAndroid Build Coastguard Worker       if (!IsSrc1Imm16) {
2869*03ce13f7SAndroid Build Coastguard Worker         T1R = makeReg(IceType_i32);
2870*03ce13f7SAndroid Build Coastguard Worker         lowerCast(InstCast::create(Func, InstCast::Sext, T1R, Src1R));
2871*03ce13f7SAndroid Build Coastguard Worker       }
2872*03ce13f7SAndroid Build Coastguard Worker     }
2873*03ce13f7SAndroid Build Coastguard Worker     if (IsSrc1Imm16) {
2874*03ce13f7SAndroid Build Coastguard Worker       _sra(T, T0R, Value);
2875*03ce13f7SAndroid Build Coastguard Worker     } else {
2876*03ce13f7SAndroid Build Coastguard Worker       _srav(T, T0R, T1R);
2877*03ce13f7SAndroid Build Coastguard Worker     }
2878*03ce13f7SAndroid Build Coastguard Worker     _mov(Dest, T);
2879*03ce13f7SAndroid Build Coastguard Worker     return;
2880*03ce13f7SAndroid Build Coastguard Worker   }
2881*03ce13f7SAndroid Build Coastguard Worker   case InstArithmetic::Udiv: {
2882*03ce13f7SAndroid Build Coastguard Worker     auto *T_Zero = I32Reg(RegMIPS32::Reg_ZERO);
2883*03ce13f7SAndroid Build Coastguard Worker     auto *T0R = Src0R;
2884*03ce13f7SAndroid Build Coastguard Worker     auto *T1R = Src1R;
2885*03ce13f7SAndroid Build Coastguard Worker     if (Dest->getType() != IceType_i32) {
2886*03ce13f7SAndroid Build Coastguard Worker       T0R = makeReg(IceType_i32);
2887*03ce13f7SAndroid Build Coastguard Worker       lowerCast(InstCast::create(Func, InstCast::Zext, T0R, Src0R));
2888*03ce13f7SAndroid Build Coastguard Worker       T1R = makeReg(IceType_i32);
2889*03ce13f7SAndroid Build Coastguard Worker       lowerCast(InstCast::create(Func, InstCast::Zext, T1R, Src1R));
2890*03ce13f7SAndroid Build Coastguard Worker     }
2891*03ce13f7SAndroid Build Coastguard Worker     _divu(T_Zero, T0R, T1R);
2892*03ce13f7SAndroid Build Coastguard Worker     _teq(T1R, T_Zero, DivideByZeroTrapCode); // Trap if divide-by-zero
2893*03ce13f7SAndroid Build Coastguard Worker     _mflo(T, T_Zero);
2894*03ce13f7SAndroid Build Coastguard Worker     _mov(Dest, T);
2895*03ce13f7SAndroid Build Coastguard Worker     return;
2896*03ce13f7SAndroid Build Coastguard Worker   }
2897*03ce13f7SAndroid Build Coastguard Worker   case InstArithmetic::Sdiv: {
2898*03ce13f7SAndroid Build Coastguard Worker     auto *T_Zero = I32Reg(RegMIPS32::Reg_ZERO);
2899*03ce13f7SAndroid Build Coastguard Worker     auto *T0R = Src0R;
2900*03ce13f7SAndroid Build Coastguard Worker     auto *T1R = Src1R;
2901*03ce13f7SAndroid Build Coastguard Worker     if (Dest->getType() != IceType_i32) {
2902*03ce13f7SAndroid Build Coastguard Worker       T0R = makeReg(IceType_i32);
2903*03ce13f7SAndroid Build Coastguard Worker       lowerCast(InstCast::create(Func, InstCast::Sext, T0R, Src0R));
2904*03ce13f7SAndroid Build Coastguard Worker       T1R = makeReg(IceType_i32);
2905*03ce13f7SAndroid Build Coastguard Worker       lowerCast(InstCast::create(Func, InstCast::Sext, T1R, Src1R));
2906*03ce13f7SAndroid Build Coastguard Worker     }
2907*03ce13f7SAndroid Build Coastguard Worker     _div(T_Zero, T0R, T1R);
2908*03ce13f7SAndroid Build Coastguard Worker     _teq(T1R, T_Zero, DivideByZeroTrapCode); // Trap if divide-by-zero
2909*03ce13f7SAndroid Build Coastguard Worker     _mflo(T, T_Zero);
2910*03ce13f7SAndroid Build Coastguard Worker     _mov(Dest, T);
2911*03ce13f7SAndroid Build Coastguard Worker     return;
2912*03ce13f7SAndroid Build Coastguard Worker   }
2913*03ce13f7SAndroid Build Coastguard Worker   case InstArithmetic::Urem: {
2914*03ce13f7SAndroid Build Coastguard Worker     auto *T_Zero = I32Reg(RegMIPS32::Reg_ZERO);
2915*03ce13f7SAndroid Build Coastguard Worker     auto *T0R = Src0R;
2916*03ce13f7SAndroid Build Coastguard Worker     auto *T1R = Src1R;
2917*03ce13f7SAndroid Build Coastguard Worker     if (Dest->getType() != IceType_i32) {
2918*03ce13f7SAndroid Build Coastguard Worker       T0R = makeReg(IceType_i32);
2919*03ce13f7SAndroid Build Coastguard Worker       lowerCast(InstCast::create(Func, InstCast::Zext, T0R, Src0R));
2920*03ce13f7SAndroid Build Coastguard Worker       T1R = makeReg(IceType_i32);
2921*03ce13f7SAndroid Build Coastguard Worker       lowerCast(InstCast::create(Func, InstCast::Zext, T1R, Src1R));
2922*03ce13f7SAndroid Build Coastguard Worker     }
2923*03ce13f7SAndroid Build Coastguard Worker     _divu(T_Zero, T0R, T1R);
2924*03ce13f7SAndroid Build Coastguard Worker     _teq(T1R, T_Zero, DivideByZeroTrapCode); // Trap if divide-by-zero
2925*03ce13f7SAndroid Build Coastguard Worker     _mfhi(T, T_Zero);
2926*03ce13f7SAndroid Build Coastguard Worker     _mov(Dest, T);
2927*03ce13f7SAndroid Build Coastguard Worker     return;
2928*03ce13f7SAndroid Build Coastguard Worker   }
2929*03ce13f7SAndroid Build Coastguard Worker   case InstArithmetic::Srem: {
2930*03ce13f7SAndroid Build Coastguard Worker     auto *T_Zero = I32Reg(RegMIPS32::Reg_ZERO);
2931*03ce13f7SAndroid Build Coastguard Worker     auto *T0R = Src0R;
2932*03ce13f7SAndroid Build Coastguard Worker     auto *T1R = Src1R;
2933*03ce13f7SAndroid Build Coastguard Worker     if (Dest->getType() != IceType_i32) {
2934*03ce13f7SAndroid Build Coastguard Worker       T0R = makeReg(IceType_i32);
2935*03ce13f7SAndroid Build Coastguard Worker       lowerCast(InstCast::create(Func, InstCast::Sext, T0R, Src0R));
2936*03ce13f7SAndroid Build Coastguard Worker       T1R = makeReg(IceType_i32);
2937*03ce13f7SAndroid Build Coastguard Worker       lowerCast(InstCast::create(Func, InstCast::Sext, T1R, Src1R));
2938*03ce13f7SAndroid Build Coastguard Worker     }
2939*03ce13f7SAndroid Build Coastguard Worker     _div(T_Zero, T0R, T1R);
2940*03ce13f7SAndroid Build Coastguard Worker     _teq(T1R, T_Zero, DivideByZeroTrapCode); // Trap if divide-by-zero
2941*03ce13f7SAndroid Build Coastguard Worker     _mfhi(T, T_Zero);
2942*03ce13f7SAndroid Build Coastguard Worker     _mov(Dest, T);
2943*03ce13f7SAndroid Build Coastguard Worker     return;
2944*03ce13f7SAndroid Build Coastguard Worker   }
2945*03ce13f7SAndroid Build Coastguard Worker   case InstArithmetic::Fadd: {
2946*03ce13f7SAndroid Build Coastguard Worker     if (DestTy == IceType_f32) {
2947*03ce13f7SAndroid Build Coastguard Worker       _add_s(T, Src0R, Src1R);
2948*03ce13f7SAndroid Build Coastguard Worker       _mov(Dest, T);
2949*03ce13f7SAndroid Build Coastguard Worker       return;
2950*03ce13f7SAndroid Build Coastguard Worker     }
2951*03ce13f7SAndroid Build Coastguard Worker     if (DestTy == IceType_f64) {
2952*03ce13f7SAndroid Build Coastguard Worker       _add_d(T, Src0R, Src1R);
2953*03ce13f7SAndroid Build Coastguard Worker       _mov(Dest, T);
2954*03ce13f7SAndroid Build Coastguard Worker       return;
2955*03ce13f7SAndroid Build Coastguard Worker     }
2956*03ce13f7SAndroid Build Coastguard Worker     break;
2957*03ce13f7SAndroid Build Coastguard Worker   }
2958*03ce13f7SAndroid Build Coastguard Worker   case InstArithmetic::Fsub:
2959*03ce13f7SAndroid Build Coastguard Worker     if (DestTy == IceType_f32) {
2960*03ce13f7SAndroid Build Coastguard Worker       _sub_s(T, Src0R, Src1R);
2961*03ce13f7SAndroid Build Coastguard Worker       _mov(Dest, T);
2962*03ce13f7SAndroid Build Coastguard Worker       return;
2963*03ce13f7SAndroid Build Coastguard Worker     }
2964*03ce13f7SAndroid Build Coastguard Worker     if (DestTy == IceType_f64) {
2965*03ce13f7SAndroid Build Coastguard Worker       _sub_d(T, Src0R, Src1R);
2966*03ce13f7SAndroid Build Coastguard Worker       _mov(Dest, T);
2967*03ce13f7SAndroid Build Coastguard Worker       return;
2968*03ce13f7SAndroid Build Coastguard Worker     }
2969*03ce13f7SAndroid Build Coastguard Worker     break;
2970*03ce13f7SAndroid Build Coastguard Worker   case InstArithmetic::Fmul:
2971*03ce13f7SAndroid Build Coastguard Worker     if (DestTy == IceType_f32) {
2972*03ce13f7SAndroid Build Coastguard Worker       _mul_s(T, Src0R, Src1R);
2973*03ce13f7SAndroid Build Coastguard Worker       _mov(Dest, T);
2974*03ce13f7SAndroid Build Coastguard Worker       return;
2975*03ce13f7SAndroid Build Coastguard Worker     }
2976*03ce13f7SAndroid Build Coastguard Worker     if (DestTy == IceType_f64) {
2977*03ce13f7SAndroid Build Coastguard Worker       _mul_d(T, Src0R, Src1R);
2978*03ce13f7SAndroid Build Coastguard Worker       _mov(Dest, T);
2979*03ce13f7SAndroid Build Coastguard Worker       return;
2980*03ce13f7SAndroid Build Coastguard Worker     }
2981*03ce13f7SAndroid Build Coastguard Worker     break;
2982*03ce13f7SAndroid Build Coastguard Worker   case InstArithmetic::Fdiv:
2983*03ce13f7SAndroid Build Coastguard Worker     if (DestTy == IceType_f32) {
2984*03ce13f7SAndroid Build Coastguard Worker       _div_s(T, Src0R, Src1R);
2985*03ce13f7SAndroid Build Coastguard Worker       _mov(Dest, T);
2986*03ce13f7SAndroid Build Coastguard Worker       return;
2987*03ce13f7SAndroid Build Coastguard Worker     }
2988*03ce13f7SAndroid Build Coastguard Worker     if (DestTy == IceType_f64) {
2989*03ce13f7SAndroid Build Coastguard Worker       _div_d(T, Src0R, Src1R);
2990*03ce13f7SAndroid Build Coastguard Worker       _mov(Dest, T);
2991*03ce13f7SAndroid Build Coastguard Worker       return;
2992*03ce13f7SAndroid Build Coastguard Worker     }
2993*03ce13f7SAndroid Build Coastguard Worker     break;
2994*03ce13f7SAndroid Build Coastguard Worker   case InstArithmetic::Frem:
2995*03ce13f7SAndroid Build Coastguard Worker     llvm::report_fatal_error("frem should have been prelowered.");
2996*03ce13f7SAndroid Build Coastguard Worker     break;
2997*03ce13f7SAndroid Build Coastguard Worker   }
2998*03ce13f7SAndroid Build Coastguard Worker   llvm::report_fatal_error("Unknown arithmetic operator");
2999*03ce13f7SAndroid Build Coastguard Worker }
3000*03ce13f7SAndroid Build Coastguard Worker 
lowerAssign(const InstAssign * Instr)3001*03ce13f7SAndroid Build Coastguard Worker void TargetMIPS32::lowerAssign(const InstAssign *Instr) {
3002*03ce13f7SAndroid Build Coastguard Worker   Variable *Dest = Instr->getDest();
3003*03ce13f7SAndroid Build Coastguard Worker 
3004*03ce13f7SAndroid Build Coastguard Worker   if (Dest->isRematerializable()) {
3005*03ce13f7SAndroid Build Coastguard Worker     Context.insert<InstFakeDef>(Dest);
3006*03ce13f7SAndroid Build Coastguard Worker     return;
3007*03ce13f7SAndroid Build Coastguard Worker   }
3008*03ce13f7SAndroid Build Coastguard Worker 
3009*03ce13f7SAndroid Build Coastguard Worker   // Source type may not be same as destination
3010*03ce13f7SAndroid Build Coastguard Worker   if (isVectorType(Dest->getType())) {
3011*03ce13f7SAndroid Build Coastguard Worker     Operand *Src0 = legalizeUndef(Instr->getSrc(0));
3012*03ce13f7SAndroid Build Coastguard Worker     auto *DstVec = llvm::dyn_cast<VariableVecOn32>(Dest);
3013*03ce13f7SAndroid Build Coastguard Worker     for (SizeT i = 0; i < DstVec->ContainersPerVector; ++i) {
3014*03ce13f7SAndroid Build Coastguard Worker       auto *DCont = DstVec->getContainers()[i];
3015*03ce13f7SAndroid Build Coastguard Worker       auto *SCont =
3016*03ce13f7SAndroid Build Coastguard Worker           legalize(getOperandAtIndex(Src0, IceType_i32, i), Legal_Reg);
3017*03ce13f7SAndroid Build Coastguard Worker       auto *TReg = makeReg(IceType_i32);
3018*03ce13f7SAndroid Build Coastguard Worker       _mov(TReg, SCont);
3019*03ce13f7SAndroid Build Coastguard Worker       _mov(DCont, TReg);
3020*03ce13f7SAndroid Build Coastguard Worker     }
3021*03ce13f7SAndroid Build Coastguard Worker     return;
3022*03ce13f7SAndroid Build Coastguard Worker   }
3023*03ce13f7SAndroid Build Coastguard Worker   Operand *Src0 = Instr->getSrc(0);
3024*03ce13f7SAndroid Build Coastguard Worker   assert(Dest->getType() == Src0->getType());
3025*03ce13f7SAndroid Build Coastguard Worker   if (Dest->getType() == IceType_i64) {
3026*03ce13f7SAndroid Build Coastguard Worker     Src0 = legalizeUndef(Src0);
3027*03ce13f7SAndroid Build Coastguard Worker     Operand *Src0Lo = legalize(loOperand(Src0), Legal_Reg);
3028*03ce13f7SAndroid Build Coastguard Worker     Operand *Src0Hi = legalize(hiOperand(Src0), Legal_Reg);
3029*03ce13f7SAndroid Build Coastguard Worker     auto *DestLo = llvm::cast<Variable>(loOperand(Dest));
3030*03ce13f7SAndroid Build Coastguard Worker     auto *DestHi = llvm::cast<Variable>(hiOperand(Dest));
3031*03ce13f7SAndroid Build Coastguard Worker     auto *T_Lo = I32Reg(), *T_Hi = I32Reg();
3032*03ce13f7SAndroid Build Coastguard Worker     _mov(T_Lo, Src0Lo);
3033*03ce13f7SAndroid Build Coastguard Worker     _mov(DestLo, T_Lo);
3034*03ce13f7SAndroid Build Coastguard Worker     _mov(T_Hi, Src0Hi);
3035*03ce13f7SAndroid Build Coastguard Worker     _mov(DestHi, T_Hi);
3036*03ce13f7SAndroid Build Coastguard Worker     return;
3037*03ce13f7SAndroid Build Coastguard Worker   }
3038*03ce13f7SAndroid Build Coastguard Worker   Operand *SrcR;
3039*03ce13f7SAndroid Build Coastguard Worker   if (Dest->hasReg()) {
3040*03ce13f7SAndroid Build Coastguard Worker     // If Dest already has a physical register, then legalize the Src operand
3041*03ce13f7SAndroid Build Coastguard Worker     // into a Variable with the same register assignment.  This especially
3042*03ce13f7SAndroid Build Coastguard Worker     // helps allow the use of Flex operands.
3043*03ce13f7SAndroid Build Coastguard Worker     SrcR = legalize(Src0, Legal_Reg, Dest->getRegNum());
3044*03ce13f7SAndroid Build Coastguard Worker   } else {
3045*03ce13f7SAndroid Build Coastguard Worker     // Dest could be a stack operand. Since we could potentially need
3046*03ce13f7SAndroid Build Coastguard Worker     // to do a Store (and store can only have Register operands),
3047*03ce13f7SAndroid Build Coastguard Worker     // legalize this to a register.
3048*03ce13f7SAndroid Build Coastguard Worker     SrcR = legalize(Src0, Legal_Reg);
3049*03ce13f7SAndroid Build Coastguard Worker   }
3050*03ce13f7SAndroid Build Coastguard Worker   _mov(Dest, SrcR);
3051*03ce13f7SAndroid Build Coastguard Worker }
3052*03ce13f7SAndroid Build Coastguard Worker 
lowerBr(const InstBr * Instr)3053*03ce13f7SAndroid Build Coastguard Worker void TargetMIPS32::lowerBr(const InstBr *Instr) {
3054*03ce13f7SAndroid Build Coastguard Worker   if (Instr->isUnconditional()) {
3055*03ce13f7SAndroid Build Coastguard Worker     _br(Instr->getTargetUnconditional());
3056*03ce13f7SAndroid Build Coastguard Worker     return;
3057*03ce13f7SAndroid Build Coastguard Worker   }
3058*03ce13f7SAndroid Build Coastguard Worker   CfgNode *TargetTrue = Instr->getTargetTrue();
3059*03ce13f7SAndroid Build Coastguard Worker   CfgNode *TargetFalse = Instr->getTargetFalse();
3060*03ce13f7SAndroid Build Coastguard Worker   Operand *Boolean = Instr->getCondition();
3061*03ce13f7SAndroid Build Coastguard Worker   const Inst *Producer = Computations.getProducerOf(Boolean);
3062*03ce13f7SAndroid Build Coastguard Worker   if (Producer == nullptr) {
3063*03ce13f7SAndroid Build Coastguard Worker     // Since we don't know the producer of this boolean we will assume its
3064*03ce13f7SAndroid Build Coastguard Worker     // producer will keep it in positive logic and just emit beqz with this
3065*03ce13f7SAndroid Build Coastguard Worker     // Boolean as an operand.
3066*03ce13f7SAndroid Build Coastguard Worker     auto *BooleanR = legalizeToReg(Boolean);
3067*03ce13f7SAndroid Build Coastguard Worker     _br(TargetTrue, TargetFalse, BooleanR, CondMIPS32::Cond::EQZ);
3068*03ce13f7SAndroid Build Coastguard Worker     return;
3069*03ce13f7SAndroid Build Coastguard Worker   }
3070*03ce13f7SAndroid Build Coastguard Worker   if (Producer->getKind() == Inst::Icmp) {
3071*03ce13f7SAndroid Build Coastguard Worker     const InstIcmp *CompareInst = llvm::cast<InstIcmp>(Producer);
3072*03ce13f7SAndroid Build Coastguard Worker     Operand *Src0 = CompareInst->getSrc(0);
3073*03ce13f7SAndroid Build Coastguard Worker     Operand *Src1 = CompareInst->getSrc(1);
3074*03ce13f7SAndroid Build Coastguard Worker     const Type Src0Ty = Src0->getType();
3075*03ce13f7SAndroid Build Coastguard Worker     assert(Src0Ty == Src1->getType());
3076*03ce13f7SAndroid Build Coastguard Worker 
3077*03ce13f7SAndroid Build Coastguard Worker     Variable *Src0R = nullptr;
3078*03ce13f7SAndroid Build Coastguard Worker     Variable *Src1R = nullptr;
3079*03ce13f7SAndroid Build Coastguard Worker     Variable *Src0HiR = nullptr;
3080*03ce13f7SAndroid Build Coastguard Worker     Variable *Src1HiR = nullptr;
3081*03ce13f7SAndroid Build Coastguard Worker     if (Src0Ty == IceType_i64) {
3082*03ce13f7SAndroid Build Coastguard Worker       Src0R = legalizeToReg(loOperand(Src0));
3083*03ce13f7SAndroid Build Coastguard Worker       Src1R = legalizeToReg(loOperand(Src1));
3084*03ce13f7SAndroid Build Coastguard Worker       Src0HiR = legalizeToReg(hiOperand(Src0));
3085*03ce13f7SAndroid Build Coastguard Worker       Src1HiR = legalizeToReg(hiOperand(Src1));
3086*03ce13f7SAndroid Build Coastguard Worker     } else {
3087*03ce13f7SAndroid Build Coastguard Worker       auto *Src0RT = legalizeToReg(Src0);
3088*03ce13f7SAndroid Build Coastguard Worker       auto *Src1RT = legalizeToReg(Src1);
3089*03ce13f7SAndroid Build Coastguard Worker       // Sign/Zero extend the source operands
3090*03ce13f7SAndroid Build Coastguard Worker       if (Src0Ty != IceType_i32) {
3091*03ce13f7SAndroid Build Coastguard Worker         InstCast::OpKind CastKind;
3092*03ce13f7SAndroid Build Coastguard Worker         switch (CompareInst->getCondition()) {
3093*03ce13f7SAndroid Build Coastguard Worker         case InstIcmp::Eq:
3094*03ce13f7SAndroid Build Coastguard Worker         case InstIcmp::Ne:
3095*03ce13f7SAndroid Build Coastguard Worker         case InstIcmp::Sgt:
3096*03ce13f7SAndroid Build Coastguard Worker         case InstIcmp::Sge:
3097*03ce13f7SAndroid Build Coastguard Worker         case InstIcmp::Slt:
3098*03ce13f7SAndroid Build Coastguard Worker         case InstIcmp::Sle:
3099*03ce13f7SAndroid Build Coastguard Worker           CastKind = InstCast::Sext;
3100*03ce13f7SAndroid Build Coastguard Worker           break;
3101*03ce13f7SAndroid Build Coastguard Worker         default:
3102*03ce13f7SAndroid Build Coastguard Worker           CastKind = InstCast::Zext;
3103*03ce13f7SAndroid Build Coastguard Worker           break;
3104*03ce13f7SAndroid Build Coastguard Worker         }
3105*03ce13f7SAndroid Build Coastguard Worker         Src0R = makeReg(IceType_i32);
3106*03ce13f7SAndroid Build Coastguard Worker         Src1R = makeReg(IceType_i32);
3107*03ce13f7SAndroid Build Coastguard Worker         lowerCast(InstCast::create(Func, CastKind, Src0R, Src0RT));
3108*03ce13f7SAndroid Build Coastguard Worker         lowerCast(InstCast::create(Func, CastKind, Src1R, Src1RT));
3109*03ce13f7SAndroid Build Coastguard Worker       } else {
3110*03ce13f7SAndroid Build Coastguard Worker         Src0R = Src0RT;
3111*03ce13f7SAndroid Build Coastguard Worker         Src1R = Src1RT;
3112*03ce13f7SAndroid Build Coastguard Worker       }
3113*03ce13f7SAndroid Build Coastguard Worker     }
3114*03ce13f7SAndroid Build Coastguard Worker     auto *DestT = makeReg(IceType_i32);
3115*03ce13f7SAndroid Build Coastguard Worker 
3116*03ce13f7SAndroid Build Coastguard Worker     switch (CompareInst->getCondition()) {
3117*03ce13f7SAndroid Build Coastguard Worker     default:
3118*03ce13f7SAndroid Build Coastguard Worker       llvm_unreachable("unexpected condition");
3119*03ce13f7SAndroid Build Coastguard Worker       return;
3120*03ce13f7SAndroid Build Coastguard Worker     case InstIcmp::Eq: {
3121*03ce13f7SAndroid Build Coastguard Worker       if (Src0Ty == IceType_i64) {
3122*03ce13f7SAndroid Build Coastguard Worker         auto *T1 = I32Reg();
3123*03ce13f7SAndroid Build Coastguard Worker         auto *T2 = I32Reg();
3124*03ce13f7SAndroid Build Coastguard Worker         auto *T3 = I32Reg();
3125*03ce13f7SAndroid Build Coastguard Worker         _xor(T1, Src0HiR, Src1HiR);
3126*03ce13f7SAndroid Build Coastguard Worker         _xor(T2, Src0R, Src1R);
3127*03ce13f7SAndroid Build Coastguard Worker         _or(T3, T1, T2);
3128*03ce13f7SAndroid Build Coastguard Worker         _mov(DestT, T3);
3129*03ce13f7SAndroid Build Coastguard Worker         _br(TargetTrue, TargetFalse, DestT, CondMIPS32::Cond::NEZ);
3130*03ce13f7SAndroid Build Coastguard Worker       } else {
3131*03ce13f7SAndroid Build Coastguard Worker         _br(TargetTrue, TargetFalse, Src0R, Src1R, CondMIPS32::Cond::NE);
3132*03ce13f7SAndroid Build Coastguard Worker       }
3133*03ce13f7SAndroid Build Coastguard Worker       return;
3134*03ce13f7SAndroid Build Coastguard Worker     }
3135*03ce13f7SAndroid Build Coastguard Worker     case InstIcmp::Ne: {
3136*03ce13f7SAndroid Build Coastguard Worker       if (Src0Ty == IceType_i64) {
3137*03ce13f7SAndroid Build Coastguard Worker         auto *T1 = I32Reg();
3138*03ce13f7SAndroid Build Coastguard Worker         auto *T2 = I32Reg();
3139*03ce13f7SAndroid Build Coastguard Worker         auto *T3 = I32Reg();
3140*03ce13f7SAndroid Build Coastguard Worker         _xor(T1, Src0HiR, Src1HiR);
3141*03ce13f7SAndroid Build Coastguard Worker         _xor(T2, Src0R, Src1R);
3142*03ce13f7SAndroid Build Coastguard Worker         _or(T3, T1, T2);
3143*03ce13f7SAndroid Build Coastguard Worker         _mov(DestT, T3);
3144*03ce13f7SAndroid Build Coastguard Worker         _br(TargetTrue, TargetFalse, DestT, CondMIPS32::Cond::EQZ);
3145*03ce13f7SAndroid Build Coastguard Worker       } else {
3146*03ce13f7SAndroid Build Coastguard Worker         _br(TargetTrue, TargetFalse, Src0R, Src1R, CondMIPS32::Cond::EQ);
3147*03ce13f7SAndroid Build Coastguard Worker       }
3148*03ce13f7SAndroid Build Coastguard Worker       return;
3149*03ce13f7SAndroid Build Coastguard Worker     }
3150*03ce13f7SAndroid Build Coastguard Worker     case InstIcmp::Ugt: {
3151*03ce13f7SAndroid Build Coastguard Worker       if (Src0Ty == IceType_i64) {
3152*03ce13f7SAndroid Build Coastguard Worker         auto *T1 = I32Reg();
3153*03ce13f7SAndroid Build Coastguard Worker         auto *T2 = I32Reg();
3154*03ce13f7SAndroid Build Coastguard Worker         auto *T3 = I32Reg();
3155*03ce13f7SAndroid Build Coastguard Worker         auto *T4 = I32Reg();
3156*03ce13f7SAndroid Build Coastguard Worker         auto *T5 = I32Reg();
3157*03ce13f7SAndroid Build Coastguard Worker         _xor(T1, Src0HiR, Src1HiR);
3158*03ce13f7SAndroid Build Coastguard Worker         _sltu(T2, Src1HiR, Src0HiR);
3159*03ce13f7SAndroid Build Coastguard Worker         _xori(T3, T2, 1);
3160*03ce13f7SAndroid Build Coastguard Worker         _sltu(T4, Src1R, Src0R);
3161*03ce13f7SAndroid Build Coastguard Worker         _xori(T5, T4, 1);
3162*03ce13f7SAndroid Build Coastguard Worker         _movz(T3, T5, T1);
3163*03ce13f7SAndroid Build Coastguard Worker         _mov(DestT, T3);
3164*03ce13f7SAndroid Build Coastguard Worker         _br(TargetTrue, TargetFalse, DestT, CondMIPS32::Cond::NEZ);
3165*03ce13f7SAndroid Build Coastguard Worker       } else {
3166*03ce13f7SAndroid Build Coastguard Worker         _sltu(DestT, Src1R, Src0R);
3167*03ce13f7SAndroid Build Coastguard Worker         _br(TargetTrue, TargetFalse, DestT, CondMIPS32::Cond::EQZ);
3168*03ce13f7SAndroid Build Coastguard Worker       }
3169*03ce13f7SAndroid Build Coastguard Worker       return;
3170*03ce13f7SAndroid Build Coastguard Worker     }
3171*03ce13f7SAndroid Build Coastguard Worker     case InstIcmp::Uge: {
3172*03ce13f7SAndroid Build Coastguard Worker       if (Src0Ty == IceType_i64) {
3173*03ce13f7SAndroid Build Coastguard Worker         auto *T1 = I32Reg();
3174*03ce13f7SAndroid Build Coastguard Worker         auto *T2 = I32Reg();
3175*03ce13f7SAndroid Build Coastguard Worker         auto *T3 = I32Reg();
3176*03ce13f7SAndroid Build Coastguard Worker         _xor(T1, Src0HiR, Src1HiR);
3177*03ce13f7SAndroid Build Coastguard Worker         _sltu(T2, Src0HiR, Src1HiR);
3178*03ce13f7SAndroid Build Coastguard Worker         _sltu(T3, Src0R, Src1R);
3179*03ce13f7SAndroid Build Coastguard Worker         _movz(T2, T3, T1);
3180*03ce13f7SAndroid Build Coastguard Worker         _mov(DestT, T2);
3181*03ce13f7SAndroid Build Coastguard Worker         _br(TargetTrue, TargetFalse, DestT, CondMIPS32::Cond::NEZ);
3182*03ce13f7SAndroid Build Coastguard Worker       } else {
3183*03ce13f7SAndroid Build Coastguard Worker         _sltu(DestT, Src0R, Src1R);
3184*03ce13f7SAndroid Build Coastguard Worker         _br(TargetTrue, TargetFalse, DestT, CondMIPS32::Cond::NEZ);
3185*03ce13f7SAndroid Build Coastguard Worker       }
3186*03ce13f7SAndroid Build Coastguard Worker       return;
3187*03ce13f7SAndroid Build Coastguard Worker     }
3188*03ce13f7SAndroid Build Coastguard Worker     case InstIcmp::Ult: {
3189*03ce13f7SAndroid Build Coastguard Worker       if (Src0Ty == IceType_i64) {
3190*03ce13f7SAndroid Build Coastguard Worker         auto *T1 = I32Reg();
3191*03ce13f7SAndroid Build Coastguard Worker         auto *T2 = I32Reg();
3192*03ce13f7SAndroid Build Coastguard Worker         auto *T3 = I32Reg();
3193*03ce13f7SAndroid Build Coastguard Worker         auto *T4 = I32Reg();
3194*03ce13f7SAndroid Build Coastguard Worker         auto *T5 = I32Reg();
3195*03ce13f7SAndroid Build Coastguard Worker         _xor(T1, Src0HiR, Src1HiR);
3196*03ce13f7SAndroid Build Coastguard Worker         _sltu(T2, Src0HiR, Src1HiR);
3197*03ce13f7SAndroid Build Coastguard Worker         _xori(T3, T2, 1);
3198*03ce13f7SAndroid Build Coastguard Worker         _sltu(T4, Src0R, Src1R);
3199*03ce13f7SAndroid Build Coastguard Worker         _xori(T5, T4, 1);
3200*03ce13f7SAndroid Build Coastguard Worker         _movz(T3, T5, T1);
3201*03ce13f7SAndroid Build Coastguard Worker         _mov(DestT, T3);
3202*03ce13f7SAndroid Build Coastguard Worker         _br(TargetTrue, TargetFalse, DestT, CondMIPS32::Cond::NEZ);
3203*03ce13f7SAndroid Build Coastguard Worker       } else {
3204*03ce13f7SAndroid Build Coastguard Worker         _sltu(DestT, Src0R, Src1R);
3205*03ce13f7SAndroid Build Coastguard Worker         _br(TargetTrue, TargetFalse, DestT, CondMIPS32::Cond::EQZ);
3206*03ce13f7SAndroid Build Coastguard Worker       }
3207*03ce13f7SAndroid Build Coastguard Worker       return;
3208*03ce13f7SAndroid Build Coastguard Worker     }
3209*03ce13f7SAndroid Build Coastguard Worker     case InstIcmp::Ule: {
3210*03ce13f7SAndroid Build Coastguard Worker       if (Src0Ty == IceType_i64) {
3211*03ce13f7SAndroid Build Coastguard Worker         auto *T1 = I32Reg();
3212*03ce13f7SAndroid Build Coastguard Worker         auto *T2 = I32Reg();
3213*03ce13f7SAndroid Build Coastguard Worker         auto *T3 = I32Reg();
3214*03ce13f7SAndroid Build Coastguard Worker         _xor(T1, Src0HiR, Src1HiR);
3215*03ce13f7SAndroid Build Coastguard Worker         _sltu(T2, Src1HiR, Src0HiR);
3216*03ce13f7SAndroid Build Coastguard Worker         _sltu(T3, Src1R, Src0R);
3217*03ce13f7SAndroid Build Coastguard Worker         _movz(T2, T3, T1);
3218*03ce13f7SAndroid Build Coastguard Worker         _mov(DestT, T2);
3219*03ce13f7SAndroid Build Coastguard Worker         _br(TargetTrue, TargetFalse, DestT, CondMIPS32::Cond::NEZ);
3220*03ce13f7SAndroid Build Coastguard Worker       } else {
3221*03ce13f7SAndroid Build Coastguard Worker         _sltu(DestT, Src1R, Src0R);
3222*03ce13f7SAndroid Build Coastguard Worker         _br(TargetTrue, TargetFalse, DestT, CondMIPS32::Cond::NEZ);
3223*03ce13f7SAndroid Build Coastguard Worker       }
3224*03ce13f7SAndroid Build Coastguard Worker       return;
3225*03ce13f7SAndroid Build Coastguard Worker     }
3226*03ce13f7SAndroid Build Coastguard Worker     case InstIcmp::Sgt: {
3227*03ce13f7SAndroid Build Coastguard Worker       if (Src0Ty == IceType_i64) {
3228*03ce13f7SAndroid Build Coastguard Worker         auto *T1 = I32Reg();
3229*03ce13f7SAndroid Build Coastguard Worker         auto *T2 = I32Reg();
3230*03ce13f7SAndroid Build Coastguard Worker         auto *T3 = I32Reg();
3231*03ce13f7SAndroid Build Coastguard Worker         auto *T4 = I32Reg();
3232*03ce13f7SAndroid Build Coastguard Worker         auto *T5 = I32Reg();
3233*03ce13f7SAndroid Build Coastguard Worker         _xor(T1, Src0HiR, Src1HiR);
3234*03ce13f7SAndroid Build Coastguard Worker         _slt(T2, Src1HiR, Src0HiR);
3235*03ce13f7SAndroid Build Coastguard Worker         _xori(T3, T2, 1);
3236*03ce13f7SAndroid Build Coastguard Worker         _sltu(T4, Src1R, Src0R);
3237*03ce13f7SAndroid Build Coastguard Worker         _xori(T5, T4, 1);
3238*03ce13f7SAndroid Build Coastguard Worker         _movz(T3, T5, T1);
3239*03ce13f7SAndroid Build Coastguard Worker         _mov(DestT, T3);
3240*03ce13f7SAndroid Build Coastguard Worker         _br(TargetTrue, TargetFalse, DestT, CondMIPS32::Cond::NEZ);
3241*03ce13f7SAndroid Build Coastguard Worker       } else {
3242*03ce13f7SAndroid Build Coastguard Worker         _slt(DestT, Src1R, Src0R);
3243*03ce13f7SAndroid Build Coastguard Worker         _br(TargetTrue, TargetFalse, DestT, CondMIPS32::Cond::EQZ);
3244*03ce13f7SAndroid Build Coastguard Worker       }
3245*03ce13f7SAndroid Build Coastguard Worker       return;
3246*03ce13f7SAndroid Build Coastguard Worker     }
3247*03ce13f7SAndroid Build Coastguard Worker     case InstIcmp::Sge: {
3248*03ce13f7SAndroid Build Coastguard Worker       if (Src0Ty == IceType_i64) {
3249*03ce13f7SAndroid Build Coastguard Worker         auto *T1 = I32Reg();
3250*03ce13f7SAndroid Build Coastguard Worker         auto *T2 = I32Reg();
3251*03ce13f7SAndroid Build Coastguard Worker         auto *T3 = I32Reg();
3252*03ce13f7SAndroid Build Coastguard Worker         _xor(T1, Src0HiR, Src1HiR);
3253*03ce13f7SAndroid Build Coastguard Worker         _slt(T2, Src0HiR, Src1HiR);
3254*03ce13f7SAndroid Build Coastguard Worker         _sltu(T3, Src0R, Src1R);
3255*03ce13f7SAndroid Build Coastguard Worker         _movz(T2, T3, T1);
3256*03ce13f7SAndroid Build Coastguard Worker         _mov(DestT, T2);
3257*03ce13f7SAndroid Build Coastguard Worker         _br(TargetTrue, TargetFalse, DestT, CondMIPS32::Cond::NEZ);
3258*03ce13f7SAndroid Build Coastguard Worker       } else {
3259*03ce13f7SAndroid Build Coastguard Worker         _slt(DestT, Src0R, Src1R);
3260*03ce13f7SAndroid Build Coastguard Worker         _br(TargetTrue, TargetFalse, DestT, CondMIPS32::Cond::NEZ);
3261*03ce13f7SAndroid Build Coastguard Worker       }
3262*03ce13f7SAndroid Build Coastguard Worker       return;
3263*03ce13f7SAndroid Build Coastguard Worker     }
3264*03ce13f7SAndroid Build Coastguard Worker     case InstIcmp::Slt: {
3265*03ce13f7SAndroid Build Coastguard Worker       if (Src0Ty == IceType_i64) {
3266*03ce13f7SAndroid Build Coastguard Worker         auto *T1 = I32Reg();
3267*03ce13f7SAndroid Build Coastguard Worker         auto *T2 = I32Reg();
3268*03ce13f7SAndroid Build Coastguard Worker         auto *T3 = I32Reg();
3269*03ce13f7SAndroid Build Coastguard Worker         auto *T4 = I32Reg();
3270*03ce13f7SAndroid Build Coastguard Worker         auto *T5 = I32Reg();
3271*03ce13f7SAndroid Build Coastguard Worker         _xor(T1, Src0HiR, Src1HiR);
3272*03ce13f7SAndroid Build Coastguard Worker         _slt(T2, Src0HiR, Src1HiR);
3273*03ce13f7SAndroid Build Coastguard Worker         _xori(T3, T2, 1);
3274*03ce13f7SAndroid Build Coastguard Worker         _sltu(T4, Src0R, Src1R);
3275*03ce13f7SAndroid Build Coastguard Worker         _xori(T5, T4, 1);
3276*03ce13f7SAndroid Build Coastguard Worker         _movz(T3, T5, T1);
3277*03ce13f7SAndroid Build Coastguard Worker         _mov(DestT, T3);
3278*03ce13f7SAndroid Build Coastguard Worker         _br(TargetTrue, TargetFalse, DestT, CondMIPS32::Cond::NEZ);
3279*03ce13f7SAndroid Build Coastguard Worker       } else {
3280*03ce13f7SAndroid Build Coastguard Worker         _slt(DestT, Src0R, Src1R);
3281*03ce13f7SAndroid Build Coastguard Worker         _br(TargetTrue, TargetFalse, DestT, CondMIPS32::Cond::EQZ);
3282*03ce13f7SAndroid Build Coastguard Worker       }
3283*03ce13f7SAndroid Build Coastguard Worker       return;
3284*03ce13f7SAndroid Build Coastguard Worker     }
3285*03ce13f7SAndroid Build Coastguard Worker     case InstIcmp::Sle: {
3286*03ce13f7SAndroid Build Coastguard Worker       if (Src0Ty == IceType_i64) {
3287*03ce13f7SAndroid Build Coastguard Worker         auto *T1 = I32Reg();
3288*03ce13f7SAndroid Build Coastguard Worker         auto *T2 = I32Reg();
3289*03ce13f7SAndroid Build Coastguard Worker         auto *T3 = I32Reg();
3290*03ce13f7SAndroid Build Coastguard Worker         _xor(T1, Src0HiR, Src1HiR);
3291*03ce13f7SAndroid Build Coastguard Worker         _slt(T2, Src1HiR, Src0HiR);
3292*03ce13f7SAndroid Build Coastguard Worker         _sltu(T3, Src1R, Src0R);
3293*03ce13f7SAndroid Build Coastguard Worker         _movz(T2, T3, T1);
3294*03ce13f7SAndroid Build Coastguard Worker         _mov(DestT, T2);
3295*03ce13f7SAndroid Build Coastguard Worker         _br(TargetTrue, TargetFalse, DestT, CondMIPS32::Cond::NEZ);
3296*03ce13f7SAndroid Build Coastguard Worker       } else {
3297*03ce13f7SAndroid Build Coastguard Worker         _slt(DestT, Src1R, Src0R);
3298*03ce13f7SAndroid Build Coastguard Worker         _br(TargetTrue, TargetFalse, DestT, CondMIPS32::Cond::NEZ);
3299*03ce13f7SAndroid Build Coastguard Worker       }
3300*03ce13f7SAndroid Build Coastguard Worker       return;
3301*03ce13f7SAndroid Build Coastguard Worker     }
3302*03ce13f7SAndroid Build Coastguard Worker     }
3303*03ce13f7SAndroid Build Coastguard Worker   }
3304*03ce13f7SAndroid Build Coastguard Worker }
3305*03ce13f7SAndroid Build Coastguard Worker 
lowerCall(const InstCall * Instr)3306*03ce13f7SAndroid Build Coastguard Worker void TargetMIPS32::lowerCall(const InstCall *Instr) {
3307*03ce13f7SAndroid Build Coastguard Worker   CfgVector<Variable *> RegArgs;
3308*03ce13f7SAndroid Build Coastguard Worker   NeedsStackAlignment = true;
3309*03ce13f7SAndroid Build Coastguard Worker 
3310*03ce13f7SAndroid Build Coastguard Worker   //  Assign arguments to registers and stack. Also reserve stack.
3311*03ce13f7SAndroid Build Coastguard Worker   TargetMIPS32::CallingConv CC;
3312*03ce13f7SAndroid Build Coastguard Worker 
3313*03ce13f7SAndroid Build Coastguard Worker   // Pair of Arg Operand -> GPR number assignments.
3314*03ce13f7SAndroid Build Coastguard Worker   llvm::SmallVector<std::pair<Operand *, RegNumT>, MIPS32_MAX_GPR_ARG> GPRArgs;
3315*03ce13f7SAndroid Build Coastguard Worker   llvm::SmallVector<std::pair<Operand *, RegNumT>, MIPS32_MAX_FP_ARG> FPArgs;
3316*03ce13f7SAndroid Build Coastguard Worker   // Pair of Arg Operand -> stack offset.
3317*03ce13f7SAndroid Build Coastguard Worker   llvm::SmallVector<std::pair<Operand *, int32_t>, 8> StackArgs;
3318*03ce13f7SAndroid Build Coastguard Worker   size_t ParameterAreaSizeBytes = 16;
3319*03ce13f7SAndroid Build Coastguard Worker 
3320*03ce13f7SAndroid Build Coastguard Worker   // Classify each argument operand according to the location where the
3321*03ce13f7SAndroid Build Coastguard Worker   // argument is passed.
3322*03ce13f7SAndroid Build Coastguard Worker 
3323*03ce13f7SAndroid Build Coastguard Worker   // v4f32 is returned through stack. $4 is setup by the caller and passed as
3324*03ce13f7SAndroid Build Coastguard Worker   // first argument implicitly. Callee then copies the return vector at $4.
3325*03ce13f7SAndroid Build Coastguard Worker   SizeT ArgNum = 0;
3326*03ce13f7SAndroid Build Coastguard Worker   Variable *Dest = Instr->getDest();
3327*03ce13f7SAndroid Build Coastguard Worker   Variable *RetVecFloat = nullptr;
3328*03ce13f7SAndroid Build Coastguard Worker   if (Dest && isVectorFloatingType(Dest->getType())) {
3329*03ce13f7SAndroid Build Coastguard Worker     ArgNum = 1;
3330*03ce13f7SAndroid Build Coastguard Worker     CC.discardReg(RegMIPS32::Reg_A0);
3331*03ce13f7SAndroid Build Coastguard Worker     RetVecFloat = Func->makeVariable(IceType_i32);
3332*03ce13f7SAndroid Build Coastguard Worker     auto *ByteCount = ConstantInteger32::create(Ctx, IceType_i32, 16);
3333*03ce13f7SAndroid Build Coastguard Worker     constexpr SizeT Alignment = 4;
3334*03ce13f7SAndroid Build Coastguard Worker     lowerAlloca(InstAlloca::create(Func, RetVecFloat, ByteCount, Alignment));
3335*03ce13f7SAndroid Build Coastguard Worker     RegArgs.emplace_back(
3336*03ce13f7SAndroid Build Coastguard Worker         legalizeToReg(RetVecFloat, RegNumT::fixme(RegMIPS32::Reg_A0)));
3337*03ce13f7SAndroid Build Coastguard Worker   }
3338*03ce13f7SAndroid Build Coastguard Worker 
3339*03ce13f7SAndroid Build Coastguard Worker   for (SizeT i = 0, NumArgs = Instr->getNumArgs(); i < NumArgs; ++i) {
3340*03ce13f7SAndroid Build Coastguard Worker     Operand *Arg = legalizeUndef(Instr->getArg(i));
3341*03ce13f7SAndroid Build Coastguard Worker     const Type Ty = Arg->getType();
3342*03ce13f7SAndroid Build Coastguard Worker     bool InReg = false;
3343*03ce13f7SAndroid Build Coastguard Worker     RegNumT Reg;
3344*03ce13f7SAndroid Build Coastguard Worker 
3345*03ce13f7SAndroid Build Coastguard Worker     InReg = CC.argInReg(Ty, i, &Reg);
3346*03ce13f7SAndroid Build Coastguard Worker 
3347*03ce13f7SAndroid Build Coastguard Worker     if (!InReg) {
3348*03ce13f7SAndroid Build Coastguard Worker       if (isVectorType(Ty)) {
3349*03ce13f7SAndroid Build Coastguard Worker         auto *ArgVec = llvm::cast<VariableVecOn32>(Arg);
3350*03ce13f7SAndroid Build Coastguard Worker         ParameterAreaSizeBytes =
3351*03ce13f7SAndroid Build Coastguard Worker             applyStackAlignmentTy(ParameterAreaSizeBytes, IceType_i64);
3352*03ce13f7SAndroid Build Coastguard Worker         for (Variable *Elem : ArgVec->getContainers()) {
3353*03ce13f7SAndroid Build Coastguard Worker           StackArgs.push_back(std::make_pair(Elem, ParameterAreaSizeBytes));
3354*03ce13f7SAndroid Build Coastguard Worker           ParameterAreaSizeBytes += typeWidthInBytesOnStack(IceType_i32);
3355*03ce13f7SAndroid Build Coastguard Worker         }
3356*03ce13f7SAndroid Build Coastguard Worker       } else {
3357*03ce13f7SAndroid Build Coastguard Worker         ParameterAreaSizeBytes =
3358*03ce13f7SAndroid Build Coastguard Worker             applyStackAlignmentTy(ParameterAreaSizeBytes, Ty);
3359*03ce13f7SAndroid Build Coastguard Worker         StackArgs.push_back(std::make_pair(Arg, ParameterAreaSizeBytes));
3360*03ce13f7SAndroid Build Coastguard Worker         ParameterAreaSizeBytes += typeWidthInBytesOnStack(Ty);
3361*03ce13f7SAndroid Build Coastguard Worker       }
3362*03ce13f7SAndroid Build Coastguard Worker       ++ArgNum;
3363*03ce13f7SAndroid Build Coastguard Worker       continue;
3364*03ce13f7SAndroid Build Coastguard Worker     }
3365*03ce13f7SAndroid Build Coastguard Worker 
3366*03ce13f7SAndroid Build Coastguard Worker     if (isVectorType(Ty)) {
3367*03ce13f7SAndroid Build Coastguard Worker       auto *ArgVec = llvm::cast<VariableVecOn32>(Arg);
3368*03ce13f7SAndroid Build Coastguard Worker       Operand *Elem0 = ArgVec->getContainers()[0];
3369*03ce13f7SAndroid Build Coastguard Worker       Operand *Elem1 = ArgVec->getContainers()[1];
3370*03ce13f7SAndroid Build Coastguard Worker       GPRArgs.push_back(
3371*03ce13f7SAndroid Build Coastguard Worker           std::make_pair(Elem0, RegNumT::fixme((unsigned)Reg + 0)));
3372*03ce13f7SAndroid Build Coastguard Worker       GPRArgs.push_back(
3373*03ce13f7SAndroid Build Coastguard Worker           std::make_pair(Elem1, RegNumT::fixme((unsigned)Reg + 1)));
3374*03ce13f7SAndroid Build Coastguard Worker       Operand *Elem2 = ArgVec->getContainers()[2];
3375*03ce13f7SAndroid Build Coastguard Worker       Operand *Elem3 = ArgVec->getContainers()[3];
3376*03ce13f7SAndroid Build Coastguard Worker       // First argument is passed in $4:$5:$6:$7
3377*03ce13f7SAndroid Build Coastguard Worker       // Second and rest arguments are passed in $6:$7:stack:stack
3378*03ce13f7SAndroid Build Coastguard Worker       if (ArgNum == 0) {
3379*03ce13f7SAndroid Build Coastguard Worker         GPRArgs.push_back(
3380*03ce13f7SAndroid Build Coastguard Worker             std::make_pair(Elem2, RegNumT::fixme((unsigned)Reg + 2)));
3381*03ce13f7SAndroid Build Coastguard Worker         GPRArgs.push_back(
3382*03ce13f7SAndroid Build Coastguard Worker             std::make_pair(Elem3, RegNumT::fixme((unsigned)Reg + 3)));
3383*03ce13f7SAndroid Build Coastguard Worker       } else {
3384*03ce13f7SAndroid Build Coastguard Worker         ParameterAreaSizeBytes =
3385*03ce13f7SAndroid Build Coastguard Worker             applyStackAlignmentTy(ParameterAreaSizeBytes, IceType_i64);
3386*03ce13f7SAndroid Build Coastguard Worker         StackArgs.push_back(std::make_pair(Elem2, ParameterAreaSizeBytes));
3387*03ce13f7SAndroid Build Coastguard Worker         ParameterAreaSizeBytes += typeWidthInBytesOnStack(IceType_i32);
3388*03ce13f7SAndroid Build Coastguard Worker         StackArgs.push_back(std::make_pair(Elem3, ParameterAreaSizeBytes));
3389*03ce13f7SAndroid Build Coastguard Worker         ParameterAreaSizeBytes += typeWidthInBytesOnStack(IceType_i32);
3390*03ce13f7SAndroid Build Coastguard Worker       }
3391*03ce13f7SAndroid Build Coastguard Worker     } else if (Ty == IceType_i64) {
3392*03ce13f7SAndroid Build Coastguard Worker       Operand *Lo = loOperand(Arg);
3393*03ce13f7SAndroid Build Coastguard Worker       Operand *Hi = hiOperand(Arg);
3394*03ce13f7SAndroid Build Coastguard Worker       GPRArgs.push_back(
3395*03ce13f7SAndroid Build Coastguard Worker           std::make_pair(Lo, RegMIPS32::get64PairFirstRegNum(Reg)));
3396*03ce13f7SAndroid Build Coastguard Worker       GPRArgs.push_back(
3397*03ce13f7SAndroid Build Coastguard Worker           std::make_pair(Hi, RegMIPS32::get64PairSecondRegNum(Reg)));
3398*03ce13f7SAndroid Build Coastguard Worker     } else if (isScalarIntegerType(Ty)) {
3399*03ce13f7SAndroid Build Coastguard Worker       GPRArgs.push_back(std::make_pair(Arg, Reg));
3400*03ce13f7SAndroid Build Coastguard Worker     } else {
3401*03ce13f7SAndroid Build Coastguard Worker       FPArgs.push_back(std::make_pair(Arg, Reg));
3402*03ce13f7SAndroid Build Coastguard Worker     }
3403*03ce13f7SAndroid Build Coastguard Worker     ++ArgNum;
3404*03ce13f7SAndroid Build Coastguard Worker   }
3405*03ce13f7SAndroid Build Coastguard Worker 
3406*03ce13f7SAndroid Build Coastguard Worker   // Adjust the parameter area so that the stack is aligned. It is assumed that
3407*03ce13f7SAndroid Build Coastguard Worker   // the stack is already aligned at the start of the calling sequence.
3408*03ce13f7SAndroid Build Coastguard Worker   ParameterAreaSizeBytes = applyStackAlignment(ParameterAreaSizeBytes);
3409*03ce13f7SAndroid Build Coastguard Worker 
3410*03ce13f7SAndroid Build Coastguard Worker   // Copy arguments that are passed on the stack to the appropriate stack
3411*03ce13f7SAndroid Build Coastguard Worker   // locations.
3412*03ce13f7SAndroid Build Coastguard Worker   Variable *SP = getPhysicalRegister(RegMIPS32::Reg_SP);
3413*03ce13f7SAndroid Build Coastguard Worker   for (auto &StackArg : StackArgs) {
3414*03ce13f7SAndroid Build Coastguard Worker     ConstantInteger32 *Loc =
3415*03ce13f7SAndroid Build Coastguard Worker         llvm::cast<ConstantInteger32>(Ctx->getConstantInt32(StackArg.second));
3416*03ce13f7SAndroid Build Coastguard Worker     Type Ty = StackArg.first->getType();
3417*03ce13f7SAndroid Build Coastguard Worker     OperandMIPS32Mem *Addr;
3418*03ce13f7SAndroid Build Coastguard Worker     constexpr bool SignExt = false;
3419*03ce13f7SAndroid Build Coastguard Worker     if (OperandMIPS32Mem::canHoldOffset(Ty, SignExt, StackArg.second)) {
3420*03ce13f7SAndroid Build Coastguard Worker       Addr = OperandMIPS32Mem::create(Func, Ty, SP, Loc);
3421*03ce13f7SAndroid Build Coastguard Worker     } else {
3422*03ce13f7SAndroid Build Coastguard Worker       Variable *NewBase = Func->makeVariable(SP->getType());
3423*03ce13f7SAndroid Build Coastguard Worker       lowerArithmetic(
3424*03ce13f7SAndroid Build Coastguard Worker           InstArithmetic::create(Func, InstArithmetic::Add, NewBase, SP, Loc));
3425*03ce13f7SAndroid Build Coastguard Worker       Addr = formMemoryOperand(NewBase, Ty);
3426*03ce13f7SAndroid Build Coastguard Worker     }
3427*03ce13f7SAndroid Build Coastguard Worker     lowerStore(InstStore::create(Func, StackArg.first, Addr));
3428*03ce13f7SAndroid Build Coastguard Worker   }
3429*03ce13f7SAndroid Build Coastguard Worker 
3430*03ce13f7SAndroid Build Coastguard Worker   // Generate the call instruction.  Assign its result to a temporary with high
3431*03ce13f7SAndroid Build Coastguard Worker   // register allocation weight.
3432*03ce13f7SAndroid Build Coastguard Worker 
3433*03ce13f7SAndroid Build Coastguard Worker   // ReturnReg doubles as ReturnRegLo as necessary.
3434*03ce13f7SAndroid Build Coastguard Worker   Variable *ReturnReg = nullptr;
3435*03ce13f7SAndroid Build Coastguard Worker   Variable *ReturnRegHi = nullptr;
3436*03ce13f7SAndroid Build Coastguard Worker   if (Dest) {
3437*03ce13f7SAndroid Build Coastguard Worker     switch (Dest->getType()) {
3438*03ce13f7SAndroid Build Coastguard Worker     case IceType_NUM:
3439*03ce13f7SAndroid Build Coastguard Worker       llvm_unreachable("Invalid Call dest type");
3440*03ce13f7SAndroid Build Coastguard Worker       return;
3441*03ce13f7SAndroid Build Coastguard Worker     case IceType_void:
3442*03ce13f7SAndroid Build Coastguard Worker       break;
3443*03ce13f7SAndroid Build Coastguard Worker     case IceType_i1:
3444*03ce13f7SAndroid Build Coastguard Worker     case IceType_i8:
3445*03ce13f7SAndroid Build Coastguard Worker     case IceType_i16:
3446*03ce13f7SAndroid Build Coastguard Worker     case IceType_i32:
3447*03ce13f7SAndroid Build Coastguard Worker       ReturnReg = makeReg(Dest->getType(), RegMIPS32::Reg_V0);
3448*03ce13f7SAndroid Build Coastguard Worker       break;
3449*03ce13f7SAndroid Build Coastguard Worker     case IceType_i64:
3450*03ce13f7SAndroid Build Coastguard Worker       ReturnReg = I32Reg(RegMIPS32::Reg_V0);
3451*03ce13f7SAndroid Build Coastguard Worker       ReturnRegHi = I32Reg(RegMIPS32::Reg_V1);
3452*03ce13f7SAndroid Build Coastguard Worker       break;
3453*03ce13f7SAndroid Build Coastguard Worker     case IceType_f32:
3454*03ce13f7SAndroid Build Coastguard Worker       ReturnReg = makeReg(Dest->getType(), RegMIPS32::Reg_F0);
3455*03ce13f7SAndroid Build Coastguard Worker       break;
3456*03ce13f7SAndroid Build Coastguard Worker     case IceType_f64:
3457*03ce13f7SAndroid Build Coastguard Worker       ReturnReg = makeReg(IceType_f64, RegMIPS32::Reg_F0);
3458*03ce13f7SAndroid Build Coastguard Worker       break;
3459*03ce13f7SAndroid Build Coastguard Worker     case IceType_v4i1:
3460*03ce13f7SAndroid Build Coastguard Worker     case IceType_v8i1:
3461*03ce13f7SAndroid Build Coastguard Worker     case IceType_v16i1:
3462*03ce13f7SAndroid Build Coastguard Worker     case IceType_v16i8:
3463*03ce13f7SAndroid Build Coastguard Worker     case IceType_v8i16:
3464*03ce13f7SAndroid Build Coastguard Worker     case IceType_v4i32: {
3465*03ce13f7SAndroid Build Coastguard Worker       ReturnReg = makeReg(Dest->getType(), RegMIPS32::Reg_V0);
3466*03ce13f7SAndroid Build Coastguard Worker       auto *RetVec = llvm::dyn_cast<VariableVecOn32>(ReturnReg);
3467*03ce13f7SAndroid Build Coastguard Worker       RetVec->initVecElement(Func);
3468*03ce13f7SAndroid Build Coastguard Worker       for (SizeT i = 0; i < RetVec->ContainersPerVector; ++i) {
3469*03ce13f7SAndroid Build Coastguard Worker         auto *Var = RetVec->getContainers()[i];
3470*03ce13f7SAndroid Build Coastguard Worker         Var->setRegNum(RegNumT::fixme(RegMIPS32::Reg_V0 + i));
3471*03ce13f7SAndroid Build Coastguard Worker       }
3472*03ce13f7SAndroid Build Coastguard Worker       break;
3473*03ce13f7SAndroid Build Coastguard Worker     }
3474*03ce13f7SAndroid Build Coastguard Worker     case IceType_v4f32:
3475*03ce13f7SAndroid Build Coastguard Worker       ReturnReg = makeReg(IceType_i32, RegMIPS32::Reg_V0);
3476*03ce13f7SAndroid Build Coastguard Worker       break;
3477*03ce13f7SAndroid Build Coastguard Worker     }
3478*03ce13f7SAndroid Build Coastguard Worker   }
3479*03ce13f7SAndroid Build Coastguard Worker   Operand *CallTarget = Instr->getCallTarget();
3480*03ce13f7SAndroid Build Coastguard Worker   // Allow ConstantRelocatable to be left alone as a direct call,
3481*03ce13f7SAndroid Build Coastguard Worker   // but force other constants like ConstantInteger32 to be in
3482*03ce13f7SAndroid Build Coastguard Worker   // a register and make it an indirect call.
3483*03ce13f7SAndroid Build Coastguard Worker   if (!llvm::isa<ConstantRelocatable>(CallTarget)) {
3484*03ce13f7SAndroid Build Coastguard Worker     CallTarget = legalize(CallTarget, Legal_Reg);
3485*03ce13f7SAndroid Build Coastguard Worker   }
3486*03ce13f7SAndroid Build Coastguard Worker 
3487*03ce13f7SAndroid Build Coastguard Worker   // Copy arguments to be passed in registers to the appropriate registers.
3488*03ce13f7SAndroid Build Coastguard Worker   for (auto &FPArg : FPArgs) {
3489*03ce13f7SAndroid Build Coastguard Worker     RegArgs.emplace_back(legalizeToReg(FPArg.first, FPArg.second));
3490*03ce13f7SAndroid Build Coastguard Worker   }
3491*03ce13f7SAndroid Build Coastguard Worker   for (auto &GPRArg : GPRArgs) {
3492*03ce13f7SAndroid Build Coastguard Worker     RegArgs.emplace_back(legalizeToReg(GPRArg.first, GPRArg.second));
3493*03ce13f7SAndroid Build Coastguard Worker   }
3494*03ce13f7SAndroid Build Coastguard Worker 
3495*03ce13f7SAndroid Build Coastguard Worker   // Generate a FakeUse of register arguments so that they do not get dead code
3496*03ce13f7SAndroid Build Coastguard Worker   // eliminated as a result of the FakeKill of scratch registers after the call.
3497*03ce13f7SAndroid Build Coastguard Worker   // These fake-uses need to be placed here to avoid argument registers from
3498*03ce13f7SAndroid Build Coastguard Worker   // being used during the legalizeToReg() calls above.
3499*03ce13f7SAndroid Build Coastguard Worker   for (auto *RegArg : RegArgs) {
3500*03ce13f7SAndroid Build Coastguard Worker     Context.insert<InstFakeUse>(RegArg);
3501*03ce13f7SAndroid Build Coastguard Worker   }
3502*03ce13f7SAndroid Build Coastguard Worker 
3503*03ce13f7SAndroid Build Coastguard Worker   // If variable alloca is used the extra 16 bytes for argument build area
3504*03ce13f7SAndroid Build Coastguard Worker   // will be allocated on stack before a call.
3505*03ce13f7SAndroid Build Coastguard Worker   if (VariableAllocaUsed)
3506*03ce13f7SAndroid Build Coastguard Worker     _addiu(SP, SP, -MaxOutArgsSizeBytes);
3507*03ce13f7SAndroid Build Coastguard Worker 
3508*03ce13f7SAndroid Build Coastguard Worker   Inst *NewCall;
3509*03ce13f7SAndroid Build Coastguard Worker 
3510*03ce13f7SAndroid Build Coastguard Worker   // We don't need to define the return register if it is a vector.
3511*03ce13f7SAndroid Build Coastguard Worker   // We have inserted fake defs of it just after the call.
3512*03ce13f7SAndroid Build Coastguard Worker   if (ReturnReg && isVectorIntegerType(ReturnReg->getType())) {
3513*03ce13f7SAndroid Build Coastguard Worker     Variable *RetReg = nullptr;
3514*03ce13f7SAndroid Build Coastguard Worker     NewCall = InstMIPS32Call::create(Func, RetReg, CallTarget);
3515*03ce13f7SAndroid Build Coastguard Worker     Context.insert(NewCall);
3516*03ce13f7SAndroid Build Coastguard Worker   } else {
3517*03ce13f7SAndroid Build Coastguard Worker     NewCall = Context.insert<InstMIPS32Call>(ReturnReg, CallTarget);
3518*03ce13f7SAndroid Build Coastguard Worker   }
3519*03ce13f7SAndroid Build Coastguard Worker 
3520*03ce13f7SAndroid Build Coastguard Worker   if (VariableAllocaUsed)
3521*03ce13f7SAndroid Build Coastguard Worker     _addiu(SP, SP, MaxOutArgsSizeBytes);
3522*03ce13f7SAndroid Build Coastguard Worker 
3523*03ce13f7SAndroid Build Coastguard Worker   // Insert a fake use of stack pointer to avoid dead code elimination of addiu
3524*03ce13f7SAndroid Build Coastguard Worker   // instruction.
3525*03ce13f7SAndroid Build Coastguard Worker   Context.insert<InstFakeUse>(SP);
3526*03ce13f7SAndroid Build Coastguard Worker 
3527*03ce13f7SAndroid Build Coastguard Worker   if (ReturnRegHi)
3528*03ce13f7SAndroid Build Coastguard Worker     Context.insert(InstFakeDef::create(Func, ReturnRegHi));
3529*03ce13f7SAndroid Build Coastguard Worker 
3530*03ce13f7SAndroid Build Coastguard Worker   if (ReturnReg) {
3531*03ce13f7SAndroid Build Coastguard Worker     if (auto *RetVec = llvm::dyn_cast<VariableVecOn32>(ReturnReg)) {
3532*03ce13f7SAndroid Build Coastguard Worker       for (Variable *Var : RetVec->getContainers()) {
3533*03ce13f7SAndroid Build Coastguard Worker         Context.insert(InstFakeDef::create(Func, Var));
3534*03ce13f7SAndroid Build Coastguard Worker       }
3535*03ce13f7SAndroid Build Coastguard Worker     }
3536*03ce13f7SAndroid Build Coastguard Worker   }
3537*03ce13f7SAndroid Build Coastguard Worker 
3538*03ce13f7SAndroid Build Coastguard Worker   // Insert a register-kill pseudo instruction.
3539*03ce13f7SAndroid Build Coastguard Worker   Context.insert(InstFakeKill::create(Func, NewCall));
3540*03ce13f7SAndroid Build Coastguard Worker 
3541*03ce13f7SAndroid Build Coastguard Worker   // Generate a FakeUse to keep the call live if necessary.
3542*03ce13f7SAndroid Build Coastguard Worker   if (Instr->hasSideEffects() && ReturnReg) {
3543*03ce13f7SAndroid Build Coastguard Worker     if (auto *RetVec = llvm::dyn_cast<VariableVecOn32>(ReturnReg)) {
3544*03ce13f7SAndroid Build Coastguard Worker       for (Variable *Var : RetVec->getContainers()) {
3545*03ce13f7SAndroid Build Coastguard Worker         Context.insert<InstFakeUse>(Var);
3546*03ce13f7SAndroid Build Coastguard Worker       }
3547*03ce13f7SAndroid Build Coastguard Worker     } else {
3548*03ce13f7SAndroid Build Coastguard Worker       Context.insert<InstFakeUse>(ReturnReg);
3549*03ce13f7SAndroid Build Coastguard Worker     }
3550*03ce13f7SAndroid Build Coastguard Worker   }
3551*03ce13f7SAndroid Build Coastguard Worker 
3552*03ce13f7SAndroid Build Coastguard Worker   if (Dest == nullptr)
3553*03ce13f7SAndroid Build Coastguard Worker     return;
3554*03ce13f7SAndroid Build Coastguard Worker 
3555*03ce13f7SAndroid Build Coastguard Worker   // Assign the result of the call to Dest.
3556*03ce13f7SAndroid Build Coastguard Worker   if (ReturnReg) {
3557*03ce13f7SAndroid Build Coastguard Worker     if (RetVecFloat) {
3558*03ce13f7SAndroid Build Coastguard Worker       auto *DestVecOn32 = llvm::cast<VariableVecOn32>(Dest);
3559*03ce13f7SAndroid Build Coastguard Worker       auto *TBase = legalizeToReg(RetVecFloat);
3560*03ce13f7SAndroid Build Coastguard Worker       for (SizeT i = 0; i < DestVecOn32->ContainersPerVector; ++i) {
3561*03ce13f7SAndroid Build Coastguard Worker         auto *Var = DestVecOn32->getContainers()[i];
3562*03ce13f7SAndroid Build Coastguard Worker         auto *TVar = makeReg(IceType_i32);
3563*03ce13f7SAndroid Build Coastguard Worker         OperandMIPS32Mem *Mem = OperandMIPS32Mem::create(
3564*03ce13f7SAndroid Build Coastguard Worker             Func, IceType_i32, TBase,
3565*03ce13f7SAndroid Build Coastguard Worker             llvm::cast<ConstantInteger32>(Ctx->getConstantInt32(i * 4)));
3566*03ce13f7SAndroid Build Coastguard Worker         _lw(TVar, Mem);
3567*03ce13f7SAndroid Build Coastguard Worker         _mov(Var, TVar);
3568*03ce13f7SAndroid Build Coastguard Worker       }
3569*03ce13f7SAndroid Build Coastguard Worker     } else if (auto *RetVec = llvm::dyn_cast<VariableVecOn32>(ReturnReg)) {
3570*03ce13f7SAndroid Build Coastguard Worker       auto *DestVecOn32 = llvm::cast<VariableVecOn32>(Dest);
3571*03ce13f7SAndroid Build Coastguard Worker       for (SizeT i = 0; i < DestVecOn32->ContainersPerVector; ++i) {
3572*03ce13f7SAndroid Build Coastguard Worker         _mov(DestVecOn32->getContainers()[i], RetVec->getContainers()[i]);
3573*03ce13f7SAndroid Build Coastguard Worker       }
3574*03ce13f7SAndroid Build Coastguard Worker     } else if (ReturnRegHi) {
3575*03ce13f7SAndroid Build Coastguard Worker       assert(Dest->getType() == IceType_i64);
3576*03ce13f7SAndroid Build Coastguard Worker       auto *Dest64On32 = llvm::cast<Variable64On32>(Dest);
3577*03ce13f7SAndroid Build Coastguard Worker       Variable *DestLo = Dest64On32->getLo();
3578*03ce13f7SAndroid Build Coastguard Worker       Variable *DestHi = Dest64On32->getHi();
3579*03ce13f7SAndroid Build Coastguard Worker       _mov(DestLo, ReturnReg);
3580*03ce13f7SAndroid Build Coastguard Worker       _mov(DestHi, ReturnRegHi);
3581*03ce13f7SAndroid Build Coastguard Worker     } else {
3582*03ce13f7SAndroid Build Coastguard Worker       assert(Dest->getType() == IceType_i32 || Dest->getType() == IceType_i16 ||
3583*03ce13f7SAndroid Build Coastguard Worker              Dest->getType() == IceType_i8 || Dest->getType() == IceType_i1 ||
3584*03ce13f7SAndroid Build Coastguard Worker              isScalarFloatingType(Dest->getType()) ||
3585*03ce13f7SAndroid Build Coastguard Worker              isVectorType(Dest->getType()));
3586*03ce13f7SAndroid Build Coastguard Worker       _mov(Dest, ReturnReg);
3587*03ce13f7SAndroid Build Coastguard Worker     }
3588*03ce13f7SAndroid Build Coastguard Worker   }
3589*03ce13f7SAndroid Build Coastguard Worker }
3590*03ce13f7SAndroid Build Coastguard Worker 
lowerCast(const InstCast * Instr)3591*03ce13f7SAndroid Build Coastguard Worker void TargetMIPS32::lowerCast(const InstCast *Instr) {
3592*03ce13f7SAndroid Build Coastguard Worker   InstCast::OpKind CastKind = Instr->getCastKind();
3593*03ce13f7SAndroid Build Coastguard Worker   Variable *Dest = Instr->getDest();
3594*03ce13f7SAndroid Build Coastguard Worker   Operand *Src0 = legalizeUndef(Instr->getSrc(0));
3595*03ce13f7SAndroid Build Coastguard Worker   const Type DestTy = Dest->getType();
3596*03ce13f7SAndroid Build Coastguard Worker   const Type Src0Ty = Src0->getType();
3597*03ce13f7SAndroid Build Coastguard Worker   const uint32_t ShiftAmount =
3598*03ce13f7SAndroid Build Coastguard Worker       (Src0Ty == IceType_i1
3599*03ce13f7SAndroid Build Coastguard Worker            ? INT32_BITS - 1
3600*03ce13f7SAndroid Build Coastguard Worker            : INT32_BITS - (CHAR_BITS * typeWidthInBytes(Src0Ty)));
3601*03ce13f7SAndroid Build Coastguard Worker   const uint32_t Mask =
3602*03ce13f7SAndroid Build Coastguard Worker       (Src0Ty == IceType_i1
3603*03ce13f7SAndroid Build Coastguard Worker            ? 1
3604*03ce13f7SAndroid Build Coastguard Worker            : (1 << (CHAR_BITS * typeWidthInBytes(Src0Ty))) - 1);
3605*03ce13f7SAndroid Build Coastguard Worker 
3606*03ce13f7SAndroid Build Coastguard Worker   if (isVectorType(DestTy)) {
3607*03ce13f7SAndroid Build Coastguard Worker     llvm::report_fatal_error("Cast: Destination type is vector");
3608*03ce13f7SAndroid Build Coastguard Worker     return;
3609*03ce13f7SAndroid Build Coastguard Worker   }
3610*03ce13f7SAndroid Build Coastguard Worker   switch (CastKind) {
3611*03ce13f7SAndroid Build Coastguard Worker   default:
3612*03ce13f7SAndroid Build Coastguard Worker     Func->setError("Cast type not supported");
3613*03ce13f7SAndroid Build Coastguard Worker     return;
3614*03ce13f7SAndroid Build Coastguard Worker   case InstCast::Sext: {
3615*03ce13f7SAndroid Build Coastguard Worker     if (DestTy == IceType_i64) {
3616*03ce13f7SAndroid Build Coastguard Worker       auto *DestLo = llvm::cast<Variable>(loOperand(Dest));
3617*03ce13f7SAndroid Build Coastguard Worker       auto *DestHi = llvm::cast<Variable>(hiOperand(Dest));
3618*03ce13f7SAndroid Build Coastguard Worker       Variable *Src0R = legalizeToReg(Src0);
3619*03ce13f7SAndroid Build Coastguard Worker       Variable *T1_Lo = I32Reg();
3620*03ce13f7SAndroid Build Coastguard Worker       Variable *T2_Lo = I32Reg();
3621*03ce13f7SAndroid Build Coastguard Worker       Variable *T_Hi = I32Reg();
3622*03ce13f7SAndroid Build Coastguard Worker       if (Src0Ty == IceType_i1) {
3623*03ce13f7SAndroid Build Coastguard Worker         _sll(T1_Lo, Src0R, INT32_BITS - 1);
3624*03ce13f7SAndroid Build Coastguard Worker         _sra(T2_Lo, T1_Lo, INT32_BITS - 1);
3625*03ce13f7SAndroid Build Coastguard Worker         _mov(DestHi, T2_Lo);
3626*03ce13f7SAndroid Build Coastguard Worker         _mov(DestLo, T2_Lo);
3627*03ce13f7SAndroid Build Coastguard Worker       } else if (Src0Ty == IceType_i8 || Src0Ty == IceType_i16) {
3628*03ce13f7SAndroid Build Coastguard Worker         _sll(T1_Lo, Src0R, ShiftAmount);
3629*03ce13f7SAndroid Build Coastguard Worker         _sra(T2_Lo, T1_Lo, ShiftAmount);
3630*03ce13f7SAndroid Build Coastguard Worker         _sra(T_Hi, T2_Lo, INT32_BITS - 1);
3631*03ce13f7SAndroid Build Coastguard Worker         _mov(DestHi, T_Hi);
3632*03ce13f7SAndroid Build Coastguard Worker         _mov(DestLo, T2_Lo);
3633*03ce13f7SAndroid Build Coastguard Worker       } else if (Src0Ty == IceType_i32) {
3634*03ce13f7SAndroid Build Coastguard Worker         _mov(T1_Lo, Src0R);
3635*03ce13f7SAndroid Build Coastguard Worker         _sra(T_Hi, T1_Lo, INT32_BITS - 1);
3636*03ce13f7SAndroid Build Coastguard Worker         _mov(DestHi, T_Hi);
3637*03ce13f7SAndroid Build Coastguard Worker         _mov(DestLo, T1_Lo);
3638*03ce13f7SAndroid Build Coastguard Worker       }
3639*03ce13f7SAndroid Build Coastguard Worker     } else {
3640*03ce13f7SAndroid Build Coastguard Worker       Variable *Src0R = legalizeToReg(Src0);
3641*03ce13f7SAndroid Build Coastguard Worker       Variable *T1 = makeReg(DestTy);
3642*03ce13f7SAndroid Build Coastguard Worker       Variable *T2 = makeReg(DestTy);
3643*03ce13f7SAndroid Build Coastguard Worker       if (Src0Ty == IceType_i1 || Src0Ty == IceType_i8 ||
3644*03ce13f7SAndroid Build Coastguard Worker           Src0Ty == IceType_i16) {
3645*03ce13f7SAndroid Build Coastguard Worker         _sll(T1, Src0R, ShiftAmount);
3646*03ce13f7SAndroid Build Coastguard Worker         _sra(T2, T1, ShiftAmount);
3647*03ce13f7SAndroid Build Coastguard Worker         _mov(Dest, T2);
3648*03ce13f7SAndroid Build Coastguard Worker       }
3649*03ce13f7SAndroid Build Coastguard Worker     }
3650*03ce13f7SAndroid Build Coastguard Worker     break;
3651*03ce13f7SAndroid Build Coastguard Worker   }
3652*03ce13f7SAndroid Build Coastguard Worker   case InstCast::Zext: {
3653*03ce13f7SAndroid Build Coastguard Worker     if (DestTy == IceType_i64) {
3654*03ce13f7SAndroid Build Coastguard Worker       auto *DestLo = llvm::cast<Variable>(loOperand(Dest));
3655*03ce13f7SAndroid Build Coastguard Worker       auto *DestHi = llvm::cast<Variable>(hiOperand(Dest));
3656*03ce13f7SAndroid Build Coastguard Worker       Variable *Src0R = legalizeToReg(Src0);
3657*03ce13f7SAndroid Build Coastguard Worker       Variable *T_Lo = I32Reg();
3658*03ce13f7SAndroid Build Coastguard Worker       Variable *T_Hi = I32Reg();
3659*03ce13f7SAndroid Build Coastguard Worker 
3660*03ce13f7SAndroid Build Coastguard Worker       if (Src0Ty == IceType_i1 || Src0Ty == IceType_i8 || Src0Ty == IceType_i16)
3661*03ce13f7SAndroid Build Coastguard Worker         _andi(T_Lo, Src0R, Mask);
3662*03ce13f7SAndroid Build Coastguard Worker       else if (Src0Ty == IceType_i32)
3663*03ce13f7SAndroid Build Coastguard Worker         _mov(T_Lo, Src0R);
3664*03ce13f7SAndroid Build Coastguard Worker       else
3665*03ce13f7SAndroid Build Coastguard Worker         assert(Src0Ty != IceType_i64);
3666*03ce13f7SAndroid Build Coastguard Worker       _mov(DestLo, T_Lo);
3667*03ce13f7SAndroid Build Coastguard Worker 
3668*03ce13f7SAndroid Build Coastguard Worker       auto *Zero = getZero();
3669*03ce13f7SAndroid Build Coastguard Worker       _addiu(T_Hi, Zero, 0);
3670*03ce13f7SAndroid Build Coastguard Worker       _mov(DestHi, T_Hi);
3671*03ce13f7SAndroid Build Coastguard Worker     } else {
3672*03ce13f7SAndroid Build Coastguard Worker       Variable *Src0R = legalizeToReg(Src0);
3673*03ce13f7SAndroid Build Coastguard Worker       Variable *T = makeReg(DestTy);
3674*03ce13f7SAndroid Build Coastguard Worker       if (Src0Ty == IceType_i1 || Src0Ty == IceType_i8 ||
3675*03ce13f7SAndroid Build Coastguard Worker           Src0Ty == IceType_i16) {
3676*03ce13f7SAndroid Build Coastguard Worker         _andi(T, Src0R, Mask);
3677*03ce13f7SAndroid Build Coastguard Worker         _mov(Dest, T);
3678*03ce13f7SAndroid Build Coastguard Worker       }
3679*03ce13f7SAndroid Build Coastguard Worker     }
3680*03ce13f7SAndroid Build Coastguard Worker     break;
3681*03ce13f7SAndroid Build Coastguard Worker   }
3682*03ce13f7SAndroid Build Coastguard Worker   case InstCast::Trunc: {
3683*03ce13f7SAndroid Build Coastguard Worker     if (Src0Ty == IceType_i64)
3684*03ce13f7SAndroid Build Coastguard Worker       Src0 = loOperand(Src0);
3685*03ce13f7SAndroid Build Coastguard Worker     Variable *Src0R = legalizeToReg(Src0);
3686*03ce13f7SAndroid Build Coastguard Worker     Variable *T = makeReg(DestTy);
3687*03ce13f7SAndroid Build Coastguard Worker     switch (DestTy) {
3688*03ce13f7SAndroid Build Coastguard Worker     case IceType_i1:
3689*03ce13f7SAndroid Build Coastguard Worker       _andi(T, Src0R, 0x1);
3690*03ce13f7SAndroid Build Coastguard Worker       break;
3691*03ce13f7SAndroid Build Coastguard Worker     case IceType_i8:
3692*03ce13f7SAndroid Build Coastguard Worker       _andi(T, Src0R, 0xff);
3693*03ce13f7SAndroid Build Coastguard Worker       break;
3694*03ce13f7SAndroid Build Coastguard Worker     case IceType_i16:
3695*03ce13f7SAndroid Build Coastguard Worker       _andi(T, Src0R, 0xffff);
3696*03ce13f7SAndroid Build Coastguard Worker       break;
3697*03ce13f7SAndroid Build Coastguard Worker     default:
3698*03ce13f7SAndroid Build Coastguard Worker       _mov(T, Src0R);
3699*03ce13f7SAndroid Build Coastguard Worker       break;
3700*03ce13f7SAndroid Build Coastguard Worker     }
3701*03ce13f7SAndroid Build Coastguard Worker     _mov(Dest, T);
3702*03ce13f7SAndroid Build Coastguard Worker     break;
3703*03ce13f7SAndroid Build Coastguard Worker   }
3704*03ce13f7SAndroid Build Coastguard Worker   case InstCast::Fptrunc: {
3705*03ce13f7SAndroid Build Coastguard Worker     assert(Dest->getType() == IceType_f32);
3706*03ce13f7SAndroid Build Coastguard Worker     assert(Src0->getType() == IceType_f64);
3707*03ce13f7SAndroid Build Coastguard Worker     auto *DestR = legalizeToReg(Dest);
3708*03ce13f7SAndroid Build Coastguard Worker     auto *Src0R = legalizeToReg(Src0);
3709*03ce13f7SAndroid Build Coastguard Worker     _cvt_s_d(DestR, Src0R);
3710*03ce13f7SAndroid Build Coastguard Worker     _mov(Dest, DestR);
3711*03ce13f7SAndroid Build Coastguard Worker     break;
3712*03ce13f7SAndroid Build Coastguard Worker   }
3713*03ce13f7SAndroid Build Coastguard Worker   case InstCast::Fpext: {
3714*03ce13f7SAndroid Build Coastguard Worker     assert(Dest->getType() == IceType_f64);
3715*03ce13f7SAndroid Build Coastguard Worker     assert(Src0->getType() == IceType_f32);
3716*03ce13f7SAndroid Build Coastguard Worker     auto *DestR = legalizeToReg(Dest);
3717*03ce13f7SAndroid Build Coastguard Worker     auto *Src0R = legalizeToReg(Src0);
3718*03ce13f7SAndroid Build Coastguard Worker     _cvt_d_s(DestR, Src0R);
3719*03ce13f7SAndroid Build Coastguard Worker     _mov(Dest, DestR);
3720*03ce13f7SAndroid Build Coastguard Worker     break;
3721*03ce13f7SAndroid Build Coastguard Worker   }
3722*03ce13f7SAndroid Build Coastguard Worker   case InstCast::Fptosi:
3723*03ce13f7SAndroid Build Coastguard Worker   case InstCast::Fptoui: {
3724*03ce13f7SAndroid Build Coastguard Worker     if (llvm::isa<Variable64On32>(Dest)) {
3725*03ce13f7SAndroid Build Coastguard Worker       llvm::report_fatal_error("fp-to-i64 should have been prelowered.");
3726*03ce13f7SAndroid Build Coastguard Worker       return;
3727*03ce13f7SAndroid Build Coastguard Worker     }
3728*03ce13f7SAndroid Build Coastguard Worker     if (DestTy != IceType_i64) {
3729*03ce13f7SAndroid Build Coastguard Worker       if (Src0Ty == IceType_f32 && isScalarIntegerType(DestTy)) {
3730*03ce13f7SAndroid Build Coastguard Worker         Variable *Src0R = legalizeToReg(Src0);
3731*03ce13f7SAndroid Build Coastguard Worker         Variable *FTmp = makeReg(IceType_f32);
3732*03ce13f7SAndroid Build Coastguard Worker         _trunc_w_s(FTmp, Src0R);
3733*03ce13f7SAndroid Build Coastguard Worker         _mov(Dest, FTmp);
3734*03ce13f7SAndroid Build Coastguard Worker         return;
3735*03ce13f7SAndroid Build Coastguard Worker       }
3736*03ce13f7SAndroid Build Coastguard Worker       if (Src0Ty == IceType_f64 && isScalarIntegerType(DestTy)) {
3737*03ce13f7SAndroid Build Coastguard Worker         Variable *Src0R = legalizeToReg(Src0);
3738*03ce13f7SAndroid Build Coastguard Worker         Variable *FTmp = makeReg(IceType_f64);
3739*03ce13f7SAndroid Build Coastguard Worker         _trunc_w_d(FTmp, Src0R);
3740*03ce13f7SAndroid Build Coastguard Worker         _mov(Dest, FTmp);
3741*03ce13f7SAndroid Build Coastguard Worker         return;
3742*03ce13f7SAndroid Build Coastguard Worker       }
3743*03ce13f7SAndroid Build Coastguard Worker     }
3744*03ce13f7SAndroid Build Coastguard Worker     llvm::report_fatal_error("Destination is i64 in fp-to-i32");
3745*03ce13f7SAndroid Build Coastguard Worker     break;
3746*03ce13f7SAndroid Build Coastguard Worker   }
3747*03ce13f7SAndroid Build Coastguard Worker   case InstCast::Sitofp:
3748*03ce13f7SAndroid Build Coastguard Worker   case InstCast::Uitofp: {
3749*03ce13f7SAndroid Build Coastguard Worker     if (llvm::isa<Variable64On32>(Dest)) {
3750*03ce13f7SAndroid Build Coastguard Worker       llvm::report_fatal_error("i64-to-fp should have been prelowered.");
3751*03ce13f7SAndroid Build Coastguard Worker       return;
3752*03ce13f7SAndroid Build Coastguard Worker     }
3753*03ce13f7SAndroid Build Coastguard Worker     if (Src0Ty != IceType_i64) {
3754*03ce13f7SAndroid Build Coastguard Worker       Variable *Src0R = legalizeToReg(Src0);
3755*03ce13f7SAndroid Build Coastguard Worker       auto *T0R = Src0R;
3756*03ce13f7SAndroid Build Coastguard Worker       if (Src0Ty != IceType_i32) {
3757*03ce13f7SAndroid Build Coastguard Worker         T0R = makeReg(IceType_i32);
3758*03ce13f7SAndroid Build Coastguard Worker         if (CastKind == InstCast::Uitofp)
3759*03ce13f7SAndroid Build Coastguard Worker           lowerCast(InstCast::create(Func, InstCast::Zext, T0R, Src0R));
3760*03ce13f7SAndroid Build Coastguard Worker         else
3761*03ce13f7SAndroid Build Coastguard Worker           lowerCast(InstCast::create(Func, InstCast::Sext, T0R, Src0R));
3762*03ce13f7SAndroid Build Coastguard Worker       }
3763*03ce13f7SAndroid Build Coastguard Worker       if (isScalarIntegerType(Src0Ty) && DestTy == IceType_f32) {
3764*03ce13f7SAndroid Build Coastguard Worker         Variable *FTmp1 = makeReg(IceType_f32);
3765*03ce13f7SAndroid Build Coastguard Worker         Variable *FTmp2 = makeReg(IceType_f32);
3766*03ce13f7SAndroid Build Coastguard Worker         _mtc1(FTmp1, T0R);
3767*03ce13f7SAndroid Build Coastguard Worker         _cvt_s_w(FTmp2, FTmp1);
3768*03ce13f7SAndroid Build Coastguard Worker         _mov(Dest, FTmp2);
3769*03ce13f7SAndroid Build Coastguard Worker         return;
3770*03ce13f7SAndroid Build Coastguard Worker       }
3771*03ce13f7SAndroid Build Coastguard Worker       if (isScalarIntegerType(Src0Ty) && DestTy == IceType_f64) {
3772*03ce13f7SAndroid Build Coastguard Worker         Variable *FTmp1 = makeReg(IceType_f64);
3773*03ce13f7SAndroid Build Coastguard Worker         Variable *FTmp2 = makeReg(IceType_f64);
3774*03ce13f7SAndroid Build Coastguard Worker         _mtc1(FTmp1, T0R);
3775*03ce13f7SAndroid Build Coastguard Worker         _cvt_d_w(FTmp2, FTmp1);
3776*03ce13f7SAndroid Build Coastguard Worker         _mov(Dest, FTmp2);
3777*03ce13f7SAndroid Build Coastguard Worker         return;
3778*03ce13f7SAndroid Build Coastguard Worker       }
3779*03ce13f7SAndroid Build Coastguard Worker     }
3780*03ce13f7SAndroid Build Coastguard Worker     llvm::report_fatal_error("Source is i64 in i32-to-fp");
3781*03ce13f7SAndroid Build Coastguard Worker     break;
3782*03ce13f7SAndroid Build Coastguard Worker   }
3783*03ce13f7SAndroid Build Coastguard Worker   case InstCast::Bitcast: {
3784*03ce13f7SAndroid Build Coastguard Worker     Operand *Src0 = Instr->getSrc(0);
3785*03ce13f7SAndroid Build Coastguard Worker     if (DestTy == Src0->getType()) {
3786*03ce13f7SAndroid Build Coastguard Worker       auto *Assign = InstAssign::create(Func, Dest, Src0);
3787*03ce13f7SAndroid Build Coastguard Worker       lowerAssign(Assign);
3788*03ce13f7SAndroid Build Coastguard Worker       return;
3789*03ce13f7SAndroid Build Coastguard Worker     }
3790*03ce13f7SAndroid Build Coastguard Worker     if (isVectorType(DestTy) || isVectorType(Src0->getType())) {
3791*03ce13f7SAndroid Build Coastguard Worker       llvm::report_fatal_error(
3792*03ce13f7SAndroid Build Coastguard Worker           "Bitcast: vector type should have been prelowered.");
3793*03ce13f7SAndroid Build Coastguard Worker       return;
3794*03ce13f7SAndroid Build Coastguard Worker     }
3795*03ce13f7SAndroid Build Coastguard Worker     switch (DestTy) {
3796*03ce13f7SAndroid Build Coastguard Worker     case IceType_NUM:
3797*03ce13f7SAndroid Build Coastguard Worker     case IceType_void:
3798*03ce13f7SAndroid Build Coastguard Worker       llvm::report_fatal_error("Unexpected bitcast.");
3799*03ce13f7SAndroid Build Coastguard Worker     case IceType_i1:
3800*03ce13f7SAndroid Build Coastguard Worker       UnimplementedLoweringError(this, Instr);
3801*03ce13f7SAndroid Build Coastguard Worker       break;
3802*03ce13f7SAndroid Build Coastguard Worker     case IceType_i8:
3803*03ce13f7SAndroid Build Coastguard Worker       assert(Src0->getType() == IceType_v8i1);
3804*03ce13f7SAndroid Build Coastguard Worker       llvm::report_fatal_error(
3805*03ce13f7SAndroid Build Coastguard Worker           "i8 to v8i1 conversion should have been prelowered.");
3806*03ce13f7SAndroid Build Coastguard Worker       break;
3807*03ce13f7SAndroid Build Coastguard Worker     case IceType_i16:
3808*03ce13f7SAndroid Build Coastguard Worker       assert(Src0->getType() == IceType_v16i1);
3809*03ce13f7SAndroid Build Coastguard Worker       llvm::report_fatal_error(
3810*03ce13f7SAndroid Build Coastguard Worker           "i16 to v16i1 conversion should have been prelowered.");
3811*03ce13f7SAndroid Build Coastguard Worker       break;
3812*03ce13f7SAndroid Build Coastguard Worker     case IceType_i32:
3813*03ce13f7SAndroid Build Coastguard Worker     case IceType_f32: {
3814*03ce13f7SAndroid Build Coastguard Worker       Variable *Src0R = legalizeToReg(Src0);
3815*03ce13f7SAndroid Build Coastguard Worker       _mov(Dest, Src0R);
3816*03ce13f7SAndroid Build Coastguard Worker       break;
3817*03ce13f7SAndroid Build Coastguard Worker     }
3818*03ce13f7SAndroid Build Coastguard Worker     case IceType_i64: {
3819*03ce13f7SAndroid Build Coastguard Worker       assert(Src0->getType() == IceType_f64);
3820*03ce13f7SAndroid Build Coastguard Worker       Variable *Src0R = legalizeToReg(Src0);
3821*03ce13f7SAndroid Build Coastguard Worker       auto *T = llvm::cast<Variable64On32>(Func->makeVariable(IceType_i64));
3822*03ce13f7SAndroid Build Coastguard Worker       T->initHiLo(Func);
3823*03ce13f7SAndroid Build Coastguard Worker       T->getHi()->setMustNotHaveReg();
3824*03ce13f7SAndroid Build Coastguard Worker       T->getLo()->setMustNotHaveReg();
3825*03ce13f7SAndroid Build Coastguard Worker       Context.insert<InstFakeDef>(T->getHi());
3826*03ce13f7SAndroid Build Coastguard Worker       Context.insert<InstFakeDef>(T->getLo());
3827*03ce13f7SAndroid Build Coastguard Worker       _mov_fp64_to_i64(T->getHi(), Src0R, Int64_Hi);
3828*03ce13f7SAndroid Build Coastguard Worker       _mov_fp64_to_i64(T->getLo(), Src0R, Int64_Lo);
3829*03ce13f7SAndroid Build Coastguard Worker       lowerAssign(InstAssign::create(Func, Dest, T));
3830*03ce13f7SAndroid Build Coastguard Worker       break;
3831*03ce13f7SAndroid Build Coastguard Worker     }
3832*03ce13f7SAndroid Build Coastguard Worker     case IceType_f64: {
3833*03ce13f7SAndroid Build Coastguard Worker       assert(Src0->getType() == IceType_i64);
3834*03ce13f7SAndroid Build Coastguard Worker       const uint32_t Mask = 0xFFFFFFFF;
3835*03ce13f7SAndroid Build Coastguard Worker       if (auto *C64 = llvm::dyn_cast<ConstantInteger64>(Src0)) {
3836*03ce13f7SAndroid Build Coastguard Worker         Variable *RegHi, *RegLo;
3837*03ce13f7SAndroid Build Coastguard Worker         const uint64_t Value = C64->getValue();
3838*03ce13f7SAndroid Build Coastguard Worker         uint64_t Upper32Bits = (Value >> INT32_BITS) & Mask;
3839*03ce13f7SAndroid Build Coastguard Worker         uint64_t Lower32Bits = Value & Mask;
3840*03ce13f7SAndroid Build Coastguard Worker         RegLo = legalizeToReg(Ctx->getConstantInt32(Lower32Bits));
3841*03ce13f7SAndroid Build Coastguard Worker         RegHi = legalizeToReg(Ctx->getConstantInt32(Upper32Bits));
3842*03ce13f7SAndroid Build Coastguard Worker         _mov(Dest, RegHi, RegLo);
3843*03ce13f7SAndroid Build Coastguard Worker       } else {
3844*03ce13f7SAndroid Build Coastguard Worker         auto *Var64On32 = llvm::cast<Variable64On32>(Src0);
3845*03ce13f7SAndroid Build Coastguard Worker         auto *RegLo = legalizeToReg(loOperand(Var64On32));
3846*03ce13f7SAndroid Build Coastguard Worker         auto *RegHi = legalizeToReg(hiOperand(Var64On32));
3847*03ce13f7SAndroid Build Coastguard Worker         _mov(Dest, RegHi, RegLo);
3848*03ce13f7SAndroid Build Coastguard Worker       }
3849*03ce13f7SAndroid Build Coastguard Worker       break;
3850*03ce13f7SAndroid Build Coastguard Worker     }
3851*03ce13f7SAndroid Build Coastguard Worker     default:
3852*03ce13f7SAndroid Build Coastguard Worker       llvm::report_fatal_error("Unexpected bitcast.");
3853*03ce13f7SAndroid Build Coastguard Worker     }
3854*03ce13f7SAndroid Build Coastguard Worker     break;
3855*03ce13f7SAndroid Build Coastguard Worker   }
3856*03ce13f7SAndroid Build Coastguard Worker   }
3857*03ce13f7SAndroid Build Coastguard Worker }
3858*03ce13f7SAndroid Build Coastguard Worker 
lowerExtractElement(const InstExtractElement * Instr)3859*03ce13f7SAndroid Build Coastguard Worker void TargetMIPS32::lowerExtractElement(const InstExtractElement *Instr) {
3860*03ce13f7SAndroid Build Coastguard Worker   Variable *Dest = Instr->getDest();
3861*03ce13f7SAndroid Build Coastguard Worker   const Type DestTy = Dest->getType();
3862*03ce13f7SAndroid Build Coastguard Worker   Operand *Src1 = Instr->getSrc(1);
3863*03ce13f7SAndroid Build Coastguard Worker   if (const auto *Imm = llvm::dyn_cast<ConstantInteger32>(Src1)) {
3864*03ce13f7SAndroid Build Coastguard Worker     const uint32_t Index = Imm->getValue();
3865*03ce13f7SAndroid Build Coastguard Worker     Variable *TDest = makeReg(DestTy);
3866*03ce13f7SAndroid Build Coastguard Worker     Variable *TReg = makeReg(DestTy);
3867*03ce13f7SAndroid Build Coastguard Worker     auto *Src0 = legalizeUndef(Instr->getSrc(0));
3868*03ce13f7SAndroid Build Coastguard Worker     auto *Src0R = llvm::dyn_cast<VariableVecOn32>(Src0);
3869*03ce13f7SAndroid Build Coastguard Worker     // Number of elements in each container
3870*03ce13f7SAndroid Build Coastguard Worker     uint32_t ElemPerCont =
3871*03ce13f7SAndroid Build Coastguard Worker         typeNumElements(Src0->getType()) / Src0R->ContainersPerVector;
3872*03ce13f7SAndroid Build Coastguard Worker     auto *Src = Src0R->getContainers()[Index / ElemPerCont];
3873*03ce13f7SAndroid Build Coastguard Worker     auto *SrcE = legalizeToReg(Src);
3874*03ce13f7SAndroid Build Coastguard Worker     // Position of the element in the container
3875*03ce13f7SAndroid Build Coastguard Worker     uint32_t PosInCont = Index % ElemPerCont;
3876*03ce13f7SAndroid Build Coastguard Worker     if (ElemPerCont == 1) {
3877*03ce13f7SAndroid Build Coastguard Worker       _mov(TDest, SrcE);
3878*03ce13f7SAndroid Build Coastguard Worker     } else if (ElemPerCont == 2) {
3879*03ce13f7SAndroid Build Coastguard Worker       switch (PosInCont) {
3880*03ce13f7SAndroid Build Coastguard Worker       case 0:
3881*03ce13f7SAndroid Build Coastguard Worker         _andi(TDest, SrcE, 0xffff);
3882*03ce13f7SAndroid Build Coastguard Worker         break;
3883*03ce13f7SAndroid Build Coastguard Worker       case 1:
3884*03ce13f7SAndroid Build Coastguard Worker         _srl(TDest, SrcE, 16);
3885*03ce13f7SAndroid Build Coastguard Worker         break;
3886*03ce13f7SAndroid Build Coastguard Worker       default:
3887*03ce13f7SAndroid Build Coastguard Worker         llvm::report_fatal_error("ExtractElement: Invalid PosInCont");
3888*03ce13f7SAndroid Build Coastguard Worker         break;
3889*03ce13f7SAndroid Build Coastguard Worker       }
3890*03ce13f7SAndroid Build Coastguard Worker     } else if (ElemPerCont == 4) {
3891*03ce13f7SAndroid Build Coastguard Worker       switch (PosInCont) {
3892*03ce13f7SAndroid Build Coastguard Worker       case 0:
3893*03ce13f7SAndroid Build Coastguard Worker         _andi(TDest, SrcE, 0xff);
3894*03ce13f7SAndroid Build Coastguard Worker         break;
3895*03ce13f7SAndroid Build Coastguard Worker       case 1:
3896*03ce13f7SAndroid Build Coastguard Worker         _srl(TReg, SrcE, 8);
3897*03ce13f7SAndroid Build Coastguard Worker         _andi(TDest, TReg, 0xff);
3898*03ce13f7SAndroid Build Coastguard Worker         break;
3899*03ce13f7SAndroid Build Coastguard Worker       case 2:
3900*03ce13f7SAndroid Build Coastguard Worker         _srl(TReg, SrcE, 16);
3901*03ce13f7SAndroid Build Coastguard Worker         _andi(TDest, TReg, 0xff);
3902*03ce13f7SAndroid Build Coastguard Worker         break;
3903*03ce13f7SAndroid Build Coastguard Worker       case 3:
3904*03ce13f7SAndroid Build Coastguard Worker         _srl(TDest, SrcE, 24);
3905*03ce13f7SAndroid Build Coastguard Worker         break;
3906*03ce13f7SAndroid Build Coastguard Worker       default:
3907*03ce13f7SAndroid Build Coastguard Worker         llvm::report_fatal_error("ExtractElement: Invalid PosInCont");
3908*03ce13f7SAndroid Build Coastguard Worker         break;
3909*03ce13f7SAndroid Build Coastguard Worker       }
3910*03ce13f7SAndroid Build Coastguard Worker     }
3911*03ce13f7SAndroid Build Coastguard Worker     if (typeElementType(Src0R->getType()) == IceType_i1) {
3912*03ce13f7SAndroid Build Coastguard Worker       Variable *TReg1 = makeReg(DestTy);
3913*03ce13f7SAndroid Build Coastguard Worker       _andi(TReg1, TDest, 0x1);
3914*03ce13f7SAndroid Build Coastguard Worker       _mov(Dest, TReg1);
3915*03ce13f7SAndroid Build Coastguard Worker     } else {
3916*03ce13f7SAndroid Build Coastguard Worker       _mov(Dest, TDest);
3917*03ce13f7SAndroid Build Coastguard Worker     }
3918*03ce13f7SAndroid Build Coastguard Worker     return;
3919*03ce13f7SAndroid Build Coastguard Worker   }
3920*03ce13f7SAndroid Build Coastguard Worker   llvm::report_fatal_error("ExtractElement requires a constant index");
3921*03ce13f7SAndroid Build Coastguard Worker }
3922*03ce13f7SAndroid Build Coastguard Worker 
lowerFcmp(const InstFcmp * Instr)3923*03ce13f7SAndroid Build Coastguard Worker void TargetMIPS32::lowerFcmp(const InstFcmp *Instr) {
3924*03ce13f7SAndroid Build Coastguard Worker   Variable *Dest = Instr->getDest();
3925*03ce13f7SAndroid Build Coastguard Worker   if (isVectorType(Dest->getType())) {
3926*03ce13f7SAndroid Build Coastguard Worker     llvm::report_fatal_error("Fcmp: Destination type is vector");
3927*03ce13f7SAndroid Build Coastguard Worker     return;
3928*03ce13f7SAndroid Build Coastguard Worker   }
3929*03ce13f7SAndroid Build Coastguard Worker 
3930*03ce13f7SAndroid Build Coastguard Worker   auto *Src0 = Instr->getSrc(0);
3931*03ce13f7SAndroid Build Coastguard Worker   auto *Src1 = Instr->getSrc(1);
3932*03ce13f7SAndroid Build Coastguard Worker   auto *Zero = getZero();
3933*03ce13f7SAndroid Build Coastguard Worker 
3934*03ce13f7SAndroid Build Coastguard Worker   InstFcmp::FCond Cond = Instr->getCondition();
3935*03ce13f7SAndroid Build Coastguard Worker   auto *DestR = makeReg(IceType_i32);
3936*03ce13f7SAndroid Build Coastguard Worker   auto *Src0R = legalizeToReg(Src0);
3937*03ce13f7SAndroid Build Coastguard Worker   auto *Src1R = legalizeToReg(Src1);
3938*03ce13f7SAndroid Build Coastguard Worker   const Type Src0Ty = Src0->getType();
3939*03ce13f7SAndroid Build Coastguard Worker 
3940*03ce13f7SAndroid Build Coastguard Worker   Operand *FCC0 = OperandMIPS32FCC::create(getFunc(), OperandMIPS32FCC::FCC0);
3941*03ce13f7SAndroid Build Coastguard Worker 
3942*03ce13f7SAndroid Build Coastguard Worker   switch (Cond) {
3943*03ce13f7SAndroid Build Coastguard Worker   default: {
3944*03ce13f7SAndroid Build Coastguard Worker     llvm::report_fatal_error("Unhandled fp comparison.");
3945*03ce13f7SAndroid Build Coastguard Worker     return;
3946*03ce13f7SAndroid Build Coastguard Worker   }
3947*03ce13f7SAndroid Build Coastguard Worker   case InstFcmp::False: {
3948*03ce13f7SAndroid Build Coastguard Worker     Context.insert<InstFakeUse>(Src0R);
3949*03ce13f7SAndroid Build Coastguard Worker     Context.insert<InstFakeUse>(Src1R);
3950*03ce13f7SAndroid Build Coastguard Worker     _addiu(DestR, Zero, 0);
3951*03ce13f7SAndroid Build Coastguard Worker     _mov(Dest, DestR);
3952*03ce13f7SAndroid Build Coastguard Worker     break;
3953*03ce13f7SAndroid Build Coastguard Worker   }
3954*03ce13f7SAndroid Build Coastguard Worker   case InstFcmp::Oeq: {
3955*03ce13f7SAndroid Build Coastguard Worker     if (Src0Ty == IceType_f32) {
3956*03ce13f7SAndroid Build Coastguard Worker       _c_eq_s(Src0R, Src1R);
3957*03ce13f7SAndroid Build Coastguard Worker     } else {
3958*03ce13f7SAndroid Build Coastguard Worker       _c_eq_d(Src0R, Src1R);
3959*03ce13f7SAndroid Build Coastguard Worker     }
3960*03ce13f7SAndroid Build Coastguard Worker     _addiu(DestR, Zero, 1);
3961*03ce13f7SAndroid Build Coastguard Worker     _movf(DestR, Zero, FCC0);
3962*03ce13f7SAndroid Build Coastguard Worker     _mov(Dest, DestR);
3963*03ce13f7SAndroid Build Coastguard Worker     break;
3964*03ce13f7SAndroid Build Coastguard Worker   }
3965*03ce13f7SAndroid Build Coastguard Worker   case InstFcmp::Ogt: {
3966*03ce13f7SAndroid Build Coastguard Worker     if (Src0Ty == IceType_f32) {
3967*03ce13f7SAndroid Build Coastguard Worker       _c_ule_s(Src0R, Src1R);
3968*03ce13f7SAndroid Build Coastguard Worker     } else {
3969*03ce13f7SAndroid Build Coastguard Worker       _c_ule_d(Src0R, Src1R);
3970*03ce13f7SAndroid Build Coastguard Worker     }
3971*03ce13f7SAndroid Build Coastguard Worker     _addiu(DestR, Zero, 1);
3972*03ce13f7SAndroid Build Coastguard Worker     _movt(DestR, Zero, FCC0);
3973*03ce13f7SAndroid Build Coastguard Worker     _mov(Dest, DestR);
3974*03ce13f7SAndroid Build Coastguard Worker     break;
3975*03ce13f7SAndroid Build Coastguard Worker   }
3976*03ce13f7SAndroid Build Coastguard Worker   case InstFcmp::Oge: {
3977*03ce13f7SAndroid Build Coastguard Worker     if (Src0Ty == IceType_f32) {
3978*03ce13f7SAndroid Build Coastguard Worker       _c_ult_s(Src0R, Src1R);
3979*03ce13f7SAndroid Build Coastguard Worker     } else {
3980*03ce13f7SAndroid Build Coastguard Worker       _c_ult_d(Src0R, Src1R);
3981*03ce13f7SAndroid Build Coastguard Worker     }
3982*03ce13f7SAndroid Build Coastguard Worker     _addiu(DestR, Zero, 1);
3983*03ce13f7SAndroid Build Coastguard Worker     _movt(DestR, Zero, FCC0);
3984*03ce13f7SAndroid Build Coastguard Worker     _mov(Dest, DestR);
3985*03ce13f7SAndroid Build Coastguard Worker     break;
3986*03ce13f7SAndroid Build Coastguard Worker   }
3987*03ce13f7SAndroid Build Coastguard Worker   case InstFcmp::Olt: {
3988*03ce13f7SAndroid Build Coastguard Worker     if (Src0Ty == IceType_f32) {
3989*03ce13f7SAndroid Build Coastguard Worker       _c_olt_s(Src0R, Src1R);
3990*03ce13f7SAndroid Build Coastguard Worker     } else {
3991*03ce13f7SAndroid Build Coastguard Worker       _c_olt_d(Src0R, Src1R);
3992*03ce13f7SAndroid Build Coastguard Worker     }
3993*03ce13f7SAndroid Build Coastguard Worker     _addiu(DestR, Zero, 1);
3994*03ce13f7SAndroid Build Coastguard Worker     _movf(DestR, Zero, FCC0);
3995*03ce13f7SAndroid Build Coastguard Worker     _mov(Dest, DestR);
3996*03ce13f7SAndroid Build Coastguard Worker     break;
3997*03ce13f7SAndroid Build Coastguard Worker   }
3998*03ce13f7SAndroid Build Coastguard Worker   case InstFcmp::Ole: {
3999*03ce13f7SAndroid Build Coastguard Worker     if (Src0Ty == IceType_f32) {
4000*03ce13f7SAndroid Build Coastguard Worker       _c_ole_s(Src0R, Src1R);
4001*03ce13f7SAndroid Build Coastguard Worker     } else {
4002*03ce13f7SAndroid Build Coastguard Worker       _c_ole_d(Src0R, Src1R);
4003*03ce13f7SAndroid Build Coastguard Worker     }
4004*03ce13f7SAndroid Build Coastguard Worker     _addiu(DestR, Zero, 1);
4005*03ce13f7SAndroid Build Coastguard Worker     _movf(DestR, Zero, FCC0);
4006*03ce13f7SAndroid Build Coastguard Worker     _mov(Dest, DestR);
4007*03ce13f7SAndroid Build Coastguard Worker     break;
4008*03ce13f7SAndroid Build Coastguard Worker   }
4009*03ce13f7SAndroid Build Coastguard Worker   case InstFcmp::One: {
4010*03ce13f7SAndroid Build Coastguard Worker     if (Src0Ty == IceType_f32) {
4011*03ce13f7SAndroid Build Coastguard Worker       _c_ueq_s(Src0R, Src1R);
4012*03ce13f7SAndroid Build Coastguard Worker     } else {
4013*03ce13f7SAndroid Build Coastguard Worker       _c_ueq_d(Src0R, Src1R);
4014*03ce13f7SAndroid Build Coastguard Worker     }
4015*03ce13f7SAndroid Build Coastguard Worker     _addiu(DestR, Zero, 1);
4016*03ce13f7SAndroid Build Coastguard Worker     _movt(DestR, Zero, FCC0);
4017*03ce13f7SAndroid Build Coastguard Worker     _mov(Dest, DestR);
4018*03ce13f7SAndroid Build Coastguard Worker     break;
4019*03ce13f7SAndroid Build Coastguard Worker   }
4020*03ce13f7SAndroid Build Coastguard Worker   case InstFcmp::Ord: {
4021*03ce13f7SAndroid Build Coastguard Worker     if (Src0Ty == IceType_f32) {
4022*03ce13f7SAndroid Build Coastguard Worker       _c_un_s(Src0R, Src1R);
4023*03ce13f7SAndroid Build Coastguard Worker     } else {
4024*03ce13f7SAndroid Build Coastguard Worker       _c_un_d(Src0R, Src1R);
4025*03ce13f7SAndroid Build Coastguard Worker     }
4026*03ce13f7SAndroid Build Coastguard Worker     _addiu(DestR, Zero, 1);
4027*03ce13f7SAndroid Build Coastguard Worker     _movt(DestR, Zero, FCC0);
4028*03ce13f7SAndroid Build Coastguard Worker     _mov(Dest, DestR);
4029*03ce13f7SAndroid Build Coastguard Worker     break;
4030*03ce13f7SAndroid Build Coastguard Worker   }
4031*03ce13f7SAndroid Build Coastguard Worker   case InstFcmp::Ueq: {
4032*03ce13f7SAndroid Build Coastguard Worker     if (Src0Ty == IceType_f32) {
4033*03ce13f7SAndroid Build Coastguard Worker       _c_ueq_s(Src0R, Src1R);
4034*03ce13f7SAndroid Build Coastguard Worker     } else {
4035*03ce13f7SAndroid Build Coastguard Worker       _c_ueq_d(Src0R, Src1R);
4036*03ce13f7SAndroid Build Coastguard Worker     }
4037*03ce13f7SAndroid Build Coastguard Worker     _addiu(DestR, Zero, 1);
4038*03ce13f7SAndroid Build Coastguard Worker     _movf(DestR, Zero, FCC0);
4039*03ce13f7SAndroid Build Coastguard Worker     _mov(Dest, DestR);
4040*03ce13f7SAndroid Build Coastguard Worker     break;
4041*03ce13f7SAndroid Build Coastguard Worker   }
4042*03ce13f7SAndroid Build Coastguard Worker   case InstFcmp::Ugt: {
4043*03ce13f7SAndroid Build Coastguard Worker     if (Src0Ty == IceType_f32) {
4044*03ce13f7SAndroid Build Coastguard Worker       _c_ole_s(Src0R, Src1R);
4045*03ce13f7SAndroid Build Coastguard Worker     } else {
4046*03ce13f7SAndroid Build Coastguard Worker       _c_ole_d(Src0R, Src1R);
4047*03ce13f7SAndroid Build Coastguard Worker     }
4048*03ce13f7SAndroid Build Coastguard Worker     _addiu(DestR, Zero, 1);
4049*03ce13f7SAndroid Build Coastguard Worker     _movt(DestR, Zero, FCC0);
4050*03ce13f7SAndroid Build Coastguard Worker     _mov(Dest, DestR);
4051*03ce13f7SAndroid Build Coastguard Worker     break;
4052*03ce13f7SAndroid Build Coastguard Worker   }
4053*03ce13f7SAndroid Build Coastguard Worker   case InstFcmp::Uge: {
4054*03ce13f7SAndroid Build Coastguard Worker     if (Src0Ty == IceType_f32) {
4055*03ce13f7SAndroid Build Coastguard Worker       _c_olt_s(Src0R, Src1R);
4056*03ce13f7SAndroid Build Coastguard Worker     } else {
4057*03ce13f7SAndroid Build Coastguard Worker       _c_olt_d(Src0R, Src1R);
4058*03ce13f7SAndroid Build Coastguard Worker     }
4059*03ce13f7SAndroid Build Coastguard Worker     _addiu(DestR, Zero, 1);
4060*03ce13f7SAndroid Build Coastguard Worker     _movt(DestR, Zero, FCC0);
4061*03ce13f7SAndroid Build Coastguard Worker     _mov(Dest, DestR);
4062*03ce13f7SAndroid Build Coastguard Worker     break;
4063*03ce13f7SAndroid Build Coastguard Worker   }
4064*03ce13f7SAndroid Build Coastguard Worker   case InstFcmp::Ult: {
4065*03ce13f7SAndroid Build Coastguard Worker     if (Src0Ty == IceType_f32) {
4066*03ce13f7SAndroid Build Coastguard Worker       _c_ult_s(Src0R, Src1R);
4067*03ce13f7SAndroid Build Coastguard Worker     } else {
4068*03ce13f7SAndroid Build Coastguard Worker       _c_ult_d(Src0R, Src1R);
4069*03ce13f7SAndroid Build Coastguard Worker     }
4070*03ce13f7SAndroid Build Coastguard Worker     _addiu(DestR, Zero, 1);
4071*03ce13f7SAndroid Build Coastguard Worker     _movf(DestR, Zero, FCC0);
4072*03ce13f7SAndroid Build Coastguard Worker     _mov(Dest, DestR);
4073*03ce13f7SAndroid Build Coastguard Worker     break;
4074*03ce13f7SAndroid Build Coastguard Worker   }
4075*03ce13f7SAndroid Build Coastguard Worker   case InstFcmp::Ule: {
4076*03ce13f7SAndroid Build Coastguard Worker     if (Src0Ty == IceType_f32) {
4077*03ce13f7SAndroid Build Coastguard Worker       _c_ule_s(Src0R, Src1R);
4078*03ce13f7SAndroid Build Coastguard Worker     } else {
4079*03ce13f7SAndroid Build Coastguard Worker       _c_ule_d(Src0R, Src1R);
4080*03ce13f7SAndroid Build Coastguard Worker     }
4081*03ce13f7SAndroid Build Coastguard Worker     _addiu(DestR, Zero, 1);
4082*03ce13f7SAndroid Build Coastguard Worker     _movf(DestR, Zero, FCC0);
4083*03ce13f7SAndroid Build Coastguard Worker     _mov(Dest, DestR);
4084*03ce13f7SAndroid Build Coastguard Worker     break;
4085*03ce13f7SAndroid Build Coastguard Worker   }
4086*03ce13f7SAndroid Build Coastguard Worker   case InstFcmp::Une: {
4087*03ce13f7SAndroid Build Coastguard Worker     if (Src0Ty == IceType_f32) {
4088*03ce13f7SAndroid Build Coastguard Worker       _c_eq_s(Src0R, Src1R);
4089*03ce13f7SAndroid Build Coastguard Worker     } else {
4090*03ce13f7SAndroid Build Coastguard Worker       _c_eq_d(Src0R, Src1R);
4091*03ce13f7SAndroid Build Coastguard Worker     }
4092*03ce13f7SAndroid Build Coastguard Worker     _addiu(DestR, Zero, 1);
4093*03ce13f7SAndroid Build Coastguard Worker     _movt(DestR, Zero, FCC0);
4094*03ce13f7SAndroid Build Coastguard Worker     _mov(Dest, DestR);
4095*03ce13f7SAndroid Build Coastguard Worker     break;
4096*03ce13f7SAndroid Build Coastguard Worker   }
4097*03ce13f7SAndroid Build Coastguard Worker   case InstFcmp::Uno: {
4098*03ce13f7SAndroid Build Coastguard Worker     if (Src0Ty == IceType_f32) {
4099*03ce13f7SAndroid Build Coastguard Worker       _c_un_s(Src0R, Src1R);
4100*03ce13f7SAndroid Build Coastguard Worker     } else {
4101*03ce13f7SAndroid Build Coastguard Worker       _c_un_d(Src0R, Src1R);
4102*03ce13f7SAndroid Build Coastguard Worker     }
4103*03ce13f7SAndroid Build Coastguard Worker     _addiu(DestR, Zero, 1);
4104*03ce13f7SAndroid Build Coastguard Worker     _movf(DestR, Zero, FCC0);
4105*03ce13f7SAndroid Build Coastguard Worker     _mov(Dest, DestR);
4106*03ce13f7SAndroid Build Coastguard Worker     break;
4107*03ce13f7SAndroid Build Coastguard Worker   }
4108*03ce13f7SAndroid Build Coastguard Worker   case InstFcmp::True: {
4109*03ce13f7SAndroid Build Coastguard Worker     Context.insert<InstFakeUse>(Src0R);
4110*03ce13f7SAndroid Build Coastguard Worker     Context.insert<InstFakeUse>(Src1R);
4111*03ce13f7SAndroid Build Coastguard Worker     _addiu(DestR, Zero, 1);
4112*03ce13f7SAndroid Build Coastguard Worker     _mov(Dest, DestR);
4113*03ce13f7SAndroid Build Coastguard Worker     break;
4114*03ce13f7SAndroid Build Coastguard Worker   }
4115*03ce13f7SAndroid Build Coastguard Worker   }
4116*03ce13f7SAndroid Build Coastguard Worker }
4117*03ce13f7SAndroid Build Coastguard Worker 
lower64Icmp(const InstIcmp * Instr)4118*03ce13f7SAndroid Build Coastguard Worker void TargetMIPS32::lower64Icmp(const InstIcmp *Instr) {
4119*03ce13f7SAndroid Build Coastguard Worker   Operand *Src0 = legalize(Instr->getSrc(0));
4120*03ce13f7SAndroid Build Coastguard Worker   Operand *Src1 = legalize(Instr->getSrc(1));
4121*03ce13f7SAndroid Build Coastguard Worker   Variable *Dest = Instr->getDest();
4122*03ce13f7SAndroid Build Coastguard Worker   InstIcmp::ICond Condition = Instr->getCondition();
4123*03ce13f7SAndroid Build Coastguard Worker 
4124*03ce13f7SAndroid Build Coastguard Worker   Variable *Src0LoR = legalizeToReg(loOperand(Src0));
4125*03ce13f7SAndroid Build Coastguard Worker   Variable *Src0HiR = legalizeToReg(hiOperand(Src0));
4126*03ce13f7SAndroid Build Coastguard Worker   Variable *Src1LoR = legalizeToReg(loOperand(Src1));
4127*03ce13f7SAndroid Build Coastguard Worker   Variable *Src1HiR = legalizeToReg(hiOperand(Src1));
4128*03ce13f7SAndroid Build Coastguard Worker 
4129*03ce13f7SAndroid Build Coastguard Worker   switch (Condition) {
4130*03ce13f7SAndroid Build Coastguard Worker   default:
4131*03ce13f7SAndroid Build Coastguard Worker     llvm_unreachable("unexpected condition");
4132*03ce13f7SAndroid Build Coastguard Worker     return;
4133*03ce13f7SAndroid Build Coastguard Worker   case InstIcmp::Eq: {
4134*03ce13f7SAndroid Build Coastguard Worker     auto *T1 = I32Reg();
4135*03ce13f7SAndroid Build Coastguard Worker     auto *T2 = I32Reg();
4136*03ce13f7SAndroid Build Coastguard Worker     auto *T3 = I32Reg();
4137*03ce13f7SAndroid Build Coastguard Worker     auto *T4 = I32Reg();
4138*03ce13f7SAndroid Build Coastguard Worker     _xor(T1, Src0HiR, Src1HiR);
4139*03ce13f7SAndroid Build Coastguard Worker     _xor(T2, Src0LoR, Src1LoR);
4140*03ce13f7SAndroid Build Coastguard Worker     _or(T3, T1, T2);
4141*03ce13f7SAndroid Build Coastguard Worker     _sltiu(T4, T3, 1);
4142*03ce13f7SAndroid Build Coastguard Worker     _mov(Dest, T4);
4143*03ce13f7SAndroid Build Coastguard Worker     return;
4144*03ce13f7SAndroid Build Coastguard Worker   }
4145*03ce13f7SAndroid Build Coastguard Worker   case InstIcmp::Ne: {
4146*03ce13f7SAndroid Build Coastguard Worker     auto *T1 = I32Reg();
4147*03ce13f7SAndroid Build Coastguard Worker     auto *T2 = I32Reg();
4148*03ce13f7SAndroid Build Coastguard Worker     auto *T3 = I32Reg();
4149*03ce13f7SAndroid Build Coastguard Worker     auto *T4 = I32Reg();
4150*03ce13f7SAndroid Build Coastguard Worker     _xor(T1, Src0HiR, Src1HiR);
4151*03ce13f7SAndroid Build Coastguard Worker     _xor(T2, Src0LoR, Src1LoR);
4152*03ce13f7SAndroid Build Coastguard Worker     _or(T3, T1, T2);
4153*03ce13f7SAndroid Build Coastguard Worker     _sltu(T4, getZero(), T3);
4154*03ce13f7SAndroid Build Coastguard Worker     _mov(Dest, T4);
4155*03ce13f7SAndroid Build Coastguard Worker     return;
4156*03ce13f7SAndroid Build Coastguard Worker   }
4157*03ce13f7SAndroid Build Coastguard Worker   case InstIcmp::Sgt: {
4158*03ce13f7SAndroid Build Coastguard Worker     auto *T1 = I32Reg();
4159*03ce13f7SAndroid Build Coastguard Worker     auto *T2 = I32Reg();
4160*03ce13f7SAndroid Build Coastguard Worker     auto *T3 = I32Reg();
4161*03ce13f7SAndroid Build Coastguard Worker     _xor(T1, Src0HiR, Src1HiR);
4162*03ce13f7SAndroid Build Coastguard Worker     _slt(T2, Src1HiR, Src0HiR);
4163*03ce13f7SAndroid Build Coastguard Worker     _sltu(T3, Src1LoR, Src0LoR);
4164*03ce13f7SAndroid Build Coastguard Worker     _movz(T2, T3, T1);
4165*03ce13f7SAndroid Build Coastguard Worker     _mov(Dest, T2);
4166*03ce13f7SAndroid Build Coastguard Worker     return;
4167*03ce13f7SAndroid Build Coastguard Worker   }
4168*03ce13f7SAndroid Build Coastguard Worker   case InstIcmp::Ugt: {
4169*03ce13f7SAndroid Build Coastguard Worker     auto *T1 = I32Reg();
4170*03ce13f7SAndroid Build Coastguard Worker     auto *T2 = I32Reg();
4171*03ce13f7SAndroid Build Coastguard Worker     auto *T3 = I32Reg();
4172*03ce13f7SAndroid Build Coastguard Worker     _xor(T1, Src0HiR, Src1HiR);
4173*03ce13f7SAndroid Build Coastguard Worker     _sltu(T2, Src1HiR, Src0HiR);
4174*03ce13f7SAndroid Build Coastguard Worker     _sltu(T3, Src1LoR, Src0LoR);
4175*03ce13f7SAndroid Build Coastguard Worker     _movz(T2, T3, T1);
4176*03ce13f7SAndroid Build Coastguard Worker     _mov(Dest, T2);
4177*03ce13f7SAndroid Build Coastguard Worker     return;
4178*03ce13f7SAndroid Build Coastguard Worker   }
4179*03ce13f7SAndroid Build Coastguard Worker   case InstIcmp::Sge: {
4180*03ce13f7SAndroid Build Coastguard Worker     auto *T1 = I32Reg();
4181*03ce13f7SAndroid Build Coastguard Worker     auto *T2 = I32Reg();
4182*03ce13f7SAndroid Build Coastguard Worker     auto *T3 = I32Reg();
4183*03ce13f7SAndroid Build Coastguard Worker     auto *T4 = I32Reg();
4184*03ce13f7SAndroid Build Coastguard Worker     auto *T5 = I32Reg();
4185*03ce13f7SAndroid Build Coastguard Worker     _xor(T1, Src0HiR, Src1HiR);
4186*03ce13f7SAndroid Build Coastguard Worker     _slt(T2, Src0HiR, Src1HiR);
4187*03ce13f7SAndroid Build Coastguard Worker     _xori(T3, T2, 1);
4188*03ce13f7SAndroid Build Coastguard Worker     _sltu(T4, Src0LoR, Src1LoR);
4189*03ce13f7SAndroid Build Coastguard Worker     _xori(T5, T4, 1);
4190*03ce13f7SAndroid Build Coastguard Worker     _movz(T3, T5, T1);
4191*03ce13f7SAndroid Build Coastguard Worker     _mov(Dest, T3);
4192*03ce13f7SAndroid Build Coastguard Worker     return;
4193*03ce13f7SAndroid Build Coastguard Worker   }
4194*03ce13f7SAndroid Build Coastguard Worker   case InstIcmp::Uge: {
4195*03ce13f7SAndroid Build Coastguard Worker     auto *T1 = I32Reg();
4196*03ce13f7SAndroid Build Coastguard Worker     auto *T2 = I32Reg();
4197*03ce13f7SAndroid Build Coastguard Worker     auto *T3 = I32Reg();
4198*03ce13f7SAndroid Build Coastguard Worker     auto *T4 = I32Reg();
4199*03ce13f7SAndroid Build Coastguard Worker     auto *T5 = I32Reg();
4200*03ce13f7SAndroid Build Coastguard Worker     _xor(T1, Src0HiR, Src1HiR);
4201*03ce13f7SAndroid Build Coastguard Worker     _sltu(T2, Src0HiR, Src1HiR);
4202*03ce13f7SAndroid Build Coastguard Worker     _xori(T3, T2, 1);
4203*03ce13f7SAndroid Build Coastguard Worker     _sltu(T4, Src0LoR, Src1LoR);
4204*03ce13f7SAndroid Build Coastguard Worker     _xori(T5, T4, 1);
4205*03ce13f7SAndroid Build Coastguard Worker     _movz(T3, T5, T1);
4206*03ce13f7SAndroid Build Coastguard Worker     _mov(Dest, T3);
4207*03ce13f7SAndroid Build Coastguard Worker     return;
4208*03ce13f7SAndroid Build Coastguard Worker   }
4209*03ce13f7SAndroid Build Coastguard Worker   case InstIcmp::Slt: {
4210*03ce13f7SAndroid Build Coastguard Worker     auto *T1 = I32Reg();
4211*03ce13f7SAndroid Build Coastguard Worker     auto *T2 = I32Reg();
4212*03ce13f7SAndroid Build Coastguard Worker     auto *T3 = I32Reg();
4213*03ce13f7SAndroid Build Coastguard Worker     _xor(T1, Src0HiR, Src1HiR);
4214*03ce13f7SAndroid Build Coastguard Worker     _slt(T2, Src0HiR, Src1HiR);
4215*03ce13f7SAndroid Build Coastguard Worker     _sltu(T3, Src0LoR, Src1LoR);
4216*03ce13f7SAndroid Build Coastguard Worker     _movz(T2, T3, T1);
4217*03ce13f7SAndroid Build Coastguard Worker     _mov(Dest, T2);
4218*03ce13f7SAndroid Build Coastguard Worker     return;
4219*03ce13f7SAndroid Build Coastguard Worker   }
4220*03ce13f7SAndroid Build Coastguard Worker   case InstIcmp::Ult: {
4221*03ce13f7SAndroid Build Coastguard Worker     auto *T1 = I32Reg();
4222*03ce13f7SAndroid Build Coastguard Worker     auto *T2 = I32Reg();
4223*03ce13f7SAndroid Build Coastguard Worker     auto *T3 = I32Reg();
4224*03ce13f7SAndroid Build Coastguard Worker     _xor(T1, Src0HiR, Src1HiR);
4225*03ce13f7SAndroid Build Coastguard Worker     _sltu(T2, Src0HiR, Src1HiR);
4226*03ce13f7SAndroid Build Coastguard Worker     _sltu(T3, Src0LoR, Src1LoR);
4227*03ce13f7SAndroid Build Coastguard Worker     _movz(T2, T3, T1);
4228*03ce13f7SAndroid Build Coastguard Worker     _mov(Dest, T2);
4229*03ce13f7SAndroid Build Coastguard Worker     return;
4230*03ce13f7SAndroid Build Coastguard Worker   }
4231*03ce13f7SAndroid Build Coastguard Worker   case InstIcmp::Sle: {
4232*03ce13f7SAndroid Build Coastguard Worker     auto *T1 = I32Reg();
4233*03ce13f7SAndroid Build Coastguard Worker     auto *T2 = I32Reg();
4234*03ce13f7SAndroid Build Coastguard Worker     auto *T3 = I32Reg();
4235*03ce13f7SAndroid Build Coastguard Worker     auto *T4 = I32Reg();
4236*03ce13f7SAndroid Build Coastguard Worker     auto *T5 = I32Reg();
4237*03ce13f7SAndroid Build Coastguard Worker     _xor(T1, Src0HiR, Src1HiR);
4238*03ce13f7SAndroid Build Coastguard Worker     _slt(T2, Src1HiR, Src0HiR);
4239*03ce13f7SAndroid Build Coastguard Worker     _xori(T3, T2, 1);
4240*03ce13f7SAndroid Build Coastguard Worker     _sltu(T4, Src1LoR, Src0LoR);
4241*03ce13f7SAndroid Build Coastguard Worker     _xori(T5, T4, 1);
4242*03ce13f7SAndroid Build Coastguard Worker     _movz(T3, T5, T1);
4243*03ce13f7SAndroid Build Coastguard Worker     _mov(Dest, T3);
4244*03ce13f7SAndroid Build Coastguard Worker     return;
4245*03ce13f7SAndroid Build Coastguard Worker   }
4246*03ce13f7SAndroid Build Coastguard Worker   case InstIcmp::Ule: {
4247*03ce13f7SAndroid Build Coastguard Worker     auto *T1 = I32Reg();
4248*03ce13f7SAndroid Build Coastguard Worker     auto *T2 = I32Reg();
4249*03ce13f7SAndroid Build Coastguard Worker     auto *T3 = I32Reg();
4250*03ce13f7SAndroid Build Coastguard Worker     auto *T4 = I32Reg();
4251*03ce13f7SAndroid Build Coastguard Worker     auto *T5 = I32Reg();
4252*03ce13f7SAndroid Build Coastguard Worker     _xor(T1, Src0HiR, Src1HiR);
4253*03ce13f7SAndroid Build Coastguard Worker     _sltu(T2, Src1HiR, Src0HiR);
4254*03ce13f7SAndroid Build Coastguard Worker     _xori(T3, T2, 1);
4255*03ce13f7SAndroid Build Coastguard Worker     _sltu(T4, Src1LoR, Src0LoR);
4256*03ce13f7SAndroid Build Coastguard Worker     _xori(T5, T4, 1);
4257*03ce13f7SAndroid Build Coastguard Worker     _movz(T3, T5, T1);
4258*03ce13f7SAndroid Build Coastguard Worker     _mov(Dest, T3);
4259*03ce13f7SAndroid Build Coastguard Worker     return;
4260*03ce13f7SAndroid Build Coastguard Worker   }
4261*03ce13f7SAndroid Build Coastguard Worker   }
4262*03ce13f7SAndroid Build Coastguard Worker }
4263*03ce13f7SAndroid Build Coastguard Worker 
lowerIcmp(const InstIcmp * Instr)4264*03ce13f7SAndroid Build Coastguard Worker void TargetMIPS32::lowerIcmp(const InstIcmp *Instr) {
4265*03ce13f7SAndroid Build Coastguard Worker   auto *Src0 = Instr->getSrc(0);
4266*03ce13f7SAndroid Build Coastguard Worker   auto *Src1 = Instr->getSrc(1);
4267*03ce13f7SAndroid Build Coastguard Worker   if (Src0->getType() == IceType_i64) {
4268*03ce13f7SAndroid Build Coastguard Worker     lower64Icmp(Instr);
4269*03ce13f7SAndroid Build Coastguard Worker     return;
4270*03ce13f7SAndroid Build Coastguard Worker   }
4271*03ce13f7SAndroid Build Coastguard Worker   Variable *Dest = Instr->getDest();
4272*03ce13f7SAndroid Build Coastguard Worker   if (isVectorType(Dest->getType())) {
4273*03ce13f7SAndroid Build Coastguard Worker     llvm::report_fatal_error("Icmp: Destination type is vector");
4274*03ce13f7SAndroid Build Coastguard Worker     return;
4275*03ce13f7SAndroid Build Coastguard Worker   }
4276*03ce13f7SAndroid Build Coastguard Worker   InstIcmp::ICond Cond = Instr->getCondition();
4277*03ce13f7SAndroid Build Coastguard Worker   auto *Src0R = legalizeToReg(Src0);
4278*03ce13f7SAndroid Build Coastguard Worker   auto *Src1R = legalizeToReg(Src1);
4279*03ce13f7SAndroid Build Coastguard Worker   const Type Src0Ty = Src0R->getType();
4280*03ce13f7SAndroid Build Coastguard Worker   const uint32_t ShAmt = INT32_BITS - getScalarIntBitWidth(Src0->getType());
4281*03ce13f7SAndroid Build Coastguard Worker   Variable *Src0RT = I32Reg();
4282*03ce13f7SAndroid Build Coastguard Worker   Variable *Src1RT = I32Reg();
4283*03ce13f7SAndroid Build Coastguard Worker 
4284*03ce13f7SAndroid Build Coastguard Worker   if (Src0Ty != IceType_i32) {
4285*03ce13f7SAndroid Build Coastguard Worker     _sll(Src0RT, Src0R, ShAmt);
4286*03ce13f7SAndroid Build Coastguard Worker     _sll(Src1RT, Src1R, ShAmt);
4287*03ce13f7SAndroid Build Coastguard Worker   } else {
4288*03ce13f7SAndroid Build Coastguard Worker     _mov(Src0RT, Src0R);
4289*03ce13f7SAndroid Build Coastguard Worker     _mov(Src1RT, Src1R);
4290*03ce13f7SAndroid Build Coastguard Worker   }
4291*03ce13f7SAndroid Build Coastguard Worker 
4292*03ce13f7SAndroid Build Coastguard Worker   switch (Cond) {
4293*03ce13f7SAndroid Build Coastguard Worker   case InstIcmp::Eq: {
4294*03ce13f7SAndroid Build Coastguard Worker     auto *DestT = I32Reg();
4295*03ce13f7SAndroid Build Coastguard Worker     auto *T = I32Reg();
4296*03ce13f7SAndroid Build Coastguard Worker     _xor(T, Src0RT, Src1RT);
4297*03ce13f7SAndroid Build Coastguard Worker     _sltiu(DestT, T, 1);
4298*03ce13f7SAndroid Build Coastguard Worker     _mov(Dest, DestT);
4299*03ce13f7SAndroid Build Coastguard Worker     return;
4300*03ce13f7SAndroid Build Coastguard Worker   }
4301*03ce13f7SAndroid Build Coastguard Worker   case InstIcmp::Ne: {
4302*03ce13f7SAndroid Build Coastguard Worker     auto *DestT = I32Reg();
4303*03ce13f7SAndroid Build Coastguard Worker     auto *T = I32Reg();
4304*03ce13f7SAndroid Build Coastguard Worker     auto *Zero = getZero();
4305*03ce13f7SAndroid Build Coastguard Worker     _xor(T, Src0RT, Src1RT);
4306*03ce13f7SAndroid Build Coastguard Worker     _sltu(DestT, Zero, T);
4307*03ce13f7SAndroid Build Coastguard Worker     _mov(Dest, DestT);
4308*03ce13f7SAndroid Build Coastguard Worker     return;
4309*03ce13f7SAndroid Build Coastguard Worker   }
4310*03ce13f7SAndroid Build Coastguard Worker   case InstIcmp::Ugt: {
4311*03ce13f7SAndroid Build Coastguard Worker     auto *DestT = I32Reg();
4312*03ce13f7SAndroid Build Coastguard Worker     _sltu(DestT, Src1RT, Src0RT);
4313*03ce13f7SAndroid Build Coastguard Worker     _mov(Dest, DestT);
4314*03ce13f7SAndroid Build Coastguard Worker     return;
4315*03ce13f7SAndroid Build Coastguard Worker   }
4316*03ce13f7SAndroid Build Coastguard Worker   case InstIcmp::Uge: {
4317*03ce13f7SAndroid Build Coastguard Worker     auto *DestT = I32Reg();
4318*03ce13f7SAndroid Build Coastguard Worker     auto *T = I32Reg();
4319*03ce13f7SAndroid Build Coastguard Worker     _sltu(T, Src0RT, Src1RT);
4320*03ce13f7SAndroid Build Coastguard Worker     _xori(DestT, T, 1);
4321*03ce13f7SAndroid Build Coastguard Worker     _mov(Dest, DestT);
4322*03ce13f7SAndroid Build Coastguard Worker     return;
4323*03ce13f7SAndroid Build Coastguard Worker   }
4324*03ce13f7SAndroid Build Coastguard Worker   case InstIcmp::Ult: {
4325*03ce13f7SAndroid Build Coastguard Worker     auto *DestT = I32Reg();
4326*03ce13f7SAndroid Build Coastguard Worker     _sltu(DestT, Src0RT, Src1RT);
4327*03ce13f7SAndroid Build Coastguard Worker     _mov(Dest, DestT);
4328*03ce13f7SAndroid Build Coastguard Worker     return;
4329*03ce13f7SAndroid Build Coastguard Worker   }
4330*03ce13f7SAndroid Build Coastguard Worker   case InstIcmp::Ule: {
4331*03ce13f7SAndroid Build Coastguard Worker     auto *DestT = I32Reg();
4332*03ce13f7SAndroid Build Coastguard Worker     auto *T = I32Reg();
4333*03ce13f7SAndroid Build Coastguard Worker     _sltu(T, Src1RT, Src0RT);
4334*03ce13f7SAndroid Build Coastguard Worker     _xori(DestT, T, 1);
4335*03ce13f7SAndroid Build Coastguard Worker     _mov(Dest, DestT);
4336*03ce13f7SAndroid Build Coastguard Worker     return;
4337*03ce13f7SAndroid Build Coastguard Worker   }
4338*03ce13f7SAndroid Build Coastguard Worker   case InstIcmp::Sgt: {
4339*03ce13f7SAndroid Build Coastguard Worker     auto *DestT = I32Reg();
4340*03ce13f7SAndroid Build Coastguard Worker     _slt(DestT, Src1RT, Src0RT);
4341*03ce13f7SAndroid Build Coastguard Worker     _mov(Dest, DestT);
4342*03ce13f7SAndroid Build Coastguard Worker     return;
4343*03ce13f7SAndroid Build Coastguard Worker   }
4344*03ce13f7SAndroid Build Coastguard Worker   case InstIcmp::Sge: {
4345*03ce13f7SAndroid Build Coastguard Worker     auto *DestT = I32Reg();
4346*03ce13f7SAndroid Build Coastguard Worker     auto *T = I32Reg();
4347*03ce13f7SAndroid Build Coastguard Worker     _slt(T, Src0RT, Src1RT);
4348*03ce13f7SAndroid Build Coastguard Worker     _xori(DestT, T, 1);
4349*03ce13f7SAndroid Build Coastguard Worker     _mov(Dest, DestT);
4350*03ce13f7SAndroid Build Coastguard Worker     return;
4351*03ce13f7SAndroid Build Coastguard Worker   }
4352*03ce13f7SAndroid Build Coastguard Worker   case InstIcmp::Slt: {
4353*03ce13f7SAndroid Build Coastguard Worker     auto *DestT = I32Reg();
4354*03ce13f7SAndroid Build Coastguard Worker     _slt(DestT, Src0RT, Src1RT);
4355*03ce13f7SAndroid Build Coastguard Worker     _mov(Dest, DestT);
4356*03ce13f7SAndroid Build Coastguard Worker     return;
4357*03ce13f7SAndroid Build Coastguard Worker   }
4358*03ce13f7SAndroid Build Coastguard Worker   case InstIcmp::Sle: {
4359*03ce13f7SAndroid Build Coastguard Worker     auto *DestT = I32Reg();
4360*03ce13f7SAndroid Build Coastguard Worker     auto *T = I32Reg();
4361*03ce13f7SAndroid Build Coastguard Worker     _slt(T, Src1RT, Src0RT);
4362*03ce13f7SAndroid Build Coastguard Worker     _xori(DestT, T, 1);
4363*03ce13f7SAndroid Build Coastguard Worker     _mov(Dest, DestT);
4364*03ce13f7SAndroid Build Coastguard Worker     return;
4365*03ce13f7SAndroid Build Coastguard Worker   }
4366*03ce13f7SAndroid Build Coastguard Worker   default:
4367*03ce13f7SAndroid Build Coastguard Worker     llvm_unreachable("Invalid ICmp operator");
4368*03ce13f7SAndroid Build Coastguard Worker     return;
4369*03ce13f7SAndroid Build Coastguard Worker   }
4370*03ce13f7SAndroid Build Coastguard Worker }
4371*03ce13f7SAndroid Build Coastguard Worker 
lowerInsertElement(const InstInsertElement * Instr)4372*03ce13f7SAndroid Build Coastguard Worker void TargetMIPS32::lowerInsertElement(const InstInsertElement *Instr) {
4373*03ce13f7SAndroid Build Coastguard Worker   Variable *Dest = Instr->getDest();
4374*03ce13f7SAndroid Build Coastguard Worker   const Type DestTy = Dest->getType();
4375*03ce13f7SAndroid Build Coastguard Worker   Operand *Src2 = Instr->getSrc(2);
4376*03ce13f7SAndroid Build Coastguard Worker   if (const auto *Imm = llvm::dyn_cast<ConstantInteger32>(Src2)) {
4377*03ce13f7SAndroid Build Coastguard Worker     const uint32_t Index = Imm->getValue();
4378*03ce13f7SAndroid Build Coastguard Worker     // Vector to insert in
4379*03ce13f7SAndroid Build Coastguard Worker     auto *Src0 = legalizeUndef(Instr->getSrc(0));
4380*03ce13f7SAndroid Build Coastguard Worker     auto *Src0R = llvm::dyn_cast<VariableVecOn32>(Src0);
4381*03ce13f7SAndroid Build Coastguard Worker     // Number of elements in each container
4382*03ce13f7SAndroid Build Coastguard Worker     uint32_t ElemPerCont =
4383*03ce13f7SAndroid Build Coastguard Worker         typeNumElements(Src0->getType()) / Src0R->ContainersPerVector;
4384*03ce13f7SAndroid Build Coastguard Worker     // Source Element
4385*03ce13f7SAndroid Build Coastguard Worker     auto *Src = Src0R->getContainers()[Index / ElemPerCont];
4386*03ce13f7SAndroid Build Coastguard Worker     auto *SrcE = Src;
4387*03ce13f7SAndroid Build Coastguard Worker     if (ElemPerCont > 1)
4388*03ce13f7SAndroid Build Coastguard Worker       SrcE = legalizeToReg(Src);
4389*03ce13f7SAndroid Build Coastguard Worker     // Dest is a vector
4390*03ce13f7SAndroid Build Coastguard Worker     auto *VDest = llvm::dyn_cast<VariableVecOn32>(Dest);
4391*03ce13f7SAndroid Build Coastguard Worker     VDest->initVecElement(Func);
4392*03ce13f7SAndroid Build Coastguard Worker     // Temp vector variable
4393*03ce13f7SAndroid Build Coastguard Worker     auto *TDest = makeReg(DestTy);
4394*03ce13f7SAndroid Build Coastguard Worker     auto *TVDest = llvm::dyn_cast<VariableVecOn32>(TDest);
4395*03ce13f7SAndroid Build Coastguard Worker     TVDest->initVecElement(Func);
4396*03ce13f7SAndroid Build Coastguard Worker     // Destination element
4397*03ce13f7SAndroid Build Coastguard Worker     auto *DstE = TVDest->getContainers()[Index / ElemPerCont];
4398*03ce13f7SAndroid Build Coastguard Worker     // Element to insert
4399*03ce13f7SAndroid Build Coastguard Worker     auto *Src1R = legalizeToReg(Instr->getSrc(1));
4400*03ce13f7SAndroid Build Coastguard Worker     auto *TReg1 = makeReg(IceType_i32);
4401*03ce13f7SAndroid Build Coastguard Worker     auto *TReg2 = makeReg(IceType_i32);
4402*03ce13f7SAndroid Build Coastguard Worker     auto *TReg3 = makeReg(IceType_i32);
4403*03ce13f7SAndroid Build Coastguard Worker     auto *TReg4 = makeReg(IceType_i32);
4404*03ce13f7SAndroid Build Coastguard Worker     auto *TReg5 = makeReg(IceType_i32);
4405*03ce13f7SAndroid Build Coastguard Worker     auto *TDReg = makeReg(IceType_i32);
4406*03ce13f7SAndroid Build Coastguard Worker     // Position of the element in the container
4407*03ce13f7SAndroid Build Coastguard Worker     uint32_t PosInCont = Index % ElemPerCont;
4408*03ce13f7SAndroid Build Coastguard Worker     // Load source vector in a temporary vector
4409*03ce13f7SAndroid Build Coastguard Worker     for (SizeT i = 0; i < TVDest->ContainersPerVector; ++i) {
4410*03ce13f7SAndroid Build Coastguard Worker       auto *DCont = TVDest->getContainers()[i];
4411*03ce13f7SAndroid Build Coastguard Worker       // Do not define DstE as we are going to redefine it
4412*03ce13f7SAndroid Build Coastguard Worker       if (DCont == DstE)
4413*03ce13f7SAndroid Build Coastguard Worker         continue;
4414*03ce13f7SAndroid Build Coastguard Worker       auto *SCont = Src0R->getContainers()[i];
4415*03ce13f7SAndroid Build Coastguard Worker       auto *TReg = makeReg(IceType_i32);
4416*03ce13f7SAndroid Build Coastguard Worker       _mov(TReg, SCont);
4417*03ce13f7SAndroid Build Coastguard Worker       _mov(DCont, TReg);
4418*03ce13f7SAndroid Build Coastguard Worker     }
4419*03ce13f7SAndroid Build Coastguard Worker     // Insert the element
4420*03ce13f7SAndroid Build Coastguard Worker     if (ElemPerCont == 1) {
4421*03ce13f7SAndroid Build Coastguard Worker       _mov(DstE, Src1R);
4422*03ce13f7SAndroid Build Coastguard Worker     } else if (ElemPerCont == 2) {
4423*03ce13f7SAndroid Build Coastguard Worker       switch (PosInCont) {
4424*03ce13f7SAndroid Build Coastguard Worker       case 0:
4425*03ce13f7SAndroid Build Coastguard Worker         _andi(TReg1, Src1R, 0xffff); // Clear upper 16-bits of source
4426*03ce13f7SAndroid Build Coastguard Worker         _srl(TReg2, SrcE, 16);
4427*03ce13f7SAndroid Build Coastguard Worker         _sll(TReg3, TReg2, 16); // Clear lower 16-bits of element
4428*03ce13f7SAndroid Build Coastguard Worker         _or(TDReg, TReg1, TReg3);
4429*03ce13f7SAndroid Build Coastguard Worker         _mov(DstE, TDReg);
4430*03ce13f7SAndroid Build Coastguard Worker         break;
4431*03ce13f7SAndroid Build Coastguard Worker       case 1:
4432*03ce13f7SAndroid Build Coastguard Worker         _sll(TReg1, Src1R, 16); // Clear lower 16-bits  of source
4433*03ce13f7SAndroid Build Coastguard Worker         _sll(TReg2, SrcE, 16);
4434*03ce13f7SAndroid Build Coastguard Worker         _srl(TReg3, TReg2, 16); // Clear upper 16-bits of element
4435*03ce13f7SAndroid Build Coastguard Worker         _or(TDReg, TReg1, TReg3);
4436*03ce13f7SAndroid Build Coastguard Worker         _mov(DstE, TDReg);
4437*03ce13f7SAndroid Build Coastguard Worker         break;
4438*03ce13f7SAndroid Build Coastguard Worker       default:
4439*03ce13f7SAndroid Build Coastguard Worker         llvm::report_fatal_error("InsertElement: Invalid PosInCont");
4440*03ce13f7SAndroid Build Coastguard Worker         break;
4441*03ce13f7SAndroid Build Coastguard Worker       }
4442*03ce13f7SAndroid Build Coastguard Worker     } else if (ElemPerCont == 4) {
4443*03ce13f7SAndroid Build Coastguard Worker       switch (PosInCont) {
4444*03ce13f7SAndroid Build Coastguard Worker       case 0:
4445*03ce13f7SAndroid Build Coastguard Worker         _andi(TReg1, Src1R, 0xff); // Clear bits[31:8] of source
4446*03ce13f7SAndroid Build Coastguard Worker         _srl(TReg2, SrcE, 8);
4447*03ce13f7SAndroid Build Coastguard Worker         _sll(TReg3, TReg2, 8); // Clear bits[7:0] of element
4448*03ce13f7SAndroid Build Coastguard Worker         _or(TDReg, TReg1, TReg3);
4449*03ce13f7SAndroid Build Coastguard Worker         _mov(DstE, TDReg);
4450*03ce13f7SAndroid Build Coastguard Worker         break;
4451*03ce13f7SAndroid Build Coastguard Worker       case 1:
4452*03ce13f7SAndroid Build Coastguard Worker         _andi(TReg1, Src1R, 0xff); // Clear bits[31:8] of source
4453*03ce13f7SAndroid Build Coastguard Worker         _sll(TReg5, TReg1, 8);     // Position in the destination
4454*03ce13f7SAndroid Build Coastguard Worker         _lui(TReg2, Ctx->getConstantInt32(0xffff));
4455*03ce13f7SAndroid Build Coastguard Worker         _ori(TReg3, TReg2, 0x00ff);
4456*03ce13f7SAndroid Build Coastguard Worker         _and(TReg4, SrcE, TReg3); // Clear bits[15:8] of element
4457*03ce13f7SAndroid Build Coastguard Worker         _or(TDReg, TReg5, TReg4);
4458*03ce13f7SAndroid Build Coastguard Worker         _mov(DstE, TDReg);
4459*03ce13f7SAndroid Build Coastguard Worker         break;
4460*03ce13f7SAndroid Build Coastguard Worker       case 2:
4461*03ce13f7SAndroid Build Coastguard Worker         _andi(TReg1, Src1R, 0xff); // Clear bits[31:8] of source
4462*03ce13f7SAndroid Build Coastguard Worker         _sll(TReg5, TReg1, 16);    // Position in the destination
4463*03ce13f7SAndroid Build Coastguard Worker         _lui(TReg2, Ctx->getConstantInt32(0xff00));
4464*03ce13f7SAndroid Build Coastguard Worker         _ori(TReg3, TReg2, 0xffff);
4465*03ce13f7SAndroid Build Coastguard Worker         _and(TReg4, SrcE, TReg3); // Clear bits[15:8] of element
4466*03ce13f7SAndroid Build Coastguard Worker         _or(TDReg, TReg5, TReg4);
4467*03ce13f7SAndroid Build Coastguard Worker         _mov(DstE, TDReg);
4468*03ce13f7SAndroid Build Coastguard Worker         break;
4469*03ce13f7SAndroid Build Coastguard Worker       case 3:
4470*03ce13f7SAndroid Build Coastguard Worker         _sll(TReg1, Src1R, 24); // Position in the destination
4471*03ce13f7SAndroid Build Coastguard Worker         _sll(TReg2, SrcE, 8);
4472*03ce13f7SAndroid Build Coastguard Worker         _srl(TReg3, TReg2, 8); // Clear bits[31:24] of element
4473*03ce13f7SAndroid Build Coastguard Worker         _or(TDReg, TReg1, TReg3);
4474*03ce13f7SAndroid Build Coastguard Worker         _mov(DstE, TDReg);
4475*03ce13f7SAndroid Build Coastguard Worker         break;
4476*03ce13f7SAndroid Build Coastguard Worker       default:
4477*03ce13f7SAndroid Build Coastguard Worker         llvm::report_fatal_error("InsertElement: Invalid PosInCont");
4478*03ce13f7SAndroid Build Coastguard Worker         break;
4479*03ce13f7SAndroid Build Coastguard Worker       }
4480*03ce13f7SAndroid Build Coastguard Worker     }
4481*03ce13f7SAndroid Build Coastguard Worker     // Write back temporary vector to the destination
4482*03ce13f7SAndroid Build Coastguard Worker     auto *Assign = InstAssign::create(Func, Dest, TDest);
4483*03ce13f7SAndroid Build Coastguard Worker     lowerAssign(Assign);
4484*03ce13f7SAndroid Build Coastguard Worker     return;
4485*03ce13f7SAndroid Build Coastguard Worker   }
4486*03ce13f7SAndroid Build Coastguard Worker   llvm::report_fatal_error("InsertElement requires a constant index");
4487*03ce13f7SAndroid Build Coastguard Worker }
4488*03ce13f7SAndroid Build Coastguard Worker 
createArithInst(Intrinsics::AtomicRMWOperation Operation,Variable * Dest,Variable * Src0,Variable * Src1)4489*03ce13f7SAndroid Build Coastguard Worker void TargetMIPS32::createArithInst(Intrinsics::AtomicRMWOperation Operation,
4490*03ce13f7SAndroid Build Coastguard Worker                                    Variable *Dest, Variable *Src0,
4491*03ce13f7SAndroid Build Coastguard Worker                                    Variable *Src1) {
4492*03ce13f7SAndroid Build Coastguard Worker   switch (Operation) {
4493*03ce13f7SAndroid Build Coastguard Worker   default:
4494*03ce13f7SAndroid Build Coastguard Worker     llvm::report_fatal_error("Unknown AtomicRMW operation");
4495*03ce13f7SAndroid Build Coastguard Worker   case Intrinsics::AtomicExchange:
4496*03ce13f7SAndroid Build Coastguard Worker     llvm::report_fatal_error("Can't handle Atomic xchg operation");
4497*03ce13f7SAndroid Build Coastguard Worker   case Intrinsics::AtomicAdd:
4498*03ce13f7SAndroid Build Coastguard Worker     _addu(Dest, Src0, Src1);
4499*03ce13f7SAndroid Build Coastguard Worker     break;
4500*03ce13f7SAndroid Build Coastguard Worker   case Intrinsics::AtomicAnd:
4501*03ce13f7SAndroid Build Coastguard Worker     _and(Dest, Src0, Src1);
4502*03ce13f7SAndroid Build Coastguard Worker     break;
4503*03ce13f7SAndroid Build Coastguard Worker   case Intrinsics::AtomicSub:
4504*03ce13f7SAndroid Build Coastguard Worker     _subu(Dest, Src0, Src1);
4505*03ce13f7SAndroid Build Coastguard Worker     break;
4506*03ce13f7SAndroid Build Coastguard Worker   case Intrinsics::AtomicOr:
4507*03ce13f7SAndroid Build Coastguard Worker     _or(Dest, Src0, Src1);
4508*03ce13f7SAndroid Build Coastguard Worker     break;
4509*03ce13f7SAndroid Build Coastguard Worker   case Intrinsics::AtomicXor:
4510*03ce13f7SAndroid Build Coastguard Worker     _xor(Dest, Src0, Src1);
4511*03ce13f7SAndroid Build Coastguard Worker     break;
4512*03ce13f7SAndroid Build Coastguard Worker   }
4513*03ce13f7SAndroid Build Coastguard Worker }
4514*03ce13f7SAndroid Build Coastguard Worker 
lowerIntrinsic(const InstIntrinsic * Instr)4515*03ce13f7SAndroid Build Coastguard Worker void TargetMIPS32::lowerIntrinsic(const InstIntrinsic *Instr) {
4516*03ce13f7SAndroid Build Coastguard Worker   Variable *Dest = Instr->getDest();
4517*03ce13f7SAndroid Build Coastguard Worker   Type DestTy = (Dest == nullptr) ? IceType_void : Dest->getType();
4518*03ce13f7SAndroid Build Coastguard Worker 
4519*03ce13f7SAndroid Build Coastguard Worker   Intrinsics::IntrinsicID ID = Instr->getIntrinsicID();
4520*03ce13f7SAndroid Build Coastguard Worker   switch (ID) {
4521*03ce13f7SAndroid Build Coastguard Worker   case Intrinsics::AtomicLoad: {
4522*03ce13f7SAndroid Build Coastguard Worker     assert(isScalarIntegerType(DestTy));
4523*03ce13f7SAndroid Build Coastguard Worker     // We require the memory address to be naturally aligned. Given that is the
4524*03ce13f7SAndroid Build Coastguard Worker     // case, then normal loads are atomic.
4525*03ce13f7SAndroid Build Coastguard Worker     if (!Intrinsics::isMemoryOrderValid(
4526*03ce13f7SAndroid Build Coastguard Worker             ID, getConstantMemoryOrder(Instr->getArg(1)))) {
4527*03ce13f7SAndroid Build Coastguard Worker       Func->setError("Unexpected memory ordering for AtomicLoad");
4528*03ce13f7SAndroid Build Coastguard Worker       return;
4529*03ce13f7SAndroid Build Coastguard Worker     }
4530*03ce13f7SAndroid Build Coastguard Worker     if (DestTy == IceType_i64) {
4531*03ce13f7SAndroid Build Coastguard Worker       llvm::report_fatal_error("AtomicLoad.i64 should have been prelowered.");
4532*03ce13f7SAndroid Build Coastguard Worker       return;
4533*03ce13f7SAndroid Build Coastguard Worker     } else if (DestTy == IceType_i32) {
4534*03ce13f7SAndroid Build Coastguard Worker       auto *T1 = makeReg(DestTy);
4535*03ce13f7SAndroid Build Coastguard Worker       auto *RegAt = getPhysicalRegister(RegMIPS32::Reg_AT);
4536*03ce13f7SAndroid Build Coastguard Worker       auto *Base = legalizeToReg(Instr->getArg(0));
4537*03ce13f7SAndroid Build Coastguard Worker       auto *Addr = formMemoryOperand(Base, DestTy);
4538*03ce13f7SAndroid Build Coastguard Worker       InstMIPS32Label *Retry = InstMIPS32Label::create(Func, this);
4539*03ce13f7SAndroid Build Coastguard Worker       InstMIPS32Label *Exit = InstMIPS32Label::create(Func, this);
4540*03ce13f7SAndroid Build Coastguard Worker       constexpr CfgNode *NoTarget = nullptr;
4541*03ce13f7SAndroid Build Coastguard Worker       _sync();
4542*03ce13f7SAndroid Build Coastguard Worker       Context.insert(Retry);
4543*03ce13f7SAndroid Build Coastguard Worker       _ll(T1, Addr);
4544*03ce13f7SAndroid Build Coastguard Worker       _br(NoTarget, NoTarget, T1, getZero(), Exit, CondMIPS32::Cond::NE);
4545*03ce13f7SAndroid Build Coastguard Worker       _addiu(RegAt, getZero(), 0); // Loaded value is zero here, writeback zero
4546*03ce13f7SAndroid Build Coastguard Worker       _sc(RegAt, Addr);
4547*03ce13f7SAndroid Build Coastguard Worker       _br(NoTarget, NoTarget, RegAt, getZero(), Retry, CondMIPS32::Cond::EQ);
4548*03ce13f7SAndroid Build Coastguard Worker       Context.insert(Exit);
4549*03ce13f7SAndroid Build Coastguard Worker       _sync();
4550*03ce13f7SAndroid Build Coastguard Worker       _mov(Dest, T1);
4551*03ce13f7SAndroid Build Coastguard Worker       Context.insert<InstFakeUse>(T1);
4552*03ce13f7SAndroid Build Coastguard Worker     } else {
4553*03ce13f7SAndroid Build Coastguard Worker       const uint32_t Mask = (1 << (CHAR_BITS * typeWidthInBytes(DestTy))) - 1;
4554*03ce13f7SAndroid Build Coastguard Worker       auto *Base = legalizeToReg(Instr->getArg(0));
4555*03ce13f7SAndroid Build Coastguard Worker       auto *T1 = makeReg(IceType_i32);
4556*03ce13f7SAndroid Build Coastguard Worker       auto *T2 = makeReg(IceType_i32);
4557*03ce13f7SAndroid Build Coastguard Worker       auto *T3 = makeReg(IceType_i32);
4558*03ce13f7SAndroid Build Coastguard Worker       auto *T4 = makeReg(IceType_i32);
4559*03ce13f7SAndroid Build Coastguard Worker       auto *T5 = makeReg(IceType_i32);
4560*03ce13f7SAndroid Build Coastguard Worker       auto *T6 = makeReg(IceType_i32);
4561*03ce13f7SAndroid Build Coastguard Worker       auto *SrcMask = makeReg(IceType_i32);
4562*03ce13f7SAndroid Build Coastguard Worker       auto *Tdest = makeReg(IceType_i32);
4563*03ce13f7SAndroid Build Coastguard Worker       auto *RegAt = getPhysicalRegister(RegMIPS32::Reg_AT);
4564*03ce13f7SAndroid Build Coastguard Worker       InstMIPS32Label *Retry = InstMIPS32Label::create(Func, this);
4565*03ce13f7SAndroid Build Coastguard Worker       InstMIPS32Label *Exit = InstMIPS32Label::create(Func, this);
4566*03ce13f7SAndroid Build Coastguard Worker       constexpr CfgNode *NoTarget = nullptr;
4567*03ce13f7SAndroid Build Coastguard Worker       _sync();
4568*03ce13f7SAndroid Build Coastguard Worker       _addiu(T1, getZero(), -4); // Address mask 0xFFFFFFFC
4569*03ce13f7SAndroid Build Coastguard Worker       _andi(T2, Base, 3);        // Last two bits of the address
4570*03ce13f7SAndroid Build Coastguard Worker       _and(T3, Base, T1);        // Align the address
4571*03ce13f7SAndroid Build Coastguard Worker       _sll(T4, T2, 3);
4572*03ce13f7SAndroid Build Coastguard Worker       _ori(T5, getZero(), Mask);
4573*03ce13f7SAndroid Build Coastguard Worker       _sllv(SrcMask, T5, T4); // Source mask
4574*03ce13f7SAndroid Build Coastguard Worker       auto *Addr = formMemoryOperand(T3, IceType_i32);
4575*03ce13f7SAndroid Build Coastguard Worker       Context.insert(Retry);
4576*03ce13f7SAndroid Build Coastguard Worker       _ll(T6, Addr);
4577*03ce13f7SAndroid Build Coastguard Worker       _and(Tdest, T6, SrcMask);
4578*03ce13f7SAndroid Build Coastguard Worker       _br(NoTarget, NoTarget, T6, getZero(), Exit, CondMIPS32::Cond::NE);
4579*03ce13f7SAndroid Build Coastguard Worker       _addiu(RegAt, getZero(), 0); // Loaded value is zero here, writeback zero
4580*03ce13f7SAndroid Build Coastguard Worker       _sc(RegAt, Addr);
4581*03ce13f7SAndroid Build Coastguard Worker       _br(NoTarget, NoTarget, RegAt, getZero(), Retry, CondMIPS32::Cond::EQ);
4582*03ce13f7SAndroid Build Coastguard Worker       Context.insert(Exit);
4583*03ce13f7SAndroid Build Coastguard Worker       auto *T7 = makeReg(IceType_i32);
4584*03ce13f7SAndroid Build Coastguard Worker       auto *T8 = makeReg(IceType_i32);
4585*03ce13f7SAndroid Build Coastguard Worker       _srlv(T7, Tdest, T4);
4586*03ce13f7SAndroid Build Coastguard Worker       _andi(T8, T7, Mask);
4587*03ce13f7SAndroid Build Coastguard Worker       _sync();
4588*03ce13f7SAndroid Build Coastguard Worker       _mov(Dest, T8);
4589*03ce13f7SAndroid Build Coastguard Worker       Context.insert<InstFakeUse>(T6);
4590*03ce13f7SAndroid Build Coastguard Worker       Context.insert<InstFakeUse>(SrcMask);
4591*03ce13f7SAndroid Build Coastguard Worker     }
4592*03ce13f7SAndroid Build Coastguard Worker     return;
4593*03ce13f7SAndroid Build Coastguard Worker   }
4594*03ce13f7SAndroid Build Coastguard Worker   case Intrinsics::AtomicStore: {
4595*03ce13f7SAndroid Build Coastguard Worker     // We require the memory address to be naturally aligned. Given that is the
4596*03ce13f7SAndroid Build Coastguard Worker     // case, then normal stores are atomic.
4597*03ce13f7SAndroid Build Coastguard Worker     if (!Intrinsics::isMemoryOrderValid(
4598*03ce13f7SAndroid Build Coastguard Worker             ID, getConstantMemoryOrder(Instr->getArg(2)))) {
4599*03ce13f7SAndroid Build Coastguard Worker       Func->setError("Unexpected memory ordering for AtomicStore");
4600*03ce13f7SAndroid Build Coastguard Worker       return;
4601*03ce13f7SAndroid Build Coastguard Worker     }
4602*03ce13f7SAndroid Build Coastguard Worker     auto *Val = Instr->getArg(0);
4603*03ce13f7SAndroid Build Coastguard Worker     auto Ty = Val->getType();
4604*03ce13f7SAndroid Build Coastguard Worker     if (Ty == IceType_i64) {
4605*03ce13f7SAndroid Build Coastguard Worker       llvm::report_fatal_error("AtomicStore.i64 should have been prelowered.");
4606*03ce13f7SAndroid Build Coastguard Worker       return;
4607*03ce13f7SAndroid Build Coastguard Worker     } else if (Ty == IceType_i32) {
4608*03ce13f7SAndroid Build Coastguard Worker       auto *Val = legalizeToReg(Instr->getArg(0));
4609*03ce13f7SAndroid Build Coastguard Worker       auto *Base = legalizeToReg(Instr->getArg(1));
4610*03ce13f7SAndroid Build Coastguard Worker       auto *Addr = formMemoryOperand(Base, Ty);
4611*03ce13f7SAndroid Build Coastguard Worker       InstMIPS32Label *Retry = InstMIPS32Label::create(Func, this);
4612*03ce13f7SAndroid Build Coastguard Worker       constexpr CfgNode *NoTarget = nullptr;
4613*03ce13f7SAndroid Build Coastguard Worker       auto *T1 = makeReg(IceType_i32);
4614*03ce13f7SAndroid Build Coastguard Worker       auto *RegAt = getPhysicalRegister(RegMIPS32::Reg_AT);
4615*03ce13f7SAndroid Build Coastguard Worker       _sync();
4616*03ce13f7SAndroid Build Coastguard Worker       Context.insert(Retry);
4617*03ce13f7SAndroid Build Coastguard Worker       _ll(T1, Addr);
4618*03ce13f7SAndroid Build Coastguard Worker       _mov(RegAt, Val);
4619*03ce13f7SAndroid Build Coastguard Worker       _sc(RegAt, Addr);
4620*03ce13f7SAndroid Build Coastguard Worker       _br(NoTarget, NoTarget, RegAt, getZero(), Retry, CondMIPS32::Cond::EQ);
4621*03ce13f7SAndroid Build Coastguard Worker       Context.insert<InstFakeUse>(T1); // To keep LL alive
4622*03ce13f7SAndroid Build Coastguard Worker       _sync();
4623*03ce13f7SAndroid Build Coastguard Worker     } else {
4624*03ce13f7SAndroid Build Coastguard Worker       auto *Val = legalizeToReg(Instr->getArg(0));
4625*03ce13f7SAndroid Build Coastguard Worker       auto *Base = legalizeToReg(Instr->getArg(1));
4626*03ce13f7SAndroid Build Coastguard Worker       InstMIPS32Label *Retry = InstMIPS32Label::create(Func, this);
4627*03ce13f7SAndroid Build Coastguard Worker       constexpr CfgNode *NoTarget = nullptr;
4628*03ce13f7SAndroid Build Coastguard Worker       auto *T1 = makeReg(IceType_i32);
4629*03ce13f7SAndroid Build Coastguard Worker       auto *T2 = makeReg(IceType_i32);
4630*03ce13f7SAndroid Build Coastguard Worker       auto *T3 = makeReg(IceType_i32);
4631*03ce13f7SAndroid Build Coastguard Worker       auto *T4 = makeReg(IceType_i32);
4632*03ce13f7SAndroid Build Coastguard Worker       auto *T5 = makeReg(IceType_i32);
4633*03ce13f7SAndroid Build Coastguard Worker       auto *T6 = makeReg(IceType_i32);
4634*03ce13f7SAndroid Build Coastguard Worker       auto *T7 = makeReg(IceType_i32);
4635*03ce13f7SAndroid Build Coastguard Worker       auto *RegAt = getPhysicalRegister(RegMIPS32::Reg_AT);
4636*03ce13f7SAndroid Build Coastguard Worker       auto *SrcMask = makeReg(IceType_i32);
4637*03ce13f7SAndroid Build Coastguard Worker       auto *DstMask = makeReg(IceType_i32);
4638*03ce13f7SAndroid Build Coastguard Worker       const uint32_t Mask = (1 << (CHAR_BITS * typeWidthInBytes(Ty))) - 1;
4639*03ce13f7SAndroid Build Coastguard Worker       _sync();
4640*03ce13f7SAndroid Build Coastguard Worker       _addiu(T1, getZero(), -4);
4641*03ce13f7SAndroid Build Coastguard Worker       _and(T7, Base, T1);
4642*03ce13f7SAndroid Build Coastguard Worker       auto *Addr = formMemoryOperand(T7, Ty);
4643*03ce13f7SAndroid Build Coastguard Worker       _andi(T2, Base, 3);
4644*03ce13f7SAndroid Build Coastguard Worker       _sll(T3, T2, 3);
4645*03ce13f7SAndroid Build Coastguard Worker       _ori(T4, getZero(), Mask);
4646*03ce13f7SAndroid Build Coastguard Worker       _sllv(T5, T4, T3);
4647*03ce13f7SAndroid Build Coastguard Worker       _sllv(T6, Val, T3);
4648*03ce13f7SAndroid Build Coastguard Worker       _nor(SrcMask, getZero(), T5);
4649*03ce13f7SAndroid Build Coastguard Worker       _and(DstMask, T6, T5);
4650*03ce13f7SAndroid Build Coastguard Worker       Context.insert(Retry);
4651*03ce13f7SAndroid Build Coastguard Worker       _ll(RegAt, Addr);
4652*03ce13f7SAndroid Build Coastguard Worker       _and(RegAt, RegAt, SrcMask);
4653*03ce13f7SAndroid Build Coastguard Worker       _or(RegAt, RegAt, DstMask);
4654*03ce13f7SAndroid Build Coastguard Worker       _sc(RegAt, Addr);
4655*03ce13f7SAndroid Build Coastguard Worker       _br(NoTarget, NoTarget, RegAt, getZero(), Retry, CondMIPS32::Cond::EQ);
4656*03ce13f7SAndroid Build Coastguard Worker       Context.insert<InstFakeUse>(SrcMask);
4657*03ce13f7SAndroid Build Coastguard Worker       Context.insert<InstFakeUse>(DstMask);
4658*03ce13f7SAndroid Build Coastguard Worker       _sync();
4659*03ce13f7SAndroid Build Coastguard Worker     }
4660*03ce13f7SAndroid Build Coastguard Worker     return;
4661*03ce13f7SAndroid Build Coastguard Worker   }
4662*03ce13f7SAndroid Build Coastguard Worker   case Intrinsics::AtomicCmpxchg: {
4663*03ce13f7SAndroid Build Coastguard Worker     assert(isScalarIntegerType(DestTy));
4664*03ce13f7SAndroid Build Coastguard Worker     // We require the memory address to be naturally aligned. Given that is the
4665*03ce13f7SAndroid Build Coastguard Worker     // case, then normal loads are atomic.
4666*03ce13f7SAndroid Build Coastguard Worker     if (!Intrinsics::isMemoryOrderValid(
4667*03ce13f7SAndroid Build Coastguard Worker             ID, getConstantMemoryOrder(Instr->getArg(3)),
4668*03ce13f7SAndroid Build Coastguard Worker             getConstantMemoryOrder(Instr->getArg(4)))) {
4669*03ce13f7SAndroid Build Coastguard Worker       Func->setError("Unexpected memory ordering for AtomicCmpxchg");
4670*03ce13f7SAndroid Build Coastguard Worker       return;
4671*03ce13f7SAndroid Build Coastguard Worker     }
4672*03ce13f7SAndroid Build Coastguard Worker 
4673*03ce13f7SAndroid Build Coastguard Worker     InstMIPS32Label *Exit = InstMIPS32Label::create(Func, this);
4674*03ce13f7SAndroid Build Coastguard Worker     InstMIPS32Label *Retry = InstMIPS32Label::create(Func, this);
4675*03ce13f7SAndroid Build Coastguard Worker     constexpr CfgNode *NoTarget = nullptr;
4676*03ce13f7SAndroid Build Coastguard Worker     auto *New = Instr->getArg(2);
4677*03ce13f7SAndroid Build Coastguard Worker     auto *Expected = Instr->getArg(1);
4678*03ce13f7SAndroid Build Coastguard Worker     auto *ActualAddress = Instr->getArg(0);
4679*03ce13f7SAndroid Build Coastguard Worker 
4680*03ce13f7SAndroid Build Coastguard Worker     if (DestTy == IceType_i64) {
4681*03ce13f7SAndroid Build Coastguard Worker       llvm::report_fatal_error(
4682*03ce13f7SAndroid Build Coastguard Worker           "AtomicCmpxchg.i64 should have been prelowered.");
4683*03ce13f7SAndroid Build Coastguard Worker       return;
4684*03ce13f7SAndroid Build Coastguard Worker     } else if (DestTy == IceType_i8 || DestTy == IceType_i16) {
4685*03ce13f7SAndroid Build Coastguard Worker       auto *NewR = legalizeToReg(New);
4686*03ce13f7SAndroid Build Coastguard Worker       auto *ExpectedR = legalizeToReg(Expected);
4687*03ce13f7SAndroid Build Coastguard Worker       auto *ActualAddressR = legalizeToReg(ActualAddress);
4688*03ce13f7SAndroid Build Coastguard Worker       const uint32_t ShiftAmount =
4689*03ce13f7SAndroid Build Coastguard Worker           (INT32_BITS - CHAR_BITS * typeWidthInBytes(DestTy));
4690*03ce13f7SAndroid Build Coastguard Worker       const uint32_t Mask = (1 << (CHAR_BITS * typeWidthInBytes(DestTy))) - 1;
4691*03ce13f7SAndroid Build Coastguard Worker       auto *RegAt = getPhysicalRegister(RegMIPS32::Reg_AT);
4692*03ce13f7SAndroid Build Coastguard Worker       auto *T1 = I32Reg();
4693*03ce13f7SAndroid Build Coastguard Worker       auto *T2 = I32Reg();
4694*03ce13f7SAndroid Build Coastguard Worker       auto *T3 = I32Reg();
4695*03ce13f7SAndroid Build Coastguard Worker       auto *T4 = I32Reg();
4696*03ce13f7SAndroid Build Coastguard Worker       auto *T5 = I32Reg();
4697*03ce13f7SAndroid Build Coastguard Worker       auto *T6 = I32Reg();
4698*03ce13f7SAndroid Build Coastguard Worker       auto *T7 = I32Reg();
4699*03ce13f7SAndroid Build Coastguard Worker       auto *T8 = I32Reg();
4700*03ce13f7SAndroid Build Coastguard Worker       auto *T9 = I32Reg();
4701*03ce13f7SAndroid Build Coastguard Worker       _addiu(RegAt, getZero(), -4);
4702*03ce13f7SAndroid Build Coastguard Worker       _and(T1, ActualAddressR, RegAt);
4703*03ce13f7SAndroid Build Coastguard Worker       auto *Addr = formMemoryOperand(T1, DestTy);
4704*03ce13f7SAndroid Build Coastguard Worker       _andi(RegAt, ActualAddressR, 3);
4705*03ce13f7SAndroid Build Coastguard Worker       _sll(T2, RegAt, 3);
4706*03ce13f7SAndroid Build Coastguard Worker       _ori(RegAt, getZero(), Mask);
4707*03ce13f7SAndroid Build Coastguard Worker       _sllv(T3, RegAt, T2);
4708*03ce13f7SAndroid Build Coastguard Worker       _nor(T4, getZero(), T3);
4709*03ce13f7SAndroid Build Coastguard Worker       _andi(RegAt, ExpectedR, Mask);
4710*03ce13f7SAndroid Build Coastguard Worker       _sllv(T5, RegAt, T2);
4711*03ce13f7SAndroid Build Coastguard Worker       _andi(RegAt, NewR, Mask);
4712*03ce13f7SAndroid Build Coastguard Worker       _sllv(T6, RegAt, T2);
4713*03ce13f7SAndroid Build Coastguard Worker       _sync();
4714*03ce13f7SAndroid Build Coastguard Worker       Context.insert(Retry);
4715*03ce13f7SAndroid Build Coastguard Worker       _ll(T7, Addr);
4716*03ce13f7SAndroid Build Coastguard Worker       _and(T8, T7, T3);
4717*03ce13f7SAndroid Build Coastguard Worker       _br(NoTarget, NoTarget, T8, T5, Exit, CondMIPS32::Cond::NE);
4718*03ce13f7SAndroid Build Coastguard Worker       _and(RegAt, T7, T4);
4719*03ce13f7SAndroid Build Coastguard Worker       _or(T9, RegAt, T6);
4720*03ce13f7SAndroid Build Coastguard Worker       _sc(T9, Addr);
4721*03ce13f7SAndroid Build Coastguard Worker       _br(NoTarget, NoTarget, getZero(), T9, Retry, CondMIPS32::Cond::EQ);
4722*03ce13f7SAndroid Build Coastguard Worker       Context.insert<InstFakeUse>(getZero());
4723*03ce13f7SAndroid Build Coastguard Worker       Context.insert(Exit);
4724*03ce13f7SAndroid Build Coastguard Worker       _srlv(RegAt, T8, T2);
4725*03ce13f7SAndroid Build Coastguard Worker       _sll(RegAt, RegAt, ShiftAmount);
4726*03ce13f7SAndroid Build Coastguard Worker       _sra(RegAt, RegAt, ShiftAmount);
4727*03ce13f7SAndroid Build Coastguard Worker       _mov(Dest, RegAt);
4728*03ce13f7SAndroid Build Coastguard Worker       _sync();
4729*03ce13f7SAndroid Build Coastguard Worker       Context.insert<InstFakeUse>(T3);
4730*03ce13f7SAndroid Build Coastguard Worker       Context.insert<InstFakeUse>(T4);
4731*03ce13f7SAndroid Build Coastguard Worker       Context.insert<InstFakeUse>(T5);
4732*03ce13f7SAndroid Build Coastguard Worker       Context.insert<InstFakeUse>(T6);
4733*03ce13f7SAndroid Build Coastguard Worker       Context.insert<InstFakeUse>(T8);
4734*03ce13f7SAndroid Build Coastguard Worker       Context.insert<InstFakeUse>(ExpectedR);
4735*03ce13f7SAndroid Build Coastguard Worker       Context.insert<InstFakeUse>(NewR);
4736*03ce13f7SAndroid Build Coastguard Worker     } else {
4737*03ce13f7SAndroid Build Coastguard Worker       auto *T1 = I32Reg();
4738*03ce13f7SAndroid Build Coastguard Worker       auto *T2 = I32Reg();
4739*03ce13f7SAndroid Build Coastguard Worker       auto *NewR = legalizeToReg(New);
4740*03ce13f7SAndroid Build Coastguard Worker       auto *ExpectedR = legalizeToReg(Expected);
4741*03ce13f7SAndroid Build Coastguard Worker       auto *ActualAddressR = legalizeToReg(ActualAddress);
4742*03ce13f7SAndroid Build Coastguard Worker       _sync();
4743*03ce13f7SAndroid Build Coastguard Worker       Context.insert(Retry);
4744*03ce13f7SAndroid Build Coastguard Worker       _ll(T1, formMemoryOperand(ActualAddressR, DestTy));
4745*03ce13f7SAndroid Build Coastguard Worker       _br(NoTarget, NoTarget, T1, ExpectedR, Exit, CondMIPS32::Cond::NE);
4746*03ce13f7SAndroid Build Coastguard Worker       _mov(T2, NewR);
4747*03ce13f7SAndroid Build Coastguard Worker       _sc(T2, formMemoryOperand(ActualAddressR, DestTy));
4748*03ce13f7SAndroid Build Coastguard Worker       _br(NoTarget, NoTarget, T2, getZero(), Retry, CondMIPS32::Cond::EQ);
4749*03ce13f7SAndroid Build Coastguard Worker       Context.insert<InstFakeUse>(getZero());
4750*03ce13f7SAndroid Build Coastguard Worker       Context.insert(Exit);
4751*03ce13f7SAndroid Build Coastguard Worker       _mov(Dest, T1);
4752*03ce13f7SAndroid Build Coastguard Worker       _sync();
4753*03ce13f7SAndroid Build Coastguard Worker       Context.insert<InstFakeUse>(ExpectedR);
4754*03ce13f7SAndroid Build Coastguard Worker       Context.insert<InstFakeUse>(NewR);
4755*03ce13f7SAndroid Build Coastguard Worker     }
4756*03ce13f7SAndroid Build Coastguard Worker     return;
4757*03ce13f7SAndroid Build Coastguard Worker   }
4758*03ce13f7SAndroid Build Coastguard Worker   case Intrinsics::AtomicRMW: {
4759*03ce13f7SAndroid Build Coastguard Worker     assert(isScalarIntegerType(DestTy));
4760*03ce13f7SAndroid Build Coastguard Worker     // We require the memory address to be naturally aligned. Given that is the
4761*03ce13f7SAndroid Build Coastguard Worker     // case, then normal loads are atomic.
4762*03ce13f7SAndroid Build Coastguard Worker     if (!Intrinsics::isMemoryOrderValid(
4763*03ce13f7SAndroid Build Coastguard Worker             ID, getConstantMemoryOrder(Instr->getArg(3)))) {
4764*03ce13f7SAndroid Build Coastguard Worker       Func->setError("Unexpected memory ordering for AtomicRMW");
4765*03ce13f7SAndroid Build Coastguard Worker       return;
4766*03ce13f7SAndroid Build Coastguard Worker     }
4767*03ce13f7SAndroid Build Coastguard Worker 
4768*03ce13f7SAndroid Build Coastguard Worker     constexpr CfgNode *NoTarget = nullptr;
4769*03ce13f7SAndroid Build Coastguard Worker     InstMIPS32Label *Retry = InstMIPS32Label::create(Func, this);
4770*03ce13f7SAndroid Build Coastguard Worker     auto Operation = static_cast<Intrinsics::AtomicRMWOperation>(
4771*03ce13f7SAndroid Build Coastguard Worker         llvm::cast<ConstantInteger32>(Instr->getArg(0))->getValue());
4772*03ce13f7SAndroid Build Coastguard Worker     auto *New = Instr->getArg(2);
4773*03ce13f7SAndroid Build Coastguard Worker     auto *ActualAddress = Instr->getArg(1);
4774*03ce13f7SAndroid Build Coastguard Worker 
4775*03ce13f7SAndroid Build Coastguard Worker     if (DestTy == IceType_i64) {
4776*03ce13f7SAndroid Build Coastguard Worker       llvm::report_fatal_error("AtomicRMW.i64 should have been prelowered.");
4777*03ce13f7SAndroid Build Coastguard Worker       return;
4778*03ce13f7SAndroid Build Coastguard Worker     } else if (DestTy == IceType_i8 || DestTy == IceType_i16) {
4779*03ce13f7SAndroid Build Coastguard Worker       const uint32_t ShiftAmount =
4780*03ce13f7SAndroid Build Coastguard Worker           INT32_BITS - (CHAR_BITS * typeWidthInBytes(DestTy));
4781*03ce13f7SAndroid Build Coastguard Worker       const uint32_t Mask = (1 << (CHAR_BITS * typeWidthInBytes(DestTy))) - 1;
4782*03ce13f7SAndroid Build Coastguard Worker       auto *NewR = legalizeToReg(New);
4783*03ce13f7SAndroid Build Coastguard Worker       auto *ActualAddressR = legalizeToReg(ActualAddress);
4784*03ce13f7SAndroid Build Coastguard Worker       auto *RegAt = getPhysicalRegister(RegMIPS32::Reg_AT);
4785*03ce13f7SAndroid Build Coastguard Worker       auto *T1 = I32Reg();
4786*03ce13f7SAndroid Build Coastguard Worker       auto *T2 = I32Reg();
4787*03ce13f7SAndroid Build Coastguard Worker       auto *T3 = I32Reg();
4788*03ce13f7SAndroid Build Coastguard Worker       auto *T4 = I32Reg();
4789*03ce13f7SAndroid Build Coastguard Worker       auto *T5 = I32Reg();
4790*03ce13f7SAndroid Build Coastguard Worker       auto *T6 = I32Reg();
4791*03ce13f7SAndroid Build Coastguard Worker       auto *T7 = I32Reg();
4792*03ce13f7SAndroid Build Coastguard Worker       _sync();
4793*03ce13f7SAndroid Build Coastguard Worker       _addiu(RegAt, getZero(), -4);
4794*03ce13f7SAndroid Build Coastguard Worker       _and(T1, ActualAddressR, RegAt);
4795*03ce13f7SAndroid Build Coastguard Worker       _andi(RegAt, ActualAddressR, 3);
4796*03ce13f7SAndroid Build Coastguard Worker       _sll(T2, RegAt, 3);
4797*03ce13f7SAndroid Build Coastguard Worker       _ori(RegAt, getZero(), Mask);
4798*03ce13f7SAndroid Build Coastguard Worker       _sllv(T3, RegAt, T2);
4799*03ce13f7SAndroid Build Coastguard Worker       _nor(T4, getZero(), T3);
4800*03ce13f7SAndroid Build Coastguard Worker       _sllv(T5, NewR, T2);
4801*03ce13f7SAndroid Build Coastguard Worker       Context.insert(Retry);
4802*03ce13f7SAndroid Build Coastguard Worker       _ll(T6, formMemoryOperand(T1, DestTy));
4803*03ce13f7SAndroid Build Coastguard Worker       if (Operation != Intrinsics::AtomicExchange) {
4804*03ce13f7SAndroid Build Coastguard Worker         createArithInst(Operation, RegAt, T6, T5);
4805*03ce13f7SAndroid Build Coastguard Worker         _and(RegAt, RegAt, T3);
4806*03ce13f7SAndroid Build Coastguard Worker       }
4807*03ce13f7SAndroid Build Coastguard Worker       _and(T7, T6, T4);
4808*03ce13f7SAndroid Build Coastguard Worker       if (Operation == Intrinsics::AtomicExchange) {
4809*03ce13f7SAndroid Build Coastguard Worker         _or(RegAt, T7, T5);
4810*03ce13f7SAndroid Build Coastguard Worker       } else {
4811*03ce13f7SAndroid Build Coastguard Worker         _or(RegAt, T7, RegAt);
4812*03ce13f7SAndroid Build Coastguard Worker       }
4813*03ce13f7SAndroid Build Coastguard Worker       _sc(RegAt, formMemoryOperand(T1, DestTy));
4814*03ce13f7SAndroid Build Coastguard Worker       _br(NoTarget, NoTarget, RegAt, getZero(), Retry, CondMIPS32::Cond::EQ);
4815*03ce13f7SAndroid Build Coastguard Worker       Context.insert<InstFakeUse>(getZero());
4816*03ce13f7SAndroid Build Coastguard Worker       _and(RegAt, T6, T3);
4817*03ce13f7SAndroid Build Coastguard Worker       _srlv(RegAt, RegAt, T2);
4818*03ce13f7SAndroid Build Coastguard Worker       _sll(RegAt, RegAt, ShiftAmount);
4819*03ce13f7SAndroid Build Coastguard Worker       _sra(RegAt, RegAt, ShiftAmount);
4820*03ce13f7SAndroid Build Coastguard Worker       _mov(Dest, RegAt);
4821*03ce13f7SAndroid Build Coastguard Worker       _sync();
4822*03ce13f7SAndroid Build Coastguard Worker       Context.insert<InstFakeUse>(NewR);
4823*03ce13f7SAndroid Build Coastguard Worker       Context.insert<InstFakeUse>(Dest);
4824*03ce13f7SAndroid Build Coastguard Worker     } else {
4825*03ce13f7SAndroid Build Coastguard Worker       auto *T1 = I32Reg();
4826*03ce13f7SAndroid Build Coastguard Worker       auto *T2 = I32Reg();
4827*03ce13f7SAndroid Build Coastguard Worker       auto *NewR = legalizeToReg(New);
4828*03ce13f7SAndroid Build Coastguard Worker       auto *ActualAddressR = legalizeToReg(ActualAddress);
4829*03ce13f7SAndroid Build Coastguard Worker       _sync();
4830*03ce13f7SAndroid Build Coastguard Worker       Context.insert(Retry);
4831*03ce13f7SAndroid Build Coastguard Worker       _ll(T1, formMemoryOperand(ActualAddressR, DestTy));
4832*03ce13f7SAndroid Build Coastguard Worker       if (Operation == Intrinsics::AtomicExchange) {
4833*03ce13f7SAndroid Build Coastguard Worker         _mov(T2, NewR);
4834*03ce13f7SAndroid Build Coastguard Worker       } else {
4835*03ce13f7SAndroid Build Coastguard Worker         createArithInst(Operation, T2, T1, NewR);
4836*03ce13f7SAndroid Build Coastguard Worker       }
4837*03ce13f7SAndroid Build Coastguard Worker       _sc(T2, formMemoryOperand(ActualAddressR, DestTy));
4838*03ce13f7SAndroid Build Coastguard Worker       _br(NoTarget, NoTarget, T2, getZero(), Retry, CondMIPS32::Cond::EQ);
4839*03ce13f7SAndroid Build Coastguard Worker       Context.insert<InstFakeUse>(getZero());
4840*03ce13f7SAndroid Build Coastguard Worker       _mov(Dest, T1);
4841*03ce13f7SAndroid Build Coastguard Worker       _sync();
4842*03ce13f7SAndroid Build Coastguard Worker       Context.insert<InstFakeUse>(NewR);
4843*03ce13f7SAndroid Build Coastguard Worker       Context.insert<InstFakeUse>(Dest);
4844*03ce13f7SAndroid Build Coastguard Worker     }
4845*03ce13f7SAndroid Build Coastguard Worker     return;
4846*03ce13f7SAndroid Build Coastguard Worker   }
4847*03ce13f7SAndroid Build Coastguard Worker   case Intrinsics::AtomicFence:
4848*03ce13f7SAndroid Build Coastguard Worker   case Intrinsics::AtomicFenceAll:
4849*03ce13f7SAndroid Build Coastguard Worker     assert(Dest == nullptr);
4850*03ce13f7SAndroid Build Coastguard Worker     _sync();
4851*03ce13f7SAndroid Build Coastguard Worker     return;
4852*03ce13f7SAndroid Build Coastguard Worker   case Intrinsics::AtomicIsLockFree: {
4853*03ce13f7SAndroid Build Coastguard Worker     Operand *ByteSize = Instr->getArg(0);
4854*03ce13f7SAndroid Build Coastguard Worker     auto *CI = llvm::dyn_cast<ConstantInteger32>(ByteSize);
4855*03ce13f7SAndroid Build Coastguard Worker     auto *T = I32Reg();
4856*03ce13f7SAndroid Build Coastguard Worker     if (CI == nullptr) {
4857*03ce13f7SAndroid Build Coastguard Worker       // The PNaCl ABI requires the byte size to be a compile-time constant.
4858*03ce13f7SAndroid Build Coastguard Worker       Func->setError("AtomicIsLockFree byte size should be compile-time const");
4859*03ce13f7SAndroid Build Coastguard Worker       return;
4860*03ce13f7SAndroid Build Coastguard Worker     }
4861*03ce13f7SAndroid Build Coastguard Worker     static constexpr int32_t NotLockFree = 0;
4862*03ce13f7SAndroid Build Coastguard Worker     static constexpr int32_t LockFree = 1;
4863*03ce13f7SAndroid Build Coastguard Worker     int32_t Result = NotLockFree;
4864*03ce13f7SAndroid Build Coastguard Worker     switch (CI->getValue()) {
4865*03ce13f7SAndroid Build Coastguard Worker     case 1:
4866*03ce13f7SAndroid Build Coastguard Worker     case 2:
4867*03ce13f7SAndroid Build Coastguard Worker     case 4:
4868*03ce13f7SAndroid Build Coastguard Worker       Result = LockFree;
4869*03ce13f7SAndroid Build Coastguard Worker       break;
4870*03ce13f7SAndroid Build Coastguard Worker     }
4871*03ce13f7SAndroid Build Coastguard Worker     _addiu(T, getZero(), Result);
4872*03ce13f7SAndroid Build Coastguard Worker     _mov(Dest, T);
4873*03ce13f7SAndroid Build Coastguard Worker     return;
4874*03ce13f7SAndroid Build Coastguard Worker   }
4875*03ce13f7SAndroid Build Coastguard Worker   case Intrinsics::Bswap: {
4876*03ce13f7SAndroid Build Coastguard Worker     auto *Src = Instr->getArg(0);
4877*03ce13f7SAndroid Build Coastguard Worker     const Type SrcTy = Src->getType();
4878*03ce13f7SAndroid Build Coastguard Worker     assert(SrcTy == IceType_i16 || SrcTy == IceType_i32 ||
4879*03ce13f7SAndroid Build Coastguard Worker            SrcTy == IceType_i64);
4880*03ce13f7SAndroid Build Coastguard Worker     switch (SrcTy) {
4881*03ce13f7SAndroid Build Coastguard Worker     case IceType_i16: {
4882*03ce13f7SAndroid Build Coastguard Worker       auto *T1 = I32Reg();
4883*03ce13f7SAndroid Build Coastguard Worker       auto *T2 = I32Reg();
4884*03ce13f7SAndroid Build Coastguard Worker       auto *T3 = I32Reg();
4885*03ce13f7SAndroid Build Coastguard Worker       auto *T4 = I32Reg();
4886*03ce13f7SAndroid Build Coastguard Worker       auto *SrcR = legalizeToReg(Src);
4887*03ce13f7SAndroid Build Coastguard Worker       _sll(T1, SrcR, 8);
4888*03ce13f7SAndroid Build Coastguard Worker       _lui(T2, Ctx->getConstantInt32(255));
4889*03ce13f7SAndroid Build Coastguard Worker       _and(T1, T1, T2);
4890*03ce13f7SAndroid Build Coastguard Worker       _sll(T3, SrcR, 24);
4891*03ce13f7SAndroid Build Coastguard Worker       _or(T1, T3, T1);
4892*03ce13f7SAndroid Build Coastguard Worker       _srl(T4, T1, 16);
4893*03ce13f7SAndroid Build Coastguard Worker       _mov(Dest, T4);
4894*03ce13f7SAndroid Build Coastguard Worker       return;
4895*03ce13f7SAndroid Build Coastguard Worker     }
4896*03ce13f7SAndroid Build Coastguard Worker     case IceType_i32: {
4897*03ce13f7SAndroid Build Coastguard Worker       auto *T1 = I32Reg();
4898*03ce13f7SAndroid Build Coastguard Worker       auto *T2 = I32Reg();
4899*03ce13f7SAndroid Build Coastguard Worker       auto *T3 = I32Reg();
4900*03ce13f7SAndroid Build Coastguard Worker       auto *T4 = I32Reg();
4901*03ce13f7SAndroid Build Coastguard Worker       auto *T5 = I32Reg();
4902*03ce13f7SAndroid Build Coastguard Worker       auto *SrcR = legalizeToReg(Src);
4903*03ce13f7SAndroid Build Coastguard Worker       _srl(T1, SrcR, 24);
4904*03ce13f7SAndroid Build Coastguard Worker       _srl(T2, SrcR, 8);
4905*03ce13f7SAndroid Build Coastguard Worker       _andi(T2, T2, 0xFF00);
4906*03ce13f7SAndroid Build Coastguard Worker       _or(T1, T2, T1);
4907*03ce13f7SAndroid Build Coastguard Worker       _sll(T4, SrcR, 8);
4908*03ce13f7SAndroid Build Coastguard Worker       _lui(T3, Ctx->getConstantInt32(255));
4909*03ce13f7SAndroid Build Coastguard Worker       _and(T4, T4, T3);
4910*03ce13f7SAndroid Build Coastguard Worker       _sll(T5, SrcR, 24);
4911*03ce13f7SAndroid Build Coastguard Worker       _or(T4, T5, T4);
4912*03ce13f7SAndroid Build Coastguard Worker       _or(T4, T4, T1);
4913*03ce13f7SAndroid Build Coastguard Worker       _mov(Dest, T4);
4914*03ce13f7SAndroid Build Coastguard Worker       return;
4915*03ce13f7SAndroid Build Coastguard Worker     }
4916*03ce13f7SAndroid Build Coastguard Worker     case IceType_i64: {
4917*03ce13f7SAndroid Build Coastguard Worker       auto *T1 = I32Reg();
4918*03ce13f7SAndroid Build Coastguard Worker       auto *T2 = I32Reg();
4919*03ce13f7SAndroid Build Coastguard Worker       auto *T3 = I32Reg();
4920*03ce13f7SAndroid Build Coastguard Worker       auto *T4 = I32Reg();
4921*03ce13f7SAndroid Build Coastguard Worker       auto *T5 = I32Reg();
4922*03ce13f7SAndroid Build Coastguard Worker       auto *T6 = I32Reg();
4923*03ce13f7SAndroid Build Coastguard Worker       auto *T7 = I32Reg();
4924*03ce13f7SAndroid Build Coastguard Worker       auto *T8 = I32Reg();
4925*03ce13f7SAndroid Build Coastguard Worker       auto *T9 = I32Reg();
4926*03ce13f7SAndroid Build Coastguard Worker       auto *T10 = I32Reg();
4927*03ce13f7SAndroid Build Coastguard Worker       auto *T11 = I32Reg();
4928*03ce13f7SAndroid Build Coastguard Worker       auto *T12 = I32Reg();
4929*03ce13f7SAndroid Build Coastguard Worker       auto *T13 = I32Reg();
4930*03ce13f7SAndroid Build Coastguard Worker       auto *T14 = I32Reg();
4931*03ce13f7SAndroid Build Coastguard Worker       auto *T15 = I32Reg();
4932*03ce13f7SAndroid Build Coastguard Worker       auto *T16 = I32Reg();
4933*03ce13f7SAndroid Build Coastguard Worker       auto *T17 = I32Reg();
4934*03ce13f7SAndroid Build Coastguard Worker       auto *T18 = I32Reg();
4935*03ce13f7SAndroid Build Coastguard Worker       auto *DestLo = llvm::cast<Variable>(loOperand(Dest));
4936*03ce13f7SAndroid Build Coastguard Worker       auto *DestHi = llvm::cast<Variable>(hiOperand(Dest));
4937*03ce13f7SAndroid Build Coastguard Worker       Src = legalizeUndef(Src);
4938*03ce13f7SAndroid Build Coastguard Worker       auto *SrcLoR = legalizeToReg(loOperand(Src));
4939*03ce13f7SAndroid Build Coastguard Worker       auto *SrcHiR = legalizeToReg(hiOperand(Src));
4940*03ce13f7SAndroid Build Coastguard Worker       _sll(T1, SrcHiR, 8);
4941*03ce13f7SAndroid Build Coastguard Worker       _srl(T2, SrcHiR, 24);
4942*03ce13f7SAndroid Build Coastguard Worker       _srl(T3, SrcHiR, 8);
4943*03ce13f7SAndroid Build Coastguard Worker       _andi(T3, T3, 0xFF00);
4944*03ce13f7SAndroid Build Coastguard Worker       _lui(T4, Ctx->getConstantInt32(255));
4945*03ce13f7SAndroid Build Coastguard Worker       _or(T5, T3, T2);
4946*03ce13f7SAndroid Build Coastguard Worker       _and(T6, T1, T4);
4947*03ce13f7SAndroid Build Coastguard Worker       _sll(T7, SrcHiR, 24);
4948*03ce13f7SAndroid Build Coastguard Worker       _or(T8, T7, T6);
4949*03ce13f7SAndroid Build Coastguard Worker       _srl(T9, SrcLoR, 24);
4950*03ce13f7SAndroid Build Coastguard Worker       _srl(T10, SrcLoR, 8);
4951*03ce13f7SAndroid Build Coastguard Worker       _andi(T11, T10, 0xFF00);
4952*03ce13f7SAndroid Build Coastguard Worker       _or(T12, T8, T5);
4953*03ce13f7SAndroid Build Coastguard Worker       _or(T13, T11, T9);
4954*03ce13f7SAndroid Build Coastguard Worker       _sll(T14, SrcLoR, 8);
4955*03ce13f7SAndroid Build Coastguard Worker       _and(T15, T14, T4);
4956*03ce13f7SAndroid Build Coastguard Worker       _sll(T16, SrcLoR, 24);
4957*03ce13f7SAndroid Build Coastguard Worker       _or(T17, T16, T15);
4958*03ce13f7SAndroid Build Coastguard Worker       _or(T18, T17, T13);
4959*03ce13f7SAndroid Build Coastguard Worker       _mov(DestLo, T12);
4960*03ce13f7SAndroid Build Coastguard Worker       _mov(DestHi, T18);
4961*03ce13f7SAndroid Build Coastguard Worker       return;
4962*03ce13f7SAndroid Build Coastguard Worker     }
4963*03ce13f7SAndroid Build Coastguard Worker     default:
4964*03ce13f7SAndroid Build Coastguard Worker       llvm::report_fatal_error("Control flow should never have reached here.");
4965*03ce13f7SAndroid Build Coastguard Worker     }
4966*03ce13f7SAndroid Build Coastguard Worker     return;
4967*03ce13f7SAndroid Build Coastguard Worker   }
4968*03ce13f7SAndroid Build Coastguard Worker   case Intrinsics::Ctpop: {
4969*03ce13f7SAndroid Build Coastguard Worker     llvm::report_fatal_error("Ctpop should have been prelowered.");
4970*03ce13f7SAndroid Build Coastguard Worker     return;
4971*03ce13f7SAndroid Build Coastguard Worker   }
4972*03ce13f7SAndroid Build Coastguard Worker   case Intrinsics::Ctlz: {
4973*03ce13f7SAndroid Build Coastguard Worker     auto *Src = Instr->getArg(0);
4974*03ce13f7SAndroid Build Coastguard Worker     const Type SrcTy = Src->getType();
4975*03ce13f7SAndroid Build Coastguard Worker     assert(SrcTy == IceType_i32 || SrcTy == IceType_i64);
4976*03ce13f7SAndroid Build Coastguard Worker     switch (SrcTy) {
4977*03ce13f7SAndroid Build Coastguard Worker     case IceType_i32: {
4978*03ce13f7SAndroid Build Coastguard Worker       auto *T = I32Reg();
4979*03ce13f7SAndroid Build Coastguard Worker       auto *SrcR = legalizeToReg(Src);
4980*03ce13f7SAndroid Build Coastguard Worker       _clz(T, SrcR);
4981*03ce13f7SAndroid Build Coastguard Worker       _mov(Dest, T);
4982*03ce13f7SAndroid Build Coastguard Worker       break;
4983*03ce13f7SAndroid Build Coastguard Worker     }
4984*03ce13f7SAndroid Build Coastguard Worker     case IceType_i64: {
4985*03ce13f7SAndroid Build Coastguard Worker       auto *T1 = I32Reg();
4986*03ce13f7SAndroid Build Coastguard Worker       auto *T2 = I32Reg();
4987*03ce13f7SAndroid Build Coastguard Worker       auto *T3 = I32Reg();
4988*03ce13f7SAndroid Build Coastguard Worker       auto *T4 = I32Reg();
4989*03ce13f7SAndroid Build Coastguard Worker       auto *DestLo = llvm::cast<Variable>(loOperand(Dest));
4990*03ce13f7SAndroid Build Coastguard Worker       auto *DestHi = llvm::cast<Variable>(hiOperand(Dest));
4991*03ce13f7SAndroid Build Coastguard Worker       Variable *SrcHiR = legalizeToReg(hiOperand(Src));
4992*03ce13f7SAndroid Build Coastguard Worker       Variable *SrcLoR = legalizeToReg(loOperand(Src));
4993*03ce13f7SAndroid Build Coastguard Worker       _clz(T1, SrcHiR);
4994*03ce13f7SAndroid Build Coastguard Worker       _clz(T2, SrcLoR);
4995*03ce13f7SAndroid Build Coastguard Worker       _addiu(T3, T2, 32);
4996*03ce13f7SAndroid Build Coastguard Worker       _movn(T3, T1, SrcHiR);
4997*03ce13f7SAndroid Build Coastguard Worker       _addiu(T4, getZero(), 0);
4998*03ce13f7SAndroid Build Coastguard Worker       _mov(DestHi, T4);
4999*03ce13f7SAndroid Build Coastguard Worker       _mov(DestLo, T3);
5000*03ce13f7SAndroid Build Coastguard Worker       break;
5001*03ce13f7SAndroid Build Coastguard Worker     }
5002*03ce13f7SAndroid Build Coastguard Worker     default:
5003*03ce13f7SAndroid Build Coastguard Worker       llvm::report_fatal_error("Control flow should never have reached here.");
5004*03ce13f7SAndroid Build Coastguard Worker     }
5005*03ce13f7SAndroid Build Coastguard Worker     break;
5006*03ce13f7SAndroid Build Coastguard Worker   }
5007*03ce13f7SAndroid Build Coastguard Worker   case Intrinsics::Cttz: {
5008*03ce13f7SAndroid Build Coastguard Worker     auto *Src = Instr->getArg(0);
5009*03ce13f7SAndroid Build Coastguard Worker     const Type SrcTy = Src->getType();
5010*03ce13f7SAndroid Build Coastguard Worker     assert(SrcTy == IceType_i32 || SrcTy == IceType_i64);
5011*03ce13f7SAndroid Build Coastguard Worker     switch (SrcTy) {
5012*03ce13f7SAndroid Build Coastguard Worker     case IceType_i32: {
5013*03ce13f7SAndroid Build Coastguard Worker       auto *T1 = I32Reg();
5014*03ce13f7SAndroid Build Coastguard Worker       auto *T2 = I32Reg();
5015*03ce13f7SAndroid Build Coastguard Worker       auto *T3 = I32Reg();
5016*03ce13f7SAndroid Build Coastguard Worker       auto *T4 = I32Reg();
5017*03ce13f7SAndroid Build Coastguard Worker       auto *T5 = I32Reg();
5018*03ce13f7SAndroid Build Coastguard Worker       auto *T6 = I32Reg();
5019*03ce13f7SAndroid Build Coastguard Worker       auto *SrcR = legalizeToReg(Src);
5020*03ce13f7SAndroid Build Coastguard Worker       _addiu(T1, SrcR, -1);
5021*03ce13f7SAndroid Build Coastguard Worker       _not(T2, SrcR);
5022*03ce13f7SAndroid Build Coastguard Worker       _and(T3, T2, T1);
5023*03ce13f7SAndroid Build Coastguard Worker       _clz(T4, T3);
5024*03ce13f7SAndroid Build Coastguard Worker       _addiu(T5, getZero(), 32);
5025*03ce13f7SAndroid Build Coastguard Worker       _subu(T6, T5, T4);
5026*03ce13f7SAndroid Build Coastguard Worker       _mov(Dest, T6);
5027*03ce13f7SAndroid Build Coastguard Worker       break;
5028*03ce13f7SAndroid Build Coastguard Worker     }
5029*03ce13f7SAndroid Build Coastguard Worker     case IceType_i64: {
5030*03ce13f7SAndroid Build Coastguard Worker       auto *THi1 = I32Reg();
5031*03ce13f7SAndroid Build Coastguard Worker       auto *THi2 = I32Reg();
5032*03ce13f7SAndroid Build Coastguard Worker       auto *THi3 = I32Reg();
5033*03ce13f7SAndroid Build Coastguard Worker       auto *THi4 = I32Reg();
5034*03ce13f7SAndroid Build Coastguard Worker       auto *THi5 = I32Reg();
5035*03ce13f7SAndroid Build Coastguard Worker       auto *THi6 = I32Reg();
5036*03ce13f7SAndroid Build Coastguard Worker       auto *TLo1 = I32Reg();
5037*03ce13f7SAndroid Build Coastguard Worker       auto *TLo2 = I32Reg();
5038*03ce13f7SAndroid Build Coastguard Worker       auto *TLo3 = I32Reg();
5039*03ce13f7SAndroid Build Coastguard Worker       auto *TLo4 = I32Reg();
5040*03ce13f7SAndroid Build Coastguard Worker       auto *TLo5 = I32Reg();
5041*03ce13f7SAndroid Build Coastguard Worker       auto *TLo6 = I32Reg();
5042*03ce13f7SAndroid Build Coastguard Worker       auto *TResHi = I32Reg();
5043*03ce13f7SAndroid Build Coastguard Worker       auto *DestLo = llvm::cast<Variable>(loOperand(Dest));
5044*03ce13f7SAndroid Build Coastguard Worker       auto *DestHi = llvm::cast<Variable>(hiOperand(Dest));
5045*03ce13f7SAndroid Build Coastguard Worker       Variable *SrcHiR = legalizeToReg(hiOperand(Src));
5046*03ce13f7SAndroid Build Coastguard Worker       Variable *SrcLoR = legalizeToReg(loOperand(Src));
5047*03ce13f7SAndroid Build Coastguard Worker       _addiu(THi1, SrcHiR, -1);
5048*03ce13f7SAndroid Build Coastguard Worker       _not(THi2, SrcHiR);
5049*03ce13f7SAndroid Build Coastguard Worker       _and(THi3, THi2, THi1);
5050*03ce13f7SAndroid Build Coastguard Worker       _clz(THi4, THi3);
5051*03ce13f7SAndroid Build Coastguard Worker       _addiu(THi5, getZero(), 64);
5052*03ce13f7SAndroid Build Coastguard Worker       _subu(THi6, THi5, THi4);
5053*03ce13f7SAndroid Build Coastguard Worker       _addiu(TLo1, SrcLoR, -1);
5054*03ce13f7SAndroid Build Coastguard Worker       _not(TLo2, SrcLoR);
5055*03ce13f7SAndroid Build Coastguard Worker       _and(TLo3, TLo2, TLo1);
5056*03ce13f7SAndroid Build Coastguard Worker       _clz(TLo4, TLo3);
5057*03ce13f7SAndroid Build Coastguard Worker       _addiu(TLo5, getZero(), 32);
5058*03ce13f7SAndroid Build Coastguard Worker       _subu(TLo6, TLo5, TLo4);
5059*03ce13f7SAndroid Build Coastguard Worker       _movn(THi6, TLo6, SrcLoR);
5060*03ce13f7SAndroid Build Coastguard Worker       _addiu(TResHi, getZero(), 0);
5061*03ce13f7SAndroid Build Coastguard Worker       _mov(DestHi, TResHi);
5062*03ce13f7SAndroid Build Coastguard Worker       _mov(DestLo, THi6);
5063*03ce13f7SAndroid Build Coastguard Worker       break;
5064*03ce13f7SAndroid Build Coastguard Worker     }
5065*03ce13f7SAndroid Build Coastguard Worker     default:
5066*03ce13f7SAndroid Build Coastguard Worker       llvm::report_fatal_error("Control flow should never have reached here.");
5067*03ce13f7SAndroid Build Coastguard Worker     }
5068*03ce13f7SAndroid Build Coastguard Worker     return;
5069*03ce13f7SAndroid Build Coastguard Worker   }
5070*03ce13f7SAndroid Build Coastguard Worker   case Intrinsics::Fabs: {
5071*03ce13f7SAndroid Build Coastguard Worker     if (isScalarFloatingType(DestTy)) {
5072*03ce13f7SAndroid Build Coastguard Worker       Variable *T = makeReg(DestTy);
5073*03ce13f7SAndroid Build Coastguard Worker       if (DestTy == IceType_f32) {
5074*03ce13f7SAndroid Build Coastguard Worker         _abs_s(T, legalizeToReg(Instr->getArg(0)));
5075*03ce13f7SAndroid Build Coastguard Worker       } else {
5076*03ce13f7SAndroid Build Coastguard Worker         _abs_d(T, legalizeToReg(Instr->getArg(0)));
5077*03ce13f7SAndroid Build Coastguard Worker       }
5078*03ce13f7SAndroid Build Coastguard Worker       _mov(Dest, T);
5079*03ce13f7SAndroid Build Coastguard Worker     }
5080*03ce13f7SAndroid Build Coastguard Worker     return;
5081*03ce13f7SAndroid Build Coastguard Worker   }
5082*03ce13f7SAndroid Build Coastguard Worker   case Intrinsics::Longjmp: {
5083*03ce13f7SAndroid Build Coastguard Worker     llvm::report_fatal_error("longjmp should have been prelowered.");
5084*03ce13f7SAndroid Build Coastguard Worker     return;
5085*03ce13f7SAndroid Build Coastguard Worker   }
5086*03ce13f7SAndroid Build Coastguard Worker   case Intrinsics::Memcpy: {
5087*03ce13f7SAndroid Build Coastguard Worker     llvm::report_fatal_error("memcpy should have been prelowered.");
5088*03ce13f7SAndroid Build Coastguard Worker     return;
5089*03ce13f7SAndroid Build Coastguard Worker   }
5090*03ce13f7SAndroid Build Coastguard Worker   case Intrinsics::Memmove: {
5091*03ce13f7SAndroid Build Coastguard Worker     llvm::report_fatal_error("memmove should have been prelowered.");
5092*03ce13f7SAndroid Build Coastguard Worker     return;
5093*03ce13f7SAndroid Build Coastguard Worker   }
5094*03ce13f7SAndroid Build Coastguard Worker   case Intrinsics::Memset: {
5095*03ce13f7SAndroid Build Coastguard Worker     llvm::report_fatal_error("memset should have been prelowered.");
5096*03ce13f7SAndroid Build Coastguard Worker     return;
5097*03ce13f7SAndroid Build Coastguard Worker   }
5098*03ce13f7SAndroid Build Coastguard Worker   case Intrinsics::Setjmp: {
5099*03ce13f7SAndroid Build Coastguard Worker     llvm::report_fatal_error("setjmp should have been prelowered.");
5100*03ce13f7SAndroid Build Coastguard Worker     return;
5101*03ce13f7SAndroid Build Coastguard Worker   }
5102*03ce13f7SAndroid Build Coastguard Worker   case Intrinsics::Sqrt: {
5103*03ce13f7SAndroid Build Coastguard Worker     if (isScalarFloatingType(DestTy)) {
5104*03ce13f7SAndroid Build Coastguard Worker       Variable *T = makeReg(DestTy);
5105*03ce13f7SAndroid Build Coastguard Worker       if (DestTy == IceType_f32) {
5106*03ce13f7SAndroid Build Coastguard Worker         _sqrt_s(T, legalizeToReg(Instr->getArg(0)));
5107*03ce13f7SAndroid Build Coastguard Worker       } else {
5108*03ce13f7SAndroid Build Coastguard Worker         _sqrt_d(T, legalizeToReg(Instr->getArg(0)));
5109*03ce13f7SAndroid Build Coastguard Worker       }
5110*03ce13f7SAndroid Build Coastguard Worker       _mov(Dest, T);
5111*03ce13f7SAndroid Build Coastguard Worker     } else {
5112*03ce13f7SAndroid Build Coastguard Worker       UnimplementedLoweringError(this, Instr);
5113*03ce13f7SAndroid Build Coastguard Worker     }
5114*03ce13f7SAndroid Build Coastguard Worker     return;
5115*03ce13f7SAndroid Build Coastguard Worker   }
5116*03ce13f7SAndroid Build Coastguard Worker   case Intrinsics::Stacksave: {
5117*03ce13f7SAndroid Build Coastguard Worker     Variable *SP = getPhysicalRegister(RegMIPS32::Reg_SP);
5118*03ce13f7SAndroid Build Coastguard Worker     _mov(Dest, SP);
5119*03ce13f7SAndroid Build Coastguard Worker     return;
5120*03ce13f7SAndroid Build Coastguard Worker   }
5121*03ce13f7SAndroid Build Coastguard Worker   case Intrinsics::Stackrestore: {
5122*03ce13f7SAndroid Build Coastguard Worker     Variable *SP = getPhysicalRegister(RegMIPS32::Reg_SP);
5123*03ce13f7SAndroid Build Coastguard Worker     Variable *Val = legalizeToReg(Instr->getArg(0));
5124*03ce13f7SAndroid Build Coastguard Worker     _mov(SP, Val);
5125*03ce13f7SAndroid Build Coastguard Worker     return;
5126*03ce13f7SAndroid Build Coastguard Worker   }
5127*03ce13f7SAndroid Build Coastguard Worker   case Intrinsics::Trap: {
5128*03ce13f7SAndroid Build Coastguard Worker     const uint32_t TrapCodeZero = 0;
5129*03ce13f7SAndroid Build Coastguard Worker     _teq(getZero(), getZero(), TrapCodeZero);
5130*03ce13f7SAndroid Build Coastguard Worker     return;
5131*03ce13f7SAndroid Build Coastguard Worker   }
5132*03ce13f7SAndroid Build Coastguard Worker   case Intrinsics::LoadSubVector: {
5133*03ce13f7SAndroid Build Coastguard Worker     UnimplementedLoweringError(this, Instr);
5134*03ce13f7SAndroid Build Coastguard Worker     return;
5135*03ce13f7SAndroid Build Coastguard Worker   }
5136*03ce13f7SAndroid Build Coastguard Worker   case Intrinsics::StoreSubVector: {
5137*03ce13f7SAndroid Build Coastguard Worker     UnimplementedLoweringError(this, Instr);
5138*03ce13f7SAndroid Build Coastguard Worker     return;
5139*03ce13f7SAndroid Build Coastguard Worker   }
5140*03ce13f7SAndroid Build Coastguard Worker   default: // UnknownIntrinsic
5141*03ce13f7SAndroid Build Coastguard Worker     Func->setError("Unexpected intrinsic");
5142*03ce13f7SAndroid Build Coastguard Worker     return;
5143*03ce13f7SAndroid Build Coastguard Worker   }
5144*03ce13f7SAndroid Build Coastguard Worker   return;
5145*03ce13f7SAndroid Build Coastguard Worker }
5146*03ce13f7SAndroid Build Coastguard Worker 
lowerLoad(const InstLoad * Instr)5147*03ce13f7SAndroid Build Coastguard Worker void TargetMIPS32::lowerLoad(const InstLoad *Instr) {
5148*03ce13f7SAndroid Build Coastguard Worker   // A Load instruction can be treated the same as an Assign instruction, after
5149*03ce13f7SAndroid Build Coastguard Worker   // the source operand is transformed into an OperandMIPS32Mem operand.
5150*03ce13f7SAndroid Build Coastguard Worker   Type Ty = Instr->getDest()->getType();
5151*03ce13f7SAndroid Build Coastguard Worker   Operand *Src0 = formMemoryOperand(Instr->getLoadAddress(), Ty);
5152*03ce13f7SAndroid Build Coastguard Worker   Variable *DestLoad = Instr->getDest();
5153*03ce13f7SAndroid Build Coastguard Worker   auto *Assign = InstAssign::create(Func, DestLoad, Src0);
5154*03ce13f7SAndroid Build Coastguard Worker   lowerAssign(Assign);
5155*03ce13f7SAndroid Build Coastguard Worker }
5156*03ce13f7SAndroid Build Coastguard Worker 
5157*03ce13f7SAndroid Build Coastguard Worker namespace {
dumpAddressOpt(const Cfg * Func,const Variable * Base,int32_t Offset,const Inst * Reason)5158*03ce13f7SAndroid Build Coastguard Worker void dumpAddressOpt(const Cfg *Func, const Variable *Base, int32_t Offset,
5159*03ce13f7SAndroid Build Coastguard Worker                     const Inst *Reason) {
5160*03ce13f7SAndroid Build Coastguard Worker   if (!BuildDefs::dump())
5161*03ce13f7SAndroid Build Coastguard Worker     return;
5162*03ce13f7SAndroid Build Coastguard Worker   if (!Func->isVerbose(IceV_AddrOpt))
5163*03ce13f7SAndroid Build Coastguard Worker     return;
5164*03ce13f7SAndroid Build Coastguard Worker   OstreamLocker _(Func->getContext());
5165*03ce13f7SAndroid Build Coastguard Worker   Ostream &Str = Func->getContext()->getStrDump();
5166*03ce13f7SAndroid Build Coastguard Worker   Str << "Instruction: ";
5167*03ce13f7SAndroid Build Coastguard Worker   Reason->dumpDecorated(Func);
5168*03ce13f7SAndroid Build Coastguard Worker   Str << "  results in Base=";
5169*03ce13f7SAndroid Build Coastguard Worker   if (Base)
5170*03ce13f7SAndroid Build Coastguard Worker     Base->dump(Func);
5171*03ce13f7SAndroid Build Coastguard Worker   else
5172*03ce13f7SAndroid Build Coastguard Worker     Str << "<null>";
5173*03ce13f7SAndroid Build Coastguard Worker   Str << ", Offset=" << Offset << "\n";
5174*03ce13f7SAndroid Build Coastguard Worker }
5175*03ce13f7SAndroid Build Coastguard Worker 
matchAssign(const VariablesMetadata * VMetadata,Variable ** Var,int32_t * Offset,const Inst ** Reason)5176*03ce13f7SAndroid Build Coastguard Worker bool matchAssign(const VariablesMetadata *VMetadata, Variable **Var,
5177*03ce13f7SAndroid Build Coastguard Worker                  int32_t *Offset, const Inst **Reason) {
5178*03ce13f7SAndroid Build Coastguard Worker   // Var originates from Var=SrcVar ==> set Var:=SrcVar
5179*03ce13f7SAndroid Build Coastguard Worker   if (*Var == nullptr)
5180*03ce13f7SAndroid Build Coastguard Worker     return false;
5181*03ce13f7SAndroid Build Coastguard Worker   const Inst *VarAssign = VMetadata->getSingleDefinition(*Var);
5182*03ce13f7SAndroid Build Coastguard Worker   if (!VarAssign)
5183*03ce13f7SAndroid Build Coastguard Worker     return false;
5184*03ce13f7SAndroid Build Coastguard Worker   assert(!VMetadata->isMultiDef(*Var));
5185*03ce13f7SAndroid Build Coastguard Worker   if (!llvm::isa<InstAssign>(VarAssign))
5186*03ce13f7SAndroid Build Coastguard Worker     return false;
5187*03ce13f7SAndroid Build Coastguard Worker 
5188*03ce13f7SAndroid Build Coastguard Worker   Operand *SrcOp = VarAssign->getSrc(0);
5189*03ce13f7SAndroid Build Coastguard Worker   bool Optimized = false;
5190*03ce13f7SAndroid Build Coastguard Worker   if (auto *SrcVar = llvm::dyn_cast<Variable>(SrcOp)) {
5191*03ce13f7SAndroid Build Coastguard Worker     if (!VMetadata->isMultiDef(SrcVar) ||
5192*03ce13f7SAndroid Build Coastguard Worker         // TODO: ensure SrcVar stays single-BB
5193*03ce13f7SAndroid Build Coastguard Worker         false) {
5194*03ce13f7SAndroid Build Coastguard Worker       Optimized = true;
5195*03ce13f7SAndroid Build Coastguard Worker       *Var = SrcVar;
5196*03ce13f7SAndroid Build Coastguard Worker     } else if (auto *Const = llvm::dyn_cast<ConstantInteger32>(SrcOp)) {
5197*03ce13f7SAndroid Build Coastguard Worker       int32_t MoreOffset = Const->getValue();
5198*03ce13f7SAndroid Build Coastguard Worker       int32_t NewOffset = MoreOffset + *Offset;
5199*03ce13f7SAndroid Build Coastguard Worker       if (Utils::WouldOverflowAdd(*Offset, MoreOffset))
5200*03ce13f7SAndroid Build Coastguard Worker         return false;
5201*03ce13f7SAndroid Build Coastguard Worker       *Var = nullptr;
5202*03ce13f7SAndroid Build Coastguard Worker       *Offset += NewOffset;
5203*03ce13f7SAndroid Build Coastguard Worker       Optimized = true;
5204*03ce13f7SAndroid Build Coastguard Worker     }
5205*03ce13f7SAndroid Build Coastguard Worker   }
5206*03ce13f7SAndroid Build Coastguard Worker 
5207*03ce13f7SAndroid Build Coastguard Worker   if (Optimized) {
5208*03ce13f7SAndroid Build Coastguard Worker     *Reason = VarAssign;
5209*03ce13f7SAndroid Build Coastguard Worker   }
5210*03ce13f7SAndroid Build Coastguard Worker 
5211*03ce13f7SAndroid Build Coastguard Worker   return Optimized;
5212*03ce13f7SAndroid Build Coastguard Worker }
5213*03ce13f7SAndroid Build Coastguard Worker 
isAddOrSub(const Inst * Instr,InstArithmetic::OpKind * Kind)5214*03ce13f7SAndroid Build Coastguard Worker bool isAddOrSub(const Inst *Instr, InstArithmetic::OpKind *Kind) {
5215*03ce13f7SAndroid Build Coastguard Worker   if (const auto *Arith = llvm::dyn_cast<InstArithmetic>(Instr)) {
5216*03ce13f7SAndroid Build Coastguard Worker     switch (Arith->getOp()) {
5217*03ce13f7SAndroid Build Coastguard Worker     default:
5218*03ce13f7SAndroid Build Coastguard Worker       return false;
5219*03ce13f7SAndroid Build Coastguard Worker     case InstArithmetic::Add:
5220*03ce13f7SAndroid Build Coastguard Worker     case InstArithmetic::Sub:
5221*03ce13f7SAndroid Build Coastguard Worker       *Kind = Arith->getOp();
5222*03ce13f7SAndroid Build Coastguard Worker       return true;
5223*03ce13f7SAndroid Build Coastguard Worker     }
5224*03ce13f7SAndroid Build Coastguard Worker   }
5225*03ce13f7SAndroid Build Coastguard Worker   return false;
5226*03ce13f7SAndroid Build Coastguard Worker }
5227*03ce13f7SAndroid Build Coastguard Worker 
matchOffsetBase(const VariablesMetadata * VMetadata,Variable ** Base,int32_t * Offset,const Inst ** Reason)5228*03ce13f7SAndroid Build Coastguard Worker bool matchOffsetBase(const VariablesMetadata *VMetadata, Variable **Base,
5229*03ce13f7SAndroid Build Coastguard Worker                      int32_t *Offset, const Inst **Reason) {
5230*03ce13f7SAndroid Build Coastguard Worker   // Base is Base=Var+Const || Base is Base=Const+Var ==>
5231*03ce13f7SAndroid Build Coastguard Worker   //   set Base=Var, Offset+=Const
5232*03ce13f7SAndroid Build Coastguard Worker   // Base is Base=Var-Const ==>
5233*03ce13f7SAndroid Build Coastguard Worker   //   set Base=Var, Offset-=Const
5234*03ce13f7SAndroid Build Coastguard Worker   if (*Base == nullptr)
5235*03ce13f7SAndroid Build Coastguard Worker     return false;
5236*03ce13f7SAndroid Build Coastguard Worker   const Inst *BaseInst = VMetadata->getSingleDefinition(*Base);
5237*03ce13f7SAndroid Build Coastguard Worker   if (BaseInst == nullptr) {
5238*03ce13f7SAndroid Build Coastguard Worker     return false;
5239*03ce13f7SAndroid Build Coastguard Worker   }
5240*03ce13f7SAndroid Build Coastguard Worker   assert(!VMetadata->isMultiDef(*Base));
5241*03ce13f7SAndroid Build Coastguard Worker 
5242*03ce13f7SAndroid Build Coastguard Worker   auto *ArithInst = llvm::dyn_cast<const InstArithmetic>(BaseInst);
5243*03ce13f7SAndroid Build Coastguard Worker   if (ArithInst == nullptr)
5244*03ce13f7SAndroid Build Coastguard Worker     return false;
5245*03ce13f7SAndroid Build Coastguard Worker   InstArithmetic::OpKind Kind;
5246*03ce13f7SAndroid Build Coastguard Worker   if (!isAddOrSub(ArithInst, &Kind))
5247*03ce13f7SAndroid Build Coastguard Worker     return false;
5248*03ce13f7SAndroid Build Coastguard Worker   bool IsAdd = Kind == InstArithmetic::Add;
5249*03ce13f7SAndroid Build Coastguard Worker   Operand *Src0 = ArithInst->getSrc(0);
5250*03ce13f7SAndroid Build Coastguard Worker   Operand *Src1 = ArithInst->getSrc(1);
5251*03ce13f7SAndroid Build Coastguard Worker   auto *Var0 = llvm::dyn_cast<Variable>(Src0);
5252*03ce13f7SAndroid Build Coastguard Worker   auto *Var1 = llvm::dyn_cast<Variable>(Src1);
5253*03ce13f7SAndroid Build Coastguard Worker   auto *Const0 = llvm::dyn_cast<ConstantInteger32>(Src0);
5254*03ce13f7SAndroid Build Coastguard Worker   auto *Const1 = llvm::dyn_cast<ConstantInteger32>(Src1);
5255*03ce13f7SAndroid Build Coastguard Worker   Variable *NewBase = nullptr;
5256*03ce13f7SAndroid Build Coastguard Worker   int32_t NewOffset = *Offset;
5257*03ce13f7SAndroid Build Coastguard Worker 
5258*03ce13f7SAndroid Build Coastguard Worker   if (Var0 == nullptr && Const0 == nullptr) {
5259*03ce13f7SAndroid Build Coastguard Worker     assert(llvm::isa<ConstantRelocatable>(Src0));
5260*03ce13f7SAndroid Build Coastguard Worker     return false;
5261*03ce13f7SAndroid Build Coastguard Worker   }
5262*03ce13f7SAndroid Build Coastguard Worker 
5263*03ce13f7SAndroid Build Coastguard Worker   if (Var1 == nullptr && Const1 == nullptr) {
5264*03ce13f7SAndroid Build Coastguard Worker     assert(llvm::isa<ConstantRelocatable>(Src1));
5265*03ce13f7SAndroid Build Coastguard Worker     return false;
5266*03ce13f7SAndroid Build Coastguard Worker   }
5267*03ce13f7SAndroid Build Coastguard Worker 
5268*03ce13f7SAndroid Build Coastguard Worker   if (Var0 && Var1)
5269*03ce13f7SAndroid Build Coastguard Worker     // TODO(jpp): merge base/index splitting into here.
5270*03ce13f7SAndroid Build Coastguard Worker     return false;
5271*03ce13f7SAndroid Build Coastguard Worker   if (!IsAdd && Var1)
5272*03ce13f7SAndroid Build Coastguard Worker     return false;
5273*03ce13f7SAndroid Build Coastguard Worker   if (Var0)
5274*03ce13f7SAndroid Build Coastguard Worker     NewBase = Var0;
5275*03ce13f7SAndroid Build Coastguard Worker   else if (Var1)
5276*03ce13f7SAndroid Build Coastguard Worker     NewBase = Var1;
5277*03ce13f7SAndroid Build Coastguard Worker   // Compute the updated constant offset.
5278*03ce13f7SAndroid Build Coastguard Worker   if (Const0) {
5279*03ce13f7SAndroid Build Coastguard Worker     int32_t MoreOffset = IsAdd ? Const0->getValue() : -Const0->getValue();
5280*03ce13f7SAndroid Build Coastguard Worker     if (Utils::WouldOverflowAdd(NewOffset, MoreOffset))
5281*03ce13f7SAndroid Build Coastguard Worker       return false;
5282*03ce13f7SAndroid Build Coastguard Worker     NewOffset += MoreOffset;
5283*03ce13f7SAndroid Build Coastguard Worker   }
5284*03ce13f7SAndroid Build Coastguard Worker   if (Const1) {
5285*03ce13f7SAndroid Build Coastguard Worker     int32_t MoreOffset = IsAdd ? Const1->getValue() : -Const1->getValue();
5286*03ce13f7SAndroid Build Coastguard Worker     if (Utils::WouldOverflowAdd(NewOffset, MoreOffset))
5287*03ce13f7SAndroid Build Coastguard Worker       return false;
5288*03ce13f7SAndroid Build Coastguard Worker     NewOffset += MoreOffset;
5289*03ce13f7SAndroid Build Coastguard Worker   }
5290*03ce13f7SAndroid Build Coastguard Worker 
5291*03ce13f7SAndroid Build Coastguard Worker   // Update the computed address parameters once we are sure optimization
5292*03ce13f7SAndroid Build Coastguard Worker   // is valid.
5293*03ce13f7SAndroid Build Coastguard Worker   *Base = NewBase;
5294*03ce13f7SAndroid Build Coastguard Worker   *Offset = NewOffset;
5295*03ce13f7SAndroid Build Coastguard Worker   *Reason = BaseInst;
5296*03ce13f7SAndroid Build Coastguard Worker   return true;
5297*03ce13f7SAndroid Build Coastguard Worker }
5298*03ce13f7SAndroid Build Coastguard Worker } // end of anonymous namespace
5299*03ce13f7SAndroid Build Coastguard Worker 
formAddressingMode(Type Ty,Cfg * Func,const Inst * LdSt,Operand * Base)5300*03ce13f7SAndroid Build Coastguard Worker OperandMIPS32Mem *TargetMIPS32::formAddressingMode(Type Ty, Cfg *Func,
5301*03ce13f7SAndroid Build Coastguard Worker                                                    const Inst *LdSt,
5302*03ce13f7SAndroid Build Coastguard Worker                                                    Operand *Base) {
5303*03ce13f7SAndroid Build Coastguard Worker   assert(Base != nullptr);
5304*03ce13f7SAndroid Build Coastguard Worker   int32_t OffsetImm = 0;
5305*03ce13f7SAndroid Build Coastguard Worker 
5306*03ce13f7SAndroid Build Coastguard Worker   Func->resetCurrentNode();
5307*03ce13f7SAndroid Build Coastguard Worker   if (Func->isVerbose(IceV_AddrOpt)) {
5308*03ce13f7SAndroid Build Coastguard Worker     OstreamLocker _(Func->getContext());
5309*03ce13f7SAndroid Build Coastguard Worker     Ostream &Str = Func->getContext()->getStrDump();
5310*03ce13f7SAndroid Build Coastguard Worker     Str << "\nAddress mode formation:\t";
5311*03ce13f7SAndroid Build Coastguard Worker     LdSt->dumpDecorated(Func);
5312*03ce13f7SAndroid Build Coastguard Worker   }
5313*03ce13f7SAndroid Build Coastguard Worker 
5314*03ce13f7SAndroid Build Coastguard Worker   if (isVectorType(Ty)) {
5315*03ce13f7SAndroid Build Coastguard Worker     return nullptr;
5316*03ce13f7SAndroid Build Coastguard Worker   }
5317*03ce13f7SAndroid Build Coastguard Worker 
5318*03ce13f7SAndroid Build Coastguard Worker   auto *BaseVar = llvm::dyn_cast<Variable>(Base);
5319*03ce13f7SAndroid Build Coastguard Worker   if (BaseVar == nullptr)
5320*03ce13f7SAndroid Build Coastguard Worker     return nullptr;
5321*03ce13f7SAndroid Build Coastguard Worker 
5322*03ce13f7SAndroid Build Coastguard Worker   const VariablesMetadata *VMetadata = Func->getVMetadata();
5323*03ce13f7SAndroid Build Coastguard Worker   const Inst *Reason = nullptr;
5324*03ce13f7SAndroid Build Coastguard Worker 
5325*03ce13f7SAndroid Build Coastguard Worker   do {
5326*03ce13f7SAndroid Build Coastguard Worker     if (Reason != nullptr) {
5327*03ce13f7SAndroid Build Coastguard Worker       dumpAddressOpt(Func, BaseVar, OffsetImm, Reason);
5328*03ce13f7SAndroid Build Coastguard Worker       Reason = nullptr;
5329*03ce13f7SAndroid Build Coastguard Worker     }
5330*03ce13f7SAndroid Build Coastguard Worker 
5331*03ce13f7SAndroid Build Coastguard Worker     if (matchAssign(VMetadata, &BaseVar, &OffsetImm, &Reason)) {
5332*03ce13f7SAndroid Build Coastguard Worker       continue;
5333*03ce13f7SAndroid Build Coastguard Worker     }
5334*03ce13f7SAndroid Build Coastguard Worker 
5335*03ce13f7SAndroid Build Coastguard Worker     if (matchOffsetBase(VMetadata, &BaseVar, &OffsetImm, &Reason)) {
5336*03ce13f7SAndroid Build Coastguard Worker       continue;
5337*03ce13f7SAndroid Build Coastguard Worker     }
5338*03ce13f7SAndroid Build Coastguard Worker   } while (Reason);
5339*03ce13f7SAndroid Build Coastguard Worker 
5340*03ce13f7SAndroid Build Coastguard Worker   if (BaseVar == nullptr) {
5341*03ce13f7SAndroid Build Coastguard Worker     // We need base register rather than just OffsetImm. Move the OffsetImm to
5342*03ce13f7SAndroid Build Coastguard Worker     // BaseVar and form 0(BaseVar) addressing.
5343*03ce13f7SAndroid Build Coastguard Worker     const Type PointerType = getPointerType();
5344*03ce13f7SAndroid Build Coastguard Worker     BaseVar = makeReg(PointerType);
5345*03ce13f7SAndroid Build Coastguard Worker     Context.insert<InstAssign>(BaseVar, Ctx->getConstantInt32(OffsetImm));
5346*03ce13f7SAndroid Build Coastguard Worker     OffsetImm = 0;
5347*03ce13f7SAndroid Build Coastguard Worker   } else if (OffsetImm != 0) {
5348*03ce13f7SAndroid Build Coastguard Worker     // If the OffsetImm is more than signed 16-bit value then add it in the
5349*03ce13f7SAndroid Build Coastguard Worker     // BaseVar and form 0(BaseVar) addressing.
5350*03ce13f7SAndroid Build Coastguard Worker     const int32_t PositiveOffset = OffsetImm > 0 ? OffsetImm : -OffsetImm;
5351*03ce13f7SAndroid Build Coastguard Worker     const InstArithmetic::OpKind Op =
5352*03ce13f7SAndroid Build Coastguard Worker         OffsetImm > 0 ? InstArithmetic::Add : InstArithmetic::Sub;
5353*03ce13f7SAndroid Build Coastguard Worker     constexpr bool ZeroExt = false;
5354*03ce13f7SAndroid Build Coastguard Worker     if (!OperandMIPS32Mem::canHoldOffset(Ty, ZeroExt, OffsetImm)) {
5355*03ce13f7SAndroid Build Coastguard Worker       const Type PointerType = getPointerType();
5356*03ce13f7SAndroid Build Coastguard Worker       Variable *T = makeReg(PointerType);
5357*03ce13f7SAndroid Build Coastguard Worker       Context.insert<InstArithmetic>(Op, T, BaseVar,
5358*03ce13f7SAndroid Build Coastguard Worker                                      Ctx->getConstantInt32(PositiveOffset));
5359*03ce13f7SAndroid Build Coastguard Worker       BaseVar = T;
5360*03ce13f7SAndroid Build Coastguard Worker       OffsetImm = 0;
5361*03ce13f7SAndroid Build Coastguard Worker     }
5362*03ce13f7SAndroid Build Coastguard Worker   }
5363*03ce13f7SAndroid Build Coastguard Worker 
5364*03ce13f7SAndroid Build Coastguard Worker   assert(BaseVar != nullptr);
5365*03ce13f7SAndroid Build Coastguard Worker   assert(OffsetImm < 0 ? (-OffsetImm & 0x0000ffff) == -OffsetImm
5366*03ce13f7SAndroid Build Coastguard Worker                        : (OffsetImm & 0x0000ffff) == OffsetImm);
5367*03ce13f7SAndroid Build Coastguard Worker 
5368*03ce13f7SAndroid Build Coastguard Worker   return OperandMIPS32Mem::create(
5369*03ce13f7SAndroid Build Coastguard Worker       Func, Ty, BaseVar,
5370*03ce13f7SAndroid Build Coastguard Worker       llvm::cast<ConstantInteger32>(Ctx->getConstantInt32(OffsetImm)));
5371*03ce13f7SAndroid Build Coastguard Worker }
5372*03ce13f7SAndroid Build Coastguard Worker 
doAddressOptLoad()5373*03ce13f7SAndroid Build Coastguard Worker void TargetMIPS32::doAddressOptLoad() {
5374*03ce13f7SAndroid Build Coastguard Worker   Inst *Instr = iteratorToInst(Context.getCur());
5375*03ce13f7SAndroid Build Coastguard Worker   assert(llvm::isa<InstLoad>(Instr));
5376*03ce13f7SAndroid Build Coastguard Worker   Variable *Dest = Instr->getDest();
5377*03ce13f7SAndroid Build Coastguard Worker   Operand *Addr = Instr->getSrc(0);
5378*03ce13f7SAndroid Build Coastguard Worker   if (OperandMIPS32Mem *Mem =
5379*03ce13f7SAndroid Build Coastguard Worker           formAddressingMode(Dest->getType(), Func, Instr, Addr)) {
5380*03ce13f7SAndroid Build Coastguard Worker     Instr->setDeleted();
5381*03ce13f7SAndroid Build Coastguard Worker     Context.insert<InstLoad>(Dest, Mem);
5382*03ce13f7SAndroid Build Coastguard Worker   }
5383*03ce13f7SAndroid Build Coastguard Worker }
5384*03ce13f7SAndroid Build Coastguard Worker 
lowerPhi(const InstPhi *)5385*03ce13f7SAndroid Build Coastguard Worker void TargetMIPS32::lowerPhi(const InstPhi * /*Instr*/) {
5386*03ce13f7SAndroid Build Coastguard Worker   Func->setError("Phi found in regular instruction list");
5387*03ce13f7SAndroid Build Coastguard Worker }
5388*03ce13f7SAndroid Build Coastguard Worker 
lowerRet(const InstRet * Instr)5389*03ce13f7SAndroid Build Coastguard Worker void TargetMIPS32::lowerRet(const InstRet *Instr) {
5390*03ce13f7SAndroid Build Coastguard Worker   Variable *Reg = nullptr;
5391*03ce13f7SAndroid Build Coastguard Worker   if (Instr->hasRetValue()) {
5392*03ce13f7SAndroid Build Coastguard Worker     Operand *Src0 = Instr->getRetValue();
5393*03ce13f7SAndroid Build Coastguard Worker     switch (Src0->getType()) {
5394*03ce13f7SAndroid Build Coastguard Worker     case IceType_f32: {
5395*03ce13f7SAndroid Build Coastguard Worker       Operand *Src0F = legalizeToReg(Src0);
5396*03ce13f7SAndroid Build Coastguard Worker       Reg = makeReg(Src0F->getType(), RegMIPS32::Reg_F0);
5397*03ce13f7SAndroid Build Coastguard Worker       _mov(Reg, Src0F);
5398*03ce13f7SAndroid Build Coastguard Worker       break;
5399*03ce13f7SAndroid Build Coastguard Worker     }
5400*03ce13f7SAndroid Build Coastguard Worker     case IceType_f64: {
5401*03ce13f7SAndroid Build Coastguard Worker       Operand *Src0F = legalizeToReg(Src0);
5402*03ce13f7SAndroid Build Coastguard Worker       Reg = makeReg(Src0F->getType(), RegMIPS32::Reg_F0F1);
5403*03ce13f7SAndroid Build Coastguard Worker       _mov(Reg, Src0F);
5404*03ce13f7SAndroid Build Coastguard Worker       break;
5405*03ce13f7SAndroid Build Coastguard Worker     }
5406*03ce13f7SAndroid Build Coastguard Worker     case IceType_i1:
5407*03ce13f7SAndroid Build Coastguard Worker     case IceType_i8:
5408*03ce13f7SAndroid Build Coastguard Worker     case IceType_i16:
5409*03ce13f7SAndroid Build Coastguard Worker     case IceType_i32: {
5410*03ce13f7SAndroid Build Coastguard Worker       Operand *Src0F = legalizeToReg(Src0);
5411*03ce13f7SAndroid Build Coastguard Worker       Reg = makeReg(Src0F->getType(), RegMIPS32::Reg_V0);
5412*03ce13f7SAndroid Build Coastguard Worker       _mov(Reg, Src0F);
5413*03ce13f7SAndroid Build Coastguard Worker       break;
5414*03ce13f7SAndroid Build Coastguard Worker     }
5415*03ce13f7SAndroid Build Coastguard Worker     case IceType_i64: {
5416*03ce13f7SAndroid Build Coastguard Worker       Src0 = legalizeUndef(Src0);
5417*03ce13f7SAndroid Build Coastguard Worker       Variable *R0 = legalizeToReg(loOperand(Src0), RegMIPS32::Reg_V0);
5418*03ce13f7SAndroid Build Coastguard Worker       Variable *R1 = legalizeToReg(hiOperand(Src0), RegMIPS32::Reg_V1);
5419*03ce13f7SAndroid Build Coastguard Worker       Reg = R0;
5420*03ce13f7SAndroid Build Coastguard Worker       Context.insert<InstFakeUse>(R1);
5421*03ce13f7SAndroid Build Coastguard Worker       break;
5422*03ce13f7SAndroid Build Coastguard Worker     }
5423*03ce13f7SAndroid Build Coastguard Worker     case IceType_v4i1:
5424*03ce13f7SAndroid Build Coastguard Worker     case IceType_v8i1:
5425*03ce13f7SAndroid Build Coastguard Worker     case IceType_v16i1:
5426*03ce13f7SAndroid Build Coastguard Worker     case IceType_v16i8:
5427*03ce13f7SAndroid Build Coastguard Worker     case IceType_v8i16:
5428*03ce13f7SAndroid Build Coastguard Worker     case IceType_v4i32: {
5429*03ce13f7SAndroid Build Coastguard Worker       auto *SrcVec = llvm::dyn_cast<VariableVecOn32>(legalizeUndef(Src0));
5430*03ce13f7SAndroid Build Coastguard Worker       Variable *V0 =
5431*03ce13f7SAndroid Build Coastguard Worker           legalizeToReg(SrcVec->getContainers()[0], RegMIPS32::Reg_V0);
5432*03ce13f7SAndroid Build Coastguard Worker       Variable *V1 =
5433*03ce13f7SAndroid Build Coastguard Worker           legalizeToReg(SrcVec->getContainers()[1], RegMIPS32::Reg_V1);
5434*03ce13f7SAndroid Build Coastguard Worker       Variable *A0 =
5435*03ce13f7SAndroid Build Coastguard Worker           legalizeToReg(SrcVec->getContainers()[2], RegMIPS32::Reg_A0);
5436*03ce13f7SAndroid Build Coastguard Worker       Variable *A1 =
5437*03ce13f7SAndroid Build Coastguard Worker           legalizeToReg(SrcVec->getContainers()[3], RegMIPS32::Reg_A1);
5438*03ce13f7SAndroid Build Coastguard Worker       Reg = V0;
5439*03ce13f7SAndroid Build Coastguard Worker       Context.insert<InstFakeUse>(V1);
5440*03ce13f7SAndroid Build Coastguard Worker       Context.insert<InstFakeUse>(A0);
5441*03ce13f7SAndroid Build Coastguard Worker       Context.insert<InstFakeUse>(A1);
5442*03ce13f7SAndroid Build Coastguard Worker       break;
5443*03ce13f7SAndroid Build Coastguard Worker     }
5444*03ce13f7SAndroid Build Coastguard Worker     case IceType_v4f32: {
5445*03ce13f7SAndroid Build Coastguard Worker       auto *SrcVec = llvm::dyn_cast<VariableVecOn32>(legalizeUndef(Src0));
5446*03ce13f7SAndroid Build Coastguard Worker       Reg = getImplicitRet();
5447*03ce13f7SAndroid Build Coastguard Worker       auto *RegT = legalizeToReg(Reg);
5448*03ce13f7SAndroid Build Coastguard Worker       // Return the vector through buffer in implicit argument a0
5449*03ce13f7SAndroid Build Coastguard Worker       for (SizeT i = 0; i < SrcVec->ContainersPerVector; ++i) {
5450*03ce13f7SAndroid Build Coastguard Worker         OperandMIPS32Mem *Mem = OperandMIPS32Mem::create(
5451*03ce13f7SAndroid Build Coastguard Worker             Func, IceType_f32, RegT,
5452*03ce13f7SAndroid Build Coastguard Worker             llvm::cast<ConstantInteger32>(Ctx->getConstantInt32(i * 4)));
5453*03ce13f7SAndroid Build Coastguard Worker         Variable *Var = legalizeToReg(SrcVec->getContainers()[i]);
5454*03ce13f7SAndroid Build Coastguard Worker         _sw(Var, Mem);
5455*03ce13f7SAndroid Build Coastguard Worker       }
5456*03ce13f7SAndroid Build Coastguard Worker       Variable *V0 = makeReg(IceType_i32, RegMIPS32::Reg_V0);
5457*03ce13f7SAndroid Build Coastguard Worker       _mov(V0, Reg); // move v0,a0
5458*03ce13f7SAndroid Build Coastguard Worker       Context.insert<InstFakeUse>(Reg);
5459*03ce13f7SAndroid Build Coastguard Worker       Context.insert<InstFakeUse>(V0);
5460*03ce13f7SAndroid Build Coastguard Worker       break;
5461*03ce13f7SAndroid Build Coastguard Worker     }
5462*03ce13f7SAndroid Build Coastguard Worker     default:
5463*03ce13f7SAndroid Build Coastguard Worker       llvm::report_fatal_error("Ret: Invalid type.");
5464*03ce13f7SAndroid Build Coastguard Worker       break;
5465*03ce13f7SAndroid Build Coastguard Worker     }
5466*03ce13f7SAndroid Build Coastguard Worker   }
5467*03ce13f7SAndroid Build Coastguard Worker   _ret(getPhysicalRegister(RegMIPS32::Reg_RA), Reg);
5468*03ce13f7SAndroid Build Coastguard Worker }
5469*03ce13f7SAndroid Build Coastguard Worker 
lowerSelect(const InstSelect * Instr)5470*03ce13f7SAndroid Build Coastguard Worker void TargetMIPS32::lowerSelect(const InstSelect *Instr) {
5471*03ce13f7SAndroid Build Coastguard Worker   Variable *Dest = Instr->getDest();
5472*03ce13f7SAndroid Build Coastguard Worker   const Type DestTy = Dest->getType();
5473*03ce13f7SAndroid Build Coastguard Worker 
5474*03ce13f7SAndroid Build Coastguard Worker   if (isVectorType(DestTy)) {
5475*03ce13f7SAndroid Build Coastguard Worker     llvm::report_fatal_error("Select: Destination type is vector");
5476*03ce13f7SAndroid Build Coastguard Worker     return;
5477*03ce13f7SAndroid Build Coastguard Worker   }
5478*03ce13f7SAndroid Build Coastguard Worker 
5479*03ce13f7SAndroid Build Coastguard Worker   Variable *DestR = nullptr;
5480*03ce13f7SAndroid Build Coastguard Worker   Variable *DestHiR = nullptr;
5481*03ce13f7SAndroid Build Coastguard Worker   Variable *SrcTR = nullptr;
5482*03ce13f7SAndroid Build Coastguard Worker   Variable *SrcTHiR = nullptr;
5483*03ce13f7SAndroid Build Coastguard Worker   Variable *SrcFR = nullptr;
5484*03ce13f7SAndroid Build Coastguard Worker   Variable *SrcFHiR = nullptr;
5485*03ce13f7SAndroid Build Coastguard Worker 
5486*03ce13f7SAndroid Build Coastguard Worker   if (DestTy == IceType_i64) {
5487*03ce13f7SAndroid Build Coastguard Worker     DestR = llvm::cast<Variable>(loOperand(Dest));
5488*03ce13f7SAndroid Build Coastguard Worker     DestHiR = llvm::cast<Variable>(hiOperand(Dest));
5489*03ce13f7SAndroid Build Coastguard Worker     SrcTR = legalizeToReg(loOperand(legalizeUndef(Instr->getTrueOperand())));
5490*03ce13f7SAndroid Build Coastguard Worker     SrcTHiR = legalizeToReg(hiOperand(legalizeUndef(Instr->getTrueOperand())));
5491*03ce13f7SAndroid Build Coastguard Worker     SrcFR = legalizeToReg(loOperand(legalizeUndef(Instr->getFalseOperand())));
5492*03ce13f7SAndroid Build Coastguard Worker     SrcFHiR = legalizeToReg(hiOperand(legalizeUndef(Instr->getFalseOperand())));
5493*03ce13f7SAndroid Build Coastguard Worker   } else {
5494*03ce13f7SAndroid Build Coastguard Worker     SrcTR = legalizeToReg(legalizeUndef(Instr->getTrueOperand()));
5495*03ce13f7SAndroid Build Coastguard Worker     SrcFR = legalizeToReg(legalizeUndef(Instr->getFalseOperand()));
5496*03ce13f7SAndroid Build Coastguard Worker   }
5497*03ce13f7SAndroid Build Coastguard Worker 
5498*03ce13f7SAndroid Build Coastguard Worker   Variable *ConditionR = legalizeToReg(Instr->getCondition());
5499*03ce13f7SAndroid Build Coastguard Worker 
5500*03ce13f7SAndroid Build Coastguard Worker   assert(Instr->getCondition()->getType() == IceType_i1);
5501*03ce13f7SAndroid Build Coastguard Worker 
5502*03ce13f7SAndroid Build Coastguard Worker   switch (DestTy) {
5503*03ce13f7SAndroid Build Coastguard Worker   case IceType_i1:
5504*03ce13f7SAndroid Build Coastguard Worker   case IceType_i8:
5505*03ce13f7SAndroid Build Coastguard Worker   case IceType_i16:
5506*03ce13f7SAndroid Build Coastguard Worker   case IceType_i32:
5507*03ce13f7SAndroid Build Coastguard Worker     _movn(SrcFR, SrcTR, ConditionR);
5508*03ce13f7SAndroid Build Coastguard Worker     _mov(Dest, SrcFR);
5509*03ce13f7SAndroid Build Coastguard Worker     break;
5510*03ce13f7SAndroid Build Coastguard Worker   case IceType_i64:
5511*03ce13f7SAndroid Build Coastguard Worker     _movn(SrcFR, SrcTR, ConditionR);
5512*03ce13f7SAndroid Build Coastguard Worker     _movn(SrcFHiR, SrcTHiR, ConditionR);
5513*03ce13f7SAndroid Build Coastguard Worker     _mov(DestR, SrcFR);
5514*03ce13f7SAndroid Build Coastguard Worker     _mov(DestHiR, SrcFHiR);
5515*03ce13f7SAndroid Build Coastguard Worker     break;
5516*03ce13f7SAndroid Build Coastguard Worker   case IceType_f32:
5517*03ce13f7SAndroid Build Coastguard Worker     _movn_s(SrcFR, SrcTR, ConditionR);
5518*03ce13f7SAndroid Build Coastguard Worker     _mov(Dest, SrcFR);
5519*03ce13f7SAndroid Build Coastguard Worker     break;
5520*03ce13f7SAndroid Build Coastguard Worker   case IceType_f64:
5521*03ce13f7SAndroid Build Coastguard Worker     _movn_d(SrcFR, SrcTR, ConditionR);
5522*03ce13f7SAndroid Build Coastguard Worker     _mov(Dest, SrcFR);
5523*03ce13f7SAndroid Build Coastguard Worker     break;
5524*03ce13f7SAndroid Build Coastguard Worker   default:
5525*03ce13f7SAndroid Build Coastguard Worker     llvm::report_fatal_error("Select: Invalid type.");
5526*03ce13f7SAndroid Build Coastguard Worker   }
5527*03ce13f7SAndroid Build Coastguard Worker }
5528*03ce13f7SAndroid Build Coastguard Worker 
lowerShuffleVector(const InstShuffleVector * Instr)5529*03ce13f7SAndroid Build Coastguard Worker void TargetMIPS32::lowerShuffleVector(const InstShuffleVector *Instr) {
5530*03ce13f7SAndroid Build Coastguard Worker   UnimplementedLoweringError(this, Instr);
5531*03ce13f7SAndroid Build Coastguard Worker }
5532*03ce13f7SAndroid Build Coastguard Worker 
lowerStore(const InstStore * Instr)5533*03ce13f7SAndroid Build Coastguard Worker void TargetMIPS32::lowerStore(const InstStore *Instr) {
5534*03ce13f7SAndroid Build Coastguard Worker   Operand *Value = Instr->getData();
5535*03ce13f7SAndroid Build Coastguard Worker   Operand *Addr = Instr->getStoreAddress();
5536*03ce13f7SAndroid Build Coastguard Worker   OperandMIPS32Mem *NewAddr = formMemoryOperand(Addr, Value->getType());
5537*03ce13f7SAndroid Build Coastguard Worker   Type Ty = NewAddr->getType();
5538*03ce13f7SAndroid Build Coastguard Worker 
5539*03ce13f7SAndroid Build Coastguard Worker   if (Ty == IceType_i64) {
5540*03ce13f7SAndroid Build Coastguard Worker     Value = legalizeUndef(Value);
5541*03ce13f7SAndroid Build Coastguard Worker     Variable *ValueHi = legalizeToReg(hiOperand(Value));
5542*03ce13f7SAndroid Build Coastguard Worker     Variable *ValueLo = legalizeToReg(loOperand(Value));
5543*03ce13f7SAndroid Build Coastguard Worker     _sw(ValueHi, llvm::cast<OperandMIPS32Mem>(hiOperand(NewAddr)));
5544*03ce13f7SAndroid Build Coastguard Worker     _sw(ValueLo, llvm::cast<OperandMIPS32Mem>(loOperand(NewAddr)));
5545*03ce13f7SAndroid Build Coastguard Worker   } else if (isVectorType(Value->getType())) {
5546*03ce13f7SAndroid Build Coastguard Worker     auto *DataVec = llvm::dyn_cast<VariableVecOn32>(Value);
5547*03ce13f7SAndroid Build Coastguard Worker     for (SizeT i = 0; i < DataVec->ContainersPerVector; ++i) {
5548*03ce13f7SAndroid Build Coastguard Worker       auto *DCont = legalizeToReg(DataVec->getContainers()[i]);
5549*03ce13f7SAndroid Build Coastguard Worker       auto *MCont = llvm::cast<OperandMIPS32Mem>(
5550*03ce13f7SAndroid Build Coastguard Worker           getOperandAtIndex(NewAddr, IceType_i32, i));
5551*03ce13f7SAndroid Build Coastguard Worker       _sw(DCont, MCont);
5552*03ce13f7SAndroid Build Coastguard Worker     }
5553*03ce13f7SAndroid Build Coastguard Worker   } else {
5554*03ce13f7SAndroid Build Coastguard Worker     Variable *ValueR = legalizeToReg(Value);
5555*03ce13f7SAndroid Build Coastguard Worker     _sw(ValueR, NewAddr);
5556*03ce13f7SAndroid Build Coastguard Worker   }
5557*03ce13f7SAndroid Build Coastguard Worker }
5558*03ce13f7SAndroid Build Coastguard Worker 
doAddressOptStore()5559*03ce13f7SAndroid Build Coastguard Worker void TargetMIPS32::doAddressOptStore() {
5560*03ce13f7SAndroid Build Coastguard Worker   Inst *Instr = iteratorToInst(Context.getCur());
5561*03ce13f7SAndroid Build Coastguard Worker   assert(llvm::isa<InstStore>(Instr));
5562*03ce13f7SAndroid Build Coastguard Worker   Operand *Src = Instr->getSrc(0);
5563*03ce13f7SAndroid Build Coastguard Worker   Operand *Addr = Instr->getSrc(1);
5564*03ce13f7SAndroid Build Coastguard Worker   if (OperandMIPS32Mem *Mem =
5565*03ce13f7SAndroid Build Coastguard Worker           formAddressingMode(Src->getType(), Func, Instr, Addr)) {
5566*03ce13f7SAndroid Build Coastguard Worker     Instr->setDeleted();
5567*03ce13f7SAndroid Build Coastguard Worker     Context.insert<InstStore>(Src, Mem);
5568*03ce13f7SAndroid Build Coastguard Worker   }
5569*03ce13f7SAndroid Build Coastguard Worker }
5570*03ce13f7SAndroid Build Coastguard Worker 
lowerSwitch(const InstSwitch * Instr)5571*03ce13f7SAndroid Build Coastguard Worker void TargetMIPS32::lowerSwitch(const InstSwitch *Instr) {
5572*03ce13f7SAndroid Build Coastguard Worker   Operand *Src = Instr->getComparison();
5573*03ce13f7SAndroid Build Coastguard Worker   SizeT NumCases = Instr->getNumCases();
5574*03ce13f7SAndroid Build Coastguard Worker   if (Src->getType() == IceType_i64) {
5575*03ce13f7SAndroid Build Coastguard Worker     Src = legalizeUndef(Src);
5576*03ce13f7SAndroid Build Coastguard Worker     Variable *Src0Lo = legalizeToReg(loOperand(Src));
5577*03ce13f7SAndroid Build Coastguard Worker     Variable *Src0Hi = legalizeToReg(hiOperand(Src));
5578*03ce13f7SAndroid Build Coastguard Worker     for (SizeT I = 0; I < NumCases; ++I) {
5579*03ce13f7SAndroid Build Coastguard Worker       Operand *ValueLo = Ctx->getConstantInt32(Instr->getValue(I));
5580*03ce13f7SAndroid Build Coastguard Worker       Operand *ValueHi = Ctx->getConstantInt32(Instr->getValue(I) >> 32);
5581*03ce13f7SAndroid Build Coastguard Worker       CfgNode *TargetTrue = Instr->getLabel(I);
5582*03ce13f7SAndroid Build Coastguard Worker       constexpr CfgNode *NoTarget = nullptr;
5583*03ce13f7SAndroid Build Coastguard Worker       ValueHi = legalizeToReg(ValueHi);
5584*03ce13f7SAndroid Build Coastguard Worker       InstMIPS32Label *IntraLabel = InstMIPS32Label::create(Func, this);
5585*03ce13f7SAndroid Build Coastguard Worker       _br(NoTarget, NoTarget, Src0Hi, ValueHi, IntraLabel,
5586*03ce13f7SAndroid Build Coastguard Worker           CondMIPS32::Cond::NE);
5587*03ce13f7SAndroid Build Coastguard Worker       ValueLo = legalizeToReg(ValueLo);
5588*03ce13f7SAndroid Build Coastguard Worker       _br(NoTarget, TargetTrue, Src0Lo, ValueLo, CondMIPS32::Cond::EQ);
5589*03ce13f7SAndroid Build Coastguard Worker       Context.insert(IntraLabel);
5590*03ce13f7SAndroid Build Coastguard Worker     }
5591*03ce13f7SAndroid Build Coastguard Worker     _br(Instr->getLabelDefault());
5592*03ce13f7SAndroid Build Coastguard Worker     return;
5593*03ce13f7SAndroid Build Coastguard Worker   }
5594*03ce13f7SAndroid Build Coastguard Worker   Variable *SrcVar = legalizeToReg(Src);
5595*03ce13f7SAndroid Build Coastguard Worker   assert(SrcVar->mustHaveReg());
5596*03ce13f7SAndroid Build Coastguard Worker   for (SizeT I = 0; I < NumCases; ++I) {
5597*03ce13f7SAndroid Build Coastguard Worker     Operand *Value = Ctx->getConstantInt32(Instr->getValue(I));
5598*03ce13f7SAndroid Build Coastguard Worker     CfgNode *TargetTrue = Instr->getLabel(I);
5599*03ce13f7SAndroid Build Coastguard Worker     constexpr CfgNode *NoTargetFalse = nullptr;
5600*03ce13f7SAndroid Build Coastguard Worker     Value = legalizeToReg(Value);
5601*03ce13f7SAndroid Build Coastguard Worker     _br(NoTargetFalse, TargetTrue, SrcVar, Value, CondMIPS32::Cond::EQ);
5602*03ce13f7SAndroid Build Coastguard Worker   }
5603*03ce13f7SAndroid Build Coastguard Worker   _br(Instr->getLabelDefault());
5604*03ce13f7SAndroid Build Coastguard Worker }
5605*03ce13f7SAndroid Build Coastguard Worker 
lowerBreakpoint(const InstBreakpoint * Instr)5606*03ce13f7SAndroid Build Coastguard Worker void TargetMIPS32::lowerBreakpoint(const InstBreakpoint *Instr) {
5607*03ce13f7SAndroid Build Coastguard Worker   UnimplementedLoweringError(this, Instr);
5608*03ce13f7SAndroid Build Coastguard Worker }
5609*03ce13f7SAndroid Build Coastguard Worker 
lowerUnreachable(const InstUnreachable *)5610*03ce13f7SAndroid Build Coastguard Worker void TargetMIPS32::lowerUnreachable(const InstUnreachable *) {
5611*03ce13f7SAndroid Build Coastguard Worker   const uint32_t TrapCodeZero = 0;
5612*03ce13f7SAndroid Build Coastguard Worker   _teq(getZero(), getZero(), TrapCodeZero);
5613*03ce13f7SAndroid Build Coastguard Worker }
5614*03ce13f7SAndroid Build Coastguard Worker 
lowerOther(const Inst * Instr)5615*03ce13f7SAndroid Build Coastguard Worker void TargetMIPS32::lowerOther(const Inst *Instr) {
5616*03ce13f7SAndroid Build Coastguard Worker   if (llvm::isa<InstMIPS32Sync>(Instr)) {
5617*03ce13f7SAndroid Build Coastguard Worker     _sync();
5618*03ce13f7SAndroid Build Coastguard Worker   } else {
5619*03ce13f7SAndroid Build Coastguard Worker     TargetLowering::lowerOther(Instr);
5620*03ce13f7SAndroid Build Coastguard Worker   }
5621*03ce13f7SAndroid Build Coastguard Worker }
5622*03ce13f7SAndroid Build Coastguard Worker 
5623*03ce13f7SAndroid Build Coastguard Worker // Turn an i64 Phi instruction into a pair of i32 Phi instructions, to preserve
5624*03ce13f7SAndroid Build Coastguard Worker // integrity of liveness analysis. Undef values are also turned into zeroes,
5625*03ce13f7SAndroid Build Coastguard Worker // since loOperand() and hiOperand() don't expect Undef input.
prelowerPhis()5626*03ce13f7SAndroid Build Coastguard Worker void TargetMIPS32::prelowerPhis() {
5627*03ce13f7SAndroid Build Coastguard Worker   PhiLowering::prelowerPhis32Bit<TargetMIPS32>(this, Context.getNode(), Func);
5628*03ce13f7SAndroid Build Coastguard Worker }
5629*03ce13f7SAndroid Build Coastguard Worker 
postLower()5630*03ce13f7SAndroid Build Coastguard Worker void TargetMIPS32::postLower() {
5631*03ce13f7SAndroid Build Coastguard Worker   if (Func->getOptLevel() == Opt_m1)
5632*03ce13f7SAndroid Build Coastguard Worker     return;
5633*03ce13f7SAndroid Build Coastguard Worker   markRedefinitions();
5634*03ce13f7SAndroid Build Coastguard Worker   Context.availabilityUpdate();
5635*03ce13f7SAndroid Build Coastguard Worker }
5636*03ce13f7SAndroid Build Coastguard Worker 
5637*03ce13f7SAndroid Build Coastguard Worker /* TODO(jvoung): avoid duplicate symbols with multiple targets.
5638*03ce13f7SAndroid Build Coastguard Worker void ConstantUndef::emitWithoutDollar(GlobalContext *) const {
5639*03ce13f7SAndroid Build Coastguard Worker   llvm_unreachable("Not expecting to emitWithoutDollar undef");
5640*03ce13f7SAndroid Build Coastguard Worker }
5641*03ce13f7SAndroid Build Coastguard Worker 
5642*03ce13f7SAndroid Build Coastguard Worker void ConstantUndef::emit(GlobalContext *) const {
5643*03ce13f7SAndroid Build Coastguard Worker   llvm_unreachable("undef value encountered by emitter.");
5644*03ce13f7SAndroid Build Coastguard Worker }
5645*03ce13f7SAndroid Build Coastguard Worker */
5646*03ce13f7SAndroid Build Coastguard Worker 
TargetDataMIPS32(GlobalContext * Ctx)5647*03ce13f7SAndroid Build Coastguard Worker TargetDataMIPS32::TargetDataMIPS32(GlobalContext *Ctx)
5648*03ce13f7SAndroid Build Coastguard Worker     : TargetDataLowering(Ctx) {}
5649*03ce13f7SAndroid Build Coastguard Worker 
5650*03ce13f7SAndroid Build Coastguard Worker // Generate .MIPS.abiflags section. This section contains a versioned data
5651*03ce13f7SAndroid Build Coastguard Worker // structure with essential information required for loader to determine the
5652*03ce13f7SAndroid Build Coastguard Worker // requirements of the application.
emitTargetRODataSections()5653*03ce13f7SAndroid Build Coastguard Worker void TargetDataMIPS32::emitTargetRODataSections() {
5654*03ce13f7SAndroid Build Coastguard Worker   struct MipsABIFlagsSection Flags;
5655*03ce13f7SAndroid Build Coastguard Worker   ELFObjectWriter *Writer = Ctx->getObjectWriter();
5656*03ce13f7SAndroid Build Coastguard Worker   const std::string Name = ".MIPS.abiflags";
5657*03ce13f7SAndroid Build Coastguard Worker   const llvm::ELF::Elf64_Word ShType = llvm::ELF::SHT_MIPS_ABIFLAGS;
5658*03ce13f7SAndroid Build Coastguard Worker   const llvm::ELF::Elf64_Xword ShFlags = llvm::ELF::SHF_ALLOC;
5659*03ce13f7SAndroid Build Coastguard Worker   const llvm::ELF::Elf64_Xword ShAddralign = 8;
5660*03ce13f7SAndroid Build Coastguard Worker   const llvm::ELF::Elf64_Xword ShEntsize = sizeof(Flags);
5661*03ce13f7SAndroid Build Coastguard Worker   Writer->writeTargetRODataSection(
5662*03ce13f7SAndroid Build Coastguard Worker       Name, ShType, ShFlags, ShAddralign, ShEntsize,
5663*03ce13f7SAndroid Build Coastguard Worker       llvm::StringRef(reinterpret_cast<const char *>(&Flags), sizeof(Flags)));
5664*03ce13f7SAndroid Build Coastguard Worker }
5665*03ce13f7SAndroid Build Coastguard Worker 
lowerGlobals(const VariableDeclarationList & Vars,const std::string & SectionSuffix)5666*03ce13f7SAndroid Build Coastguard Worker void TargetDataMIPS32::lowerGlobals(const VariableDeclarationList &Vars,
5667*03ce13f7SAndroid Build Coastguard Worker                                     const std::string &SectionSuffix) {
5668*03ce13f7SAndroid Build Coastguard Worker   const bool IsPIC = false;
5669*03ce13f7SAndroid Build Coastguard Worker   switch (getFlags().getOutFileType()) {
5670*03ce13f7SAndroid Build Coastguard Worker   case FT_Elf: {
5671*03ce13f7SAndroid Build Coastguard Worker     ELFObjectWriter *Writer = Ctx->getObjectWriter();
5672*03ce13f7SAndroid Build Coastguard Worker     Writer->writeDataSection(Vars, llvm::ELF::R_MIPS_32, SectionSuffix, IsPIC);
5673*03ce13f7SAndroid Build Coastguard Worker   } break;
5674*03ce13f7SAndroid Build Coastguard Worker   case FT_Asm:
5675*03ce13f7SAndroid Build Coastguard Worker   case FT_Iasm: {
5676*03ce13f7SAndroid Build Coastguard Worker     OstreamLocker L(Ctx);
5677*03ce13f7SAndroid Build Coastguard Worker     for (const VariableDeclaration *Var : Vars) {
5678*03ce13f7SAndroid Build Coastguard Worker       if (getFlags().matchTranslateOnly(Var->getName(), 0)) {
5679*03ce13f7SAndroid Build Coastguard Worker         emitGlobal(*Var, SectionSuffix);
5680*03ce13f7SAndroid Build Coastguard Worker       }
5681*03ce13f7SAndroid Build Coastguard Worker     }
5682*03ce13f7SAndroid Build Coastguard Worker   } break;
5683*03ce13f7SAndroid Build Coastguard Worker   }
5684*03ce13f7SAndroid Build Coastguard Worker }
5685*03ce13f7SAndroid Build Coastguard Worker 
5686*03ce13f7SAndroid Build Coastguard Worker namespace {
5687*03ce13f7SAndroid Build Coastguard Worker template <typename T> struct ConstantPoolEmitterTraits;
5688*03ce13f7SAndroid Build Coastguard Worker 
5689*03ce13f7SAndroid Build Coastguard Worker static_assert(sizeof(uint64_t) == 8,
5690*03ce13f7SAndroid Build Coastguard Worker               "uint64_t is supposed to be 8 bytes wide.");
5691*03ce13f7SAndroid Build Coastguard Worker 
5692*03ce13f7SAndroid Build Coastguard Worker // TODO(jaydeep.patil): implement the following when implementing constant
5693*03ce13f7SAndroid Build Coastguard Worker // randomization:
5694*03ce13f7SAndroid Build Coastguard Worker //  * template <> struct ConstantPoolEmitterTraits<uint8_t>
5695*03ce13f7SAndroid Build Coastguard Worker //  * template <> struct ConstantPoolEmitterTraits<uint16_t>
5696*03ce13f7SAndroid Build Coastguard Worker //  * template <> struct ConstantPoolEmitterTraits<uint32_t>
5697*03ce13f7SAndroid Build Coastguard Worker template <> struct ConstantPoolEmitterTraits<float> {
5698*03ce13f7SAndroid Build Coastguard Worker   using ConstantType = ConstantFloat;
5699*03ce13f7SAndroid Build Coastguard Worker   static constexpr Type IceType = IceType_f32;
5700*03ce13f7SAndroid Build Coastguard Worker   // AsmTag and TypeName can't be constexpr because llvm::StringRef is unhappy
5701*03ce13f7SAndroid Build Coastguard Worker   // about them being constexpr.
5702*03ce13f7SAndroid Build Coastguard Worker   static const char AsmTag[];
5703*03ce13f7SAndroid Build Coastguard Worker   static const char TypeName[];
bitcastToUint64Ice::MIPS32::__anon466779d10611::ConstantPoolEmitterTraits5704*03ce13f7SAndroid Build Coastguard Worker   static uint64_t bitcastToUint64(float Value) {
5705*03ce13f7SAndroid Build Coastguard Worker     static_assert(sizeof(Value) == sizeof(uint32_t),
5706*03ce13f7SAndroid Build Coastguard Worker                   "Float should be 4 bytes.");
5707*03ce13f7SAndroid Build Coastguard Worker     const uint32_t IntValue = Utils::bitCopy<uint32_t>(Value);
5708*03ce13f7SAndroid Build Coastguard Worker     return static_cast<uint64_t>(IntValue);
5709*03ce13f7SAndroid Build Coastguard Worker   }
5710*03ce13f7SAndroid Build Coastguard Worker };
5711*03ce13f7SAndroid Build Coastguard Worker const char ConstantPoolEmitterTraits<float>::AsmTag[] = ".word";
5712*03ce13f7SAndroid Build Coastguard Worker const char ConstantPoolEmitterTraits<float>::TypeName[] = "f32";
5713*03ce13f7SAndroid Build Coastguard Worker 
5714*03ce13f7SAndroid Build Coastguard Worker template <> struct ConstantPoolEmitterTraits<double> {
5715*03ce13f7SAndroid Build Coastguard Worker   using ConstantType = ConstantDouble;
5716*03ce13f7SAndroid Build Coastguard Worker   static constexpr Type IceType = IceType_f64;
5717*03ce13f7SAndroid Build Coastguard Worker   static const char AsmTag[];
5718*03ce13f7SAndroid Build Coastguard Worker   static const char TypeName[];
bitcastToUint64Ice::MIPS32::__anon466779d10611::ConstantPoolEmitterTraits5719*03ce13f7SAndroid Build Coastguard Worker   static uint64_t bitcastToUint64(double Value) {
5720*03ce13f7SAndroid Build Coastguard Worker     static_assert(sizeof(double) == sizeof(uint64_t),
5721*03ce13f7SAndroid Build Coastguard Worker                   "Double should be 8 bytes.");
5722*03ce13f7SAndroid Build Coastguard Worker     return Utils::bitCopy<uint64_t>(Value);
5723*03ce13f7SAndroid Build Coastguard Worker   }
5724*03ce13f7SAndroid Build Coastguard Worker };
5725*03ce13f7SAndroid Build Coastguard Worker const char ConstantPoolEmitterTraits<double>::AsmTag[] = ".quad";
5726*03ce13f7SAndroid Build Coastguard Worker const char ConstantPoolEmitterTraits<double>::TypeName[] = "f64";
5727*03ce13f7SAndroid Build Coastguard Worker 
5728*03ce13f7SAndroid Build Coastguard Worker template <typename T>
emitConstant(Ostream & Str,const typename ConstantPoolEmitterTraits<T>::ConstantType * Const)5729*03ce13f7SAndroid Build Coastguard Worker void emitConstant(
5730*03ce13f7SAndroid Build Coastguard Worker     Ostream &Str,
5731*03ce13f7SAndroid Build Coastguard Worker     const typename ConstantPoolEmitterTraits<T>::ConstantType *Const) {
5732*03ce13f7SAndroid Build Coastguard Worker   if (!BuildDefs::dump())
5733*03ce13f7SAndroid Build Coastguard Worker     return;
5734*03ce13f7SAndroid Build Coastguard Worker   using Traits = ConstantPoolEmitterTraits<T>;
5735*03ce13f7SAndroid Build Coastguard Worker   Str << Const->getLabelName();
5736*03ce13f7SAndroid Build Coastguard Worker   T Value = Const->getValue();
5737*03ce13f7SAndroid Build Coastguard Worker   Str << ":\n\t" << Traits::AsmTag << "\t0x";
5738*03ce13f7SAndroid Build Coastguard Worker   Str.write_hex(Traits::bitcastToUint64(Value));
5739*03ce13f7SAndroid Build Coastguard Worker   Str << "\t/* " << Traits::TypeName << " " << Value << " */\n";
5740*03ce13f7SAndroid Build Coastguard Worker }
5741*03ce13f7SAndroid Build Coastguard Worker 
emitConstantPool(GlobalContext * Ctx)5742*03ce13f7SAndroid Build Coastguard Worker template <typename T> void emitConstantPool(GlobalContext *Ctx) {
5743*03ce13f7SAndroid Build Coastguard Worker   if (!BuildDefs::dump())
5744*03ce13f7SAndroid Build Coastguard Worker     return;
5745*03ce13f7SAndroid Build Coastguard Worker   using Traits = ConstantPoolEmitterTraits<T>;
5746*03ce13f7SAndroid Build Coastguard Worker   static constexpr size_t MinimumAlignment = 4;
5747*03ce13f7SAndroid Build Coastguard Worker   SizeT Align = std::max(MinimumAlignment, typeAlignInBytes(Traits::IceType));
5748*03ce13f7SAndroid Build Coastguard Worker   assert((Align % 4) == 0 && "Constants should be aligned");
5749*03ce13f7SAndroid Build Coastguard Worker   Ostream &Str = Ctx->getStrEmit();
5750*03ce13f7SAndroid Build Coastguard Worker   ConstantList Pool = Ctx->getConstantPool(Traits::IceType);
5751*03ce13f7SAndroid Build Coastguard Worker   Str << "\t.section\t.rodata.cst" << Align << ",\"aM\",%progbits," << Align
5752*03ce13f7SAndroid Build Coastguard Worker       << "\n"
5753*03ce13f7SAndroid Build Coastguard Worker       << "\t.align\t" << (Align == 4 ? 2 : 3) << "\n";
5754*03ce13f7SAndroid Build Coastguard Worker   for (Constant *C : Pool) {
5755*03ce13f7SAndroid Build Coastguard Worker     if (!C->getShouldBePooled()) {
5756*03ce13f7SAndroid Build Coastguard Worker       continue;
5757*03ce13f7SAndroid Build Coastguard Worker     }
5758*03ce13f7SAndroid Build Coastguard Worker     emitConstant<T>(Str, llvm::dyn_cast<typename Traits::ConstantType>(C));
5759*03ce13f7SAndroid Build Coastguard Worker   }
5760*03ce13f7SAndroid Build Coastguard Worker }
5761*03ce13f7SAndroid Build Coastguard Worker } // end of anonymous namespace
5762*03ce13f7SAndroid Build Coastguard Worker 
lowerConstants()5763*03ce13f7SAndroid Build Coastguard Worker void TargetDataMIPS32::lowerConstants() {
5764*03ce13f7SAndroid Build Coastguard Worker   if (getFlags().getDisableTranslation())
5765*03ce13f7SAndroid Build Coastguard Worker     return;
5766*03ce13f7SAndroid Build Coastguard Worker   switch (getFlags().getOutFileType()) {
5767*03ce13f7SAndroid Build Coastguard Worker   case FT_Elf: {
5768*03ce13f7SAndroid Build Coastguard Worker     ELFObjectWriter *Writer = Ctx->getObjectWriter();
5769*03ce13f7SAndroid Build Coastguard Worker     Writer->writeConstantPool<ConstantFloat>(IceType_f32);
5770*03ce13f7SAndroid Build Coastguard Worker     Writer->writeConstantPool<ConstantDouble>(IceType_f64);
5771*03ce13f7SAndroid Build Coastguard Worker   } break;
5772*03ce13f7SAndroid Build Coastguard Worker   case FT_Asm:
5773*03ce13f7SAndroid Build Coastguard Worker   case FT_Iasm: {
5774*03ce13f7SAndroid Build Coastguard Worker     OstreamLocker _(Ctx);
5775*03ce13f7SAndroid Build Coastguard Worker     emitConstantPool<float>(Ctx);
5776*03ce13f7SAndroid Build Coastguard Worker     emitConstantPool<double>(Ctx);
5777*03ce13f7SAndroid Build Coastguard Worker     break;
5778*03ce13f7SAndroid Build Coastguard Worker   }
5779*03ce13f7SAndroid Build Coastguard Worker   }
5780*03ce13f7SAndroid Build Coastguard Worker }
5781*03ce13f7SAndroid Build Coastguard Worker 
lowerJumpTables()5782*03ce13f7SAndroid Build Coastguard Worker void TargetDataMIPS32::lowerJumpTables() {
5783*03ce13f7SAndroid Build Coastguard Worker   if (getFlags().getDisableTranslation())
5784*03ce13f7SAndroid Build Coastguard Worker     return;
5785*03ce13f7SAndroid Build Coastguard Worker }
5786*03ce13f7SAndroid Build Coastguard Worker 
5787*03ce13f7SAndroid Build Coastguard Worker // Helper for legalize() to emit the right code to lower an operand to a
5788*03ce13f7SAndroid Build Coastguard Worker // register of the appropriate type.
copyToReg(Operand * Src,RegNumT RegNum)5789*03ce13f7SAndroid Build Coastguard Worker Variable *TargetMIPS32::copyToReg(Operand *Src, RegNumT RegNum) {
5790*03ce13f7SAndroid Build Coastguard Worker   Type Ty = Src->getType();
5791*03ce13f7SAndroid Build Coastguard Worker   Variable *Reg = makeReg(Ty, RegNum);
5792*03ce13f7SAndroid Build Coastguard Worker   if (isVectorType(Ty)) {
5793*03ce13f7SAndroid Build Coastguard Worker     llvm::report_fatal_error("Invalid copy from vector type.");
5794*03ce13f7SAndroid Build Coastguard Worker   } else {
5795*03ce13f7SAndroid Build Coastguard Worker     if (auto *Mem = llvm::dyn_cast<OperandMIPS32Mem>(Src)) {
5796*03ce13f7SAndroid Build Coastguard Worker       _lw(Reg, Mem);
5797*03ce13f7SAndroid Build Coastguard Worker     } else {
5798*03ce13f7SAndroid Build Coastguard Worker       _mov(Reg, Src);
5799*03ce13f7SAndroid Build Coastguard Worker     }
5800*03ce13f7SAndroid Build Coastguard Worker   }
5801*03ce13f7SAndroid Build Coastguard Worker   return Reg;
5802*03ce13f7SAndroid Build Coastguard Worker }
5803*03ce13f7SAndroid Build Coastguard Worker 
legalize(Operand * From,LegalMask Allowed,RegNumT RegNum)5804*03ce13f7SAndroid Build Coastguard Worker Operand *TargetMIPS32::legalize(Operand *From, LegalMask Allowed,
5805*03ce13f7SAndroid Build Coastguard Worker                                 RegNumT RegNum) {
5806*03ce13f7SAndroid Build Coastguard Worker   Type Ty = From->getType();
5807*03ce13f7SAndroid Build Coastguard Worker   // Assert that a physical register is allowed.  To date, all calls
5808*03ce13f7SAndroid Build Coastguard Worker   // to legalize() allow a physical register. Legal_Flex converts
5809*03ce13f7SAndroid Build Coastguard Worker   // registers to the right type OperandMIPS32FlexReg as needed.
5810*03ce13f7SAndroid Build Coastguard Worker   assert(Allowed & Legal_Reg);
5811*03ce13f7SAndroid Build Coastguard Worker 
5812*03ce13f7SAndroid Build Coastguard Worker   if (RegNum.hasNoValue()) {
5813*03ce13f7SAndroid Build Coastguard Worker     if (Variable *Subst = getContext().availabilityGet(From)) {
5814*03ce13f7SAndroid Build Coastguard Worker       // At this point we know there is a potential substitution available.
5815*03ce13f7SAndroid Build Coastguard Worker       if (!Subst->isRematerializable() && Subst->mustHaveReg() &&
5816*03ce13f7SAndroid Build Coastguard Worker           !Subst->hasReg()) {
5817*03ce13f7SAndroid Build Coastguard Worker         // At this point we know the substitution will have a register.
5818*03ce13f7SAndroid Build Coastguard Worker         if (From->getType() == Subst->getType()) {
5819*03ce13f7SAndroid Build Coastguard Worker           // At this point we know the substitution's register is compatible.
5820*03ce13f7SAndroid Build Coastguard Worker           return Subst;
5821*03ce13f7SAndroid Build Coastguard Worker         }
5822*03ce13f7SAndroid Build Coastguard Worker       }
5823*03ce13f7SAndroid Build Coastguard Worker     }
5824*03ce13f7SAndroid Build Coastguard Worker   }
5825*03ce13f7SAndroid Build Coastguard Worker 
5826*03ce13f7SAndroid Build Coastguard Worker   // Go through the various types of operands:
5827*03ce13f7SAndroid Build Coastguard Worker   // OperandMIPS32Mem, Constant, and Variable.
5828*03ce13f7SAndroid Build Coastguard Worker   // Given the above assertion, if type of operand is not legal
5829*03ce13f7SAndroid Build Coastguard Worker   // (e.g., OperandMIPS32Mem and !Legal_Mem), we can always copy
5830*03ce13f7SAndroid Build Coastguard Worker   // to a register.
5831*03ce13f7SAndroid Build Coastguard Worker   if (auto *Mem = llvm::dyn_cast<OperandMIPS32Mem>(From)) {
5832*03ce13f7SAndroid Build Coastguard Worker     // Base must be in a physical register.
5833*03ce13f7SAndroid Build Coastguard Worker     Variable *Base = Mem->getBase();
5834*03ce13f7SAndroid Build Coastguard Worker     ConstantInteger32 *Offset = llvm::cast<ConstantInteger32>(Mem->getOffset());
5835*03ce13f7SAndroid Build Coastguard Worker     Variable *RegBase = nullptr;
5836*03ce13f7SAndroid Build Coastguard Worker     assert(Base);
5837*03ce13f7SAndroid Build Coastguard Worker 
5838*03ce13f7SAndroid Build Coastguard Worker     RegBase = llvm::cast<Variable>(
5839*03ce13f7SAndroid Build Coastguard Worker         legalize(Base, Legal_Reg | Legal_Rematerializable));
5840*03ce13f7SAndroid Build Coastguard Worker 
5841*03ce13f7SAndroid Build Coastguard Worker     if (Offset != nullptr && Offset->getValue() != 0) {
5842*03ce13f7SAndroid Build Coastguard Worker       static constexpr bool ZeroExt = false;
5843*03ce13f7SAndroid Build Coastguard Worker       if (!OperandMIPS32Mem::canHoldOffset(Ty, ZeroExt, Offset->getValue())) {
5844*03ce13f7SAndroid Build Coastguard Worker         llvm::report_fatal_error("Invalid memory offset.");
5845*03ce13f7SAndroid Build Coastguard Worker       }
5846*03ce13f7SAndroid Build Coastguard Worker     }
5847*03ce13f7SAndroid Build Coastguard Worker 
5848*03ce13f7SAndroid Build Coastguard Worker     // Create a new operand if there was a change.
5849*03ce13f7SAndroid Build Coastguard Worker     if (Base != RegBase) {
5850*03ce13f7SAndroid Build Coastguard Worker       Mem = OperandMIPS32Mem::create(Func, Ty, RegBase, Offset,
5851*03ce13f7SAndroid Build Coastguard Worker                                      Mem->getAddrMode());
5852*03ce13f7SAndroid Build Coastguard Worker     }
5853*03ce13f7SAndroid Build Coastguard Worker 
5854*03ce13f7SAndroid Build Coastguard Worker     if (Allowed & Legal_Mem) {
5855*03ce13f7SAndroid Build Coastguard Worker       From = Mem;
5856*03ce13f7SAndroid Build Coastguard Worker     } else {
5857*03ce13f7SAndroid Build Coastguard Worker       Variable *Reg = makeReg(Ty, RegNum);
5858*03ce13f7SAndroid Build Coastguard Worker       _lw(Reg, Mem);
5859*03ce13f7SAndroid Build Coastguard Worker       From = Reg;
5860*03ce13f7SAndroid Build Coastguard Worker     }
5861*03ce13f7SAndroid Build Coastguard Worker     return From;
5862*03ce13f7SAndroid Build Coastguard Worker   }
5863*03ce13f7SAndroid Build Coastguard Worker 
5864*03ce13f7SAndroid Build Coastguard Worker   if (llvm::isa<Constant>(From)) {
5865*03ce13f7SAndroid Build Coastguard Worker     if (llvm::isa<ConstantUndef>(From)) {
5866*03ce13f7SAndroid Build Coastguard Worker       From = legalizeUndef(From, RegNum);
5867*03ce13f7SAndroid Build Coastguard Worker       if (isVectorType(Ty))
5868*03ce13f7SAndroid Build Coastguard Worker         return From;
5869*03ce13f7SAndroid Build Coastguard Worker     }
5870*03ce13f7SAndroid Build Coastguard Worker     if (auto *C = llvm::dyn_cast<ConstantRelocatable>(From)) {
5871*03ce13f7SAndroid Build Coastguard Worker       Variable *Reg = makeReg(Ty, RegNum);
5872*03ce13f7SAndroid Build Coastguard Worker       Variable *TReg = makeReg(Ty, RegNum);
5873*03ce13f7SAndroid Build Coastguard Worker       _lui(TReg, C, RO_Hi);
5874*03ce13f7SAndroid Build Coastguard Worker       _addiu(Reg, TReg, C, RO_Lo);
5875*03ce13f7SAndroid Build Coastguard Worker       return Reg;
5876*03ce13f7SAndroid Build Coastguard Worker     } else if (auto *C32 = llvm::dyn_cast<ConstantInteger32>(From)) {
5877*03ce13f7SAndroid Build Coastguard Worker       const uint32_t Value = C32->getValue();
5878*03ce13f7SAndroid Build Coastguard Worker       // Use addiu if the immediate is a 16bit value. Otherwise load it
5879*03ce13f7SAndroid Build Coastguard Worker       // using a lui-ori instructions.
5880*03ce13f7SAndroid Build Coastguard Worker       Variable *Reg = makeReg(Ty, RegNum);
5881*03ce13f7SAndroid Build Coastguard Worker       if (isInt<16>(int32_t(Value))) {
5882*03ce13f7SAndroid Build Coastguard Worker         Variable *Zero = makeReg(Ty, RegMIPS32::Reg_ZERO);
5883*03ce13f7SAndroid Build Coastguard Worker         Context.insert<InstFakeDef>(Zero);
5884*03ce13f7SAndroid Build Coastguard Worker         _addiu(Reg, Zero, Value);
5885*03ce13f7SAndroid Build Coastguard Worker       } else {
5886*03ce13f7SAndroid Build Coastguard Worker         uint32_t UpperBits = (Value >> 16) & 0xFFFF;
5887*03ce13f7SAndroid Build Coastguard Worker         uint32_t LowerBits = Value & 0xFFFF;
5888*03ce13f7SAndroid Build Coastguard Worker         if (LowerBits) {
5889*03ce13f7SAndroid Build Coastguard Worker           Variable *TReg = makeReg(Ty, RegNum);
5890*03ce13f7SAndroid Build Coastguard Worker           _lui(TReg, Ctx->getConstantInt32(UpperBits));
5891*03ce13f7SAndroid Build Coastguard Worker           _ori(Reg, TReg, LowerBits);
5892*03ce13f7SAndroid Build Coastguard Worker         } else {
5893*03ce13f7SAndroid Build Coastguard Worker           _lui(Reg, Ctx->getConstantInt32(UpperBits));
5894*03ce13f7SAndroid Build Coastguard Worker         }
5895*03ce13f7SAndroid Build Coastguard Worker       }
5896*03ce13f7SAndroid Build Coastguard Worker       return Reg;
5897*03ce13f7SAndroid Build Coastguard Worker     } else if (isScalarFloatingType(Ty)) {
5898*03ce13f7SAndroid Build Coastguard Worker       auto *CFrom = llvm::cast<Constant>(From);
5899*03ce13f7SAndroid Build Coastguard Worker       Variable *TReg = makeReg(Ty);
5900*03ce13f7SAndroid Build Coastguard Worker       if (!CFrom->getShouldBePooled()) {
5901*03ce13f7SAndroid Build Coastguard Worker         // Float/Double constant 0 is not pooled.
5902*03ce13f7SAndroid Build Coastguard Worker         Context.insert<InstFakeDef>(TReg);
5903*03ce13f7SAndroid Build Coastguard Worker         _mov(TReg, getZero());
5904*03ce13f7SAndroid Build Coastguard Worker       } else {
5905*03ce13f7SAndroid Build Coastguard Worker         // Load floats/doubles from literal pool.
5906*03ce13f7SAndroid Build Coastguard Worker         Constant *Offset = Ctx->getConstantSym(0, CFrom->getLabelName());
5907*03ce13f7SAndroid Build Coastguard Worker         Variable *TReg1 = makeReg(getPointerType());
5908*03ce13f7SAndroid Build Coastguard Worker         _lui(TReg1, Offset, RO_Hi);
5909*03ce13f7SAndroid Build Coastguard Worker         OperandMIPS32Mem *Addr =
5910*03ce13f7SAndroid Build Coastguard Worker             OperandMIPS32Mem::create(Func, Ty, TReg1, Offset);
5911*03ce13f7SAndroid Build Coastguard Worker         if (Ty == IceType_f32)
5912*03ce13f7SAndroid Build Coastguard Worker           _lwc1(TReg, Addr, RO_Lo);
5913*03ce13f7SAndroid Build Coastguard Worker         else
5914*03ce13f7SAndroid Build Coastguard Worker           _ldc1(TReg, Addr, RO_Lo);
5915*03ce13f7SAndroid Build Coastguard Worker       }
5916*03ce13f7SAndroid Build Coastguard Worker       return copyToReg(TReg, RegNum);
5917*03ce13f7SAndroid Build Coastguard Worker     }
5918*03ce13f7SAndroid Build Coastguard Worker   }
5919*03ce13f7SAndroid Build Coastguard Worker 
5920*03ce13f7SAndroid Build Coastguard Worker   if (auto *Var = llvm::dyn_cast<Variable>(From)) {
5921*03ce13f7SAndroid Build Coastguard Worker     if (Var->isRematerializable()) {
5922*03ce13f7SAndroid Build Coastguard Worker       if (Allowed & Legal_Rematerializable) {
5923*03ce13f7SAndroid Build Coastguard Worker         return From;
5924*03ce13f7SAndroid Build Coastguard Worker       }
5925*03ce13f7SAndroid Build Coastguard Worker 
5926*03ce13f7SAndroid Build Coastguard Worker       Variable *T = makeReg(Var->getType(), RegNum);
5927*03ce13f7SAndroid Build Coastguard Worker       _mov(T, Var);
5928*03ce13f7SAndroid Build Coastguard Worker       return T;
5929*03ce13f7SAndroid Build Coastguard Worker     }
5930*03ce13f7SAndroid Build Coastguard Worker     // Check if the variable is guaranteed a physical register.  This
5931*03ce13f7SAndroid Build Coastguard Worker     // can happen either when the variable is pre-colored or when it is
5932*03ce13f7SAndroid Build Coastguard Worker     // assigned infinite weight.
5933*03ce13f7SAndroid Build Coastguard Worker     bool MustHaveRegister = (Var->hasReg() || Var->mustHaveReg());
5934*03ce13f7SAndroid Build Coastguard Worker     // We need a new physical register for the operand if:
5935*03ce13f7SAndroid Build Coastguard Worker     //   Mem is not allowed and Var isn't guaranteed a physical
5936*03ce13f7SAndroid Build Coastguard Worker     //   register, or
5937*03ce13f7SAndroid Build Coastguard Worker     //   RegNum is required and Var->getRegNum() doesn't match.
5938*03ce13f7SAndroid Build Coastguard Worker     if ((!(Allowed & Legal_Mem) && !MustHaveRegister) ||
5939*03ce13f7SAndroid Build Coastguard Worker         (RegNum.hasValue() && RegNum != Var->getRegNum())) {
5940*03ce13f7SAndroid Build Coastguard Worker       From = copyToReg(From, RegNum);
5941*03ce13f7SAndroid Build Coastguard Worker     }
5942*03ce13f7SAndroid Build Coastguard Worker     return From;
5943*03ce13f7SAndroid Build Coastguard Worker   }
5944*03ce13f7SAndroid Build Coastguard Worker   return From;
5945*03ce13f7SAndroid Build Coastguard Worker }
5946*03ce13f7SAndroid Build Coastguard Worker 
5947*03ce13f7SAndroid Build Coastguard Worker namespace BoolFolding {
5948*03ce13f7SAndroid Build Coastguard Worker // TODO(sagar.thakur): Add remaining instruction kinds to shouldTrackProducer()
5949*03ce13f7SAndroid Build Coastguard Worker // and isValidConsumer()
shouldTrackProducer(const Inst & Instr)5950*03ce13f7SAndroid Build Coastguard Worker bool shouldTrackProducer(const Inst &Instr) {
5951*03ce13f7SAndroid Build Coastguard Worker   return Instr.getKind() == Inst::Icmp;
5952*03ce13f7SAndroid Build Coastguard Worker }
5953*03ce13f7SAndroid Build Coastguard Worker 
isValidConsumer(const Inst & Instr)5954*03ce13f7SAndroid Build Coastguard Worker bool isValidConsumer(const Inst &Instr) { return Instr.getKind() == Inst::Br; }
5955*03ce13f7SAndroid Build Coastguard Worker } // end of namespace BoolFolding
5956*03ce13f7SAndroid Build Coastguard Worker 
recordProducers(CfgNode * Node)5957*03ce13f7SAndroid Build Coastguard Worker void TargetMIPS32::ComputationTracker::recordProducers(CfgNode *Node) {
5958*03ce13f7SAndroid Build Coastguard Worker   for (Inst &Instr : Node->getInsts()) {
5959*03ce13f7SAndroid Build Coastguard Worker     if (Instr.isDeleted())
5960*03ce13f7SAndroid Build Coastguard Worker       continue;
5961*03ce13f7SAndroid Build Coastguard Worker     // Check whether Instr is a valid producer.
5962*03ce13f7SAndroid Build Coastguard Worker     Variable *Dest = Instr.getDest();
5963*03ce13f7SAndroid Build Coastguard Worker     if (Dest // only consider instructions with an actual dest var; and
5964*03ce13f7SAndroid Build Coastguard Worker         && Dest->getType() == IceType_i1 // only bool-type dest vars; and
5965*03ce13f7SAndroid Build Coastguard Worker         && BoolFolding::shouldTrackProducer(Instr)) { // white-listed instr.
5966*03ce13f7SAndroid Build Coastguard Worker       KnownComputations.emplace(Dest->getIndex(),
5967*03ce13f7SAndroid Build Coastguard Worker                                 ComputationEntry(&Instr, IceType_i1));
5968*03ce13f7SAndroid Build Coastguard Worker     }
5969*03ce13f7SAndroid Build Coastguard Worker     // Check each src variable against the map.
5970*03ce13f7SAndroid Build Coastguard Worker     FOREACH_VAR_IN_INST(Var, Instr) {
5971*03ce13f7SAndroid Build Coastguard Worker       SizeT VarNum = Var->getIndex();
5972*03ce13f7SAndroid Build Coastguard Worker       auto ComputationIter = KnownComputations.find(VarNum);
5973*03ce13f7SAndroid Build Coastguard Worker       if (ComputationIter == KnownComputations.end()) {
5974*03ce13f7SAndroid Build Coastguard Worker         continue;
5975*03ce13f7SAndroid Build Coastguard Worker       }
5976*03ce13f7SAndroid Build Coastguard Worker 
5977*03ce13f7SAndroid Build Coastguard Worker       ++ComputationIter->second.NumUses;
5978*03ce13f7SAndroid Build Coastguard Worker       switch (ComputationIter->second.ComputationType) {
5979*03ce13f7SAndroid Build Coastguard Worker       default:
5980*03ce13f7SAndroid Build Coastguard Worker         KnownComputations.erase(VarNum);
5981*03ce13f7SAndroid Build Coastguard Worker         continue;
5982*03ce13f7SAndroid Build Coastguard Worker       case IceType_i1:
5983*03ce13f7SAndroid Build Coastguard Worker         if (!BoolFolding::isValidConsumer(Instr)) {
5984*03ce13f7SAndroid Build Coastguard Worker           KnownComputations.erase(VarNum);
5985*03ce13f7SAndroid Build Coastguard Worker           continue;
5986*03ce13f7SAndroid Build Coastguard Worker         }
5987*03ce13f7SAndroid Build Coastguard Worker         break;
5988*03ce13f7SAndroid Build Coastguard Worker       }
5989*03ce13f7SAndroid Build Coastguard Worker 
5990*03ce13f7SAndroid Build Coastguard Worker       if (Instr.isLastUse(Var)) {
5991*03ce13f7SAndroid Build Coastguard Worker         ComputationIter->second.IsLiveOut = false;
5992*03ce13f7SAndroid Build Coastguard Worker       }
5993*03ce13f7SAndroid Build Coastguard Worker     }
5994*03ce13f7SAndroid Build Coastguard Worker   }
5995*03ce13f7SAndroid Build Coastguard Worker 
5996*03ce13f7SAndroid Build Coastguard Worker   for (auto Iter = KnownComputations.begin(), End = KnownComputations.end();
5997*03ce13f7SAndroid Build Coastguard Worker        Iter != End;) {
5998*03ce13f7SAndroid Build Coastguard Worker     // Disable the folding if its dest may be live beyond this block.
5999*03ce13f7SAndroid Build Coastguard Worker     if (Iter->second.IsLiveOut || Iter->second.NumUses > 1) {
6000*03ce13f7SAndroid Build Coastguard Worker       Iter = KnownComputations.erase(Iter);
6001*03ce13f7SAndroid Build Coastguard Worker       continue;
6002*03ce13f7SAndroid Build Coastguard Worker     }
6003*03ce13f7SAndroid Build Coastguard Worker 
6004*03ce13f7SAndroid Build Coastguard Worker     // Mark as "dead" rather than outright deleting. This is so that other
6005*03ce13f7SAndroid Build Coastguard Worker     // peephole style optimizations during or before lowering have access to
6006*03ce13f7SAndroid Build Coastguard Worker     // this instruction in undeleted form. See for example
6007*03ce13f7SAndroid Build Coastguard Worker     // tryOptimizedCmpxchgCmpBr().
6008*03ce13f7SAndroid Build Coastguard Worker     Iter->second.Instr->setDead();
6009*03ce13f7SAndroid Build Coastguard Worker     ++Iter;
6010*03ce13f7SAndroid Build Coastguard Worker   }
6011*03ce13f7SAndroid Build Coastguard Worker }
6012*03ce13f7SAndroid Build Coastguard Worker 
TargetHeaderMIPS32(GlobalContext * Ctx)6013*03ce13f7SAndroid Build Coastguard Worker TargetHeaderMIPS32::TargetHeaderMIPS32(GlobalContext *Ctx)
6014*03ce13f7SAndroid Build Coastguard Worker     : TargetHeaderLowering(Ctx) {}
6015*03ce13f7SAndroid Build Coastguard Worker 
lower()6016*03ce13f7SAndroid Build Coastguard Worker void TargetHeaderMIPS32::lower() {
6017*03ce13f7SAndroid Build Coastguard Worker   if (!BuildDefs::dump())
6018*03ce13f7SAndroid Build Coastguard Worker     return;
6019*03ce13f7SAndroid Build Coastguard Worker   OstreamLocker L(Ctx);
6020*03ce13f7SAndroid Build Coastguard Worker   Ostream &Str = Ctx->getStrEmit();
6021*03ce13f7SAndroid Build Coastguard Worker   Str << "\t.set\t"
6022*03ce13f7SAndroid Build Coastguard Worker       << "nomicromips\n";
6023*03ce13f7SAndroid Build Coastguard Worker   Str << "\t.set\t"
6024*03ce13f7SAndroid Build Coastguard Worker       << "nomips16\n";
6025*03ce13f7SAndroid Build Coastguard Worker   Str << "\t.set\t"
6026*03ce13f7SAndroid Build Coastguard Worker       << "noat\n";
6027*03ce13f7SAndroid Build Coastguard Worker }
6028*03ce13f7SAndroid Build Coastguard Worker 
6029*03ce13f7SAndroid Build Coastguard Worker SmallBitVector TargetMIPS32::TypeToRegisterSet[RCMIPS32_NUM];
6030*03ce13f7SAndroid Build Coastguard Worker SmallBitVector TargetMIPS32::TypeToRegisterSetUnfiltered[RCMIPS32_NUM];
6031*03ce13f7SAndroid Build Coastguard Worker SmallBitVector TargetMIPS32::RegisterAliases[RegMIPS32::Reg_NUM];
6032*03ce13f7SAndroid Build Coastguard Worker 
6033*03ce13f7SAndroid Build Coastguard Worker } // end of namespace MIPS32
6034*03ce13f7SAndroid Build Coastguard Worker } // end of namespace Ice
6035