xref: /aosp_15_r20/external/swiftshader/third_party/subzero/src/IceTargetLoweringX8664.cpp (revision 03ce13f70fcc45d86ee91b7ee4cab1936a95046e)
1*03ce13f7SAndroid Build Coastguard Worker //===- subzero/src/IceTargetLoweringX8664.cpp - x86-64 lowering -----------===//
2*03ce13f7SAndroid Build Coastguard Worker //
3*03ce13f7SAndroid Build Coastguard Worker //                        The Subzero Code Generator
4*03ce13f7SAndroid Build Coastguard Worker //
5*03ce13f7SAndroid Build Coastguard Worker // This file is distributed under the University of Illinois Open Source
6*03ce13f7SAndroid Build Coastguard Worker // License. See LICENSE.TXT for details.
7*03ce13f7SAndroid Build Coastguard Worker //
8*03ce13f7SAndroid Build Coastguard Worker //===----------------------------------------------------------------------===//
9*03ce13f7SAndroid Build Coastguard Worker ///
10*03ce13f7SAndroid Build Coastguard Worker /// \file
11*03ce13f7SAndroid Build Coastguard Worker /// \brief Implements the TargetLoweringX8664 class, which consists almost
12*03ce13f7SAndroid Build Coastguard Worker /// entirely of the lowering sequence for each high-level instruction.
13*03ce13f7SAndroid Build Coastguard Worker ///
14*03ce13f7SAndroid Build Coastguard Worker //===----------------------------------------------------------------------===//
15*03ce13f7SAndroid Build Coastguard Worker #include "IceTargetLoweringX8664.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 "IceInstVarIter.h"
24*03ce13f7SAndroid Build Coastguard Worker #include "IceInstX8664.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 "IceTargetLoweringX8664.def"
29*03ce13f7SAndroid Build Coastguard Worker #include "IceUtils.h"
30*03ce13f7SAndroid Build Coastguard Worker #include "IceVariableSplitting.h"
31*03ce13f7SAndroid Build Coastguard Worker 
32*03ce13f7SAndroid Build Coastguard Worker #include "llvm/Support/MathExtras.h"
33*03ce13f7SAndroid Build Coastguard Worker 
34*03ce13f7SAndroid Build Coastguard Worker #include <stack>
35*03ce13f7SAndroid Build Coastguard Worker 
36*03ce13f7SAndroid Build Coastguard Worker #if defined(_WIN64)
37*03ce13f7SAndroid Build Coastguard Worker extern "C" void __chkstk();
38*03ce13f7SAndroid Build Coastguard Worker #endif
39*03ce13f7SAndroid Build Coastguard Worker 
40*03ce13f7SAndroid Build Coastguard Worker namespace X8664 {
41*03ce13f7SAndroid Build Coastguard Worker 
createTargetLowering(::Ice::Cfg * Func)42*03ce13f7SAndroid Build Coastguard Worker std::unique_ptr<::Ice::TargetLowering> createTargetLowering(::Ice::Cfg *Func) {
43*03ce13f7SAndroid Build Coastguard Worker   return ::Ice::X8664::TargetX8664::create(Func);
44*03ce13f7SAndroid Build Coastguard Worker }
45*03ce13f7SAndroid Build Coastguard Worker 
46*03ce13f7SAndroid Build Coastguard Worker std::unique_ptr<::Ice::TargetDataLowering>
createTargetDataLowering(::Ice::GlobalContext * Ctx)47*03ce13f7SAndroid Build Coastguard Worker createTargetDataLowering(::Ice::GlobalContext *Ctx) {
48*03ce13f7SAndroid Build Coastguard Worker   return ::Ice::X8664::TargetDataX8664::create(Ctx);
49*03ce13f7SAndroid Build Coastguard Worker }
50*03ce13f7SAndroid Build Coastguard Worker 
51*03ce13f7SAndroid Build Coastguard Worker std::unique_ptr<::Ice::TargetHeaderLowering>
createTargetHeaderLowering(::Ice::GlobalContext * Ctx)52*03ce13f7SAndroid Build Coastguard Worker createTargetHeaderLowering(::Ice::GlobalContext *Ctx) {
53*03ce13f7SAndroid Build Coastguard Worker   return ::Ice::X8664::TargetHeaderX86::create(Ctx);
54*03ce13f7SAndroid Build Coastguard Worker }
55*03ce13f7SAndroid Build Coastguard Worker 
staticInit(::Ice::GlobalContext * Ctx)56*03ce13f7SAndroid Build Coastguard Worker void staticInit(::Ice::GlobalContext *Ctx) {
57*03ce13f7SAndroid Build Coastguard Worker   ::Ice::X8664::TargetX8664::staticInit(Ctx);
58*03ce13f7SAndroid Build Coastguard Worker }
59*03ce13f7SAndroid Build Coastguard Worker 
shouldBePooled(const class::Ice::Constant * C)60*03ce13f7SAndroid Build Coastguard Worker bool shouldBePooled(const class ::Ice::Constant *C) {
61*03ce13f7SAndroid Build Coastguard Worker   return ::Ice::X8664::TargetX8664::shouldBePooled(C);
62*03ce13f7SAndroid Build Coastguard Worker }
63*03ce13f7SAndroid Build Coastguard Worker 
getPointerType()64*03ce13f7SAndroid Build Coastguard Worker ::Ice::Type getPointerType() {
65*03ce13f7SAndroid Build Coastguard Worker   return ::Ice::X8664::TargetX8664::getPointerType();
66*03ce13f7SAndroid Build Coastguard Worker }
67*03ce13f7SAndroid Build Coastguard Worker 
68*03ce13f7SAndroid Build Coastguard Worker } // namespace X8664
69*03ce13f7SAndroid Build Coastguard Worker 
70*03ce13f7SAndroid Build Coastguard Worker namespace Ice {
71*03ce13f7SAndroid Build Coastguard Worker namespace X8664 {
72*03ce13f7SAndroid Build Coastguard Worker 
73*03ce13f7SAndroid Build Coastguard Worker /// The number of bits in a byte
74*03ce13f7SAndroid Build Coastguard Worker static constexpr uint32_t X86_CHAR_BIT = 8;
75*03ce13f7SAndroid Build Coastguard Worker /// Size of the return address on the stack
76*03ce13f7SAndroid Build Coastguard Worker static constexpr uint32_t X86_RET_IP_SIZE_BYTES = 8;
77*03ce13f7SAndroid Build Coastguard Worker 
78*03ce13f7SAndroid Build Coastguard Worker /// \name Limits for unrolling memory intrinsics.
79*03ce13f7SAndroid Build Coastguard Worker /// @{
80*03ce13f7SAndroid Build Coastguard Worker static constexpr uint32_t MEMCPY_UNROLL_LIMIT = 8;
81*03ce13f7SAndroid Build Coastguard Worker static constexpr uint32_t MEMMOVE_UNROLL_LIMIT = 8;
82*03ce13f7SAndroid Build Coastguard Worker static constexpr uint32_t MEMSET_UNROLL_LIMIT = 8;
83*03ce13f7SAndroid Build Coastguard Worker /// @}
84*03ce13f7SAndroid Build Coastguard Worker 
85*03ce13f7SAndroid Build Coastguard Worker // The Microsoft x64 ABI requires the caller to allocate a minimum 32 byte
86*03ce13f7SAndroid Build Coastguard Worker // "shadow store" (aka "home space") so that the callee may copy the 4
87*03ce13f7SAndroid Build Coastguard Worker // register args to it.
getShadowStoreSize()88*03ce13f7SAndroid Build Coastguard Worker SizeT getShadowStoreSize() {
89*03ce13f7SAndroid Build Coastguard Worker #if defined(_WIN64)
90*03ce13f7SAndroid Build Coastguard Worker   static const SizeT ShadowStoreSize = 4 * typeWidthInBytes(WordType);
91*03ce13f7SAndroid Build Coastguard Worker   return ShadowStoreSize;
92*03ce13f7SAndroid Build Coastguard Worker #else
93*03ce13f7SAndroid Build Coastguard Worker   return 0;
94*03ce13f7SAndroid Build Coastguard Worker #endif
95*03ce13f7SAndroid Build Coastguard Worker }
96*03ce13f7SAndroid Build Coastguard Worker 
BoolFoldingEntry(Inst * I)97*03ce13f7SAndroid Build Coastguard Worker BoolFoldingEntry::BoolFoldingEntry(Inst *I)
98*03ce13f7SAndroid Build Coastguard Worker     : Instr(I), IsComplex(BoolFolding::hasComplexLowering(I)) {}
99*03ce13f7SAndroid Build Coastguard Worker 
100*03ce13f7SAndroid Build Coastguard Worker BoolFolding::BoolFoldingProducerKind
getProducerKind(const Inst * Instr)101*03ce13f7SAndroid Build Coastguard Worker BoolFolding::getProducerKind(const Inst *Instr) {
102*03ce13f7SAndroid Build Coastguard Worker   if (llvm::isa<InstIcmp>(Instr)) {
103*03ce13f7SAndroid Build Coastguard Worker     return PK_Icmp32;
104*03ce13f7SAndroid Build Coastguard Worker   }
105*03ce13f7SAndroid Build Coastguard Worker   if (llvm::isa<InstFcmp>(Instr))
106*03ce13f7SAndroid Build Coastguard Worker     return PK_Fcmp;
107*03ce13f7SAndroid Build Coastguard Worker   if (auto *Arith = llvm::dyn_cast<InstArithmetic>(Instr)) {
108*03ce13f7SAndroid Build Coastguard Worker     switch (Arith->getOp()) {
109*03ce13f7SAndroid Build Coastguard Worker     default:
110*03ce13f7SAndroid Build Coastguard Worker       return PK_None;
111*03ce13f7SAndroid Build Coastguard Worker     case InstArithmetic::And:
112*03ce13f7SAndroid Build Coastguard Worker     case InstArithmetic::Or:
113*03ce13f7SAndroid Build Coastguard Worker       return PK_Arith;
114*03ce13f7SAndroid Build Coastguard Worker     }
115*03ce13f7SAndroid Build Coastguard Worker   }
116*03ce13f7SAndroid Build Coastguard Worker   return PK_None; // TODO(stichnot): remove this
117*03ce13f7SAndroid Build Coastguard Worker 
118*03ce13f7SAndroid Build Coastguard Worker   if (auto *Cast = llvm::dyn_cast<InstCast>(Instr)) {
119*03ce13f7SAndroid Build Coastguard Worker     switch (Cast->getCastKind()) {
120*03ce13f7SAndroid Build Coastguard Worker     default:
121*03ce13f7SAndroid Build Coastguard Worker       return PK_None;
122*03ce13f7SAndroid Build Coastguard Worker     case InstCast::Trunc:
123*03ce13f7SAndroid Build Coastguard Worker       return PK_Trunc;
124*03ce13f7SAndroid Build Coastguard Worker     }
125*03ce13f7SAndroid Build Coastguard Worker   }
126*03ce13f7SAndroid Build Coastguard Worker   return PK_None;
127*03ce13f7SAndroid Build Coastguard Worker }
128*03ce13f7SAndroid Build Coastguard Worker 
129*03ce13f7SAndroid Build Coastguard Worker BoolFolding::BoolFoldingConsumerKind
getConsumerKind(const Inst * Instr)130*03ce13f7SAndroid Build Coastguard Worker BoolFolding::getConsumerKind(const Inst *Instr) {
131*03ce13f7SAndroid Build Coastguard Worker   if (llvm::isa<InstBr>(Instr))
132*03ce13f7SAndroid Build Coastguard Worker     return CK_Br;
133*03ce13f7SAndroid Build Coastguard Worker   if (llvm::isa<InstSelect>(Instr))
134*03ce13f7SAndroid Build Coastguard Worker     return CK_Select;
135*03ce13f7SAndroid Build Coastguard Worker   return CK_None; // TODO(stichnot): remove this
136*03ce13f7SAndroid Build Coastguard Worker 
137*03ce13f7SAndroid Build Coastguard Worker   if (auto *Cast = llvm::dyn_cast<InstCast>(Instr)) {
138*03ce13f7SAndroid Build Coastguard Worker     switch (Cast->getCastKind()) {
139*03ce13f7SAndroid Build Coastguard Worker     default:
140*03ce13f7SAndroid Build Coastguard Worker       return CK_None;
141*03ce13f7SAndroid Build Coastguard Worker     case InstCast::Sext:
142*03ce13f7SAndroid Build Coastguard Worker       return CK_Sext;
143*03ce13f7SAndroid Build Coastguard Worker     case InstCast::Zext:
144*03ce13f7SAndroid Build Coastguard Worker       return CK_Zext;
145*03ce13f7SAndroid Build Coastguard Worker     }
146*03ce13f7SAndroid Build Coastguard Worker   }
147*03ce13f7SAndroid Build Coastguard Worker   return CK_None;
148*03ce13f7SAndroid Build Coastguard Worker }
149*03ce13f7SAndroid Build Coastguard Worker 
150*03ce13f7SAndroid Build Coastguard Worker /// Returns true if the producing instruction has a "complex" lowering sequence.
151*03ce13f7SAndroid Build Coastguard Worker /// This generally means that its lowering sequence requires more than one
152*03ce13f7SAndroid Build Coastguard Worker /// conditional branch, namely 64-bit integer compares and some floating-point
153*03ce13f7SAndroid Build Coastguard Worker /// compares. When this is true, and there is more than one consumer, we prefer
154*03ce13f7SAndroid Build Coastguard Worker /// to disable the folding optimization because it minimizes branches.
155*03ce13f7SAndroid Build Coastguard Worker 
hasComplexLowering(const Inst * Instr)156*03ce13f7SAndroid Build Coastguard Worker bool BoolFolding::hasComplexLowering(const Inst *Instr) {
157*03ce13f7SAndroid Build Coastguard Worker   switch (getProducerKind(Instr)) {
158*03ce13f7SAndroid Build Coastguard Worker   default:
159*03ce13f7SAndroid Build Coastguard Worker     return false;
160*03ce13f7SAndroid Build Coastguard Worker   case PK_Icmp64:
161*03ce13f7SAndroid Build Coastguard Worker     return false;
162*03ce13f7SAndroid Build Coastguard Worker   case PK_Fcmp:
163*03ce13f7SAndroid Build Coastguard Worker     return TargetX8664::TableFcmp[llvm::cast<InstFcmp>(Instr)->getCondition()]
164*03ce13f7SAndroid Build Coastguard Worker                .C2 != CondX86::Br_None;
165*03ce13f7SAndroid Build Coastguard Worker   }
166*03ce13f7SAndroid Build Coastguard Worker }
167*03ce13f7SAndroid Build Coastguard Worker 
isValidFolding(BoolFolding::BoolFoldingProducerKind ProducerKind,BoolFolding::BoolFoldingConsumerKind ConsumerKind)168*03ce13f7SAndroid Build Coastguard Worker bool BoolFolding::isValidFolding(
169*03ce13f7SAndroid Build Coastguard Worker     BoolFolding::BoolFoldingProducerKind ProducerKind,
170*03ce13f7SAndroid Build Coastguard Worker     BoolFolding::BoolFoldingConsumerKind ConsumerKind) {
171*03ce13f7SAndroid Build Coastguard Worker   switch (ProducerKind) {
172*03ce13f7SAndroid Build Coastguard Worker   default:
173*03ce13f7SAndroid Build Coastguard Worker     return false;
174*03ce13f7SAndroid Build Coastguard Worker   case PK_Icmp32:
175*03ce13f7SAndroid Build Coastguard Worker   case PK_Icmp64:
176*03ce13f7SAndroid Build Coastguard Worker   case PK_Fcmp:
177*03ce13f7SAndroid Build Coastguard Worker     return (ConsumerKind == CK_Br) || (ConsumerKind == CK_Select);
178*03ce13f7SAndroid Build Coastguard Worker   case PK_Arith:
179*03ce13f7SAndroid Build Coastguard Worker     return ConsumerKind == CK_Br;
180*03ce13f7SAndroid Build Coastguard Worker   }
181*03ce13f7SAndroid Build Coastguard Worker }
182*03ce13f7SAndroid Build Coastguard Worker 
init(CfgNode * Node)183*03ce13f7SAndroid Build Coastguard Worker void BoolFolding::init(CfgNode *Node) {
184*03ce13f7SAndroid Build Coastguard Worker   Producers.clear();
185*03ce13f7SAndroid Build Coastguard Worker   for (Inst &Instr : Node->getInsts()) {
186*03ce13f7SAndroid Build Coastguard Worker     if (Instr.isDeleted())
187*03ce13f7SAndroid Build Coastguard Worker       continue;
188*03ce13f7SAndroid Build Coastguard Worker     invalidateProducersOnStore(&Instr);
189*03ce13f7SAndroid Build Coastguard Worker     // Check whether Instr is a valid producer.
190*03ce13f7SAndroid Build Coastguard Worker     Variable *Var = Instr.getDest();
191*03ce13f7SAndroid Build Coastguard Worker     if (Var) { // only consider instructions with an actual dest var
192*03ce13f7SAndroid Build Coastguard Worker       if (isBooleanType(Var->getType())) {        // only bool-type dest vars
193*03ce13f7SAndroid Build Coastguard Worker         if (getProducerKind(&Instr) != PK_None) { // white-listed instructions
194*03ce13f7SAndroid Build Coastguard Worker           Producers[Var->getIndex()] = BoolFoldingEntry(&Instr);
195*03ce13f7SAndroid Build Coastguard Worker         }
196*03ce13f7SAndroid Build Coastguard Worker       }
197*03ce13f7SAndroid Build Coastguard Worker     }
198*03ce13f7SAndroid Build Coastguard Worker     // Check each src variable against the map.
199*03ce13f7SAndroid Build Coastguard Worker     FOREACH_VAR_IN_INST(Var, Instr) {
200*03ce13f7SAndroid Build Coastguard Worker       SizeT VarNum = Var->getIndex();
201*03ce13f7SAndroid Build Coastguard Worker       if (!containsValid(VarNum))
202*03ce13f7SAndroid Build Coastguard Worker         continue;
203*03ce13f7SAndroid Build Coastguard Worker       // All valid consumers use Var as the first source operand
204*03ce13f7SAndroid Build Coastguard Worker       if (IndexOfVarOperandInInst(Var) != 0) {
205*03ce13f7SAndroid Build Coastguard Worker         setInvalid(VarNum);
206*03ce13f7SAndroid Build Coastguard Worker         continue;
207*03ce13f7SAndroid Build Coastguard Worker       }
208*03ce13f7SAndroid Build Coastguard Worker       // Consumer instructions must be white-listed
209*03ce13f7SAndroid Build Coastguard Worker       BoolFolding::BoolFoldingConsumerKind ConsumerKind =
210*03ce13f7SAndroid Build Coastguard Worker           getConsumerKind(&Instr);
211*03ce13f7SAndroid Build Coastguard Worker       if (ConsumerKind == CK_None) {
212*03ce13f7SAndroid Build Coastguard Worker         setInvalid(VarNum);
213*03ce13f7SAndroid Build Coastguard Worker         continue;
214*03ce13f7SAndroid Build Coastguard Worker       }
215*03ce13f7SAndroid Build Coastguard Worker       BoolFolding::BoolFoldingProducerKind ProducerKind =
216*03ce13f7SAndroid Build Coastguard Worker           getProducerKind(Producers[VarNum].Instr);
217*03ce13f7SAndroid Build Coastguard Worker       if (!isValidFolding(ProducerKind, ConsumerKind)) {
218*03ce13f7SAndroid Build Coastguard Worker         setInvalid(VarNum);
219*03ce13f7SAndroid Build Coastguard Worker         continue;
220*03ce13f7SAndroid Build Coastguard Worker       }
221*03ce13f7SAndroid Build Coastguard Worker       // Avoid creating multiple copies of complex producer instructions.
222*03ce13f7SAndroid Build Coastguard Worker       if (Producers[VarNum].IsComplex && Producers[VarNum].NumUses > 0) {
223*03ce13f7SAndroid Build Coastguard Worker         setInvalid(VarNum);
224*03ce13f7SAndroid Build Coastguard Worker         continue;
225*03ce13f7SAndroid Build Coastguard Worker       }
226*03ce13f7SAndroid Build Coastguard Worker       ++Producers[VarNum].NumUses;
227*03ce13f7SAndroid Build Coastguard Worker       if (Instr.isLastUse(Var)) {
228*03ce13f7SAndroid Build Coastguard Worker         Producers[VarNum].IsLiveOut = false;
229*03ce13f7SAndroid Build Coastguard Worker       }
230*03ce13f7SAndroid Build Coastguard Worker     }
231*03ce13f7SAndroid Build Coastguard Worker   }
232*03ce13f7SAndroid Build Coastguard Worker   for (auto &I : Producers) {
233*03ce13f7SAndroid Build Coastguard Worker     // Ignore entries previously marked invalid.
234*03ce13f7SAndroid Build Coastguard Worker     if (I.second.Instr == nullptr)
235*03ce13f7SAndroid Build Coastguard Worker       continue;
236*03ce13f7SAndroid Build Coastguard Worker     // Disable the producer if its dest may be live beyond this block.
237*03ce13f7SAndroid Build Coastguard Worker     if (I.second.IsLiveOut) {
238*03ce13f7SAndroid Build Coastguard Worker       setInvalid(I.first);
239*03ce13f7SAndroid Build Coastguard Worker       continue;
240*03ce13f7SAndroid Build Coastguard Worker     }
241*03ce13f7SAndroid Build Coastguard Worker     // Mark as "dead" rather than outright deleting. This is so that other
242*03ce13f7SAndroid Build Coastguard Worker     // peephole style optimizations during or before lowering have access to
243*03ce13f7SAndroid Build Coastguard Worker     // this instruction in undeleted form. See for example
244*03ce13f7SAndroid Build Coastguard Worker     // tryOptimizedCmpxchgCmpBr().
245*03ce13f7SAndroid Build Coastguard Worker     I.second.Instr->setDead();
246*03ce13f7SAndroid Build Coastguard Worker   }
247*03ce13f7SAndroid Build Coastguard Worker }
248*03ce13f7SAndroid Build Coastguard Worker 
getProducerFor(const Operand * Opnd) const249*03ce13f7SAndroid Build Coastguard Worker const Inst *BoolFolding::getProducerFor(const Operand *Opnd) const {
250*03ce13f7SAndroid Build Coastguard Worker   auto *Var = llvm::dyn_cast<const Variable>(Opnd);
251*03ce13f7SAndroid Build Coastguard Worker   if (Var == nullptr)
252*03ce13f7SAndroid Build Coastguard Worker     return nullptr;
253*03ce13f7SAndroid Build Coastguard Worker   SizeT VarNum = Var->getIndex();
254*03ce13f7SAndroid Build Coastguard Worker   auto Element = Producers.find(VarNum);
255*03ce13f7SAndroid Build Coastguard Worker   if (Element == Producers.end())
256*03ce13f7SAndroid Build Coastguard Worker     return nullptr;
257*03ce13f7SAndroid Build Coastguard Worker   return Element->second.Instr;
258*03ce13f7SAndroid Build Coastguard Worker }
259*03ce13f7SAndroid Build Coastguard Worker 
dump(const Cfg * Func) const260*03ce13f7SAndroid Build Coastguard Worker void BoolFolding::dump(const Cfg *Func) const {
261*03ce13f7SAndroid Build Coastguard Worker   if (!BuildDefs::dump() || !Func->isVerbose(IceV_Folding))
262*03ce13f7SAndroid Build Coastguard Worker     return;
263*03ce13f7SAndroid Build Coastguard Worker   OstreamLocker L(Func->getContext());
264*03ce13f7SAndroid Build Coastguard Worker   Ostream &Str = Func->getContext()->getStrDump();
265*03ce13f7SAndroid Build Coastguard Worker   for (auto &I : Producers) {
266*03ce13f7SAndroid Build Coastguard Worker     if (I.second.Instr == nullptr)
267*03ce13f7SAndroid Build Coastguard Worker       continue;
268*03ce13f7SAndroid Build Coastguard Worker     Str << "Found foldable producer:\n  ";
269*03ce13f7SAndroid Build Coastguard Worker     I.second.Instr->dump(Func);
270*03ce13f7SAndroid Build Coastguard Worker     Str << "\n";
271*03ce13f7SAndroid Build Coastguard Worker   }
272*03ce13f7SAndroid Build Coastguard Worker }
273*03ce13f7SAndroid Build Coastguard Worker 
274*03ce13f7SAndroid Build Coastguard Worker /// If the given instruction has potential memory side effects (e.g. store, rmw,
275*03ce13f7SAndroid Build Coastguard Worker /// or a call instruction with potential memory side effects), then we must not
276*03ce13f7SAndroid Build Coastguard Worker /// allow a pre-store Producer instruction with memory operands to be folded
277*03ce13f7SAndroid Build Coastguard Worker /// into a post-store Consumer instruction.  If this is detected, the Producer
278*03ce13f7SAndroid Build Coastguard Worker /// is invalidated.
279*03ce13f7SAndroid Build Coastguard Worker ///
280*03ce13f7SAndroid Build Coastguard Worker /// We use the Producer's IsLiveOut field to determine whether any potential
281*03ce13f7SAndroid Build Coastguard Worker /// Consumers come after this store instruction.  The IsLiveOut field is
282*03ce13f7SAndroid Build Coastguard Worker /// initialized to true, and BoolFolding::init() sets IsLiveOut to false when it
283*03ce13f7SAndroid Build Coastguard Worker /// sees the variable's definitive last use (indicating the variable is not in
284*03ce13f7SAndroid Build Coastguard Worker /// the node's live-out set).  Thus if we see here that IsLiveOut is false, we
285*03ce13f7SAndroid Build Coastguard Worker /// know that there can be no consumers after the store, and therefore we know
286*03ce13f7SAndroid Build Coastguard Worker /// the folding is safe despite the store instruction.
287*03ce13f7SAndroid Build Coastguard Worker 
invalidateProducersOnStore(const Inst * Instr)288*03ce13f7SAndroid Build Coastguard Worker void BoolFolding::invalidateProducersOnStore(const Inst *Instr) {
289*03ce13f7SAndroid Build Coastguard Worker   if (!Instr->isMemoryWrite())
290*03ce13f7SAndroid Build Coastguard Worker     return;
291*03ce13f7SAndroid Build Coastguard Worker   for (auto &ProducerPair : Producers) {
292*03ce13f7SAndroid Build Coastguard Worker     if (!ProducerPair.second.IsLiveOut)
293*03ce13f7SAndroid Build Coastguard Worker       continue;
294*03ce13f7SAndroid Build Coastguard Worker     Inst *PInst = ProducerPair.second.Instr;
295*03ce13f7SAndroid Build Coastguard Worker     if (PInst == nullptr)
296*03ce13f7SAndroid Build Coastguard Worker       continue;
297*03ce13f7SAndroid Build Coastguard Worker     bool HasMemOperand = false;
298*03ce13f7SAndroid Build Coastguard Worker     const SizeT SrcSize = PInst->getSrcSize();
299*03ce13f7SAndroid Build Coastguard Worker     for (SizeT I = 0; I < SrcSize; ++I) {
300*03ce13f7SAndroid Build Coastguard Worker       if (llvm::isa<X86OperandMem>(PInst->getSrc(I))) {
301*03ce13f7SAndroid Build Coastguard Worker         HasMemOperand = true;
302*03ce13f7SAndroid Build Coastguard Worker         break;
303*03ce13f7SAndroid Build Coastguard Worker       }
304*03ce13f7SAndroid Build Coastguard Worker     }
305*03ce13f7SAndroid Build Coastguard Worker     if (!HasMemOperand)
306*03ce13f7SAndroid Build Coastguard Worker       continue;
307*03ce13f7SAndroid Build Coastguard Worker     setInvalid(ProducerPair.first);
308*03ce13f7SAndroid Build Coastguard Worker   }
309*03ce13f7SAndroid Build Coastguard Worker }
310*03ce13f7SAndroid Build Coastguard Worker 
initNodeForLowering(CfgNode * Node)311*03ce13f7SAndroid Build Coastguard Worker void TargetX8664::initNodeForLowering(CfgNode *Node) {
312*03ce13f7SAndroid Build Coastguard Worker   FoldingInfo.init(Node);
313*03ce13f7SAndroid Build Coastguard Worker   FoldingInfo.dump(Func);
314*03ce13f7SAndroid Build Coastguard Worker }
315*03ce13f7SAndroid Build Coastguard Worker 
TargetX8664(Cfg * Func)316*03ce13f7SAndroid Build Coastguard Worker TargetX8664::TargetX8664(Cfg *Func) : TargetX86(Func) {}
317*03ce13f7SAndroid Build Coastguard Worker 
staticInit(GlobalContext * Ctx)318*03ce13f7SAndroid Build Coastguard Worker void TargetX8664::staticInit(GlobalContext *Ctx) {
319*03ce13f7SAndroid Build Coastguard Worker   RegNumT::setLimit(RegX8664::Reg_NUM);
320*03ce13f7SAndroid Build Coastguard Worker   RegX8664::initRegisterSet(getFlags(), &TypeToRegisterSet, &RegisterAliases);
321*03ce13f7SAndroid Build Coastguard Worker   for (size_t i = 0; i < TypeToRegisterSet.size(); ++i)
322*03ce13f7SAndroid Build Coastguard Worker     TypeToRegisterSetUnfiltered[i] = TypeToRegisterSet[i];
323*03ce13f7SAndroid Build Coastguard Worker   filterTypeToRegisterSet(Ctx, RegX8664::Reg_NUM, TypeToRegisterSet.data(),
324*03ce13f7SAndroid Build Coastguard Worker                           TypeToRegisterSet.size(), RegX8664::getRegName,
325*03ce13f7SAndroid Build Coastguard Worker                           getRegClassName);
326*03ce13f7SAndroid Build Coastguard Worker }
327*03ce13f7SAndroid Build Coastguard Worker 
shouldBePooled(const Constant * C)328*03ce13f7SAndroid Build Coastguard Worker bool TargetX8664::shouldBePooled(const Constant *C) {
329*03ce13f7SAndroid Build Coastguard Worker   if (auto *ConstFloat = llvm::dyn_cast<ConstantFloat>(C)) {
330*03ce13f7SAndroid Build Coastguard Worker     return !Utils::isPositiveZero(ConstFloat->getValue());
331*03ce13f7SAndroid Build Coastguard Worker   }
332*03ce13f7SAndroid Build Coastguard Worker   if (auto *ConstDouble = llvm::dyn_cast<ConstantDouble>(C)) {
333*03ce13f7SAndroid Build Coastguard Worker     return !Utils::isPositiveZero(ConstDouble->getValue());
334*03ce13f7SAndroid Build Coastguard Worker   }
335*03ce13f7SAndroid Build Coastguard Worker   return false;
336*03ce13f7SAndroid Build Coastguard Worker }
337*03ce13f7SAndroid Build Coastguard Worker 
getPointerType()338*03ce13f7SAndroid Build Coastguard Worker ::Ice::Type TargetX8664::getPointerType() { return ::Ice::IceType_i64; }
339*03ce13f7SAndroid Build Coastguard Worker 
translateO2()340*03ce13f7SAndroid Build Coastguard Worker void TargetX8664::translateO2() {
341*03ce13f7SAndroid Build Coastguard Worker   TimerMarker T(TimerStack::TT_O2, Func);
342*03ce13f7SAndroid Build Coastguard Worker 
343*03ce13f7SAndroid Build Coastguard Worker   genTargetHelperCalls();
344*03ce13f7SAndroid Build Coastguard Worker   Func->dump("After target helper call insertion");
345*03ce13f7SAndroid Build Coastguard Worker 
346*03ce13f7SAndroid Build Coastguard Worker   // Merge Alloca instructions, and lay out the stack.
347*03ce13f7SAndroid Build Coastguard Worker   static constexpr bool SortAndCombineAllocas = true;
348*03ce13f7SAndroid Build Coastguard Worker   Func->processAllocas(SortAndCombineAllocas);
349*03ce13f7SAndroid Build Coastguard Worker   Func->dump("After Alloca processing");
350*03ce13f7SAndroid Build Coastguard Worker 
351*03ce13f7SAndroid Build Coastguard Worker   // Run this early so it can be used to focus optimizations on potentially hot
352*03ce13f7SAndroid Build Coastguard Worker   // code.
353*03ce13f7SAndroid Build Coastguard Worker   // TODO(stichnot,ascull): currently only used for regalloc not
354*03ce13f7SAndroid Build Coastguard Worker   // expensive high level optimizations which could be focused on potentially
355*03ce13f7SAndroid Build Coastguard Worker   // hot code.
356*03ce13f7SAndroid Build Coastguard Worker   Func->generateLoopInfo();
357*03ce13f7SAndroid Build Coastguard Worker   Func->dump("After loop analysis");
358*03ce13f7SAndroid Build Coastguard Worker   if (getFlags().getLoopInvariantCodeMotion()) {
359*03ce13f7SAndroid Build Coastguard Worker     Func->loopInvariantCodeMotion();
360*03ce13f7SAndroid Build Coastguard Worker     Func->dump("After LICM");
361*03ce13f7SAndroid Build Coastguard Worker   }
362*03ce13f7SAndroid Build Coastguard Worker 
363*03ce13f7SAndroid Build Coastguard Worker   if (getFlags().getLocalCSE() != Ice::LCSE_Disabled) {
364*03ce13f7SAndroid Build Coastguard Worker     Func->localCSE(getFlags().getLocalCSE() == Ice::LCSE_EnabledSSA);
365*03ce13f7SAndroid Build Coastguard Worker     Func->dump("After Local CSE");
366*03ce13f7SAndroid Build Coastguard Worker     Func->floatConstantCSE();
367*03ce13f7SAndroid Build Coastguard Worker   }
368*03ce13f7SAndroid Build Coastguard Worker   if (getFlags().getEnableShortCircuit()) {
369*03ce13f7SAndroid Build Coastguard Worker     Func->shortCircuitJumps();
370*03ce13f7SAndroid Build Coastguard Worker     Func->dump("After Short Circuiting");
371*03ce13f7SAndroid Build Coastguard Worker   }
372*03ce13f7SAndroid Build Coastguard Worker 
373*03ce13f7SAndroid Build Coastguard Worker   if (!getFlags().getEnablePhiEdgeSplit()) {
374*03ce13f7SAndroid Build Coastguard Worker     // Lower Phi instructions.
375*03ce13f7SAndroid Build Coastguard Worker     Func->placePhiLoads();
376*03ce13f7SAndroid Build Coastguard Worker     if (Func->hasError())
377*03ce13f7SAndroid Build Coastguard Worker       return;
378*03ce13f7SAndroid Build Coastguard Worker     Func->placePhiStores();
379*03ce13f7SAndroid Build Coastguard Worker     if (Func->hasError())
380*03ce13f7SAndroid Build Coastguard Worker       return;
381*03ce13f7SAndroid Build Coastguard Worker     Func->deletePhis();
382*03ce13f7SAndroid Build Coastguard Worker     if (Func->hasError())
383*03ce13f7SAndroid Build Coastguard Worker       return;
384*03ce13f7SAndroid Build Coastguard Worker     Func->dump("After Phi lowering");
385*03ce13f7SAndroid Build Coastguard Worker   }
386*03ce13f7SAndroid Build Coastguard Worker 
387*03ce13f7SAndroid Build Coastguard Worker   // Address mode optimization.
388*03ce13f7SAndroid Build Coastguard Worker   Func->getVMetadata()->init(VMK_SingleDefs);
389*03ce13f7SAndroid Build Coastguard Worker   Func->doAddressOpt();
390*03ce13f7SAndroid Build Coastguard Worker   Func->materializeVectorShuffles();
391*03ce13f7SAndroid Build Coastguard Worker 
392*03ce13f7SAndroid Build Coastguard Worker   // Find read-modify-write opportunities. Do this after address mode
393*03ce13f7SAndroid Build Coastguard Worker   // optimization so that doAddressOpt() doesn't need to be applied to RMW
394*03ce13f7SAndroid Build Coastguard Worker   // instructions as well.
395*03ce13f7SAndroid Build Coastguard Worker   findRMW();
396*03ce13f7SAndroid Build Coastguard Worker   Func->dump("After RMW transform");
397*03ce13f7SAndroid Build Coastguard Worker 
398*03ce13f7SAndroid Build Coastguard Worker   // Argument lowering
399*03ce13f7SAndroid Build Coastguard Worker   Func->doArgLowering();
400*03ce13f7SAndroid Build Coastguard Worker 
401*03ce13f7SAndroid Build Coastguard Worker   // Target lowering. This requires liveness analysis for some parts of the
402*03ce13f7SAndroid Build Coastguard Worker   // lowering decisions, such as compare/branch fusing. If non-lightweight
403*03ce13f7SAndroid Build Coastguard Worker   // liveness analysis is used, the instructions need to be renumbered first
404*03ce13f7SAndroid Build Coastguard Worker   // TODO: This renumbering should only be necessary if we're actually
405*03ce13f7SAndroid Build Coastguard Worker   // calculating live intervals, which we only do for register allocation.
406*03ce13f7SAndroid Build Coastguard Worker   Func->renumberInstructions();
407*03ce13f7SAndroid Build Coastguard Worker   if (Func->hasError())
408*03ce13f7SAndroid Build Coastguard Worker     return;
409*03ce13f7SAndroid Build Coastguard Worker 
410*03ce13f7SAndroid Build Coastguard Worker   // TODO: It should be sufficient to use the fastest liveness calculation,
411*03ce13f7SAndroid Build Coastguard Worker   // i.e. livenessLightweight(). However, for some reason that slows down the
412*03ce13f7SAndroid Build Coastguard Worker   // rest of the translation. Investigate.
413*03ce13f7SAndroid Build Coastguard Worker   Func->liveness(Liveness_Basic);
414*03ce13f7SAndroid Build Coastguard Worker   if (Func->hasError())
415*03ce13f7SAndroid Build Coastguard Worker     return;
416*03ce13f7SAndroid Build Coastguard Worker   Func->dump("After x86 address mode opt");
417*03ce13f7SAndroid Build Coastguard Worker 
418*03ce13f7SAndroid Build Coastguard Worker   doLoadOpt();
419*03ce13f7SAndroid Build Coastguard Worker 
420*03ce13f7SAndroid Build Coastguard Worker   Func->genCode();
421*03ce13f7SAndroid Build Coastguard Worker   if (Func->hasError())
422*03ce13f7SAndroid Build Coastguard Worker     return;
423*03ce13f7SAndroid Build Coastguard Worker   Func->dump("After x86 codegen");
424*03ce13f7SAndroid Build Coastguard Worker   splitBlockLocalVariables(Func);
425*03ce13f7SAndroid Build Coastguard Worker 
426*03ce13f7SAndroid Build Coastguard Worker   // Register allocation. This requires instruction renumbering and full
427*03ce13f7SAndroid Build Coastguard Worker   // liveness analysis. Loops must be identified before liveness so variable
428*03ce13f7SAndroid Build Coastguard Worker   // use weights are correct.
429*03ce13f7SAndroid Build Coastguard Worker   Func->renumberInstructions();
430*03ce13f7SAndroid Build Coastguard Worker   if (Func->hasError())
431*03ce13f7SAndroid Build Coastguard Worker     return;
432*03ce13f7SAndroid Build Coastguard Worker   Func->liveness(Liveness_Intervals);
433*03ce13f7SAndroid Build Coastguard Worker   if (Func->hasError())
434*03ce13f7SAndroid Build Coastguard Worker     return;
435*03ce13f7SAndroid Build Coastguard Worker   // The post-codegen dump is done here, after liveness analysis and associated
436*03ce13f7SAndroid Build Coastguard Worker   // cleanup, to make the dump cleaner and more useful.
437*03ce13f7SAndroid Build Coastguard Worker   Func->dump("After initial x86 codegen");
438*03ce13f7SAndroid Build Coastguard Worker   // Validate the live range computations. The expensive validation call is
439*03ce13f7SAndroid Build Coastguard Worker   // deliberately only made when assertions are enabled.
440*03ce13f7SAndroid Build Coastguard Worker   assert(Func->validateLiveness());
441*03ce13f7SAndroid Build Coastguard Worker   Func->getVMetadata()->init(VMK_All);
442*03ce13f7SAndroid Build Coastguard Worker   regAlloc(RAK_Global);
443*03ce13f7SAndroid Build Coastguard Worker   if (Func->hasError())
444*03ce13f7SAndroid Build Coastguard Worker     return;
445*03ce13f7SAndroid Build Coastguard Worker   Func->dump("After linear scan regalloc");
446*03ce13f7SAndroid Build Coastguard Worker 
447*03ce13f7SAndroid Build Coastguard Worker   if (getFlags().getEnablePhiEdgeSplit()) {
448*03ce13f7SAndroid Build Coastguard Worker     Func->advancedPhiLowering();
449*03ce13f7SAndroid Build Coastguard Worker     Func->dump("After advanced Phi lowering");
450*03ce13f7SAndroid Build Coastguard Worker   }
451*03ce13f7SAndroid Build Coastguard Worker 
452*03ce13f7SAndroid Build Coastguard Worker   // Stack frame mapping.
453*03ce13f7SAndroid Build Coastguard Worker   Func->genFrame();
454*03ce13f7SAndroid Build Coastguard Worker   if (Func->hasError())
455*03ce13f7SAndroid Build Coastguard Worker     return;
456*03ce13f7SAndroid Build Coastguard Worker   Func->dump("After stack frame mapping");
457*03ce13f7SAndroid Build Coastguard Worker 
458*03ce13f7SAndroid Build Coastguard Worker   Func->contractEmptyNodes();
459*03ce13f7SAndroid Build Coastguard Worker   Func->reorderNodes();
460*03ce13f7SAndroid Build Coastguard Worker 
461*03ce13f7SAndroid Build Coastguard Worker   // Branch optimization.  This needs to be done just before code emission. In
462*03ce13f7SAndroid Build Coastguard Worker   // particular, no transformations that insert or reorder CfgNodes should be
463*03ce13f7SAndroid Build Coastguard Worker   // done after branch optimization. We go ahead and do it before nop insertion
464*03ce13f7SAndroid Build Coastguard Worker   // to reduce the amount of work needed for searching for opportunities.
465*03ce13f7SAndroid Build Coastguard Worker   Func->doBranchOpt();
466*03ce13f7SAndroid Build Coastguard Worker   Func->dump("After branch optimization");
467*03ce13f7SAndroid Build Coastguard Worker }
468*03ce13f7SAndroid Build Coastguard Worker 
translateOm1()469*03ce13f7SAndroid Build Coastguard Worker void TargetX8664::translateOm1() {
470*03ce13f7SAndroid Build Coastguard Worker   TimerMarker T(TimerStack::TT_Om1, Func);
471*03ce13f7SAndroid Build Coastguard Worker 
472*03ce13f7SAndroid Build Coastguard Worker   genTargetHelperCalls();
473*03ce13f7SAndroid Build Coastguard Worker 
474*03ce13f7SAndroid Build Coastguard Worker   // Do not merge Alloca instructions, and lay out the stack.
475*03ce13f7SAndroid Build Coastguard Worker   // static constexpr bool SortAndCombineAllocas = false;
476*03ce13f7SAndroid Build Coastguard Worker   static constexpr bool SortAndCombineAllocas =
477*03ce13f7SAndroid Build Coastguard Worker       true; // TODO(b/171222930): Fix Win32 bug when this is false
478*03ce13f7SAndroid Build Coastguard Worker   Func->processAllocas(SortAndCombineAllocas);
479*03ce13f7SAndroid Build Coastguard Worker   Func->dump("After Alloca processing");
480*03ce13f7SAndroid Build Coastguard Worker 
481*03ce13f7SAndroid Build Coastguard Worker   Func->placePhiLoads();
482*03ce13f7SAndroid Build Coastguard Worker   if (Func->hasError())
483*03ce13f7SAndroid Build Coastguard Worker     return;
484*03ce13f7SAndroid Build Coastguard Worker   Func->placePhiStores();
485*03ce13f7SAndroid Build Coastguard Worker   if (Func->hasError())
486*03ce13f7SAndroid Build Coastguard Worker     return;
487*03ce13f7SAndroid Build Coastguard Worker   Func->deletePhis();
488*03ce13f7SAndroid Build Coastguard Worker   if (Func->hasError())
489*03ce13f7SAndroid Build Coastguard Worker     return;
490*03ce13f7SAndroid Build Coastguard Worker   Func->dump("After Phi lowering");
491*03ce13f7SAndroid Build Coastguard Worker 
492*03ce13f7SAndroid Build Coastguard Worker   Func->doArgLowering();
493*03ce13f7SAndroid Build Coastguard Worker   Func->genCode();
494*03ce13f7SAndroid Build Coastguard Worker   if (Func->hasError())
495*03ce13f7SAndroid Build Coastguard Worker     return;
496*03ce13f7SAndroid Build Coastguard Worker   Func->dump("After initial x86 codegen");
497*03ce13f7SAndroid Build Coastguard Worker 
498*03ce13f7SAndroid Build Coastguard Worker   regAlloc(RAK_InfOnly);
499*03ce13f7SAndroid Build Coastguard Worker   if (Func->hasError())
500*03ce13f7SAndroid Build Coastguard Worker     return;
501*03ce13f7SAndroid Build Coastguard Worker   Func->dump("After regalloc of infinite-weight variables");
502*03ce13f7SAndroid Build Coastguard Worker 
503*03ce13f7SAndroid Build Coastguard Worker   Func->genFrame();
504*03ce13f7SAndroid Build Coastguard Worker   if (Func->hasError())
505*03ce13f7SAndroid Build Coastguard Worker     return;
506*03ce13f7SAndroid Build Coastguard Worker   Func->dump("After stack frame mapping");
507*03ce13f7SAndroid Build Coastguard Worker }
508*03ce13f7SAndroid Build Coastguard Worker 
canRMW(const InstArithmetic * Arith)509*03ce13f7SAndroid Build Coastguard Worker inline bool canRMW(const InstArithmetic *Arith) {
510*03ce13f7SAndroid Build Coastguard Worker   Type Ty = Arith->getDest()->getType();
511*03ce13f7SAndroid Build Coastguard Worker   // X86 vector instructions write to a register and have no RMW option.
512*03ce13f7SAndroid Build Coastguard Worker   if (isVectorType(Ty))
513*03ce13f7SAndroid Build Coastguard Worker     return false;
514*03ce13f7SAndroid Build Coastguard Worker   bool isI64 = Ty == IceType_i64;
515*03ce13f7SAndroid Build Coastguard Worker 
516*03ce13f7SAndroid Build Coastguard Worker   switch (Arith->getOp()) {
517*03ce13f7SAndroid Build Coastguard Worker   // Not handled for lack of simple lowering:
518*03ce13f7SAndroid Build Coastguard Worker   //   shift on i64
519*03ce13f7SAndroid Build Coastguard Worker   //   mul, udiv, urem, sdiv, srem, frem
520*03ce13f7SAndroid Build Coastguard Worker   // Not handled for lack of RMW instructions:
521*03ce13f7SAndroid Build Coastguard Worker   //   fadd, fsub, fmul, fdiv (also vector types)
522*03ce13f7SAndroid Build Coastguard Worker   default:
523*03ce13f7SAndroid Build Coastguard Worker     return false;
524*03ce13f7SAndroid Build Coastguard Worker   case InstArithmetic::Add:
525*03ce13f7SAndroid Build Coastguard Worker   case InstArithmetic::Sub:
526*03ce13f7SAndroid Build Coastguard Worker   case InstArithmetic::And:
527*03ce13f7SAndroid Build Coastguard Worker   case InstArithmetic::Or:
528*03ce13f7SAndroid Build Coastguard Worker   case InstArithmetic::Xor:
529*03ce13f7SAndroid Build Coastguard Worker     return true;
530*03ce13f7SAndroid Build Coastguard Worker   case InstArithmetic::Shl:
531*03ce13f7SAndroid Build Coastguard Worker   case InstArithmetic::Lshr:
532*03ce13f7SAndroid Build Coastguard Worker   case InstArithmetic::Ashr:
533*03ce13f7SAndroid Build Coastguard Worker     return false; // TODO(stichnot): implement
534*03ce13f7SAndroid Build Coastguard Worker     return !isI64;
535*03ce13f7SAndroid Build Coastguard Worker   }
536*03ce13f7SAndroid Build Coastguard Worker }
537*03ce13f7SAndroid Build Coastguard Worker 
isSameMemAddressOperand(const Operand * A,const Operand * B)538*03ce13f7SAndroid Build Coastguard Worker bool isSameMemAddressOperand(const Operand *A, const Operand *B) {
539*03ce13f7SAndroid Build Coastguard Worker   if (A == B)
540*03ce13f7SAndroid Build Coastguard Worker     return true;
541*03ce13f7SAndroid Build Coastguard Worker   if (auto *MemA = llvm::dyn_cast<X86OperandMem>(A)) {
542*03ce13f7SAndroid Build Coastguard Worker     if (auto *MemB = llvm::dyn_cast<X86OperandMem>(B)) {
543*03ce13f7SAndroid Build Coastguard Worker       return MemA->getBase() == MemB->getBase() &&
544*03ce13f7SAndroid Build Coastguard Worker              MemA->getOffset() == MemB->getOffset() &&
545*03ce13f7SAndroid Build Coastguard Worker              MemA->getIndex() == MemB->getIndex() &&
546*03ce13f7SAndroid Build Coastguard Worker              MemA->getShift() == MemB->getShift() &&
547*03ce13f7SAndroid Build Coastguard Worker              MemA->getSegmentRegister() == MemB->getSegmentRegister();
548*03ce13f7SAndroid Build Coastguard Worker     }
549*03ce13f7SAndroid Build Coastguard Worker   }
550*03ce13f7SAndroid Build Coastguard Worker   return false;
551*03ce13f7SAndroid Build Coastguard Worker }
552*03ce13f7SAndroid Build Coastguard Worker 
findRMW()553*03ce13f7SAndroid Build Coastguard Worker void TargetX8664::findRMW() {
554*03ce13f7SAndroid Build Coastguard Worker   TimerMarker _(TimerStack::TT_findRMW, Func);
555*03ce13f7SAndroid Build Coastguard Worker   Func->dump("Before RMW");
556*03ce13f7SAndroid Build Coastguard Worker   if (Func->isVerbose(IceV_RMW))
557*03ce13f7SAndroid Build Coastguard Worker     Func->getContext()->lockStr();
558*03ce13f7SAndroid Build Coastguard Worker   for (CfgNode *Node : Func->getNodes()) {
559*03ce13f7SAndroid Build Coastguard Worker     // Walk through the instructions, considering each sequence of 3
560*03ce13f7SAndroid Build Coastguard Worker     // instructions, and look for the particular RMW pattern. Note that this
561*03ce13f7SAndroid Build Coastguard Worker     // search can be "broken" (false negatives) if there are intervening
562*03ce13f7SAndroid Build Coastguard Worker     // deleted instructions, or intervening instructions that could be safely
563*03ce13f7SAndroid Build Coastguard Worker     // moved out of the way to reveal an RMW pattern.
564*03ce13f7SAndroid Build Coastguard Worker     auto E = Node->getInsts().end();
565*03ce13f7SAndroid Build Coastguard Worker     auto I1 = E, I2 = E, I3 = Node->getInsts().begin();
566*03ce13f7SAndroid Build Coastguard Worker     for (; I3 != E; I1 = I2, I2 = I3, ++I3) {
567*03ce13f7SAndroid Build Coastguard Worker       // Make I3 skip over deleted instructions.
568*03ce13f7SAndroid Build Coastguard Worker       while (I3 != E && I3->isDeleted())
569*03ce13f7SAndroid Build Coastguard Worker         ++I3;
570*03ce13f7SAndroid Build Coastguard Worker       if (I1 == E || I2 == E || I3 == E)
571*03ce13f7SAndroid Build Coastguard Worker         continue;
572*03ce13f7SAndroid Build Coastguard Worker       assert(!I1->isDeleted());
573*03ce13f7SAndroid Build Coastguard Worker       assert(!I2->isDeleted());
574*03ce13f7SAndroid Build Coastguard Worker       assert(!I3->isDeleted());
575*03ce13f7SAndroid Build Coastguard Worker       auto *Load = llvm::dyn_cast<InstLoad>(I1);
576*03ce13f7SAndroid Build Coastguard Worker       auto *Arith = llvm::dyn_cast<InstArithmetic>(I2);
577*03ce13f7SAndroid Build Coastguard Worker       auto *Store = llvm::dyn_cast<InstStore>(I3);
578*03ce13f7SAndroid Build Coastguard Worker       if (!Load || !Arith || !Store)
579*03ce13f7SAndroid Build Coastguard Worker         continue;
580*03ce13f7SAndroid Build Coastguard Worker       // Look for:
581*03ce13f7SAndroid Build Coastguard Worker       //   a = Load addr
582*03ce13f7SAndroid Build Coastguard Worker       //   b = <op> a, other
583*03ce13f7SAndroid Build Coastguard Worker       //   Store b, addr
584*03ce13f7SAndroid Build Coastguard Worker       // Change to:
585*03ce13f7SAndroid Build Coastguard Worker       //   a = Load addr
586*03ce13f7SAndroid Build Coastguard Worker       //   b = <op> a, other
587*03ce13f7SAndroid Build Coastguard Worker       //   x = FakeDef
588*03ce13f7SAndroid Build Coastguard Worker       //   RMW <op>, addr, other, x
589*03ce13f7SAndroid Build Coastguard Worker       //   b = Store b, addr, x
590*03ce13f7SAndroid Build Coastguard Worker       // Note that inferTwoAddress() makes sure setDestRedefined() gets called
591*03ce13f7SAndroid Build Coastguard Worker       // on the updated Store instruction, to avoid liveness problems later.
592*03ce13f7SAndroid Build Coastguard Worker       //
593*03ce13f7SAndroid Build Coastguard Worker       // With this transformation, the Store instruction acquires a Dest
594*03ce13f7SAndroid Build Coastguard Worker       // variable and is now subject to dead code elimination if there are no
595*03ce13f7SAndroid Build Coastguard Worker       // more uses of "b".  Variable "x" is a beacon for determining whether the
596*03ce13f7SAndroid Build Coastguard Worker       // Store instruction gets dead-code eliminated.  If the Store instruction
597*03ce13f7SAndroid Build Coastguard Worker       // is eliminated, then it must be the case that the RMW instruction ends
598*03ce13f7SAndroid Build Coastguard Worker       // x's live range, and therefore the RMW instruction will be retained and
599*03ce13f7SAndroid Build Coastguard Worker       // later lowered.  On the other hand, if the RMW instruction does not end
600*03ce13f7SAndroid Build Coastguard Worker       // x's live range, then the Store instruction must still be present, and
601*03ce13f7SAndroid Build Coastguard Worker       // therefore the RMW instruction is ignored during lowering because it is
602*03ce13f7SAndroid Build Coastguard Worker       // redundant with the Store instruction.
603*03ce13f7SAndroid Build Coastguard Worker       //
604*03ce13f7SAndroid Build Coastguard Worker       // Note that if "a" has further uses, the RMW transformation may still
605*03ce13f7SAndroid Build Coastguard Worker       // trigger, resulting in two loads and one store, which is worse than the
606*03ce13f7SAndroid Build Coastguard Worker       // original one load and one store.  However, this is probably rare, and
607*03ce13f7SAndroid Build Coastguard Worker       // caching probably keeps it just as fast.
608*03ce13f7SAndroid Build Coastguard Worker       if (!isSameMemAddressOperand(Load->getLoadAddress(),
609*03ce13f7SAndroid Build Coastguard Worker                                    Store->getStoreAddress()))
610*03ce13f7SAndroid Build Coastguard Worker         continue;
611*03ce13f7SAndroid Build Coastguard Worker       Operand *ArithSrcFromLoad = Arith->getSrc(0);
612*03ce13f7SAndroid Build Coastguard Worker       Operand *ArithSrcOther = Arith->getSrc(1);
613*03ce13f7SAndroid Build Coastguard Worker       if (ArithSrcFromLoad != Load->getDest()) {
614*03ce13f7SAndroid Build Coastguard Worker         if (!Arith->isCommutative() || ArithSrcOther != Load->getDest())
615*03ce13f7SAndroid Build Coastguard Worker           continue;
616*03ce13f7SAndroid Build Coastguard Worker         std::swap(ArithSrcFromLoad, ArithSrcOther);
617*03ce13f7SAndroid Build Coastguard Worker       }
618*03ce13f7SAndroid Build Coastguard Worker       if (Arith->getDest() != Store->getData())
619*03ce13f7SAndroid Build Coastguard Worker         continue;
620*03ce13f7SAndroid Build Coastguard Worker       if (!canRMW(Arith))
621*03ce13f7SAndroid Build Coastguard Worker         continue;
622*03ce13f7SAndroid Build Coastguard Worker       if (Func->isVerbose(IceV_RMW)) {
623*03ce13f7SAndroid Build Coastguard Worker         Ostream &Str = Func->getContext()->getStrDump();
624*03ce13f7SAndroid Build Coastguard Worker         Str << "Found RMW in " << Func->getFunctionName() << ":\n  ";
625*03ce13f7SAndroid Build Coastguard Worker         Load->dump(Func);
626*03ce13f7SAndroid Build Coastguard Worker         Str << "\n  ";
627*03ce13f7SAndroid Build Coastguard Worker         Arith->dump(Func);
628*03ce13f7SAndroid Build Coastguard Worker         Str << "\n  ";
629*03ce13f7SAndroid Build Coastguard Worker         Store->dump(Func);
630*03ce13f7SAndroid Build Coastguard Worker         Str << "\n";
631*03ce13f7SAndroid Build Coastguard Worker       }
632*03ce13f7SAndroid Build Coastguard Worker       Variable *Beacon = Func->makeVariable(IceType_i32);
633*03ce13f7SAndroid Build Coastguard Worker       Beacon->setMustNotHaveReg();
634*03ce13f7SAndroid Build Coastguard Worker       Store->setRmwBeacon(Beacon);
635*03ce13f7SAndroid Build Coastguard Worker       auto *BeaconDef = InstFakeDef::create(Func, Beacon);
636*03ce13f7SAndroid Build Coastguard Worker       Node->getInsts().insert(I3, BeaconDef);
637*03ce13f7SAndroid Build Coastguard Worker       auto *RMW =
638*03ce13f7SAndroid Build Coastguard Worker           InstX86FakeRMW::create(Func, ArithSrcOther, Store->getStoreAddress(),
639*03ce13f7SAndroid Build Coastguard Worker                                  Beacon, Arith->getOp());
640*03ce13f7SAndroid Build Coastguard Worker       Node->getInsts().insert(I3, RMW);
641*03ce13f7SAndroid Build Coastguard Worker     }
642*03ce13f7SAndroid Build Coastguard Worker   }
643*03ce13f7SAndroid Build Coastguard Worker   if (Func->isVerbose(IceV_RMW))
644*03ce13f7SAndroid Build Coastguard Worker     Func->getContext()->unlockStr();
645*03ce13f7SAndroid Build Coastguard Worker }
646*03ce13f7SAndroid Build Coastguard Worker 
647*03ce13f7SAndroid Build Coastguard Worker /// Value is in bytes. Return Value adjusted to the next highest multiple of
648*03ce13f7SAndroid Build Coastguard Worker /// the stack alignment.
applyStackAlignment(uint32_t Value)649*03ce13f7SAndroid Build Coastguard Worker uint32_t TargetX8664::applyStackAlignment(uint32_t Value) {
650*03ce13f7SAndroid Build Coastguard Worker   return Utils::applyAlignment(Value, X86_STACK_ALIGNMENT_BYTES);
651*03ce13f7SAndroid Build Coastguard Worker }
652*03ce13f7SAndroid Build Coastguard Worker 
653*03ce13f7SAndroid Build Coastguard Worker // Converts a ConstantInteger32 operand into its constant value, or
654*03ce13f7SAndroid Build Coastguard Worker // MemoryOrderInvalid if the operand is not a ConstantInteger32.
getConstantMemoryOrder(Operand * Opnd)655*03ce13f7SAndroid Build Coastguard Worker inline uint64_t getConstantMemoryOrder(Operand *Opnd) {
656*03ce13f7SAndroid Build Coastguard Worker   if (auto *Integer = llvm::dyn_cast<ConstantInteger32>(Opnd))
657*03ce13f7SAndroid Build Coastguard Worker     return Integer->getValue();
658*03ce13f7SAndroid Build Coastguard Worker   return Intrinsics::MemoryOrderInvalid;
659*03ce13f7SAndroid Build Coastguard Worker }
660*03ce13f7SAndroid Build Coastguard Worker 
661*03ce13f7SAndroid Build Coastguard Worker /// Determines whether the dest of a Load instruction can be folded into one of
662*03ce13f7SAndroid Build Coastguard Worker /// the src operands of a 2-operand instruction. This is true as long as the
663*03ce13f7SAndroid Build Coastguard Worker /// load dest matches exactly one of the binary instruction's src operands.
664*03ce13f7SAndroid Build Coastguard Worker /// Replaces Src0 or Src1 with LoadSrc if the answer is true.
canFoldLoadIntoBinaryInst(Operand * LoadSrc,Variable * LoadDest,Operand * & Src0,Operand * & Src1)665*03ce13f7SAndroid Build Coastguard Worker inline bool canFoldLoadIntoBinaryInst(Operand *LoadSrc, Variable *LoadDest,
666*03ce13f7SAndroid Build Coastguard Worker                                       Operand *&Src0, Operand *&Src1) {
667*03ce13f7SAndroid Build Coastguard Worker   if (Src0 == LoadDest && Src1 != LoadDest) {
668*03ce13f7SAndroid Build Coastguard Worker     Src0 = LoadSrc;
669*03ce13f7SAndroid Build Coastguard Worker     return true;
670*03ce13f7SAndroid Build Coastguard Worker   }
671*03ce13f7SAndroid Build Coastguard Worker   if (Src0 != LoadDest && Src1 == LoadDest) {
672*03ce13f7SAndroid Build Coastguard Worker     Src1 = LoadSrc;
673*03ce13f7SAndroid Build Coastguard Worker     return true;
674*03ce13f7SAndroid Build Coastguard Worker   }
675*03ce13f7SAndroid Build Coastguard Worker   return false;
676*03ce13f7SAndroid Build Coastguard Worker }
677*03ce13f7SAndroid Build Coastguard Worker 
doLoadOpt()678*03ce13f7SAndroid Build Coastguard Worker void TargetX8664::doLoadOpt() {
679*03ce13f7SAndroid Build Coastguard Worker   TimerMarker _(TimerStack::TT_loadOpt, Func);
680*03ce13f7SAndroid Build Coastguard Worker   for (CfgNode *Node : Func->getNodes()) {
681*03ce13f7SAndroid Build Coastguard Worker     Context.init(Node);
682*03ce13f7SAndroid Build Coastguard Worker     while (!Context.atEnd()) {
683*03ce13f7SAndroid Build Coastguard Worker       Variable *LoadDest = nullptr;
684*03ce13f7SAndroid Build Coastguard Worker       Operand *LoadSrc = nullptr;
685*03ce13f7SAndroid Build Coastguard Worker       Inst *CurInst = iteratorToInst(Context.getCur());
686*03ce13f7SAndroid Build Coastguard Worker       Inst *Next = Context.getNextInst();
687*03ce13f7SAndroid Build Coastguard Worker       // Determine whether the current instruction is a Load instruction or
688*03ce13f7SAndroid Build Coastguard Worker       // equivalent.
689*03ce13f7SAndroid Build Coastguard Worker       if (auto *Load = llvm::dyn_cast<InstLoad>(CurInst)) {
690*03ce13f7SAndroid Build Coastguard Worker         // An InstLoad qualifies unless it uses a 64-bit absolute address,
691*03ce13f7SAndroid Build Coastguard Worker         // which requires legalization to insert a copy to register.
692*03ce13f7SAndroid Build Coastguard Worker         // TODO(b/148272103): Fold these after legalization.
693*03ce13f7SAndroid Build Coastguard Worker         if (!llvm::isa<Constant>(Load->getLoadAddress())) {
694*03ce13f7SAndroid Build Coastguard Worker           LoadDest = Load->getDest();
695*03ce13f7SAndroid Build Coastguard Worker           constexpr bool DoLegalize = false;
696*03ce13f7SAndroid Build Coastguard Worker           LoadSrc = formMemoryOperand(Load->getLoadAddress(),
697*03ce13f7SAndroid Build Coastguard Worker                                       LoadDest->getType(), DoLegalize);
698*03ce13f7SAndroid Build Coastguard Worker         }
699*03ce13f7SAndroid Build Coastguard Worker       } else if (auto *Intrin = llvm::dyn_cast<InstIntrinsic>(CurInst)) {
700*03ce13f7SAndroid Build Coastguard Worker         // An AtomicLoad intrinsic qualifies as long as it has a valid memory
701*03ce13f7SAndroid Build Coastguard Worker         // ordering, and can be implemented in a single instruction (i.e., not
702*03ce13f7SAndroid Build Coastguard Worker         // i64 on x86-32).
703*03ce13f7SAndroid Build Coastguard Worker         Intrinsics::IntrinsicID ID = Intrin->getIntrinsicID();
704*03ce13f7SAndroid Build Coastguard Worker         if (ID == Intrinsics::AtomicLoad &&
705*03ce13f7SAndroid Build Coastguard Worker             Intrinsics::isMemoryOrderValid(
706*03ce13f7SAndroid Build Coastguard Worker                 ID, getConstantMemoryOrder(Intrin->getArg(1)))) {
707*03ce13f7SAndroid Build Coastguard Worker           LoadDest = Intrin->getDest();
708*03ce13f7SAndroid Build Coastguard Worker           constexpr bool DoLegalize = false;
709*03ce13f7SAndroid Build Coastguard Worker           LoadSrc = formMemoryOperand(Intrin->getArg(0), LoadDest->getType(),
710*03ce13f7SAndroid Build Coastguard Worker                                       DoLegalize);
711*03ce13f7SAndroid Build Coastguard Worker         }
712*03ce13f7SAndroid Build Coastguard Worker       }
713*03ce13f7SAndroid Build Coastguard Worker       // A Load instruction can be folded into the following instruction only
714*03ce13f7SAndroid Build Coastguard Worker       // if the following instruction ends the Load's Dest variable's live
715*03ce13f7SAndroid Build Coastguard Worker       // range.
716*03ce13f7SAndroid Build Coastguard Worker       if (LoadDest && Next && Next->isLastUse(LoadDest)) {
717*03ce13f7SAndroid Build Coastguard Worker         assert(LoadSrc);
718*03ce13f7SAndroid Build Coastguard Worker         Inst *NewInst = nullptr;
719*03ce13f7SAndroid Build Coastguard Worker         if (auto *Arith = llvm::dyn_cast<InstArithmetic>(Next)) {
720*03ce13f7SAndroid Build Coastguard Worker           Operand *Src0 = Arith->getSrc(0);
721*03ce13f7SAndroid Build Coastguard Worker           Operand *Src1 = Arith->getSrc(1);
722*03ce13f7SAndroid Build Coastguard Worker           if (canFoldLoadIntoBinaryInst(LoadSrc, LoadDest, Src0, Src1)) {
723*03ce13f7SAndroid Build Coastguard Worker             NewInst = InstArithmetic::create(Func, Arith->getOp(),
724*03ce13f7SAndroid Build Coastguard Worker                                              Arith->getDest(), Src0, Src1);
725*03ce13f7SAndroid Build Coastguard Worker           }
726*03ce13f7SAndroid Build Coastguard Worker         } else if (auto *Icmp = llvm::dyn_cast<InstIcmp>(Next)) {
727*03ce13f7SAndroid Build Coastguard Worker           Operand *Src0 = Icmp->getSrc(0);
728*03ce13f7SAndroid Build Coastguard Worker           Operand *Src1 = Icmp->getSrc(1);
729*03ce13f7SAndroid Build Coastguard Worker           if (canFoldLoadIntoBinaryInst(LoadSrc, LoadDest, Src0, Src1)) {
730*03ce13f7SAndroid Build Coastguard Worker             NewInst = InstIcmp::create(Func, Icmp->getCondition(),
731*03ce13f7SAndroid Build Coastguard Worker                                        Icmp->getDest(), Src0, Src1);
732*03ce13f7SAndroid Build Coastguard Worker           }
733*03ce13f7SAndroid Build Coastguard Worker         } else if (auto *Fcmp = llvm::dyn_cast<InstFcmp>(Next)) {
734*03ce13f7SAndroid Build Coastguard Worker           Operand *Src0 = Fcmp->getSrc(0);
735*03ce13f7SAndroid Build Coastguard Worker           Operand *Src1 = Fcmp->getSrc(1);
736*03ce13f7SAndroid Build Coastguard Worker           if (canFoldLoadIntoBinaryInst(LoadSrc, LoadDest, Src0, Src1)) {
737*03ce13f7SAndroid Build Coastguard Worker             NewInst = InstFcmp::create(Func, Fcmp->getCondition(),
738*03ce13f7SAndroid Build Coastguard Worker                                        Fcmp->getDest(), Src0, Src1);
739*03ce13f7SAndroid Build Coastguard Worker           }
740*03ce13f7SAndroid Build Coastguard Worker         } else if (auto *Select = llvm::dyn_cast<InstSelect>(Next)) {
741*03ce13f7SAndroid Build Coastguard Worker           Operand *Src0 = Select->getTrueOperand();
742*03ce13f7SAndroid Build Coastguard Worker           Operand *Src1 = Select->getFalseOperand();
743*03ce13f7SAndroid Build Coastguard Worker           if (canFoldLoadIntoBinaryInst(LoadSrc, LoadDest, Src0, Src1)) {
744*03ce13f7SAndroid Build Coastguard Worker             NewInst = InstSelect::create(Func, Select->getDest(),
745*03ce13f7SAndroid Build Coastguard Worker                                          Select->getCondition(), Src0, Src1);
746*03ce13f7SAndroid Build Coastguard Worker           }
747*03ce13f7SAndroid Build Coastguard Worker         } else if (auto *Cast = llvm::dyn_cast<InstCast>(Next)) {
748*03ce13f7SAndroid Build Coastguard Worker           // The load dest can always be folded into a Cast instruction.
749*03ce13f7SAndroid Build Coastguard Worker           auto *Src0 = llvm::dyn_cast<Variable>(Cast->getSrc(0));
750*03ce13f7SAndroid Build Coastguard Worker           if (Src0 == LoadDest) {
751*03ce13f7SAndroid Build Coastguard Worker             NewInst = InstCast::create(Func, Cast->getCastKind(),
752*03ce13f7SAndroid Build Coastguard Worker                                        Cast->getDest(), LoadSrc);
753*03ce13f7SAndroid Build Coastguard Worker           }
754*03ce13f7SAndroid Build Coastguard Worker         }
755*03ce13f7SAndroid Build Coastguard Worker         if (NewInst) {
756*03ce13f7SAndroid Build Coastguard Worker           CurInst->setDeleted();
757*03ce13f7SAndroid Build Coastguard Worker           Next->setDeleted();
758*03ce13f7SAndroid Build Coastguard Worker           Context.insert(NewInst);
759*03ce13f7SAndroid Build Coastguard Worker           // Update NewInst->LiveRangesEnded so that target lowering may
760*03ce13f7SAndroid Build Coastguard Worker           // benefit. Also update NewInst->HasSideEffects.
761*03ce13f7SAndroid Build Coastguard Worker           NewInst->spliceLivenessInfo(Next, CurInst);
762*03ce13f7SAndroid Build Coastguard Worker         }
763*03ce13f7SAndroid Build Coastguard Worker       }
764*03ce13f7SAndroid Build Coastguard Worker       Context.advanceCur();
765*03ce13f7SAndroid Build Coastguard Worker       Context.advanceNext();
766*03ce13f7SAndroid Build Coastguard Worker     }
767*03ce13f7SAndroid Build Coastguard Worker   }
768*03ce13f7SAndroid Build Coastguard Worker   Func->dump("After load optimization");
769*03ce13f7SAndroid Build Coastguard Worker }
770*03ce13f7SAndroid Build Coastguard Worker 
doBranchOpt(Inst * I,const CfgNode * NextNode)771*03ce13f7SAndroid Build Coastguard Worker bool TargetX8664::doBranchOpt(Inst *I, const CfgNode *NextNode) {
772*03ce13f7SAndroid Build Coastguard Worker   if (auto *Br = llvm::dyn_cast<InstX86Br>(I)) {
773*03ce13f7SAndroid Build Coastguard Worker     return Br->optimizeBranch(NextNode);
774*03ce13f7SAndroid Build Coastguard Worker   }
775*03ce13f7SAndroid Build Coastguard Worker   return false;
776*03ce13f7SAndroid Build Coastguard Worker }
777*03ce13f7SAndroid Build Coastguard Worker 
getPhysicalRegister(RegNumT RegNum,Type Ty)778*03ce13f7SAndroid Build Coastguard Worker Variable *TargetX8664::getPhysicalRegister(RegNumT RegNum, Type Ty) {
779*03ce13f7SAndroid Build Coastguard Worker   if (Ty == IceType_void)
780*03ce13f7SAndroid Build Coastguard Worker     Ty = IceType_i32;
781*03ce13f7SAndroid Build Coastguard Worker   if (PhysicalRegisters[Ty].empty())
782*03ce13f7SAndroid Build Coastguard Worker     PhysicalRegisters[Ty].resize(RegX8664::Reg_NUM);
783*03ce13f7SAndroid Build Coastguard Worker   assert(unsigned(RegNum) < PhysicalRegisters[Ty].size());
784*03ce13f7SAndroid Build Coastguard Worker   Variable *Reg = PhysicalRegisters[Ty][RegNum];
785*03ce13f7SAndroid Build Coastguard Worker   if (Reg == nullptr) {
786*03ce13f7SAndroid Build Coastguard Worker     Reg = Func->makeVariable(Ty);
787*03ce13f7SAndroid Build Coastguard Worker     Reg->setRegNum(RegNum);
788*03ce13f7SAndroid Build Coastguard Worker     PhysicalRegisters[Ty][RegNum] = Reg;
789*03ce13f7SAndroid Build Coastguard Worker     // Specially mark a named physical register as an "argument" so that it is
790*03ce13f7SAndroid Build Coastguard Worker     // considered live upon function entry.  Otherwise it's possible to get
791*03ce13f7SAndroid Build Coastguard Worker     // liveness validation errors for saving callee-save registers.
792*03ce13f7SAndroid Build Coastguard Worker     Func->addImplicitArg(Reg);
793*03ce13f7SAndroid Build Coastguard Worker     // Don't bother tracking the live range of a named physical register.
794*03ce13f7SAndroid Build Coastguard Worker     Reg->setIgnoreLiveness();
795*03ce13f7SAndroid Build Coastguard Worker   }
796*03ce13f7SAndroid Build Coastguard Worker   assert(RegX8664::getGprForType(Ty, RegNum) == RegNum);
797*03ce13f7SAndroid Build Coastguard Worker   return Reg;
798*03ce13f7SAndroid Build Coastguard Worker }
799*03ce13f7SAndroid Build Coastguard Worker 
getRegName(RegNumT RegNum,Type Ty) const800*03ce13f7SAndroid Build Coastguard Worker const char *TargetX8664::getRegName(RegNumT RegNum, Type Ty) const {
801*03ce13f7SAndroid Build Coastguard Worker   return RegX8664::getRegName(RegX8664::getGprForType(Ty, RegNum));
802*03ce13f7SAndroid Build Coastguard Worker }
803*03ce13f7SAndroid Build Coastguard Worker 
emitVariable(const Variable * Var) const804*03ce13f7SAndroid Build Coastguard Worker void TargetX8664::emitVariable(const Variable *Var) const {
805*03ce13f7SAndroid Build Coastguard Worker   if (!BuildDefs::dump())
806*03ce13f7SAndroid Build Coastguard Worker     return;
807*03ce13f7SAndroid Build Coastguard Worker   Ostream &Str = Ctx->getStrEmit();
808*03ce13f7SAndroid Build Coastguard Worker   if (Var->hasReg()) {
809*03ce13f7SAndroid Build Coastguard Worker     Str << "%" << getRegName(Var->getRegNum(), Var->getType());
810*03ce13f7SAndroid Build Coastguard Worker     return;
811*03ce13f7SAndroid Build Coastguard Worker   }
812*03ce13f7SAndroid Build Coastguard Worker   if (Var->mustHaveReg()) {
813*03ce13f7SAndroid Build Coastguard Worker     llvm::report_fatal_error("Infinite-weight Variable (" + Var->getName() +
814*03ce13f7SAndroid Build Coastguard Worker                              ") has no register assigned - function " +
815*03ce13f7SAndroid Build Coastguard Worker                              Func->getFunctionName());
816*03ce13f7SAndroid Build Coastguard Worker   }
817*03ce13f7SAndroid Build Coastguard Worker   const int32_t Offset = Var->getStackOffset();
818*03ce13f7SAndroid Build Coastguard Worker   auto BaseRegNum = Var->getBaseRegNum();
819*03ce13f7SAndroid Build Coastguard Worker   if (BaseRegNum.hasNoValue())
820*03ce13f7SAndroid Build Coastguard Worker     BaseRegNum = getFrameOrStackReg();
821*03ce13f7SAndroid Build Coastguard Worker 
822*03ce13f7SAndroid Build Coastguard Worker   // Print in the form "Offset(%reg)", omitting Offset when it is 0.
823*03ce13f7SAndroid Build Coastguard Worker   if (getFlags().getDecorateAsm()) {
824*03ce13f7SAndroid Build Coastguard Worker     Str << Var->getSymbolicStackOffset();
825*03ce13f7SAndroid Build Coastguard Worker   } else if (Offset != 0) {
826*03ce13f7SAndroid Build Coastguard Worker     Str << Offset;
827*03ce13f7SAndroid Build Coastguard Worker   }
828*03ce13f7SAndroid Build Coastguard Worker   const Type FrameSPTy = WordType;
829*03ce13f7SAndroid Build Coastguard Worker   Str << "(%" << getRegName(BaseRegNum, FrameSPTy) << ")";
830*03ce13f7SAndroid Build Coastguard Worker }
831*03ce13f7SAndroid Build Coastguard Worker 
addProlog(CfgNode * Node)832*03ce13f7SAndroid Build Coastguard Worker void TargetX8664::addProlog(CfgNode *Node) {
833*03ce13f7SAndroid Build Coastguard Worker   // Stack frame layout:
834*03ce13f7SAndroid Build Coastguard Worker   //
835*03ce13f7SAndroid Build Coastguard Worker   // +------------------------+  ^ +
836*03ce13f7SAndroid Build Coastguard Worker   // | 1. return address      |  |
837*03ce13f7SAndroid Build Coastguard Worker   // +------------------------+  v -
838*03ce13f7SAndroid Build Coastguard Worker   // | 2. preserved registers |
839*03ce13f7SAndroid Build Coastguard Worker   // +------------------------+ <--- BasePointer (if used)
840*03ce13f7SAndroid Build Coastguard Worker   // | 3. padding             |
841*03ce13f7SAndroid Build Coastguard Worker   // +------------------------+
842*03ce13f7SAndroid Build Coastguard Worker   // | 4. global spill area   |
843*03ce13f7SAndroid Build Coastguard Worker   // +------------------------+
844*03ce13f7SAndroid Build Coastguard Worker   // | 5. padding             |
845*03ce13f7SAndroid Build Coastguard Worker   // +------------------------+
846*03ce13f7SAndroid Build Coastguard Worker   // | 6. local spill area    |
847*03ce13f7SAndroid Build Coastguard Worker   // +------------------------+
848*03ce13f7SAndroid Build Coastguard Worker   // | 7. padding             |
849*03ce13f7SAndroid Build Coastguard Worker   // +------------------------+
850*03ce13f7SAndroid Build Coastguard Worker   // | 7.5 shadow (WinX64)    |
851*03ce13f7SAndroid Build Coastguard Worker   // +------------------------+
852*03ce13f7SAndroid Build Coastguard Worker   // | 8. allocas             |
853*03ce13f7SAndroid Build Coastguard Worker   // +------------------------+
854*03ce13f7SAndroid Build Coastguard Worker   // | 9. padding             |
855*03ce13f7SAndroid Build Coastguard Worker   // +------------------------+
856*03ce13f7SAndroid Build Coastguard Worker   // | 10. out args           |
857*03ce13f7SAndroid Build Coastguard Worker   // +------------------------+ <--- StackPointer
858*03ce13f7SAndroid Build Coastguard Worker   //
859*03ce13f7SAndroid Build Coastguard Worker   // The following variables record the size in bytes of the given areas:
860*03ce13f7SAndroid Build Coastguard Worker   //  * X86_RET_IP_SIZE_BYTES:   area 1
861*03ce13f7SAndroid Build Coastguard Worker   //  * PreservedRegsSizeBytes:  area 2
862*03ce13f7SAndroid Build Coastguard Worker   //  * SpillAreaPaddingBytes:   area 3
863*03ce13f7SAndroid Build Coastguard Worker   //  * GlobalsSize:             area 4
864*03ce13f7SAndroid Build Coastguard Worker   //  * LocalsSlotsPaddingBytes: area 5
865*03ce13f7SAndroid Build Coastguard Worker   //  * GlobalsAndSubsequentPaddingSize: areas 4 - 5
866*03ce13f7SAndroid Build Coastguard Worker   //  * LocalsSpillAreaSize:     area 6
867*03ce13f7SAndroid Build Coastguard Worker   //  * FixedAllocaSizeBytes:    areas 7 - 8
868*03ce13f7SAndroid Build Coastguard Worker   //  * SpillAreaSizeBytes:      areas 3 - 10
869*03ce13f7SAndroid Build Coastguard Worker   //  * maxOutArgsSizeBytes():   areas 9 - 10
870*03ce13f7SAndroid Build Coastguard Worker 
871*03ce13f7SAndroid Build Coastguard Worker   // Determine stack frame offsets for each Variable without a register
872*03ce13f7SAndroid Build Coastguard Worker   // assignment. This can be done as one variable per stack slot. Or, do
873*03ce13f7SAndroid Build Coastguard Worker   // coalescing by running the register allocator again with an infinite set of
874*03ce13f7SAndroid Build Coastguard Worker   // registers (as a side effect, this gives variables a second chance at
875*03ce13f7SAndroid Build Coastguard Worker   // physical register assignment).
876*03ce13f7SAndroid Build Coastguard Worker   //
877*03ce13f7SAndroid Build Coastguard Worker   // A middle ground approach is to leverage sparsity and allocate one block of
878*03ce13f7SAndroid Build Coastguard Worker   // space on the frame for globals (variables with multi-block lifetime), and
879*03ce13f7SAndroid Build Coastguard Worker   // one block to share for locals (single-block lifetime).
880*03ce13f7SAndroid Build Coastguard Worker 
881*03ce13f7SAndroid Build Coastguard Worker   const SizeT ShadowStoreSize = getShadowStoreSize();
882*03ce13f7SAndroid Build Coastguard Worker 
883*03ce13f7SAndroid Build Coastguard Worker   // StackPointer: points just past return address of calling function
884*03ce13f7SAndroid Build Coastguard Worker 
885*03ce13f7SAndroid Build Coastguard Worker   Context.init(Node);
886*03ce13f7SAndroid Build Coastguard Worker   Context.setInsertPoint(Context.getCur());
887*03ce13f7SAndroid Build Coastguard Worker 
888*03ce13f7SAndroid Build Coastguard Worker   SmallBitVector CalleeSaves = getRegisterSet(RegSet_CalleeSave, RegSet_None);
889*03ce13f7SAndroid Build Coastguard Worker   RegsUsed = SmallBitVector(CalleeSaves.size());
890*03ce13f7SAndroid Build Coastguard Worker   VarList SortedSpilledVariables, VariablesLinkedToSpillSlots;
891*03ce13f7SAndroid Build Coastguard Worker   size_t GlobalsSize = 0;
892*03ce13f7SAndroid Build Coastguard Worker   // If there is a separate locals area, this represents that area. Otherwise
893*03ce13f7SAndroid Build Coastguard Worker   // it counts any variable not counted by GlobalsSize.
894*03ce13f7SAndroid Build Coastguard Worker   SpillAreaSizeBytes = 0;
895*03ce13f7SAndroid Build Coastguard Worker   // If there is a separate locals area, this specifies the alignment for it.
896*03ce13f7SAndroid Build Coastguard Worker   uint32_t LocalsSlotsAlignmentBytes = 0;
897*03ce13f7SAndroid Build Coastguard Worker   // The entire spill locations area gets aligned to largest natural alignment
898*03ce13f7SAndroid Build Coastguard Worker   // of the variables that have a spill slot.
899*03ce13f7SAndroid Build Coastguard Worker   uint32_t SpillAreaAlignmentBytes = 0;
900*03ce13f7SAndroid Build Coastguard Worker   // A spill slot linked to a variable with a stack slot should reuse that
901*03ce13f7SAndroid Build Coastguard Worker   // stack slot.
902*03ce13f7SAndroid Build Coastguard Worker   std::function<bool(Variable *)> TargetVarHook =
903*03ce13f7SAndroid Build Coastguard Worker       [&VariablesLinkedToSpillSlots](Variable *Var) {
904*03ce13f7SAndroid Build Coastguard Worker         // TODO(stichnot): Refactor this into the base class.
905*03ce13f7SAndroid Build Coastguard Worker         Variable *Root = Var->getLinkedToStackRoot();
906*03ce13f7SAndroid Build Coastguard Worker         if (Root != nullptr) {
907*03ce13f7SAndroid Build Coastguard Worker           assert(!Root->hasReg());
908*03ce13f7SAndroid Build Coastguard Worker           if (!Root->hasReg()) {
909*03ce13f7SAndroid Build Coastguard Worker             VariablesLinkedToSpillSlots.push_back(Var);
910*03ce13f7SAndroid Build Coastguard Worker             return true;
911*03ce13f7SAndroid Build Coastguard Worker           }
912*03ce13f7SAndroid Build Coastguard Worker         }
913*03ce13f7SAndroid Build Coastguard Worker         return false;
914*03ce13f7SAndroid Build Coastguard Worker       };
915*03ce13f7SAndroid Build Coastguard Worker 
916*03ce13f7SAndroid Build Coastguard Worker   // Compute the list of spilled variables and bounds for GlobalsSize, etc.
917*03ce13f7SAndroid Build Coastguard Worker   getVarStackSlotParams(SortedSpilledVariables, RegsUsed, &GlobalsSize,
918*03ce13f7SAndroid Build Coastguard Worker                         &SpillAreaSizeBytes, &SpillAreaAlignmentBytes,
919*03ce13f7SAndroid Build Coastguard Worker                         &LocalsSlotsAlignmentBytes, TargetVarHook);
920*03ce13f7SAndroid Build Coastguard Worker   uint32_t LocalsSpillAreaSize = SpillAreaSizeBytes;
921*03ce13f7SAndroid Build Coastguard Worker   SpillAreaSizeBytes += GlobalsSize;
922*03ce13f7SAndroid Build Coastguard Worker 
923*03ce13f7SAndroid Build Coastguard Worker   // Add push instructions for preserved registers.
924*03ce13f7SAndroid Build Coastguard Worker   uint32_t NumCallee = 0;
925*03ce13f7SAndroid Build Coastguard Worker   size_t PreservedRegsSizeBytes = 0;
926*03ce13f7SAndroid Build Coastguard Worker   SmallBitVector Pushed(CalleeSaves.size());
927*03ce13f7SAndroid Build Coastguard Worker   for (RegNumT i : RegNumBVIter(CalleeSaves)) {
928*03ce13f7SAndroid Build Coastguard Worker     const auto Canonical = RegX8664::getBaseReg(i);
929*03ce13f7SAndroid Build Coastguard Worker     assert(Canonical == RegX8664::getBaseReg(Canonical));
930*03ce13f7SAndroid Build Coastguard Worker     if (RegsUsed[i]) {
931*03ce13f7SAndroid Build Coastguard Worker       Pushed[Canonical] = true;
932*03ce13f7SAndroid Build Coastguard Worker     }
933*03ce13f7SAndroid Build Coastguard Worker   }
934*03ce13f7SAndroid Build Coastguard Worker   for (RegNumT RegNum : RegNumBVIter(Pushed)) {
935*03ce13f7SAndroid Build Coastguard Worker     assert(RegNum == RegX8664::getBaseReg(RegNum));
936*03ce13f7SAndroid Build Coastguard Worker     ++NumCallee;
937*03ce13f7SAndroid Build Coastguard Worker     if (RegX8664::isXmm(RegNum)) {
938*03ce13f7SAndroid Build Coastguard Worker       PreservedRegsSizeBytes += 16;
939*03ce13f7SAndroid Build Coastguard Worker     } else {
940*03ce13f7SAndroid Build Coastguard Worker       PreservedRegsSizeBytes += typeWidthInBytes(WordType);
941*03ce13f7SAndroid Build Coastguard Worker     }
942*03ce13f7SAndroid Build Coastguard Worker     _push_reg(RegNum);
943*03ce13f7SAndroid Build Coastguard Worker   }
944*03ce13f7SAndroid Build Coastguard Worker   Ctx->statsUpdateRegistersSaved(NumCallee);
945*03ce13f7SAndroid Build Coastguard Worker 
946*03ce13f7SAndroid Build Coastguard Worker   // StackPointer: points past preserved registers at start of spill area
947*03ce13f7SAndroid Build Coastguard Worker 
948*03ce13f7SAndroid Build Coastguard Worker   // Generate "push frameptr; mov frameptr, stackptr"
949*03ce13f7SAndroid Build Coastguard Worker   if (IsEbpBasedFrame) {
950*03ce13f7SAndroid Build Coastguard Worker     assert(
951*03ce13f7SAndroid Build Coastguard Worker         (RegsUsed & getRegisterSet(RegSet_FramePointer, RegSet_None)).count() ==
952*03ce13f7SAndroid Build Coastguard Worker         0);
953*03ce13f7SAndroid Build Coastguard Worker     PreservedRegsSizeBytes += typeWidthInBytes(WordType);
954*03ce13f7SAndroid Build Coastguard Worker     _link_bp();
955*03ce13f7SAndroid Build Coastguard Worker   }
956*03ce13f7SAndroid Build Coastguard Worker 
957*03ce13f7SAndroid Build Coastguard Worker   // Align the variables area. SpillAreaPaddingBytes is the size of the region
958*03ce13f7SAndroid Build Coastguard Worker   // after the preserved registers and before the spill areas.
959*03ce13f7SAndroid Build Coastguard Worker   // LocalsSlotsPaddingBytes is the amount of padding between the globals and
960*03ce13f7SAndroid Build Coastguard Worker   // locals area if they are separate.
961*03ce13f7SAndroid Build Coastguard Worker   assert(LocalsSlotsAlignmentBytes <= SpillAreaAlignmentBytes);
962*03ce13f7SAndroid Build Coastguard Worker   uint32_t SpillAreaPaddingBytes = 0;
963*03ce13f7SAndroid Build Coastguard Worker   uint32_t LocalsSlotsPaddingBytes = 0;
964*03ce13f7SAndroid Build Coastguard Worker   alignStackSpillAreas(X86_RET_IP_SIZE_BYTES + PreservedRegsSizeBytes,
965*03ce13f7SAndroid Build Coastguard Worker                        SpillAreaAlignmentBytes, GlobalsSize,
966*03ce13f7SAndroid Build Coastguard Worker                        LocalsSlotsAlignmentBytes, &SpillAreaPaddingBytes,
967*03ce13f7SAndroid Build Coastguard Worker                        &LocalsSlotsPaddingBytes);
968*03ce13f7SAndroid Build Coastguard Worker   SpillAreaSizeBytes += SpillAreaPaddingBytes + LocalsSlotsPaddingBytes;
969*03ce13f7SAndroid Build Coastguard Worker   uint32_t GlobalsAndSubsequentPaddingSize =
970*03ce13f7SAndroid Build Coastguard Worker       GlobalsSize + LocalsSlotsPaddingBytes;
971*03ce13f7SAndroid Build Coastguard Worker 
972*03ce13f7SAndroid Build Coastguard Worker   // Combine fixed allocations into SpillAreaSizeBytes if we are emitting the
973*03ce13f7SAndroid Build Coastguard Worker   // fixed allocations in the prolog.
974*03ce13f7SAndroid Build Coastguard Worker   if (PrologEmitsFixedAllocas)
975*03ce13f7SAndroid Build Coastguard Worker     SpillAreaSizeBytes += FixedAllocaSizeBytes;
976*03ce13f7SAndroid Build Coastguard Worker 
977*03ce13f7SAndroid Build Coastguard Worker   // Win64 ABI: add space for shadow store (aka home space)
978*03ce13f7SAndroid Build Coastguard Worker   SpillAreaSizeBytes += ShadowStoreSize;
979*03ce13f7SAndroid Build Coastguard Worker 
980*03ce13f7SAndroid Build Coastguard Worker   // Entering the function has made the stack pointer unaligned. Re-align it by
981*03ce13f7SAndroid Build Coastguard Worker   // adjusting the stack size.
982*03ce13f7SAndroid Build Coastguard Worker   // Note that StackOffset does not include spill area. It's the offset from the
983*03ce13f7SAndroid Build Coastguard Worker   // base stack pointer (epb), whether we set it or not, to the the first stack
984*03ce13f7SAndroid Build Coastguard Worker   // arg (if any). StackSize, on the other hand, does include the spill area.
985*03ce13f7SAndroid Build Coastguard Worker   const uint32_t StackOffset =
986*03ce13f7SAndroid Build Coastguard Worker       ShadowStoreSize + X86_RET_IP_SIZE_BYTES + PreservedRegsSizeBytes;
987*03ce13f7SAndroid Build Coastguard Worker   uint32_t StackSize = Utils::applyAlignment(StackOffset + SpillAreaSizeBytes,
988*03ce13f7SAndroid Build Coastguard Worker                                              RequiredStackAlignment);
989*03ce13f7SAndroid Build Coastguard Worker   StackSize = Utils::applyAlignment(StackSize + maxOutArgsSizeBytes(),
990*03ce13f7SAndroid Build Coastguard Worker                                     RequiredStackAlignment);
991*03ce13f7SAndroid Build Coastguard Worker   SpillAreaSizeBytes = StackSize - StackOffset; // Adjust for alignment, if any
992*03ce13f7SAndroid Build Coastguard Worker 
993*03ce13f7SAndroid Build Coastguard Worker   if (SpillAreaSizeBytes) {
994*03ce13f7SAndroid Build Coastguard Worker     auto *Func = Node->getCfg();
995*03ce13f7SAndroid Build Coastguard Worker     if (SpillAreaSizeBytes > Func->getStackSizeLimit()) {
996*03ce13f7SAndroid Build Coastguard Worker       Func->setError("Stack size limit exceeded");
997*03ce13f7SAndroid Build Coastguard Worker     }
998*03ce13f7SAndroid Build Coastguard Worker 
999*03ce13f7SAndroid Build Coastguard Worker     emitStackProbe(SpillAreaSizeBytes);
1000*03ce13f7SAndroid Build Coastguard Worker 
1001*03ce13f7SAndroid Build Coastguard Worker     // Generate "sub stackptr, SpillAreaSizeBytes"
1002*03ce13f7SAndroid Build Coastguard Worker     _sub_sp(Ctx->getConstantInt32(SpillAreaSizeBytes));
1003*03ce13f7SAndroid Build Coastguard Worker   }
1004*03ce13f7SAndroid Build Coastguard Worker 
1005*03ce13f7SAndroid Build Coastguard Worker   // StackPointer: points just past the spill area (end of stack frame)
1006*03ce13f7SAndroid Build Coastguard Worker 
1007*03ce13f7SAndroid Build Coastguard Worker   // Account for known-frame-offset alloca instructions that were not already
1008*03ce13f7SAndroid Build Coastguard Worker   // combined into the prolog.
1009*03ce13f7SAndroid Build Coastguard Worker   if (!PrologEmitsFixedAllocas)
1010*03ce13f7SAndroid Build Coastguard Worker     SpillAreaSizeBytes += FixedAllocaSizeBytes;
1011*03ce13f7SAndroid Build Coastguard Worker 
1012*03ce13f7SAndroid Build Coastguard Worker   Ctx->statsUpdateFrameBytes(SpillAreaSizeBytes);
1013*03ce13f7SAndroid Build Coastguard Worker 
1014*03ce13f7SAndroid Build Coastguard Worker   // Fill in stack offsets for stack args, and copy args into registers for
1015*03ce13f7SAndroid Build Coastguard Worker   // those that were register-allocated. Args are pushed right to left, so
1016*03ce13f7SAndroid Build Coastguard Worker   // Arg[0] is closest to the stack/frame pointer.
1017*03ce13f7SAndroid Build Coastguard Worker   RegNumT FrameOrStackReg = IsEbpBasedFrame ? getFrameReg() : getStackReg();
1018*03ce13f7SAndroid Build Coastguard Worker   Variable *FramePtr = getPhysicalRegister(FrameOrStackReg, WordType);
1019*03ce13f7SAndroid Build Coastguard Worker   size_t BasicFrameOffset = StackOffset;
1020*03ce13f7SAndroid Build Coastguard Worker   if (!IsEbpBasedFrame)
1021*03ce13f7SAndroid Build Coastguard Worker     BasicFrameOffset += SpillAreaSizeBytes;
1022*03ce13f7SAndroid Build Coastguard Worker 
1023*03ce13f7SAndroid Build Coastguard Worker   const VarList &Args = Func->getArgs();
1024*03ce13f7SAndroid Build Coastguard Worker   size_t InArgsSizeBytes = 0;
1025*03ce13f7SAndroid Build Coastguard Worker   unsigned NumXmmArgs = 0;
1026*03ce13f7SAndroid Build Coastguard Worker   unsigned NumGPRArgs = 0;
1027*03ce13f7SAndroid Build Coastguard Worker   for (SizeT i = 0, NumArgs = Args.size(); i < NumArgs; ++i) {
1028*03ce13f7SAndroid Build Coastguard Worker     Variable *Arg = Args[i];
1029*03ce13f7SAndroid Build Coastguard Worker     // Skip arguments passed in registers.
1030*03ce13f7SAndroid Build Coastguard Worker     if (isVectorType(Arg->getType())) {
1031*03ce13f7SAndroid Build Coastguard Worker       if (RegX8664::getRegisterForXmmArgNum(
1032*03ce13f7SAndroid Build Coastguard Worker               RegX8664::getArgIndex(i, NumXmmArgs))
1033*03ce13f7SAndroid Build Coastguard Worker               .hasValue()) {
1034*03ce13f7SAndroid Build Coastguard Worker         ++NumXmmArgs;
1035*03ce13f7SAndroid Build Coastguard Worker         continue;
1036*03ce13f7SAndroid Build Coastguard Worker       }
1037*03ce13f7SAndroid Build Coastguard Worker     } else if (isScalarFloatingType(Arg->getType())) {
1038*03ce13f7SAndroid Build Coastguard Worker       if (RegX8664::getRegisterForXmmArgNum(
1039*03ce13f7SAndroid Build Coastguard Worker               RegX8664::getArgIndex(i, NumXmmArgs))
1040*03ce13f7SAndroid Build Coastguard Worker               .hasValue()) {
1041*03ce13f7SAndroid Build Coastguard Worker         ++NumXmmArgs;
1042*03ce13f7SAndroid Build Coastguard Worker         continue;
1043*03ce13f7SAndroid Build Coastguard Worker       }
1044*03ce13f7SAndroid Build Coastguard Worker     } else {
1045*03ce13f7SAndroid Build Coastguard Worker       assert(isScalarIntegerType(Arg->getType()));
1046*03ce13f7SAndroid Build Coastguard Worker       if (RegX8664::getRegisterForGprArgNum(
1047*03ce13f7SAndroid Build Coastguard Worker               WordType, RegX8664::getArgIndex(i, NumGPRArgs))
1048*03ce13f7SAndroid Build Coastguard Worker               .hasValue()) {
1049*03ce13f7SAndroid Build Coastguard Worker         ++NumGPRArgs;
1050*03ce13f7SAndroid Build Coastguard Worker         continue;
1051*03ce13f7SAndroid Build Coastguard Worker       }
1052*03ce13f7SAndroid Build Coastguard Worker     }
1053*03ce13f7SAndroid Build Coastguard Worker     // For esp-based frames where the allocas are done outside the prolog, the
1054*03ce13f7SAndroid Build Coastguard Worker     // esp value may not stabilize to its home value until after all the
1055*03ce13f7SAndroid Build Coastguard Worker     // fixed-size alloca instructions have executed.  In this case, a stack
1056*03ce13f7SAndroid Build Coastguard Worker     // adjustment is needed when accessing in-args in order to copy them into
1057*03ce13f7SAndroid Build Coastguard Worker     // registers.
1058*03ce13f7SAndroid Build Coastguard Worker     size_t StackAdjBytes = 0;
1059*03ce13f7SAndroid Build Coastguard Worker     if (!IsEbpBasedFrame && !PrologEmitsFixedAllocas)
1060*03ce13f7SAndroid Build Coastguard Worker       StackAdjBytes -= FixedAllocaSizeBytes;
1061*03ce13f7SAndroid Build Coastguard Worker     finishArgumentLowering(Arg, FramePtr, BasicFrameOffset, StackAdjBytes,
1062*03ce13f7SAndroid Build Coastguard Worker                            InArgsSizeBytes);
1063*03ce13f7SAndroid Build Coastguard Worker   }
1064*03ce13f7SAndroid Build Coastguard Worker 
1065*03ce13f7SAndroid Build Coastguard Worker   // Fill in stack offsets for locals.
1066*03ce13f7SAndroid Build Coastguard Worker   assignVarStackSlots(SortedSpilledVariables, SpillAreaPaddingBytes,
1067*03ce13f7SAndroid Build Coastguard Worker                       SpillAreaSizeBytes, GlobalsAndSubsequentPaddingSize,
1068*03ce13f7SAndroid Build Coastguard Worker                       IsEbpBasedFrame && !needsStackPointerAlignment());
1069*03ce13f7SAndroid Build Coastguard Worker   // Assign stack offsets to variables that have been linked to spilled
1070*03ce13f7SAndroid Build Coastguard Worker   // variables.
1071*03ce13f7SAndroid Build Coastguard Worker   for (Variable *Var : VariablesLinkedToSpillSlots) {
1072*03ce13f7SAndroid Build Coastguard Worker     const Variable *Root = Var->getLinkedToStackRoot();
1073*03ce13f7SAndroid Build Coastguard Worker     assert(Root != nullptr);
1074*03ce13f7SAndroid Build Coastguard Worker     Var->setStackOffset(Root->getStackOffset());
1075*03ce13f7SAndroid Build Coastguard Worker 
1076*03ce13f7SAndroid Build Coastguard Worker     // If the stack root variable is an arg, make this variable an arg too so
1077*03ce13f7SAndroid Build Coastguard Worker     // that stackVarToAsmAddress uses the correct base pointer (e.g. ebp on
1078*03ce13f7SAndroid Build Coastguard Worker     // x86).
1079*03ce13f7SAndroid Build Coastguard Worker     Var->setIsArg(Root->getIsArg());
1080*03ce13f7SAndroid Build Coastguard Worker   }
1081*03ce13f7SAndroid Build Coastguard Worker   this->HasComputedFrame = true;
1082*03ce13f7SAndroid Build Coastguard Worker 
1083*03ce13f7SAndroid Build Coastguard Worker   if (BuildDefs::dump() && Func->isVerbose(IceV_Frame)) {
1084*03ce13f7SAndroid Build Coastguard Worker     OstreamLocker L(Func->getContext());
1085*03ce13f7SAndroid Build Coastguard Worker     Ostream &Str = Func->getContext()->getStrDump();
1086*03ce13f7SAndroid Build Coastguard Worker 
1087*03ce13f7SAndroid Build Coastguard Worker     Str << "Stack layout:\n";
1088*03ce13f7SAndroid Build Coastguard Worker     uint32_t EspAdjustmentPaddingSize =
1089*03ce13f7SAndroid Build Coastguard Worker         SpillAreaSizeBytes - LocalsSpillAreaSize -
1090*03ce13f7SAndroid Build Coastguard Worker         GlobalsAndSubsequentPaddingSize - SpillAreaPaddingBytes -
1091*03ce13f7SAndroid Build Coastguard Worker         maxOutArgsSizeBytes();
1092*03ce13f7SAndroid Build Coastguard Worker     Str << " in-args = " << InArgsSizeBytes << " bytes\n"
1093*03ce13f7SAndroid Build Coastguard Worker         << " return address = " << X86_RET_IP_SIZE_BYTES << " bytes\n"
1094*03ce13f7SAndroid Build Coastguard Worker         << " preserved registers = " << PreservedRegsSizeBytes << " bytes\n"
1095*03ce13f7SAndroid Build Coastguard Worker         << " spill area padding = " << SpillAreaPaddingBytes << " bytes\n"
1096*03ce13f7SAndroid Build Coastguard Worker         << " globals spill area = " << GlobalsSize << " bytes\n"
1097*03ce13f7SAndroid Build Coastguard Worker         << " globals-locals spill areas intermediate padding = "
1098*03ce13f7SAndroid Build Coastguard Worker         << GlobalsAndSubsequentPaddingSize - GlobalsSize << " bytes\n"
1099*03ce13f7SAndroid Build Coastguard Worker         << " locals spill area = " << LocalsSpillAreaSize << " bytes\n"
1100*03ce13f7SAndroid Build Coastguard Worker         << " esp alignment padding = " << EspAdjustmentPaddingSize
1101*03ce13f7SAndroid Build Coastguard Worker         << " bytes\n";
1102*03ce13f7SAndroid Build Coastguard Worker 
1103*03ce13f7SAndroid Build Coastguard Worker     Str << "Stack details:\n"
1104*03ce13f7SAndroid Build Coastguard Worker         << " esp adjustment = " << SpillAreaSizeBytes << " bytes\n"
1105*03ce13f7SAndroid Build Coastguard Worker         << " spill area alignment = " << SpillAreaAlignmentBytes << " bytes\n"
1106*03ce13f7SAndroid Build Coastguard Worker         << " outgoing args size = " << maxOutArgsSizeBytes() << " bytes\n"
1107*03ce13f7SAndroid Build Coastguard Worker         << " locals spill area alignment = " << LocalsSlotsAlignmentBytes
1108*03ce13f7SAndroid Build Coastguard Worker         << " bytes\n"
1109*03ce13f7SAndroid Build Coastguard Worker         << " is ebp based = " << IsEbpBasedFrame << "\n";
1110*03ce13f7SAndroid Build Coastguard Worker   }
1111*03ce13f7SAndroid Build Coastguard Worker }
1112*03ce13f7SAndroid Build Coastguard Worker 
1113*03ce13f7SAndroid Build Coastguard Worker /// Helper function for addProlog().
1114*03ce13f7SAndroid Build Coastguard Worker ///
1115*03ce13f7SAndroid Build Coastguard Worker /// This assumes Arg is an argument passed on the stack. This sets the frame
1116*03ce13f7SAndroid Build Coastguard Worker /// offset for Arg and updates InArgsSizeBytes according to Arg's width. For an
1117*03ce13f7SAndroid Build Coastguard Worker /// I64 arg that has been split into Lo and Hi components, it calls itself
1118*03ce13f7SAndroid Build Coastguard Worker /// recursively on the components, taking care to handle Lo first because of the
1119*03ce13f7SAndroid Build Coastguard Worker /// little-endian architecture. Lastly, this function generates an instruction
1120*03ce13f7SAndroid Build Coastguard Worker /// to copy Arg into its assigned register if applicable.
1121*03ce13f7SAndroid Build Coastguard Worker 
finishArgumentLowering(Variable * Arg,Variable * FramePtr,size_t BasicFrameOffset,size_t StackAdjBytes,size_t & InArgsSizeBytes)1122*03ce13f7SAndroid Build Coastguard Worker void TargetX8664::finishArgumentLowering(Variable *Arg, Variable *FramePtr,
1123*03ce13f7SAndroid Build Coastguard Worker                                          size_t BasicFrameOffset,
1124*03ce13f7SAndroid Build Coastguard Worker                                          size_t StackAdjBytes,
1125*03ce13f7SAndroid Build Coastguard Worker                                          size_t &InArgsSizeBytes) {
1126*03ce13f7SAndroid Build Coastguard Worker   Type Ty = Arg->getType();
1127*03ce13f7SAndroid Build Coastguard Worker   if (isVectorType(Ty)) {
1128*03ce13f7SAndroid Build Coastguard Worker     InArgsSizeBytes = applyStackAlignment(InArgsSizeBytes);
1129*03ce13f7SAndroid Build Coastguard Worker   }
1130*03ce13f7SAndroid Build Coastguard Worker   Arg->setStackOffset(BasicFrameOffset + InArgsSizeBytes);
1131*03ce13f7SAndroid Build Coastguard Worker   InArgsSizeBytes += typeWidthInBytesOnStack(Ty);
1132*03ce13f7SAndroid Build Coastguard Worker   if (Arg->hasReg()) {
1133*03ce13f7SAndroid Build Coastguard Worker     auto *Mem = X86OperandMem::create(
1134*03ce13f7SAndroid Build Coastguard Worker         Func, Ty, FramePtr,
1135*03ce13f7SAndroid Build Coastguard Worker         Ctx->getConstantInt32(Arg->getStackOffset() + StackAdjBytes));
1136*03ce13f7SAndroid Build Coastguard Worker     if (isVectorType(Arg->getType())) {
1137*03ce13f7SAndroid Build Coastguard Worker       _movp(Arg, Mem);
1138*03ce13f7SAndroid Build Coastguard Worker     } else {
1139*03ce13f7SAndroid Build Coastguard Worker       _mov(Arg, Mem);
1140*03ce13f7SAndroid Build Coastguard Worker     }
1141*03ce13f7SAndroid Build Coastguard Worker     // This argument-copying instruction uses an explicit X86OperandMem
1142*03ce13f7SAndroid Build Coastguard Worker     // operand instead of a Variable, so its fill-from-stack operation has to
1143*03ce13f7SAndroid Build Coastguard Worker     // be tracked separately for statistics.
1144*03ce13f7SAndroid Build Coastguard Worker     Ctx->statsUpdateFills();
1145*03ce13f7SAndroid Build Coastguard Worker   }
1146*03ce13f7SAndroid Build Coastguard Worker }
1147*03ce13f7SAndroid Build Coastguard Worker 
addEpilog(CfgNode * Node)1148*03ce13f7SAndroid Build Coastguard Worker void TargetX8664::addEpilog(CfgNode *Node) {
1149*03ce13f7SAndroid Build Coastguard Worker   InstList &Insts = Node->getInsts();
1150*03ce13f7SAndroid Build Coastguard Worker   InstList::reverse_iterator RI, E;
1151*03ce13f7SAndroid Build Coastguard Worker   for (RI = Insts.rbegin(), E = Insts.rend(); RI != E; ++RI) {
1152*03ce13f7SAndroid Build Coastguard Worker     if (llvm::isa<Insts::Ret>(*RI))
1153*03ce13f7SAndroid Build Coastguard Worker       break;
1154*03ce13f7SAndroid Build Coastguard Worker   }
1155*03ce13f7SAndroid Build Coastguard Worker   if (RI == E)
1156*03ce13f7SAndroid Build Coastguard Worker     return;
1157*03ce13f7SAndroid Build Coastguard Worker 
1158*03ce13f7SAndroid Build Coastguard Worker   // Convert the reverse_iterator position into its corresponding (forward)
1159*03ce13f7SAndroid Build Coastguard Worker   // iterator position.
1160*03ce13f7SAndroid Build Coastguard Worker   InstList::iterator InsertPoint = reverseToForwardIterator(RI);
1161*03ce13f7SAndroid Build Coastguard Worker   --InsertPoint;
1162*03ce13f7SAndroid Build Coastguard Worker   Context.init(Node);
1163*03ce13f7SAndroid Build Coastguard Worker   Context.setInsertPoint(InsertPoint);
1164*03ce13f7SAndroid Build Coastguard Worker 
1165*03ce13f7SAndroid Build Coastguard Worker   if (IsEbpBasedFrame) {
1166*03ce13f7SAndroid Build Coastguard Worker     _unlink_bp();
1167*03ce13f7SAndroid Build Coastguard Worker   } else {
1168*03ce13f7SAndroid Build Coastguard Worker     // add stackptr, SpillAreaSizeBytes
1169*03ce13f7SAndroid Build Coastguard Worker     if (SpillAreaSizeBytes != 0) {
1170*03ce13f7SAndroid Build Coastguard Worker       _add_sp(Ctx->getConstantInt32(SpillAreaSizeBytes));
1171*03ce13f7SAndroid Build Coastguard Worker     }
1172*03ce13f7SAndroid Build Coastguard Worker   }
1173*03ce13f7SAndroid Build Coastguard Worker 
1174*03ce13f7SAndroid Build Coastguard Worker   // Add pop instructions for preserved registers.
1175*03ce13f7SAndroid Build Coastguard Worker   SmallBitVector CalleeSaves = getRegisterSet(RegSet_CalleeSave, RegSet_None);
1176*03ce13f7SAndroid Build Coastguard Worker   SmallBitVector Popped(CalleeSaves.size());
1177*03ce13f7SAndroid Build Coastguard Worker   for (int32_t i = CalleeSaves.size() - 1; i >= 0; --i) {
1178*03ce13f7SAndroid Build Coastguard Worker     const auto RegNum = RegNumT::fromInt(i);
1179*03ce13f7SAndroid Build Coastguard Worker     if (RegNum == getFrameReg() && IsEbpBasedFrame)
1180*03ce13f7SAndroid Build Coastguard Worker       continue;
1181*03ce13f7SAndroid Build Coastguard Worker     const RegNumT Canonical = RegX8664::getBaseReg(RegNum);
1182*03ce13f7SAndroid Build Coastguard Worker     if (CalleeSaves[i] && RegsUsed[i]) {
1183*03ce13f7SAndroid Build Coastguard Worker       Popped[Canonical] = true;
1184*03ce13f7SAndroid Build Coastguard Worker     }
1185*03ce13f7SAndroid Build Coastguard Worker   }
1186*03ce13f7SAndroid Build Coastguard Worker   for (int32_t i = Popped.size() - 1; i >= 0; --i) {
1187*03ce13f7SAndroid Build Coastguard Worker     if (!Popped[i])
1188*03ce13f7SAndroid Build Coastguard Worker       continue;
1189*03ce13f7SAndroid Build Coastguard Worker     const auto RegNum = RegNumT::fromInt(i);
1190*03ce13f7SAndroid Build Coastguard Worker     assert(RegNum == RegX8664::getBaseReg(RegNum));
1191*03ce13f7SAndroid Build Coastguard Worker     _pop_reg(RegNum);
1192*03ce13f7SAndroid Build Coastguard Worker   }
1193*03ce13f7SAndroid Build Coastguard Worker }
1194*03ce13f7SAndroid Build Coastguard Worker 
stackSlotType()1195*03ce13f7SAndroid Build Coastguard Worker Type TargetX8664::stackSlotType() { return WordType; }
1196*03ce13f7SAndroid Build Coastguard Worker 
getRegisterSet(RegSetMask Include,RegSetMask Exclude) const1197*03ce13f7SAndroid Build Coastguard Worker SmallBitVector TargetX8664::getRegisterSet(RegSetMask Include,
1198*03ce13f7SAndroid Build Coastguard Worker                                            RegSetMask Exclude) const {
1199*03ce13f7SAndroid Build Coastguard Worker   return RegX8664::getRegisterSet(getFlags(), Include, Exclude);
1200*03ce13f7SAndroid Build Coastguard Worker }
1201*03ce13f7SAndroid Build Coastguard Worker 
lowerAlloca(const InstAlloca * Instr)1202*03ce13f7SAndroid Build Coastguard Worker void TargetX8664::lowerAlloca(const InstAlloca *Instr) {
1203*03ce13f7SAndroid Build Coastguard Worker   // For default align=0, set it to the real value 1, to avoid any
1204*03ce13f7SAndroid Build Coastguard Worker   // bit-manipulation problems below.
1205*03ce13f7SAndroid Build Coastguard Worker   const uint32_t AlignmentParam = std::max(1u, Instr->getAlignInBytes());
1206*03ce13f7SAndroid Build Coastguard Worker 
1207*03ce13f7SAndroid Build Coastguard Worker   // LLVM enforces power of 2 alignment.
1208*03ce13f7SAndroid Build Coastguard Worker   assert(llvm::isPowerOf2_32(AlignmentParam));
1209*03ce13f7SAndroid Build Coastguard Worker 
1210*03ce13f7SAndroid Build Coastguard Worker   const uint32_t Alignment = std::max(AlignmentParam, RequiredStackAlignment);
1211*03ce13f7SAndroid Build Coastguard Worker   const bool OverAligned = Alignment > RequiredStackAlignment;
1212*03ce13f7SAndroid Build Coastguard Worker   const bool OptM1 = Func->getOptLevel() == Opt_m1;
1213*03ce13f7SAndroid Build Coastguard Worker   const bool AllocaWithKnownOffset = Instr->getKnownFrameOffset();
1214*03ce13f7SAndroid Build Coastguard Worker   const bool UseFramePointer =
1215*03ce13f7SAndroid Build Coastguard Worker       hasFramePointer() || OverAligned || !AllocaWithKnownOffset || OptM1;
1216*03ce13f7SAndroid Build Coastguard Worker 
1217*03ce13f7SAndroid Build Coastguard Worker   if (UseFramePointer)
1218*03ce13f7SAndroid Build Coastguard Worker     setHasFramePointer();
1219*03ce13f7SAndroid Build Coastguard Worker 
1220*03ce13f7SAndroid Build Coastguard Worker   Variable *esp = getPhysicalRegister(getStackReg(), WordType);
1221*03ce13f7SAndroid Build Coastguard Worker   if (OverAligned) {
1222*03ce13f7SAndroid Build Coastguard Worker     _and(esp, Ctx->getConstantInt32(-Alignment));
1223*03ce13f7SAndroid Build Coastguard Worker   }
1224*03ce13f7SAndroid Build Coastguard Worker 
1225*03ce13f7SAndroid Build Coastguard Worker   Variable *Dest = Instr->getDest();
1226*03ce13f7SAndroid Build Coastguard Worker   Operand *TotalSize = legalize(Instr->getSizeInBytes());
1227*03ce13f7SAndroid Build Coastguard Worker 
1228*03ce13f7SAndroid Build Coastguard Worker   if (const auto *ConstantTotalSize =
1229*03ce13f7SAndroid Build Coastguard Worker           llvm::dyn_cast<ConstantInteger32>(TotalSize)) {
1230*03ce13f7SAndroid Build Coastguard Worker     const uint32_t Value =
1231*03ce13f7SAndroid Build Coastguard Worker         Utils::applyAlignment(ConstantTotalSize->getValue(), Alignment);
1232*03ce13f7SAndroid Build Coastguard Worker     if (UseFramePointer) {
1233*03ce13f7SAndroid Build Coastguard Worker       _sub_sp(Ctx->getConstantInt32(Value));
1234*03ce13f7SAndroid Build Coastguard Worker     } else {
1235*03ce13f7SAndroid Build Coastguard Worker       // If we don't need a Frame Pointer, this alloca has a known offset to the
1236*03ce13f7SAndroid Build Coastguard Worker       // stack pointer. We don't need adjust the stack pointer, nor assign any
1237*03ce13f7SAndroid Build Coastguard Worker       // value to Dest, as Dest is rematerializable.
1238*03ce13f7SAndroid Build Coastguard Worker       assert(Dest->isRematerializable());
1239*03ce13f7SAndroid Build Coastguard Worker       FixedAllocaSizeBytes += Value;
1240*03ce13f7SAndroid Build Coastguard Worker       Context.insert<InstFakeDef>(Dest);
1241*03ce13f7SAndroid Build Coastguard Worker     }
1242*03ce13f7SAndroid Build Coastguard Worker   } else {
1243*03ce13f7SAndroid Build Coastguard Worker     // Non-constant sizes need to be adjusted to the next highest multiple of
1244*03ce13f7SAndroid Build Coastguard Worker     // the required alignment at runtime.
1245*03ce13f7SAndroid Build Coastguard Worker     Variable *T = nullptr;
1246*03ce13f7SAndroid Build Coastguard Worker     if (TotalSize->getType() != IceType_i64) {
1247*03ce13f7SAndroid Build Coastguard Worker       T = makeReg(IceType_i64);
1248*03ce13f7SAndroid Build Coastguard Worker       _movzx(T, TotalSize);
1249*03ce13f7SAndroid Build Coastguard Worker     } else {
1250*03ce13f7SAndroid Build Coastguard Worker       T = makeReg(IceType_i32);
1251*03ce13f7SAndroid Build Coastguard Worker       _mov(T, TotalSize);
1252*03ce13f7SAndroid Build Coastguard Worker     }
1253*03ce13f7SAndroid Build Coastguard Worker     _add(T, Ctx->getConstantInt32(Alignment - 1));
1254*03ce13f7SAndroid Build Coastguard Worker     _and(T, Ctx->getConstantInt32(-Alignment));
1255*03ce13f7SAndroid Build Coastguard Worker     _sub_sp(T);
1256*03ce13f7SAndroid Build Coastguard Worker   }
1257*03ce13f7SAndroid Build Coastguard Worker   // Add enough to the returned address to account for the out args area.
1258*03ce13f7SAndroid Build Coastguard Worker   uint32_t OutArgsSize = maxOutArgsSizeBytes();
1259*03ce13f7SAndroid Build Coastguard Worker   if (OutArgsSize > 0) {
1260*03ce13f7SAndroid Build Coastguard Worker     Variable *T = makeReg(Dest->getType());
1261*03ce13f7SAndroid Build Coastguard Worker     auto *CalculateOperand = X86OperandMem::create(
1262*03ce13f7SAndroid Build Coastguard Worker         Func, IceType_void, esp, Ctx->getConstantInt(IceType_i32, OutArgsSize));
1263*03ce13f7SAndroid Build Coastguard Worker     _lea(T, CalculateOperand);
1264*03ce13f7SAndroid Build Coastguard Worker     _mov(Dest, T);
1265*03ce13f7SAndroid Build Coastguard Worker   } else {
1266*03ce13f7SAndroid Build Coastguard Worker     _mov(Dest, esp);
1267*03ce13f7SAndroid Build Coastguard Worker   }
1268*03ce13f7SAndroid Build Coastguard Worker }
1269*03ce13f7SAndroid Build Coastguard Worker 
lowerArguments()1270*03ce13f7SAndroid Build Coastguard Worker void TargetX8664::lowerArguments() {
1271*03ce13f7SAndroid Build Coastguard Worker   const bool OptM1 = Func->getOptLevel() == Opt_m1;
1272*03ce13f7SAndroid Build Coastguard Worker   VarList &Args = Func->getArgs();
1273*03ce13f7SAndroid Build Coastguard Worker   unsigned NumXmmArgs = 0;
1274*03ce13f7SAndroid Build Coastguard Worker   bool XmmSlotsRemain = true;
1275*03ce13f7SAndroid Build Coastguard Worker   unsigned NumGprArgs = 0;
1276*03ce13f7SAndroid Build Coastguard Worker   bool GprSlotsRemain = true;
1277*03ce13f7SAndroid Build Coastguard Worker 
1278*03ce13f7SAndroid Build Coastguard Worker   Context.init(Func->getEntryNode());
1279*03ce13f7SAndroid Build Coastguard Worker   Context.setInsertPoint(Context.getCur());
1280*03ce13f7SAndroid Build Coastguard Worker 
1281*03ce13f7SAndroid Build Coastguard Worker   for (SizeT i = 0, End = Args.size();
1282*03ce13f7SAndroid Build Coastguard Worker        i < End && (XmmSlotsRemain || GprSlotsRemain); ++i) {
1283*03ce13f7SAndroid Build Coastguard Worker     Variable *Arg = Args[i];
1284*03ce13f7SAndroid Build Coastguard Worker     Type Ty = Arg->getType();
1285*03ce13f7SAndroid Build Coastguard Worker     Variable *RegisterArg = nullptr;
1286*03ce13f7SAndroid Build Coastguard Worker     RegNumT RegNum;
1287*03ce13f7SAndroid Build Coastguard Worker     if (isVectorType(Ty)) {
1288*03ce13f7SAndroid Build Coastguard Worker       RegNum = RegX8664::getRegisterForXmmArgNum(
1289*03ce13f7SAndroid Build Coastguard Worker           RegX8664::getArgIndex(i, NumXmmArgs));
1290*03ce13f7SAndroid Build Coastguard Worker       if (RegNum.hasNoValue()) {
1291*03ce13f7SAndroid Build Coastguard Worker         XmmSlotsRemain = false;
1292*03ce13f7SAndroid Build Coastguard Worker         continue;
1293*03ce13f7SAndroid Build Coastguard Worker       }
1294*03ce13f7SAndroid Build Coastguard Worker       ++NumXmmArgs;
1295*03ce13f7SAndroid Build Coastguard Worker       RegisterArg = Func->makeVariable(Ty);
1296*03ce13f7SAndroid Build Coastguard Worker     } else if (isScalarFloatingType(Ty)) {
1297*03ce13f7SAndroid Build Coastguard Worker       RegNum = RegX8664::getRegisterForXmmArgNum(
1298*03ce13f7SAndroid Build Coastguard Worker           RegX8664::getArgIndex(i, NumXmmArgs));
1299*03ce13f7SAndroid Build Coastguard Worker       if (RegNum.hasNoValue()) {
1300*03ce13f7SAndroid Build Coastguard Worker         XmmSlotsRemain = false;
1301*03ce13f7SAndroid Build Coastguard Worker         continue;
1302*03ce13f7SAndroid Build Coastguard Worker       }
1303*03ce13f7SAndroid Build Coastguard Worker       ++NumXmmArgs;
1304*03ce13f7SAndroid Build Coastguard Worker       RegisterArg = Func->makeVariable(Ty);
1305*03ce13f7SAndroid Build Coastguard Worker     } else if (isScalarIntegerType(Ty)) {
1306*03ce13f7SAndroid Build Coastguard Worker       RegNum = RegX8664::getRegisterForGprArgNum(
1307*03ce13f7SAndroid Build Coastguard Worker           Ty, RegX8664::getArgIndex(i, NumGprArgs));
1308*03ce13f7SAndroid Build Coastguard Worker       if (RegNum.hasNoValue()) {
1309*03ce13f7SAndroid Build Coastguard Worker         GprSlotsRemain = false;
1310*03ce13f7SAndroid Build Coastguard Worker         continue;
1311*03ce13f7SAndroid Build Coastguard Worker       }
1312*03ce13f7SAndroid Build Coastguard Worker       ++NumGprArgs;
1313*03ce13f7SAndroid Build Coastguard Worker       RegisterArg = Func->makeVariable(Ty);
1314*03ce13f7SAndroid Build Coastguard Worker     }
1315*03ce13f7SAndroid Build Coastguard Worker     assert(RegNum.hasValue());
1316*03ce13f7SAndroid Build Coastguard Worker     assert(RegisterArg != nullptr);
1317*03ce13f7SAndroid Build Coastguard Worker     // Replace Arg in the argument list with the home register. Then generate
1318*03ce13f7SAndroid Build Coastguard Worker     // an instruction in the prolog to copy the home register to the assigned
1319*03ce13f7SAndroid Build Coastguard Worker     // location of Arg.
1320*03ce13f7SAndroid Build Coastguard Worker     if (BuildDefs::dump())
1321*03ce13f7SAndroid Build Coastguard Worker       RegisterArg->setName(Func, "home_reg:" + Arg->getName());
1322*03ce13f7SAndroid Build Coastguard Worker     RegisterArg->setRegNum(RegNum);
1323*03ce13f7SAndroid Build Coastguard Worker     RegisterArg->setIsArg();
1324*03ce13f7SAndroid Build Coastguard Worker     Arg->setIsArg(false);
1325*03ce13f7SAndroid Build Coastguard Worker 
1326*03ce13f7SAndroid Build Coastguard Worker     Args[i] = RegisterArg;
1327*03ce13f7SAndroid Build Coastguard Worker     // When not Om1, do the assignment through a temporary, instead of directly
1328*03ce13f7SAndroid Build Coastguard Worker     // from the pre-colored variable, so that a subsequent availabilityGet()
1329*03ce13f7SAndroid Build Coastguard Worker     // call has a chance to work.  (In Om1, don't bother creating extra
1330*03ce13f7SAndroid Build Coastguard Worker     // instructions with extra variables to register-allocate.)
1331*03ce13f7SAndroid Build Coastguard Worker     if (OptM1) {
1332*03ce13f7SAndroid Build Coastguard Worker       Context.insert<InstAssign>(Arg, RegisterArg);
1333*03ce13f7SAndroid Build Coastguard Worker     } else {
1334*03ce13f7SAndroid Build Coastguard Worker       Variable *Tmp = makeReg(RegisterArg->getType());
1335*03ce13f7SAndroid Build Coastguard Worker       Context.insert<InstAssign>(Tmp, RegisterArg);
1336*03ce13f7SAndroid Build Coastguard Worker       Context.insert<InstAssign>(Arg, Tmp);
1337*03ce13f7SAndroid Build Coastguard Worker     }
1338*03ce13f7SAndroid Build Coastguard Worker   }
1339*03ce13f7SAndroid Build Coastguard Worker   if (!OptM1)
1340*03ce13f7SAndroid Build Coastguard Worker     Context.availabilityUpdate();
1341*03ce13f7SAndroid Build Coastguard Worker }
1342*03ce13f7SAndroid Build Coastguard Worker 
1343*03ce13f7SAndroid Build Coastguard Worker /// Strength-reduce scalar integer multiplication by a constant (for i32 or
1344*03ce13f7SAndroid Build Coastguard Worker /// narrower) for certain constants. The lea instruction can be used to multiply
1345*03ce13f7SAndroid Build Coastguard Worker /// by 3, 5, or 9, and the lsh instruction can be used to multiply by powers of
1346*03ce13f7SAndroid Build Coastguard Worker /// 2. These can be combined such that e.g. multiplying by 100 can be done as 2
1347*03ce13f7SAndroid Build Coastguard Worker /// lea-based multiplies by 5, combined with left-shifting by 2.
1348*03ce13f7SAndroid Build Coastguard Worker 
optimizeScalarMul(Variable * Dest,Operand * Src0,int32_t Src1)1349*03ce13f7SAndroid Build Coastguard Worker bool TargetX8664::optimizeScalarMul(Variable *Dest, Operand *Src0,
1350*03ce13f7SAndroid Build Coastguard Worker                                     int32_t Src1) {
1351*03ce13f7SAndroid Build Coastguard Worker   // Disable this optimization for Om1 and O0, just to keep things simple
1352*03ce13f7SAndroid Build Coastguard Worker   // there.
1353*03ce13f7SAndroid Build Coastguard Worker   if (Func->getOptLevel() < Opt_1)
1354*03ce13f7SAndroid Build Coastguard Worker     return false;
1355*03ce13f7SAndroid Build Coastguard Worker   Type Ty = Dest->getType();
1356*03ce13f7SAndroid Build Coastguard Worker   if (Src1 == -1) {
1357*03ce13f7SAndroid Build Coastguard Worker     Variable *T = nullptr;
1358*03ce13f7SAndroid Build Coastguard Worker     _mov(T, Src0);
1359*03ce13f7SAndroid Build Coastguard Worker     _neg(T);
1360*03ce13f7SAndroid Build Coastguard Worker     _mov(Dest, T);
1361*03ce13f7SAndroid Build Coastguard Worker     return true;
1362*03ce13f7SAndroid Build Coastguard Worker   }
1363*03ce13f7SAndroid Build Coastguard Worker   if (Src1 == 0) {
1364*03ce13f7SAndroid Build Coastguard Worker     _mov(Dest, Ctx->getConstantZero(Ty));
1365*03ce13f7SAndroid Build Coastguard Worker     return true;
1366*03ce13f7SAndroid Build Coastguard Worker   }
1367*03ce13f7SAndroid Build Coastguard Worker   if (Src1 == 1) {
1368*03ce13f7SAndroid Build Coastguard Worker     Variable *T = nullptr;
1369*03ce13f7SAndroid Build Coastguard Worker     _mov(T, Src0);
1370*03ce13f7SAndroid Build Coastguard Worker     _mov(Dest, T);
1371*03ce13f7SAndroid Build Coastguard Worker     return true;
1372*03ce13f7SAndroid Build Coastguard Worker   }
1373*03ce13f7SAndroid Build Coastguard Worker   // Don't bother with the edge case where Src1 == MININT.
1374*03ce13f7SAndroid Build Coastguard Worker   if (Src1 == -Src1)
1375*03ce13f7SAndroid Build Coastguard Worker     return false;
1376*03ce13f7SAndroid Build Coastguard Worker   const bool Src1IsNegative = Src1 < 0;
1377*03ce13f7SAndroid Build Coastguard Worker   if (Src1IsNegative)
1378*03ce13f7SAndroid Build Coastguard Worker     Src1 = -Src1;
1379*03ce13f7SAndroid Build Coastguard Worker   uint32_t Count9 = 0;
1380*03ce13f7SAndroid Build Coastguard Worker   uint32_t Count5 = 0;
1381*03ce13f7SAndroid Build Coastguard Worker   uint32_t Count3 = 0;
1382*03ce13f7SAndroid Build Coastguard Worker   uint32_t Count2 = 0;
1383*03ce13f7SAndroid Build Coastguard Worker   uint32_t CountOps = 0;
1384*03ce13f7SAndroid Build Coastguard Worker   while (Src1 > 1) {
1385*03ce13f7SAndroid Build Coastguard Worker     if (Src1 % 9 == 0) {
1386*03ce13f7SAndroid Build Coastguard Worker       ++CountOps;
1387*03ce13f7SAndroid Build Coastguard Worker       ++Count9;
1388*03ce13f7SAndroid Build Coastguard Worker       Src1 /= 9;
1389*03ce13f7SAndroid Build Coastguard Worker     } else if (Src1 % 5 == 0) {
1390*03ce13f7SAndroid Build Coastguard Worker       ++CountOps;
1391*03ce13f7SAndroid Build Coastguard Worker       ++Count5;
1392*03ce13f7SAndroid Build Coastguard Worker       Src1 /= 5;
1393*03ce13f7SAndroid Build Coastguard Worker     } else if (Src1 % 3 == 0) {
1394*03ce13f7SAndroid Build Coastguard Worker       ++CountOps;
1395*03ce13f7SAndroid Build Coastguard Worker       ++Count3;
1396*03ce13f7SAndroid Build Coastguard Worker       Src1 /= 3;
1397*03ce13f7SAndroid Build Coastguard Worker     } else if (Src1 % 2 == 0) {
1398*03ce13f7SAndroid Build Coastguard Worker       if (Count2 == 0)
1399*03ce13f7SAndroid Build Coastguard Worker         ++CountOps;
1400*03ce13f7SAndroid Build Coastguard Worker       ++Count2;
1401*03ce13f7SAndroid Build Coastguard Worker       Src1 /= 2;
1402*03ce13f7SAndroid Build Coastguard Worker     } else {
1403*03ce13f7SAndroid Build Coastguard Worker       return false;
1404*03ce13f7SAndroid Build Coastguard Worker     }
1405*03ce13f7SAndroid Build Coastguard Worker   }
1406*03ce13f7SAndroid Build Coastguard Worker   // Lea optimization only works for i16 and i32 types, not i8.
1407*03ce13f7SAndroid Build Coastguard Worker   if (Ty != IceType_i32 && Ty != IceType_i64 && (Count3 || Count5 || Count9))
1408*03ce13f7SAndroid Build Coastguard Worker     return false;
1409*03ce13f7SAndroid Build Coastguard Worker   // Limit the number of lea/shl operations for a single multiply, to a
1410*03ce13f7SAndroid Build Coastguard Worker   // somewhat arbitrary choice of 3.
1411*03ce13f7SAndroid Build Coastguard Worker   constexpr uint32_t MaxOpsForOptimizedMul = 3;
1412*03ce13f7SAndroid Build Coastguard Worker   if (CountOps > MaxOpsForOptimizedMul)
1413*03ce13f7SAndroid Build Coastguard Worker     return false;
1414*03ce13f7SAndroid Build Coastguard Worker   Variable *T = makeReg(WordType);
1415*03ce13f7SAndroid Build Coastguard Worker   if (typeWidthInBytes(Src0->getType()) < typeWidthInBytes(T->getType())) {
1416*03ce13f7SAndroid Build Coastguard Worker     Operand *Src0RM = legalize(Src0, Legal_Reg | Legal_Mem);
1417*03ce13f7SAndroid Build Coastguard Worker     _movzx(T, Src0RM);
1418*03ce13f7SAndroid Build Coastguard Worker   } else {
1419*03ce13f7SAndroid Build Coastguard Worker     _mov(T, Src0);
1420*03ce13f7SAndroid Build Coastguard Worker   }
1421*03ce13f7SAndroid Build Coastguard Worker   Constant *Zero = Ctx->getConstantZero(IceType_i32);
1422*03ce13f7SAndroid Build Coastguard Worker   for (uint32_t i = 0; i < Count9; ++i) {
1423*03ce13f7SAndroid Build Coastguard Worker     constexpr uint16_t Shift = 3; // log2(9-1)
1424*03ce13f7SAndroid Build Coastguard Worker     _lea(T, X86OperandMem::create(Func, IceType_void, T, Zero, T, Shift));
1425*03ce13f7SAndroid Build Coastguard Worker   }
1426*03ce13f7SAndroid Build Coastguard Worker   for (uint32_t i = 0; i < Count5; ++i) {
1427*03ce13f7SAndroid Build Coastguard Worker     constexpr uint16_t Shift = 2; // log2(5-1)
1428*03ce13f7SAndroid Build Coastguard Worker     _lea(T, X86OperandMem::create(Func, IceType_void, T, Zero, T, Shift));
1429*03ce13f7SAndroid Build Coastguard Worker   }
1430*03ce13f7SAndroid Build Coastguard Worker   for (uint32_t i = 0; i < Count3; ++i) {
1431*03ce13f7SAndroid Build Coastguard Worker     constexpr uint16_t Shift = 1; // log2(3-1)
1432*03ce13f7SAndroid Build Coastguard Worker     _lea(T, X86OperandMem::create(Func, IceType_void, T, Zero, T, Shift));
1433*03ce13f7SAndroid Build Coastguard Worker   }
1434*03ce13f7SAndroid Build Coastguard Worker   if (Count2) {
1435*03ce13f7SAndroid Build Coastguard Worker     _shl(T, Ctx->getConstantInt(Ty, Count2));
1436*03ce13f7SAndroid Build Coastguard Worker   }
1437*03ce13f7SAndroid Build Coastguard Worker   if (Src1IsNegative)
1438*03ce13f7SAndroid Build Coastguard Worker     _neg(T);
1439*03ce13f7SAndroid Build Coastguard Worker   _mov(Dest, T);
1440*03ce13f7SAndroid Build Coastguard Worker   return true;
1441*03ce13f7SAndroid Build Coastguard Worker }
1442*03ce13f7SAndroid Build Coastguard Worker 
lowerShift64(InstArithmetic::OpKind Op,Operand * Src0Lo,Operand * Src0Hi,Operand * Src1Lo,Variable * DestLo,Variable * DestHi)1443*03ce13f7SAndroid Build Coastguard Worker void TargetX8664::lowerShift64(InstArithmetic::OpKind Op, Operand *Src0Lo,
1444*03ce13f7SAndroid Build Coastguard Worker                                Operand *Src0Hi, Operand *Src1Lo,
1445*03ce13f7SAndroid Build Coastguard Worker                                Variable *DestLo, Variable *DestHi) {
1446*03ce13f7SAndroid Build Coastguard Worker   // TODO: Refactor the similarities between Shl, Lshr, and Ashr.
1447*03ce13f7SAndroid Build Coastguard Worker   Variable *T_1 = nullptr, *T_2 = nullptr, *T_3 = nullptr;
1448*03ce13f7SAndroid Build Coastguard Worker   Constant *Zero = Ctx->getConstantZero(IceType_i32);
1449*03ce13f7SAndroid Build Coastguard Worker   Constant *SignExtend = Ctx->getConstantInt32(0x1f);
1450*03ce13f7SAndroid Build Coastguard Worker   if (auto *ConstantShiftAmount = llvm::dyn_cast<ConstantInteger32>(Src1Lo)) {
1451*03ce13f7SAndroid Build Coastguard Worker     uint32_t ShiftAmount = ConstantShiftAmount->getValue();
1452*03ce13f7SAndroid Build Coastguard Worker     if (ShiftAmount > 32) {
1453*03ce13f7SAndroid Build Coastguard Worker       Constant *ReducedShift = Ctx->getConstantInt32(ShiftAmount - 32);
1454*03ce13f7SAndroid Build Coastguard Worker       switch (Op) {
1455*03ce13f7SAndroid Build Coastguard Worker       default:
1456*03ce13f7SAndroid Build Coastguard Worker         assert(0 && "non-shift op");
1457*03ce13f7SAndroid Build Coastguard Worker         break;
1458*03ce13f7SAndroid Build Coastguard Worker       case InstArithmetic::Shl: {
1459*03ce13f7SAndroid Build Coastguard Worker         // a=b<<c ==>
1460*03ce13f7SAndroid Build Coastguard Worker         //   t2 = b.lo
1461*03ce13f7SAndroid Build Coastguard Worker         //   t2 = shl t2, ShiftAmount-32
1462*03ce13f7SAndroid Build Coastguard Worker         //   t3 = t2
1463*03ce13f7SAndroid Build Coastguard Worker         //   t2 = 0
1464*03ce13f7SAndroid Build Coastguard Worker         _mov(T_2, Src0Lo);
1465*03ce13f7SAndroid Build Coastguard Worker         _shl(T_2, ReducedShift);
1466*03ce13f7SAndroid Build Coastguard Worker         _mov(DestHi, T_2);
1467*03ce13f7SAndroid Build Coastguard Worker         _mov(DestLo, Zero);
1468*03ce13f7SAndroid Build Coastguard Worker       } break;
1469*03ce13f7SAndroid Build Coastguard Worker       case InstArithmetic::Lshr: {
1470*03ce13f7SAndroid Build Coastguard Worker         // a=b>>c (unsigned) ==>
1471*03ce13f7SAndroid Build Coastguard Worker         //   t2 = b.hi
1472*03ce13f7SAndroid Build Coastguard Worker         //   t2 = shr t2, ShiftAmount-32
1473*03ce13f7SAndroid Build Coastguard Worker         //   a.lo = t2
1474*03ce13f7SAndroid Build Coastguard Worker         //   a.hi = 0
1475*03ce13f7SAndroid Build Coastguard Worker         _mov(T_2, Src0Hi);
1476*03ce13f7SAndroid Build Coastguard Worker         _shr(T_2, ReducedShift);
1477*03ce13f7SAndroid Build Coastguard Worker         _mov(DestLo, T_2);
1478*03ce13f7SAndroid Build Coastguard Worker         _mov(DestHi, Zero);
1479*03ce13f7SAndroid Build Coastguard Worker       } break;
1480*03ce13f7SAndroid Build Coastguard Worker       case InstArithmetic::Ashr: {
1481*03ce13f7SAndroid Build Coastguard Worker         // a=b>>c (signed) ==>
1482*03ce13f7SAndroid Build Coastguard Worker         //   t3 = b.hi
1483*03ce13f7SAndroid Build Coastguard Worker         //   t3 = sar t3, 0x1f
1484*03ce13f7SAndroid Build Coastguard Worker         //   t2 = b.hi
1485*03ce13f7SAndroid Build Coastguard Worker         //   t2 = shrd t2, t3, ShiftAmount-32
1486*03ce13f7SAndroid Build Coastguard Worker         //   a.lo = t2
1487*03ce13f7SAndroid Build Coastguard Worker         //   a.hi = t3
1488*03ce13f7SAndroid Build Coastguard Worker         _mov(T_3, Src0Hi);
1489*03ce13f7SAndroid Build Coastguard Worker         _sar(T_3, SignExtend);
1490*03ce13f7SAndroid Build Coastguard Worker         _mov(T_2, Src0Hi);
1491*03ce13f7SAndroid Build Coastguard Worker         _shrd(T_2, T_3, ReducedShift);
1492*03ce13f7SAndroid Build Coastguard Worker         _mov(DestLo, T_2);
1493*03ce13f7SAndroid Build Coastguard Worker         _mov(DestHi, T_3);
1494*03ce13f7SAndroid Build Coastguard Worker       } break;
1495*03ce13f7SAndroid Build Coastguard Worker       }
1496*03ce13f7SAndroid Build Coastguard Worker     } else if (ShiftAmount == 32) {
1497*03ce13f7SAndroid Build Coastguard Worker       switch (Op) {
1498*03ce13f7SAndroid Build Coastguard Worker       default:
1499*03ce13f7SAndroid Build Coastguard Worker         assert(0 && "non-shift op");
1500*03ce13f7SAndroid Build Coastguard Worker         break;
1501*03ce13f7SAndroid Build Coastguard Worker       case InstArithmetic::Shl: {
1502*03ce13f7SAndroid Build Coastguard Worker         // a=b<<c ==>
1503*03ce13f7SAndroid Build Coastguard Worker         //   t2 = b.lo
1504*03ce13f7SAndroid Build Coastguard Worker         //   a.hi = t2
1505*03ce13f7SAndroid Build Coastguard Worker         //   a.lo = 0
1506*03ce13f7SAndroid Build Coastguard Worker         _mov(T_2, Src0Lo);
1507*03ce13f7SAndroid Build Coastguard Worker         _mov(DestHi, T_2);
1508*03ce13f7SAndroid Build Coastguard Worker         _mov(DestLo, Zero);
1509*03ce13f7SAndroid Build Coastguard Worker       } break;
1510*03ce13f7SAndroid Build Coastguard Worker       case InstArithmetic::Lshr: {
1511*03ce13f7SAndroid Build Coastguard Worker         // a=b>>c (unsigned) ==>
1512*03ce13f7SAndroid Build Coastguard Worker         //   t2 = b.hi
1513*03ce13f7SAndroid Build Coastguard Worker         //   a.lo = t2
1514*03ce13f7SAndroid Build Coastguard Worker         //   a.hi = 0
1515*03ce13f7SAndroid Build Coastguard Worker         _mov(T_2, Src0Hi);
1516*03ce13f7SAndroid Build Coastguard Worker         _mov(DestLo, T_2);
1517*03ce13f7SAndroid Build Coastguard Worker         _mov(DestHi, Zero);
1518*03ce13f7SAndroid Build Coastguard Worker       } break;
1519*03ce13f7SAndroid Build Coastguard Worker       case InstArithmetic::Ashr: {
1520*03ce13f7SAndroid Build Coastguard Worker         // a=b>>c (signed) ==>
1521*03ce13f7SAndroid Build Coastguard Worker         //   t2 = b.hi
1522*03ce13f7SAndroid Build Coastguard Worker         //   a.lo = t2
1523*03ce13f7SAndroid Build Coastguard Worker         //   t3 = b.hi
1524*03ce13f7SAndroid Build Coastguard Worker         //   t3 = sar t3, 0x1f
1525*03ce13f7SAndroid Build Coastguard Worker         //   a.hi = t3
1526*03ce13f7SAndroid Build Coastguard Worker         _mov(T_2, Src0Hi);
1527*03ce13f7SAndroid Build Coastguard Worker         _mov(DestLo, T_2);
1528*03ce13f7SAndroid Build Coastguard Worker         _mov(T_3, Src0Hi);
1529*03ce13f7SAndroid Build Coastguard Worker         _sar(T_3, SignExtend);
1530*03ce13f7SAndroid Build Coastguard Worker         _mov(DestHi, T_3);
1531*03ce13f7SAndroid Build Coastguard Worker       } break;
1532*03ce13f7SAndroid Build Coastguard Worker       }
1533*03ce13f7SAndroid Build Coastguard Worker     } else {
1534*03ce13f7SAndroid Build Coastguard Worker       // COMMON PREFIX OF: a=b SHIFT_OP c ==>
1535*03ce13f7SAndroid Build Coastguard Worker       //   t2 = b.lo
1536*03ce13f7SAndroid Build Coastguard Worker       //   t3 = b.hi
1537*03ce13f7SAndroid Build Coastguard Worker       _mov(T_2, Src0Lo);
1538*03ce13f7SAndroid Build Coastguard Worker       _mov(T_3, Src0Hi);
1539*03ce13f7SAndroid Build Coastguard Worker       switch (Op) {
1540*03ce13f7SAndroid Build Coastguard Worker       default:
1541*03ce13f7SAndroid Build Coastguard Worker         assert(0 && "non-shift op");
1542*03ce13f7SAndroid Build Coastguard Worker         break;
1543*03ce13f7SAndroid Build Coastguard Worker       case InstArithmetic::Shl: {
1544*03ce13f7SAndroid Build Coastguard Worker         // a=b<<c ==>
1545*03ce13f7SAndroid Build Coastguard Worker         //   t3 = shld t3, t2, ShiftAmount
1546*03ce13f7SAndroid Build Coastguard Worker         //   t2 = shl t2, ShiftAmount
1547*03ce13f7SAndroid Build Coastguard Worker         _shld(T_3, T_2, ConstantShiftAmount);
1548*03ce13f7SAndroid Build Coastguard Worker         _shl(T_2, ConstantShiftAmount);
1549*03ce13f7SAndroid Build Coastguard Worker       } break;
1550*03ce13f7SAndroid Build Coastguard Worker       case InstArithmetic::Lshr: {
1551*03ce13f7SAndroid Build Coastguard Worker         // a=b>>c (unsigned) ==>
1552*03ce13f7SAndroid Build Coastguard Worker         //   t2 = shrd t2, t3, ShiftAmount
1553*03ce13f7SAndroid Build Coastguard Worker         //   t3 = shr t3, ShiftAmount
1554*03ce13f7SAndroid Build Coastguard Worker         _shrd(T_2, T_3, ConstantShiftAmount);
1555*03ce13f7SAndroid Build Coastguard Worker         _shr(T_3, ConstantShiftAmount);
1556*03ce13f7SAndroid Build Coastguard Worker       } break;
1557*03ce13f7SAndroid Build Coastguard Worker       case InstArithmetic::Ashr: {
1558*03ce13f7SAndroid Build Coastguard Worker         // a=b>>c (signed) ==>
1559*03ce13f7SAndroid Build Coastguard Worker         //   t2 = shrd t2, t3, ShiftAmount
1560*03ce13f7SAndroid Build Coastguard Worker         //   t3 = sar t3, ShiftAmount
1561*03ce13f7SAndroid Build Coastguard Worker         _shrd(T_2, T_3, ConstantShiftAmount);
1562*03ce13f7SAndroid Build Coastguard Worker         _sar(T_3, ConstantShiftAmount);
1563*03ce13f7SAndroid Build Coastguard Worker       } break;
1564*03ce13f7SAndroid Build Coastguard Worker       }
1565*03ce13f7SAndroid Build Coastguard Worker       // COMMON SUFFIX OF: a=b SHIFT_OP c ==>
1566*03ce13f7SAndroid Build Coastguard Worker       //   a.lo = t2
1567*03ce13f7SAndroid Build Coastguard Worker       //   a.hi = t3
1568*03ce13f7SAndroid Build Coastguard Worker       _mov(DestLo, T_2);
1569*03ce13f7SAndroid Build Coastguard Worker       _mov(DestHi, T_3);
1570*03ce13f7SAndroid Build Coastguard Worker     }
1571*03ce13f7SAndroid Build Coastguard Worker   } else {
1572*03ce13f7SAndroid Build Coastguard Worker     // NON-CONSTANT CASES.
1573*03ce13f7SAndroid Build Coastguard Worker     Constant *BitTest = Ctx->getConstantInt32(0x20);
1574*03ce13f7SAndroid Build Coastguard Worker     InstX86Label *Label = InstX86Label::create(Func, this);
1575*03ce13f7SAndroid Build Coastguard Worker     // COMMON PREFIX OF: a=b SHIFT_OP c ==>
1576*03ce13f7SAndroid Build Coastguard Worker     //   t1:ecx = c.lo & 0xff
1577*03ce13f7SAndroid Build Coastguard Worker     //   t2 = b.lo
1578*03ce13f7SAndroid Build Coastguard Worker     //   t3 = b.hi
1579*03ce13f7SAndroid Build Coastguard Worker     T_1 = copyToReg8(Src1Lo, RegX8664::Reg_cl);
1580*03ce13f7SAndroid Build Coastguard Worker     _mov(T_2, Src0Lo);
1581*03ce13f7SAndroid Build Coastguard Worker     _mov(T_3, Src0Hi);
1582*03ce13f7SAndroid Build Coastguard Worker     switch (Op) {
1583*03ce13f7SAndroid Build Coastguard Worker     default:
1584*03ce13f7SAndroid Build Coastguard Worker       assert(0 && "non-shift op");
1585*03ce13f7SAndroid Build Coastguard Worker       break;
1586*03ce13f7SAndroid Build Coastguard Worker     case InstArithmetic::Shl: {
1587*03ce13f7SAndroid Build Coastguard Worker       // a=b<<c ==>
1588*03ce13f7SAndroid Build Coastguard Worker       //   t3 = shld t3, t2, t1
1589*03ce13f7SAndroid Build Coastguard Worker       //   t2 = shl t2, t1
1590*03ce13f7SAndroid Build Coastguard Worker       //   test t1, 0x20
1591*03ce13f7SAndroid Build Coastguard Worker       //   je L1
1592*03ce13f7SAndroid Build Coastguard Worker       //   use(t3)
1593*03ce13f7SAndroid Build Coastguard Worker       //   t3 = t2
1594*03ce13f7SAndroid Build Coastguard Worker       //   t2 = 0
1595*03ce13f7SAndroid Build Coastguard Worker       _shld(T_3, T_2, T_1);
1596*03ce13f7SAndroid Build Coastguard Worker       _shl(T_2, T_1);
1597*03ce13f7SAndroid Build Coastguard Worker       _test(T_1, BitTest);
1598*03ce13f7SAndroid Build Coastguard Worker       _br(CondX86::Br_e, Label);
1599*03ce13f7SAndroid Build Coastguard Worker       // T_2 and T_3 are being assigned again because of the intra-block control
1600*03ce13f7SAndroid Build Coastguard Worker       // flow, so we need to use _redefined to avoid liveness problems.
1601*03ce13f7SAndroid Build Coastguard Worker       _redefined(_mov(T_3, T_2));
1602*03ce13f7SAndroid Build Coastguard Worker       _redefined(_mov(T_2, Zero));
1603*03ce13f7SAndroid Build Coastguard Worker     } break;
1604*03ce13f7SAndroid Build Coastguard Worker     case InstArithmetic::Lshr: {
1605*03ce13f7SAndroid Build Coastguard Worker       // a=b>>c (unsigned) ==>
1606*03ce13f7SAndroid Build Coastguard Worker       //   t2 = shrd t2, t3, t1
1607*03ce13f7SAndroid Build Coastguard Worker       //   t3 = shr t3, t1
1608*03ce13f7SAndroid Build Coastguard Worker       //   test t1, 0x20
1609*03ce13f7SAndroid Build Coastguard Worker       //   je L1
1610*03ce13f7SAndroid Build Coastguard Worker       //   use(t2)
1611*03ce13f7SAndroid Build Coastguard Worker       //   t2 = t3
1612*03ce13f7SAndroid Build Coastguard Worker       //   t3 = 0
1613*03ce13f7SAndroid Build Coastguard Worker       _shrd(T_2, T_3, T_1);
1614*03ce13f7SAndroid Build Coastguard Worker       _shr(T_3, T_1);
1615*03ce13f7SAndroid Build Coastguard Worker       _test(T_1, BitTest);
1616*03ce13f7SAndroid Build Coastguard Worker       _br(CondX86::Br_e, Label);
1617*03ce13f7SAndroid Build Coastguard Worker       // T_2 and T_3 are being assigned again because of the intra-block control
1618*03ce13f7SAndroid Build Coastguard Worker       // flow, so we need to use _redefined to avoid liveness problems.
1619*03ce13f7SAndroid Build Coastguard Worker       _redefined(_mov(T_2, T_3));
1620*03ce13f7SAndroid Build Coastguard Worker       _redefined(_mov(T_3, Zero));
1621*03ce13f7SAndroid Build Coastguard Worker     } break;
1622*03ce13f7SAndroid Build Coastguard Worker     case InstArithmetic::Ashr: {
1623*03ce13f7SAndroid Build Coastguard Worker       // a=b>>c (signed) ==>
1624*03ce13f7SAndroid Build Coastguard Worker       //   t2 = shrd t2, t3, t1
1625*03ce13f7SAndroid Build Coastguard Worker       //   t3 = sar t3, t1
1626*03ce13f7SAndroid Build Coastguard Worker       //   test t1, 0x20
1627*03ce13f7SAndroid Build Coastguard Worker       //   je L1
1628*03ce13f7SAndroid Build Coastguard Worker       //   use(t2)
1629*03ce13f7SAndroid Build Coastguard Worker       //   t2 = t3
1630*03ce13f7SAndroid Build Coastguard Worker       //   t3 = sar t3, 0x1f
1631*03ce13f7SAndroid Build Coastguard Worker       Constant *SignExtend = Ctx->getConstantInt32(0x1f);
1632*03ce13f7SAndroid Build Coastguard Worker       _shrd(T_2, T_3, T_1);
1633*03ce13f7SAndroid Build Coastguard Worker       _sar(T_3, T_1);
1634*03ce13f7SAndroid Build Coastguard Worker       _test(T_1, BitTest);
1635*03ce13f7SAndroid Build Coastguard Worker       _br(CondX86::Br_e, Label);
1636*03ce13f7SAndroid Build Coastguard Worker       // T_2 and T_3 are being assigned again because of the intra-block control
1637*03ce13f7SAndroid Build Coastguard Worker       // flow, so T_2 needs to use _redefined to avoid liveness problems. T_3
1638*03ce13f7SAndroid Build Coastguard Worker       // doesn't need special treatment because it is reassigned via _sar
1639*03ce13f7SAndroid Build Coastguard Worker       // instead of _mov.
1640*03ce13f7SAndroid Build Coastguard Worker       _redefined(_mov(T_2, T_3));
1641*03ce13f7SAndroid Build Coastguard Worker       _sar(T_3, SignExtend);
1642*03ce13f7SAndroid Build Coastguard Worker     } break;
1643*03ce13f7SAndroid Build Coastguard Worker     }
1644*03ce13f7SAndroid Build Coastguard Worker     // COMMON SUFFIX OF: a=b SHIFT_OP c ==>
1645*03ce13f7SAndroid Build Coastguard Worker     // L1:
1646*03ce13f7SAndroid Build Coastguard Worker     //   a.lo = t2
1647*03ce13f7SAndroid Build Coastguard Worker     //   a.hi = t3
1648*03ce13f7SAndroid Build Coastguard Worker     Context.insert(Label);
1649*03ce13f7SAndroid Build Coastguard Worker     _mov(DestLo, T_2);
1650*03ce13f7SAndroid Build Coastguard Worker     _mov(DestHi, T_3);
1651*03ce13f7SAndroid Build Coastguard Worker   }
1652*03ce13f7SAndroid Build Coastguard Worker }
1653*03ce13f7SAndroid Build Coastguard Worker 
lowerArithmetic(const InstArithmetic * Instr)1654*03ce13f7SAndroid Build Coastguard Worker void TargetX8664::lowerArithmetic(const InstArithmetic *Instr) {
1655*03ce13f7SAndroid Build Coastguard Worker   Variable *Dest = Instr->getDest();
1656*03ce13f7SAndroid Build Coastguard Worker   if (Dest->isRematerializable()) {
1657*03ce13f7SAndroid Build Coastguard Worker     Context.insert<InstFakeDef>(Dest);
1658*03ce13f7SAndroid Build Coastguard Worker     return;
1659*03ce13f7SAndroid Build Coastguard Worker   }
1660*03ce13f7SAndroid Build Coastguard Worker   Type Ty = Dest->getType();
1661*03ce13f7SAndroid Build Coastguard Worker   Operand *Src0 = legalize(Instr->getSrc(0));
1662*03ce13f7SAndroid Build Coastguard Worker   Operand *Src1 = legalize(Instr->getSrc(1));
1663*03ce13f7SAndroid Build Coastguard Worker   if (Instr->isCommutative()) {
1664*03ce13f7SAndroid Build Coastguard Worker     uint32_t SwapCount = 0;
1665*03ce13f7SAndroid Build Coastguard Worker     if (!llvm::isa<Variable>(Src0) && llvm::isa<Variable>(Src1)) {
1666*03ce13f7SAndroid Build Coastguard Worker       std::swap(Src0, Src1);
1667*03ce13f7SAndroid Build Coastguard Worker       ++SwapCount;
1668*03ce13f7SAndroid Build Coastguard Worker     }
1669*03ce13f7SAndroid Build Coastguard Worker     if (llvm::isa<Constant>(Src0) && !llvm::isa<Constant>(Src1)) {
1670*03ce13f7SAndroid Build Coastguard Worker       std::swap(Src0, Src1);
1671*03ce13f7SAndroid Build Coastguard Worker       ++SwapCount;
1672*03ce13f7SAndroid Build Coastguard Worker     }
1673*03ce13f7SAndroid Build Coastguard Worker     // Improve two-address code patterns by avoiding a copy to the dest
1674*03ce13f7SAndroid Build Coastguard Worker     // register when one of the source operands ends its lifetime here.
1675*03ce13f7SAndroid Build Coastguard Worker     if (!Instr->isLastUse(Src0) && Instr->isLastUse(Src1)) {
1676*03ce13f7SAndroid Build Coastguard Worker       std::swap(Src0, Src1);
1677*03ce13f7SAndroid Build Coastguard Worker       ++SwapCount;
1678*03ce13f7SAndroid Build Coastguard Worker     }
1679*03ce13f7SAndroid Build Coastguard Worker     assert(SwapCount <= 1);
1680*03ce13f7SAndroid Build Coastguard Worker     (void)SwapCount;
1681*03ce13f7SAndroid Build Coastguard Worker   }
1682*03ce13f7SAndroid Build Coastguard Worker   if (isVectorType(Ty)) {
1683*03ce13f7SAndroid Build Coastguard Worker     // TODO: Trap on integer divide and integer modulo by zero. See:
1684*03ce13f7SAndroid Build Coastguard Worker     // https://code.google.com/p/nativeclient/issues/detail?id=3899
1685*03ce13f7SAndroid Build Coastguard Worker     if (llvm::isa<X86OperandMem>(Src1))
1686*03ce13f7SAndroid Build Coastguard Worker       Src1 = legalizeToReg(Src1);
1687*03ce13f7SAndroid Build Coastguard Worker     switch (Instr->getOp()) {
1688*03ce13f7SAndroid Build Coastguard Worker     case InstArithmetic::_num:
1689*03ce13f7SAndroid Build Coastguard Worker       llvm_unreachable("Unknown arithmetic operator");
1690*03ce13f7SAndroid Build Coastguard Worker       break;
1691*03ce13f7SAndroid Build Coastguard Worker     case InstArithmetic::Add: {
1692*03ce13f7SAndroid Build Coastguard Worker       Variable *T = makeReg(Ty);
1693*03ce13f7SAndroid Build Coastguard Worker       _movp(T, Src0);
1694*03ce13f7SAndroid Build Coastguard Worker       _padd(T, Src1);
1695*03ce13f7SAndroid Build Coastguard Worker       _movp(Dest, T);
1696*03ce13f7SAndroid Build Coastguard Worker     } break;
1697*03ce13f7SAndroid Build Coastguard Worker     case InstArithmetic::And: {
1698*03ce13f7SAndroid Build Coastguard Worker       Variable *T = makeReg(Ty);
1699*03ce13f7SAndroid Build Coastguard Worker       _movp(T, Src0);
1700*03ce13f7SAndroid Build Coastguard Worker       _pand(T, Src1);
1701*03ce13f7SAndroid Build Coastguard Worker       _movp(Dest, T);
1702*03ce13f7SAndroid Build Coastguard Worker     } break;
1703*03ce13f7SAndroid Build Coastguard Worker     case InstArithmetic::Or: {
1704*03ce13f7SAndroid Build Coastguard Worker       Variable *T = makeReg(Ty);
1705*03ce13f7SAndroid Build Coastguard Worker       _movp(T, Src0);
1706*03ce13f7SAndroid Build Coastguard Worker       _por(T, Src1);
1707*03ce13f7SAndroid Build Coastguard Worker       _movp(Dest, T);
1708*03ce13f7SAndroid Build Coastguard Worker     } break;
1709*03ce13f7SAndroid Build Coastguard Worker     case InstArithmetic::Xor: {
1710*03ce13f7SAndroid Build Coastguard Worker       Variable *T = makeReg(Ty);
1711*03ce13f7SAndroid Build Coastguard Worker       _movp(T, Src0);
1712*03ce13f7SAndroid Build Coastguard Worker       _pxor(T, Src1);
1713*03ce13f7SAndroid Build Coastguard Worker       _movp(Dest, T);
1714*03ce13f7SAndroid Build Coastguard Worker     } break;
1715*03ce13f7SAndroid Build Coastguard Worker     case InstArithmetic::Sub: {
1716*03ce13f7SAndroid Build Coastguard Worker       Variable *T = makeReg(Ty);
1717*03ce13f7SAndroid Build Coastguard Worker       _movp(T, Src0);
1718*03ce13f7SAndroid Build Coastguard Worker       _psub(T, Src1);
1719*03ce13f7SAndroid Build Coastguard Worker       _movp(Dest, T);
1720*03ce13f7SAndroid Build Coastguard Worker     } break;
1721*03ce13f7SAndroid Build Coastguard Worker     case InstArithmetic::Mul: {
1722*03ce13f7SAndroid Build Coastguard Worker       bool TypesAreValidForPmull = Ty == IceType_v4i32 || Ty == IceType_v8i16;
1723*03ce13f7SAndroid Build Coastguard Worker       bool InstructionSetIsValidForPmull =
1724*03ce13f7SAndroid Build Coastguard Worker           Ty == IceType_v8i16 || InstructionSet >= SSE4_1;
1725*03ce13f7SAndroid Build Coastguard Worker       if (TypesAreValidForPmull && InstructionSetIsValidForPmull) {
1726*03ce13f7SAndroid Build Coastguard Worker         Variable *T = makeReg(Ty);
1727*03ce13f7SAndroid Build Coastguard Worker         _movp(T, Src0);
1728*03ce13f7SAndroid Build Coastguard Worker         _pmull(T, Src0 == Src1 ? T : Src1);
1729*03ce13f7SAndroid Build Coastguard Worker         _movp(Dest, T);
1730*03ce13f7SAndroid Build Coastguard Worker       } else if (Ty == IceType_v4i32) {
1731*03ce13f7SAndroid Build Coastguard Worker         // Lowering sequence:
1732*03ce13f7SAndroid Build Coastguard Worker         // Note: The mask arguments have index 0 on the left.
1733*03ce13f7SAndroid Build Coastguard Worker         //
1734*03ce13f7SAndroid Build Coastguard Worker         // movups  T1, Src0
1735*03ce13f7SAndroid Build Coastguard Worker         // pshufd  T2, Src0, {1,0,3,0}
1736*03ce13f7SAndroid Build Coastguard Worker         // pshufd  T3, Src1, {1,0,3,0}
1737*03ce13f7SAndroid Build Coastguard Worker         // # T1 = {Src0[0] * Src1[0], Src0[2] * Src1[2]}
1738*03ce13f7SAndroid Build Coastguard Worker         // pmuludq T1, Src1
1739*03ce13f7SAndroid Build Coastguard Worker         // # T2 = {Src0[1] * Src1[1], Src0[3] * Src1[3]}
1740*03ce13f7SAndroid Build Coastguard Worker         // pmuludq T2, T3
1741*03ce13f7SAndroid Build Coastguard Worker         // # T1 = {lo(T1[0]), lo(T1[2]), lo(T2[0]), lo(T2[2])}
1742*03ce13f7SAndroid Build Coastguard Worker         // shufps  T1, T2, {0,2,0,2}
1743*03ce13f7SAndroid Build Coastguard Worker         // pshufd  T4, T1, {0,2,1,3}
1744*03ce13f7SAndroid Build Coastguard Worker         // movups  Dest, T4
1745*03ce13f7SAndroid Build Coastguard Worker 
1746*03ce13f7SAndroid Build Coastguard Worker         // Mask that directs pshufd to create a vector with entries
1747*03ce13f7SAndroid Build Coastguard Worker         // Src[1, 0, 3, 0]
1748*03ce13f7SAndroid Build Coastguard Worker         constexpr unsigned Constant1030 = 0x31;
1749*03ce13f7SAndroid Build Coastguard Worker         Constant *Mask1030 = Ctx->getConstantInt32(Constant1030);
1750*03ce13f7SAndroid Build Coastguard Worker         // Mask that directs shufps to create a vector with entries
1751*03ce13f7SAndroid Build Coastguard Worker         // Dest[0, 2], Src[0, 2]
1752*03ce13f7SAndroid Build Coastguard Worker         constexpr unsigned Mask0202 = 0x88;
1753*03ce13f7SAndroid Build Coastguard Worker         // Mask that directs pshufd to create a vector with entries
1754*03ce13f7SAndroid Build Coastguard Worker         // Src[0, 2, 1, 3]
1755*03ce13f7SAndroid Build Coastguard Worker         constexpr unsigned Mask0213 = 0xd8;
1756*03ce13f7SAndroid Build Coastguard Worker         Variable *T1 = makeReg(IceType_v4i32);
1757*03ce13f7SAndroid Build Coastguard Worker         Variable *T2 = makeReg(IceType_v4i32);
1758*03ce13f7SAndroid Build Coastguard Worker         Variable *T3 = makeReg(IceType_v4i32);
1759*03ce13f7SAndroid Build Coastguard Worker         Variable *T4 = makeReg(IceType_v4i32);
1760*03ce13f7SAndroid Build Coastguard Worker         _movp(T1, Src0);
1761*03ce13f7SAndroid Build Coastguard Worker         _pshufd(T2, Src0, Mask1030);
1762*03ce13f7SAndroid Build Coastguard Worker         _pshufd(T3, Src1, Mask1030);
1763*03ce13f7SAndroid Build Coastguard Worker         _pmuludq(T1, Src1);
1764*03ce13f7SAndroid Build Coastguard Worker         _pmuludq(T2, T3);
1765*03ce13f7SAndroid Build Coastguard Worker         _shufps(T1, T2, Ctx->getConstantInt32(Mask0202));
1766*03ce13f7SAndroid Build Coastguard Worker         _pshufd(T4, T1, Ctx->getConstantInt32(Mask0213));
1767*03ce13f7SAndroid Build Coastguard Worker         _movp(Dest, T4);
1768*03ce13f7SAndroid Build Coastguard Worker       } else if (Ty == IceType_v16i8) {
1769*03ce13f7SAndroid Build Coastguard Worker         llvm::report_fatal_error("Scalarized operation was expected");
1770*03ce13f7SAndroid Build Coastguard Worker       } else {
1771*03ce13f7SAndroid Build Coastguard Worker         llvm::report_fatal_error("Invalid vector multiply type");
1772*03ce13f7SAndroid Build Coastguard Worker       }
1773*03ce13f7SAndroid Build Coastguard Worker     } break;
1774*03ce13f7SAndroid Build Coastguard Worker     case InstArithmetic::Shl: {
1775*03ce13f7SAndroid Build Coastguard Worker       assert(llvm::isa<Constant>(Src1) && "Non-constant shift not scalarized");
1776*03ce13f7SAndroid Build Coastguard Worker       Variable *T = makeReg(Ty);
1777*03ce13f7SAndroid Build Coastguard Worker       _movp(T, Src0);
1778*03ce13f7SAndroid Build Coastguard Worker       _psll(T, Src1);
1779*03ce13f7SAndroid Build Coastguard Worker       _movp(Dest, T);
1780*03ce13f7SAndroid Build Coastguard Worker     } break;
1781*03ce13f7SAndroid Build Coastguard Worker     case InstArithmetic::Lshr: {
1782*03ce13f7SAndroid Build Coastguard Worker       assert(llvm::isa<Constant>(Src1) && "Non-constant shift not scalarized");
1783*03ce13f7SAndroid Build Coastguard Worker       Variable *T = makeReg(Ty);
1784*03ce13f7SAndroid Build Coastguard Worker       _movp(T, Src0);
1785*03ce13f7SAndroid Build Coastguard Worker       _psrl(T, Src1);
1786*03ce13f7SAndroid Build Coastguard Worker       _movp(Dest, T);
1787*03ce13f7SAndroid Build Coastguard Worker     } break;
1788*03ce13f7SAndroid Build Coastguard Worker     case InstArithmetic::Ashr: {
1789*03ce13f7SAndroid Build Coastguard Worker       assert(llvm::isa<Constant>(Src1) && "Non-constant shift not scalarized");
1790*03ce13f7SAndroid Build Coastguard Worker       Variable *T = makeReg(Ty);
1791*03ce13f7SAndroid Build Coastguard Worker       _movp(T, Src0);
1792*03ce13f7SAndroid Build Coastguard Worker       _psra(T, Src1);
1793*03ce13f7SAndroid Build Coastguard Worker       _movp(Dest, T);
1794*03ce13f7SAndroid Build Coastguard Worker     } break;
1795*03ce13f7SAndroid Build Coastguard Worker     case InstArithmetic::Udiv:
1796*03ce13f7SAndroid Build Coastguard Worker     case InstArithmetic::Urem:
1797*03ce13f7SAndroid Build Coastguard Worker     case InstArithmetic::Sdiv:
1798*03ce13f7SAndroid Build Coastguard Worker     case InstArithmetic::Srem:
1799*03ce13f7SAndroid Build Coastguard Worker       llvm::report_fatal_error("Scalarized operation was expected");
1800*03ce13f7SAndroid Build Coastguard Worker       break;
1801*03ce13f7SAndroid Build Coastguard Worker     case InstArithmetic::Fadd: {
1802*03ce13f7SAndroid Build Coastguard Worker       Variable *T = makeReg(Ty);
1803*03ce13f7SAndroid Build Coastguard Worker       _movp(T, Src0);
1804*03ce13f7SAndroid Build Coastguard Worker       _addps(T, Src1);
1805*03ce13f7SAndroid Build Coastguard Worker       _movp(Dest, T);
1806*03ce13f7SAndroid Build Coastguard Worker     } break;
1807*03ce13f7SAndroid Build Coastguard Worker     case InstArithmetic::Fsub: {
1808*03ce13f7SAndroid Build Coastguard Worker       Variable *T = makeReg(Ty);
1809*03ce13f7SAndroid Build Coastguard Worker       _movp(T, Src0);
1810*03ce13f7SAndroid Build Coastguard Worker       _subps(T, Src1);
1811*03ce13f7SAndroid Build Coastguard Worker       _movp(Dest, T);
1812*03ce13f7SAndroid Build Coastguard Worker     } break;
1813*03ce13f7SAndroid Build Coastguard Worker     case InstArithmetic::Fmul: {
1814*03ce13f7SAndroid Build Coastguard Worker       Variable *T = makeReg(Ty);
1815*03ce13f7SAndroid Build Coastguard Worker       _movp(T, Src0);
1816*03ce13f7SAndroid Build Coastguard Worker       _mulps(T, Src0 == Src1 ? T : Src1);
1817*03ce13f7SAndroid Build Coastguard Worker       _movp(Dest, T);
1818*03ce13f7SAndroid Build Coastguard Worker     } break;
1819*03ce13f7SAndroid Build Coastguard Worker     case InstArithmetic::Fdiv: {
1820*03ce13f7SAndroid Build Coastguard Worker       Variable *T = makeReg(Ty);
1821*03ce13f7SAndroid Build Coastguard Worker       _movp(T, Src0);
1822*03ce13f7SAndroid Build Coastguard Worker       _divps(T, Src1);
1823*03ce13f7SAndroid Build Coastguard Worker       _movp(Dest, T);
1824*03ce13f7SAndroid Build Coastguard Worker     } break;
1825*03ce13f7SAndroid Build Coastguard Worker     case InstArithmetic::Frem:
1826*03ce13f7SAndroid Build Coastguard Worker       llvm::report_fatal_error("Scalarized operation was expected");
1827*03ce13f7SAndroid Build Coastguard Worker       break;
1828*03ce13f7SAndroid Build Coastguard Worker     }
1829*03ce13f7SAndroid Build Coastguard Worker     return;
1830*03ce13f7SAndroid Build Coastguard Worker   }
1831*03ce13f7SAndroid Build Coastguard Worker   Variable *T_edx = nullptr;
1832*03ce13f7SAndroid Build Coastguard Worker   Variable *T = nullptr;
1833*03ce13f7SAndroid Build Coastguard Worker   switch (Instr->getOp()) {
1834*03ce13f7SAndroid Build Coastguard Worker   case InstArithmetic::_num:
1835*03ce13f7SAndroid Build Coastguard Worker     llvm_unreachable("Unknown arithmetic operator");
1836*03ce13f7SAndroid Build Coastguard Worker     break;
1837*03ce13f7SAndroid Build Coastguard Worker   case InstArithmetic::Add: {
1838*03ce13f7SAndroid Build Coastguard Worker     const bool ValidType = Ty == IceType_i32 || Ty == IceType_i64;
1839*03ce13f7SAndroid Build Coastguard Worker     auto *Const = llvm::dyn_cast<Constant>(Instr->getSrc(1));
1840*03ce13f7SAndroid Build Coastguard Worker     const bool ValidKind =
1841*03ce13f7SAndroid Build Coastguard Worker         Const != nullptr && (llvm::isa<ConstantInteger32>(Const) ||
1842*03ce13f7SAndroid Build Coastguard Worker                              llvm::isa<ConstantRelocatable>(Const));
1843*03ce13f7SAndroid Build Coastguard Worker     if (getFlags().getAggressiveLea() && ValidType && ValidKind) {
1844*03ce13f7SAndroid Build Coastguard Worker       auto *Var = legalizeToReg(Src0);
1845*03ce13f7SAndroid Build Coastguard Worker       auto *Mem = X86OperandMem::create(Func, IceType_void, Var, Const);
1846*03ce13f7SAndroid Build Coastguard Worker       T = makeReg(Ty);
1847*03ce13f7SAndroid Build Coastguard Worker       _lea(T, Mem);
1848*03ce13f7SAndroid Build Coastguard Worker       _mov(Dest, T);
1849*03ce13f7SAndroid Build Coastguard Worker       break;
1850*03ce13f7SAndroid Build Coastguard Worker     }
1851*03ce13f7SAndroid Build Coastguard Worker     _mov(T, Src0);
1852*03ce13f7SAndroid Build Coastguard Worker     _add(T, Src1);
1853*03ce13f7SAndroid Build Coastguard Worker     _mov(Dest, T);
1854*03ce13f7SAndroid Build Coastguard Worker   } break;
1855*03ce13f7SAndroid Build Coastguard Worker   case InstArithmetic::And:
1856*03ce13f7SAndroid Build Coastguard Worker     _mov(T, Src0);
1857*03ce13f7SAndroid Build Coastguard Worker     _and(T, Src1);
1858*03ce13f7SAndroid Build Coastguard Worker     _mov(Dest, T);
1859*03ce13f7SAndroid Build Coastguard Worker     break;
1860*03ce13f7SAndroid Build Coastguard Worker   case InstArithmetic::Or:
1861*03ce13f7SAndroid Build Coastguard Worker     _mov(T, Src0);
1862*03ce13f7SAndroid Build Coastguard Worker     _or(T, Src1);
1863*03ce13f7SAndroid Build Coastguard Worker     _mov(Dest, T);
1864*03ce13f7SAndroid Build Coastguard Worker     break;
1865*03ce13f7SAndroid Build Coastguard Worker   case InstArithmetic::Xor:
1866*03ce13f7SAndroid Build Coastguard Worker     _mov(T, Src0);
1867*03ce13f7SAndroid Build Coastguard Worker     _xor(T, Src1);
1868*03ce13f7SAndroid Build Coastguard Worker     _mov(Dest, T);
1869*03ce13f7SAndroid Build Coastguard Worker     break;
1870*03ce13f7SAndroid Build Coastguard Worker   case InstArithmetic::Sub:
1871*03ce13f7SAndroid Build Coastguard Worker     _mov(T, Src0);
1872*03ce13f7SAndroid Build Coastguard Worker     _sub(T, Src1);
1873*03ce13f7SAndroid Build Coastguard Worker     _mov(Dest, T);
1874*03ce13f7SAndroid Build Coastguard Worker     break;
1875*03ce13f7SAndroid Build Coastguard Worker   case InstArithmetic::Mul:
1876*03ce13f7SAndroid Build Coastguard Worker     if (auto *C = llvm::dyn_cast<ConstantInteger32>(Src1)) {
1877*03ce13f7SAndroid Build Coastguard Worker       if (optimizeScalarMul(Dest, Src0, C->getValue()))
1878*03ce13f7SAndroid Build Coastguard Worker         return;
1879*03ce13f7SAndroid Build Coastguard Worker     }
1880*03ce13f7SAndroid Build Coastguard Worker     // The 8-bit version of imul only allows the form "imul r/m8" where T must
1881*03ce13f7SAndroid Build Coastguard Worker     // be in al.
1882*03ce13f7SAndroid Build Coastguard Worker     if (isByteSizedArithType(Ty)) {
1883*03ce13f7SAndroid Build Coastguard Worker       _mov(T, Src0, RegX8664::Reg_al);
1884*03ce13f7SAndroid Build Coastguard Worker       Src1 = legalize(Src1, Legal_Reg | Legal_Mem);
1885*03ce13f7SAndroid Build Coastguard Worker       _imul(T, Src0 == Src1 ? T : Src1);
1886*03ce13f7SAndroid Build Coastguard Worker       _mov(Dest, T);
1887*03ce13f7SAndroid Build Coastguard Worker     } else if (auto *ImmConst = llvm::dyn_cast<ConstantInteger32>(Src1)) {
1888*03ce13f7SAndroid Build Coastguard Worker       T = makeReg(Ty);
1889*03ce13f7SAndroid Build Coastguard Worker       Src0 = legalize(Src0, Legal_Reg | Legal_Mem);
1890*03ce13f7SAndroid Build Coastguard Worker       _imul_imm(T, Src0, ImmConst);
1891*03ce13f7SAndroid Build Coastguard Worker       _mov(Dest, T);
1892*03ce13f7SAndroid Build Coastguard Worker     } else {
1893*03ce13f7SAndroid Build Coastguard Worker       _mov(T, Src0);
1894*03ce13f7SAndroid Build Coastguard Worker       // No need to legalize Src1 to Reg | Mem because the Imm case is handled
1895*03ce13f7SAndroid Build Coastguard Worker       // already by the ConstantInteger32 case above.
1896*03ce13f7SAndroid Build Coastguard Worker       _imul(T, Src0 == Src1 ? T : Src1);
1897*03ce13f7SAndroid Build Coastguard Worker       _mov(Dest, T);
1898*03ce13f7SAndroid Build Coastguard Worker     }
1899*03ce13f7SAndroid Build Coastguard Worker     break;
1900*03ce13f7SAndroid Build Coastguard Worker   case InstArithmetic::Shl:
1901*03ce13f7SAndroid Build Coastguard Worker     _mov(T, Src0);
1902*03ce13f7SAndroid Build Coastguard Worker     if (!llvm::isa<ConstantInteger32>(Src1) &&
1903*03ce13f7SAndroid Build Coastguard Worker         !llvm::isa<ConstantInteger64>(Src1))
1904*03ce13f7SAndroid Build Coastguard Worker       Src1 = copyToReg8(Src1, RegX8664::Reg_cl);
1905*03ce13f7SAndroid Build Coastguard Worker     _shl(T, Src1);
1906*03ce13f7SAndroid Build Coastguard Worker     _mov(Dest, T);
1907*03ce13f7SAndroid Build Coastguard Worker     break;
1908*03ce13f7SAndroid Build Coastguard Worker   case InstArithmetic::Lshr:
1909*03ce13f7SAndroid Build Coastguard Worker     _mov(T, Src0);
1910*03ce13f7SAndroid Build Coastguard Worker     if (!llvm::isa<ConstantInteger32>(Src1) &&
1911*03ce13f7SAndroid Build Coastguard Worker         !llvm::isa<ConstantInteger64>(Src1))
1912*03ce13f7SAndroid Build Coastguard Worker       Src1 = copyToReg8(Src1, RegX8664::Reg_cl);
1913*03ce13f7SAndroid Build Coastguard Worker     _shr(T, Src1);
1914*03ce13f7SAndroid Build Coastguard Worker     _mov(Dest, T);
1915*03ce13f7SAndroid Build Coastguard Worker     break;
1916*03ce13f7SAndroid Build Coastguard Worker   case InstArithmetic::Ashr:
1917*03ce13f7SAndroid Build Coastguard Worker     _mov(T, Src0);
1918*03ce13f7SAndroid Build Coastguard Worker     if (!llvm::isa<ConstantInteger32>(Src1) &&
1919*03ce13f7SAndroid Build Coastguard Worker         !llvm::isa<ConstantInteger64>(Src1))
1920*03ce13f7SAndroid Build Coastguard Worker       Src1 = copyToReg8(Src1, RegX8664::Reg_cl);
1921*03ce13f7SAndroid Build Coastguard Worker     _sar(T, Src1);
1922*03ce13f7SAndroid Build Coastguard Worker     _mov(Dest, T);
1923*03ce13f7SAndroid Build Coastguard Worker     break;
1924*03ce13f7SAndroid Build Coastguard Worker   case InstArithmetic::Udiv: {
1925*03ce13f7SAndroid Build Coastguard Worker     // div and idiv are the few arithmetic operators that do not allow
1926*03ce13f7SAndroid Build Coastguard Worker     // immediates as the operand.
1927*03ce13f7SAndroid Build Coastguard Worker     Src1 = legalize(Src1, Legal_Reg | Legal_Mem);
1928*03ce13f7SAndroid Build Coastguard Worker     RegNumT Eax;
1929*03ce13f7SAndroid Build Coastguard Worker     RegNumT Edx;
1930*03ce13f7SAndroid Build Coastguard Worker     switch (Ty) {
1931*03ce13f7SAndroid Build Coastguard Worker     default:
1932*03ce13f7SAndroid Build Coastguard Worker       llvm::report_fatal_error("Bad type for udiv");
1933*03ce13f7SAndroid Build Coastguard Worker     case IceType_i64:
1934*03ce13f7SAndroid Build Coastguard Worker       Eax = RegX8664::Reg_rax;
1935*03ce13f7SAndroid Build Coastguard Worker       Edx = RegX8664::Reg_rdx;
1936*03ce13f7SAndroid Build Coastguard Worker       break;
1937*03ce13f7SAndroid Build Coastguard Worker     case IceType_i32:
1938*03ce13f7SAndroid Build Coastguard Worker       Eax = RegX8664::Reg_eax;
1939*03ce13f7SAndroid Build Coastguard Worker       Edx = RegX8664::Reg_edx;
1940*03ce13f7SAndroid Build Coastguard Worker       break;
1941*03ce13f7SAndroid Build Coastguard Worker     case IceType_i16:
1942*03ce13f7SAndroid Build Coastguard Worker       Eax = RegX8664::Reg_ax;
1943*03ce13f7SAndroid Build Coastguard Worker       Edx = RegX8664::Reg_dx;
1944*03ce13f7SAndroid Build Coastguard Worker       break;
1945*03ce13f7SAndroid Build Coastguard Worker     case IceType_i8:
1946*03ce13f7SAndroid Build Coastguard Worker       Eax = RegX8664::Reg_al;
1947*03ce13f7SAndroid Build Coastguard Worker       Edx = RegX8664::Reg_ah;
1948*03ce13f7SAndroid Build Coastguard Worker       break;
1949*03ce13f7SAndroid Build Coastguard Worker     }
1950*03ce13f7SAndroid Build Coastguard Worker     T_edx = makeReg(Ty, Edx);
1951*03ce13f7SAndroid Build Coastguard Worker     _mov(T, Src0, Eax);
1952*03ce13f7SAndroid Build Coastguard Worker     _mov(T_edx, Ctx->getConstantZero(Ty));
1953*03ce13f7SAndroid Build Coastguard Worker     _div(T_edx, Src1, T);
1954*03ce13f7SAndroid Build Coastguard Worker     _redefined(Context.insert<InstFakeDef>(T, T_edx));
1955*03ce13f7SAndroid Build Coastguard Worker     _mov(Dest, T);
1956*03ce13f7SAndroid Build Coastguard Worker   } break;
1957*03ce13f7SAndroid Build Coastguard Worker   case InstArithmetic::Sdiv:
1958*03ce13f7SAndroid Build Coastguard Worker     // TODO(stichnot): Enable this after doing better performance and cross
1959*03ce13f7SAndroid Build Coastguard Worker     // testing.
1960*03ce13f7SAndroid Build Coastguard Worker     if (false && Func->getOptLevel() >= Opt_1) {
1961*03ce13f7SAndroid Build Coastguard Worker       // Optimize division by constant power of 2, but not for Om1 or O0, just
1962*03ce13f7SAndroid Build Coastguard Worker       // to keep things simple there.
1963*03ce13f7SAndroid Build Coastguard Worker       if (auto *C = llvm::dyn_cast<ConstantInteger32>(Src1)) {
1964*03ce13f7SAndroid Build Coastguard Worker         const int32_t Divisor = C->getValue();
1965*03ce13f7SAndroid Build Coastguard Worker         const uint32_t UDivisor = Divisor;
1966*03ce13f7SAndroid Build Coastguard Worker         if (Divisor > 0 && llvm::isPowerOf2_32(UDivisor)) {
1967*03ce13f7SAndroid Build Coastguard Worker           uint32_t LogDiv = llvm::Log2_32(UDivisor);
1968*03ce13f7SAndroid Build Coastguard Worker           // LLVM does the following for dest=src/(1<<log):
1969*03ce13f7SAndroid Build Coastguard Worker           //   t=src
1970*03ce13f7SAndroid Build Coastguard Worker           //   sar t,typewidth-1 // -1 if src is negative, 0 if not
1971*03ce13f7SAndroid Build Coastguard Worker           //   shr t,typewidth-log
1972*03ce13f7SAndroid Build Coastguard Worker           //   add t,src
1973*03ce13f7SAndroid Build Coastguard Worker           //   sar t,log
1974*03ce13f7SAndroid Build Coastguard Worker           //   dest=t
1975*03ce13f7SAndroid Build Coastguard Worker           uint32_t TypeWidth = X86_CHAR_BIT * typeWidthInBytes(Ty);
1976*03ce13f7SAndroid Build Coastguard Worker           _mov(T, Src0);
1977*03ce13f7SAndroid Build Coastguard Worker           // If for some reason we are dividing by 1, just treat it like an
1978*03ce13f7SAndroid Build Coastguard Worker           // assignment.
1979*03ce13f7SAndroid Build Coastguard Worker           if (LogDiv > 0) {
1980*03ce13f7SAndroid Build Coastguard Worker             // The initial sar is unnecessary when dividing by 2.
1981*03ce13f7SAndroid Build Coastguard Worker             if (LogDiv > 1)
1982*03ce13f7SAndroid Build Coastguard Worker               _sar(T, Ctx->getConstantInt(Ty, TypeWidth - 1));
1983*03ce13f7SAndroid Build Coastguard Worker             _shr(T, Ctx->getConstantInt(Ty, TypeWidth - LogDiv));
1984*03ce13f7SAndroid Build Coastguard Worker             _add(T, Src0);
1985*03ce13f7SAndroid Build Coastguard Worker             _sar(T, Ctx->getConstantInt(Ty, LogDiv));
1986*03ce13f7SAndroid Build Coastguard Worker           }
1987*03ce13f7SAndroid Build Coastguard Worker           _mov(Dest, T);
1988*03ce13f7SAndroid Build Coastguard Worker           return;
1989*03ce13f7SAndroid Build Coastguard Worker         }
1990*03ce13f7SAndroid Build Coastguard Worker       }
1991*03ce13f7SAndroid Build Coastguard Worker     }
1992*03ce13f7SAndroid Build Coastguard Worker     Src1 = legalize(Src1, Legal_Reg | Legal_Mem);
1993*03ce13f7SAndroid Build Coastguard Worker     switch (Ty) {
1994*03ce13f7SAndroid Build Coastguard Worker     default:
1995*03ce13f7SAndroid Build Coastguard Worker       llvm::report_fatal_error("Bad type for sdiv");
1996*03ce13f7SAndroid Build Coastguard Worker     case IceType_i64:
1997*03ce13f7SAndroid Build Coastguard Worker       T_edx = makeReg(Ty, RegX8664::Reg_rdx);
1998*03ce13f7SAndroid Build Coastguard Worker       _mov(T, Src0, RegX8664::Reg_rax);
1999*03ce13f7SAndroid Build Coastguard Worker       break;
2000*03ce13f7SAndroid Build Coastguard Worker     case IceType_i32:
2001*03ce13f7SAndroid Build Coastguard Worker       T_edx = makeReg(Ty, RegX8664::Reg_edx);
2002*03ce13f7SAndroid Build Coastguard Worker       _mov(T, Src0, RegX8664::Reg_eax);
2003*03ce13f7SAndroid Build Coastguard Worker       break;
2004*03ce13f7SAndroid Build Coastguard Worker     case IceType_i16:
2005*03ce13f7SAndroid Build Coastguard Worker       T_edx = makeReg(Ty, RegX8664::Reg_dx);
2006*03ce13f7SAndroid Build Coastguard Worker       _mov(T, Src0, RegX8664::Reg_ax);
2007*03ce13f7SAndroid Build Coastguard Worker       break;
2008*03ce13f7SAndroid Build Coastguard Worker     case IceType_i8:
2009*03ce13f7SAndroid Build Coastguard Worker       T_edx = makeReg(IceType_i16, RegX8664::Reg_ax);
2010*03ce13f7SAndroid Build Coastguard Worker       _mov(T, Src0, RegX8664::Reg_al);
2011*03ce13f7SAndroid Build Coastguard Worker       break;
2012*03ce13f7SAndroid Build Coastguard Worker     }
2013*03ce13f7SAndroid Build Coastguard Worker     _cbwdq(T_edx, T);
2014*03ce13f7SAndroid Build Coastguard Worker     _idiv(T_edx, Src1, T);
2015*03ce13f7SAndroid Build Coastguard Worker     _redefined(Context.insert<InstFakeDef>(T, T_edx));
2016*03ce13f7SAndroid Build Coastguard Worker     _mov(Dest, T);
2017*03ce13f7SAndroid Build Coastguard Worker     break;
2018*03ce13f7SAndroid Build Coastguard Worker   case InstArithmetic::Urem: {
2019*03ce13f7SAndroid Build Coastguard Worker     Src1 = legalize(Src1, Legal_Reg | Legal_Mem);
2020*03ce13f7SAndroid Build Coastguard Worker     RegNumT Eax;
2021*03ce13f7SAndroid Build Coastguard Worker     RegNumT Edx;
2022*03ce13f7SAndroid Build Coastguard Worker     switch (Ty) {
2023*03ce13f7SAndroid Build Coastguard Worker     default:
2024*03ce13f7SAndroid Build Coastguard Worker       llvm::report_fatal_error("Bad type for urem");
2025*03ce13f7SAndroid Build Coastguard Worker     case IceType_i64:
2026*03ce13f7SAndroid Build Coastguard Worker       Eax = RegX8664::Reg_rax;
2027*03ce13f7SAndroid Build Coastguard Worker       Edx = RegX8664::Reg_rdx;
2028*03ce13f7SAndroid Build Coastguard Worker       break;
2029*03ce13f7SAndroid Build Coastguard Worker     case IceType_i32:
2030*03ce13f7SAndroid Build Coastguard Worker       Eax = RegX8664::Reg_eax;
2031*03ce13f7SAndroid Build Coastguard Worker       Edx = RegX8664::Reg_edx;
2032*03ce13f7SAndroid Build Coastguard Worker       break;
2033*03ce13f7SAndroid Build Coastguard Worker     case IceType_i16:
2034*03ce13f7SAndroid Build Coastguard Worker       Eax = RegX8664::Reg_ax;
2035*03ce13f7SAndroid Build Coastguard Worker       Edx = RegX8664::Reg_dx;
2036*03ce13f7SAndroid Build Coastguard Worker       break;
2037*03ce13f7SAndroid Build Coastguard Worker     case IceType_i8:
2038*03ce13f7SAndroid Build Coastguard Worker       Eax = RegX8664::Reg_al;
2039*03ce13f7SAndroid Build Coastguard Worker       Edx = RegX8664::Reg_ah;
2040*03ce13f7SAndroid Build Coastguard Worker       break;
2041*03ce13f7SAndroid Build Coastguard Worker     }
2042*03ce13f7SAndroid Build Coastguard Worker     T_edx = makeReg(Ty, Edx);
2043*03ce13f7SAndroid Build Coastguard Worker     _mov(T_edx, Ctx->getConstantZero(Ty));
2044*03ce13f7SAndroid Build Coastguard Worker     _mov(T, Src0, Eax);
2045*03ce13f7SAndroid Build Coastguard Worker     _div(T, Src1, T_edx);
2046*03ce13f7SAndroid Build Coastguard Worker     _redefined(Context.insert<InstFakeDef>(T_edx, T));
2047*03ce13f7SAndroid Build Coastguard Worker     if (Ty == IceType_i8) {
2048*03ce13f7SAndroid Build Coastguard Worker       // Register ah must be moved into one of {al,bl,cl,dl} before it can be
2049*03ce13f7SAndroid Build Coastguard Worker       // moved into a general 8-bit register.
2050*03ce13f7SAndroid Build Coastguard Worker       auto *T_AhRcvr = makeReg(Ty);
2051*03ce13f7SAndroid Build Coastguard Worker       T_AhRcvr->setRegClass(RCX86_IsAhRcvr);
2052*03ce13f7SAndroid Build Coastguard Worker       _mov(T_AhRcvr, T_edx);
2053*03ce13f7SAndroid Build Coastguard Worker       T_edx = T_AhRcvr;
2054*03ce13f7SAndroid Build Coastguard Worker     }
2055*03ce13f7SAndroid Build Coastguard Worker     _mov(Dest, T_edx);
2056*03ce13f7SAndroid Build Coastguard Worker   } break;
2057*03ce13f7SAndroid Build Coastguard Worker   case InstArithmetic::Srem: {
2058*03ce13f7SAndroid Build Coastguard Worker     // TODO(stichnot): Enable this after doing better performance and cross
2059*03ce13f7SAndroid Build Coastguard Worker     // testing.
2060*03ce13f7SAndroid Build Coastguard Worker     if (false && Func->getOptLevel() >= Opt_1) {
2061*03ce13f7SAndroid Build Coastguard Worker       // Optimize mod by constant power of 2, but not for Om1 or O0, just to
2062*03ce13f7SAndroid Build Coastguard Worker       // keep things simple there.
2063*03ce13f7SAndroid Build Coastguard Worker       if (auto *C = llvm::dyn_cast<ConstantInteger32>(Src1)) {
2064*03ce13f7SAndroid Build Coastguard Worker         const int32_t Divisor = C->getValue();
2065*03ce13f7SAndroid Build Coastguard Worker         const uint32_t UDivisor = Divisor;
2066*03ce13f7SAndroid Build Coastguard Worker         if (Divisor > 0 && llvm::isPowerOf2_32(UDivisor)) {
2067*03ce13f7SAndroid Build Coastguard Worker           uint32_t LogDiv = llvm::Log2_32(UDivisor);
2068*03ce13f7SAndroid Build Coastguard Worker           // LLVM does the following for dest=src%(1<<log):
2069*03ce13f7SAndroid Build Coastguard Worker           //   t=src
2070*03ce13f7SAndroid Build Coastguard Worker           //   sar t,typewidth-1 // -1 if src is negative, 0 if not
2071*03ce13f7SAndroid Build Coastguard Worker           //   shr t,typewidth-log
2072*03ce13f7SAndroid Build Coastguard Worker           //   add t,src
2073*03ce13f7SAndroid Build Coastguard Worker           //   and t, -(1<<log)
2074*03ce13f7SAndroid Build Coastguard Worker           //   sub t,src
2075*03ce13f7SAndroid Build Coastguard Worker           //   neg t
2076*03ce13f7SAndroid Build Coastguard Worker           //   dest=t
2077*03ce13f7SAndroid Build Coastguard Worker           uint32_t TypeWidth = X86_CHAR_BIT * typeWidthInBytes(Ty);
2078*03ce13f7SAndroid Build Coastguard Worker           // If for some reason we are dividing by 1, just assign 0.
2079*03ce13f7SAndroid Build Coastguard Worker           if (LogDiv == 0) {
2080*03ce13f7SAndroid Build Coastguard Worker             _mov(Dest, Ctx->getConstantZero(Ty));
2081*03ce13f7SAndroid Build Coastguard Worker             return;
2082*03ce13f7SAndroid Build Coastguard Worker           }
2083*03ce13f7SAndroid Build Coastguard Worker           _mov(T, Src0);
2084*03ce13f7SAndroid Build Coastguard Worker           // The initial sar is unnecessary when dividing by 2.
2085*03ce13f7SAndroid Build Coastguard Worker           if (LogDiv > 1)
2086*03ce13f7SAndroid Build Coastguard Worker             _sar(T, Ctx->getConstantInt(Ty, TypeWidth - 1));
2087*03ce13f7SAndroid Build Coastguard Worker           _shr(T, Ctx->getConstantInt(Ty, TypeWidth - LogDiv));
2088*03ce13f7SAndroid Build Coastguard Worker           _add(T, Src0);
2089*03ce13f7SAndroid Build Coastguard Worker           _and(T, Ctx->getConstantInt(Ty, -(1 << LogDiv)));
2090*03ce13f7SAndroid Build Coastguard Worker           _sub(T, Src0);
2091*03ce13f7SAndroid Build Coastguard Worker           _neg(T);
2092*03ce13f7SAndroid Build Coastguard Worker           _mov(Dest, T);
2093*03ce13f7SAndroid Build Coastguard Worker           return;
2094*03ce13f7SAndroid Build Coastguard Worker         }
2095*03ce13f7SAndroid Build Coastguard Worker       }
2096*03ce13f7SAndroid Build Coastguard Worker     }
2097*03ce13f7SAndroid Build Coastguard Worker     Src1 = legalize(Src1, Legal_Reg | Legal_Mem);
2098*03ce13f7SAndroid Build Coastguard Worker     RegNumT Eax;
2099*03ce13f7SAndroid Build Coastguard Worker     RegNumT Edx;
2100*03ce13f7SAndroid Build Coastguard Worker     switch (Ty) {
2101*03ce13f7SAndroid Build Coastguard Worker     default:
2102*03ce13f7SAndroid Build Coastguard Worker       llvm::report_fatal_error("Bad type for srem");
2103*03ce13f7SAndroid Build Coastguard Worker     case IceType_i64:
2104*03ce13f7SAndroid Build Coastguard Worker       Eax = RegX8664::Reg_rax;
2105*03ce13f7SAndroid Build Coastguard Worker       Edx = RegX8664::Reg_rdx;
2106*03ce13f7SAndroid Build Coastguard Worker       break;
2107*03ce13f7SAndroid Build Coastguard Worker     case IceType_i32:
2108*03ce13f7SAndroid Build Coastguard Worker       Eax = RegX8664::Reg_eax;
2109*03ce13f7SAndroid Build Coastguard Worker       Edx = RegX8664::Reg_edx;
2110*03ce13f7SAndroid Build Coastguard Worker       break;
2111*03ce13f7SAndroid Build Coastguard Worker     case IceType_i16:
2112*03ce13f7SAndroid Build Coastguard Worker       Eax = RegX8664::Reg_ax;
2113*03ce13f7SAndroid Build Coastguard Worker       Edx = RegX8664::Reg_dx;
2114*03ce13f7SAndroid Build Coastguard Worker       break;
2115*03ce13f7SAndroid Build Coastguard Worker     case IceType_i8:
2116*03ce13f7SAndroid Build Coastguard Worker       Eax = RegX8664::Reg_al;
2117*03ce13f7SAndroid Build Coastguard Worker       Edx = RegX8664::Reg_ah;
2118*03ce13f7SAndroid Build Coastguard Worker       break;
2119*03ce13f7SAndroid Build Coastguard Worker     }
2120*03ce13f7SAndroid Build Coastguard Worker     T_edx = makeReg(Ty, Edx);
2121*03ce13f7SAndroid Build Coastguard Worker     _mov(T, Src0, Eax);
2122*03ce13f7SAndroid Build Coastguard Worker     _cbwdq(T_edx, T);
2123*03ce13f7SAndroid Build Coastguard Worker     _idiv(T, Src1, T_edx);
2124*03ce13f7SAndroid Build Coastguard Worker     _redefined(Context.insert<InstFakeDef>(T_edx, T));
2125*03ce13f7SAndroid Build Coastguard Worker     if (Ty == IceType_i8) {
2126*03ce13f7SAndroid Build Coastguard Worker       // Register ah must be moved into one of {al,bl,cl,dl} before it can be
2127*03ce13f7SAndroid Build Coastguard Worker       // moved into a general 8-bit register.
2128*03ce13f7SAndroid Build Coastguard Worker       auto *T_AhRcvr = makeReg(Ty);
2129*03ce13f7SAndroid Build Coastguard Worker       T_AhRcvr->setRegClass(RCX86_IsAhRcvr);
2130*03ce13f7SAndroid Build Coastguard Worker       _mov(T_AhRcvr, T_edx);
2131*03ce13f7SAndroid Build Coastguard Worker       T_edx = T_AhRcvr;
2132*03ce13f7SAndroid Build Coastguard Worker     }
2133*03ce13f7SAndroid Build Coastguard Worker     _mov(Dest, T_edx);
2134*03ce13f7SAndroid Build Coastguard Worker   } break;
2135*03ce13f7SAndroid Build Coastguard Worker   case InstArithmetic::Fadd:
2136*03ce13f7SAndroid Build Coastguard Worker     _mov(T, Src0);
2137*03ce13f7SAndroid Build Coastguard Worker     _addss(T, Src1);
2138*03ce13f7SAndroid Build Coastguard Worker     _mov(Dest, T);
2139*03ce13f7SAndroid Build Coastguard Worker     break;
2140*03ce13f7SAndroid Build Coastguard Worker   case InstArithmetic::Fsub:
2141*03ce13f7SAndroid Build Coastguard Worker     _mov(T, Src0);
2142*03ce13f7SAndroid Build Coastguard Worker     _subss(T, Src1);
2143*03ce13f7SAndroid Build Coastguard Worker     _mov(Dest, T);
2144*03ce13f7SAndroid Build Coastguard Worker     break;
2145*03ce13f7SAndroid Build Coastguard Worker   case InstArithmetic::Fmul:
2146*03ce13f7SAndroid Build Coastguard Worker     _mov(T, Src0);
2147*03ce13f7SAndroid Build Coastguard Worker     _mulss(T, Src0 == Src1 ? T : Src1);
2148*03ce13f7SAndroid Build Coastguard Worker     _mov(Dest, T);
2149*03ce13f7SAndroid Build Coastguard Worker     break;
2150*03ce13f7SAndroid Build Coastguard Worker   case InstArithmetic::Fdiv:
2151*03ce13f7SAndroid Build Coastguard Worker     _mov(T, Src0);
2152*03ce13f7SAndroid Build Coastguard Worker     _divss(T, Src1);
2153*03ce13f7SAndroid Build Coastguard Worker     _mov(Dest, T);
2154*03ce13f7SAndroid Build Coastguard Worker     break;
2155*03ce13f7SAndroid Build Coastguard Worker   case InstArithmetic::Frem:
2156*03ce13f7SAndroid Build Coastguard Worker     llvm::report_fatal_error("Helper call was expected");
2157*03ce13f7SAndroid Build Coastguard Worker     break;
2158*03ce13f7SAndroid Build Coastguard Worker   }
2159*03ce13f7SAndroid Build Coastguard Worker }
2160*03ce13f7SAndroid Build Coastguard Worker 
lowerAssign(const InstAssign * Instr)2161*03ce13f7SAndroid Build Coastguard Worker void TargetX8664::lowerAssign(const InstAssign *Instr) {
2162*03ce13f7SAndroid Build Coastguard Worker   Variable *Dest = Instr->getDest();
2163*03ce13f7SAndroid Build Coastguard Worker   if (Dest->isRematerializable()) {
2164*03ce13f7SAndroid Build Coastguard Worker     Context.insert<InstFakeDef>(Dest);
2165*03ce13f7SAndroid Build Coastguard Worker     return;
2166*03ce13f7SAndroid Build Coastguard Worker   }
2167*03ce13f7SAndroid Build Coastguard Worker   Operand *Src = Instr->getSrc(0);
2168*03ce13f7SAndroid Build Coastguard Worker   assert(Dest->getType() == Src->getType());
2169*03ce13f7SAndroid Build Coastguard Worker   lowerMove(Dest, Src, false);
2170*03ce13f7SAndroid Build Coastguard Worker }
2171*03ce13f7SAndroid Build Coastguard Worker 
lowerBr(const InstBr * Br)2172*03ce13f7SAndroid Build Coastguard Worker void TargetX8664::lowerBr(const InstBr *Br) {
2173*03ce13f7SAndroid Build Coastguard Worker   if (Br->isUnconditional()) {
2174*03ce13f7SAndroid Build Coastguard Worker     _br(Br->getTargetUnconditional());
2175*03ce13f7SAndroid Build Coastguard Worker     return;
2176*03ce13f7SAndroid Build Coastguard Worker   }
2177*03ce13f7SAndroid Build Coastguard Worker   Operand *Cond = Br->getCondition();
2178*03ce13f7SAndroid Build Coastguard Worker 
2179*03ce13f7SAndroid Build Coastguard Worker   // Handle folding opportunities.
2180*03ce13f7SAndroid Build Coastguard Worker   if (const Inst *Producer = FoldingInfo.getProducerFor(Cond)) {
2181*03ce13f7SAndroid Build Coastguard Worker     assert(Producer->isDeleted());
2182*03ce13f7SAndroid Build Coastguard Worker     switch (BoolFolding::getProducerKind(Producer)) {
2183*03ce13f7SAndroid Build Coastguard Worker     default:
2184*03ce13f7SAndroid Build Coastguard Worker       break;
2185*03ce13f7SAndroid Build Coastguard Worker     case BoolFolding::PK_Icmp32:
2186*03ce13f7SAndroid Build Coastguard Worker     case BoolFolding::PK_Icmp64: {
2187*03ce13f7SAndroid Build Coastguard Worker       lowerIcmpAndConsumer(llvm::cast<InstIcmp>(Producer), Br);
2188*03ce13f7SAndroid Build Coastguard Worker       return;
2189*03ce13f7SAndroid Build Coastguard Worker     }
2190*03ce13f7SAndroid Build Coastguard Worker     case BoolFolding::PK_Fcmp: {
2191*03ce13f7SAndroid Build Coastguard Worker       lowerFcmpAndConsumer(llvm::cast<InstFcmp>(Producer), Br);
2192*03ce13f7SAndroid Build Coastguard Worker       return;
2193*03ce13f7SAndroid Build Coastguard Worker     }
2194*03ce13f7SAndroid Build Coastguard Worker     case BoolFolding::PK_Arith: {
2195*03ce13f7SAndroid Build Coastguard Worker       lowerArithAndConsumer(llvm::cast<InstArithmetic>(Producer), Br);
2196*03ce13f7SAndroid Build Coastguard Worker       return;
2197*03ce13f7SAndroid Build Coastguard Worker     }
2198*03ce13f7SAndroid Build Coastguard Worker     }
2199*03ce13f7SAndroid Build Coastguard Worker   }
2200*03ce13f7SAndroid Build Coastguard Worker   Operand *Src0 = legalize(Cond, Legal_Reg | Legal_Mem);
2201*03ce13f7SAndroid Build Coastguard Worker   Constant *Zero = Ctx->getConstantZero(IceType_i32);
2202*03ce13f7SAndroid Build Coastguard Worker   _cmp(Src0, Zero);
2203*03ce13f7SAndroid Build Coastguard Worker   _br(CondX86::Br_ne, Br->getTargetTrue(), Br->getTargetFalse());
2204*03ce13f7SAndroid Build Coastguard Worker }
2205*03ce13f7SAndroid Build Coastguard Worker 
2206*03ce13f7SAndroid Build Coastguard Worker // constexprMax returns a (constexpr) max(S0, S1), and it is used for defining
2207*03ce13f7SAndroid Build Coastguard Worker // OperandList in lowerCall. std::max() is supposed to work, but it doesn't.
constexprMax(SizeT S0,SizeT S1)2208*03ce13f7SAndroid Build Coastguard Worker inline constexpr SizeT constexprMax(SizeT S0, SizeT S1) {
2209*03ce13f7SAndroid Build Coastguard Worker   return S0 < S1 ? S1 : S0;
2210*03ce13f7SAndroid Build Coastguard Worker }
2211*03ce13f7SAndroid Build Coastguard Worker 
lowerCall(const InstCall * Instr)2212*03ce13f7SAndroid Build Coastguard Worker void TargetX8664::lowerCall(const InstCall *Instr) {
2213*03ce13f7SAndroid Build Coastguard Worker   // Common x86-64 calling convention lowering:
2214*03ce13f7SAndroid Build Coastguard Worker   //
2215*03ce13f7SAndroid Build Coastguard Worker   // * At the point before the call, the stack must be aligned to 16 bytes.
2216*03ce13f7SAndroid Build Coastguard Worker   //
2217*03ce13f7SAndroid Build Coastguard Worker   // * Non-register arguments are pushed onto the stack in right-to-left order,
2218*03ce13f7SAndroid Build Coastguard Worker   // such that the left-most argument ends up on the top of the stack at the
2219*03ce13f7SAndroid Build Coastguard Worker   // lowest memory address.
2220*03ce13f7SAndroid Build Coastguard Worker   //
2221*03ce13f7SAndroid Build Coastguard Worker   // * Stack arguments of vector type are aligned to start at the next highest
2222*03ce13f7SAndroid Build Coastguard Worker   // multiple of 16 bytes. Other stack arguments are aligned to the next word
2223*03ce13f7SAndroid Build Coastguard Worker   // size boundary (4 or 8 bytes, respectively).
2224*03ce13f7SAndroid Build Coastguard Worker 
2225*03ce13f7SAndroid Build Coastguard Worker   constexpr SizeT MaxOperands =
2226*03ce13f7SAndroid Build Coastguard Worker       constexprMax(RegX8664::X86_MAX_XMM_ARGS, RegX8664::X86_MAX_GPR_ARGS);
2227*03ce13f7SAndroid Build Coastguard Worker   using OperandList = llvm::SmallVector<Operand *, MaxOperands>;
2228*03ce13f7SAndroid Build Coastguard Worker 
2229*03ce13f7SAndroid Build Coastguard Worker   OperandList XmmArgs;
2230*03ce13f7SAndroid Build Coastguard Worker   llvm::SmallVector<SizeT, MaxOperands> XmmArgIndices;
2231*03ce13f7SAndroid Build Coastguard Worker   CfgVector<std::pair<const Type, Operand *>> GprArgs;
2232*03ce13f7SAndroid Build Coastguard Worker   CfgVector<SizeT> GprArgIndices;
2233*03ce13f7SAndroid Build Coastguard Worker   OperandList StackArgs, StackArgLocations;
2234*03ce13f7SAndroid Build Coastguard Worker   uint32_t ParameterAreaSizeBytes = 0;
2235*03ce13f7SAndroid Build Coastguard Worker 
2236*03ce13f7SAndroid Build Coastguard Worker   ParameterAreaSizeBytes += getShadowStoreSize();
2237*03ce13f7SAndroid Build Coastguard Worker 
2238*03ce13f7SAndroid Build Coastguard Worker   // Classify each argument operand according to the location where the argument
2239*03ce13f7SAndroid Build Coastguard Worker   // is passed.
2240*03ce13f7SAndroid Build Coastguard Worker   for (SizeT i = 0, NumArgs = Instr->getNumArgs(); i < NumArgs; ++i) {
2241*03ce13f7SAndroid Build Coastguard Worker     Operand *Arg = Instr->getArg(i);
2242*03ce13f7SAndroid Build Coastguard Worker     const Type Ty = Arg->getType();
2243*03ce13f7SAndroid Build Coastguard Worker     // The PNaCl ABI requires the width of arguments to be at least 32 bits.
2244*03ce13f7SAndroid Build Coastguard Worker     assert(typeWidthInBytes(Ty) >= 4);
2245*03ce13f7SAndroid Build Coastguard Worker     if (isVectorType(Ty) && RegX8664::getRegisterForXmmArgNum(
2246*03ce13f7SAndroid Build Coastguard Worker                                 RegX8664::getArgIndex(i, XmmArgs.size()))
2247*03ce13f7SAndroid Build Coastguard Worker                                 .hasValue()) {
2248*03ce13f7SAndroid Build Coastguard Worker       XmmArgs.push_back(Arg);
2249*03ce13f7SAndroid Build Coastguard Worker       XmmArgIndices.push_back(i);
2250*03ce13f7SAndroid Build Coastguard Worker     } else if (isScalarFloatingType(Ty) &&
2251*03ce13f7SAndroid Build Coastguard Worker                RegX8664::getRegisterForXmmArgNum(
2252*03ce13f7SAndroid Build Coastguard Worker                    RegX8664::getArgIndex(i, XmmArgs.size()))
2253*03ce13f7SAndroid Build Coastguard Worker                    .hasValue()) {
2254*03ce13f7SAndroid Build Coastguard Worker       XmmArgs.push_back(Arg);
2255*03ce13f7SAndroid Build Coastguard Worker       XmmArgIndices.push_back(i);
2256*03ce13f7SAndroid Build Coastguard Worker     } else if (isScalarIntegerType(Ty) &&
2257*03ce13f7SAndroid Build Coastguard Worker                RegX8664::getRegisterForGprArgNum(
2258*03ce13f7SAndroid Build Coastguard Worker                    Ty, RegX8664::getArgIndex(i, GprArgs.size()))
2259*03ce13f7SAndroid Build Coastguard Worker                    .hasValue()) {
2260*03ce13f7SAndroid Build Coastguard Worker       GprArgs.emplace_back(Ty, Arg);
2261*03ce13f7SAndroid Build Coastguard Worker       GprArgIndices.push_back(i);
2262*03ce13f7SAndroid Build Coastguard Worker     } else {
2263*03ce13f7SAndroid Build Coastguard Worker       // Place on stack.
2264*03ce13f7SAndroid Build Coastguard Worker       StackArgs.push_back(Arg);
2265*03ce13f7SAndroid Build Coastguard Worker       if (isVectorType(Arg->getType())) {
2266*03ce13f7SAndroid Build Coastguard Worker         ParameterAreaSizeBytes = applyStackAlignment(ParameterAreaSizeBytes);
2267*03ce13f7SAndroid Build Coastguard Worker       }
2268*03ce13f7SAndroid Build Coastguard Worker       Variable *esp = getPhysicalRegister(getStackReg(), WordType);
2269*03ce13f7SAndroid Build Coastguard Worker       Constant *Loc = Ctx->getConstantInt32(ParameterAreaSizeBytes);
2270*03ce13f7SAndroid Build Coastguard Worker       StackArgLocations.push_back(X86OperandMem::create(Func, Ty, esp, Loc));
2271*03ce13f7SAndroid Build Coastguard Worker       ParameterAreaSizeBytes += typeWidthInBytesOnStack(Arg->getType());
2272*03ce13f7SAndroid Build Coastguard Worker     }
2273*03ce13f7SAndroid Build Coastguard Worker   }
2274*03ce13f7SAndroid Build Coastguard Worker   // Adjust the parameter area so that the stack is aligned. It is assumed that
2275*03ce13f7SAndroid Build Coastguard Worker   // the stack is already aligned at the start of the calling sequence.
2276*03ce13f7SAndroid Build Coastguard Worker   ParameterAreaSizeBytes = applyStackAlignment(ParameterAreaSizeBytes);
2277*03ce13f7SAndroid Build Coastguard Worker   assert(ParameterAreaSizeBytes <= maxOutArgsSizeBytes());
2278*03ce13f7SAndroid Build Coastguard Worker   // Copy arguments that are passed on the stack to the appropriate stack
2279*03ce13f7SAndroid Build Coastguard Worker   // locations.  We make sure legalize() is called on each argument at this
2280*03ce13f7SAndroid Build Coastguard Worker   // point, to allow availabilityGet() to work.
2281*03ce13f7SAndroid Build Coastguard Worker   for (SizeT i = 0, NumStackArgs = StackArgs.size(); i < NumStackArgs; ++i) {
2282*03ce13f7SAndroid Build Coastguard Worker     lowerStore(
2283*03ce13f7SAndroid Build Coastguard Worker         InstStore::create(Func, legalize(StackArgs[i]), StackArgLocations[i]));
2284*03ce13f7SAndroid Build Coastguard Worker   }
2285*03ce13f7SAndroid Build Coastguard Worker   // Copy arguments to be passed in registers to the appropriate registers.
2286*03ce13f7SAndroid Build Coastguard Worker   for (SizeT i = 0, NumXmmArgs = XmmArgs.size(); i < NumXmmArgs; ++i) {
2287*03ce13f7SAndroid Build Coastguard Worker     XmmArgs[i] = legalizeToReg(legalize(XmmArgs[i]),
2288*03ce13f7SAndroid Build Coastguard Worker                                RegX8664::getRegisterForXmmArgNum(
2289*03ce13f7SAndroid Build Coastguard Worker                                    RegX8664::getArgIndex(XmmArgIndices[i], i)));
2290*03ce13f7SAndroid Build Coastguard Worker   }
2291*03ce13f7SAndroid Build Coastguard Worker   // Materialize moves for arguments passed in GPRs.
2292*03ce13f7SAndroid Build Coastguard Worker   for (SizeT i = 0, NumGprArgs = GprArgs.size(); i < NumGprArgs; ++i) {
2293*03ce13f7SAndroid Build Coastguard Worker     const Type SignatureTy = GprArgs[i].first;
2294*03ce13f7SAndroid Build Coastguard Worker     Operand *Arg =
2295*03ce13f7SAndroid Build Coastguard Worker         legalize(GprArgs[i].second, Legal_Default | Legal_Rematerializable);
2296*03ce13f7SAndroid Build Coastguard Worker     GprArgs[i].second = legalizeToReg(
2297*03ce13f7SAndroid Build Coastguard Worker         Arg, RegX8664::getRegisterForGprArgNum(
2298*03ce13f7SAndroid Build Coastguard Worker                  Arg->getType(), RegX8664::getArgIndex(GprArgIndices[i], i)));
2299*03ce13f7SAndroid Build Coastguard Worker     assert(SignatureTy == IceType_i64 || SignatureTy == IceType_i32);
2300*03ce13f7SAndroid Build Coastguard Worker     assert(SignatureTy == Arg->getType());
2301*03ce13f7SAndroid Build Coastguard Worker     (void)SignatureTy;
2302*03ce13f7SAndroid Build Coastguard Worker   }
2303*03ce13f7SAndroid Build Coastguard Worker   // Generate a FakeUse of register arguments so that they do not get dead code
2304*03ce13f7SAndroid Build Coastguard Worker   // eliminated as a result of the FakeKill of scratch registers after the call.
2305*03ce13f7SAndroid Build Coastguard Worker   // These need to be right before the call instruction.
2306*03ce13f7SAndroid Build Coastguard Worker   for (auto *Arg : XmmArgs) {
2307*03ce13f7SAndroid Build Coastguard Worker     Context.insert<InstFakeUse>(llvm::cast<Variable>(Arg));
2308*03ce13f7SAndroid Build Coastguard Worker   }
2309*03ce13f7SAndroid Build Coastguard Worker   for (auto &ArgPair : GprArgs) {
2310*03ce13f7SAndroid Build Coastguard Worker     Context.insert<InstFakeUse>(llvm::cast<Variable>(ArgPair.second));
2311*03ce13f7SAndroid Build Coastguard Worker   }
2312*03ce13f7SAndroid Build Coastguard Worker   // Generate the call instruction. Assign its result to a temporary with high
2313*03ce13f7SAndroid Build Coastguard Worker   // register allocation weight.
2314*03ce13f7SAndroid Build Coastguard Worker   Variable *Dest = Instr->getDest();
2315*03ce13f7SAndroid Build Coastguard Worker   const Type DestTy = Dest ? Dest->getType() : IceType_void;
2316*03ce13f7SAndroid Build Coastguard Worker   Variable *ReturnReg = nullptr;
2317*03ce13f7SAndroid Build Coastguard Worker   if (Dest) {
2318*03ce13f7SAndroid Build Coastguard Worker     switch (DestTy) {
2319*03ce13f7SAndroid Build Coastguard Worker     case IceType_NUM:
2320*03ce13f7SAndroid Build Coastguard Worker     case IceType_void:
2321*03ce13f7SAndroid Build Coastguard Worker     case IceType_i1:
2322*03ce13f7SAndroid Build Coastguard Worker     case IceType_i8:
2323*03ce13f7SAndroid Build Coastguard Worker     case IceType_i16:
2324*03ce13f7SAndroid Build Coastguard Worker       llvm::report_fatal_error("Invalid Call dest type");
2325*03ce13f7SAndroid Build Coastguard Worker       break;
2326*03ce13f7SAndroid Build Coastguard Worker     case IceType_i32:
2327*03ce13f7SAndroid Build Coastguard Worker       ReturnReg = makeReg(DestTy, RegX8664::Reg_eax);
2328*03ce13f7SAndroid Build Coastguard Worker       break;
2329*03ce13f7SAndroid Build Coastguard Worker     case IceType_i64:
2330*03ce13f7SAndroid Build Coastguard Worker       ReturnReg = makeReg(IceType_i64, RegX8664::Reg_rax);
2331*03ce13f7SAndroid Build Coastguard Worker 
2332*03ce13f7SAndroid Build Coastguard Worker       break;
2333*03ce13f7SAndroid Build Coastguard Worker     case IceType_f32:
2334*03ce13f7SAndroid Build Coastguard Worker     case IceType_f64:
2335*03ce13f7SAndroid Build Coastguard Worker     case IceType_v4i1:
2336*03ce13f7SAndroid Build Coastguard Worker     case IceType_v8i1:
2337*03ce13f7SAndroid Build Coastguard Worker     case IceType_v16i1:
2338*03ce13f7SAndroid Build Coastguard Worker     case IceType_v16i8:
2339*03ce13f7SAndroid Build Coastguard Worker     case IceType_v8i16:
2340*03ce13f7SAndroid Build Coastguard Worker     case IceType_v4i32:
2341*03ce13f7SAndroid Build Coastguard Worker     case IceType_v4f32:
2342*03ce13f7SAndroid Build Coastguard Worker       ReturnReg = makeReg(DestTy, RegX8664::Reg_xmm0);
2343*03ce13f7SAndroid Build Coastguard Worker       break;
2344*03ce13f7SAndroid Build Coastguard Worker     }
2345*03ce13f7SAndroid Build Coastguard Worker   }
2346*03ce13f7SAndroid Build Coastguard Worker   // Emit the call to the function.
2347*03ce13f7SAndroid Build Coastguard Worker   Operand *CallTarget =
2348*03ce13f7SAndroid Build Coastguard Worker       legalize(Instr->getCallTarget(), Legal_Reg | Legal_Imm | Legal_AddrAbs);
2349*03ce13f7SAndroid Build Coastguard Worker   size_t NumVariadicFpArgs = Instr->isVariadic() ? XmmArgs.size() : 0;
2350*03ce13f7SAndroid Build Coastguard Worker   Inst *NewCall = emitCallToTarget(CallTarget, ReturnReg, NumVariadicFpArgs);
2351*03ce13f7SAndroid Build Coastguard Worker   // Mark the call as killing all the caller-save registers.
2352*03ce13f7SAndroid Build Coastguard Worker   Context.insert<InstFakeKill>(NewCall);
2353*03ce13f7SAndroid Build Coastguard Worker   // Generate a FakeUse to keep the call live if necessary.
2354*03ce13f7SAndroid Build Coastguard Worker   if (Instr->hasSideEffects() && ReturnReg) {
2355*03ce13f7SAndroid Build Coastguard Worker     Context.insert<InstFakeUse>(ReturnReg);
2356*03ce13f7SAndroid Build Coastguard Worker   }
2357*03ce13f7SAndroid Build Coastguard Worker   // Process the return value, if any.
2358*03ce13f7SAndroid Build Coastguard Worker   if (Dest == nullptr)
2359*03ce13f7SAndroid Build Coastguard Worker     return;
2360*03ce13f7SAndroid Build Coastguard Worker   // Assign the result of the call to Dest.  Route it through a temporary so
2361*03ce13f7SAndroid Build Coastguard Worker   // that the local register availability peephole can be subsequently used.
2362*03ce13f7SAndroid Build Coastguard Worker   Variable *Tmp = nullptr;
2363*03ce13f7SAndroid Build Coastguard Worker   if (isVectorType(DestTy)) {
2364*03ce13f7SAndroid Build Coastguard Worker     assert(ReturnReg && "Vector type requires a return register");
2365*03ce13f7SAndroid Build Coastguard Worker     Tmp = makeReg(DestTy);
2366*03ce13f7SAndroid Build Coastguard Worker     _movp(Tmp, ReturnReg);
2367*03ce13f7SAndroid Build Coastguard Worker     _movp(Dest, Tmp);
2368*03ce13f7SAndroid Build Coastguard Worker   } else if (isScalarFloatingType(DestTy)) {
2369*03ce13f7SAndroid Build Coastguard Worker     assert(ReturnReg && "FP type requires a return register");
2370*03ce13f7SAndroid Build Coastguard Worker     _mov(Tmp, ReturnReg);
2371*03ce13f7SAndroid Build Coastguard Worker     _mov(Dest, Tmp);
2372*03ce13f7SAndroid Build Coastguard Worker   } else {
2373*03ce13f7SAndroid Build Coastguard Worker     assert(isScalarIntegerType(DestTy));
2374*03ce13f7SAndroid Build Coastguard Worker     assert(ReturnReg && "Integer type requires a return register");
2375*03ce13f7SAndroid Build Coastguard Worker     _mov(Tmp, ReturnReg);
2376*03ce13f7SAndroid Build Coastguard Worker     _mov(Dest, Tmp);
2377*03ce13f7SAndroid Build Coastguard Worker   }
2378*03ce13f7SAndroid Build Coastguard Worker }
2379*03ce13f7SAndroid Build Coastguard Worker 
lowerCast(const InstCast * Instr)2380*03ce13f7SAndroid Build Coastguard Worker void TargetX8664::lowerCast(const InstCast *Instr) {
2381*03ce13f7SAndroid Build Coastguard Worker   // a = cast(b) ==> t=cast(b); a=t; (link t->b, link a->t, no overlap)
2382*03ce13f7SAndroid Build Coastguard Worker   InstCast::OpKind CastKind = Instr->getCastKind();
2383*03ce13f7SAndroid Build Coastguard Worker   Variable *Dest = Instr->getDest();
2384*03ce13f7SAndroid Build Coastguard Worker   Type DestTy = Dest->getType();
2385*03ce13f7SAndroid Build Coastguard Worker   switch (CastKind) {
2386*03ce13f7SAndroid Build Coastguard Worker   default:
2387*03ce13f7SAndroid Build Coastguard Worker     Func->setError("Cast type not supported");
2388*03ce13f7SAndroid Build Coastguard Worker     return;
2389*03ce13f7SAndroid Build Coastguard Worker   case InstCast::Sext: {
2390*03ce13f7SAndroid Build Coastguard Worker     // Src0RM is the source operand legalized to physical register or memory,
2391*03ce13f7SAndroid Build Coastguard Worker     // but not immediate, since the relevant x86 native instructions don't
2392*03ce13f7SAndroid Build Coastguard Worker     // allow an immediate operand. If the operand is an immediate, we could
2393*03ce13f7SAndroid Build Coastguard Worker     // consider computing the strength-reduced result at translation time, but
2394*03ce13f7SAndroid Build Coastguard Worker     // we're unlikely to see something like that in the bitcode that the
2395*03ce13f7SAndroid Build Coastguard Worker     // optimizer wouldn't have already taken care of.
2396*03ce13f7SAndroid Build Coastguard Worker     Operand *Src0RM = legalize(Instr->getSrc(0), Legal_Reg | Legal_Mem);
2397*03ce13f7SAndroid Build Coastguard Worker     if (isVectorType(DestTy)) {
2398*03ce13f7SAndroid Build Coastguard Worker       if (DestTy == IceType_v16i8) {
2399*03ce13f7SAndroid Build Coastguard Worker         // onemask = materialize(1,1,...); dst = (src & onemask) > 0
2400*03ce13f7SAndroid Build Coastguard Worker         Variable *OneMask = makeVectorOfOnes(DestTy);
2401*03ce13f7SAndroid Build Coastguard Worker         Variable *T = makeReg(DestTy);
2402*03ce13f7SAndroid Build Coastguard Worker         _movp(T, Src0RM);
2403*03ce13f7SAndroid Build Coastguard Worker         _pand(T, OneMask);
2404*03ce13f7SAndroid Build Coastguard Worker         Variable *Zeros = makeVectorOfZeros(DestTy);
2405*03ce13f7SAndroid Build Coastguard Worker         _pcmpgt(T, Zeros);
2406*03ce13f7SAndroid Build Coastguard Worker         _movp(Dest, T);
2407*03ce13f7SAndroid Build Coastguard Worker       } else {
2408*03ce13f7SAndroid Build Coastguard Worker         /// width = width(elty) - 1; dest = (src << width) >> width
2409*03ce13f7SAndroid Build Coastguard Worker         SizeT ShiftAmount =
2410*03ce13f7SAndroid Build Coastguard Worker             X86_CHAR_BIT * typeWidthInBytes(typeElementType(DestTy)) - 1;
2411*03ce13f7SAndroid Build Coastguard Worker         Constant *ShiftConstant = Ctx->getConstantInt8(ShiftAmount);
2412*03ce13f7SAndroid Build Coastguard Worker         Variable *T = makeReg(DestTy);
2413*03ce13f7SAndroid Build Coastguard Worker         _movp(T, Src0RM);
2414*03ce13f7SAndroid Build Coastguard Worker         _psll(T, ShiftConstant);
2415*03ce13f7SAndroid Build Coastguard Worker         _psra(T, ShiftConstant);
2416*03ce13f7SAndroid Build Coastguard Worker         _movp(Dest, T);
2417*03ce13f7SAndroid Build Coastguard Worker       }
2418*03ce13f7SAndroid Build Coastguard Worker     } else if (Src0RM->getType() == IceType_i1) {
2419*03ce13f7SAndroid Build Coastguard Worker       // t1 = src
2420*03ce13f7SAndroid Build Coastguard Worker       // shl t1, dst_bitwidth - 1
2421*03ce13f7SAndroid Build Coastguard Worker       // sar t1, dst_bitwidth - 1
2422*03ce13f7SAndroid Build Coastguard Worker       // dst = t1
2423*03ce13f7SAndroid Build Coastguard Worker       size_t DestBits = X86_CHAR_BIT * typeWidthInBytes(DestTy);
2424*03ce13f7SAndroid Build Coastguard Worker       Constant *ShiftAmount = Ctx->getConstantInt32(DestBits - 1);
2425*03ce13f7SAndroid Build Coastguard Worker       Variable *T = makeReg(DestTy);
2426*03ce13f7SAndroid Build Coastguard Worker       if (typeWidthInBytes(DestTy) <= typeWidthInBytes(Src0RM->getType())) {
2427*03ce13f7SAndroid Build Coastguard Worker         _mov(T, Src0RM);
2428*03ce13f7SAndroid Build Coastguard Worker       } else {
2429*03ce13f7SAndroid Build Coastguard Worker         // Widen the source using movsx or movzx. (It doesn't matter which one,
2430*03ce13f7SAndroid Build Coastguard Worker         // since the following shl/sar overwrite the bits.)
2431*03ce13f7SAndroid Build Coastguard Worker         _movzx(T, Src0RM);
2432*03ce13f7SAndroid Build Coastguard Worker       }
2433*03ce13f7SAndroid Build Coastguard Worker       _shl(T, ShiftAmount);
2434*03ce13f7SAndroid Build Coastguard Worker       _sar(T, ShiftAmount);
2435*03ce13f7SAndroid Build Coastguard Worker       _mov(Dest, T);
2436*03ce13f7SAndroid Build Coastguard Worker     } else {
2437*03ce13f7SAndroid Build Coastguard Worker       // t1 = movsx src; dst = t1
2438*03ce13f7SAndroid Build Coastguard Worker       Variable *T = makeReg(DestTy);
2439*03ce13f7SAndroid Build Coastguard Worker       _movsx(T, Src0RM);
2440*03ce13f7SAndroid Build Coastguard Worker       _mov(Dest, T);
2441*03ce13f7SAndroid Build Coastguard Worker     }
2442*03ce13f7SAndroid Build Coastguard Worker     break;
2443*03ce13f7SAndroid Build Coastguard Worker   }
2444*03ce13f7SAndroid Build Coastguard Worker   case InstCast::Zext: {
2445*03ce13f7SAndroid Build Coastguard Worker     Operand *Src0RM = legalize(Instr->getSrc(0), Legal_Reg | Legal_Mem);
2446*03ce13f7SAndroid Build Coastguard Worker     if (isVectorType(DestTy)) {
2447*03ce13f7SAndroid Build Coastguard Worker       // onemask = materialize(1,1,...); dest = onemask & src
2448*03ce13f7SAndroid Build Coastguard Worker       Variable *OneMask = makeVectorOfOnes(DestTy);
2449*03ce13f7SAndroid Build Coastguard Worker       Variable *T = makeReg(DestTy);
2450*03ce13f7SAndroid Build Coastguard Worker       _movp(T, Src0RM);
2451*03ce13f7SAndroid Build Coastguard Worker       _pand(T, OneMask);
2452*03ce13f7SAndroid Build Coastguard Worker       _movp(Dest, T);
2453*03ce13f7SAndroid Build Coastguard Worker     } else if (Src0RM->getType() == IceType_i1) {
2454*03ce13f7SAndroid Build Coastguard Worker       // t = Src0RM; Dest = t
2455*03ce13f7SAndroid Build Coastguard Worker       Variable *T = nullptr;
2456*03ce13f7SAndroid Build Coastguard Worker       if (DestTy == IceType_i8) {
2457*03ce13f7SAndroid Build Coastguard Worker         _mov(T, Src0RM);
2458*03ce13f7SAndroid Build Coastguard Worker       } else {
2459*03ce13f7SAndroid Build Coastguard Worker         assert(DestTy != IceType_i1);
2460*03ce13f7SAndroid Build Coastguard Worker         // Use 32-bit for both 16-bit and 32-bit, since 32-bit ops are shorter.
2461*03ce13f7SAndroid Build Coastguard Worker         // In x86-64 we need to widen T to 64-bits to ensure that T -- if
2462*03ce13f7SAndroid Build Coastguard Worker         // written to the stack (i.e., in -Om1) will be fully zero-extended.
2463*03ce13f7SAndroid Build Coastguard Worker         T = makeReg(DestTy == IceType_i64 ? IceType_i64 : IceType_i32);
2464*03ce13f7SAndroid Build Coastguard Worker         _movzx(T, Src0RM);
2465*03ce13f7SAndroid Build Coastguard Worker       }
2466*03ce13f7SAndroid Build Coastguard Worker       _mov(Dest, T);
2467*03ce13f7SAndroid Build Coastguard Worker     } else {
2468*03ce13f7SAndroid Build Coastguard Worker       // t1 = movzx src; dst = t1
2469*03ce13f7SAndroid Build Coastguard Worker       Variable *T = makeReg(DestTy);
2470*03ce13f7SAndroid Build Coastguard Worker       _movzx(T, Src0RM);
2471*03ce13f7SAndroid Build Coastguard Worker       _mov(Dest, T);
2472*03ce13f7SAndroid Build Coastguard Worker     }
2473*03ce13f7SAndroid Build Coastguard Worker     break;
2474*03ce13f7SAndroid Build Coastguard Worker   }
2475*03ce13f7SAndroid Build Coastguard Worker   case InstCast::Trunc: {
2476*03ce13f7SAndroid Build Coastguard Worker     if (isVectorType(DestTy)) {
2477*03ce13f7SAndroid Build Coastguard Worker       // onemask = materialize(1,1,...); dst = src & onemask
2478*03ce13f7SAndroid Build Coastguard Worker       Operand *Src0RM = legalize(Instr->getSrc(0), Legal_Reg | Legal_Mem);
2479*03ce13f7SAndroid Build Coastguard Worker       Type Src0Ty = Src0RM->getType();
2480*03ce13f7SAndroid Build Coastguard Worker       Variable *OneMask = makeVectorOfOnes(Src0Ty);
2481*03ce13f7SAndroid Build Coastguard Worker       Variable *T = makeReg(DestTy);
2482*03ce13f7SAndroid Build Coastguard Worker       _movp(T, Src0RM);
2483*03ce13f7SAndroid Build Coastguard Worker       _pand(T, OneMask);
2484*03ce13f7SAndroid Build Coastguard Worker       _movp(Dest, T);
2485*03ce13f7SAndroid Build Coastguard Worker     } else if (DestTy == IceType_i1 || DestTy == IceType_i8) {
2486*03ce13f7SAndroid Build Coastguard Worker       // Make sure we truncate from and into valid registers.
2487*03ce13f7SAndroid Build Coastguard Worker       Operand *Src0 = legalizeUndef(Instr->getSrc(0));
2488*03ce13f7SAndroid Build Coastguard Worker       Operand *Src0RM = legalize(Src0, Legal_Reg | Legal_Mem);
2489*03ce13f7SAndroid Build Coastguard Worker       Variable *T = copyToReg8(Src0RM);
2490*03ce13f7SAndroid Build Coastguard Worker       if (DestTy == IceType_i1)
2491*03ce13f7SAndroid Build Coastguard Worker         _and(T, Ctx->getConstantInt1(1));
2492*03ce13f7SAndroid Build Coastguard Worker       _mov(Dest, T);
2493*03ce13f7SAndroid Build Coastguard Worker     } else {
2494*03ce13f7SAndroid Build Coastguard Worker       Operand *Src0 = legalizeUndef(Instr->getSrc(0));
2495*03ce13f7SAndroid Build Coastguard Worker       Operand *Src0RM = legalize(Src0, Legal_Reg | Legal_Mem);
2496*03ce13f7SAndroid Build Coastguard Worker       // t1 = trunc Src0RM; Dest = t1
2497*03ce13f7SAndroid Build Coastguard Worker       Variable *T = makeReg(DestTy);
2498*03ce13f7SAndroid Build Coastguard Worker       _mov(T, Src0RM);
2499*03ce13f7SAndroid Build Coastguard Worker       _mov(Dest, T);
2500*03ce13f7SAndroid Build Coastguard Worker     }
2501*03ce13f7SAndroid Build Coastguard Worker     break;
2502*03ce13f7SAndroid Build Coastguard Worker   }
2503*03ce13f7SAndroid Build Coastguard Worker   case InstCast::Fptrunc:
2504*03ce13f7SAndroid Build Coastguard Worker   case InstCast::Fpext: {
2505*03ce13f7SAndroid Build Coastguard Worker     Operand *Src0RM = legalize(Instr->getSrc(0), Legal_Reg | Legal_Mem);
2506*03ce13f7SAndroid Build Coastguard Worker     // t1 = cvt Src0RM; Dest = t1
2507*03ce13f7SAndroid Build Coastguard Worker     Variable *T = makeReg(DestTy);
2508*03ce13f7SAndroid Build Coastguard Worker     _cvt(T, Src0RM, Insts::Cvt::Float2float);
2509*03ce13f7SAndroid Build Coastguard Worker     _mov(Dest, T);
2510*03ce13f7SAndroid Build Coastguard Worker     break;
2511*03ce13f7SAndroid Build Coastguard Worker   }
2512*03ce13f7SAndroid Build Coastguard Worker   case InstCast::Fptosi:
2513*03ce13f7SAndroid Build Coastguard Worker     if (isVectorType(DestTy)) {
2514*03ce13f7SAndroid Build Coastguard Worker       assert(DestTy == IceType_v4i32);
2515*03ce13f7SAndroid Build Coastguard Worker       assert(Instr->getSrc(0)->getType() == IceType_v4f32);
2516*03ce13f7SAndroid Build Coastguard Worker       Operand *Src0R = legalizeToReg(Instr->getSrc(0));
2517*03ce13f7SAndroid Build Coastguard Worker       Variable *T = makeReg(DestTy);
2518*03ce13f7SAndroid Build Coastguard Worker       _cvt(T, Src0R, Insts::Cvt::Tps2dq);
2519*03ce13f7SAndroid Build Coastguard Worker       _movp(Dest, T);
2520*03ce13f7SAndroid Build Coastguard Worker     } else {
2521*03ce13f7SAndroid Build Coastguard Worker       Operand *Src0RM = legalize(Instr->getSrc(0), Legal_Reg | Legal_Mem);
2522*03ce13f7SAndroid Build Coastguard Worker       // t1.i32 = cvt Src0RM; t2.dest_type = t1; Dest = t2.dest_type
2523*03ce13f7SAndroid Build Coastguard Worker       Variable *T_1 = nullptr;
2524*03ce13f7SAndroid Build Coastguard Worker       if (DestTy == IceType_i64) {
2525*03ce13f7SAndroid Build Coastguard Worker         T_1 = makeReg(IceType_i64);
2526*03ce13f7SAndroid Build Coastguard Worker       } else {
2527*03ce13f7SAndroid Build Coastguard Worker         assert(DestTy != IceType_i64);
2528*03ce13f7SAndroid Build Coastguard Worker         T_1 = makeReg(IceType_i32);
2529*03ce13f7SAndroid Build Coastguard Worker       }
2530*03ce13f7SAndroid Build Coastguard Worker       // cvt() requires its integer argument to be a GPR.
2531*03ce13f7SAndroid Build Coastguard Worker       Variable *T_2 = makeReg(DestTy);
2532*03ce13f7SAndroid Build Coastguard Worker       if (isByteSizedType(DestTy)) {
2533*03ce13f7SAndroid Build Coastguard Worker         assert(T_1->getType() == IceType_i32);
2534*03ce13f7SAndroid Build Coastguard Worker         T_1->setRegClass(RCX86_Is32To8);
2535*03ce13f7SAndroid Build Coastguard Worker         T_2->setRegClass(RCX86_IsTrunc8Rcvr);
2536*03ce13f7SAndroid Build Coastguard Worker       }
2537*03ce13f7SAndroid Build Coastguard Worker       _cvt(T_1, Src0RM, Insts::Cvt::Tss2si);
2538*03ce13f7SAndroid Build Coastguard Worker       _mov(T_2, T_1); // T_1 and T_2 may have different integer types
2539*03ce13f7SAndroid Build Coastguard Worker       if (DestTy == IceType_i1)
2540*03ce13f7SAndroid Build Coastguard Worker         _and(T_2, Ctx->getConstantInt1(1));
2541*03ce13f7SAndroid Build Coastguard Worker       _mov(Dest, T_2);
2542*03ce13f7SAndroid Build Coastguard Worker     }
2543*03ce13f7SAndroid Build Coastguard Worker     break;
2544*03ce13f7SAndroid Build Coastguard Worker   case InstCast::Fptoui:
2545*03ce13f7SAndroid Build Coastguard Worker     if (isVectorType(DestTy)) {
2546*03ce13f7SAndroid Build Coastguard Worker       llvm::report_fatal_error("Helper call was expected");
2547*03ce13f7SAndroid Build Coastguard Worker     } else if (DestTy == IceType_i64) {
2548*03ce13f7SAndroid Build Coastguard Worker       llvm::report_fatal_error("Helper call was expected");
2549*03ce13f7SAndroid Build Coastguard Worker     } else {
2550*03ce13f7SAndroid Build Coastguard Worker       Operand *Src0RM = legalize(Instr->getSrc(0), Legal_Reg | Legal_Mem);
2551*03ce13f7SAndroid Build Coastguard Worker       // t1.i32 = cvt Src0RM; t2.dest_type = t1; Dest = t2.dest_type
2552*03ce13f7SAndroid Build Coastguard Worker       assert(DestTy != IceType_i64);
2553*03ce13f7SAndroid Build Coastguard Worker       Variable *T_1 = nullptr;
2554*03ce13f7SAndroid Build Coastguard Worker       if (DestTy == IceType_i32) {
2555*03ce13f7SAndroid Build Coastguard Worker         T_1 = makeReg(IceType_i64);
2556*03ce13f7SAndroid Build Coastguard Worker       } else {
2557*03ce13f7SAndroid Build Coastguard Worker         assert(DestTy != IceType_i32);
2558*03ce13f7SAndroid Build Coastguard Worker         T_1 = makeReg(IceType_i32);
2559*03ce13f7SAndroid Build Coastguard Worker       }
2560*03ce13f7SAndroid Build Coastguard Worker       Variable *T_2 = makeReg(DestTy);
2561*03ce13f7SAndroid Build Coastguard Worker       if (isByteSizedType(DestTy)) {
2562*03ce13f7SAndroid Build Coastguard Worker         assert(T_1->getType() == IceType_i32);
2563*03ce13f7SAndroid Build Coastguard Worker         T_1->setRegClass(RCX86_Is32To8);
2564*03ce13f7SAndroid Build Coastguard Worker         T_2->setRegClass(RCX86_IsTrunc8Rcvr);
2565*03ce13f7SAndroid Build Coastguard Worker       }
2566*03ce13f7SAndroid Build Coastguard Worker       _cvt(T_1, Src0RM, Insts::Cvt::Tss2si);
2567*03ce13f7SAndroid Build Coastguard Worker       _mov(T_2, T_1); // T_1 and T_2 may have different integer types
2568*03ce13f7SAndroid Build Coastguard Worker       if (DestTy == IceType_i1)
2569*03ce13f7SAndroid Build Coastguard Worker         _and(T_2, Ctx->getConstantInt1(1));
2570*03ce13f7SAndroid Build Coastguard Worker       _mov(Dest, T_2);
2571*03ce13f7SAndroid Build Coastguard Worker     }
2572*03ce13f7SAndroid Build Coastguard Worker     break;
2573*03ce13f7SAndroid Build Coastguard Worker   case InstCast::Sitofp:
2574*03ce13f7SAndroid Build Coastguard Worker     if (isVectorType(DestTy)) {
2575*03ce13f7SAndroid Build Coastguard Worker       assert(DestTy == IceType_v4f32);
2576*03ce13f7SAndroid Build Coastguard Worker       assert(Instr->getSrc(0)->getType() == IceType_v4i32);
2577*03ce13f7SAndroid Build Coastguard Worker       Operand *Src0R = legalizeToReg(Instr->getSrc(0));
2578*03ce13f7SAndroid Build Coastguard Worker       Variable *T = makeReg(DestTy);
2579*03ce13f7SAndroid Build Coastguard Worker       _cvt(T, Src0R, Insts::Cvt::Dq2ps);
2580*03ce13f7SAndroid Build Coastguard Worker       _movp(Dest, T);
2581*03ce13f7SAndroid Build Coastguard Worker     } else {
2582*03ce13f7SAndroid Build Coastguard Worker       Operand *Src0RM = legalize(Instr->getSrc(0), Legal_Reg | Legal_Mem);
2583*03ce13f7SAndroid Build Coastguard Worker       // Sign-extend the operand.
2584*03ce13f7SAndroid Build Coastguard Worker       // t1.i32 = movsx Src0RM; t2 = Cvt t1.i32; Dest = t2
2585*03ce13f7SAndroid Build Coastguard Worker       Variable *T_1 = nullptr;
2586*03ce13f7SAndroid Build Coastguard Worker       if (Src0RM->getType() == IceType_i64) {
2587*03ce13f7SAndroid Build Coastguard Worker         T_1 = makeReg(IceType_i64);
2588*03ce13f7SAndroid Build Coastguard Worker       } else {
2589*03ce13f7SAndroid Build Coastguard Worker         assert(Src0RM->getType() != IceType_i64);
2590*03ce13f7SAndroid Build Coastguard Worker         T_1 = makeReg(IceType_i32);
2591*03ce13f7SAndroid Build Coastguard Worker       }
2592*03ce13f7SAndroid Build Coastguard Worker       Variable *T_2 = makeReg(DestTy);
2593*03ce13f7SAndroid Build Coastguard Worker       if (Src0RM->getType() == T_1->getType())
2594*03ce13f7SAndroid Build Coastguard Worker         _mov(T_1, Src0RM);
2595*03ce13f7SAndroid Build Coastguard Worker       else
2596*03ce13f7SAndroid Build Coastguard Worker         _movsx(T_1, Src0RM);
2597*03ce13f7SAndroid Build Coastguard Worker       _cvt(T_2, T_1, Insts::Cvt::Si2ss);
2598*03ce13f7SAndroid Build Coastguard Worker       _mov(Dest, T_2);
2599*03ce13f7SAndroid Build Coastguard Worker     }
2600*03ce13f7SAndroid Build Coastguard Worker     break;
2601*03ce13f7SAndroid Build Coastguard Worker   case InstCast::Uitofp: {
2602*03ce13f7SAndroid Build Coastguard Worker     Operand *Src0 = Instr->getSrc(0);
2603*03ce13f7SAndroid Build Coastguard Worker     if (isVectorType(Src0->getType())) {
2604*03ce13f7SAndroid Build Coastguard Worker       llvm::report_fatal_error("Helper call was expected");
2605*03ce13f7SAndroid Build Coastguard Worker     } else if (Src0->getType() == IceType_i64) {
2606*03ce13f7SAndroid Build Coastguard Worker       llvm::report_fatal_error("Helper call was expected");
2607*03ce13f7SAndroid Build Coastguard Worker     } else {
2608*03ce13f7SAndroid Build Coastguard Worker       Operand *Src0RM = legalize(Src0, Legal_Reg | Legal_Mem);
2609*03ce13f7SAndroid Build Coastguard Worker       // Zero-extend the operand.
2610*03ce13f7SAndroid Build Coastguard Worker       // t1.i32 = movzx Src0RM; t2 = Cvt t1.i32; Dest = t2
2611*03ce13f7SAndroid Build Coastguard Worker       Variable *T_1 = nullptr;
2612*03ce13f7SAndroid Build Coastguard Worker       if (Src0RM->getType() == IceType_i32) {
2613*03ce13f7SAndroid Build Coastguard Worker         T_1 = makeReg(IceType_i64);
2614*03ce13f7SAndroid Build Coastguard Worker       } else {
2615*03ce13f7SAndroid Build Coastguard Worker         assert(Src0RM->getType() != IceType_i64);
2616*03ce13f7SAndroid Build Coastguard Worker         T_1 = makeReg(IceType_i32);
2617*03ce13f7SAndroid Build Coastguard Worker       }
2618*03ce13f7SAndroid Build Coastguard Worker       Variable *T_2 = makeReg(DestTy);
2619*03ce13f7SAndroid Build Coastguard Worker       if (Src0RM->getType() == T_1->getType())
2620*03ce13f7SAndroid Build Coastguard Worker         _mov(T_1, Src0RM);
2621*03ce13f7SAndroid Build Coastguard Worker       else
2622*03ce13f7SAndroid Build Coastguard Worker         _movzx(T_1, Src0RM)->setMustKeep();
2623*03ce13f7SAndroid Build Coastguard Worker       _cvt(T_2, T_1, Insts::Cvt::Si2ss);
2624*03ce13f7SAndroid Build Coastguard Worker       _mov(Dest, T_2);
2625*03ce13f7SAndroid Build Coastguard Worker     }
2626*03ce13f7SAndroid Build Coastguard Worker     break;
2627*03ce13f7SAndroid Build Coastguard Worker   }
2628*03ce13f7SAndroid Build Coastguard Worker   case InstCast::Bitcast: {
2629*03ce13f7SAndroid Build Coastguard Worker     Operand *Src0 = Instr->getSrc(0);
2630*03ce13f7SAndroid Build Coastguard Worker     if (DestTy == Src0->getType()) {
2631*03ce13f7SAndroid Build Coastguard Worker       auto *Assign = InstAssign::create(Func, Dest, Src0);
2632*03ce13f7SAndroid Build Coastguard Worker       lowerAssign(Assign);
2633*03ce13f7SAndroid Build Coastguard Worker       return;
2634*03ce13f7SAndroid Build Coastguard Worker     }
2635*03ce13f7SAndroid Build Coastguard Worker     switch (DestTy) {
2636*03ce13f7SAndroid Build Coastguard Worker     default:
2637*03ce13f7SAndroid Build Coastguard Worker       llvm_unreachable("Unexpected Bitcast dest type");
2638*03ce13f7SAndroid Build Coastguard Worker     case IceType_i8: {
2639*03ce13f7SAndroid Build Coastguard Worker       llvm::report_fatal_error("Helper call was expected");
2640*03ce13f7SAndroid Build Coastguard Worker     } break;
2641*03ce13f7SAndroid Build Coastguard Worker     case IceType_i16: {
2642*03ce13f7SAndroid Build Coastguard Worker       llvm::report_fatal_error("Helper call was expected");
2643*03ce13f7SAndroid Build Coastguard Worker     } break;
2644*03ce13f7SAndroid Build Coastguard Worker     case IceType_i32:
2645*03ce13f7SAndroid Build Coastguard Worker     case IceType_f32: {
2646*03ce13f7SAndroid Build Coastguard Worker       Variable *Src0R = legalizeToReg(Src0);
2647*03ce13f7SAndroid Build Coastguard Worker       Variable *T = makeReg(DestTy);
2648*03ce13f7SAndroid Build Coastguard Worker       _movd(T, Src0R);
2649*03ce13f7SAndroid Build Coastguard Worker       _mov(Dest, T);
2650*03ce13f7SAndroid Build Coastguard Worker     } break;
2651*03ce13f7SAndroid Build Coastguard Worker     case IceType_i64: {
2652*03ce13f7SAndroid Build Coastguard Worker       assert(Src0->getType() == IceType_f64);
2653*03ce13f7SAndroid Build Coastguard Worker       Variable *Src0R = legalizeToReg(Src0);
2654*03ce13f7SAndroid Build Coastguard Worker       Variable *T = makeReg(IceType_i64);
2655*03ce13f7SAndroid Build Coastguard Worker       _movd(T, Src0R);
2656*03ce13f7SAndroid Build Coastguard Worker       _mov(Dest, T);
2657*03ce13f7SAndroid Build Coastguard Worker     } break;
2658*03ce13f7SAndroid Build Coastguard Worker     case IceType_f64: {
2659*03ce13f7SAndroid Build Coastguard Worker       assert(Src0->getType() == IceType_i64);
2660*03ce13f7SAndroid Build Coastguard Worker       Operand *Src0RM = legalize(Src0, Legal_Reg | Legal_Mem);
2661*03ce13f7SAndroid Build Coastguard Worker       Variable *T = makeReg(IceType_f64);
2662*03ce13f7SAndroid Build Coastguard Worker       _movd(T, Src0RM);
2663*03ce13f7SAndroid Build Coastguard Worker       _mov(Dest, T);
2664*03ce13f7SAndroid Build Coastguard Worker     } break;
2665*03ce13f7SAndroid Build Coastguard Worker     case IceType_v8i1: {
2666*03ce13f7SAndroid Build Coastguard Worker       llvm::report_fatal_error("Helper call was expected");
2667*03ce13f7SAndroid Build Coastguard Worker     } break;
2668*03ce13f7SAndroid Build Coastguard Worker     case IceType_v16i1: {
2669*03ce13f7SAndroid Build Coastguard Worker       llvm::report_fatal_error("Helper call was expected");
2670*03ce13f7SAndroid Build Coastguard Worker     } break;
2671*03ce13f7SAndroid Build Coastguard Worker     case IceType_v8i16:
2672*03ce13f7SAndroid Build Coastguard Worker     case IceType_v16i8:
2673*03ce13f7SAndroid Build Coastguard Worker     case IceType_v4i32:
2674*03ce13f7SAndroid Build Coastguard Worker     case IceType_v4f32: {
2675*03ce13f7SAndroid Build Coastguard Worker       if (Src0->getType() == IceType_i32) {
2676*03ce13f7SAndroid Build Coastguard Worker         // Bitcast requires equal type sizes, which isn't strictly the case
2677*03ce13f7SAndroid Build Coastguard Worker         // between scalars and vectors, but to emulate v4i8 vectors one has to
2678*03ce13f7SAndroid Build Coastguard Worker         // use v16i8 vectors.
2679*03ce13f7SAndroid Build Coastguard Worker         Operand *Src0RM = legalize(Src0, Legal_Reg | Legal_Mem);
2680*03ce13f7SAndroid Build Coastguard Worker         Variable *T = makeReg(DestTy);
2681*03ce13f7SAndroid Build Coastguard Worker         _movd(T, Src0RM);
2682*03ce13f7SAndroid Build Coastguard Worker         _mov(Dest, T);
2683*03ce13f7SAndroid Build Coastguard Worker       } else {
2684*03ce13f7SAndroid Build Coastguard Worker         _movp(Dest, legalizeToReg(Src0));
2685*03ce13f7SAndroid Build Coastguard Worker       }
2686*03ce13f7SAndroid Build Coastguard Worker     } break;
2687*03ce13f7SAndroid Build Coastguard Worker     }
2688*03ce13f7SAndroid Build Coastguard Worker     break;
2689*03ce13f7SAndroid Build Coastguard Worker   }
2690*03ce13f7SAndroid Build Coastguard Worker   }
2691*03ce13f7SAndroid Build Coastguard Worker }
2692*03ce13f7SAndroid Build Coastguard Worker 
lowerExtractElement(const InstExtractElement * Instr)2693*03ce13f7SAndroid Build Coastguard Worker void TargetX8664::lowerExtractElement(const InstExtractElement *Instr) {
2694*03ce13f7SAndroid Build Coastguard Worker   Operand *SourceVectNotLegalized = Instr->getSrc(0);
2695*03ce13f7SAndroid Build Coastguard Worker   auto *ElementIndex = llvm::dyn_cast<ConstantInteger32>(Instr->getSrc(1));
2696*03ce13f7SAndroid Build Coastguard Worker   // Only constant indices are allowed in PNaCl IR.
2697*03ce13f7SAndroid Build Coastguard Worker   assert(ElementIndex);
2698*03ce13f7SAndroid Build Coastguard Worker 
2699*03ce13f7SAndroid Build Coastguard Worker   unsigned Index = ElementIndex->getValue();
2700*03ce13f7SAndroid Build Coastguard Worker   Type Ty = SourceVectNotLegalized->getType();
2701*03ce13f7SAndroid Build Coastguard Worker   Type ElementTy = typeElementType(Ty);
2702*03ce13f7SAndroid Build Coastguard Worker   Type InVectorElementTy = InstX86Base::getInVectorElementType(Ty);
2703*03ce13f7SAndroid Build Coastguard Worker 
2704*03ce13f7SAndroid Build Coastguard Worker   // TODO(wala): Determine the best lowering sequences for each type.
2705*03ce13f7SAndroid Build Coastguard Worker   bool CanUsePextr = Ty == IceType_v8i16 || Ty == IceType_v8i1 ||
2706*03ce13f7SAndroid Build Coastguard Worker                      (InstructionSet >= SSE4_1 && Ty != IceType_v4f32);
2707*03ce13f7SAndroid Build Coastguard Worker   Variable *ExtractedElementR =
2708*03ce13f7SAndroid Build Coastguard Worker       makeReg(CanUsePextr ? IceType_i32 : InVectorElementTy);
2709*03ce13f7SAndroid Build Coastguard Worker   if (CanUsePextr) {
2710*03ce13f7SAndroid Build Coastguard Worker     // Use pextrb, pextrw, or pextrd.  The "b" and "w" versions clear the upper
2711*03ce13f7SAndroid Build Coastguard Worker     // bits of the destination register, so we represent this by always
2712*03ce13f7SAndroid Build Coastguard Worker     // extracting into an i32 register.  The _mov into Dest below will do
2713*03ce13f7SAndroid Build Coastguard Worker     // truncation as necessary.
2714*03ce13f7SAndroid Build Coastguard Worker     Constant *Mask = Ctx->getConstantInt32(Index);
2715*03ce13f7SAndroid Build Coastguard Worker     Variable *SourceVectR = legalizeToReg(SourceVectNotLegalized);
2716*03ce13f7SAndroid Build Coastguard Worker     _pextr(ExtractedElementR, SourceVectR, Mask);
2717*03ce13f7SAndroid Build Coastguard Worker   } else if (Ty == IceType_v4i32 || Ty == IceType_v4f32 || Ty == IceType_v4i1) {
2718*03ce13f7SAndroid Build Coastguard Worker     // Use pshufd and movd/movss.
2719*03ce13f7SAndroid Build Coastguard Worker     Variable *T = nullptr;
2720*03ce13f7SAndroid Build Coastguard Worker     if (Index) {
2721*03ce13f7SAndroid Build Coastguard Worker       // The shuffle only needs to occur if the element to be extracted is not
2722*03ce13f7SAndroid Build Coastguard Worker       // at the lowest index.
2723*03ce13f7SAndroid Build Coastguard Worker       Constant *Mask = Ctx->getConstantInt32(Index);
2724*03ce13f7SAndroid Build Coastguard Worker       T = makeReg(Ty);
2725*03ce13f7SAndroid Build Coastguard Worker       _pshufd(T, legalize(SourceVectNotLegalized, Legal_Reg | Legal_Mem), Mask);
2726*03ce13f7SAndroid Build Coastguard Worker     } else {
2727*03ce13f7SAndroid Build Coastguard Worker       T = legalizeToReg(SourceVectNotLegalized);
2728*03ce13f7SAndroid Build Coastguard Worker     }
2729*03ce13f7SAndroid Build Coastguard Worker 
2730*03ce13f7SAndroid Build Coastguard Worker     if (InVectorElementTy == IceType_i32) {
2731*03ce13f7SAndroid Build Coastguard Worker       _movd(ExtractedElementR, T);
2732*03ce13f7SAndroid Build Coastguard Worker     } else { // Ty == IceType_f32
2733*03ce13f7SAndroid Build Coastguard Worker       // TODO(wala): _movss is only used here because _mov does not allow a
2734*03ce13f7SAndroid Build Coastguard Worker       // vector source and a scalar destination.  _mov should be able to be
2735*03ce13f7SAndroid Build Coastguard Worker       // used here.
2736*03ce13f7SAndroid Build Coastguard Worker       // _movss is a binary instruction, so the FakeDef is needed to keep the
2737*03ce13f7SAndroid Build Coastguard Worker       // live range analysis consistent.
2738*03ce13f7SAndroid Build Coastguard Worker       Context.insert<InstFakeDef>(ExtractedElementR);
2739*03ce13f7SAndroid Build Coastguard Worker       _movss(ExtractedElementR, T);
2740*03ce13f7SAndroid Build Coastguard Worker     }
2741*03ce13f7SAndroid Build Coastguard Worker   } else {
2742*03ce13f7SAndroid Build Coastguard Worker     assert(Ty == IceType_v16i8 || Ty == IceType_v16i1);
2743*03ce13f7SAndroid Build Coastguard Worker     // Spill the value to a stack slot and do the extraction in memory.
2744*03ce13f7SAndroid Build Coastguard Worker     //
2745*03ce13f7SAndroid Build Coastguard Worker     // TODO(wala): use legalize(SourceVectNotLegalized, Legal_Mem) when support
2746*03ce13f7SAndroid Build Coastguard Worker     // for legalizing to mem is implemented.
2747*03ce13f7SAndroid Build Coastguard Worker     Variable *Slot = Func->makeVariable(Ty);
2748*03ce13f7SAndroid Build Coastguard Worker     Slot->setMustNotHaveReg();
2749*03ce13f7SAndroid Build Coastguard Worker     _movp(Slot, legalizeToReg(SourceVectNotLegalized));
2750*03ce13f7SAndroid Build Coastguard Worker 
2751*03ce13f7SAndroid Build Coastguard Worker     // Compute the location of the element in memory.
2752*03ce13f7SAndroid Build Coastguard Worker     unsigned Offset = Index * typeWidthInBytes(InVectorElementTy);
2753*03ce13f7SAndroid Build Coastguard Worker     X86OperandMem *Loc =
2754*03ce13f7SAndroid Build Coastguard Worker         getMemoryOperandForStackSlot(InVectorElementTy, Slot, Offset);
2755*03ce13f7SAndroid Build Coastguard Worker     _mov(ExtractedElementR, Loc);
2756*03ce13f7SAndroid Build Coastguard Worker   }
2757*03ce13f7SAndroid Build Coastguard Worker 
2758*03ce13f7SAndroid Build Coastguard Worker   if (ElementTy == IceType_i1) {
2759*03ce13f7SAndroid Build Coastguard Worker     // Truncate extracted integers to i1s if necessary.
2760*03ce13f7SAndroid Build Coastguard Worker     Variable *T = makeReg(IceType_i1);
2761*03ce13f7SAndroid Build Coastguard Worker     InstCast *Cast =
2762*03ce13f7SAndroid Build Coastguard Worker         InstCast::create(Func, InstCast::Trunc, T, ExtractedElementR);
2763*03ce13f7SAndroid Build Coastguard Worker     lowerCast(Cast);
2764*03ce13f7SAndroid Build Coastguard Worker     ExtractedElementR = T;
2765*03ce13f7SAndroid Build Coastguard Worker   }
2766*03ce13f7SAndroid Build Coastguard Worker 
2767*03ce13f7SAndroid Build Coastguard Worker   // Copy the element to the destination.
2768*03ce13f7SAndroid Build Coastguard Worker   Variable *Dest = Instr->getDest();
2769*03ce13f7SAndroid Build Coastguard Worker   _mov(Dest, ExtractedElementR);
2770*03ce13f7SAndroid Build Coastguard Worker }
2771*03ce13f7SAndroid Build Coastguard Worker 
lowerFcmp(const InstFcmp * Fcmp)2772*03ce13f7SAndroid Build Coastguard Worker void TargetX8664::lowerFcmp(const InstFcmp *Fcmp) {
2773*03ce13f7SAndroid Build Coastguard Worker   Variable *Dest = Fcmp->getDest();
2774*03ce13f7SAndroid Build Coastguard Worker 
2775*03ce13f7SAndroid Build Coastguard Worker   if (isVectorType(Dest->getType())) {
2776*03ce13f7SAndroid Build Coastguard Worker     lowerFcmpVector(Fcmp);
2777*03ce13f7SAndroid Build Coastguard Worker   } else {
2778*03ce13f7SAndroid Build Coastguard Worker     constexpr Inst *Consumer = nullptr;
2779*03ce13f7SAndroid Build Coastguard Worker     lowerFcmpAndConsumer(Fcmp, Consumer);
2780*03ce13f7SAndroid Build Coastguard Worker   }
2781*03ce13f7SAndroid Build Coastguard Worker }
2782*03ce13f7SAndroid Build Coastguard Worker 
lowerFcmpAndConsumer(const InstFcmp * Fcmp,const Inst * Consumer)2783*03ce13f7SAndroid Build Coastguard Worker void TargetX8664::lowerFcmpAndConsumer(const InstFcmp *Fcmp,
2784*03ce13f7SAndroid Build Coastguard Worker                                        const Inst *Consumer) {
2785*03ce13f7SAndroid Build Coastguard Worker   Operand *Src0 = Fcmp->getSrc(0);
2786*03ce13f7SAndroid Build Coastguard Worker   Operand *Src1 = Fcmp->getSrc(1);
2787*03ce13f7SAndroid Build Coastguard Worker   Variable *Dest = Fcmp->getDest();
2788*03ce13f7SAndroid Build Coastguard Worker 
2789*03ce13f7SAndroid Build Coastguard Worker   if (Consumer != nullptr) {
2790*03ce13f7SAndroid Build Coastguard Worker     if (auto *Select = llvm::dyn_cast<InstSelect>(Consumer)) {
2791*03ce13f7SAndroid Build Coastguard Worker       if (lowerOptimizeFcmpSelect(Fcmp, Select))
2792*03ce13f7SAndroid Build Coastguard Worker         return;
2793*03ce13f7SAndroid Build Coastguard Worker     }
2794*03ce13f7SAndroid Build Coastguard Worker   }
2795*03ce13f7SAndroid Build Coastguard Worker 
2796*03ce13f7SAndroid Build Coastguard Worker   if (isVectorType(Dest->getType())) {
2797*03ce13f7SAndroid Build Coastguard Worker     lowerFcmp(Fcmp);
2798*03ce13f7SAndroid Build Coastguard Worker     if (Consumer != nullptr)
2799*03ce13f7SAndroid Build Coastguard Worker       lowerSelectVector(llvm::cast<InstSelect>(Consumer));
2800*03ce13f7SAndroid Build Coastguard Worker     return;
2801*03ce13f7SAndroid Build Coastguard Worker   }
2802*03ce13f7SAndroid Build Coastguard Worker 
2803*03ce13f7SAndroid Build Coastguard Worker   // Lowering a = fcmp cond, b, c
2804*03ce13f7SAndroid Build Coastguard Worker   //   ucomiss b, c       /* only if C1 != Br_None */
2805*03ce13f7SAndroid Build Coastguard Worker   //                      /* but swap b,c order if SwapOperands==true */
2806*03ce13f7SAndroid Build Coastguard Worker   //   mov a, <default>
2807*03ce13f7SAndroid Build Coastguard Worker   //   j<C1> label        /* only if C1 != Br_None */
2808*03ce13f7SAndroid Build Coastguard Worker   //   j<C2> label        /* only if C2 != Br_None */
2809*03ce13f7SAndroid Build Coastguard Worker   //   FakeUse(a)         /* only if C1 != Br_None */
2810*03ce13f7SAndroid Build Coastguard Worker   //   mov a, !<default>  /* only if C1 != Br_None */
2811*03ce13f7SAndroid Build Coastguard Worker   //   label:             /* only if C1 != Br_None */
2812*03ce13f7SAndroid Build Coastguard Worker   //
2813*03ce13f7SAndroid Build Coastguard Worker   // setcc lowering when C1 != Br_None && C2 == Br_None:
2814*03ce13f7SAndroid Build Coastguard Worker   //   ucomiss b, c       /* but swap b,c order if SwapOperands==true */
2815*03ce13f7SAndroid Build Coastguard Worker   //   setcc a, C1
2816*03ce13f7SAndroid Build Coastguard Worker   InstFcmp::FCond Condition = Fcmp->getCondition();
2817*03ce13f7SAndroid Build Coastguard Worker   assert(static_cast<size_t>(Condition) < TableFcmpSize);
2818*03ce13f7SAndroid Build Coastguard Worker   if (TableFcmp[Condition].SwapScalarOperands)
2819*03ce13f7SAndroid Build Coastguard Worker     std::swap(Src0, Src1);
2820*03ce13f7SAndroid Build Coastguard Worker   const bool HasC1 = (TableFcmp[Condition].C1 != CondX86::Br_None);
2821*03ce13f7SAndroid Build Coastguard Worker   const bool HasC2 = (TableFcmp[Condition].C2 != CondX86::Br_None);
2822*03ce13f7SAndroid Build Coastguard Worker   if (HasC1) {
2823*03ce13f7SAndroid Build Coastguard Worker     Src0 = legalize(Src0);
2824*03ce13f7SAndroid Build Coastguard Worker     Operand *Src1RM = legalize(Src1, Legal_Reg | Legal_Mem);
2825*03ce13f7SAndroid Build Coastguard Worker     Variable *T = nullptr;
2826*03ce13f7SAndroid Build Coastguard Worker     _mov(T, Src0);
2827*03ce13f7SAndroid Build Coastguard Worker     _ucomiss(T, Src1RM);
2828*03ce13f7SAndroid Build Coastguard Worker     if (!HasC2) {
2829*03ce13f7SAndroid Build Coastguard Worker       assert(TableFcmp[Condition].Default);
2830*03ce13f7SAndroid Build Coastguard Worker       setccOrConsumer(TableFcmp[Condition].C1, Dest, Consumer);
2831*03ce13f7SAndroid Build Coastguard Worker       return;
2832*03ce13f7SAndroid Build Coastguard Worker     }
2833*03ce13f7SAndroid Build Coastguard Worker   }
2834*03ce13f7SAndroid Build Coastguard Worker   int32_t IntDefault = TableFcmp[Condition].Default;
2835*03ce13f7SAndroid Build Coastguard Worker   if (Consumer == nullptr) {
2836*03ce13f7SAndroid Build Coastguard Worker     Constant *Default = Ctx->getConstantInt(Dest->getType(), IntDefault);
2837*03ce13f7SAndroid Build Coastguard Worker     _mov(Dest, Default);
2838*03ce13f7SAndroid Build Coastguard Worker     if (HasC1) {
2839*03ce13f7SAndroid Build Coastguard Worker       InstX86Label *Label = InstX86Label::create(Func, this);
2840*03ce13f7SAndroid Build Coastguard Worker       _br(TableFcmp[Condition].C1, Label);
2841*03ce13f7SAndroid Build Coastguard Worker       if (HasC2) {
2842*03ce13f7SAndroid Build Coastguard Worker         _br(TableFcmp[Condition].C2, Label);
2843*03ce13f7SAndroid Build Coastguard Worker       }
2844*03ce13f7SAndroid Build Coastguard Worker       Constant *NonDefault = Ctx->getConstantInt(Dest->getType(), !IntDefault);
2845*03ce13f7SAndroid Build Coastguard Worker       _redefined(_mov(Dest, NonDefault));
2846*03ce13f7SAndroid Build Coastguard Worker       Context.insert(Label);
2847*03ce13f7SAndroid Build Coastguard Worker     }
2848*03ce13f7SAndroid Build Coastguard Worker     return;
2849*03ce13f7SAndroid Build Coastguard Worker   }
2850*03ce13f7SAndroid Build Coastguard Worker   if (const auto *Br = llvm::dyn_cast<InstBr>(Consumer)) {
2851*03ce13f7SAndroid Build Coastguard Worker     CfgNode *TrueSucc = Br->getTargetTrue();
2852*03ce13f7SAndroid Build Coastguard Worker     CfgNode *FalseSucc = Br->getTargetFalse();
2853*03ce13f7SAndroid Build Coastguard Worker     if (IntDefault != 0)
2854*03ce13f7SAndroid Build Coastguard Worker       std::swap(TrueSucc, FalseSucc);
2855*03ce13f7SAndroid Build Coastguard Worker     if (HasC1) {
2856*03ce13f7SAndroid Build Coastguard Worker       _br(TableFcmp[Condition].C1, FalseSucc);
2857*03ce13f7SAndroid Build Coastguard Worker       if (HasC2) {
2858*03ce13f7SAndroid Build Coastguard Worker         _br(TableFcmp[Condition].C2, FalseSucc);
2859*03ce13f7SAndroid Build Coastguard Worker       }
2860*03ce13f7SAndroid Build Coastguard Worker       _br(TrueSucc);
2861*03ce13f7SAndroid Build Coastguard Worker       return;
2862*03ce13f7SAndroid Build Coastguard Worker     }
2863*03ce13f7SAndroid Build Coastguard Worker     _br(FalseSucc);
2864*03ce13f7SAndroid Build Coastguard Worker     return;
2865*03ce13f7SAndroid Build Coastguard Worker   }
2866*03ce13f7SAndroid Build Coastguard Worker   if (auto *Select = llvm::dyn_cast<InstSelect>(Consumer)) {
2867*03ce13f7SAndroid Build Coastguard Worker     Operand *SrcT = Select->getTrueOperand();
2868*03ce13f7SAndroid Build Coastguard Worker     Operand *SrcF = Select->getFalseOperand();
2869*03ce13f7SAndroid Build Coastguard Worker     Variable *SelectDest = Select->getDest();
2870*03ce13f7SAndroid Build Coastguard Worker     if (IntDefault != 0)
2871*03ce13f7SAndroid Build Coastguard Worker       std::swap(SrcT, SrcF);
2872*03ce13f7SAndroid Build Coastguard Worker     lowerMove(SelectDest, SrcF, false);
2873*03ce13f7SAndroid Build Coastguard Worker     if (HasC1) {
2874*03ce13f7SAndroid Build Coastguard Worker       InstX86Label *Label = InstX86Label::create(Func, this);
2875*03ce13f7SAndroid Build Coastguard Worker       _br(TableFcmp[Condition].C1, Label);
2876*03ce13f7SAndroid Build Coastguard Worker       if (HasC2) {
2877*03ce13f7SAndroid Build Coastguard Worker         _br(TableFcmp[Condition].C2, Label);
2878*03ce13f7SAndroid Build Coastguard Worker       }
2879*03ce13f7SAndroid Build Coastguard Worker       static constexpr bool IsRedefinition = true;
2880*03ce13f7SAndroid Build Coastguard Worker       lowerMove(SelectDest, SrcT, IsRedefinition);
2881*03ce13f7SAndroid Build Coastguard Worker       Context.insert(Label);
2882*03ce13f7SAndroid Build Coastguard Worker     }
2883*03ce13f7SAndroid Build Coastguard Worker     return;
2884*03ce13f7SAndroid Build Coastguard Worker   }
2885*03ce13f7SAndroid Build Coastguard Worker   llvm::report_fatal_error("Unexpected consumer type");
2886*03ce13f7SAndroid Build Coastguard Worker }
2887*03ce13f7SAndroid Build Coastguard Worker 
lowerFcmpVector(const InstFcmp * Fcmp)2888*03ce13f7SAndroid Build Coastguard Worker void TargetX8664::lowerFcmpVector(const InstFcmp *Fcmp) {
2889*03ce13f7SAndroid Build Coastguard Worker   Operand *Src0 = Fcmp->getSrc(0);
2890*03ce13f7SAndroid Build Coastguard Worker   Operand *Src1 = Fcmp->getSrc(1);
2891*03ce13f7SAndroid Build Coastguard Worker   Variable *Dest = Fcmp->getDest();
2892*03ce13f7SAndroid Build Coastguard Worker 
2893*03ce13f7SAndroid Build Coastguard Worker   if (!isVectorType(Dest->getType()))
2894*03ce13f7SAndroid Build Coastguard Worker     llvm::report_fatal_error("Expected vector compare");
2895*03ce13f7SAndroid Build Coastguard Worker 
2896*03ce13f7SAndroid Build Coastguard Worker   InstFcmp::FCond Condition = Fcmp->getCondition();
2897*03ce13f7SAndroid Build Coastguard Worker   assert(static_cast<size_t>(Condition) < TableFcmpSize);
2898*03ce13f7SAndroid Build Coastguard Worker 
2899*03ce13f7SAndroid Build Coastguard Worker   if (TableFcmp[Condition].SwapVectorOperands)
2900*03ce13f7SAndroid Build Coastguard Worker     std::swap(Src0, Src1);
2901*03ce13f7SAndroid Build Coastguard Worker 
2902*03ce13f7SAndroid Build Coastguard Worker   Variable *T = nullptr;
2903*03ce13f7SAndroid Build Coastguard Worker 
2904*03ce13f7SAndroid Build Coastguard Worker   if (Condition == InstFcmp::True) {
2905*03ce13f7SAndroid Build Coastguard Worker     // makeVectorOfOnes() requires an integer vector type.
2906*03ce13f7SAndroid Build Coastguard Worker     T = makeVectorOfMinusOnes(IceType_v4i32);
2907*03ce13f7SAndroid Build Coastguard Worker   } else if (Condition == InstFcmp::False) {
2908*03ce13f7SAndroid Build Coastguard Worker     T = makeVectorOfZeros(Dest->getType());
2909*03ce13f7SAndroid Build Coastguard Worker   } else {
2910*03ce13f7SAndroid Build Coastguard Worker     Operand *Src0RM = legalize(Src0, Legal_Reg | Legal_Mem);
2911*03ce13f7SAndroid Build Coastguard Worker     Operand *Src1RM = legalize(Src1, Legal_Reg | Legal_Mem);
2912*03ce13f7SAndroid Build Coastguard Worker     if (llvm::isa<X86OperandMem>(Src1RM))
2913*03ce13f7SAndroid Build Coastguard Worker       Src1RM = legalizeToReg(Src1RM);
2914*03ce13f7SAndroid Build Coastguard Worker 
2915*03ce13f7SAndroid Build Coastguard Worker     switch (Condition) {
2916*03ce13f7SAndroid Build Coastguard Worker     default: {
2917*03ce13f7SAndroid Build Coastguard Worker       const CmppsCond Predicate = TableFcmp[Condition].Predicate;
2918*03ce13f7SAndroid Build Coastguard Worker       assert(Predicate != CondX86::Cmpps_Invalid);
2919*03ce13f7SAndroid Build Coastguard Worker       T = makeReg(Src0RM->getType());
2920*03ce13f7SAndroid Build Coastguard Worker       _movp(T, Src0RM);
2921*03ce13f7SAndroid Build Coastguard Worker       _cmpps(T, Src1RM, Predicate);
2922*03ce13f7SAndroid Build Coastguard Worker     } break;
2923*03ce13f7SAndroid Build Coastguard Worker     case InstFcmp::One: {
2924*03ce13f7SAndroid Build Coastguard Worker       // Check both unequal and ordered.
2925*03ce13f7SAndroid Build Coastguard Worker       T = makeReg(Src0RM->getType());
2926*03ce13f7SAndroid Build Coastguard Worker       Variable *T2 = makeReg(Src0RM->getType());
2927*03ce13f7SAndroid Build Coastguard Worker       _movp(T, Src0RM);
2928*03ce13f7SAndroid Build Coastguard Worker       _cmpps(T, Src1RM, CondX86::Cmpps_neq);
2929*03ce13f7SAndroid Build Coastguard Worker       _movp(T2, Src0RM);
2930*03ce13f7SAndroid Build Coastguard Worker       _cmpps(T2, Src1RM, CondX86::Cmpps_ord);
2931*03ce13f7SAndroid Build Coastguard Worker       _pand(T, T2);
2932*03ce13f7SAndroid Build Coastguard Worker     } break;
2933*03ce13f7SAndroid Build Coastguard Worker     case InstFcmp::Ueq: {
2934*03ce13f7SAndroid Build Coastguard Worker       // Check both equal or unordered.
2935*03ce13f7SAndroid Build Coastguard Worker       T = makeReg(Src0RM->getType());
2936*03ce13f7SAndroid Build Coastguard Worker       Variable *T2 = makeReg(Src0RM->getType());
2937*03ce13f7SAndroid Build Coastguard Worker       _movp(T, Src0RM);
2938*03ce13f7SAndroid Build Coastguard Worker       _cmpps(T, Src1RM, CondX86::Cmpps_eq);
2939*03ce13f7SAndroid Build Coastguard Worker       _movp(T2, Src0RM);
2940*03ce13f7SAndroid Build Coastguard Worker       _cmpps(T2, Src1RM, CondX86::Cmpps_unord);
2941*03ce13f7SAndroid Build Coastguard Worker       _por(T, T2);
2942*03ce13f7SAndroid Build Coastguard Worker     } break;
2943*03ce13f7SAndroid Build Coastguard Worker     }
2944*03ce13f7SAndroid Build Coastguard Worker   }
2945*03ce13f7SAndroid Build Coastguard Worker 
2946*03ce13f7SAndroid Build Coastguard Worker   assert(T != nullptr);
2947*03ce13f7SAndroid Build Coastguard Worker   _movp(Dest, T);
2948*03ce13f7SAndroid Build Coastguard Worker   eliminateNextVectorSextInstruction(Dest);
2949*03ce13f7SAndroid Build Coastguard Worker }
2950*03ce13f7SAndroid Build Coastguard Worker 
isZero(const Operand * Opnd)2951*03ce13f7SAndroid Build Coastguard Worker inline bool isZero(const Operand *Opnd) {
2952*03ce13f7SAndroid Build Coastguard Worker   if (auto *C64 = llvm::dyn_cast<ConstantInteger64>(Opnd))
2953*03ce13f7SAndroid Build Coastguard Worker     return C64->getValue() == 0;
2954*03ce13f7SAndroid Build Coastguard Worker   if (auto *C32 = llvm::dyn_cast<ConstantInteger32>(Opnd))
2955*03ce13f7SAndroid Build Coastguard Worker     return C32->getValue() == 0;
2956*03ce13f7SAndroid Build Coastguard Worker   return false;
2957*03ce13f7SAndroid Build Coastguard Worker }
2958*03ce13f7SAndroid Build Coastguard Worker 
lowerIcmpAndConsumer(const InstIcmp * Icmp,const Inst * Consumer)2959*03ce13f7SAndroid Build Coastguard Worker void TargetX8664::lowerIcmpAndConsumer(const InstIcmp *Icmp,
2960*03ce13f7SAndroid Build Coastguard Worker                                        const Inst *Consumer) {
2961*03ce13f7SAndroid Build Coastguard Worker   Operand *Src0 = legalize(Icmp->getSrc(0));
2962*03ce13f7SAndroid Build Coastguard Worker   Operand *Src1 = legalize(Icmp->getSrc(1));
2963*03ce13f7SAndroid Build Coastguard Worker   Variable *Dest = Icmp->getDest();
2964*03ce13f7SAndroid Build Coastguard Worker 
2965*03ce13f7SAndroid Build Coastguard Worker   if (isVectorType(Dest->getType())) {
2966*03ce13f7SAndroid Build Coastguard Worker     lowerIcmp(Icmp);
2967*03ce13f7SAndroid Build Coastguard Worker     if (Consumer != nullptr)
2968*03ce13f7SAndroid Build Coastguard Worker       lowerSelectVector(llvm::cast<InstSelect>(Consumer));
2969*03ce13f7SAndroid Build Coastguard Worker     return;
2970*03ce13f7SAndroid Build Coastguard Worker   }
2971*03ce13f7SAndroid Build Coastguard Worker 
2972*03ce13f7SAndroid Build Coastguard Worker   // cmp b, c
2973*03ce13f7SAndroid Build Coastguard Worker   if (isZero(Src1)) {
2974*03ce13f7SAndroid Build Coastguard Worker     switch (Icmp->getCondition()) {
2975*03ce13f7SAndroid Build Coastguard Worker     default:
2976*03ce13f7SAndroid Build Coastguard Worker       break;
2977*03ce13f7SAndroid Build Coastguard Worker     case InstIcmp::Uge:
2978*03ce13f7SAndroid Build Coastguard Worker       movOrConsumer(true, Dest, Consumer);
2979*03ce13f7SAndroid Build Coastguard Worker       return;
2980*03ce13f7SAndroid Build Coastguard Worker     case InstIcmp::Ult:
2981*03ce13f7SAndroid Build Coastguard Worker       movOrConsumer(false, Dest, Consumer);
2982*03ce13f7SAndroid Build Coastguard Worker       return;
2983*03ce13f7SAndroid Build Coastguard Worker     }
2984*03ce13f7SAndroid Build Coastguard Worker   }
2985*03ce13f7SAndroid Build Coastguard Worker   Operand *Src0RM = legalizeSrc0ForCmp(Src0, Src1);
2986*03ce13f7SAndroid Build Coastguard Worker   _cmp(Src0RM, Src1);
2987*03ce13f7SAndroid Build Coastguard Worker   setccOrConsumer(getIcmp32Mapping(Icmp->getCondition()), Dest, Consumer);
2988*03ce13f7SAndroid Build Coastguard Worker }
2989*03ce13f7SAndroid Build Coastguard Worker 
lowerIcmpVector(const InstIcmp * Icmp)2990*03ce13f7SAndroid Build Coastguard Worker void TargetX8664::lowerIcmpVector(const InstIcmp *Icmp) {
2991*03ce13f7SAndroid Build Coastguard Worker   Operand *Src0 = legalize(Icmp->getSrc(0));
2992*03ce13f7SAndroid Build Coastguard Worker   Operand *Src1 = legalize(Icmp->getSrc(1));
2993*03ce13f7SAndroid Build Coastguard Worker   Variable *Dest = Icmp->getDest();
2994*03ce13f7SAndroid Build Coastguard Worker 
2995*03ce13f7SAndroid Build Coastguard Worker   if (!isVectorType(Dest->getType()))
2996*03ce13f7SAndroid Build Coastguard Worker     llvm::report_fatal_error("Expected a vector compare");
2997*03ce13f7SAndroid Build Coastguard Worker 
2998*03ce13f7SAndroid Build Coastguard Worker   Type Ty = Src0->getType();
2999*03ce13f7SAndroid Build Coastguard Worker   // Promote i1 vectors to 128 bit integer vector types.
3000*03ce13f7SAndroid Build Coastguard Worker   if (typeElementType(Ty) == IceType_i1) {
3001*03ce13f7SAndroid Build Coastguard Worker     Type NewTy = IceType_NUM;
3002*03ce13f7SAndroid Build Coastguard Worker     switch (Ty) {
3003*03ce13f7SAndroid Build Coastguard Worker     default:
3004*03ce13f7SAndroid Build Coastguard Worker       llvm::report_fatal_error("unexpected type");
3005*03ce13f7SAndroid Build Coastguard Worker       break;
3006*03ce13f7SAndroid Build Coastguard Worker     case IceType_v4i1:
3007*03ce13f7SAndroid Build Coastguard Worker       NewTy = IceType_v4i32;
3008*03ce13f7SAndroid Build Coastguard Worker       break;
3009*03ce13f7SAndroid Build Coastguard Worker     case IceType_v8i1:
3010*03ce13f7SAndroid Build Coastguard Worker       NewTy = IceType_v8i16;
3011*03ce13f7SAndroid Build Coastguard Worker       break;
3012*03ce13f7SAndroid Build Coastguard Worker     case IceType_v16i1:
3013*03ce13f7SAndroid Build Coastguard Worker       NewTy = IceType_v16i8;
3014*03ce13f7SAndroid Build Coastguard Worker       break;
3015*03ce13f7SAndroid Build Coastguard Worker     }
3016*03ce13f7SAndroid Build Coastguard Worker     Variable *NewSrc0 = Func->makeVariable(NewTy);
3017*03ce13f7SAndroid Build Coastguard Worker     Variable *NewSrc1 = Func->makeVariable(NewTy);
3018*03ce13f7SAndroid Build Coastguard Worker     lowerCast(InstCast::create(Func, InstCast::Sext, NewSrc0, Src0));
3019*03ce13f7SAndroid Build Coastguard Worker     lowerCast(InstCast::create(Func, InstCast::Sext, NewSrc1, Src1));
3020*03ce13f7SAndroid Build Coastguard Worker     Src0 = NewSrc0;
3021*03ce13f7SAndroid Build Coastguard Worker     Src1 = NewSrc1;
3022*03ce13f7SAndroid Build Coastguard Worker     Ty = NewTy;
3023*03ce13f7SAndroid Build Coastguard Worker   }
3024*03ce13f7SAndroid Build Coastguard Worker 
3025*03ce13f7SAndroid Build Coastguard Worker   InstIcmp::ICond Condition = Icmp->getCondition();
3026*03ce13f7SAndroid Build Coastguard Worker 
3027*03ce13f7SAndroid Build Coastguard Worker   Operand *Src0RM = legalize(Src0, Legal_Reg | Legal_Mem);
3028*03ce13f7SAndroid Build Coastguard Worker   Operand *Src1RM = legalize(Src1, Legal_Reg | Legal_Mem);
3029*03ce13f7SAndroid Build Coastguard Worker 
3030*03ce13f7SAndroid Build Coastguard Worker   // SSE2 only has signed comparison operations. Transform unsigned inputs in
3031*03ce13f7SAndroid Build Coastguard Worker   // a manner that allows for the use of signed comparison operations by
3032*03ce13f7SAndroid Build Coastguard Worker   // flipping the high order bits.
3033*03ce13f7SAndroid Build Coastguard Worker   if (Condition == InstIcmp::Ugt || Condition == InstIcmp::Uge ||
3034*03ce13f7SAndroid Build Coastguard Worker       Condition == InstIcmp::Ult || Condition == InstIcmp::Ule) {
3035*03ce13f7SAndroid Build Coastguard Worker     Variable *T0 = makeReg(Ty);
3036*03ce13f7SAndroid Build Coastguard Worker     Variable *T1 = makeReg(Ty);
3037*03ce13f7SAndroid Build Coastguard Worker     Variable *HighOrderBits = makeVectorOfHighOrderBits(Ty);
3038*03ce13f7SAndroid Build Coastguard Worker     _movp(T0, Src0RM);
3039*03ce13f7SAndroid Build Coastguard Worker     _pxor(T0, HighOrderBits);
3040*03ce13f7SAndroid Build Coastguard Worker     _movp(T1, Src1RM);
3041*03ce13f7SAndroid Build Coastguard Worker     _pxor(T1, HighOrderBits);
3042*03ce13f7SAndroid Build Coastguard Worker     Src0RM = T0;
3043*03ce13f7SAndroid Build Coastguard Worker     Src1RM = T1;
3044*03ce13f7SAndroid Build Coastguard Worker   }
3045*03ce13f7SAndroid Build Coastguard Worker 
3046*03ce13f7SAndroid Build Coastguard Worker   Variable *T = makeReg(Ty);
3047*03ce13f7SAndroid Build Coastguard Worker   switch (Condition) {
3048*03ce13f7SAndroid Build Coastguard Worker   default:
3049*03ce13f7SAndroid Build Coastguard Worker     llvm_unreachable("unexpected condition");
3050*03ce13f7SAndroid Build Coastguard Worker     break;
3051*03ce13f7SAndroid Build Coastguard Worker   case InstIcmp::Eq: {
3052*03ce13f7SAndroid Build Coastguard Worker     if (llvm::isa<X86OperandMem>(Src1RM))
3053*03ce13f7SAndroid Build Coastguard Worker       Src1RM = legalizeToReg(Src1RM);
3054*03ce13f7SAndroid Build Coastguard Worker     _movp(T, Src0RM);
3055*03ce13f7SAndroid Build Coastguard Worker     _pcmpeq(T, Src1RM);
3056*03ce13f7SAndroid Build Coastguard Worker   } break;
3057*03ce13f7SAndroid Build Coastguard Worker   case InstIcmp::Ne: {
3058*03ce13f7SAndroid Build Coastguard Worker     if (llvm::isa<X86OperandMem>(Src1RM))
3059*03ce13f7SAndroid Build Coastguard Worker       Src1RM = legalizeToReg(Src1RM);
3060*03ce13f7SAndroid Build Coastguard Worker     _movp(T, Src0RM);
3061*03ce13f7SAndroid Build Coastguard Worker     _pcmpeq(T, Src1RM);
3062*03ce13f7SAndroid Build Coastguard Worker     Variable *MinusOne = makeVectorOfMinusOnes(Ty);
3063*03ce13f7SAndroid Build Coastguard Worker     _pxor(T, MinusOne);
3064*03ce13f7SAndroid Build Coastguard Worker   } break;
3065*03ce13f7SAndroid Build Coastguard Worker   case InstIcmp::Ugt:
3066*03ce13f7SAndroid Build Coastguard Worker   case InstIcmp::Sgt: {
3067*03ce13f7SAndroid Build Coastguard Worker     if (llvm::isa<X86OperandMem>(Src1RM))
3068*03ce13f7SAndroid Build Coastguard Worker       Src1RM = legalizeToReg(Src1RM);
3069*03ce13f7SAndroid Build Coastguard Worker     _movp(T, Src0RM);
3070*03ce13f7SAndroid Build Coastguard Worker     _pcmpgt(T, Src1RM);
3071*03ce13f7SAndroid Build Coastguard Worker   } break;
3072*03ce13f7SAndroid Build Coastguard Worker   case InstIcmp::Uge:
3073*03ce13f7SAndroid Build Coastguard Worker   case InstIcmp::Sge: {
3074*03ce13f7SAndroid Build Coastguard Worker     // !(Src1RM > Src0RM)
3075*03ce13f7SAndroid Build Coastguard Worker     if (llvm::isa<X86OperandMem>(Src0RM))
3076*03ce13f7SAndroid Build Coastguard Worker       Src0RM = legalizeToReg(Src0RM);
3077*03ce13f7SAndroid Build Coastguard Worker     _movp(T, Src1RM);
3078*03ce13f7SAndroid Build Coastguard Worker     _pcmpgt(T, Src0RM);
3079*03ce13f7SAndroid Build Coastguard Worker     Variable *MinusOne = makeVectorOfMinusOnes(Ty);
3080*03ce13f7SAndroid Build Coastguard Worker     _pxor(T, MinusOne);
3081*03ce13f7SAndroid Build Coastguard Worker   } break;
3082*03ce13f7SAndroid Build Coastguard Worker   case InstIcmp::Ult:
3083*03ce13f7SAndroid Build Coastguard Worker   case InstIcmp::Slt: {
3084*03ce13f7SAndroid Build Coastguard Worker     if (llvm::isa<X86OperandMem>(Src0RM))
3085*03ce13f7SAndroid Build Coastguard Worker       Src0RM = legalizeToReg(Src0RM);
3086*03ce13f7SAndroid Build Coastguard Worker     _movp(T, Src1RM);
3087*03ce13f7SAndroid Build Coastguard Worker     _pcmpgt(T, Src0RM);
3088*03ce13f7SAndroid Build Coastguard Worker   } break;
3089*03ce13f7SAndroid Build Coastguard Worker   case InstIcmp::Ule:
3090*03ce13f7SAndroid Build Coastguard Worker   case InstIcmp::Sle: {
3091*03ce13f7SAndroid Build Coastguard Worker     // !(Src0RM > Src1RM)
3092*03ce13f7SAndroid Build Coastguard Worker     if (llvm::isa<X86OperandMem>(Src1RM))
3093*03ce13f7SAndroid Build Coastguard Worker       Src1RM = legalizeToReg(Src1RM);
3094*03ce13f7SAndroid Build Coastguard Worker     _movp(T, Src0RM);
3095*03ce13f7SAndroid Build Coastguard Worker     _pcmpgt(T, Src1RM);
3096*03ce13f7SAndroid Build Coastguard Worker     Variable *MinusOne = makeVectorOfMinusOnes(Ty);
3097*03ce13f7SAndroid Build Coastguard Worker     _pxor(T, MinusOne);
3098*03ce13f7SAndroid Build Coastguard Worker   } break;
3099*03ce13f7SAndroid Build Coastguard Worker   }
3100*03ce13f7SAndroid Build Coastguard Worker 
3101*03ce13f7SAndroid Build Coastguard Worker   _movp(Dest, T);
3102*03ce13f7SAndroid Build Coastguard Worker   eliminateNextVectorSextInstruction(Dest);
3103*03ce13f7SAndroid Build Coastguard Worker }
3104*03ce13f7SAndroid Build Coastguard Worker 
setccOrConsumer(BrCond Condition,Variable * Dest,const Inst * Consumer)3105*03ce13f7SAndroid Build Coastguard Worker void TargetX8664::setccOrConsumer(BrCond Condition, Variable *Dest,
3106*03ce13f7SAndroid Build Coastguard Worker                                   const Inst *Consumer) {
3107*03ce13f7SAndroid Build Coastguard Worker   if (Consumer == nullptr) {
3108*03ce13f7SAndroid Build Coastguard Worker     _setcc(Dest, Condition);
3109*03ce13f7SAndroid Build Coastguard Worker     return;
3110*03ce13f7SAndroid Build Coastguard Worker   }
3111*03ce13f7SAndroid Build Coastguard Worker   if (const auto *Br = llvm::dyn_cast<InstBr>(Consumer)) {
3112*03ce13f7SAndroid Build Coastguard Worker     _br(Condition, Br->getTargetTrue(), Br->getTargetFalse());
3113*03ce13f7SAndroid Build Coastguard Worker     return;
3114*03ce13f7SAndroid Build Coastguard Worker   }
3115*03ce13f7SAndroid Build Coastguard Worker   if (const auto *Select = llvm::dyn_cast<InstSelect>(Consumer)) {
3116*03ce13f7SAndroid Build Coastguard Worker     Operand *SrcT = Select->getTrueOperand();
3117*03ce13f7SAndroid Build Coastguard Worker     Operand *SrcF = Select->getFalseOperand();
3118*03ce13f7SAndroid Build Coastguard Worker     Variable *SelectDest = Select->getDest();
3119*03ce13f7SAndroid Build Coastguard Worker     lowerSelectMove(SelectDest, Condition, SrcT, SrcF);
3120*03ce13f7SAndroid Build Coastguard Worker     return;
3121*03ce13f7SAndroid Build Coastguard Worker   }
3122*03ce13f7SAndroid Build Coastguard Worker   llvm::report_fatal_error("Unexpected consumer type");
3123*03ce13f7SAndroid Build Coastguard Worker }
3124*03ce13f7SAndroid Build Coastguard Worker 
movOrConsumer(bool IcmpResult,Variable * Dest,const Inst * Consumer)3125*03ce13f7SAndroid Build Coastguard Worker void TargetX8664::movOrConsumer(bool IcmpResult, Variable *Dest,
3126*03ce13f7SAndroid Build Coastguard Worker                                 const Inst *Consumer) {
3127*03ce13f7SAndroid Build Coastguard Worker   if (Consumer == nullptr) {
3128*03ce13f7SAndroid Build Coastguard Worker     _mov(Dest, Ctx->getConstantInt(Dest->getType(), (IcmpResult ? 1 : 0)));
3129*03ce13f7SAndroid Build Coastguard Worker     return;
3130*03ce13f7SAndroid Build Coastguard Worker   }
3131*03ce13f7SAndroid Build Coastguard Worker   if (const auto *Br = llvm::dyn_cast<InstBr>(Consumer)) {
3132*03ce13f7SAndroid Build Coastguard Worker     // TODO(sehr,stichnot): This could be done with a single unconditional
3133*03ce13f7SAndroid Build Coastguard Worker     // branch instruction, but subzero doesn't know how to handle the resulting
3134*03ce13f7SAndroid Build Coastguard Worker     // control flow graph changes now.  Make it do so to eliminate mov and cmp.
3135*03ce13f7SAndroid Build Coastguard Worker     _mov(Dest, Ctx->getConstantInt(Dest->getType(), (IcmpResult ? 1 : 0)));
3136*03ce13f7SAndroid Build Coastguard Worker     _cmp(Dest, Ctx->getConstantInt(Dest->getType(), 0));
3137*03ce13f7SAndroid Build Coastguard Worker     _br(CondX86::Br_ne, Br->getTargetTrue(), Br->getTargetFalse());
3138*03ce13f7SAndroid Build Coastguard Worker     return;
3139*03ce13f7SAndroid Build Coastguard Worker   }
3140*03ce13f7SAndroid Build Coastguard Worker   if (const auto *Select = llvm::dyn_cast<InstSelect>(Consumer)) {
3141*03ce13f7SAndroid Build Coastguard Worker     Operand *Src = nullptr;
3142*03ce13f7SAndroid Build Coastguard Worker     if (IcmpResult) {
3143*03ce13f7SAndroid Build Coastguard Worker       Src = legalize(Select->getTrueOperand(), Legal_Reg | Legal_Imm);
3144*03ce13f7SAndroid Build Coastguard Worker     } else {
3145*03ce13f7SAndroid Build Coastguard Worker       Src = legalize(Select->getFalseOperand(), Legal_Reg | Legal_Imm);
3146*03ce13f7SAndroid Build Coastguard Worker     }
3147*03ce13f7SAndroid Build Coastguard Worker     Variable *SelectDest = Select->getDest();
3148*03ce13f7SAndroid Build Coastguard Worker     lowerMove(SelectDest, Src, false);
3149*03ce13f7SAndroid Build Coastguard Worker     return;
3150*03ce13f7SAndroid Build Coastguard Worker   }
3151*03ce13f7SAndroid Build Coastguard Worker   llvm::report_fatal_error("Unexpected consumer type");
3152*03ce13f7SAndroid Build Coastguard Worker }
3153*03ce13f7SAndroid Build Coastguard Worker 
lowerArithAndConsumer(const InstArithmetic * Arith,const Inst * Consumer)3154*03ce13f7SAndroid Build Coastguard Worker void TargetX8664::lowerArithAndConsumer(const InstArithmetic *Arith,
3155*03ce13f7SAndroid Build Coastguard Worker                                         const Inst *Consumer) {
3156*03ce13f7SAndroid Build Coastguard Worker   Variable *T = nullptr;
3157*03ce13f7SAndroid Build Coastguard Worker   Operand *Src0 = legalize(Arith->getSrc(0));
3158*03ce13f7SAndroid Build Coastguard Worker   Operand *Src1 = legalize(Arith->getSrc(1));
3159*03ce13f7SAndroid Build Coastguard Worker   Variable *Dest = Arith->getDest();
3160*03ce13f7SAndroid Build Coastguard Worker   switch (Arith->getOp()) {
3161*03ce13f7SAndroid Build Coastguard Worker   default:
3162*03ce13f7SAndroid Build Coastguard Worker     llvm_unreachable("arithmetic operator not AND or OR");
3163*03ce13f7SAndroid Build Coastguard Worker     break;
3164*03ce13f7SAndroid Build Coastguard Worker   case InstArithmetic::And:
3165*03ce13f7SAndroid Build Coastguard Worker     _mov(T, Src0);
3166*03ce13f7SAndroid Build Coastguard Worker     // Test cannot have an address in the second position.  Since T is
3167*03ce13f7SAndroid Build Coastguard Worker     // guaranteed to be a register and Src1 could be a memory load, ensure
3168*03ce13f7SAndroid Build Coastguard Worker     // that the second argument is a register.
3169*03ce13f7SAndroid Build Coastguard Worker     if (llvm::isa<Constant>(Src1))
3170*03ce13f7SAndroid Build Coastguard Worker       _test(T, Src1);
3171*03ce13f7SAndroid Build Coastguard Worker     else
3172*03ce13f7SAndroid Build Coastguard Worker       _test(Src1, T);
3173*03ce13f7SAndroid Build Coastguard Worker     break;
3174*03ce13f7SAndroid Build Coastguard Worker   case InstArithmetic::Or:
3175*03ce13f7SAndroid Build Coastguard Worker     _mov(T, Src0);
3176*03ce13f7SAndroid Build Coastguard Worker     _or(T, Src1);
3177*03ce13f7SAndroid Build Coastguard Worker     break;
3178*03ce13f7SAndroid Build Coastguard Worker   }
3179*03ce13f7SAndroid Build Coastguard Worker 
3180*03ce13f7SAndroid Build Coastguard Worker   if (Consumer == nullptr) {
3181*03ce13f7SAndroid Build Coastguard Worker     llvm::report_fatal_error("Expected a consumer instruction");
3182*03ce13f7SAndroid Build Coastguard Worker   }
3183*03ce13f7SAndroid Build Coastguard Worker   if (const auto *Br = llvm::dyn_cast<InstBr>(Consumer)) {
3184*03ce13f7SAndroid Build Coastguard Worker     Context.insert<InstFakeUse>(T);
3185*03ce13f7SAndroid Build Coastguard Worker     Context.insert<InstFakeDef>(Dest);
3186*03ce13f7SAndroid Build Coastguard Worker     _br(CondX86::Br_ne, Br->getTargetTrue(), Br->getTargetFalse());
3187*03ce13f7SAndroid Build Coastguard Worker     return;
3188*03ce13f7SAndroid Build Coastguard Worker   }
3189*03ce13f7SAndroid Build Coastguard Worker   llvm::report_fatal_error("Unexpected consumer type");
3190*03ce13f7SAndroid Build Coastguard Worker }
3191*03ce13f7SAndroid Build Coastguard Worker 
lowerInsertElement(const InstInsertElement * Instr)3192*03ce13f7SAndroid Build Coastguard Worker void TargetX8664::lowerInsertElement(const InstInsertElement *Instr) {
3193*03ce13f7SAndroid Build Coastguard Worker   Operand *SourceVectNotLegalized = Instr->getSrc(0);
3194*03ce13f7SAndroid Build Coastguard Worker   Operand *ElementToInsertNotLegalized = Instr->getSrc(1);
3195*03ce13f7SAndroid Build Coastguard Worker   auto *ElementIndex = llvm::dyn_cast<ConstantInteger32>(Instr->getSrc(2));
3196*03ce13f7SAndroid Build Coastguard Worker   // Only constant indices are allowed in PNaCl IR.
3197*03ce13f7SAndroid Build Coastguard Worker   assert(ElementIndex);
3198*03ce13f7SAndroid Build Coastguard Worker   unsigned Index = ElementIndex->getValue();
3199*03ce13f7SAndroid Build Coastguard Worker   assert(Index < typeNumElements(SourceVectNotLegalized->getType()));
3200*03ce13f7SAndroid Build Coastguard Worker 
3201*03ce13f7SAndroid Build Coastguard Worker   Type Ty = SourceVectNotLegalized->getType();
3202*03ce13f7SAndroid Build Coastguard Worker   Type ElementTy = typeElementType(Ty);
3203*03ce13f7SAndroid Build Coastguard Worker   Type InVectorElementTy = InstX86Base::getInVectorElementType(Ty);
3204*03ce13f7SAndroid Build Coastguard Worker 
3205*03ce13f7SAndroid Build Coastguard Worker   if (ElementTy == IceType_i1) {
3206*03ce13f7SAndroid Build Coastguard Worker     // Expand the element to the appropriate size for it to be inserted in the
3207*03ce13f7SAndroid Build Coastguard Worker     // vector.
3208*03ce13f7SAndroid Build Coastguard Worker     Variable *Expanded = Func->makeVariable(InVectorElementTy);
3209*03ce13f7SAndroid Build Coastguard Worker     auto *Cast = InstCast::create(Func, InstCast::Zext, Expanded,
3210*03ce13f7SAndroid Build Coastguard Worker                                   ElementToInsertNotLegalized);
3211*03ce13f7SAndroid Build Coastguard Worker     lowerCast(Cast);
3212*03ce13f7SAndroid Build Coastguard Worker     ElementToInsertNotLegalized = Expanded;
3213*03ce13f7SAndroid Build Coastguard Worker   }
3214*03ce13f7SAndroid Build Coastguard Worker 
3215*03ce13f7SAndroid Build Coastguard Worker   if (Ty == IceType_v8i16 || Ty == IceType_v8i1 || InstructionSet >= SSE4_1) {
3216*03ce13f7SAndroid Build Coastguard Worker     // Use insertps, pinsrb, pinsrw, or pinsrd.
3217*03ce13f7SAndroid Build Coastguard Worker     Operand *ElementRM =
3218*03ce13f7SAndroid Build Coastguard Worker         legalize(ElementToInsertNotLegalized, Legal_Reg | Legal_Mem);
3219*03ce13f7SAndroid Build Coastguard Worker     Operand *SourceVectRM =
3220*03ce13f7SAndroid Build Coastguard Worker         legalize(SourceVectNotLegalized, Legal_Reg | Legal_Mem);
3221*03ce13f7SAndroid Build Coastguard Worker     Variable *T = makeReg(Ty);
3222*03ce13f7SAndroid Build Coastguard Worker     _movp(T, SourceVectRM);
3223*03ce13f7SAndroid Build Coastguard Worker     if (Ty == IceType_v4f32) {
3224*03ce13f7SAndroid Build Coastguard Worker       _insertps(T, ElementRM, Ctx->getConstantInt32(Index << 4));
3225*03ce13f7SAndroid Build Coastguard Worker     } else {
3226*03ce13f7SAndroid Build Coastguard Worker       // For the pinsrb and pinsrw instructions, when the source operand is a
3227*03ce13f7SAndroid Build Coastguard Worker       // register, it must be a full r32 register like eax, and not ax/al/ah.
3228*03ce13f7SAndroid Build Coastguard Worker       // For filetype=asm, InstX86Pinsr::emit() compensates for
3229*03ce13f7SAndroid Build Coastguard Worker       // the use
3230*03ce13f7SAndroid Build Coastguard Worker       // of r16 and r8 by converting them through getBaseReg(), while emitIAS()
3231*03ce13f7SAndroid Build Coastguard Worker       // validates that the original and base register encodings are the same.
3232*03ce13f7SAndroid Build Coastguard Worker       if (ElementRM->getType() == IceType_i8 &&
3233*03ce13f7SAndroid Build Coastguard Worker           llvm::isa<Variable>(ElementRM)) {
3234*03ce13f7SAndroid Build Coastguard Worker         // Don't use ah/bh/ch/dh for pinsrb.
3235*03ce13f7SAndroid Build Coastguard Worker         ElementRM = copyToReg8(ElementRM);
3236*03ce13f7SAndroid Build Coastguard Worker       }
3237*03ce13f7SAndroid Build Coastguard Worker       _pinsr(T, ElementRM, Ctx->getConstantInt32(Index));
3238*03ce13f7SAndroid Build Coastguard Worker     }
3239*03ce13f7SAndroid Build Coastguard Worker     _movp(Instr->getDest(), T);
3240*03ce13f7SAndroid Build Coastguard Worker   } else if (Ty == IceType_v4i32 || Ty == IceType_v4f32 || Ty == IceType_v4i1) {
3241*03ce13f7SAndroid Build Coastguard Worker     // Use shufps or movss.
3242*03ce13f7SAndroid Build Coastguard Worker     Variable *ElementR = nullptr;
3243*03ce13f7SAndroid Build Coastguard Worker     Operand *SourceVectRM =
3244*03ce13f7SAndroid Build Coastguard Worker         legalize(SourceVectNotLegalized, Legal_Reg | Legal_Mem);
3245*03ce13f7SAndroid Build Coastguard Worker 
3246*03ce13f7SAndroid Build Coastguard Worker     if (InVectorElementTy == IceType_f32) {
3247*03ce13f7SAndroid Build Coastguard Worker       // ElementR will be in an XMM register since it is floating point.
3248*03ce13f7SAndroid Build Coastguard Worker       ElementR = legalizeToReg(ElementToInsertNotLegalized);
3249*03ce13f7SAndroid Build Coastguard Worker     } else {
3250*03ce13f7SAndroid Build Coastguard Worker       // Copy an integer to an XMM register.
3251*03ce13f7SAndroid Build Coastguard Worker       Operand *T = legalize(ElementToInsertNotLegalized, Legal_Reg | Legal_Mem);
3252*03ce13f7SAndroid Build Coastguard Worker       ElementR = makeReg(Ty);
3253*03ce13f7SAndroid Build Coastguard Worker       _movd(ElementR, T);
3254*03ce13f7SAndroid Build Coastguard Worker     }
3255*03ce13f7SAndroid Build Coastguard Worker 
3256*03ce13f7SAndroid Build Coastguard Worker     if (Index == 0) {
3257*03ce13f7SAndroid Build Coastguard Worker       Variable *T = makeReg(Ty);
3258*03ce13f7SAndroid Build Coastguard Worker       _movp(T, SourceVectRM);
3259*03ce13f7SAndroid Build Coastguard Worker       _movss(T, ElementR);
3260*03ce13f7SAndroid Build Coastguard Worker       _movp(Instr->getDest(), T);
3261*03ce13f7SAndroid Build Coastguard Worker       return;
3262*03ce13f7SAndroid Build Coastguard Worker     }
3263*03ce13f7SAndroid Build Coastguard Worker 
3264*03ce13f7SAndroid Build Coastguard Worker     // shufps treats the source and destination operands as vectors of four
3265*03ce13f7SAndroid Build Coastguard Worker     // doublewords. The destination's two high doublewords are selected from
3266*03ce13f7SAndroid Build Coastguard Worker     // the source operand and the two low doublewords are selected from the
3267*03ce13f7SAndroid Build Coastguard Worker     // (original value of) the destination operand. An insertelement operation
3268*03ce13f7SAndroid Build Coastguard Worker     // can be effected with a sequence of two shufps operations with
3269*03ce13f7SAndroid Build Coastguard Worker     // appropriate masks. In all cases below, Element[0] is being inserted into
3270*03ce13f7SAndroid Build Coastguard Worker     // SourceVectOperand. Indices are ordered from left to right.
3271*03ce13f7SAndroid Build Coastguard Worker     //
3272*03ce13f7SAndroid Build Coastguard Worker     // insertelement into index 1 (result is stored in ElementR):
3273*03ce13f7SAndroid Build Coastguard Worker     //   ElementR := ElementR[0, 0] SourceVectRM[0, 0]
3274*03ce13f7SAndroid Build Coastguard Worker     //   ElementR := ElementR[3, 0] SourceVectRM[2, 3]
3275*03ce13f7SAndroid Build Coastguard Worker     //
3276*03ce13f7SAndroid Build Coastguard Worker     // insertelement into index 2 (result is stored in T):
3277*03ce13f7SAndroid Build Coastguard Worker     //   T := SourceVectRM
3278*03ce13f7SAndroid Build Coastguard Worker     //   ElementR := ElementR[0, 0] T[0, 3]
3279*03ce13f7SAndroid Build Coastguard Worker     //   T := T[0, 1] ElementR[0, 3]
3280*03ce13f7SAndroid Build Coastguard Worker     //
3281*03ce13f7SAndroid Build Coastguard Worker     // insertelement into index 3 (result is stored in T):
3282*03ce13f7SAndroid Build Coastguard Worker     //   T := SourceVectRM
3283*03ce13f7SAndroid Build Coastguard Worker     //   ElementR := ElementR[0, 0] T[0, 2]
3284*03ce13f7SAndroid Build Coastguard Worker     //   T := T[0, 1] ElementR[3, 0]
3285*03ce13f7SAndroid Build Coastguard Worker     const unsigned char Mask1[3] = {0, 192, 128};
3286*03ce13f7SAndroid Build Coastguard Worker     const unsigned char Mask2[3] = {227, 196, 52};
3287*03ce13f7SAndroid Build Coastguard Worker 
3288*03ce13f7SAndroid Build Coastguard Worker     Constant *Mask1Constant = Ctx->getConstantInt32(Mask1[Index - 1]);
3289*03ce13f7SAndroid Build Coastguard Worker     Constant *Mask2Constant = Ctx->getConstantInt32(Mask2[Index - 1]);
3290*03ce13f7SAndroid Build Coastguard Worker 
3291*03ce13f7SAndroid Build Coastguard Worker     if (Index == 1) {
3292*03ce13f7SAndroid Build Coastguard Worker       _shufps(ElementR, SourceVectRM, Mask1Constant);
3293*03ce13f7SAndroid Build Coastguard Worker       _shufps(ElementR, SourceVectRM, Mask2Constant);
3294*03ce13f7SAndroid Build Coastguard Worker       _movp(Instr->getDest(), ElementR);
3295*03ce13f7SAndroid Build Coastguard Worker     } else {
3296*03ce13f7SAndroid Build Coastguard Worker       Variable *T = makeReg(Ty);
3297*03ce13f7SAndroid Build Coastguard Worker       _movp(T, SourceVectRM);
3298*03ce13f7SAndroid Build Coastguard Worker       _shufps(ElementR, T, Mask1Constant);
3299*03ce13f7SAndroid Build Coastguard Worker       _shufps(T, ElementR, Mask2Constant);
3300*03ce13f7SAndroid Build Coastguard Worker       _movp(Instr->getDest(), T);
3301*03ce13f7SAndroid Build Coastguard Worker     }
3302*03ce13f7SAndroid Build Coastguard Worker   } else {
3303*03ce13f7SAndroid Build Coastguard Worker     assert(Ty == IceType_v16i8 || Ty == IceType_v16i1);
3304*03ce13f7SAndroid Build Coastguard Worker     // Spill the value to a stack slot and perform the insertion in memory.
3305*03ce13f7SAndroid Build Coastguard Worker     //
3306*03ce13f7SAndroid Build Coastguard Worker     // TODO(wala): use legalize(SourceVectNotLegalized, Legal_Mem) when support
3307*03ce13f7SAndroid Build Coastguard Worker     // for legalizing to mem is implemented.
3308*03ce13f7SAndroid Build Coastguard Worker     Variable *Slot = Func->makeVariable(Ty);
3309*03ce13f7SAndroid Build Coastguard Worker     Slot->setMustNotHaveReg();
3310*03ce13f7SAndroid Build Coastguard Worker     _movp(Slot, legalizeToReg(SourceVectNotLegalized));
3311*03ce13f7SAndroid Build Coastguard Worker 
3312*03ce13f7SAndroid Build Coastguard Worker     // Compute the location of the position to insert in memory.
3313*03ce13f7SAndroid Build Coastguard Worker     unsigned Offset = Index * typeWidthInBytes(InVectorElementTy);
3314*03ce13f7SAndroid Build Coastguard Worker     X86OperandMem *Loc =
3315*03ce13f7SAndroid Build Coastguard Worker         getMemoryOperandForStackSlot(InVectorElementTy, Slot, Offset);
3316*03ce13f7SAndroid Build Coastguard Worker     _store(legalizeToReg(ElementToInsertNotLegalized), Loc);
3317*03ce13f7SAndroid Build Coastguard Worker 
3318*03ce13f7SAndroid Build Coastguard Worker     Variable *T = makeReg(Ty);
3319*03ce13f7SAndroid Build Coastguard Worker     _movp(T, Slot);
3320*03ce13f7SAndroid Build Coastguard Worker     _movp(Instr->getDest(), T);
3321*03ce13f7SAndroid Build Coastguard Worker   }
3322*03ce13f7SAndroid Build Coastguard Worker }
3323*03ce13f7SAndroid Build Coastguard Worker 
lowerIntrinsic(const InstIntrinsic * Instr)3324*03ce13f7SAndroid Build Coastguard Worker void TargetX8664::lowerIntrinsic(const InstIntrinsic *Instr) {
3325*03ce13f7SAndroid Build Coastguard Worker   switch (Intrinsics::IntrinsicID ID = Instr->getIntrinsicID()) {
3326*03ce13f7SAndroid Build Coastguard Worker   case Intrinsics::AtomicCmpxchg: {
3327*03ce13f7SAndroid Build Coastguard Worker     if (!Intrinsics::isMemoryOrderValid(
3328*03ce13f7SAndroid Build Coastguard Worker             ID, getConstantMemoryOrder(Instr->getArg(3)),
3329*03ce13f7SAndroid Build Coastguard Worker             getConstantMemoryOrder(Instr->getArg(4)))) {
3330*03ce13f7SAndroid Build Coastguard Worker       Func->setError("Unexpected memory ordering for AtomicCmpxchg");
3331*03ce13f7SAndroid Build Coastguard Worker       return;
3332*03ce13f7SAndroid Build Coastguard Worker     }
3333*03ce13f7SAndroid Build Coastguard Worker     Variable *DestPrev = Instr->getDest();
3334*03ce13f7SAndroid Build Coastguard Worker     Operand *PtrToMem = legalize(Instr->getArg(0));
3335*03ce13f7SAndroid Build Coastguard Worker     Operand *Expected = legalize(Instr->getArg(1));
3336*03ce13f7SAndroid Build Coastguard Worker     Operand *Desired = legalize(Instr->getArg(2));
3337*03ce13f7SAndroid Build Coastguard Worker     if (tryOptimizedCmpxchgCmpBr(DestPrev, PtrToMem, Expected, Desired))
3338*03ce13f7SAndroid Build Coastguard Worker       return;
3339*03ce13f7SAndroid Build Coastguard Worker     lowerAtomicCmpxchg(DestPrev, PtrToMem, Expected, Desired);
3340*03ce13f7SAndroid Build Coastguard Worker     return;
3341*03ce13f7SAndroid Build Coastguard Worker   }
3342*03ce13f7SAndroid Build Coastguard Worker   case Intrinsics::AtomicFence:
3343*03ce13f7SAndroid Build Coastguard Worker     if (!Intrinsics::isMemoryOrderValid(
3344*03ce13f7SAndroid Build Coastguard Worker             ID, getConstantMemoryOrder(Instr->getArg(0)))) {
3345*03ce13f7SAndroid Build Coastguard Worker       Func->setError("Unexpected memory ordering for AtomicFence");
3346*03ce13f7SAndroid Build Coastguard Worker       return;
3347*03ce13f7SAndroid Build Coastguard Worker     }
3348*03ce13f7SAndroid Build Coastguard Worker     _mfence();
3349*03ce13f7SAndroid Build Coastguard Worker     return;
3350*03ce13f7SAndroid Build Coastguard Worker   case Intrinsics::AtomicFenceAll:
3351*03ce13f7SAndroid Build Coastguard Worker     // NOTE: FenceAll should prevent and load/store from being moved across the
3352*03ce13f7SAndroid Build Coastguard Worker     // fence (both atomic and non-atomic). The InstX8632Mfence instruction is
3353*03ce13f7SAndroid Build Coastguard Worker     // currently marked coarsely as "HasSideEffects".
3354*03ce13f7SAndroid Build Coastguard Worker     _mfence();
3355*03ce13f7SAndroid Build Coastguard Worker     return;
3356*03ce13f7SAndroid Build Coastguard Worker   case Intrinsics::AtomicIsLockFree: {
3357*03ce13f7SAndroid Build Coastguard Worker     // X86 is always lock free for 8/16/32/64 bit accesses.
3358*03ce13f7SAndroid Build Coastguard Worker     // TODO(jvoung): Since the result is constant when given a constant byte
3359*03ce13f7SAndroid Build Coastguard Worker     // size, this opens up DCE opportunities.
3360*03ce13f7SAndroid Build Coastguard Worker     Operand *ByteSize = Instr->getArg(0);
3361*03ce13f7SAndroid Build Coastguard Worker     Variable *Dest = Instr->getDest();
3362*03ce13f7SAndroid Build Coastguard Worker     if (auto *CI = llvm::dyn_cast<ConstantInteger32>(ByteSize)) {
3363*03ce13f7SAndroid Build Coastguard Worker       Constant *Result;
3364*03ce13f7SAndroid Build Coastguard Worker       switch (CI->getValue()) {
3365*03ce13f7SAndroid Build Coastguard Worker       default:
3366*03ce13f7SAndroid Build Coastguard Worker         // Some x86-64 processors support the cmpxchg16b instruction, which can
3367*03ce13f7SAndroid Build Coastguard Worker         // make 16-byte operations lock free (when used with the LOCK prefix).
3368*03ce13f7SAndroid Build Coastguard Worker         // However, that's not supported in 32-bit mode, so just return 0 even
3369*03ce13f7SAndroid Build Coastguard Worker         // for large sizes.
3370*03ce13f7SAndroid Build Coastguard Worker         Result = Ctx->getConstantZero(IceType_i32);
3371*03ce13f7SAndroid Build Coastguard Worker         break;
3372*03ce13f7SAndroid Build Coastguard Worker       case 1:
3373*03ce13f7SAndroid Build Coastguard Worker       case 2:
3374*03ce13f7SAndroid Build Coastguard Worker       case 4:
3375*03ce13f7SAndroid Build Coastguard Worker       case 8:
3376*03ce13f7SAndroid Build Coastguard Worker         Result = Ctx->getConstantInt32(1);
3377*03ce13f7SAndroid Build Coastguard Worker         break;
3378*03ce13f7SAndroid Build Coastguard Worker       }
3379*03ce13f7SAndroid Build Coastguard Worker       _mov(Dest, Result);
3380*03ce13f7SAndroid Build Coastguard Worker       return;
3381*03ce13f7SAndroid Build Coastguard Worker     }
3382*03ce13f7SAndroid Build Coastguard Worker     // The PNaCl ABI requires the byte size to be a compile-time constant.
3383*03ce13f7SAndroid Build Coastguard Worker     Func->setError("AtomicIsLockFree byte size should be compile-time const");
3384*03ce13f7SAndroid Build Coastguard Worker     return;
3385*03ce13f7SAndroid Build Coastguard Worker   }
3386*03ce13f7SAndroid Build Coastguard Worker   case Intrinsics::AtomicLoad: {
3387*03ce13f7SAndroid Build Coastguard Worker     // We require the memory address to be naturally aligned. Given that is the
3388*03ce13f7SAndroid Build Coastguard Worker     // case, then normal loads are atomic.
3389*03ce13f7SAndroid Build Coastguard Worker     if (!Intrinsics::isMemoryOrderValid(
3390*03ce13f7SAndroid Build Coastguard Worker             ID, getConstantMemoryOrder(Instr->getArg(1)))) {
3391*03ce13f7SAndroid Build Coastguard Worker       Func->setError("Unexpected memory ordering for AtomicLoad");
3392*03ce13f7SAndroid Build Coastguard Worker       return;
3393*03ce13f7SAndroid Build Coastguard Worker     }
3394*03ce13f7SAndroid Build Coastguard Worker     Variable *Dest = Instr->getDest();
3395*03ce13f7SAndroid Build Coastguard Worker     auto *Load = InstLoad::create(Func, Dest, Instr->getArg(0));
3396*03ce13f7SAndroid Build Coastguard Worker     lowerLoad(Load);
3397*03ce13f7SAndroid Build Coastguard Worker     // Make sure the atomic load isn't elided when unused, by adding a FakeUse.
3398*03ce13f7SAndroid Build Coastguard Worker     // Since lowerLoad may fuse the load w/ an arithmetic instruction, insert
3399*03ce13f7SAndroid Build Coastguard Worker     // the FakeUse on the last-inserted instruction's dest.
3400*03ce13f7SAndroid Build Coastguard Worker     Context.insert<InstFakeUse>(Context.getLastInserted()->getDest());
3401*03ce13f7SAndroid Build Coastguard Worker     return;
3402*03ce13f7SAndroid Build Coastguard Worker   }
3403*03ce13f7SAndroid Build Coastguard Worker   case Intrinsics::AtomicRMW:
3404*03ce13f7SAndroid Build Coastguard Worker     if (!Intrinsics::isMemoryOrderValid(
3405*03ce13f7SAndroid Build Coastguard Worker             ID, getConstantMemoryOrder(Instr->getArg(3)))) {
3406*03ce13f7SAndroid Build Coastguard Worker       Func->setError("Unexpected memory ordering for AtomicRMW");
3407*03ce13f7SAndroid Build Coastguard Worker       return;
3408*03ce13f7SAndroid Build Coastguard Worker     }
3409*03ce13f7SAndroid Build Coastguard Worker     lowerAtomicRMW(
3410*03ce13f7SAndroid Build Coastguard Worker         Instr->getDest(),
3411*03ce13f7SAndroid Build Coastguard Worker         static_cast<uint32_t>(
3412*03ce13f7SAndroid Build Coastguard Worker             llvm::cast<ConstantInteger32>(Instr->getArg(0))->getValue()),
3413*03ce13f7SAndroid Build Coastguard Worker         Instr->getArg(1), Instr->getArg(2));
3414*03ce13f7SAndroid Build Coastguard Worker     return;
3415*03ce13f7SAndroid Build Coastguard Worker   case Intrinsics::AtomicStore: {
3416*03ce13f7SAndroid Build Coastguard Worker     if (!Intrinsics::isMemoryOrderValid(
3417*03ce13f7SAndroid Build Coastguard Worker             ID, getConstantMemoryOrder(Instr->getArg(2)))) {
3418*03ce13f7SAndroid Build Coastguard Worker       Func->setError("Unexpected memory ordering for AtomicStore");
3419*03ce13f7SAndroid Build Coastguard Worker       return;
3420*03ce13f7SAndroid Build Coastguard Worker     }
3421*03ce13f7SAndroid Build Coastguard Worker     // We require the memory address to be naturally aligned. Given that is the
3422*03ce13f7SAndroid Build Coastguard Worker     // case, then normal stores are atomic. Add a fence after the store to make
3423*03ce13f7SAndroid Build Coastguard Worker     // it visible.
3424*03ce13f7SAndroid Build Coastguard Worker     Operand *Value = Instr->getArg(0);
3425*03ce13f7SAndroid Build Coastguard Worker     Operand *Ptr = Instr->getArg(1);
3426*03ce13f7SAndroid Build Coastguard Worker     auto *Store = InstStore::create(Func, Value, Ptr);
3427*03ce13f7SAndroid Build Coastguard Worker     lowerStore(Store);
3428*03ce13f7SAndroid Build Coastguard Worker     _mfence();
3429*03ce13f7SAndroid Build Coastguard Worker     return;
3430*03ce13f7SAndroid Build Coastguard Worker   }
3431*03ce13f7SAndroid Build Coastguard Worker   case Intrinsics::Bswap: {
3432*03ce13f7SAndroid Build Coastguard Worker     Variable *Dest = Instr->getDest();
3433*03ce13f7SAndroid Build Coastguard Worker     Operand *Val = Instr->getArg(0);
3434*03ce13f7SAndroid Build Coastguard Worker     // Use rotate left for 16-bit bswap.
3435*03ce13f7SAndroid Build Coastguard Worker     if (Val->getType() == IceType_i64 || Val->getType() == IceType_i32) {
3436*03ce13f7SAndroid Build Coastguard Worker       Variable *T = legalizeToReg(Val);
3437*03ce13f7SAndroid Build Coastguard Worker       _bswap(T);
3438*03ce13f7SAndroid Build Coastguard Worker       _mov(Dest, T);
3439*03ce13f7SAndroid Build Coastguard Worker     } else {
3440*03ce13f7SAndroid Build Coastguard Worker       assert(Val->getType() == IceType_i16);
3441*03ce13f7SAndroid Build Coastguard Worker       Constant *Eight = Ctx->getConstantInt16(8);
3442*03ce13f7SAndroid Build Coastguard Worker       Variable *T = nullptr;
3443*03ce13f7SAndroid Build Coastguard Worker       Val = legalize(Val);
3444*03ce13f7SAndroid Build Coastguard Worker       _mov(T, Val);
3445*03ce13f7SAndroid Build Coastguard Worker       _rol(T, Eight);
3446*03ce13f7SAndroid Build Coastguard Worker       _mov(Dest, T);
3447*03ce13f7SAndroid Build Coastguard Worker     }
3448*03ce13f7SAndroid Build Coastguard Worker     return;
3449*03ce13f7SAndroid Build Coastguard Worker   }
3450*03ce13f7SAndroid Build Coastguard Worker   case Intrinsics::Ctpop: {
3451*03ce13f7SAndroid Build Coastguard Worker     Variable *Dest = Instr->getDest();
3452*03ce13f7SAndroid Build Coastguard Worker     Variable *T = nullptr;
3453*03ce13f7SAndroid Build Coastguard Worker     Operand *Val = Instr->getArg(0);
3454*03ce13f7SAndroid Build Coastguard Worker     Type ValTy = Val->getType();
3455*03ce13f7SAndroid Build Coastguard Worker     assert(ValTy == IceType_i32 || ValTy == IceType_i64);
3456*03ce13f7SAndroid Build Coastguard Worker 
3457*03ce13f7SAndroid Build Coastguard Worker     T = makeReg(IceType_i64);
3458*03ce13f7SAndroid Build Coastguard Worker     if (ValTy == IceType_i32) {
3459*03ce13f7SAndroid Build Coastguard Worker       // in x86-64, __popcountsi2 is not defined, so we cheat a bit by
3460*03ce13f7SAndroid Build Coastguard Worker       // converting it to a 64-bit value, and using ctpop_i64. _movzx should
3461*03ce13f7SAndroid Build Coastguard Worker       // ensure we will not have any bits set on Val's upper 32 bits.
3462*03ce13f7SAndroid Build Coastguard Worker       Variable *V = makeReg(IceType_i64);
3463*03ce13f7SAndroid Build Coastguard Worker       Operand *ValRM = legalize(Val, Legal_Reg | Legal_Mem);
3464*03ce13f7SAndroid Build Coastguard Worker       _movzx(V, ValRM);
3465*03ce13f7SAndroid Build Coastguard Worker       Val = V;
3466*03ce13f7SAndroid Build Coastguard Worker     }
3467*03ce13f7SAndroid Build Coastguard Worker     ValTy = IceType_i64;
3468*03ce13f7SAndroid Build Coastguard Worker 
3469*03ce13f7SAndroid Build Coastguard Worker     InstCall *Call =
3470*03ce13f7SAndroid Build Coastguard Worker         makeHelperCall(ValTy == IceType_i32 ? RuntimeHelper::H_call_ctpop_i32
3471*03ce13f7SAndroid Build Coastguard Worker                                             : RuntimeHelper::H_call_ctpop_i64,
3472*03ce13f7SAndroid Build Coastguard Worker                        T, 1);
3473*03ce13f7SAndroid Build Coastguard Worker     Call->addArg(Val);
3474*03ce13f7SAndroid Build Coastguard Worker     lowerCall(Call);
3475*03ce13f7SAndroid Build Coastguard Worker     // The popcount helpers always return 32-bit values, while the intrinsic's
3476*03ce13f7SAndroid Build Coastguard Worker     // signature matches the native POPCNT instruction and fills a 64-bit reg
3477*03ce13f7SAndroid Build Coastguard Worker     // (in 64-bit mode). Thus, clear the upper bits of the dest just in case
3478*03ce13f7SAndroid Build Coastguard Worker     // the user doesn't do that in the IR. If the user does that in the IR,
3479*03ce13f7SAndroid Build Coastguard Worker     // then this zero'ing instruction is dead and gets optimized out.
3480*03ce13f7SAndroid Build Coastguard Worker     assert(Val->getType() == IceType_i64);
3481*03ce13f7SAndroid Build Coastguard Worker     // T is 64 bit. It needs to be copied to dest. We need to:
3482*03ce13f7SAndroid Build Coastguard Worker     //
3483*03ce13f7SAndroid Build Coastguard Worker     // T_1.32 = trunc T.64 to i32
3484*03ce13f7SAndroid Build Coastguard Worker     // T_2.64 = zext T_1.32 to i64
3485*03ce13f7SAndroid Build Coastguard Worker     // Dest.<<right_size>> = T_2.<<right_size>>
3486*03ce13f7SAndroid Build Coastguard Worker     //
3487*03ce13f7SAndroid Build Coastguard Worker     // which ensures the upper 32 bits will always be cleared. Just doing a
3488*03ce13f7SAndroid Build Coastguard Worker     //
3489*03ce13f7SAndroid Build Coastguard Worker     // mov Dest.32 = trunc T.32 to i32
3490*03ce13f7SAndroid Build Coastguard Worker     //
3491*03ce13f7SAndroid Build Coastguard Worker     // is dangerous because there's a chance the compiler will optimize this
3492*03ce13f7SAndroid Build Coastguard Worker     // copy out. To use _movzx we need two new registers (one 32-, and
3493*03ce13f7SAndroid Build Coastguard Worker     // another 64-bit wide.)
3494*03ce13f7SAndroid Build Coastguard Worker     Variable *T_1 = makeReg(IceType_i32);
3495*03ce13f7SAndroid Build Coastguard Worker     _mov(T_1, T);
3496*03ce13f7SAndroid Build Coastguard Worker     Variable *T_2 = makeReg(IceType_i64);
3497*03ce13f7SAndroid Build Coastguard Worker     _movzx(T_2, T_1);
3498*03ce13f7SAndroid Build Coastguard Worker     _mov(Dest, T_2);
3499*03ce13f7SAndroid Build Coastguard Worker     return;
3500*03ce13f7SAndroid Build Coastguard Worker   }
3501*03ce13f7SAndroid Build Coastguard Worker   case Intrinsics::Ctlz: {
3502*03ce13f7SAndroid Build Coastguard Worker     // The "is zero undef" parameter is ignored and we always return a
3503*03ce13f7SAndroid Build Coastguard Worker     // well-defined value.
3504*03ce13f7SAndroid Build Coastguard Worker     Operand *Val = legalize(Instr->getArg(0));
3505*03ce13f7SAndroid Build Coastguard Worker     Operand *FirstVal = Val;
3506*03ce13f7SAndroid Build Coastguard Worker     Operand *SecondVal = nullptr;
3507*03ce13f7SAndroid Build Coastguard Worker     constexpr bool IsCttz = false;
3508*03ce13f7SAndroid Build Coastguard Worker     lowerCountZeros(IsCttz, Val->getType(), Instr->getDest(), FirstVal,
3509*03ce13f7SAndroid Build Coastguard Worker                     SecondVal);
3510*03ce13f7SAndroid Build Coastguard Worker     return;
3511*03ce13f7SAndroid Build Coastguard Worker   }
3512*03ce13f7SAndroid Build Coastguard Worker   case Intrinsics::Cttz: {
3513*03ce13f7SAndroid Build Coastguard Worker     // The "is zero undef" parameter is ignored and we always return a
3514*03ce13f7SAndroid Build Coastguard Worker     // well-defined value.
3515*03ce13f7SAndroid Build Coastguard Worker     Operand *Val = legalize(Instr->getArg(0));
3516*03ce13f7SAndroid Build Coastguard Worker     Operand *FirstVal = Val;
3517*03ce13f7SAndroid Build Coastguard Worker     Operand *SecondVal = nullptr;
3518*03ce13f7SAndroid Build Coastguard Worker     constexpr bool IsCttz = true;
3519*03ce13f7SAndroid Build Coastguard Worker     lowerCountZeros(IsCttz, Val->getType(), Instr->getDest(), FirstVal,
3520*03ce13f7SAndroid Build Coastguard Worker                     SecondVal);
3521*03ce13f7SAndroid Build Coastguard Worker     return;
3522*03ce13f7SAndroid Build Coastguard Worker   }
3523*03ce13f7SAndroid Build Coastguard Worker   case Intrinsics::Fabs: {
3524*03ce13f7SAndroid Build Coastguard Worker     Operand *Src = legalize(Instr->getArg(0));
3525*03ce13f7SAndroid Build Coastguard Worker     Type Ty = Src->getType();
3526*03ce13f7SAndroid Build Coastguard Worker     Variable *Dest = Instr->getDest();
3527*03ce13f7SAndroid Build Coastguard Worker     Variable *T = makeVectorOfFabsMask(Ty);
3528*03ce13f7SAndroid Build Coastguard Worker     // The pand instruction operates on an m128 memory operand, so if Src is an
3529*03ce13f7SAndroid Build Coastguard Worker     // f32 or f64, we need to make sure it's in a register.
3530*03ce13f7SAndroid Build Coastguard Worker     if (isVectorType(Ty)) {
3531*03ce13f7SAndroid Build Coastguard Worker       if (llvm::isa<X86OperandMem>(Src))
3532*03ce13f7SAndroid Build Coastguard Worker         Src = legalizeToReg(Src);
3533*03ce13f7SAndroid Build Coastguard Worker     } else {
3534*03ce13f7SAndroid Build Coastguard Worker       Src = legalizeToReg(Src);
3535*03ce13f7SAndroid Build Coastguard Worker     }
3536*03ce13f7SAndroid Build Coastguard Worker     _pand(T, Src);
3537*03ce13f7SAndroid Build Coastguard Worker     if (isVectorType(Ty))
3538*03ce13f7SAndroid Build Coastguard Worker       _movp(Dest, T);
3539*03ce13f7SAndroid Build Coastguard Worker     else
3540*03ce13f7SAndroid Build Coastguard Worker       _mov(Dest, T);
3541*03ce13f7SAndroid Build Coastguard Worker     return;
3542*03ce13f7SAndroid Build Coastguard Worker   }
3543*03ce13f7SAndroid Build Coastguard Worker   case Intrinsics::Longjmp: {
3544*03ce13f7SAndroid Build Coastguard Worker     InstCall *Call = makeHelperCall(RuntimeHelper::H_call_longjmp, nullptr, 2);
3545*03ce13f7SAndroid Build Coastguard Worker     Call->addArg(Instr->getArg(0));
3546*03ce13f7SAndroid Build Coastguard Worker     Call->addArg(Instr->getArg(1));
3547*03ce13f7SAndroid Build Coastguard Worker     lowerCall(Call);
3548*03ce13f7SAndroid Build Coastguard Worker     return;
3549*03ce13f7SAndroid Build Coastguard Worker   }
3550*03ce13f7SAndroid Build Coastguard Worker   case Intrinsics::Memcpy: {
3551*03ce13f7SAndroid Build Coastguard Worker     lowerMemcpy(Instr->getArg(0), Instr->getArg(1), Instr->getArg(2));
3552*03ce13f7SAndroid Build Coastguard Worker     return;
3553*03ce13f7SAndroid Build Coastguard Worker   }
3554*03ce13f7SAndroid Build Coastguard Worker   case Intrinsics::Memmove: {
3555*03ce13f7SAndroid Build Coastguard Worker     lowerMemmove(Instr->getArg(0), Instr->getArg(1), Instr->getArg(2));
3556*03ce13f7SAndroid Build Coastguard Worker     return;
3557*03ce13f7SAndroid Build Coastguard Worker   }
3558*03ce13f7SAndroid Build Coastguard Worker   case Intrinsics::Memset: {
3559*03ce13f7SAndroid Build Coastguard Worker     lowerMemset(Instr->getArg(0), Instr->getArg(1), Instr->getArg(2));
3560*03ce13f7SAndroid Build Coastguard Worker     return;
3561*03ce13f7SAndroid Build Coastguard Worker   }
3562*03ce13f7SAndroid Build Coastguard Worker   case Intrinsics::Setjmp: {
3563*03ce13f7SAndroid Build Coastguard Worker     InstCall *Call =
3564*03ce13f7SAndroid Build Coastguard Worker         makeHelperCall(RuntimeHelper::H_call_setjmp, Instr->getDest(), 1);
3565*03ce13f7SAndroid Build Coastguard Worker     Call->addArg(Instr->getArg(0));
3566*03ce13f7SAndroid Build Coastguard Worker     lowerCall(Call);
3567*03ce13f7SAndroid Build Coastguard Worker     return;
3568*03ce13f7SAndroid Build Coastguard Worker   }
3569*03ce13f7SAndroid Build Coastguard Worker   case Intrinsics::Sqrt: {
3570*03ce13f7SAndroid Build Coastguard Worker     Operand *Src = legalize(Instr->getArg(0));
3571*03ce13f7SAndroid Build Coastguard Worker     Variable *Dest = Instr->getDest();
3572*03ce13f7SAndroid Build Coastguard Worker     Variable *T = makeReg(Dest->getType());
3573*03ce13f7SAndroid Build Coastguard Worker     _sqrt(T, Src);
3574*03ce13f7SAndroid Build Coastguard Worker     if (isVectorType(Dest->getType())) {
3575*03ce13f7SAndroid Build Coastguard Worker       _movp(Dest, T);
3576*03ce13f7SAndroid Build Coastguard Worker     } else {
3577*03ce13f7SAndroid Build Coastguard Worker       _mov(Dest, T);
3578*03ce13f7SAndroid Build Coastguard Worker     }
3579*03ce13f7SAndroid Build Coastguard Worker     return;
3580*03ce13f7SAndroid Build Coastguard Worker   }
3581*03ce13f7SAndroid Build Coastguard Worker   case Intrinsics::Stacksave: {
3582*03ce13f7SAndroid Build Coastguard Worker     Variable *rsp =
3583*03ce13f7SAndroid Build Coastguard Worker         Func->getTarget()->getPhysicalRegister(getStackReg(), WordType);
3584*03ce13f7SAndroid Build Coastguard Worker     Variable *Dest = Instr->getDest();
3585*03ce13f7SAndroid Build Coastguard Worker     _mov(Dest, rsp);
3586*03ce13f7SAndroid Build Coastguard Worker     return;
3587*03ce13f7SAndroid Build Coastguard Worker   }
3588*03ce13f7SAndroid Build Coastguard Worker   case Intrinsics::Stackrestore: {
3589*03ce13f7SAndroid Build Coastguard Worker     Operand *Src = Instr->getArg(0);
3590*03ce13f7SAndroid Build Coastguard Worker     _mov_sp(Src);
3591*03ce13f7SAndroid Build Coastguard Worker     return;
3592*03ce13f7SAndroid Build Coastguard Worker   }
3593*03ce13f7SAndroid Build Coastguard Worker 
3594*03ce13f7SAndroid Build Coastguard Worker   case Intrinsics::Trap:
3595*03ce13f7SAndroid Build Coastguard Worker     _ud2();
3596*03ce13f7SAndroid Build Coastguard Worker     return;
3597*03ce13f7SAndroid Build Coastguard Worker   case Intrinsics::LoadSubVector: {
3598*03ce13f7SAndroid Build Coastguard Worker     assert(llvm::isa<ConstantInteger32>(Instr->getArg(1)) &&
3599*03ce13f7SAndroid Build Coastguard Worker            "LoadSubVector second argument must be a constant");
3600*03ce13f7SAndroid Build Coastguard Worker     Variable *Dest = Instr->getDest();
3601*03ce13f7SAndroid Build Coastguard Worker     Type Ty = Dest->getType();
3602*03ce13f7SAndroid Build Coastguard Worker     auto *SubVectorSize = llvm::cast<ConstantInteger32>(Instr->getArg(1));
3603*03ce13f7SAndroid Build Coastguard Worker     Operand *Addr = Instr->getArg(0);
3604*03ce13f7SAndroid Build Coastguard Worker     X86OperandMem *Src = formMemoryOperand(Addr, Ty);
3605*03ce13f7SAndroid Build Coastguard Worker     doMockBoundsCheck(Src);
3606*03ce13f7SAndroid Build Coastguard Worker 
3607*03ce13f7SAndroid Build Coastguard Worker     if (Dest->isRematerializable()) {
3608*03ce13f7SAndroid Build Coastguard Worker       Context.insert<InstFakeDef>(Dest);
3609*03ce13f7SAndroid Build Coastguard Worker       return;
3610*03ce13f7SAndroid Build Coastguard Worker     }
3611*03ce13f7SAndroid Build Coastguard Worker 
3612*03ce13f7SAndroid Build Coastguard Worker     auto *T = makeReg(Ty);
3613*03ce13f7SAndroid Build Coastguard Worker     switch (SubVectorSize->getValue()) {
3614*03ce13f7SAndroid Build Coastguard Worker     case 4:
3615*03ce13f7SAndroid Build Coastguard Worker       _movd(T, Src);
3616*03ce13f7SAndroid Build Coastguard Worker       break;
3617*03ce13f7SAndroid Build Coastguard Worker     case 8:
3618*03ce13f7SAndroid Build Coastguard Worker       _movq(T, Src);
3619*03ce13f7SAndroid Build Coastguard Worker       break;
3620*03ce13f7SAndroid Build Coastguard Worker     default:
3621*03ce13f7SAndroid Build Coastguard Worker       Func->setError("Unexpected size for LoadSubVector");
3622*03ce13f7SAndroid Build Coastguard Worker       return;
3623*03ce13f7SAndroid Build Coastguard Worker     }
3624*03ce13f7SAndroid Build Coastguard Worker     _movp(Dest, T);
3625*03ce13f7SAndroid Build Coastguard Worker     return;
3626*03ce13f7SAndroid Build Coastguard Worker   }
3627*03ce13f7SAndroid Build Coastguard Worker   case Intrinsics::StoreSubVector: {
3628*03ce13f7SAndroid Build Coastguard Worker     assert(llvm::isa<ConstantInteger32>(Instr->getArg(2)) &&
3629*03ce13f7SAndroid Build Coastguard Worker            "StoreSubVector third argument must be a constant");
3630*03ce13f7SAndroid Build Coastguard Worker     auto *SubVectorSize = llvm::cast<ConstantInteger32>(Instr->getArg(2));
3631*03ce13f7SAndroid Build Coastguard Worker     Operand *Value = Instr->getArg(0);
3632*03ce13f7SAndroid Build Coastguard Worker     Operand *Addr = Instr->getArg(1);
3633*03ce13f7SAndroid Build Coastguard Worker     X86OperandMem *NewAddr = formMemoryOperand(Addr, Value->getType());
3634*03ce13f7SAndroid Build Coastguard Worker     doMockBoundsCheck(NewAddr);
3635*03ce13f7SAndroid Build Coastguard Worker 
3636*03ce13f7SAndroid Build Coastguard Worker     Value = legalizeToReg(Value);
3637*03ce13f7SAndroid Build Coastguard Worker 
3638*03ce13f7SAndroid Build Coastguard Worker     switch (SubVectorSize->getValue()) {
3639*03ce13f7SAndroid Build Coastguard Worker     case 4:
3640*03ce13f7SAndroid Build Coastguard Worker       _stored(Value, NewAddr);
3641*03ce13f7SAndroid Build Coastguard Worker       break;
3642*03ce13f7SAndroid Build Coastguard Worker     case 8:
3643*03ce13f7SAndroid Build Coastguard Worker       _storeq(Value, NewAddr);
3644*03ce13f7SAndroid Build Coastguard Worker       break;
3645*03ce13f7SAndroid Build Coastguard Worker     default:
3646*03ce13f7SAndroid Build Coastguard Worker       Func->setError("Unexpected size for StoreSubVector");
3647*03ce13f7SAndroid Build Coastguard Worker       return;
3648*03ce13f7SAndroid Build Coastguard Worker     }
3649*03ce13f7SAndroid Build Coastguard Worker     return;
3650*03ce13f7SAndroid Build Coastguard Worker   }
3651*03ce13f7SAndroid Build Coastguard Worker   case Intrinsics::VectorPackSigned: {
3652*03ce13f7SAndroid Build Coastguard Worker     Operand *Src0 = Instr->getArg(0);
3653*03ce13f7SAndroid Build Coastguard Worker     Operand *Src1 = Instr->getArg(1);
3654*03ce13f7SAndroid Build Coastguard Worker     Variable *Dest = Instr->getDest();
3655*03ce13f7SAndroid Build Coastguard Worker     auto *T = makeReg(Src0->getType());
3656*03ce13f7SAndroid Build Coastguard Worker     auto *Src0RM = legalize(Src0, Legal_Reg | Legal_Mem);
3657*03ce13f7SAndroid Build Coastguard Worker     auto *Src1RM = legalize(Src1, Legal_Reg | Legal_Mem);
3658*03ce13f7SAndroid Build Coastguard Worker     _movp(T, Src0RM);
3659*03ce13f7SAndroid Build Coastguard Worker     _packss(T, Src1RM);
3660*03ce13f7SAndroid Build Coastguard Worker     _movp(Dest, T);
3661*03ce13f7SAndroid Build Coastguard Worker     return;
3662*03ce13f7SAndroid Build Coastguard Worker   }
3663*03ce13f7SAndroid Build Coastguard Worker   case Intrinsics::VectorPackUnsigned: {
3664*03ce13f7SAndroid Build Coastguard Worker     Operand *Src0 = Instr->getArg(0);
3665*03ce13f7SAndroid Build Coastguard Worker     Operand *Src1 = Instr->getArg(1);
3666*03ce13f7SAndroid Build Coastguard Worker     Variable *Dest = Instr->getDest();
3667*03ce13f7SAndroid Build Coastguard Worker     auto *T = makeReg(Src0->getType());
3668*03ce13f7SAndroid Build Coastguard Worker     auto *Src0RM = legalize(Src0, Legal_Reg | Legal_Mem);
3669*03ce13f7SAndroid Build Coastguard Worker     auto *Src1RM = legalize(Src1, Legal_Reg | Legal_Mem);
3670*03ce13f7SAndroid Build Coastguard Worker     _movp(T, Src0RM);
3671*03ce13f7SAndroid Build Coastguard Worker     _packus(T, Src1RM);
3672*03ce13f7SAndroid Build Coastguard Worker     _movp(Dest, T);
3673*03ce13f7SAndroid Build Coastguard Worker     return;
3674*03ce13f7SAndroid Build Coastguard Worker   }
3675*03ce13f7SAndroid Build Coastguard Worker   case Intrinsics::SignMask: {
3676*03ce13f7SAndroid Build Coastguard Worker     Operand *SrcReg = legalizeToReg(Instr->getArg(0));
3677*03ce13f7SAndroid Build Coastguard Worker     Variable *Dest = Instr->getDest();
3678*03ce13f7SAndroid Build Coastguard Worker     Variable *T = makeReg(IceType_i32);
3679*03ce13f7SAndroid Build Coastguard Worker     if (SrcReg->getType() == IceType_v4f32 ||
3680*03ce13f7SAndroid Build Coastguard Worker         SrcReg->getType() == IceType_v4i32 ||
3681*03ce13f7SAndroid Build Coastguard Worker         SrcReg->getType() == IceType_v16i8) {
3682*03ce13f7SAndroid Build Coastguard Worker       _movmsk(T, SrcReg);
3683*03ce13f7SAndroid Build Coastguard Worker     } else {
3684*03ce13f7SAndroid Build Coastguard Worker       // TODO(capn): We could implement v8i16 sign mask using packsswb/pmovmskb
3685*03ce13f7SAndroid Build Coastguard Worker       llvm::report_fatal_error("Invalid type for SignMask intrinsic");
3686*03ce13f7SAndroid Build Coastguard Worker     }
3687*03ce13f7SAndroid Build Coastguard Worker     _mov(Dest, T);
3688*03ce13f7SAndroid Build Coastguard Worker     return;
3689*03ce13f7SAndroid Build Coastguard Worker   }
3690*03ce13f7SAndroid Build Coastguard Worker   case Intrinsics::MultiplyHighSigned: {
3691*03ce13f7SAndroid Build Coastguard Worker     Operand *Src0 = Instr->getArg(0);
3692*03ce13f7SAndroid Build Coastguard Worker     Operand *Src1 = Instr->getArg(1);
3693*03ce13f7SAndroid Build Coastguard Worker     Variable *Dest = Instr->getDest();
3694*03ce13f7SAndroid Build Coastguard Worker     auto *T = makeReg(Dest->getType());
3695*03ce13f7SAndroid Build Coastguard Worker     auto *Src0RM = legalize(Src0, Legal_Reg | Legal_Mem);
3696*03ce13f7SAndroid Build Coastguard Worker     auto *Src1RM = legalize(Src1, Legal_Reg | Legal_Mem);
3697*03ce13f7SAndroid Build Coastguard Worker     _movp(T, Src0RM);
3698*03ce13f7SAndroid Build Coastguard Worker     _pmulhw(T, Src1RM);
3699*03ce13f7SAndroid Build Coastguard Worker     _movp(Dest, T);
3700*03ce13f7SAndroid Build Coastguard Worker     return;
3701*03ce13f7SAndroid Build Coastguard Worker   }
3702*03ce13f7SAndroid Build Coastguard Worker   case Intrinsics::MultiplyHighUnsigned: {
3703*03ce13f7SAndroid Build Coastguard Worker     Operand *Src0 = Instr->getArg(0);
3704*03ce13f7SAndroid Build Coastguard Worker     Operand *Src1 = Instr->getArg(1);
3705*03ce13f7SAndroid Build Coastguard Worker     Variable *Dest = Instr->getDest();
3706*03ce13f7SAndroid Build Coastguard Worker     auto *T = makeReg(Dest->getType());
3707*03ce13f7SAndroid Build Coastguard Worker     auto *Src0RM = legalize(Src0, Legal_Reg | Legal_Mem);
3708*03ce13f7SAndroid Build Coastguard Worker     auto *Src1RM = legalize(Src1, Legal_Reg | Legal_Mem);
3709*03ce13f7SAndroid Build Coastguard Worker     _movp(T, Src0RM);
3710*03ce13f7SAndroid Build Coastguard Worker     _pmulhuw(T, Src1RM);
3711*03ce13f7SAndroid Build Coastguard Worker     _movp(Dest, T);
3712*03ce13f7SAndroid Build Coastguard Worker     return;
3713*03ce13f7SAndroid Build Coastguard Worker   }
3714*03ce13f7SAndroid Build Coastguard Worker   case Intrinsics::MultiplyAddPairs: {
3715*03ce13f7SAndroid Build Coastguard Worker     Operand *Src0 = Instr->getArg(0);
3716*03ce13f7SAndroid Build Coastguard Worker     Operand *Src1 = Instr->getArg(1);
3717*03ce13f7SAndroid Build Coastguard Worker     Variable *Dest = Instr->getDest();
3718*03ce13f7SAndroid Build Coastguard Worker     auto *T = makeReg(Dest->getType());
3719*03ce13f7SAndroid Build Coastguard Worker     auto *Src0RM = legalize(Src0, Legal_Reg | Legal_Mem);
3720*03ce13f7SAndroid Build Coastguard Worker     auto *Src1RM = legalize(Src1, Legal_Reg | Legal_Mem);
3721*03ce13f7SAndroid Build Coastguard Worker     _movp(T, Src0RM);
3722*03ce13f7SAndroid Build Coastguard Worker     _pmaddwd(T, Src1RM);
3723*03ce13f7SAndroid Build Coastguard Worker     _movp(Dest, T);
3724*03ce13f7SAndroid Build Coastguard Worker     return;
3725*03ce13f7SAndroid Build Coastguard Worker   }
3726*03ce13f7SAndroid Build Coastguard Worker   case Intrinsics::AddSaturateSigned: {
3727*03ce13f7SAndroid Build Coastguard Worker     Operand *Src0 = Instr->getArg(0);
3728*03ce13f7SAndroid Build Coastguard Worker     Operand *Src1 = Instr->getArg(1);
3729*03ce13f7SAndroid Build Coastguard Worker     Variable *Dest = Instr->getDest();
3730*03ce13f7SAndroid Build Coastguard Worker     auto *T = makeReg(Dest->getType());
3731*03ce13f7SAndroid Build Coastguard Worker     auto *Src0RM = legalize(Src0, Legal_Reg | Legal_Mem);
3732*03ce13f7SAndroid Build Coastguard Worker     auto *Src1RM = legalize(Src1, Legal_Reg | Legal_Mem);
3733*03ce13f7SAndroid Build Coastguard Worker     _movp(T, Src0RM);
3734*03ce13f7SAndroid Build Coastguard Worker     _padds(T, Src1RM);
3735*03ce13f7SAndroid Build Coastguard Worker     _movp(Dest, T);
3736*03ce13f7SAndroid Build Coastguard Worker     return;
3737*03ce13f7SAndroid Build Coastguard Worker   }
3738*03ce13f7SAndroid Build Coastguard Worker   case Intrinsics::SubtractSaturateSigned: {
3739*03ce13f7SAndroid Build Coastguard Worker     Operand *Src0 = Instr->getArg(0);
3740*03ce13f7SAndroid Build Coastguard Worker     Operand *Src1 = Instr->getArg(1);
3741*03ce13f7SAndroid Build Coastguard Worker     Variable *Dest = Instr->getDest();
3742*03ce13f7SAndroid Build Coastguard Worker     auto *T = makeReg(Dest->getType());
3743*03ce13f7SAndroid Build Coastguard Worker     auto *Src0RM = legalize(Src0, Legal_Reg | Legal_Mem);
3744*03ce13f7SAndroid Build Coastguard Worker     auto *Src1RM = legalize(Src1, Legal_Reg | Legal_Mem);
3745*03ce13f7SAndroid Build Coastguard Worker     _movp(T, Src0RM);
3746*03ce13f7SAndroid Build Coastguard Worker     _psubs(T, Src1RM);
3747*03ce13f7SAndroid Build Coastguard Worker     _movp(Dest, T);
3748*03ce13f7SAndroid Build Coastguard Worker     return;
3749*03ce13f7SAndroid Build Coastguard Worker   }
3750*03ce13f7SAndroid Build Coastguard Worker   case Intrinsics::AddSaturateUnsigned: {
3751*03ce13f7SAndroid Build Coastguard Worker     Operand *Src0 = Instr->getArg(0);
3752*03ce13f7SAndroid Build Coastguard Worker     Operand *Src1 = Instr->getArg(1);
3753*03ce13f7SAndroid Build Coastguard Worker     Variable *Dest = Instr->getDest();
3754*03ce13f7SAndroid Build Coastguard Worker     auto *T = makeReg(Dest->getType());
3755*03ce13f7SAndroid Build Coastguard Worker     auto *Src0RM = legalize(Src0, Legal_Reg | Legal_Mem);
3756*03ce13f7SAndroid Build Coastguard Worker     auto *Src1RM = legalize(Src1, Legal_Reg | Legal_Mem);
3757*03ce13f7SAndroid Build Coastguard Worker     _movp(T, Src0RM);
3758*03ce13f7SAndroid Build Coastguard Worker     _paddus(T, Src1RM);
3759*03ce13f7SAndroid Build Coastguard Worker     _movp(Dest, T);
3760*03ce13f7SAndroid Build Coastguard Worker     return;
3761*03ce13f7SAndroid Build Coastguard Worker   }
3762*03ce13f7SAndroid Build Coastguard Worker   case Intrinsics::SubtractSaturateUnsigned: {
3763*03ce13f7SAndroid Build Coastguard Worker     Operand *Src0 = Instr->getArg(0);
3764*03ce13f7SAndroid Build Coastguard Worker     Operand *Src1 = Instr->getArg(1);
3765*03ce13f7SAndroid Build Coastguard Worker     Variable *Dest = Instr->getDest();
3766*03ce13f7SAndroid Build Coastguard Worker     auto *T = makeReg(Dest->getType());
3767*03ce13f7SAndroid Build Coastguard Worker     auto *Src0RM = legalize(Src0, Legal_Reg | Legal_Mem);
3768*03ce13f7SAndroid Build Coastguard Worker     auto *Src1RM = legalize(Src1, Legal_Reg | Legal_Mem);
3769*03ce13f7SAndroid Build Coastguard Worker     _movp(T, Src0RM);
3770*03ce13f7SAndroid Build Coastguard Worker     _psubus(T, Src1RM);
3771*03ce13f7SAndroid Build Coastguard Worker     _movp(Dest, T);
3772*03ce13f7SAndroid Build Coastguard Worker     return;
3773*03ce13f7SAndroid Build Coastguard Worker   }
3774*03ce13f7SAndroid Build Coastguard Worker   case Intrinsics::Nearbyint: {
3775*03ce13f7SAndroid Build Coastguard Worker     Operand *Src = Instr->getArg(0);
3776*03ce13f7SAndroid Build Coastguard Worker     Variable *Dest = Instr->getDest();
3777*03ce13f7SAndroid Build Coastguard Worker     Type DestTy = Dest->getType();
3778*03ce13f7SAndroid Build Coastguard Worker     if (isVectorType(DestTy)) {
3779*03ce13f7SAndroid Build Coastguard Worker       assert(DestTy == IceType_v4i32);
3780*03ce13f7SAndroid Build Coastguard Worker       assert(Src->getType() == IceType_v4f32);
3781*03ce13f7SAndroid Build Coastguard Worker       Operand *Src0R = legalizeToReg(Src);
3782*03ce13f7SAndroid Build Coastguard Worker       Variable *T = makeReg(DestTy);
3783*03ce13f7SAndroid Build Coastguard Worker       _cvt(T, Src0R, Insts::Cvt::Ps2dq);
3784*03ce13f7SAndroid Build Coastguard Worker       _movp(Dest, T);
3785*03ce13f7SAndroid Build Coastguard Worker     } else {
3786*03ce13f7SAndroid Build Coastguard Worker       Operand *Src0RM = legalize(Src, Legal_Reg | Legal_Mem);
3787*03ce13f7SAndroid Build Coastguard Worker       // t1.i32 = cvt Src0RM; t2.dest_type = t1; Dest = t2.dest_type
3788*03ce13f7SAndroid Build Coastguard Worker       Variable *T_1 = nullptr;
3789*03ce13f7SAndroid Build Coastguard Worker       if (DestTy == IceType_i64) {
3790*03ce13f7SAndroid Build Coastguard Worker         T_1 = makeReg(IceType_i64);
3791*03ce13f7SAndroid Build Coastguard Worker       } else {
3792*03ce13f7SAndroid Build Coastguard Worker         assert(DestTy != IceType_i64);
3793*03ce13f7SAndroid Build Coastguard Worker         T_1 = makeReg(IceType_i32);
3794*03ce13f7SAndroid Build Coastguard Worker       }
3795*03ce13f7SAndroid Build Coastguard Worker       // cvt() requires its integer argument to be a GPR.
3796*03ce13f7SAndroid Build Coastguard Worker       Variable *T_2 = makeReg(DestTy);
3797*03ce13f7SAndroid Build Coastguard Worker       if (isByteSizedType(DestTy)) {
3798*03ce13f7SAndroid Build Coastguard Worker         assert(T_1->getType() == IceType_i32);
3799*03ce13f7SAndroid Build Coastguard Worker         T_1->setRegClass(RCX86_Is32To8);
3800*03ce13f7SAndroid Build Coastguard Worker         T_2->setRegClass(RCX86_IsTrunc8Rcvr);
3801*03ce13f7SAndroid Build Coastguard Worker       }
3802*03ce13f7SAndroid Build Coastguard Worker       _cvt(T_1, Src0RM, Insts::Cvt::Ss2si);
3803*03ce13f7SAndroid Build Coastguard Worker       _mov(T_2, T_1); // T_1 and T_2 may have different integer types
3804*03ce13f7SAndroid Build Coastguard Worker       if (DestTy == IceType_i1)
3805*03ce13f7SAndroid Build Coastguard Worker         _and(T_2, Ctx->getConstantInt1(1));
3806*03ce13f7SAndroid Build Coastguard Worker       _mov(Dest, T_2);
3807*03ce13f7SAndroid Build Coastguard Worker     }
3808*03ce13f7SAndroid Build Coastguard Worker     return;
3809*03ce13f7SAndroid Build Coastguard Worker   }
3810*03ce13f7SAndroid Build Coastguard Worker   case Intrinsics::Round: {
3811*03ce13f7SAndroid Build Coastguard Worker     assert(InstructionSet >= SSE4_1);
3812*03ce13f7SAndroid Build Coastguard Worker     Variable *Dest = Instr->getDest();
3813*03ce13f7SAndroid Build Coastguard Worker     Operand *Src = Instr->getArg(0);
3814*03ce13f7SAndroid Build Coastguard Worker     Operand *Mode = Instr->getArg(1);
3815*03ce13f7SAndroid Build Coastguard Worker     assert(llvm::isa<ConstantInteger32>(Mode) &&
3816*03ce13f7SAndroid Build Coastguard Worker            "Round last argument must be a constant");
3817*03ce13f7SAndroid Build Coastguard Worker     auto *SrcRM = legalize(Src, Legal_Reg | Legal_Mem);
3818*03ce13f7SAndroid Build Coastguard Worker     int32_t Imm = llvm::cast<ConstantInteger32>(Mode)->getValue();
3819*03ce13f7SAndroid Build Coastguard Worker     (void)Imm;
3820*03ce13f7SAndroid Build Coastguard Worker     assert(Imm >= 0 && Imm < 4 && "Invalid rounding mode");
3821*03ce13f7SAndroid Build Coastguard Worker     auto *T = makeReg(Dest->getType());
3822*03ce13f7SAndroid Build Coastguard Worker     _round(T, SrcRM, Mode);
3823*03ce13f7SAndroid Build Coastguard Worker     _movp(Dest, T);
3824*03ce13f7SAndroid Build Coastguard Worker     return;
3825*03ce13f7SAndroid Build Coastguard Worker   }
3826*03ce13f7SAndroid Build Coastguard Worker   default: // UnknownIntrinsic
3827*03ce13f7SAndroid Build Coastguard Worker     Func->setError("Unexpected intrinsic");
3828*03ce13f7SAndroid Build Coastguard Worker     return;
3829*03ce13f7SAndroid Build Coastguard Worker   }
3830*03ce13f7SAndroid Build Coastguard Worker   return;
3831*03ce13f7SAndroid Build Coastguard Worker }
3832*03ce13f7SAndroid Build Coastguard Worker 
lowerAtomicCmpxchg(Variable * DestPrev,Operand * Ptr,Operand * Expected,Operand * Desired)3833*03ce13f7SAndroid Build Coastguard Worker void TargetX8664::lowerAtomicCmpxchg(Variable *DestPrev, Operand *Ptr,
3834*03ce13f7SAndroid Build Coastguard Worker                                      Operand *Expected, Operand *Desired) {
3835*03ce13f7SAndroid Build Coastguard Worker   Type Ty = Expected->getType();
3836*03ce13f7SAndroid Build Coastguard Worker   RegNumT Eax;
3837*03ce13f7SAndroid Build Coastguard Worker   switch (Ty) {
3838*03ce13f7SAndroid Build Coastguard Worker   default:
3839*03ce13f7SAndroid Build Coastguard Worker     llvm::report_fatal_error("Bad type for cmpxchg");
3840*03ce13f7SAndroid Build Coastguard Worker   case IceType_i64:
3841*03ce13f7SAndroid Build Coastguard Worker     Eax = RegX8664::Reg_rax;
3842*03ce13f7SAndroid Build Coastguard Worker     break;
3843*03ce13f7SAndroid Build Coastguard Worker   case IceType_i32:
3844*03ce13f7SAndroid Build Coastguard Worker     Eax = RegX8664::Reg_eax;
3845*03ce13f7SAndroid Build Coastguard Worker     break;
3846*03ce13f7SAndroid Build Coastguard Worker   case IceType_i16:
3847*03ce13f7SAndroid Build Coastguard Worker     Eax = RegX8664::Reg_ax;
3848*03ce13f7SAndroid Build Coastguard Worker     break;
3849*03ce13f7SAndroid Build Coastguard Worker   case IceType_i8:
3850*03ce13f7SAndroid Build Coastguard Worker     Eax = RegX8664::Reg_al;
3851*03ce13f7SAndroid Build Coastguard Worker     break;
3852*03ce13f7SAndroid Build Coastguard Worker   }
3853*03ce13f7SAndroid Build Coastguard Worker   Variable *T_eax = makeReg(Ty, Eax);
3854*03ce13f7SAndroid Build Coastguard Worker   _mov(T_eax, Expected);
3855*03ce13f7SAndroid Build Coastguard Worker   X86OperandMem *Addr = formMemoryOperand(Ptr, Ty);
3856*03ce13f7SAndroid Build Coastguard Worker   Variable *DesiredReg = legalizeToReg(Desired);
3857*03ce13f7SAndroid Build Coastguard Worker   constexpr bool Locked = true;
3858*03ce13f7SAndroid Build Coastguard Worker   _cmpxchg(Addr, T_eax, DesiredReg, Locked);
3859*03ce13f7SAndroid Build Coastguard Worker   _mov(DestPrev, T_eax);
3860*03ce13f7SAndroid Build Coastguard Worker }
3861*03ce13f7SAndroid Build Coastguard Worker 
tryOptimizedCmpxchgCmpBr(Variable * Dest,Operand * PtrToMem,Operand * Expected,Operand * Desired)3862*03ce13f7SAndroid Build Coastguard Worker bool TargetX8664::tryOptimizedCmpxchgCmpBr(Variable *Dest, Operand *PtrToMem,
3863*03ce13f7SAndroid Build Coastguard Worker                                            Operand *Expected,
3864*03ce13f7SAndroid Build Coastguard Worker                                            Operand *Desired) {
3865*03ce13f7SAndroid Build Coastguard Worker   if (Func->getOptLevel() == Opt_m1)
3866*03ce13f7SAndroid Build Coastguard Worker     return false;
3867*03ce13f7SAndroid Build Coastguard Worker   // Peek ahead a few instructions and see how Dest is used.
3868*03ce13f7SAndroid Build Coastguard Worker   // It's very common to have:
3869*03ce13f7SAndroid Build Coastguard Worker   //
3870*03ce13f7SAndroid Build Coastguard Worker   // %x = call i32 @llvm.nacl.atomic.cmpxchg.i32(i32* ptr, i32 %expected, ...)
3871*03ce13f7SAndroid Build Coastguard Worker   // [%y_phi = ...] // list of phi stores
3872*03ce13f7SAndroid Build Coastguard Worker   // %p = icmp eq i32 %x, %expected
3873*03ce13f7SAndroid Build Coastguard Worker   // br i1 %p, label %l1, label %l2
3874*03ce13f7SAndroid Build Coastguard Worker   //
3875*03ce13f7SAndroid Build Coastguard Worker   // which we can optimize into:
3876*03ce13f7SAndroid Build Coastguard Worker   //
3877*03ce13f7SAndroid Build Coastguard Worker   // %x = <cmpxchg code>
3878*03ce13f7SAndroid Build Coastguard Worker   // [%y_phi = ...] // list of phi stores
3879*03ce13f7SAndroid Build Coastguard Worker   // br eq, %l1, %l2
3880*03ce13f7SAndroid Build Coastguard Worker   InstList::iterator I = Context.getCur();
3881*03ce13f7SAndroid Build Coastguard Worker   // I is currently the InstIntrinsic. Peek past that.
3882*03ce13f7SAndroid Build Coastguard Worker   // This assumes that the atomic cmpxchg has not been lowered yet,
3883*03ce13f7SAndroid Build Coastguard Worker   // so that the instructions seen in the scan from "Cur" is simple.
3884*03ce13f7SAndroid Build Coastguard Worker   assert(llvm::isa<InstIntrinsic>(*I));
3885*03ce13f7SAndroid Build Coastguard Worker   Inst *NextInst = Context.getNextInst(I);
3886*03ce13f7SAndroid Build Coastguard Worker   if (!NextInst)
3887*03ce13f7SAndroid Build Coastguard Worker     return false;
3888*03ce13f7SAndroid Build Coastguard Worker   // There might be phi assignments right before the compare+branch, since this
3889*03ce13f7SAndroid Build Coastguard Worker   // could be a backward branch for a loop. This placement of assignments is
3890*03ce13f7SAndroid Build Coastguard Worker   // determined by placePhiStores().
3891*03ce13f7SAndroid Build Coastguard Worker   CfgVector<InstAssign *> PhiAssigns;
3892*03ce13f7SAndroid Build Coastguard Worker   while (auto *PhiAssign = llvm::dyn_cast<InstAssign>(NextInst)) {
3893*03ce13f7SAndroid Build Coastguard Worker     if (PhiAssign->getDest() == Dest)
3894*03ce13f7SAndroid Build Coastguard Worker       return false;
3895*03ce13f7SAndroid Build Coastguard Worker     PhiAssigns.push_back(PhiAssign);
3896*03ce13f7SAndroid Build Coastguard Worker     NextInst = Context.getNextInst(I);
3897*03ce13f7SAndroid Build Coastguard Worker     if (!NextInst)
3898*03ce13f7SAndroid Build Coastguard Worker       return false;
3899*03ce13f7SAndroid Build Coastguard Worker   }
3900*03ce13f7SAndroid Build Coastguard Worker   if (auto *NextCmp = llvm::dyn_cast<InstIcmp>(NextInst)) {
3901*03ce13f7SAndroid Build Coastguard Worker     if (!(NextCmp->getCondition() == InstIcmp::Eq &&
3902*03ce13f7SAndroid Build Coastguard Worker           ((NextCmp->getSrc(0) == Dest && NextCmp->getSrc(1) == Expected) ||
3903*03ce13f7SAndroid Build Coastguard Worker            (NextCmp->getSrc(1) == Dest && NextCmp->getSrc(0) == Expected)))) {
3904*03ce13f7SAndroid Build Coastguard Worker       return false;
3905*03ce13f7SAndroid Build Coastguard Worker     }
3906*03ce13f7SAndroid Build Coastguard Worker     NextInst = Context.getNextInst(I);
3907*03ce13f7SAndroid Build Coastguard Worker     if (!NextInst)
3908*03ce13f7SAndroid Build Coastguard Worker       return false;
3909*03ce13f7SAndroid Build Coastguard Worker     if (auto *NextBr = llvm::dyn_cast<InstBr>(NextInst)) {
3910*03ce13f7SAndroid Build Coastguard Worker       if (!NextBr->isUnconditional() &&
3911*03ce13f7SAndroid Build Coastguard Worker           NextCmp->getDest() == NextBr->getCondition() &&
3912*03ce13f7SAndroid Build Coastguard Worker           NextBr->isLastUse(NextCmp->getDest())) {
3913*03ce13f7SAndroid Build Coastguard Worker         lowerAtomicCmpxchg(Dest, PtrToMem, Expected, Desired);
3914*03ce13f7SAndroid Build Coastguard Worker         for (size_t i = 0; i < PhiAssigns.size(); ++i) {
3915*03ce13f7SAndroid Build Coastguard Worker           // Lower the phi assignments now, before the branch (same placement
3916*03ce13f7SAndroid Build Coastguard Worker           // as before).
3917*03ce13f7SAndroid Build Coastguard Worker           InstAssign *PhiAssign = PhiAssigns[i];
3918*03ce13f7SAndroid Build Coastguard Worker           PhiAssign->setDeleted();
3919*03ce13f7SAndroid Build Coastguard Worker           lowerAssign(PhiAssign);
3920*03ce13f7SAndroid Build Coastguard Worker           Context.advanceNext();
3921*03ce13f7SAndroid Build Coastguard Worker         }
3922*03ce13f7SAndroid Build Coastguard Worker         _br(CondX86::Br_e, NextBr->getTargetTrue(), NextBr->getTargetFalse());
3923*03ce13f7SAndroid Build Coastguard Worker         // Skip over the old compare and branch, by deleting them.
3924*03ce13f7SAndroid Build Coastguard Worker         NextCmp->setDeleted();
3925*03ce13f7SAndroid Build Coastguard Worker         NextBr->setDeleted();
3926*03ce13f7SAndroid Build Coastguard Worker         Context.advanceNext();
3927*03ce13f7SAndroid Build Coastguard Worker         Context.advanceNext();
3928*03ce13f7SAndroid Build Coastguard Worker         return true;
3929*03ce13f7SAndroid Build Coastguard Worker       }
3930*03ce13f7SAndroid Build Coastguard Worker     }
3931*03ce13f7SAndroid Build Coastguard Worker   }
3932*03ce13f7SAndroid Build Coastguard Worker   return false;
3933*03ce13f7SAndroid Build Coastguard Worker }
3934*03ce13f7SAndroid Build Coastguard Worker 
lowerAtomicRMW(Variable * Dest,uint32_t Operation,Operand * Ptr,Operand * Val)3935*03ce13f7SAndroid Build Coastguard Worker void TargetX8664::lowerAtomicRMW(Variable *Dest, uint32_t Operation,
3936*03ce13f7SAndroid Build Coastguard Worker                                  Operand *Ptr, Operand *Val) {
3937*03ce13f7SAndroid Build Coastguard Worker   bool NeedsCmpxchg = false;
3938*03ce13f7SAndroid Build Coastguard Worker   LowerBinOp Op_Lo = nullptr;
3939*03ce13f7SAndroid Build Coastguard Worker   LowerBinOp Op_Hi = nullptr;
3940*03ce13f7SAndroid Build Coastguard Worker   switch (Operation) {
3941*03ce13f7SAndroid Build Coastguard Worker   default:
3942*03ce13f7SAndroid Build Coastguard Worker     Func->setError("Unknown AtomicRMW operation");
3943*03ce13f7SAndroid Build Coastguard Worker     return;
3944*03ce13f7SAndroid Build Coastguard Worker   case Intrinsics::AtomicAdd: {
3945*03ce13f7SAndroid Build Coastguard Worker     X86OperandMem *Addr = formMemoryOperand(Ptr, Dest->getType());
3946*03ce13f7SAndroid Build Coastguard Worker     constexpr bool Locked = true;
3947*03ce13f7SAndroid Build Coastguard Worker     Variable *T = nullptr;
3948*03ce13f7SAndroid Build Coastguard Worker     _mov(T, Val);
3949*03ce13f7SAndroid Build Coastguard Worker     _xadd(Addr, T, Locked);
3950*03ce13f7SAndroid Build Coastguard Worker     _mov(Dest, T);
3951*03ce13f7SAndroid Build Coastguard Worker     return;
3952*03ce13f7SAndroid Build Coastguard Worker   }
3953*03ce13f7SAndroid Build Coastguard Worker   case Intrinsics::AtomicSub: {
3954*03ce13f7SAndroid Build Coastguard Worker     X86OperandMem *Addr = formMemoryOperand(Ptr, Dest->getType());
3955*03ce13f7SAndroid Build Coastguard Worker     constexpr bool Locked = true;
3956*03ce13f7SAndroid Build Coastguard Worker     Variable *T = nullptr;
3957*03ce13f7SAndroid Build Coastguard Worker     _mov(T, Val);
3958*03ce13f7SAndroid Build Coastguard Worker     _neg(T);
3959*03ce13f7SAndroid Build Coastguard Worker     _xadd(Addr, T, Locked);
3960*03ce13f7SAndroid Build Coastguard Worker     _mov(Dest, T);
3961*03ce13f7SAndroid Build Coastguard Worker     return;
3962*03ce13f7SAndroid Build Coastguard Worker   }
3963*03ce13f7SAndroid Build Coastguard Worker   case Intrinsics::AtomicOr:
3964*03ce13f7SAndroid Build Coastguard Worker     // TODO(jvoung): If Dest is null or dead, then some of these
3965*03ce13f7SAndroid Build Coastguard Worker     // operations do not need an "exchange", but just a locked op.
3966*03ce13f7SAndroid Build Coastguard Worker     // That appears to be "worth" it for sub, or, and, and xor.
3967*03ce13f7SAndroid Build Coastguard Worker     // xadd is probably fine vs lock add for add, and xchg is fine
3968*03ce13f7SAndroid Build Coastguard Worker     // vs an atomic store.
3969*03ce13f7SAndroid Build Coastguard Worker     NeedsCmpxchg = true;
3970*03ce13f7SAndroid Build Coastguard Worker     Op_Lo = &TargetX8664::_or;
3971*03ce13f7SAndroid Build Coastguard Worker     Op_Hi = &TargetX8664::_or;
3972*03ce13f7SAndroid Build Coastguard Worker     break;
3973*03ce13f7SAndroid Build Coastguard Worker   case Intrinsics::AtomicAnd:
3974*03ce13f7SAndroid Build Coastguard Worker     NeedsCmpxchg = true;
3975*03ce13f7SAndroid Build Coastguard Worker     Op_Lo = &TargetX8664::_and;
3976*03ce13f7SAndroid Build Coastguard Worker     Op_Hi = &TargetX8664::_and;
3977*03ce13f7SAndroid Build Coastguard Worker     break;
3978*03ce13f7SAndroid Build Coastguard Worker   case Intrinsics::AtomicXor:
3979*03ce13f7SAndroid Build Coastguard Worker     NeedsCmpxchg = true;
3980*03ce13f7SAndroid Build Coastguard Worker     Op_Lo = &TargetX8664::_xor;
3981*03ce13f7SAndroid Build Coastguard Worker     Op_Hi = &TargetX8664::_xor;
3982*03ce13f7SAndroid Build Coastguard Worker     break;
3983*03ce13f7SAndroid Build Coastguard Worker   case Intrinsics::AtomicExchange:
3984*03ce13f7SAndroid Build Coastguard Worker     X86OperandMem *Addr = formMemoryOperand(Ptr, Dest->getType());
3985*03ce13f7SAndroid Build Coastguard Worker     Variable *T = nullptr;
3986*03ce13f7SAndroid Build Coastguard Worker     _mov(T, Val);
3987*03ce13f7SAndroid Build Coastguard Worker     _xchg(Addr, T);
3988*03ce13f7SAndroid Build Coastguard Worker     _mov(Dest, T);
3989*03ce13f7SAndroid Build Coastguard Worker     return;
3990*03ce13f7SAndroid Build Coastguard Worker   }
3991*03ce13f7SAndroid Build Coastguard Worker   // Otherwise, we need a cmpxchg loop.
3992*03ce13f7SAndroid Build Coastguard Worker   (void)NeedsCmpxchg;
3993*03ce13f7SAndroid Build Coastguard Worker   assert(NeedsCmpxchg);
3994*03ce13f7SAndroid Build Coastguard Worker   expandAtomicRMWAsCmpxchg(Op_Lo, Op_Hi, Dest, Ptr, Val);
3995*03ce13f7SAndroid Build Coastguard Worker }
3996*03ce13f7SAndroid Build Coastguard Worker 
expandAtomicRMWAsCmpxchg(LowerBinOp Op_Lo,LowerBinOp Op_Hi,Variable * Dest,Operand * Ptr,Operand * Val)3997*03ce13f7SAndroid Build Coastguard Worker void TargetX8664::expandAtomicRMWAsCmpxchg(LowerBinOp Op_Lo, LowerBinOp Op_Hi,
3998*03ce13f7SAndroid Build Coastguard Worker                                            Variable *Dest, Operand *Ptr,
3999*03ce13f7SAndroid Build Coastguard Worker                                            Operand *Val) {
4000*03ce13f7SAndroid Build Coastguard Worker   // Expand a more complex RMW operation as a cmpxchg loop:
4001*03ce13f7SAndroid Build Coastguard Worker   // For 64-bit:
4002*03ce13f7SAndroid Build Coastguard Worker   //   mov     eax, [ptr]
4003*03ce13f7SAndroid Build Coastguard Worker   //   mov     edx, [ptr + 4]
4004*03ce13f7SAndroid Build Coastguard Worker   // .LABEL:
4005*03ce13f7SAndroid Build Coastguard Worker   //   mov     ebx, eax
4006*03ce13f7SAndroid Build Coastguard Worker   //   <Op_Lo> ebx, <desired_adj_lo>
4007*03ce13f7SAndroid Build Coastguard Worker   //   mov     ecx, edx
4008*03ce13f7SAndroid Build Coastguard Worker   //   <Op_Hi> ecx, <desired_adj_hi>
4009*03ce13f7SAndroid Build Coastguard Worker   //   lock cmpxchg8b [ptr]
4010*03ce13f7SAndroid Build Coastguard Worker   //   jne     .LABEL
4011*03ce13f7SAndroid Build Coastguard Worker   //   mov     <dest_lo>, eax
4012*03ce13f7SAndroid Build Coastguard Worker   //   mov     <dest_lo>, edx
4013*03ce13f7SAndroid Build Coastguard Worker   //
4014*03ce13f7SAndroid Build Coastguard Worker   // For 32-bit:
4015*03ce13f7SAndroid Build Coastguard Worker   //   mov     eax, [ptr]
4016*03ce13f7SAndroid Build Coastguard Worker   // .LABEL:
4017*03ce13f7SAndroid Build Coastguard Worker   //   mov     <reg>, eax
4018*03ce13f7SAndroid Build Coastguard Worker   //   op      <reg>, [desired_adj]
4019*03ce13f7SAndroid Build Coastguard Worker   //   lock cmpxchg [ptr], <reg>
4020*03ce13f7SAndroid Build Coastguard Worker   //   jne     .LABEL
4021*03ce13f7SAndroid Build Coastguard Worker   //   mov     <dest>, eax
4022*03ce13f7SAndroid Build Coastguard Worker   //
4023*03ce13f7SAndroid Build Coastguard Worker   // If Op_{Lo,Hi} are nullptr, then just copy the value.
4024*03ce13f7SAndroid Build Coastguard Worker   Val = legalize(Val);
4025*03ce13f7SAndroid Build Coastguard Worker   Type Ty = Val->getType();
4026*03ce13f7SAndroid Build Coastguard Worker   X86OperandMem *Addr = formMemoryOperand(Ptr, Ty);
4027*03ce13f7SAndroid Build Coastguard Worker   RegNumT Eax;
4028*03ce13f7SAndroid Build Coastguard Worker   switch (Ty) {
4029*03ce13f7SAndroid Build Coastguard Worker   default:
4030*03ce13f7SAndroid Build Coastguard Worker     llvm::report_fatal_error("Bad type for atomicRMW");
4031*03ce13f7SAndroid Build Coastguard Worker   case IceType_i64:
4032*03ce13f7SAndroid Build Coastguard Worker     Eax = RegX8664::Reg_rax;
4033*03ce13f7SAndroid Build Coastguard Worker     break;
4034*03ce13f7SAndroid Build Coastguard Worker   case IceType_i32:
4035*03ce13f7SAndroid Build Coastguard Worker     Eax = RegX8664::Reg_eax;
4036*03ce13f7SAndroid Build Coastguard Worker     break;
4037*03ce13f7SAndroid Build Coastguard Worker   case IceType_i16:
4038*03ce13f7SAndroid Build Coastguard Worker     Eax = RegX8664::Reg_ax;
4039*03ce13f7SAndroid Build Coastguard Worker     break;
4040*03ce13f7SAndroid Build Coastguard Worker   case IceType_i8:
4041*03ce13f7SAndroid Build Coastguard Worker     Eax = RegX8664::Reg_al;
4042*03ce13f7SAndroid Build Coastguard Worker     break;
4043*03ce13f7SAndroid Build Coastguard Worker   }
4044*03ce13f7SAndroid Build Coastguard Worker   Variable *T_eax = makeReg(Ty, Eax);
4045*03ce13f7SAndroid Build Coastguard Worker   _mov(T_eax, Addr);
4046*03ce13f7SAndroid Build Coastguard Worker   auto *Label = Context.insert<InstX86Label>(this);
4047*03ce13f7SAndroid Build Coastguard Worker   // We want to pick a different register for T than Eax, so don't use
4048*03ce13f7SAndroid Build Coastguard Worker   // _mov(T == nullptr, T_eax).
4049*03ce13f7SAndroid Build Coastguard Worker   Variable *T = makeReg(Ty);
4050*03ce13f7SAndroid Build Coastguard Worker   _mov(T, T_eax);
4051*03ce13f7SAndroid Build Coastguard Worker   (this->*Op_Lo)(T, Val);
4052*03ce13f7SAndroid Build Coastguard Worker   constexpr bool Locked = true;
4053*03ce13f7SAndroid Build Coastguard Worker   _cmpxchg(Addr, T_eax, T, Locked);
4054*03ce13f7SAndroid Build Coastguard Worker   _br(CondX86::Br_ne, Label);
4055*03ce13f7SAndroid Build Coastguard Worker   // If Val is a variable, model the extended live range of Val through
4056*03ce13f7SAndroid Build Coastguard Worker   // the end of the loop, since it will be re-used by the loop.
4057*03ce13f7SAndroid Build Coastguard Worker   if (auto *ValVar = llvm::dyn_cast<Variable>(Val)) {
4058*03ce13f7SAndroid Build Coastguard Worker     Context.insert<InstFakeUse>(ValVar);
4059*03ce13f7SAndroid Build Coastguard Worker   }
4060*03ce13f7SAndroid Build Coastguard Worker   // The address base (if any) is also reused in the loop.
4061*03ce13f7SAndroid Build Coastguard Worker   if (Variable *Base = Addr->getBase())
4062*03ce13f7SAndroid Build Coastguard Worker     Context.insert<InstFakeUse>(Base);
4063*03ce13f7SAndroid Build Coastguard Worker   _mov(Dest, T_eax);
4064*03ce13f7SAndroid Build Coastguard Worker }
4065*03ce13f7SAndroid Build Coastguard Worker 
4066*03ce13f7SAndroid Build Coastguard Worker /// Lowers count {trailing, leading} zeros intrinsic.
4067*03ce13f7SAndroid Build Coastguard Worker ///
4068*03ce13f7SAndroid Build Coastguard Worker /// We could do constant folding here, but that should have
4069*03ce13f7SAndroid Build Coastguard Worker /// been done by the front-end/middle-end optimizations.
4070*03ce13f7SAndroid Build Coastguard Worker 
lowerCountZeros(bool Cttz,Type Ty,Variable * Dest,Operand * FirstVal,Operand * SecondVal)4071*03ce13f7SAndroid Build Coastguard Worker void TargetX8664::lowerCountZeros(bool Cttz, Type Ty, Variable *Dest,
4072*03ce13f7SAndroid Build Coastguard Worker                                   Operand *FirstVal, Operand *SecondVal) {
4073*03ce13f7SAndroid Build Coastguard Worker   // TODO(jvoung): Determine if the user CPU supports LZCNT (BMI).
4074*03ce13f7SAndroid Build Coastguard Worker   // Then the instructions will handle the Val == 0 case much more simply
4075*03ce13f7SAndroid Build Coastguard Worker   // and won't require conversion from bit position to number of zeros.
4076*03ce13f7SAndroid Build Coastguard Worker   //
4077*03ce13f7SAndroid Build Coastguard Worker   // Otherwise:
4078*03ce13f7SAndroid Build Coastguard Worker   //   bsr IF_NOT_ZERO, Val
4079*03ce13f7SAndroid Build Coastguard Worker   //   mov T_DEST, ((Ty == i32) ? 63 : 127)
4080*03ce13f7SAndroid Build Coastguard Worker   //   cmovne T_DEST, IF_NOT_ZERO
4081*03ce13f7SAndroid Build Coastguard Worker   //   xor T_DEST, ((Ty == i32) ? 31 : 63)
4082*03ce13f7SAndroid Build Coastguard Worker   //   mov DEST, T_DEST
4083*03ce13f7SAndroid Build Coastguard Worker   //
4084*03ce13f7SAndroid Build Coastguard Worker   // NOTE: T_DEST must be a register because cmov requires its dest to be a
4085*03ce13f7SAndroid Build Coastguard Worker   // register. Also, bsf and bsr require their dest to be a register.
4086*03ce13f7SAndroid Build Coastguard Worker   //
4087*03ce13f7SAndroid Build Coastguard Worker   // The xor DEST, C(31|63) converts a bit position to # of leading zeroes.
4088*03ce13f7SAndroid Build Coastguard Worker   // E.g., for 000... 00001100, bsr will say that the most significant bit
4089*03ce13f7SAndroid Build Coastguard Worker   // set is at position 3, while the number of leading zeros is 28. Xor is
4090*03ce13f7SAndroid Build Coastguard Worker   // like (M - N) for N <= M, and converts 63 to 32, and 127 to 64 (for the
4091*03ce13f7SAndroid Build Coastguard Worker   // all-zeros case).
4092*03ce13f7SAndroid Build Coastguard Worker   //
4093*03ce13f7SAndroid Build Coastguard Worker   // Cttz, is similar, but uses bsf instead, and doesn't require the xor
4094*03ce13f7SAndroid Build Coastguard Worker   // bit position conversion, and the speculation is reversed.
4095*03ce13f7SAndroid Build Coastguard Worker 
4096*03ce13f7SAndroid Build Coastguard Worker   // TODO(jpp): refactor this method.
4097*03ce13f7SAndroid Build Coastguard Worker   assert(Ty == IceType_i32 || Ty == IceType_i64);
4098*03ce13f7SAndroid Build Coastguard Worker   const Type DestTy = Dest->getType();
4099*03ce13f7SAndroid Build Coastguard Worker   Variable *T = makeReg(DestTy);
4100*03ce13f7SAndroid Build Coastguard Worker   Operand *FirstValRM = legalize(FirstVal, Legal_Mem | Legal_Reg);
4101*03ce13f7SAndroid Build Coastguard Worker   if (Cttz) {
4102*03ce13f7SAndroid Build Coastguard Worker     _bsf(T, FirstValRM);
4103*03ce13f7SAndroid Build Coastguard Worker   } else {
4104*03ce13f7SAndroid Build Coastguard Worker     _bsr(T, FirstValRM);
4105*03ce13f7SAndroid Build Coastguard Worker   }
4106*03ce13f7SAndroid Build Coastguard Worker   Variable *T_Dest = makeReg(DestTy);
4107*03ce13f7SAndroid Build Coastguard Worker   Constant *_31 = Ctx->getConstantInt32(31);
4108*03ce13f7SAndroid Build Coastguard Worker   Constant *_32 = Ctx->getConstantInt(DestTy, 32);
4109*03ce13f7SAndroid Build Coastguard Worker   Constant *_63 = Ctx->getConstantInt(DestTy, 63);
4110*03ce13f7SAndroid Build Coastguard Worker   Constant *_64 = Ctx->getConstantInt(DestTy, 64);
4111*03ce13f7SAndroid Build Coastguard Worker   if (Cttz) {
4112*03ce13f7SAndroid Build Coastguard Worker     if (DestTy == IceType_i64) {
4113*03ce13f7SAndroid Build Coastguard Worker       _mov(T_Dest, _64);
4114*03ce13f7SAndroid Build Coastguard Worker     } else {
4115*03ce13f7SAndroid Build Coastguard Worker       _mov(T_Dest, _32);
4116*03ce13f7SAndroid Build Coastguard Worker     }
4117*03ce13f7SAndroid Build Coastguard Worker   } else {
4118*03ce13f7SAndroid Build Coastguard Worker     Constant *_127 = Ctx->getConstantInt(DestTy, 127);
4119*03ce13f7SAndroid Build Coastguard Worker     if (DestTy == IceType_i64) {
4120*03ce13f7SAndroid Build Coastguard Worker       _mov(T_Dest, _127);
4121*03ce13f7SAndroid Build Coastguard Worker     } else {
4122*03ce13f7SAndroid Build Coastguard Worker       _mov(T_Dest, _63);
4123*03ce13f7SAndroid Build Coastguard Worker     }
4124*03ce13f7SAndroid Build Coastguard Worker   }
4125*03ce13f7SAndroid Build Coastguard Worker   _cmov(T_Dest, T, CondX86::Br_ne);
4126*03ce13f7SAndroid Build Coastguard Worker   if (!Cttz) {
4127*03ce13f7SAndroid Build Coastguard Worker     if (DestTy == IceType_i64) {
4128*03ce13f7SAndroid Build Coastguard Worker       // Even though there's a _63 available at this point, that constant might
4129*03ce13f7SAndroid Build Coastguard Worker       // not be an i32, which will cause the xor emission to fail.
4130*03ce13f7SAndroid Build Coastguard Worker       Constant *_63 = Ctx->getConstantInt32(63);
4131*03ce13f7SAndroid Build Coastguard Worker       _xor(T_Dest, _63);
4132*03ce13f7SAndroid Build Coastguard Worker     } else {
4133*03ce13f7SAndroid Build Coastguard Worker       _xor(T_Dest, _31);
4134*03ce13f7SAndroid Build Coastguard Worker     }
4135*03ce13f7SAndroid Build Coastguard Worker   }
4136*03ce13f7SAndroid Build Coastguard Worker   _mov(Dest, T_Dest);
4137*03ce13f7SAndroid Build Coastguard Worker }
4138*03ce13f7SAndroid Build Coastguard Worker 
typedLoad(Type Ty,Variable * Dest,Variable * Base,Constant * Offset)4139*03ce13f7SAndroid Build Coastguard Worker void TargetX8664::typedLoad(Type Ty, Variable *Dest, Variable *Base,
4140*03ce13f7SAndroid Build Coastguard Worker                             Constant *Offset) {
4141*03ce13f7SAndroid Build Coastguard Worker   // If Offset is a ConstantRelocatable in Non-SFI mode, we will need to
4142*03ce13f7SAndroid Build Coastguard Worker   // legalize Mem properly.
4143*03ce13f7SAndroid Build Coastguard Worker   if (Offset)
4144*03ce13f7SAndroid Build Coastguard Worker     assert(!llvm::isa<ConstantRelocatable>(Offset));
4145*03ce13f7SAndroid Build Coastguard Worker 
4146*03ce13f7SAndroid Build Coastguard Worker   auto *Mem = X86OperandMem::create(Func, Ty, Base, Offset);
4147*03ce13f7SAndroid Build Coastguard Worker 
4148*03ce13f7SAndroid Build Coastguard Worker   if (isVectorType(Ty))
4149*03ce13f7SAndroid Build Coastguard Worker     _movp(Dest, Mem);
4150*03ce13f7SAndroid Build Coastguard Worker   else if (Ty == IceType_f64)
4151*03ce13f7SAndroid Build Coastguard Worker     _movq(Dest, Mem);
4152*03ce13f7SAndroid Build Coastguard Worker   else
4153*03ce13f7SAndroid Build Coastguard Worker     _mov(Dest, Mem);
4154*03ce13f7SAndroid Build Coastguard Worker }
4155*03ce13f7SAndroid Build Coastguard Worker 
typedStore(Type Ty,Variable * Value,Variable * Base,Constant * Offset)4156*03ce13f7SAndroid Build Coastguard Worker void TargetX8664::typedStore(Type Ty, Variable *Value, Variable *Base,
4157*03ce13f7SAndroid Build Coastguard Worker                              Constant *Offset) {
4158*03ce13f7SAndroid Build Coastguard Worker   // If Offset is a ConstantRelocatable in Non-SFI mode, we will need to
4159*03ce13f7SAndroid Build Coastguard Worker   // legalize Mem properly.
4160*03ce13f7SAndroid Build Coastguard Worker   if (Offset)
4161*03ce13f7SAndroid Build Coastguard Worker     assert(!llvm::isa<ConstantRelocatable>(Offset));
4162*03ce13f7SAndroid Build Coastguard Worker 
4163*03ce13f7SAndroid Build Coastguard Worker   auto *Mem = X86OperandMem::create(Func, Ty, Base, Offset);
4164*03ce13f7SAndroid Build Coastguard Worker 
4165*03ce13f7SAndroid Build Coastguard Worker   if (isVectorType(Ty))
4166*03ce13f7SAndroid Build Coastguard Worker     _storep(Value, Mem);
4167*03ce13f7SAndroid Build Coastguard Worker   else if (Ty == IceType_f64)
4168*03ce13f7SAndroid Build Coastguard Worker     _storeq(Value, Mem);
4169*03ce13f7SAndroid Build Coastguard Worker   else
4170*03ce13f7SAndroid Build Coastguard Worker     _store(Value, Mem);
4171*03ce13f7SAndroid Build Coastguard Worker }
4172*03ce13f7SAndroid Build Coastguard Worker 
copyMemory(Type Ty,Variable * Dest,Variable * Src,int32_t OffsetAmt)4173*03ce13f7SAndroid Build Coastguard Worker void TargetX8664::copyMemory(Type Ty, Variable *Dest, Variable *Src,
4174*03ce13f7SAndroid Build Coastguard Worker                              int32_t OffsetAmt) {
4175*03ce13f7SAndroid Build Coastguard Worker   Constant *Offset = OffsetAmt ? Ctx->getConstantInt32(OffsetAmt) : nullptr;
4176*03ce13f7SAndroid Build Coastguard Worker   // TODO(ascull): this or add nullptr test to _movp, _movq
4177*03ce13f7SAndroid Build Coastguard Worker   Variable *Data = makeReg(Ty);
4178*03ce13f7SAndroid Build Coastguard Worker 
4179*03ce13f7SAndroid Build Coastguard Worker   typedLoad(Ty, Data, Src, Offset);
4180*03ce13f7SAndroid Build Coastguard Worker   typedStore(Ty, Data, Dest, Offset);
4181*03ce13f7SAndroid Build Coastguard Worker }
4182*03ce13f7SAndroid Build Coastguard Worker 
lowerMemcpy(Operand * Dest,Operand * Src,Operand * Count)4183*03ce13f7SAndroid Build Coastguard Worker void TargetX8664::lowerMemcpy(Operand *Dest, Operand *Src, Operand *Count) {
4184*03ce13f7SAndroid Build Coastguard Worker   // There is a load and store for each chunk in the unroll
4185*03ce13f7SAndroid Build Coastguard Worker   constexpr uint32_t BytesPerStorep = 16;
4186*03ce13f7SAndroid Build Coastguard Worker 
4187*03ce13f7SAndroid Build Coastguard Worker   // Check if the operands are constants
4188*03ce13f7SAndroid Build Coastguard Worker   const auto *CountConst = llvm::dyn_cast<const ConstantInteger32>(Count);
4189*03ce13f7SAndroid Build Coastguard Worker   const bool IsCountConst = CountConst != nullptr;
4190*03ce13f7SAndroid Build Coastguard Worker   const uint32_t CountValue = IsCountConst ? CountConst->getValue() : 0;
4191*03ce13f7SAndroid Build Coastguard Worker 
4192*03ce13f7SAndroid Build Coastguard Worker   if (shouldOptimizeMemIntrins() && IsCountConst &&
4193*03ce13f7SAndroid Build Coastguard Worker       CountValue <= BytesPerStorep * MEMCPY_UNROLL_LIMIT) {
4194*03ce13f7SAndroid Build Coastguard Worker     // Unlikely, but nothing to do if it does happen
4195*03ce13f7SAndroid Build Coastguard Worker     if (CountValue == 0)
4196*03ce13f7SAndroid Build Coastguard Worker       return;
4197*03ce13f7SAndroid Build Coastguard Worker 
4198*03ce13f7SAndroid Build Coastguard Worker     Variable *SrcBase = legalizeToReg(Src);
4199*03ce13f7SAndroid Build Coastguard Worker     Variable *DestBase = legalizeToReg(Dest);
4200*03ce13f7SAndroid Build Coastguard Worker 
4201*03ce13f7SAndroid Build Coastguard Worker     // Find the largest type that can be used and use it as much as possible in
4202*03ce13f7SAndroid Build Coastguard Worker     // reverse order. Then handle any remainder with overlapping copies. Since
4203*03ce13f7SAndroid Build Coastguard Worker     // the remainder will be at the end, there will be reduced pressure on the
4204*03ce13f7SAndroid Build Coastguard Worker     // memory unit as the accesses to the same memory are far apart.
4205*03ce13f7SAndroid Build Coastguard Worker     Type Ty = largestTypeInSize(CountValue);
4206*03ce13f7SAndroid Build Coastguard Worker     uint32_t TyWidth = typeWidthInBytes(Ty);
4207*03ce13f7SAndroid Build Coastguard Worker 
4208*03ce13f7SAndroid Build Coastguard Worker     uint32_t RemainingBytes = CountValue;
4209*03ce13f7SAndroid Build Coastguard Worker     int32_t Offset = (CountValue & ~(TyWidth - 1)) - TyWidth;
4210*03ce13f7SAndroid Build Coastguard Worker     while (RemainingBytes >= TyWidth) {
4211*03ce13f7SAndroid Build Coastguard Worker       copyMemory(Ty, DestBase, SrcBase, Offset);
4212*03ce13f7SAndroid Build Coastguard Worker       RemainingBytes -= TyWidth;
4213*03ce13f7SAndroid Build Coastguard Worker       Offset -= TyWidth;
4214*03ce13f7SAndroid Build Coastguard Worker     }
4215*03ce13f7SAndroid Build Coastguard Worker 
4216*03ce13f7SAndroid Build Coastguard Worker     if (RemainingBytes == 0)
4217*03ce13f7SAndroid Build Coastguard Worker       return;
4218*03ce13f7SAndroid Build Coastguard Worker 
4219*03ce13f7SAndroid Build Coastguard Worker     // Lower the remaining bytes. Adjust to larger types in order to make use
4220*03ce13f7SAndroid Build Coastguard Worker     // of overlaps in the copies.
4221*03ce13f7SAndroid Build Coastguard Worker     Type LeftOverTy = firstTypeThatFitsSize(RemainingBytes);
4222*03ce13f7SAndroid Build Coastguard Worker     Offset = CountValue - typeWidthInBytes(LeftOverTy);
4223*03ce13f7SAndroid Build Coastguard Worker     copyMemory(LeftOverTy, DestBase, SrcBase, Offset);
4224*03ce13f7SAndroid Build Coastguard Worker     return;
4225*03ce13f7SAndroid Build Coastguard Worker   }
4226*03ce13f7SAndroid Build Coastguard Worker 
4227*03ce13f7SAndroid Build Coastguard Worker   // Fall back on a function call
4228*03ce13f7SAndroid Build Coastguard Worker   InstCall *Call = makeHelperCall(RuntimeHelper::H_call_memcpy, nullptr, 3);
4229*03ce13f7SAndroid Build Coastguard Worker   Call->addArg(Dest);
4230*03ce13f7SAndroid Build Coastguard Worker   Call->addArg(Src);
4231*03ce13f7SAndroid Build Coastguard Worker   Call->addArg(Count);
4232*03ce13f7SAndroid Build Coastguard Worker   lowerCall(Call);
4233*03ce13f7SAndroid Build Coastguard Worker }
4234*03ce13f7SAndroid Build Coastguard Worker 
lowerMemmove(Operand * Dest,Operand * Src,Operand * Count)4235*03ce13f7SAndroid Build Coastguard Worker void TargetX8664::lowerMemmove(Operand *Dest, Operand *Src, Operand *Count) {
4236*03ce13f7SAndroid Build Coastguard Worker   // There is a load and store for each chunk in the unroll
4237*03ce13f7SAndroid Build Coastguard Worker   constexpr uint32_t BytesPerStorep = 16;
4238*03ce13f7SAndroid Build Coastguard Worker 
4239*03ce13f7SAndroid Build Coastguard Worker   // Check if the operands are constants
4240*03ce13f7SAndroid Build Coastguard Worker   const auto *CountConst = llvm::dyn_cast<const ConstantInteger32>(Count);
4241*03ce13f7SAndroid Build Coastguard Worker   const bool IsCountConst = CountConst != nullptr;
4242*03ce13f7SAndroid Build Coastguard Worker   const uint32_t CountValue = IsCountConst ? CountConst->getValue() : 0;
4243*03ce13f7SAndroid Build Coastguard Worker 
4244*03ce13f7SAndroid Build Coastguard Worker   if (shouldOptimizeMemIntrins() && IsCountConst &&
4245*03ce13f7SAndroid Build Coastguard Worker       CountValue <= BytesPerStorep * MEMMOVE_UNROLL_LIMIT) {
4246*03ce13f7SAndroid Build Coastguard Worker     // Unlikely, but nothing to do if it does happen
4247*03ce13f7SAndroid Build Coastguard Worker     if (CountValue == 0)
4248*03ce13f7SAndroid Build Coastguard Worker       return;
4249*03ce13f7SAndroid Build Coastguard Worker 
4250*03ce13f7SAndroid Build Coastguard Worker     Variable *SrcBase = legalizeToReg(Src);
4251*03ce13f7SAndroid Build Coastguard Worker     Variable *DestBase = legalizeToReg(Dest);
4252*03ce13f7SAndroid Build Coastguard Worker 
4253*03ce13f7SAndroid Build Coastguard Worker     std::tuple<Type, Constant *, Variable *> Moves[MEMMOVE_UNROLL_LIMIT];
4254*03ce13f7SAndroid Build Coastguard Worker     Constant *Offset;
4255*03ce13f7SAndroid Build Coastguard Worker     Variable *Reg;
4256*03ce13f7SAndroid Build Coastguard Worker 
4257*03ce13f7SAndroid Build Coastguard Worker     // Copy the data into registers as the source and destination could overlap
4258*03ce13f7SAndroid Build Coastguard Worker     // so make sure not to clobber the memory. This also means overlapping
4259*03ce13f7SAndroid Build Coastguard Worker     // moves can be used as we are taking a safe snapshot of the memory.
4260*03ce13f7SAndroid Build Coastguard Worker     Type Ty = largestTypeInSize(CountValue);
4261*03ce13f7SAndroid Build Coastguard Worker     uint32_t TyWidth = typeWidthInBytes(Ty);
4262*03ce13f7SAndroid Build Coastguard Worker 
4263*03ce13f7SAndroid Build Coastguard Worker     uint32_t RemainingBytes = CountValue;
4264*03ce13f7SAndroid Build Coastguard Worker     int32_t OffsetAmt = (CountValue & ~(TyWidth - 1)) - TyWidth;
4265*03ce13f7SAndroid Build Coastguard Worker     size_t N = 0;
4266*03ce13f7SAndroid Build Coastguard Worker     while (RemainingBytes >= TyWidth) {
4267*03ce13f7SAndroid Build Coastguard Worker       assert(N <= MEMMOVE_UNROLL_LIMIT);
4268*03ce13f7SAndroid Build Coastguard Worker       Offset = Ctx->getConstantInt32(OffsetAmt);
4269*03ce13f7SAndroid Build Coastguard Worker       Reg = makeReg(Ty);
4270*03ce13f7SAndroid Build Coastguard Worker       typedLoad(Ty, Reg, SrcBase, Offset);
4271*03ce13f7SAndroid Build Coastguard Worker       RemainingBytes -= TyWidth;
4272*03ce13f7SAndroid Build Coastguard Worker       OffsetAmt -= TyWidth;
4273*03ce13f7SAndroid Build Coastguard Worker       Moves[N++] = std::make_tuple(Ty, Offset, Reg);
4274*03ce13f7SAndroid Build Coastguard Worker     }
4275*03ce13f7SAndroid Build Coastguard Worker 
4276*03ce13f7SAndroid Build Coastguard Worker     if (RemainingBytes != 0) {
4277*03ce13f7SAndroid Build Coastguard Worker       // Lower the remaining bytes. Adjust to larger types in order to make use
4278*03ce13f7SAndroid Build Coastguard Worker       // of overlaps in the copies.
4279*03ce13f7SAndroid Build Coastguard Worker       assert(N <= MEMMOVE_UNROLL_LIMIT);
4280*03ce13f7SAndroid Build Coastguard Worker       Ty = firstTypeThatFitsSize(RemainingBytes);
4281*03ce13f7SAndroid Build Coastguard Worker       Offset = Ctx->getConstantInt32(CountValue - typeWidthInBytes(Ty));
4282*03ce13f7SAndroid Build Coastguard Worker       Reg = makeReg(Ty);
4283*03ce13f7SAndroid Build Coastguard Worker       typedLoad(Ty, Reg, SrcBase, Offset);
4284*03ce13f7SAndroid Build Coastguard Worker       Moves[N++] = std::make_tuple(Ty, Offset, Reg);
4285*03ce13f7SAndroid Build Coastguard Worker     }
4286*03ce13f7SAndroid Build Coastguard Worker 
4287*03ce13f7SAndroid Build Coastguard Worker     // Copy the data out into the destination memory
4288*03ce13f7SAndroid Build Coastguard Worker     for (size_t i = 0; i < N; ++i) {
4289*03ce13f7SAndroid Build Coastguard Worker       std::tie(Ty, Offset, Reg) = Moves[i];
4290*03ce13f7SAndroid Build Coastguard Worker       typedStore(Ty, Reg, DestBase, Offset);
4291*03ce13f7SAndroid Build Coastguard Worker     }
4292*03ce13f7SAndroid Build Coastguard Worker 
4293*03ce13f7SAndroid Build Coastguard Worker     return;
4294*03ce13f7SAndroid Build Coastguard Worker   }
4295*03ce13f7SAndroid Build Coastguard Worker 
4296*03ce13f7SAndroid Build Coastguard Worker   // Fall back on a function call
4297*03ce13f7SAndroid Build Coastguard Worker   InstCall *Call = makeHelperCall(RuntimeHelper::H_call_memmove, nullptr, 3);
4298*03ce13f7SAndroid Build Coastguard Worker   Call->addArg(Dest);
4299*03ce13f7SAndroid Build Coastguard Worker   Call->addArg(Src);
4300*03ce13f7SAndroid Build Coastguard Worker   Call->addArg(Count);
4301*03ce13f7SAndroid Build Coastguard Worker   lowerCall(Call);
4302*03ce13f7SAndroid Build Coastguard Worker }
4303*03ce13f7SAndroid Build Coastguard Worker 
lowerMemset(Operand * Dest,Operand * Val,Operand * Count)4304*03ce13f7SAndroid Build Coastguard Worker void TargetX8664::lowerMemset(Operand *Dest, Operand *Val, Operand *Count) {
4305*03ce13f7SAndroid Build Coastguard Worker   constexpr uint32_t BytesPerStorep = 16;
4306*03ce13f7SAndroid Build Coastguard Worker   constexpr uint32_t BytesPerStoreq = 8;
4307*03ce13f7SAndroid Build Coastguard Worker   constexpr uint32_t BytesPerStorei32 = 4;
4308*03ce13f7SAndroid Build Coastguard Worker   assert(Val->getType() == IceType_i8);
4309*03ce13f7SAndroid Build Coastguard Worker 
4310*03ce13f7SAndroid Build Coastguard Worker   // Check if the operands are constants
4311*03ce13f7SAndroid Build Coastguard Worker   const auto *CountConst = llvm::dyn_cast<const ConstantInteger32>(Count);
4312*03ce13f7SAndroid Build Coastguard Worker   const auto *ValConst = llvm::dyn_cast<const ConstantInteger32>(Val);
4313*03ce13f7SAndroid Build Coastguard Worker   const bool IsCountConst = CountConst != nullptr;
4314*03ce13f7SAndroid Build Coastguard Worker   const bool IsValConst = ValConst != nullptr;
4315*03ce13f7SAndroid Build Coastguard Worker   const uint32_t CountValue = IsCountConst ? CountConst->getValue() : 0;
4316*03ce13f7SAndroid Build Coastguard Worker   const uint32_t ValValue = IsValConst ? ValConst->getValue() : 0;
4317*03ce13f7SAndroid Build Coastguard Worker 
4318*03ce13f7SAndroid Build Coastguard Worker   // Unlikely, but nothing to do if it does happen
4319*03ce13f7SAndroid Build Coastguard Worker   if (IsCountConst && CountValue == 0)
4320*03ce13f7SAndroid Build Coastguard Worker     return;
4321*03ce13f7SAndroid Build Coastguard Worker 
4322*03ce13f7SAndroid Build Coastguard Worker   // TODO(ascull): if the count is constant but val is not it would be possible
4323*03ce13f7SAndroid Build Coastguard Worker   // to inline by spreading the value across 4 bytes and accessing subregs e.g.
4324*03ce13f7SAndroid Build Coastguard Worker   // eax, ax and al.
4325*03ce13f7SAndroid Build Coastguard Worker   if (shouldOptimizeMemIntrins() && IsCountConst && IsValConst) {
4326*03ce13f7SAndroid Build Coastguard Worker     Variable *Base = nullptr;
4327*03ce13f7SAndroid Build Coastguard Worker     Variable *VecReg = nullptr;
4328*03ce13f7SAndroid Build Coastguard Worker     const uint32_t MaskValue = (ValValue & 0xff);
4329*03ce13f7SAndroid Build Coastguard Worker     const uint32_t SpreadValue =
4330*03ce13f7SAndroid Build Coastguard Worker         (MaskValue << 24) | (MaskValue << 16) | (MaskValue << 8) | MaskValue;
4331*03ce13f7SAndroid Build Coastguard Worker 
4332*03ce13f7SAndroid Build Coastguard Worker     auto lowerSet = [this, &Base, SpreadValue, &VecReg](Type Ty,
4333*03ce13f7SAndroid Build Coastguard Worker                                                         uint32_t OffsetAmt) {
4334*03ce13f7SAndroid Build Coastguard Worker       assert(Base != nullptr);
4335*03ce13f7SAndroid Build Coastguard Worker       Constant *Offset = OffsetAmt ? Ctx->getConstantInt32(OffsetAmt) : nullptr;
4336*03ce13f7SAndroid Build Coastguard Worker 
4337*03ce13f7SAndroid Build Coastguard Worker       // TODO(ascull): is 64-bit better with vector or scalar movq?
4338*03ce13f7SAndroid Build Coastguard Worker       auto *Mem = X86OperandMem::create(Func, Ty, Base, Offset);
4339*03ce13f7SAndroid Build Coastguard Worker       if (isVectorType(Ty)) {
4340*03ce13f7SAndroid Build Coastguard Worker         assert(VecReg != nullptr);
4341*03ce13f7SAndroid Build Coastguard Worker         _storep(VecReg, Mem);
4342*03ce13f7SAndroid Build Coastguard Worker       } else if (Ty == IceType_f64) {
4343*03ce13f7SAndroid Build Coastguard Worker         assert(VecReg != nullptr);
4344*03ce13f7SAndroid Build Coastguard Worker         _storeq(VecReg, Mem);
4345*03ce13f7SAndroid Build Coastguard Worker       } else {
4346*03ce13f7SAndroid Build Coastguard Worker         assert(Ty != IceType_i64);
4347*03ce13f7SAndroid Build Coastguard Worker         _store(Ctx->getConstantInt(Ty, SpreadValue), Mem);
4348*03ce13f7SAndroid Build Coastguard Worker       }
4349*03ce13f7SAndroid Build Coastguard Worker     };
4350*03ce13f7SAndroid Build Coastguard Worker 
4351*03ce13f7SAndroid Build Coastguard Worker     // Find the largest type that can be used and use it as much as possible in
4352*03ce13f7SAndroid Build Coastguard Worker     // reverse order. Then handle any remainder with overlapping copies. Since
4353*03ce13f7SAndroid Build Coastguard Worker     // the remainder will be at the end, there will be reduces pressure on the
4354*03ce13f7SAndroid Build Coastguard Worker     // memory unit as the access to the same memory are far apart.
4355*03ce13f7SAndroid Build Coastguard Worker     Type Ty = IceType_void;
4356*03ce13f7SAndroid Build Coastguard Worker     if (ValValue == 0 && CountValue >= BytesPerStoreq &&
4357*03ce13f7SAndroid Build Coastguard Worker         CountValue <= BytesPerStorep * MEMSET_UNROLL_LIMIT) {
4358*03ce13f7SAndroid Build Coastguard Worker       // When the value is zero it can be loaded into a vector register cheaply
4359*03ce13f7SAndroid Build Coastguard Worker       // using the xor trick.
4360*03ce13f7SAndroid Build Coastguard Worker       Base = legalizeToReg(Dest);
4361*03ce13f7SAndroid Build Coastguard Worker       VecReg = makeVectorOfZeros(IceType_v16i8);
4362*03ce13f7SAndroid Build Coastguard Worker       Ty = largestTypeInSize(CountValue);
4363*03ce13f7SAndroid Build Coastguard Worker     } else if (CountValue <= BytesPerStorei32 * MEMSET_UNROLL_LIMIT) {
4364*03ce13f7SAndroid Build Coastguard Worker       // When the value is non-zero or the count is small we can't use vector
4365*03ce13f7SAndroid Build Coastguard Worker       // instructions so are limited to 32-bit stores.
4366*03ce13f7SAndroid Build Coastguard Worker       Base = legalizeToReg(Dest);
4367*03ce13f7SAndroid Build Coastguard Worker       constexpr uint32_t MaxSize = 4;
4368*03ce13f7SAndroid Build Coastguard Worker       Ty = largestTypeInSize(CountValue, MaxSize);
4369*03ce13f7SAndroid Build Coastguard Worker     }
4370*03ce13f7SAndroid Build Coastguard Worker 
4371*03ce13f7SAndroid Build Coastguard Worker     if (Base) {
4372*03ce13f7SAndroid Build Coastguard Worker       uint32_t TyWidth = typeWidthInBytes(Ty);
4373*03ce13f7SAndroid Build Coastguard Worker 
4374*03ce13f7SAndroid Build Coastguard Worker       uint32_t RemainingBytes = CountValue;
4375*03ce13f7SAndroid Build Coastguard Worker       uint32_t Offset = (CountValue & ~(TyWidth - 1)) - TyWidth;
4376*03ce13f7SAndroid Build Coastguard Worker       while (RemainingBytes >= TyWidth) {
4377*03ce13f7SAndroid Build Coastguard Worker         lowerSet(Ty, Offset);
4378*03ce13f7SAndroid Build Coastguard Worker         RemainingBytes -= TyWidth;
4379*03ce13f7SAndroid Build Coastguard Worker         Offset -= TyWidth;
4380*03ce13f7SAndroid Build Coastguard Worker       }
4381*03ce13f7SAndroid Build Coastguard Worker 
4382*03ce13f7SAndroid Build Coastguard Worker       if (RemainingBytes == 0)
4383*03ce13f7SAndroid Build Coastguard Worker         return;
4384*03ce13f7SAndroid Build Coastguard Worker 
4385*03ce13f7SAndroid Build Coastguard Worker       // Lower the remaining bytes. Adjust to larger types in order to make use
4386*03ce13f7SAndroid Build Coastguard Worker       // of overlaps in the copies.
4387*03ce13f7SAndroid Build Coastguard Worker       Type LeftOverTy = firstTypeThatFitsSize(RemainingBytes);
4388*03ce13f7SAndroid Build Coastguard Worker       Offset = CountValue - typeWidthInBytes(LeftOverTy);
4389*03ce13f7SAndroid Build Coastguard Worker       lowerSet(LeftOverTy, Offset);
4390*03ce13f7SAndroid Build Coastguard Worker       return;
4391*03ce13f7SAndroid Build Coastguard Worker     }
4392*03ce13f7SAndroid Build Coastguard Worker   }
4393*03ce13f7SAndroid Build Coastguard Worker 
4394*03ce13f7SAndroid Build Coastguard Worker   // Fall back on calling the memset function. The value operand needs to be
4395*03ce13f7SAndroid Build Coastguard Worker   // extended to a stack slot size because the PNaCl ABI requires arguments to
4396*03ce13f7SAndroid Build Coastguard Worker   // be at least 32 bits wide.
4397*03ce13f7SAndroid Build Coastguard Worker   Operand *ValExt;
4398*03ce13f7SAndroid Build Coastguard Worker   if (IsValConst) {
4399*03ce13f7SAndroid Build Coastguard Worker     ValExt = Ctx->getConstantInt(stackSlotType(), ValValue);
4400*03ce13f7SAndroid Build Coastguard Worker   } else {
4401*03ce13f7SAndroid Build Coastguard Worker     Variable *ValExtVar = Func->makeVariable(stackSlotType());
4402*03ce13f7SAndroid Build Coastguard Worker     lowerCast(InstCast::create(Func, InstCast::Zext, ValExtVar, Val));
4403*03ce13f7SAndroid Build Coastguard Worker     ValExt = ValExtVar;
4404*03ce13f7SAndroid Build Coastguard Worker   }
4405*03ce13f7SAndroid Build Coastguard Worker   InstCall *Call = makeHelperCall(RuntimeHelper::H_call_memset, nullptr, 3);
4406*03ce13f7SAndroid Build Coastguard Worker   Call->addArg(Dest);
4407*03ce13f7SAndroid Build Coastguard Worker   Call->addArg(ValExt);
4408*03ce13f7SAndroid Build Coastguard Worker   Call->addArg(Count);
4409*03ce13f7SAndroid Build Coastguard Worker   lowerCall(Call);
4410*03ce13f7SAndroid Build Coastguard Worker }
4411*03ce13f7SAndroid Build Coastguard Worker 
4412*03ce13f7SAndroid Build Coastguard Worker class AddressOptimizer {
4413*03ce13f7SAndroid Build Coastguard Worker   AddressOptimizer() = delete;
4414*03ce13f7SAndroid Build Coastguard Worker   AddressOptimizer(const AddressOptimizer &) = delete;
4415*03ce13f7SAndroid Build Coastguard Worker   AddressOptimizer &operator=(const AddressOptimizer &) = delete;
4416*03ce13f7SAndroid Build Coastguard Worker 
4417*03ce13f7SAndroid Build Coastguard Worker public:
AddressOptimizer(const Cfg * Func)4418*03ce13f7SAndroid Build Coastguard Worker   explicit AddressOptimizer(const Cfg *Func)
4419*03ce13f7SAndroid Build Coastguard Worker       : Func(Func), VMetadata(Func->getVMetadata()) {}
4420*03ce13f7SAndroid Build Coastguard Worker 
4421*03ce13f7SAndroid Build Coastguard Worker   inline void dumpAddressOpt(const ConstantRelocatable *const Relocatable,
4422*03ce13f7SAndroid Build Coastguard Worker                              int32_t Offset, const Variable *Base,
4423*03ce13f7SAndroid Build Coastguard Worker                              const Variable *Index, uint16_t Shift,
4424*03ce13f7SAndroid Build Coastguard Worker                              const Inst *Reason) const;
4425*03ce13f7SAndroid Build Coastguard Worker 
4426*03ce13f7SAndroid Build Coastguard Worker   inline const Inst *matchAssign(Variable **Var,
4427*03ce13f7SAndroid Build Coastguard Worker                                  ConstantRelocatable **Relocatable,
4428*03ce13f7SAndroid Build Coastguard Worker                                  int32_t *Offset);
4429*03ce13f7SAndroid Build Coastguard Worker 
4430*03ce13f7SAndroid Build Coastguard Worker   inline const Inst *matchCombinedBaseIndex(Variable **Base, Variable **Index,
4431*03ce13f7SAndroid Build Coastguard Worker                                             uint16_t *Shift);
4432*03ce13f7SAndroid Build Coastguard Worker 
4433*03ce13f7SAndroid Build Coastguard Worker   inline const Inst *matchShiftedIndex(Variable **Index, uint16_t *Shift);
4434*03ce13f7SAndroid Build Coastguard Worker 
4435*03ce13f7SAndroid Build Coastguard Worker   inline const Inst *matchOffsetIndexOrBase(Variable **IndexOrBase,
4436*03ce13f7SAndroid Build Coastguard Worker                                             const uint16_t Shift,
4437*03ce13f7SAndroid Build Coastguard Worker                                             ConstantRelocatable **Relocatable,
4438*03ce13f7SAndroid Build Coastguard Worker                                             int32_t *Offset);
4439*03ce13f7SAndroid Build Coastguard Worker 
4440*03ce13f7SAndroid Build Coastguard Worker private:
4441*03ce13f7SAndroid Build Coastguard Worker   const Cfg *const Func;
4442*03ce13f7SAndroid Build Coastguard Worker   const VariablesMetadata *const VMetadata;
4443*03ce13f7SAndroid Build Coastguard Worker 
isAdd(const Inst * Instr)4444*03ce13f7SAndroid Build Coastguard Worker   static bool isAdd(const Inst *Instr) {
4445*03ce13f7SAndroid Build Coastguard Worker     if (auto *Arith = llvm::dyn_cast_or_null<const InstArithmetic>(Instr)) {
4446*03ce13f7SAndroid Build Coastguard Worker       return (Arith->getOp() == InstArithmetic::Add);
4447*03ce13f7SAndroid Build Coastguard Worker     }
4448*03ce13f7SAndroid Build Coastguard Worker     return false;
4449*03ce13f7SAndroid Build Coastguard Worker   }
4450*03ce13f7SAndroid Build Coastguard Worker };
4451*03ce13f7SAndroid Build Coastguard Worker 
dumpAddressOpt(const ConstantRelocatable * const Relocatable,int32_t Offset,const Variable * Base,const Variable * Index,uint16_t Shift,const Inst * Reason) const4452*03ce13f7SAndroid Build Coastguard Worker void AddressOptimizer::dumpAddressOpt(
4453*03ce13f7SAndroid Build Coastguard Worker     const ConstantRelocatable *const Relocatable, int32_t Offset,
4454*03ce13f7SAndroid Build Coastguard Worker     const Variable *Base, const Variable *Index, uint16_t Shift,
4455*03ce13f7SAndroid Build Coastguard Worker     const Inst *Reason) const {
4456*03ce13f7SAndroid Build Coastguard Worker   if (!BuildDefs::dump())
4457*03ce13f7SAndroid Build Coastguard Worker     return;
4458*03ce13f7SAndroid Build Coastguard Worker   if (!Func->isVerbose(IceV_AddrOpt))
4459*03ce13f7SAndroid Build Coastguard Worker     return;
4460*03ce13f7SAndroid Build Coastguard Worker   OstreamLocker L(Func->getContext());
4461*03ce13f7SAndroid Build Coastguard Worker   Ostream &Str = Func->getContext()->getStrDump();
4462*03ce13f7SAndroid Build Coastguard Worker   Str << "Instruction: ";
4463*03ce13f7SAndroid Build Coastguard Worker   Reason->dumpDecorated(Func);
4464*03ce13f7SAndroid Build Coastguard Worker   Str << "  results in Base=";
4465*03ce13f7SAndroid Build Coastguard Worker   if (Base)
4466*03ce13f7SAndroid Build Coastguard Worker     Base->dump(Func);
4467*03ce13f7SAndroid Build Coastguard Worker   else
4468*03ce13f7SAndroid Build Coastguard Worker     Str << "<null>";
4469*03ce13f7SAndroid Build Coastguard Worker   Str << ", Index=";
4470*03ce13f7SAndroid Build Coastguard Worker   if (Index)
4471*03ce13f7SAndroid Build Coastguard Worker     Index->dump(Func);
4472*03ce13f7SAndroid Build Coastguard Worker   else
4473*03ce13f7SAndroid Build Coastguard Worker     Str << "<null>";
4474*03ce13f7SAndroid Build Coastguard Worker   Str << ", Shift=" << Shift << ", Offset=" << Offset
4475*03ce13f7SAndroid Build Coastguard Worker       << ", Relocatable=" << Relocatable << "\n";
4476*03ce13f7SAndroid Build Coastguard Worker }
4477*03ce13f7SAndroid Build Coastguard Worker 
matchAssign(Variable ** Var,ConstantRelocatable ** Relocatable,int32_t * Offset)4478*03ce13f7SAndroid Build Coastguard Worker const Inst *AddressOptimizer::matchAssign(Variable **Var,
4479*03ce13f7SAndroid Build Coastguard Worker                                           ConstantRelocatable **Relocatable,
4480*03ce13f7SAndroid Build Coastguard Worker                                           int32_t *Offset) {
4481*03ce13f7SAndroid Build Coastguard Worker   // Var originates from Var=SrcVar ==> set Var:=SrcVar
4482*03ce13f7SAndroid Build Coastguard Worker   if (*Var == nullptr)
4483*03ce13f7SAndroid Build Coastguard Worker     return nullptr;
4484*03ce13f7SAndroid Build Coastguard Worker   if (const Inst *VarAssign = VMetadata->getSingleDefinition(*Var)) {
4485*03ce13f7SAndroid Build Coastguard Worker     assert(!VMetadata->isMultiDef(*Var));
4486*03ce13f7SAndroid Build Coastguard Worker     if (llvm::isa<InstAssign>(VarAssign)) {
4487*03ce13f7SAndroid Build Coastguard Worker       Operand *SrcOp = VarAssign->getSrc(0);
4488*03ce13f7SAndroid Build Coastguard Worker       assert(SrcOp);
4489*03ce13f7SAndroid Build Coastguard Worker       if (auto *SrcVar = llvm::dyn_cast<Variable>(SrcOp)) {
4490*03ce13f7SAndroid Build Coastguard Worker         if (!VMetadata->isMultiDef(SrcVar) &&
4491*03ce13f7SAndroid Build Coastguard Worker             // TODO: ensure SrcVar stays single-BB
4492*03ce13f7SAndroid Build Coastguard Worker             true) {
4493*03ce13f7SAndroid Build Coastguard Worker           *Var = SrcVar;
4494*03ce13f7SAndroid Build Coastguard Worker           return VarAssign;
4495*03ce13f7SAndroid Build Coastguard Worker         }
4496*03ce13f7SAndroid Build Coastguard Worker       } else if (auto *Const = llvm::dyn_cast<ConstantInteger32>(SrcOp)) {
4497*03ce13f7SAndroid Build Coastguard Worker         int32_t MoreOffset = Const->getValue();
4498*03ce13f7SAndroid Build Coastguard Worker         if (Utils::WouldOverflowAdd(*Offset, MoreOffset))
4499*03ce13f7SAndroid Build Coastguard Worker           return nullptr;
4500*03ce13f7SAndroid Build Coastguard Worker         *Var = nullptr;
4501*03ce13f7SAndroid Build Coastguard Worker         *Offset += MoreOffset;
4502*03ce13f7SAndroid Build Coastguard Worker         return VarAssign;
4503*03ce13f7SAndroid Build Coastguard Worker       } else if (auto *AddReloc = llvm::dyn_cast<ConstantRelocatable>(SrcOp)) {
4504*03ce13f7SAndroid Build Coastguard Worker         if (*Relocatable == nullptr) {
4505*03ce13f7SAndroid Build Coastguard Worker           // It is always safe to fold a relocatable through assignment -- the
4506*03ce13f7SAndroid Build Coastguard Worker           // assignment frees a slot in the address operand that can be used to
4507*03ce13f7SAndroid Build Coastguard Worker           // hold the Sandbox Pointer -- if any.
4508*03ce13f7SAndroid Build Coastguard Worker           *Var = nullptr;
4509*03ce13f7SAndroid Build Coastguard Worker           *Relocatable = AddReloc;
4510*03ce13f7SAndroid Build Coastguard Worker           return VarAssign;
4511*03ce13f7SAndroid Build Coastguard Worker         }
4512*03ce13f7SAndroid Build Coastguard Worker       }
4513*03ce13f7SAndroid Build Coastguard Worker     }
4514*03ce13f7SAndroid Build Coastguard Worker   }
4515*03ce13f7SAndroid Build Coastguard Worker   return nullptr;
4516*03ce13f7SAndroid Build Coastguard Worker }
4517*03ce13f7SAndroid Build Coastguard Worker 
matchCombinedBaseIndex(Variable ** Base,Variable ** Index,uint16_t * Shift)4518*03ce13f7SAndroid Build Coastguard Worker const Inst *AddressOptimizer::matchCombinedBaseIndex(Variable **Base,
4519*03ce13f7SAndroid Build Coastguard Worker                                                      Variable **Index,
4520*03ce13f7SAndroid Build Coastguard Worker                                                      uint16_t *Shift) {
4521*03ce13f7SAndroid Build Coastguard Worker   // Index==nullptr && Base is Base=Var1+Var2 ==>
4522*03ce13f7SAndroid Build Coastguard Worker   //   set Base=Var1, Index=Var2, Shift=0
4523*03ce13f7SAndroid Build Coastguard Worker   if (*Base == nullptr)
4524*03ce13f7SAndroid Build Coastguard Worker     return nullptr;
4525*03ce13f7SAndroid Build Coastguard Worker   if (*Index != nullptr)
4526*03ce13f7SAndroid Build Coastguard Worker     return nullptr;
4527*03ce13f7SAndroid Build Coastguard Worker   auto *BaseInst = VMetadata->getSingleDefinition(*Base);
4528*03ce13f7SAndroid Build Coastguard Worker   if (BaseInst == nullptr)
4529*03ce13f7SAndroid Build Coastguard Worker     return nullptr;
4530*03ce13f7SAndroid Build Coastguard Worker   assert(!VMetadata->isMultiDef(*Base));
4531*03ce13f7SAndroid Build Coastguard Worker   if (BaseInst->getSrcSize() < 2)
4532*03ce13f7SAndroid Build Coastguard Worker     return nullptr;
4533*03ce13f7SAndroid Build Coastguard Worker   if (auto *Var1 = llvm::dyn_cast<Variable>(BaseInst->getSrc(0))) {
4534*03ce13f7SAndroid Build Coastguard Worker     if (VMetadata->isMultiDef(Var1))
4535*03ce13f7SAndroid Build Coastguard Worker       return nullptr;
4536*03ce13f7SAndroid Build Coastguard Worker     if (auto *Var2 = llvm::dyn_cast<Variable>(BaseInst->getSrc(1))) {
4537*03ce13f7SAndroid Build Coastguard Worker       if (VMetadata->isMultiDef(Var2))
4538*03ce13f7SAndroid Build Coastguard Worker         return nullptr;
4539*03ce13f7SAndroid Build Coastguard Worker       if (isAdd(BaseInst) &&
4540*03ce13f7SAndroid Build Coastguard Worker           // TODO: ensure Var1 and Var2 stay single-BB
4541*03ce13f7SAndroid Build Coastguard Worker           true) {
4542*03ce13f7SAndroid Build Coastguard Worker         *Base = Var1;
4543*03ce13f7SAndroid Build Coastguard Worker         *Index = Var2;
4544*03ce13f7SAndroid Build Coastguard Worker         *Shift = 0; // should already have been 0
4545*03ce13f7SAndroid Build Coastguard Worker         return BaseInst;
4546*03ce13f7SAndroid Build Coastguard Worker       }
4547*03ce13f7SAndroid Build Coastguard Worker     }
4548*03ce13f7SAndroid Build Coastguard Worker   }
4549*03ce13f7SAndroid Build Coastguard Worker   return nullptr;
4550*03ce13f7SAndroid Build Coastguard Worker }
4551*03ce13f7SAndroid Build Coastguard Worker 
matchShiftedIndex(Variable ** Index,uint16_t * Shift)4552*03ce13f7SAndroid Build Coastguard Worker const Inst *AddressOptimizer::matchShiftedIndex(Variable **Index,
4553*03ce13f7SAndroid Build Coastguard Worker                                                 uint16_t *Shift) {
4554*03ce13f7SAndroid Build Coastguard Worker   // Index is Index=Var*Const && log2(Const)+Shift<=3 ==>
4555*03ce13f7SAndroid Build Coastguard Worker   //   Index=Var, Shift+=log2(Const)
4556*03ce13f7SAndroid Build Coastguard Worker   if (*Index == nullptr)
4557*03ce13f7SAndroid Build Coastguard Worker     return nullptr;
4558*03ce13f7SAndroid Build Coastguard Worker   auto *IndexInst = VMetadata->getSingleDefinition(*Index);
4559*03ce13f7SAndroid Build Coastguard Worker   if (IndexInst == nullptr)
4560*03ce13f7SAndroid Build Coastguard Worker     return nullptr;
4561*03ce13f7SAndroid Build Coastguard Worker   assert(!VMetadata->isMultiDef(*Index));
4562*03ce13f7SAndroid Build Coastguard Worker 
4563*03ce13f7SAndroid Build Coastguard Worker   // When using an unsigned 32-bit array index on x64, it gets zero-extended
4564*03ce13f7SAndroid Build Coastguard Worker   // before the shift & add. The explicit zero extension can be eliminated
4565*03ce13f7SAndroid Build Coastguard Worker   // because x86 32-bit operations automatically get zero-extended into the
4566*03ce13f7SAndroid Build Coastguard Worker   // corresponding 64-bit register.
4567*03ce13f7SAndroid Build Coastguard Worker   if (auto *CastInst = llvm::dyn_cast<InstCast>(IndexInst)) {
4568*03ce13f7SAndroid Build Coastguard Worker     if (CastInst->getCastKind() == InstCast::Zext) {
4569*03ce13f7SAndroid Build Coastguard Worker       if (auto *Var = llvm::dyn_cast<Variable>(CastInst->getSrc(0))) {
4570*03ce13f7SAndroid Build Coastguard Worker         if (Var->getType() == IceType_i32 &&
4571*03ce13f7SAndroid Build Coastguard Worker             CastInst->getDest()->getType() == IceType_i64) {
4572*03ce13f7SAndroid Build Coastguard Worker           IndexInst = VMetadata->getSingleDefinition(Var);
4573*03ce13f7SAndroid Build Coastguard Worker         }
4574*03ce13f7SAndroid Build Coastguard Worker       }
4575*03ce13f7SAndroid Build Coastguard Worker     }
4576*03ce13f7SAndroid Build Coastguard Worker   }
4577*03ce13f7SAndroid Build Coastguard Worker 
4578*03ce13f7SAndroid Build Coastguard Worker   if (IndexInst->getSrcSize() < 2)
4579*03ce13f7SAndroid Build Coastguard Worker     return nullptr;
4580*03ce13f7SAndroid Build Coastguard Worker   if (auto *ArithInst = llvm::dyn_cast<InstArithmetic>(IndexInst)) {
4581*03ce13f7SAndroid Build Coastguard Worker     if (auto *Var = llvm::dyn_cast<Variable>(ArithInst->getSrc(0))) {
4582*03ce13f7SAndroid Build Coastguard Worker       if (auto *Const =
4583*03ce13f7SAndroid Build Coastguard Worker               llvm::dyn_cast<ConstantInteger32>(ArithInst->getSrc(1))) {
4584*03ce13f7SAndroid Build Coastguard Worker         if (VMetadata->isMultiDef(Var) || Const->getType() != IceType_i32)
4585*03ce13f7SAndroid Build Coastguard Worker           return nullptr;
4586*03ce13f7SAndroid Build Coastguard Worker         switch (ArithInst->getOp()) {
4587*03ce13f7SAndroid Build Coastguard Worker         default:
4588*03ce13f7SAndroid Build Coastguard Worker           return nullptr;
4589*03ce13f7SAndroid Build Coastguard Worker         case InstArithmetic::Mul: {
4590*03ce13f7SAndroid Build Coastguard Worker           uint32_t Mult = Const->getValue();
4591*03ce13f7SAndroid Build Coastguard Worker           uint32_t LogMult;
4592*03ce13f7SAndroid Build Coastguard Worker           switch (Mult) {
4593*03ce13f7SAndroid Build Coastguard Worker           case 1:
4594*03ce13f7SAndroid Build Coastguard Worker             LogMult = 0;
4595*03ce13f7SAndroid Build Coastguard Worker             break;
4596*03ce13f7SAndroid Build Coastguard Worker           case 2:
4597*03ce13f7SAndroid Build Coastguard Worker             LogMult = 1;
4598*03ce13f7SAndroid Build Coastguard Worker             break;
4599*03ce13f7SAndroid Build Coastguard Worker           case 4:
4600*03ce13f7SAndroid Build Coastguard Worker             LogMult = 2;
4601*03ce13f7SAndroid Build Coastguard Worker             break;
4602*03ce13f7SAndroid Build Coastguard Worker           case 8:
4603*03ce13f7SAndroid Build Coastguard Worker             LogMult = 3;
4604*03ce13f7SAndroid Build Coastguard Worker             break;
4605*03ce13f7SAndroid Build Coastguard Worker           default:
4606*03ce13f7SAndroid Build Coastguard Worker             return nullptr;
4607*03ce13f7SAndroid Build Coastguard Worker           }
4608*03ce13f7SAndroid Build Coastguard Worker           if (*Shift + LogMult <= 3) {
4609*03ce13f7SAndroid Build Coastguard Worker             *Index = Var;
4610*03ce13f7SAndroid Build Coastguard Worker             *Shift += LogMult;
4611*03ce13f7SAndroid Build Coastguard Worker             return IndexInst;
4612*03ce13f7SAndroid Build Coastguard Worker           }
4613*03ce13f7SAndroid Build Coastguard Worker         }
4614*03ce13f7SAndroid Build Coastguard Worker         case InstArithmetic::Shl: {
4615*03ce13f7SAndroid Build Coastguard Worker           uint32_t ShiftAmount = Const->getValue();
4616*03ce13f7SAndroid Build Coastguard Worker           switch (ShiftAmount) {
4617*03ce13f7SAndroid Build Coastguard Worker           case 0:
4618*03ce13f7SAndroid Build Coastguard Worker           case 1:
4619*03ce13f7SAndroid Build Coastguard Worker           case 2:
4620*03ce13f7SAndroid Build Coastguard Worker           case 3:
4621*03ce13f7SAndroid Build Coastguard Worker             break;
4622*03ce13f7SAndroid Build Coastguard Worker           default:
4623*03ce13f7SAndroid Build Coastguard Worker             return nullptr;
4624*03ce13f7SAndroid Build Coastguard Worker           }
4625*03ce13f7SAndroid Build Coastguard Worker           if (*Shift + ShiftAmount <= 3) {
4626*03ce13f7SAndroid Build Coastguard Worker             *Index = Var;
4627*03ce13f7SAndroid Build Coastguard Worker             *Shift += ShiftAmount;
4628*03ce13f7SAndroid Build Coastguard Worker             return IndexInst;
4629*03ce13f7SAndroid Build Coastguard Worker           }
4630*03ce13f7SAndroid Build Coastguard Worker         }
4631*03ce13f7SAndroid Build Coastguard Worker         }
4632*03ce13f7SAndroid Build Coastguard Worker       }
4633*03ce13f7SAndroid Build Coastguard Worker     }
4634*03ce13f7SAndroid Build Coastguard Worker   }
4635*03ce13f7SAndroid Build Coastguard Worker   return nullptr;
4636*03ce13f7SAndroid Build Coastguard Worker }
4637*03ce13f7SAndroid Build Coastguard Worker 
matchOffsetIndexOrBase(Variable ** IndexOrBase,const uint16_t Shift,ConstantRelocatable ** Relocatable,int32_t * Offset)4638*03ce13f7SAndroid Build Coastguard Worker const Inst *AddressOptimizer::matchOffsetIndexOrBase(
4639*03ce13f7SAndroid Build Coastguard Worker     Variable **IndexOrBase, const uint16_t Shift,
4640*03ce13f7SAndroid Build Coastguard Worker     ConstantRelocatable **Relocatable, int32_t *Offset) {
4641*03ce13f7SAndroid Build Coastguard Worker   // Base is Base=Var+Const || Base is Base=Const+Var ==>
4642*03ce13f7SAndroid Build Coastguard Worker   //   set Base=Var, Offset+=Const
4643*03ce13f7SAndroid Build Coastguard Worker   // Base is Base=Var-Const ==>
4644*03ce13f7SAndroid Build Coastguard Worker   //   set Base=Var, Offset-=Const
4645*03ce13f7SAndroid Build Coastguard Worker   // Index is Index=Var+Const ==>
4646*03ce13f7SAndroid Build Coastguard Worker   //   set Index=Var, Offset+=(Const<<Shift)
4647*03ce13f7SAndroid Build Coastguard Worker   // Index is Index=Const+Var ==>
4648*03ce13f7SAndroid Build Coastguard Worker   //   set Index=Var, Offset+=(Const<<Shift)
4649*03ce13f7SAndroid Build Coastguard Worker   // Index is Index=Var-Const ==>
4650*03ce13f7SAndroid Build Coastguard Worker   //   set Index=Var, Offset-=(Const<<Shift)
4651*03ce13f7SAndroid Build Coastguard Worker   // Treat Index=Var Or Const as Index=Var + Const
4652*03ce13f7SAndroid Build Coastguard Worker   //    when Var = Var' << N and log2(Const) <= N
4653*03ce13f7SAndroid Build Coastguard Worker   // or when Var = (2^M) * (2^N) and log2(Const) <= (M+N)
4654*03ce13f7SAndroid Build Coastguard Worker 
4655*03ce13f7SAndroid Build Coastguard Worker   if (*IndexOrBase == nullptr) {
4656*03ce13f7SAndroid Build Coastguard Worker     return nullptr;
4657*03ce13f7SAndroid Build Coastguard Worker   }
4658*03ce13f7SAndroid Build Coastguard Worker   const Inst *Definition = VMetadata->getSingleDefinition(*IndexOrBase);
4659*03ce13f7SAndroid Build Coastguard Worker   if (Definition == nullptr) {
4660*03ce13f7SAndroid Build Coastguard Worker     return nullptr;
4661*03ce13f7SAndroid Build Coastguard Worker   }
4662*03ce13f7SAndroid Build Coastguard Worker   assert(!VMetadata->isMultiDef(*IndexOrBase));
4663*03ce13f7SAndroid Build Coastguard Worker   if (auto *ArithInst = llvm::dyn_cast<const InstArithmetic>(Definition)) {
4664*03ce13f7SAndroid Build Coastguard Worker     switch (ArithInst->getOp()) {
4665*03ce13f7SAndroid Build Coastguard Worker     case InstArithmetic::Add:
4666*03ce13f7SAndroid Build Coastguard Worker     case InstArithmetic::Sub:
4667*03ce13f7SAndroid Build Coastguard Worker     case InstArithmetic::Or:
4668*03ce13f7SAndroid Build Coastguard Worker       break;
4669*03ce13f7SAndroid Build Coastguard Worker     default:
4670*03ce13f7SAndroid Build Coastguard Worker       return nullptr;
4671*03ce13f7SAndroid Build Coastguard Worker     }
4672*03ce13f7SAndroid Build Coastguard Worker 
4673*03ce13f7SAndroid Build Coastguard Worker     Operand *Src0 = ArithInst->getSrc(0);
4674*03ce13f7SAndroid Build Coastguard Worker     Operand *Src1 = ArithInst->getSrc(1);
4675*03ce13f7SAndroid Build Coastguard Worker     auto *Var0 = llvm::dyn_cast<Variable>(Src0);
4676*03ce13f7SAndroid Build Coastguard Worker     auto *Var1 = llvm::dyn_cast<Variable>(Src1);
4677*03ce13f7SAndroid Build Coastguard Worker     auto *Const0 = llvm::dyn_cast<ConstantInteger32>(Src0);
4678*03ce13f7SAndroid Build Coastguard Worker     auto *Const1 = llvm::dyn_cast<ConstantInteger32>(Src1);
4679*03ce13f7SAndroid Build Coastguard Worker     auto *Reloc0 = llvm::dyn_cast<ConstantRelocatable>(Src0);
4680*03ce13f7SAndroid Build Coastguard Worker     auto *Reloc1 = llvm::dyn_cast<ConstantRelocatable>(Src1);
4681*03ce13f7SAndroid Build Coastguard Worker 
4682*03ce13f7SAndroid Build Coastguard Worker     bool IsAdd = false;
4683*03ce13f7SAndroid Build Coastguard Worker     if (ArithInst->getOp() == InstArithmetic::Or) {
4684*03ce13f7SAndroid Build Coastguard Worker       Variable *Var = nullptr;
4685*03ce13f7SAndroid Build Coastguard Worker       ConstantInteger32 *Const = nullptr;
4686*03ce13f7SAndroid Build Coastguard Worker       if (Var0 && Const1) {
4687*03ce13f7SAndroid Build Coastguard Worker         Var = Var0;
4688*03ce13f7SAndroid Build Coastguard Worker         Const = Const1;
4689*03ce13f7SAndroid Build Coastguard Worker       } else if (Const0 && Var1) {
4690*03ce13f7SAndroid Build Coastguard Worker         Var = Var1;
4691*03ce13f7SAndroid Build Coastguard Worker         Const = Const0;
4692*03ce13f7SAndroid Build Coastguard Worker       } else {
4693*03ce13f7SAndroid Build Coastguard Worker         return nullptr;
4694*03ce13f7SAndroid Build Coastguard Worker       }
4695*03ce13f7SAndroid Build Coastguard Worker       auto *VarDef =
4696*03ce13f7SAndroid Build Coastguard Worker           llvm::dyn_cast<InstArithmetic>(VMetadata->getSingleDefinition(Var));
4697*03ce13f7SAndroid Build Coastguard Worker       if (VarDef == nullptr)
4698*03ce13f7SAndroid Build Coastguard Worker         return nullptr;
4699*03ce13f7SAndroid Build Coastguard Worker 
4700*03ce13f7SAndroid Build Coastguard Worker       SizeT ZeroesAvailable = 0;
4701*03ce13f7SAndroid Build Coastguard Worker       if (VarDef->getOp() == InstArithmetic::Shl) {
4702*03ce13f7SAndroid Build Coastguard Worker         if (auto *ConstInt =
4703*03ce13f7SAndroid Build Coastguard Worker                 llvm::dyn_cast<ConstantInteger32>(VarDef->getSrc(1))) {
4704*03ce13f7SAndroid Build Coastguard Worker           ZeroesAvailable = ConstInt->getValue();
4705*03ce13f7SAndroid Build Coastguard Worker         }
4706*03ce13f7SAndroid Build Coastguard Worker       } else if (VarDef->getOp() == InstArithmetic::Mul) {
4707*03ce13f7SAndroid Build Coastguard Worker         SizeT PowerOfTwo = 0;
4708*03ce13f7SAndroid Build Coastguard Worker         if (auto *MultConst =
4709*03ce13f7SAndroid Build Coastguard Worker                 llvm::dyn_cast<ConstantInteger32>(VarDef->getSrc(0))) {
4710*03ce13f7SAndroid Build Coastguard Worker           if (llvm::isPowerOf2_32(MultConst->getValue())) {
4711*03ce13f7SAndroid Build Coastguard Worker             PowerOfTwo += MultConst->getValue();
4712*03ce13f7SAndroid Build Coastguard Worker           }
4713*03ce13f7SAndroid Build Coastguard Worker         }
4714*03ce13f7SAndroid Build Coastguard Worker         if (auto *MultConst =
4715*03ce13f7SAndroid Build Coastguard Worker                 llvm::dyn_cast<ConstantInteger32>(VarDef->getSrc(1))) {
4716*03ce13f7SAndroid Build Coastguard Worker           if (llvm::isPowerOf2_32(MultConst->getValue())) {
4717*03ce13f7SAndroid Build Coastguard Worker             PowerOfTwo += MultConst->getValue();
4718*03ce13f7SAndroid Build Coastguard Worker           }
4719*03ce13f7SAndroid Build Coastguard Worker         }
4720*03ce13f7SAndroid Build Coastguard Worker         ZeroesAvailable = llvm::Log2_32(PowerOfTwo) + 1;
4721*03ce13f7SAndroid Build Coastguard Worker       }
4722*03ce13f7SAndroid Build Coastguard Worker       SizeT ZeroesNeeded = llvm::Log2_32(Const->getValue()) + 1;
4723*03ce13f7SAndroid Build Coastguard Worker       if (ZeroesNeeded == 0 || ZeroesNeeded > ZeroesAvailable)
4724*03ce13f7SAndroid Build Coastguard Worker         return nullptr;
4725*03ce13f7SAndroid Build Coastguard Worker       IsAdd = true; // treat it as an add if the above conditions hold
4726*03ce13f7SAndroid Build Coastguard Worker     } else {
4727*03ce13f7SAndroid Build Coastguard Worker       IsAdd = ArithInst->getOp() == InstArithmetic::Add;
4728*03ce13f7SAndroid Build Coastguard Worker     }
4729*03ce13f7SAndroid Build Coastguard Worker 
4730*03ce13f7SAndroid Build Coastguard Worker     Variable *NewIndexOrBase = nullptr;
4731*03ce13f7SAndroid Build Coastguard Worker     int32_t NewOffset = 0;
4732*03ce13f7SAndroid Build Coastguard Worker     ConstantRelocatable *NewRelocatable = *Relocatable;
4733*03ce13f7SAndroid Build Coastguard Worker     if (Var0 && Var1)
4734*03ce13f7SAndroid Build Coastguard Worker       // TODO(sehr): merge base/index splitting into here.
4735*03ce13f7SAndroid Build Coastguard Worker       return nullptr;
4736*03ce13f7SAndroid Build Coastguard Worker     if (!IsAdd && Var1)
4737*03ce13f7SAndroid Build Coastguard Worker       return nullptr;
4738*03ce13f7SAndroid Build Coastguard Worker     if (Var0)
4739*03ce13f7SAndroid Build Coastguard Worker       NewIndexOrBase = Var0;
4740*03ce13f7SAndroid Build Coastguard Worker     else if (Var1)
4741*03ce13f7SAndroid Build Coastguard Worker       NewIndexOrBase = Var1;
4742*03ce13f7SAndroid Build Coastguard Worker     // Don't know how to add/subtract two relocatables.
4743*03ce13f7SAndroid Build Coastguard Worker     if ((*Relocatable && (Reloc0 || Reloc1)) || (Reloc0 && Reloc1))
4744*03ce13f7SAndroid Build Coastguard Worker       return nullptr;
4745*03ce13f7SAndroid Build Coastguard Worker     // Don't know how to subtract a relocatable.
4746*03ce13f7SAndroid Build Coastguard Worker     if (!IsAdd && Reloc1)
4747*03ce13f7SAndroid Build Coastguard Worker       return nullptr;
4748*03ce13f7SAndroid Build Coastguard Worker     // Incorporate ConstantRelocatables.
4749*03ce13f7SAndroid Build Coastguard Worker     if (Reloc0)
4750*03ce13f7SAndroid Build Coastguard Worker       NewRelocatable = Reloc0;
4751*03ce13f7SAndroid Build Coastguard Worker     else if (Reloc1)
4752*03ce13f7SAndroid Build Coastguard Worker       NewRelocatable = Reloc1;
4753*03ce13f7SAndroid Build Coastguard Worker     // Compute the updated constant offset.
4754*03ce13f7SAndroid Build Coastguard Worker     if (Const0) {
4755*03ce13f7SAndroid Build Coastguard Worker       const int32_t MoreOffset =
4756*03ce13f7SAndroid Build Coastguard Worker           IsAdd ? Const0->getValue() : -Const0->getValue();
4757*03ce13f7SAndroid Build Coastguard Worker       if (Utils::WouldOverflowAdd(*Offset + NewOffset, MoreOffset))
4758*03ce13f7SAndroid Build Coastguard Worker         return nullptr;
4759*03ce13f7SAndroid Build Coastguard Worker       NewOffset += MoreOffset;
4760*03ce13f7SAndroid Build Coastguard Worker     }
4761*03ce13f7SAndroid Build Coastguard Worker     if (Const1) {
4762*03ce13f7SAndroid Build Coastguard Worker       const int32_t MoreOffset =
4763*03ce13f7SAndroid Build Coastguard Worker           IsAdd ? Const1->getValue() : -Const1->getValue();
4764*03ce13f7SAndroid Build Coastguard Worker       if (Utils::WouldOverflowAdd(*Offset + NewOffset, MoreOffset))
4765*03ce13f7SAndroid Build Coastguard Worker         return nullptr;
4766*03ce13f7SAndroid Build Coastguard Worker       NewOffset += MoreOffset;
4767*03ce13f7SAndroid Build Coastguard Worker     }
4768*03ce13f7SAndroid Build Coastguard Worker     if (Utils::WouldOverflowAdd(*Offset, NewOffset << Shift))
4769*03ce13f7SAndroid Build Coastguard Worker       return nullptr;
4770*03ce13f7SAndroid Build Coastguard Worker     *IndexOrBase = NewIndexOrBase;
4771*03ce13f7SAndroid Build Coastguard Worker     *Offset += (NewOffset << Shift);
4772*03ce13f7SAndroid Build Coastguard Worker     // Shift is always zero if this is called with the base
4773*03ce13f7SAndroid Build Coastguard Worker     *Relocatable = NewRelocatable;
4774*03ce13f7SAndroid Build Coastguard Worker     return Definition;
4775*03ce13f7SAndroid Build Coastguard Worker   }
4776*03ce13f7SAndroid Build Coastguard Worker   return nullptr;
4777*03ce13f7SAndroid Build Coastguard Worker }
4778*03ce13f7SAndroid Build Coastguard Worker 
computeAddressOpt(const Inst * Instr,Type MemType,Operand * Addr)4779*03ce13f7SAndroid Build Coastguard Worker X86OperandMem *TargetX8664::computeAddressOpt(const Inst *Instr, Type MemType,
4780*03ce13f7SAndroid Build Coastguard Worker                                               Operand *Addr) {
4781*03ce13f7SAndroid Build Coastguard Worker   Func->resetCurrentNode();
4782*03ce13f7SAndroid Build Coastguard Worker   if (Func->isVerbose(IceV_AddrOpt)) {
4783*03ce13f7SAndroid Build Coastguard Worker     OstreamLocker L(Func->getContext());
4784*03ce13f7SAndroid Build Coastguard Worker     Ostream &Str = Func->getContext()->getStrDump();
4785*03ce13f7SAndroid Build Coastguard Worker     Str << "\nStarting computeAddressOpt for instruction:\n  ";
4786*03ce13f7SAndroid Build Coastguard Worker     Instr->dumpDecorated(Func);
4787*03ce13f7SAndroid Build Coastguard Worker   }
4788*03ce13f7SAndroid Build Coastguard Worker 
4789*03ce13f7SAndroid Build Coastguard Worker   OptAddr NewAddr;
4790*03ce13f7SAndroid Build Coastguard Worker   NewAddr.Base = llvm::dyn_cast<Variable>(Addr);
4791*03ce13f7SAndroid Build Coastguard Worker   if (NewAddr.Base == nullptr)
4792*03ce13f7SAndroid Build Coastguard Worker     return nullptr;
4793*03ce13f7SAndroid Build Coastguard Worker 
4794*03ce13f7SAndroid Build Coastguard Worker   // If the Base has more than one use or is live across multiple blocks, then
4795*03ce13f7SAndroid Build Coastguard Worker   // don't go further. Alternatively (?), never consider a transformation that
4796*03ce13f7SAndroid Build Coastguard Worker   // would change a variable that is currently *not* live across basic block
4797*03ce13f7SAndroid Build Coastguard Worker   // boundaries into one that *is*.
4798*03ce13f7SAndroid Build Coastguard Worker   if (!getFlags().getLoopInvariantCodeMotion()) {
4799*03ce13f7SAndroid Build Coastguard Worker     // Need multi block address opt when licm is enabled.
4800*03ce13f7SAndroid Build Coastguard Worker     // Might make sense to restrict to current node and loop header.
4801*03ce13f7SAndroid Build Coastguard Worker     if (Func->getVMetadata()->isMultiBlock(
4802*03ce13f7SAndroid Build Coastguard Worker             NewAddr.Base) /* || Base->getUseCount() > 1*/)
4803*03ce13f7SAndroid Build Coastguard Worker       return nullptr;
4804*03ce13f7SAndroid Build Coastguard Worker   }
4805*03ce13f7SAndroid Build Coastguard Worker   AddressOptimizer AddrOpt(Func);
4806*03ce13f7SAndroid Build Coastguard Worker   const bool MockBounds = getFlags().getMockBoundsCheck();
4807*03ce13f7SAndroid Build Coastguard Worker   const Inst *Reason = nullptr;
4808*03ce13f7SAndroid Build Coastguard Worker   bool AddressWasOptimized = false;
4809*03ce13f7SAndroid Build Coastguard Worker   // The following unnamed struct identifies the address mode formation steps
4810*03ce13f7SAndroid Build Coastguard Worker   // that could potentially create an invalid memory operand (i.e., no free
4811*03ce13f7SAndroid Build Coastguard Worker   // slots for RebasePtr.) We add all those variables to this struct so that we
4812*03ce13f7SAndroid Build Coastguard Worker   // can use memset() to reset all members to false.
4813*03ce13f7SAndroid Build Coastguard Worker   struct {
4814*03ce13f7SAndroid Build Coastguard Worker     bool AssignBase = false;
4815*03ce13f7SAndroid Build Coastguard Worker     bool AssignIndex = false;
4816*03ce13f7SAndroid Build Coastguard Worker     bool OffsetFromBase = false;
4817*03ce13f7SAndroid Build Coastguard Worker     bool OffsetFromIndex = false;
4818*03ce13f7SAndroid Build Coastguard Worker     bool CombinedBaseIndex = false;
4819*03ce13f7SAndroid Build Coastguard Worker   } Skip;
4820*03ce13f7SAndroid Build Coastguard Worker   // NewAddrCheckpoint is used to rollback the address being formed in case an
4821*03ce13f7SAndroid Build Coastguard Worker   // invalid address is formed.
4822*03ce13f7SAndroid Build Coastguard Worker   OptAddr NewAddrCheckpoint;
4823*03ce13f7SAndroid Build Coastguard Worker   Reason = Instr;
4824*03ce13f7SAndroid Build Coastguard Worker   do {
4825*03ce13f7SAndroid Build Coastguard Worker     if (Reason) {
4826*03ce13f7SAndroid Build Coastguard Worker       AddrOpt.dumpAddressOpt(NewAddr.Relocatable, NewAddr.Offset, NewAddr.Base,
4827*03ce13f7SAndroid Build Coastguard Worker                              NewAddr.Index, NewAddr.Shift, Reason);
4828*03ce13f7SAndroid Build Coastguard Worker       AddressWasOptimized = true;
4829*03ce13f7SAndroid Build Coastguard Worker       Reason = nullptr;
4830*03ce13f7SAndroid Build Coastguard Worker       memset(reinterpret_cast<void *>(&Skip), 0, sizeof(Skip));
4831*03ce13f7SAndroid Build Coastguard Worker     }
4832*03ce13f7SAndroid Build Coastguard Worker 
4833*03ce13f7SAndroid Build Coastguard Worker     NewAddrCheckpoint = NewAddr;
4834*03ce13f7SAndroid Build Coastguard Worker 
4835*03ce13f7SAndroid Build Coastguard Worker     // Update Base and Index to follow through assignments to definitions.
4836*03ce13f7SAndroid Build Coastguard Worker     if (!Skip.AssignBase &&
4837*03ce13f7SAndroid Build Coastguard Worker         (Reason = AddrOpt.matchAssign(&NewAddr.Base, &NewAddr.Relocatable,
4838*03ce13f7SAndroid Build Coastguard Worker                                       &NewAddr.Offset))) {
4839*03ce13f7SAndroid Build Coastguard Worker       // Assignments of Base from a Relocatable or ConstantInt32 can result
4840*03ce13f7SAndroid Build Coastguard Worker       // in Base becoming nullptr.  To avoid code duplication in this loop we
4841*03ce13f7SAndroid Build Coastguard Worker       // prefer that Base be non-nullptr if possible.
4842*03ce13f7SAndroid Build Coastguard Worker       if ((NewAddr.Base == nullptr) && (NewAddr.Index != nullptr) &&
4843*03ce13f7SAndroid Build Coastguard Worker           NewAddr.Shift == 0) {
4844*03ce13f7SAndroid Build Coastguard Worker         std::swap(NewAddr.Base, NewAddr.Index);
4845*03ce13f7SAndroid Build Coastguard Worker       }
4846*03ce13f7SAndroid Build Coastguard Worker       continue;
4847*03ce13f7SAndroid Build Coastguard Worker     }
4848*03ce13f7SAndroid Build Coastguard Worker     if (!Skip.AssignBase &&
4849*03ce13f7SAndroid Build Coastguard Worker         (Reason = AddrOpt.matchAssign(&NewAddr.Index, &NewAddr.Relocatable,
4850*03ce13f7SAndroid Build Coastguard Worker                                       &NewAddr.Offset))) {
4851*03ce13f7SAndroid Build Coastguard Worker       continue;
4852*03ce13f7SAndroid Build Coastguard Worker     }
4853*03ce13f7SAndroid Build Coastguard Worker 
4854*03ce13f7SAndroid Build Coastguard Worker     if (!MockBounds) {
4855*03ce13f7SAndroid Build Coastguard Worker       // Transition from:
4856*03ce13f7SAndroid Build Coastguard Worker       //   <Relocatable + Offset>(Base) to
4857*03ce13f7SAndroid Build Coastguard Worker       //   <Relocatable + Offset>(Base, Index)
4858*03ce13f7SAndroid Build Coastguard Worker       if (!Skip.CombinedBaseIndex &&
4859*03ce13f7SAndroid Build Coastguard Worker           (Reason = AddrOpt.matchCombinedBaseIndex(
4860*03ce13f7SAndroid Build Coastguard Worker                &NewAddr.Base, &NewAddr.Index, &NewAddr.Shift))) {
4861*03ce13f7SAndroid Build Coastguard Worker         continue;
4862*03ce13f7SAndroid Build Coastguard Worker       }
4863*03ce13f7SAndroid Build Coastguard Worker 
4864*03ce13f7SAndroid Build Coastguard Worker       // Recognize multiply/shift and update Shift amount.
4865*03ce13f7SAndroid Build Coastguard Worker       // Index becomes Index=Var<<Const && Const+Shift<=3 ==>
4866*03ce13f7SAndroid Build Coastguard Worker       //   Index=Var, Shift+=Const
4867*03ce13f7SAndroid Build Coastguard Worker       // Index becomes Index=Const*Var && log2(Const)+Shift<=3 ==>
4868*03ce13f7SAndroid Build Coastguard Worker       //   Index=Var, Shift+=log2(Const)
4869*03ce13f7SAndroid Build Coastguard Worker       if ((Reason =
4870*03ce13f7SAndroid Build Coastguard Worker                AddrOpt.matchShiftedIndex(&NewAddr.Index, &NewAddr.Shift))) {
4871*03ce13f7SAndroid Build Coastguard Worker         continue;
4872*03ce13f7SAndroid Build Coastguard Worker       }
4873*03ce13f7SAndroid Build Coastguard Worker 
4874*03ce13f7SAndroid Build Coastguard Worker       // If Shift is zero, the choice of Base and Index was purely arbitrary.
4875*03ce13f7SAndroid Build Coastguard Worker       // Recognize multiply/shift and set Shift amount.
4876*03ce13f7SAndroid Build Coastguard Worker       // Shift==0 && Base is Base=Var*Const && log2(Const)+Shift<=3 ==>
4877*03ce13f7SAndroid Build Coastguard Worker       //   swap(Index,Base)
4878*03ce13f7SAndroid Build Coastguard Worker       // Similar for Base=Const*Var and Base=Var<<Const
4879*03ce13f7SAndroid Build Coastguard Worker       if (NewAddr.Shift == 0 &&
4880*03ce13f7SAndroid Build Coastguard Worker           (Reason = AddrOpt.matchShiftedIndex(&NewAddr.Base, &NewAddr.Shift))) {
4881*03ce13f7SAndroid Build Coastguard Worker         std::swap(NewAddr.Base, NewAddr.Index);
4882*03ce13f7SAndroid Build Coastguard Worker         continue;
4883*03ce13f7SAndroid Build Coastguard Worker       }
4884*03ce13f7SAndroid Build Coastguard Worker     }
4885*03ce13f7SAndroid Build Coastguard Worker 
4886*03ce13f7SAndroid Build Coastguard Worker     // Update Offset to reflect additions/subtractions with constants and
4887*03ce13f7SAndroid Build Coastguard Worker     // relocatables.
4888*03ce13f7SAndroid Build Coastguard Worker     // TODO: consider overflow issues with respect to Offset.
4889*03ce13f7SAndroid Build Coastguard Worker     if (!Skip.OffsetFromBase && (Reason = AddrOpt.matchOffsetIndexOrBase(
4890*03ce13f7SAndroid Build Coastguard Worker                                      &NewAddr.Base, /*Shift =*/0,
4891*03ce13f7SAndroid Build Coastguard Worker                                      &NewAddr.Relocatable, &NewAddr.Offset))) {
4892*03ce13f7SAndroid Build Coastguard Worker       continue;
4893*03ce13f7SAndroid Build Coastguard Worker     }
4894*03ce13f7SAndroid Build Coastguard Worker     if (!Skip.OffsetFromIndex && (Reason = AddrOpt.matchOffsetIndexOrBase(
4895*03ce13f7SAndroid Build Coastguard Worker                                       &NewAddr.Index, NewAddr.Shift,
4896*03ce13f7SAndroid Build Coastguard Worker                                       &NewAddr.Relocatable, &NewAddr.Offset))) {
4897*03ce13f7SAndroid Build Coastguard Worker       continue;
4898*03ce13f7SAndroid Build Coastguard Worker     }
4899*03ce13f7SAndroid Build Coastguard Worker 
4900*03ce13f7SAndroid Build Coastguard Worker     break;
4901*03ce13f7SAndroid Build Coastguard Worker   } while (Reason);
4902*03ce13f7SAndroid Build Coastguard Worker 
4903*03ce13f7SAndroid Build Coastguard Worker   if (!AddressWasOptimized) {
4904*03ce13f7SAndroid Build Coastguard Worker     return nullptr;
4905*03ce13f7SAndroid Build Coastguard Worker   }
4906*03ce13f7SAndroid Build Coastguard Worker 
4907*03ce13f7SAndroid Build Coastguard Worker   Constant *OffsetOp = nullptr;
4908*03ce13f7SAndroid Build Coastguard Worker   if (NewAddr.Relocatable == nullptr) {
4909*03ce13f7SAndroid Build Coastguard Worker     OffsetOp = Ctx->getConstantInt32(NewAddr.Offset);
4910*03ce13f7SAndroid Build Coastguard Worker   } else {
4911*03ce13f7SAndroid Build Coastguard Worker     OffsetOp =
4912*03ce13f7SAndroid Build Coastguard Worker         Ctx->getConstantSym(NewAddr.Relocatable->getOffset() + NewAddr.Offset,
4913*03ce13f7SAndroid Build Coastguard Worker                             NewAddr.Relocatable->getName());
4914*03ce13f7SAndroid Build Coastguard Worker   }
4915*03ce13f7SAndroid Build Coastguard Worker   // Vanilla ICE load instructions should not use the segment registers, and
4916*03ce13f7SAndroid Build Coastguard Worker   // computeAddressOpt only works at the level of Variables and Constants, not
4917*03ce13f7SAndroid Build Coastguard Worker   // other X86OperandMem, so there should be no mention of segment
4918*03ce13f7SAndroid Build Coastguard Worker   // registers there either.
4919*03ce13f7SAndroid Build Coastguard Worker   static constexpr auto SegmentReg =
4920*03ce13f7SAndroid Build Coastguard Worker       X86OperandMem::SegmentRegisters::DefaultSegment;
4921*03ce13f7SAndroid Build Coastguard Worker 
4922*03ce13f7SAndroid Build Coastguard Worker   return X86OperandMem::create(Func, MemType, NewAddr.Base, OffsetOp,
4923*03ce13f7SAndroid Build Coastguard Worker                                NewAddr.Index, NewAddr.Shift, SegmentReg);
4924*03ce13f7SAndroid Build Coastguard Worker }
4925*03ce13f7SAndroid Build Coastguard Worker 
4926*03ce13f7SAndroid Build Coastguard Worker /// Add a mock bounds check on the memory address before using it as a load or
4927*03ce13f7SAndroid Build Coastguard Worker /// store operand.  The basic idea is that given a memory operand [reg], we
4928*03ce13f7SAndroid Build Coastguard Worker /// would first add bounds-check code something like:
4929*03ce13f7SAndroid Build Coastguard Worker ///
4930*03ce13f7SAndroid Build Coastguard Worker ///   cmp reg, <lb>
4931*03ce13f7SAndroid Build Coastguard Worker ///   jl out_of_line_error
4932*03ce13f7SAndroid Build Coastguard Worker ///   cmp reg, <ub>
4933*03ce13f7SAndroid Build Coastguard Worker ///   jg out_of_line_error
4934*03ce13f7SAndroid Build Coastguard Worker ///
4935*03ce13f7SAndroid Build Coastguard Worker /// In reality, the specific code will depend on how <lb> and <ub> are
4936*03ce13f7SAndroid Build Coastguard Worker /// represented, e.g. an immediate, a global, or a function argument.
4937*03ce13f7SAndroid Build Coastguard Worker ///
4938*03ce13f7SAndroid Build Coastguard Worker /// As such, we need to enforce that the memory operand does not have the form
4939*03ce13f7SAndroid Build Coastguard Worker /// [reg1+reg2], because then there is no simple cmp instruction that would
4940*03ce13f7SAndroid Build Coastguard Worker /// suffice.  However, we consider [reg+offset] to be OK because the offset is
4941*03ce13f7SAndroid Build Coastguard Worker /// usually small, and so <ub> could have a safety buffer built in and then we
4942*03ce13f7SAndroid Build Coastguard Worker /// could instead branch to a custom out_of_line_error that does the precise
4943*03ce13f7SAndroid Build Coastguard Worker /// check and jumps back if it turns out OK.
4944*03ce13f7SAndroid Build Coastguard Worker ///
4945*03ce13f7SAndroid Build Coastguard Worker /// For the purpose of mocking the bounds check, we'll do something like this:
4946*03ce13f7SAndroid Build Coastguard Worker ///
4947*03ce13f7SAndroid Build Coastguard Worker ///   cmp reg, 0
4948*03ce13f7SAndroid Build Coastguard Worker ///   je label
4949*03ce13f7SAndroid Build Coastguard Worker ///   cmp reg, 1
4950*03ce13f7SAndroid Build Coastguard Worker ///   je label
4951*03ce13f7SAndroid Build Coastguard Worker ///   label:
4952*03ce13f7SAndroid Build Coastguard Worker ///
4953*03ce13f7SAndroid Build Coastguard Worker /// Also note that we don't need to add a bounds check to a dereference of a
4954*03ce13f7SAndroid Build Coastguard Worker /// simple global variable address.
4955*03ce13f7SAndroid Build Coastguard Worker 
doMockBoundsCheck(Operand * Opnd)4956*03ce13f7SAndroid Build Coastguard Worker void TargetX8664::doMockBoundsCheck(Operand *Opnd) {
4957*03ce13f7SAndroid Build Coastguard Worker   if (!getFlags().getMockBoundsCheck())
4958*03ce13f7SAndroid Build Coastguard Worker     return;
4959*03ce13f7SAndroid Build Coastguard Worker   if (auto *Mem = llvm::dyn_cast<X86OperandMem>(Opnd)) {
4960*03ce13f7SAndroid Build Coastguard Worker     if (Mem->getIndex()) {
4961*03ce13f7SAndroid Build Coastguard Worker       llvm::report_fatal_error("doMockBoundsCheck: Opnd contains index reg");
4962*03ce13f7SAndroid Build Coastguard Worker     }
4963*03ce13f7SAndroid Build Coastguard Worker     Opnd = Mem->getBase();
4964*03ce13f7SAndroid Build Coastguard Worker   }
4965*03ce13f7SAndroid Build Coastguard Worker   // At this point Opnd could be nullptr, or Variable, or Constant, or perhaps
4966*03ce13f7SAndroid Build Coastguard Worker   // something else.  We only care if it is Variable.
4967*03ce13f7SAndroid Build Coastguard Worker   auto *Var = llvm::dyn_cast_or_null<Variable>(Opnd);
4968*03ce13f7SAndroid Build Coastguard Worker   if (Var == nullptr)
4969*03ce13f7SAndroid Build Coastguard Worker     return;
4970*03ce13f7SAndroid Build Coastguard Worker   // We use lowerStore() to copy out-args onto the stack.  This creates a memory
4971*03ce13f7SAndroid Build Coastguard Worker   // operand with the stack pointer as the base register.  Don't do bounds
4972*03ce13f7SAndroid Build Coastguard Worker   // checks on that.
4973*03ce13f7SAndroid Build Coastguard Worker   if (Var->getRegNum() == getStackReg())
4974*03ce13f7SAndroid Build Coastguard Worker     return;
4975*03ce13f7SAndroid Build Coastguard Worker 
4976*03ce13f7SAndroid Build Coastguard Worker   auto *Label = InstX86Label::create(Func, this);
4977*03ce13f7SAndroid Build Coastguard Worker   _cmp(Opnd, Ctx->getConstantZero(IceType_i32));
4978*03ce13f7SAndroid Build Coastguard Worker   _br(CondX86::Br_e, Label);
4979*03ce13f7SAndroid Build Coastguard Worker   _cmp(Opnd, Ctx->getConstantInt32(1));
4980*03ce13f7SAndroid Build Coastguard Worker   _br(CondX86::Br_e, Label);
4981*03ce13f7SAndroid Build Coastguard Worker   Context.insert(Label);
4982*03ce13f7SAndroid Build Coastguard Worker }
4983*03ce13f7SAndroid Build Coastguard Worker 
lowerLoad(const InstLoad * Load)4984*03ce13f7SAndroid Build Coastguard Worker void TargetX8664::lowerLoad(const InstLoad *Load) {
4985*03ce13f7SAndroid Build Coastguard Worker   // A Load instruction can be treated the same as an Assign instruction, after
4986*03ce13f7SAndroid Build Coastguard Worker   // the source operand is transformed into an X86OperandMem operand.  Note that
4987*03ce13f7SAndroid Build Coastguard Worker   // the address mode optimization already creates an X86OperandMem operand, so
4988*03ce13f7SAndroid Build Coastguard Worker   // it doesn't need another level of transformation.
4989*03ce13f7SAndroid Build Coastguard Worker   Variable *DestLoad = Load->getDest();
4990*03ce13f7SAndroid Build Coastguard Worker   Type Ty = DestLoad->getType();
4991*03ce13f7SAndroid Build Coastguard Worker   Operand *Src0 = formMemoryOperand(Load->getLoadAddress(), Ty);
4992*03ce13f7SAndroid Build Coastguard Worker   doMockBoundsCheck(Src0);
4993*03ce13f7SAndroid Build Coastguard Worker   auto *Assign = InstAssign::create(Func, DestLoad, Src0);
4994*03ce13f7SAndroid Build Coastguard Worker   lowerAssign(Assign);
4995*03ce13f7SAndroid Build Coastguard Worker }
4996*03ce13f7SAndroid Build Coastguard Worker 
doAddressOptOther()4997*03ce13f7SAndroid Build Coastguard Worker void TargetX8664::doAddressOptOther() {
4998*03ce13f7SAndroid Build Coastguard Worker   // Inverts some Icmp instructions which helps doAddressOptLoad later.
4999*03ce13f7SAndroid Build Coastguard Worker   // TODO(manasijm): Refactor to unify the conditions for Var0 and Var1
5000*03ce13f7SAndroid Build Coastguard Worker   Inst *Instr = iteratorToInst(Context.getCur());
5001*03ce13f7SAndroid Build Coastguard Worker   auto *VMetadata = Func->getVMetadata();
5002*03ce13f7SAndroid Build Coastguard Worker   if (auto *Icmp = llvm::dyn_cast<InstIcmp>(Instr)) {
5003*03ce13f7SAndroid Build Coastguard Worker     if (llvm::isa<Constant>(Icmp->getSrc(0)) ||
5004*03ce13f7SAndroid Build Coastguard Worker         llvm::isa<Constant>(Icmp->getSrc(1)))
5005*03ce13f7SAndroid Build Coastguard Worker       return;
5006*03ce13f7SAndroid Build Coastguard Worker     auto *Var0 = llvm::dyn_cast<Variable>(Icmp->getSrc(0));
5007*03ce13f7SAndroid Build Coastguard Worker     if (Var0 == nullptr)
5008*03ce13f7SAndroid Build Coastguard Worker       return;
5009*03ce13f7SAndroid Build Coastguard Worker     if (!VMetadata->isTracked(Var0))
5010*03ce13f7SAndroid Build Coastguard Worker       return;
5011*03ce13f7SAndroid Build Coastguard Worker     auto *Op0Def = VMetadata->getFirstDefinitionSingleBlock(Var0);
5012*03ce13f7SAndroid Build Coastguard Worker     if (Op0Def == nullptr || !llvm::isa<InstLoad>(Op0Def))
5013*03ce13f7SAndroid Build Coastguard Worker       return;
5014*03ce13f7SAndroid Build Coastguard Worker     if (VMetadata->getLocalUseNode(Var0) != Context.getNode())
5015*03ce13f7SAndroid Build Coastguard Worker       return;
5016*03ce13f7SAndroid Build Coastguard Worker 
5017*03ce13f7SAndroid Build Coastguard Worker     auto *Var1 = llvm::dyn_cast<Variable>(Icmp->getSrc(1));
5018*03ce13f7SAndroid Build Coastguard Worker     if (Var1 != nullptr && VMetadata->isTracked(Var1)) {
5019*03ce13f7SAndroid Build Coastguard Worker       auto *Op1Def = VMetadata->getFirstDefinitionSingleBlock(Var1);
5020*03ce13f7SAndroid Build Coastguard Worker       if (Op1Def != nullptr && !VMetadata->isMultiBlock(Var1) &&
5021*03ce13f7SAndroid Build Coastguard Worker           llvm::isa<InstLoad>(Op1Def)) {
5022*03ce13f7SAndroid Build Coastguard Worker         return; // Both are loads
5023*03ce13f7SAndroid Build Coastguard Worker       }
5024*03ce13f7SAndroid Build Coastguard Worker     }
5025*03ce13f7SAndroid Build Coastguard Worker     Icmp->reverseConditionAndOperands();
5026*03ce13f7SAndroid Build Coastguard Worker   }
5027*03ce13f7SAndroid Build Coastguard Worker }
5028*03ce13f7SAndroid Build Coastguard Worker 
doAddressOptLoad()5029*03ce13f7SAndroid Build Coastguard Worker void TargetX8664::doAddressOptLoad() {
5030*03ce13f7SAndroid Build Coastguard Worker   Inst *Instr = iteratorToInst(Context.getCur());
5031*03ce13f7SAndroid Build Coastguard Worker   Operand *Addr = Instr->getSrc(0);
5032*03ce13f7SAndroid Build Coastguard Worker   Variable *Dest = Instr->getDest();
5033*03ce13f7SAndroid Build Coastguard Worker   if (auto *OptAddr = computeAddressOpt(Instr, Dest->getType(), Addr)) {
5034*03ce13f7SAndroid Build Coastguard Worker     Instr->setDeleted();
5035*03ce13f7SAndroid Build Coastguard Worker     Context.insert<InstLoad>(Dest, OptAddr);
5036*03ce13f7SAndroid Build Coastguard Worker   }
5037*03ce13f7SAndroid Build Coastguard Worker }
5038*03ce13f7SAndroid Build Coastguard Worker 
doAddressOptLoadSubVector()5039*03ce13f7SAndroid Build Coastguard Worker void TargetX8664::doAddressOptLoadSubVector() {
5040*03ce13f7SAndroid Build Coastguard Worker   auto *Intrinsic = llvm::cast<InstIntrinsic>(Context.getCur());
5041*03ce13f7SAndroid Build Coastguard Worker   Operand *Addr = Intrinsic->getArg(0);
5042*03ce13f7SAndroid Build Coastguard Worker   Variable *Dest = Intrinsic->getDest();
5043*03ce13f7SAndroid Build Coastguard Worker   if (auto *OptAddr = computeAddressOpt(Intrinsic, Dest->getType(), Addr)) {
5044*03ce13f7SAndroid Build Coastguard Worker     Intrinsic->setDeleted();
5045*03ce13f7SAndroid Build Coastguard Worker     const Ice::Intrinsics::IntrinsicInfo Info = {
5046*03ce13f7SAndroid Build Coastguard Worker         Ice::Intrinsics::LoadSubVector, Ice::Intrinsics::SideEffects_F,
5047*03ce13f7SAndroid Build Coastguard Worker         Ice::Intrinsics::ReturnsTwice_F, Ice::Intrinsics::MemoryWrite_F};
5048*03ce13f7SAndroid Build Coastguard Worker     auto *NewLoad = Context.insert<InstIntrinsic>(2, Dest, Info);
5049*03ce13f7SAndroid Build Coastguard Worker     NewLoad->addArg(OptAddr);
5050*03ce13f7SAndroid Build Coastguard Worker     NewLoad->addArg(Intrinsic->getArg(1));
5051*03ce13f7SAndroid Build Coastguard Worker   }
5052*03ce13f7SAndroid Build Coastguard Worker }
5053*03ce13f7SAndroid Build Coastguard Worker 
lowerPhi(const InstPhi *)5054*03ce13f7SAndroid Build Coastguard Worker void TargetX8664::lowerPhi(const InstPhi * /*Instr*/) {
5055*03ce13f7SAndroid Build Coastguard Worker   Func->setError("Phi found in regular instruction list");
5056*03ce13f7SAndroid Build Coastguard Worker }
5057*03ce13f7SAndroid Build Coastguard Worker 
lowerRet(const InstRet * Instr)5058*03ce13f7SAndroid Build Coastguard Worker void TargetX8664::lowerRet(const InstRet *Instr) {
5059*03ce13f7SAndroid Build Coastguard Worker   Variable *Reg = nullptr;
5060*03ce13f7SAndroid Build Coastguard Worker   if (Instr->hasRetValue()) {
5061*03ce13f7SAndroid Build Coastguard Worker     Operand *RetValue = legalize(Instr->getRetValue());
5062*03ce13f7SAndroid Build Coastguard Worker     const Type ReturnType = RetValue->getType();
5063*03ce13f7SAndroid Build Coastguard Worker     assert(isVectorType(ReturnType) || isScalarFloatingType(ReturnType) ||
5064*03ce13f7SAndroid Build Coastguard Worker            (ReturnType == IceType_i32) || (ReturnType == IceType_i64));
5065*03ce13f7SAndroid Build Coastguard Worker     Reg = moveReturnValueToRegister(RetValue, ReturnType);
5066*03ce13f7SAndroid Build Coastguard Worker   }
5067*03ce13f7SAndroid Build Coastguard Worker   // Add a ret instruction even if sandboxing is enabled, because addEpilog
5068*03ce13f7SAndroid Build Coastguard Worker   // explicitly looks for a ret instruction as a marker for where to insert the
5069*03ce13f7SAndroid Build Coastguard Worker   // frame removal instructions.
5070*03ce13f7SAndroid Build Coastguard Worker   _ret(Reg);
5071*03ce13f7SAndroid Build Coastguard Worker   // Add a fake use of esp to make sure esp stays alive for the entire
5072*03ce13f7SAndroid Build Coastguard Worker   // function. Otherwise post-call esp adjustments get dead-code eliminated.
5073*03ce13f7SAndroid Build Coastguard Worker   keepEspLiveAtExit();
5074*03ce13f7SAndroid Build Coastguard Worker }
5075*03ce13f7SAndroid Build Coastguard Worker 
makePshufdMask(SizeT Index0,SizeT Index1,SizeT Index2,SizeT Index3)5076*03ce13f7SAndroid Build Coastguard Worker inline uint32_t makePshufdMask(SizeT Index0, SizeT Index1, SizeT Index2,
5077*03ce13f7SAndroid Build Coastguard Worker                                SizeT Index3) {
5078*03ce13f7SAndroid Build Coastguard Worker   const SizeT Mask = (Index0 & 0x3) | ((Index1 & 0x3) << 2) |
5079*03ce13f7SAndroid Build Coastguard Worker                      ((Index2 & 0x3) << 4) | ((Index3 & 0x3) << 6);
5080*03ce13f7SAndroid Build Coastguard Worker   assert(Mask < 256);
5081*03ce13f7SAndroid Build Coastguard Worker   return Mask;
5082*03ce13f7SAndroid Build Coastguard Worker }
5083*03ce13f7SAndroid Build Coastguard Worker 
lowerShuffleVector_AllFromSameSrc(Operand * Src,SizeT Index0,SizeT Index1,SizeT Index2,SizeT Index3)5084*03ce13f7SAndroid Build Coastguard Worker Variable *TargetX8664::lowerShuffleVector_AllFromSameSrc(
5085*03ce13f7SAndroid Build Coastguard Worker     Operand *Src, SizeT Index0, SizeT Index1, SizeT Index2, SizeT Index3) {
5086*03ce13f7SAndroid Build Coastguard Worker   constexpr SizeT SrcBit = 1 << 2;
5087*03ce13f7SAndroid Build Coastguard Worker   assert((Index0 & SrcBit) == (Index1 & SrcBit));
5088*03ce13f7SAndroid Build Coastguard Worker   assert((Index0 & SrcBit) == (Index2 & SrcBit));
5089*03ce13f7SAndroid Build Coastguard Worker   assert((Index0 & SrcBit) == (Index3 & SrcBit));
5090*03ce13f7SAndroid Build Coastguard Worker   (void)SrcBit;
5091*03ce13f7SAndroid Build Coastguard Worker 
5092*03ce13f7SAndroid Build Coastguard Worker   const Type SrcTy = Src->getType();
5093*03ce13f7SAndroid Build Coastguard Worker   auto *T = makeReg(SrcTy);
5094*03ce13f7SAndroid Build Coastguard Worker   auto *SrcRM = legalize(Src, Legal_Reg | Legal_Mem);
5095*03ce13f7SAndroid Build Coastguard Worker   auto *Mask =
5096*03ce13f7SAndroid Build Coastguard Worker       Ctx->getConstantInt32(makePshufdMask(Index0, Index1, Index2, Index3));
5097*03ce13f7SAndroid Build Coastguard Worker   _pshufd(T, SrcRM, Mask);
5098*03ce13f7SAndroid Build Coastguard Worker   return T;
5099*03ce13f7SAndroid Build Coastguard Worker }
5100*03ce13f7SAndroid Build Coastguard Worker 
5101*03ce13f7SAndroid Build Coastguard Worker Variable *
lowerShuffleVector_TwoFromSameSrc(Operand * Src0,SizeT Index0,SizeT Index1,Operand * Src1,SizeT Index2,SizeT Index3)5102*03ce13f7SAndroid Build Coastguard Worker TargetX8664::lowerShuffleVector_TwoFromSameSrc(Operand *Src0, SizeT Index0,
5103*03ce13f7SAndroid Build Coastguard Worker                                                SizeT Index1, Operand *Src1,
5104*03ce13f7SAndroid Build Coastguard Worker                                                SizeT Index2, SizeT Index3) {
5105*03ce13f7SAndroid Build Coastguard Worker   constexpr SizeT SrcBit = 1 << 2;
5106*03ce13f7SAndroid Build Coastguard Worker   assert((Index0 & SrcBit) == (Index1 & SrcBit) || (Index1 == IGNORE_INDEX));
5107*03ce13f7SAndroid Build Coastguard Worker   assert((Index2 & SrcBit) == (Index3 & SrcBit) || (Index3 == IGNORE_INDEX));
5108*03ce13f7SAndroid Build Coastguard Worker   (void)SrcBit;
5109*03ce13f7SAndroid Build Coastguard Worker 
5110*03ce13f7SAndroid Build Coastguard Worker   const Type SrcTy = Src0->getType();
5111*03ce13f7SAndroid Build Coastguard Worker   assert(Src1->getType() == SrcTy);
5112*03ce13f7SAndroid Build Coastguard Worker   auto *T = makeReg(SrcTy);
5113*03ce13f7SAndroid Build Coastguard Worker   auto *Src0R = legalizeToReg(Src0);
5114*03ce13f7SAndroid Build Coastguard Worker   auto *Src1RM = legalize(Src1, Legal_Reg | Legal_Mem);
5115*03ce13f7SAndroid Build Coastguard Worker   auto *Mask =
5116*03ce13f7SAndroid Build Coastguard Worker       Ctx->getConstantInt32(makePshufdMask(Index0, Index1, Index2, Index3));
5117*03ce13f7SAndroid Build Coastguard Worker   _movp(T, Src0R);
5118*03ce13f7SAndroid Build Coastguard Worker   _shufps(T, Src1RM, Mask);
5119*03ce13f7SAndroid Build Coastguard Worker   return T;
5120*03ce13f7SAndroid Build Coastguard Worker }
5121*03ce13f7SAndroid Build Coastguard Worker 
lowerShuffleVector_UnifyFromDifferentSrcs(Operand * Src0,SizeT Index0,Operand * Src1,SizeT Index1)5122*03ce13f7SAndroid Build Coastguard Worker Variable *TargetX8664::lowerShuffleVector_UnifyFromDifferentSrcs(Operand *Src0,
5123*03ce13f7SAndroid Build Coastguard Worker                                                                  SizeT Index0,
5124*03ce13f7SAndroid Build Coastguard Worker                                                                  Operand *Src1,
5125*03ce13f7SAndroid Build Coastguard Worker                                                                  SizeT Index1) {
5126*03ce13f7SAndroid Build Coastguard Worker   return lowerShuffleVector_TwoFromSameSrc(Src0, Index0, IGNORE_INDEX, Src1,
5127*03ce13f7SAndroid Build Coastguard Worker                                            Index1, IGNORE_INDEX);
5128*03ce13f7SAndroid Build Coastguard Worker }
5129*03ce13f7SAndroid Build Coastguard Worker 
makeSrcSwitchMask(SizeT Index0,SizeT Index1,SizeT Index2,SizeT Index3)5130*03ce13f7SAndroid Build Coastguard Worker inline SizeT makeSrcSwitchMask(SizeT Index0, SizeT Index1, SizeT Index2,
5131*03ce13f7SAndroid Build Coastguard Worker                                SizeT Index3) {
5132*03ce13f7SAndroid Build Coastguard Worker   constexpr SizeT SrcBit = 1 << 2;
5133*03ce13f7SAndroid Build Coastguard Worker   const SizeT Index0Bits = ((Index0 & SrcBit) == 0) ? 0 : (1 << 0);
5134*03ce13f7SAndroid Build Coastguard Worker   const SizeT Index1Bits = ((Index1 & SrcBit) == 0) ? 0 : (1 << 1);
5135*03ce13f7SAndroid Build Coastguard Worker   const SizeT Index2Bits = ((Index2 & SrcBit) == 0) ? 0 : (1 << 2);
5136*03ce13f7SAndroid Build Coastguard Worker   const SizeT Index3Bits = ((Index3 & SrcBit) == 0) ? 0 : (1 << 3);
5137*03ce13f7SAndroid Build Coastguard Worker   return Index0Bits | Index1Bits | Index2Bits | Index3Bits;
5138*03ce13f7SAndroid Build Coastguard Worker }
5139*03ce13f7SAndroid Build Coastguard Worker 
lowerShuffleVector_NewMaskName()5140*03ce13f7SAndroid Build Coastguard Worker GlobalString TargetX8664::lowerShuffleVector_NewMaskName() {
5141*03ce13f7SAndroid Build Coastguard Worker   GlobalString FuncName = Func->getFunctionName();
5142*03ce13f7SAndroid Build Coastguard Worker   const SizeT Id = PshufbMaskCount++;
5143*03ce13f7SAndroid Build Coastguard Worker   if (!BuildDefs::dump() || !FuncName.hasStdString()) {
5144*03ce13f7SAndroid Build Coastguard Worker     return GlobalString::createWithString(
5145*03ce13f7SAndroid Build Coastguard Worker         Ctx,
5146*03ce13f7SAndroid Build Coastguard Worker         "$PS" + std::to_string(FuncName.getID()) + "_" + std::to_string(Id));
5147*03ce13f7SAndroid Build Coastguard Worker   }
5148*03ce13f7SAndroid Build Coastguard Worker   return GlobalString::createWithString(
5149*03ce13f7SAndroid Build Coastguard Worker       Ctx, "Pshufb$" + Func->getFunctionName() + "$" + std::to_string(Id));
5150*03ce13f7SAndroid Build Coastguard Worker }
5151*03ce13f7SAndroid Build Coastguard Worker 
lowerShuffleVector_CreatePshufbMask(int8_t Idx0,int8_t Idx1,int8_t Idx2,int8_t Idx3,int8_t Idx4,int8_t Idx5,int8_t Idx6,int8_t Idx7,int8_t Idx8,int8_t Idx9,int8_t Idx10,int8_t Idx11,int8_t Idx12,int8_t Idx13,int8_t Idx14,int8_t Idx15)5152*03ce13f7SAndroid Build Coastguard Worker ConstantRelocatable *TargetX8664::lowerShuffleVector_CreatePshufbMask(
5153*03ce13f7SAndroid Build Coastguard Worker     int8_t Idx0, int8_t Idx1, int8_t Idx2, int8_t Idx3, int8_t Idx4,
5154*03ce13f7SAndroid Build Coastguard Worker     int8_t Idx5, int8_t Idx6, int8_t Idx7, int8_t Idx8, int8_t Idx9,
5155*03ce13f7SAndroid Build Coastguard Worker     int8_t Idx10, int8_t Idx11, int8_t Idx12, int8_t Idx13, int8_t Idx14,
5156*03ce13f7SAndroid Build Coastguard Worker     int8_t Idx15) {
5157*03ce13f7SAndroid Build Coastguard Worker   static constexpr uint8_t NumElements = 16;
5158*03ce13f7SAndroid Build Coastguard Worker   const char Initializer[NumElements] = {
5159*03ce13f7SAndroid Build Coastguard Worker       Idx0, Idx1, Idx2,  Idx3,  Idx4,  Idx5,  Idx6,  Idx7,
5160*03ce13f7SAndroid Build Coastguard Worker       Idx8, Idx9, Idx10, Idx11, Idx12, Idx13, Idx14, Idx15,
5161*03ce13f7SAndroid Build Coastguard Worker   };
5162*03ce13f7SAndroid Build Coastguard Worker 
5163*03ce13f7SAndroid Build Coastguard Worker   static constexpr Type V4VectorType = IceType_v4i32;
5164*03ce13f7SAndroid Build Coastguard Worker   const uint32_t MaskAlignment = typeWidthInBytesOnStack(V4VectorType);
5165*03ce13f7SAndroid Build Coastguard Worker   auto *Mask = VariableDeclaration::create(Func->getGlobalPool());
5166*03ce13f7SAndroid Build Coastguard Worker   GlobalString MaskName = lowerShuffleVector_NewMaskName();
5167*03ce13f7SAndroid Build Coastguard Worker   Mask->setIsConstant(true);
5168*03ce13f7SAndroid Build Coastguard Worker   Mask->addInitializer(VariableDeclaration::DataInitializer::create(
5169*03ce13f7SAndroid Build Coastguard Worker       Func->getGlobalPool(), Initializer, NumElements));
5170*03ce13f7SAndroid Build Coastguard Worker   Mask->setName(MaskName);
5171*03ce13f7SAndroid Build Coastguard Worker   // Mask needs to be 16-byte aligned, or pshufb will seg fault.
5172*03ce13f7SAndroid Build Coastguard Worker   Mask->setAlignment(MaskAlignment);
5173*03ce13f7SAndroid Build Coastguard Worker   Func->addGlobal(Mask);
5174*03ce13f7SAndroid Build Coastguard Worker 
5175*03ce13f7SAndroid Build Coastguard Worker   constexpr RelocOffsetT Offset = 0;
5176*03ce13f7SAndroid Build Coastguard Worker   return llvm::cast<ConstantRelocatable>(Ctx->getConstantSym(Offset, MaskName));
5177*03ce13f7SAndroid Build Coastguard Worker }
5178*03ce13f7SAndroid Build Coastguard Worker 
lowerShuffleVector_UsingPshufb(Variable * Dest,Operand * Src0,Operand * Src1,int8_t Idx0,int8_t Idx1,int8_t Idx2,int8_t Idx3,int8_t Idx4,int8_t Idx5,int8_t Idx6,int8_t Idx7,int8_t Idx8,int8_t Idx9,int8_t Idx10,int8_t Idx11,int8_t Idx12,int8_t Idx13,int8_t Idx14,int8_t Idx15)5179*03ce13f7SAndroid Build Coastguard Worker void TargetX8664::lowerShuffleVector_UsingPshufb(
5180*03ce13f7SAndroid Build Coastguard Worker     Variable *Dest, Operand *Src0, Operand *Src1, int8_t Idx0, int8_t Idx1,
5181*03ce13f7SAndroid Build Coastguard Worker     int8_t Idx2, int8_t Idx3, int8_t Idx4, int8_t Idx5, int8_t Idx6,
5182*03ce13f7SAndroid Build Coastguard Worker     int8_t Idx7, int8_t Idx8, int8_t Idx9, int8_t Idx10, int8_t Idx11,
5183*03ce13f7SAndroid Build Coastguard Worker     int8_t Idx12, int8_t Idx13, int8_t Idx14, int8_t Idx15) {
5184*03ce13f7SAndroid Build Coastguard Worker   const Type DestTy = Dest->getType();
5185*03ce13f7SAndroid Build Coastguard Worker   static constexpr bool NotRebased = false;
5186*03ce13f7SAndroid Build Coastguard Worker   static constexpr Variable *NoBase = nullptr;
5187*03ce13f7SAndroid Build Coastguard Worker   // We use void for the memory operand instead of DestTy because using the
5188*03ce13f7SAndroid Build Coastguard Worker   // latter causes a validation failure: the X86 Inst layer complains that
5189*03ce13f7SAndroid Build Coastguard Worker   // vector mem operands could be under aligned. Thus, using void we avoid the
5190*03ce13f7SAndroid Build Coastguard Worker   // validation error. Note that the mask global declaration is aligned, so it
5191*03ce13f7SAndroid Build Coastguard Worker   // can be used as an XMM mem operand.
5192*03ce13f7SAndroid Build Coastguard Worker   static constexpr Type MaskType = IceType_void;
5193*03ce13f7SAndroid Build Coastguard Worker #define IDX_IN_SRC(N, S)                                                       \
5194*03ce13f7SAndroid Build Coastguard Worker   ((((N) & (1 << 4)) == (S << 4)) ? ((N)&0xf) : CLEAR_ALL_BITS)
5195*03ce13f7SAndroid Build Coastguard Worker   auto *Mask0M = X86OperandMem::create(
5196*03ce13f7SAndroid Build Coastguard Worker       Func, MaskType, NoBase,
5197*03ce13f7SAndroid Build Coastguard Worker       lowerShuffleVector_CreatePshufbMask(
5198*03ce13f7SAndroid Build Coastguard Worker           IDX_IN_SRC(Idx0, 0), IDX_IN_SRC(Idx1, 0), IDX_IN_SRC(Idx2, 0),
5199*03ce13f7SAndroid Build Coastguard Worker           IDX_IN_SRC(Idx3, 0), IDX_IN_SRC(Idx4, 0), IDX_IN_SRC(Idx5, 0),
5200*03ce13f7SAndroid Build Coastguard Worker           IDX_IN_SRC(Idx6, 0), IDX_IN_SRC(Idx7, 0), IDX_IN_SRC(Idx8, 0),
5201*03ce13f7SAndroid Build Coastguard Worker           IDX_IN_SRC(Idx9, 0), IDX_IN_SRC(Idx10, 0), IDX_IN_SRC(Idx11, 0),
5202*03ce13f7SAndroid Build Coastguard Worker           IDX_IN_SRC(Idx12, 0), IDX_IN_SRC(Idx13, 0), IDX_IN_SRC(Idx14, 0),
5203*03ce13f7SAndroid Build Coastguard Worker           IDX_IN_SRC(Idx15, 0)),
5204*03ce13f7SAndroid Build Coastguard Worker       NotRebased);
5205*03ce13f7SAndroid Build Coastguard Worker 
5206*03ce13f7SAndroid Build Coastguard Worker   auto *T0 = makeReg(DestTy);
5207*03ce13f7SAndroid Build Coastguard Worker   auto *Src0RM = legalize(Src0, Legal_Reg | Legal_Mem);
5208*03ce13f7SAndroid Build Coastguard Worker   _movp(T0, Src0RM);
5209*03ce13f7SAndroid Build Coastguard Worker 
5210*03ce13f7SAndroid Build Coastguard Worker   _pshufb(T0, Mask0M);
5211*03ce13f7SAndroid Build Coastguard Worker 
5212*03ce13f7SAndroid Build Coastguard Worker   if (Idx0 >= 16 || Idx1 >= 16 || Idx2 >= 16 || Idx3 >= 16 || Idx4 >= 16 ||
5213*03ce13f7SAndroid Build Coastguard Worker       Idx5 >= 16 || Idx6 >= 16 || Idx7 >= 16 || Idx8 >= 16 || Idx9 >= 16 ||
5214*03ce13f7SAndroid Build Coastguard Worker       Idx10 >= 16 || Idx11 >= 16 || Idx12 >= 16 || Idx13 >= 16 || Idx14 >= 16 ||
5215*03ce13f7SAndroid Build Coastguard Worker       Idx15 >= 16) {
5216*03ce13f7SAndroid Build Coastguard Worker     auto *Mask1M = X86OperandMem::create(
5217*03ce13f7SAndroid Build Coastguard Worker         Func, MaskType, NoBase,
5218*03ce13f7SAndroid Build Coastguard Worker         lowerShuffleVector_CreatePshufbMask(
5219*03ce13f7SAndroid Build Coastguard Worker             IDX_IN_SRC(Idx0, 1), IDX_IN_SRC(Idx1, 1), IDX_IN_SRC(Idx2, 1),
5220*03ce13f7SAndroid Build Coastguard Worker             IDX_IN_SRC(Idx3, 1), IDX_IN_SRC(Idx4, 1), IDX_IN_SRC(Idx5, 1),
5221*03ce13f7SAndroid Build Coastguard Worker             IDX_IN_SRC(Idx6, 1), IDX_IN_SRC(Idx7, 1), IDX_IN_SRC(Idx8, 1),
5222*03ce13f7SAndroid Build Coastguard Worker             IDX_IN_SRC(Idx9, 1), IDX_IN_SRC(Idx10, 1), IDX_IN_SRC(Idx11, 1),
5223*03ce13f7SAndroid Build Coastguard Worker             IDX_IN_SRC(Idx12, 1), IDX_IN_SRC(Idx13, 1), IDX_IN_SRC(Idx14, 1),
5224*03ce13f7SAndroid Build Coastguard Worker             IDX_IN_SRC(Idx15, 1)),
5225*03ce13f7SAndroid Build Coastguard Worker         NotRebased);
5226*03ce13f7SAndroid Build Coastguard Worker #undef IDX_IN_SRC
5227*03ce13f7SAndroid Build Coastguard Worker     auto *T1 = makeReg(DestTy);
5228*03ce13f7SAndroid Build Coastguard Worker     auto *Src1RM = legalize(Src1, Legal_Reg | Legal_Mem);
5229*03ce13f7SAndroid Build Coastguard Worker     _movp(T1, Src1RM);
5230*03ce13f7SAndroid Build Coastguard Worker     _pshufb(T1, Mask1M);
5231*03ce13f7SAndroid Build Coastguard Worker     _por(T0, T1);
5232*03ce13f7SAndroid Build Coastguard Worker   }
5233*03ce13f7SAndroid Build Coastguard Worker 
5234*03ce13f7SAndroid Build Coastguard Worker   _movp(Dest, T0);
5235*03ce13f7SAndroid Build Coastguard Worker }
5236*03ce13f7SAndroid Build Coastguard Worker 
lowerShuffleVector(const InstShuffleVector * Instr)5237*03ce13f7SAndroid Build Coastguard Worker void TargetX8664::lowerShuffleVector(const InstShuffleVector *Instr) {
5238*03ce13f7SAndroid Build Coastguard Worker   auto *Dest = Instr->getDest();
5239*03ce13f7SAndroid Build Coastguard Worker   const Type DestTy = Dest->getType();
5240*03ce13f7SAndroid Build Coastguard Worker   auto *Src0 = Instr->getSrc(0);
5241*03ce13f7SAndroid Build Coastguard Worker   auto *Src1 = Instr->getSrc(1);
5242*03ce13f7SAndroid Build Coastguard Worker   const SizeT NumElements = typeNumElements(DestTy);
5243*03ce13f7SAndroid Build Coastguard Worker 
5244*03ce13f7SAndroid Build Coastguard Worker   auto *T = makeReg(DestTy);
5245*03ce13f7SAndroid Build Coastguard Worker 
5246*03ce13f7SAndroid Build Coastguard Worker   switch (DestTy) {
5247*03ce13f7SAndroid Build Coastguard Worker   default:
5248*03ce13f7SAndroid Build Coastguard Worker     llvm::report_fatal_error("Unexpected vector type.");
5249*03ce13f7SAndroid Build Coastguard Worker   case IceType_v16i1:
5250*03ce13f7SAndroid Build Coastguard Worker   case IceType_v16i8: {
5251*03ce13f7SAndroid Build Coastguard Worker     static constexpr SizeT ExpectedNumElements = 16;
5252*03ce13f7SAndroid Build Coastguard Worker     assert(ExpectedNumElements == Instr->getNumIndexes());
5253*03ce13f7SAndroid Build Coastguard Worker     (void)ExpectedNumElements;
5254*03ce13f7SAndroid Build Coastguard Worker 
5255*03ce13f7SAndroid Build Coastguard Worker     if (Instr->indexesAre(0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7)) {
5256*03ce13f7SAndroid Build Coastguard Worker       auto *T = makeReg(DestTy);
5257*03ce13f7SAndroid Build Coastguard Worker       auto *Src0RM = legalize(Src0, Legal_Reg | Legal_Mem);
5258*03ce13f7SAndroid Build Coastguard Worker       _movp(T, Src0RM);
5259*03ce13f7SAndroid Build Coastguard Worker       _punpckl(T, Src0RM);
5260*03ce13f7SAndroid Build Coastguard Worker       _movp(Dest, T);
5261*03ce13f7SAndroid Build Coastguard Worker       return;
5262*03ce13f7SAndroid Build Coastguard Worker     }
5263*03ce13f7SAndroid Build Coastguard Worker 
5264*03ce13f7SAndroid Build Coastguard Worker     if (Instr->indexesAre(0, 16, 1, 17, 2, 18, 3, 19, 4, 20, 5, 21, 6, 22, 7,
5265*03ce13f7SAndroid Build Coastguard Worker                           23)) {
5266*03ce13f7SAndroid Build Coastguard Worker       auto *T = makeReg(DestTy);
5267*03ce13f7SAndroid Build Coastguard Worker       auto *Src0RM = legalize(Src0, Legal_Reg | Legal_Mem);
5268*03ce13f7SAndroid Build Coastguard Worker       auto *Src1RM = legalize(Src1, Legal_Reg | Legal_Mem);
5269*03ce13f7SAndroid Build Coastguard Worker       _movp(T, Src0RM);
5270*03ce13f7SAndroid Build Coastguard Worker       _punpckl(T, Src1RM);
5271*03ce13f7SAndroid Build Coastguard Worker       _movp(Dest, T);
5272*03ce13f7SAndroid Build Coastguard Worker       return;
5273*03ce13f7SAndroid Build Coastguard Worker     }
5274*03ce13f7SAndroid Build Coastguard Worker 
5275*03ce13f7SAndroid Build Coastguard Worker     if (Instr->indexesAre(8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14,
5276*03ce13f7SAndroid Build Coastguard Worker                           15, 15)) {
5277*03ce13f7SAndroid Build Coastguard Worker       auto *T = makeReg(DestTy);
5278*03ce13f7SAndroid Build Coastguard Worker       auto *Src0RM = legalize(Src0, Legal_Reg | Legal_Mem);
5279*03ce13f7SAndroid Build Coastguard Worker       _movp(T, Src0RM);
5280*03ce13f7SAndroid Build Coastguard Worker       _punpckh(T, Src0RM);
5281*03ce13f7SAndroid Build Coastguard Worker       _movp(Dest, T);
5282*03ce13f7SAndroid Build Coastguard Worker       return;
5283*03ce13f7SAndroid Build Coastguard Worker     }
5284*03ce13f7SAndroid Build Coastguard Worker 
5285*03ce13f7SAndroid Build Coastguard Worker     if (Instr->indexesAre(8, 24, 9, 25, 10, 26, 11, 27, 12, 28, 13, 29, 14, 30,
5286*03ce13f7SAndroid Build Coastguard Worker                           15, 31)) {
5287*03ce13f7SAndroid Build Coastguard Worker       auto *T = makeReg(DestTy);
5288*03ce13f7SAndroid Build Coastguard Worker       auto *Src0RM = legalize(Src0, Legal_Reg | Legal_Mem);
5289*03ce13f7SAndroid Build Coastguard Worker       auto *Src1RM = legalize(Src1, Legal_Reg | Legal_Mem);
5290*03ce13f7SAndroid Build Coastguard Worker       _movp(T, Src0RM);
5291*03ce13f7SAndroid Build Coastguard Worker       _punpckh(T, Src1RM);
5292*03ce13f7SAndroid Build Coastguard Worker       _movp(Dest, T);
5293*03ce13f7SAndroid Build Coastguard Worker       return;
5294*03ce13f7SAndroid Build Coastguard Worker     }
5295*03ce13f7SAndroid Build Coastguard Worker 
5296*03ce13f7SAndroid Build Coastguard Worker     if (InstructionSet < SSE4_1) {
5297*03ce13f7SAndroid Build Coastguard Worker       // TODO(jpp): figure out how to lower with sse2.
5298*03ce13f7SAndroid Build Coastguard Worker       break;
5299*03ce13f7SAndroid Build Coastguard Worker     }
5300*03ce13f7SAndroid Build Coastguard Worker 
5301*03ce13f7SAndroid Build Coastguard Worker     const SizeT Index0 = Instr->getIndexValue(0);
5302*03ce13f7SAndroid Build Coastguard Worker     const SizeT Index1 = Instr->getIndexValue(1);
5303*03ce13f7SAndroid Build Coastguard Worker     const SizeT Index2 = Instr->getIndexValue(2);
5304*03ce13f7SAndroid Build Coastguard Worker     const SizeT Index3 = Instr->getIndexValue(3);
5305*03ce13f7SAndroid Build Coastguard Worker     const SizeT Index4 = Instr->getIndexValue(4);
5306*03ce13f7SAndroid Build Coastguard Worker     const SizeT Index5 = Instr->getIndexValue(5);
5307*03ce13f7SAndroid Build Coastguard Worker     const SizeT Index6 = Instr->getIndexValue(6);
5308*03ce13f7SAndroid Build Coastguard Worker     const SizeT Index7 = Instr->getIndexValue(7);
5309*03ce13f7SAndroid Build Coastguard Worker     const SizeT Index8 = Instr->getIndexValue(8);
5310*03ce13f7SAndroid Build Coastguard Worker     const SizeT Index9 = Instr->getIndexValue(9);
5311*03ce13f7SAndroid Build Coastguard Worker     const SizeT Index10 = Instr->getIndexValue(10);
5312*03ce13f7SAndroid Build Coastguard Worker     const SizeT Index11 = Instr->getIndexValue(11);
5313*03ce13f7SAndroid Build Coastguard Worker     const SizeT Index12 = Instr->getIndexValue(12);
5314*03ce13f7SAndroid Build Coastguard Worker     const SizeT Index13 = Instr->getIndexValue(13);
5315*03ce13f7SAndroid Build Coastguard Worker     const SizeT Index14 = Instr->getIndexValue(14);
5316*03ce13f7SAndroid Build Coastguard Worker     const SizeT Index15 = Instr->getIndexValue(15);
5317*03ce13f7SAndroid Build Coastguard Worker 
5318*03ce13f7SAndroid Build Coastguard Worker     lowerShuffleVector_UsingPshufb(Dest, Src0, Src1, Index0, Index1, Index2,
5319*03ce13f7SAndroid Build Coastguard Worker                                    Index3, Index4, Index5, Index6, Index7,
5320*03ce13f7SAndroid Build Coastguard Worker                                    Index8, Index9, Index10, Index11, Index12,
5321*03ce13f7SAndroid Build Coastguard Worker                                    Index13, Index14, Index15);
5322*03ce13f7SAndroid Build Coastguard Worker     return;
5323*03ce13f7SAndroid Build Coastguard Worker   }
5324*03ce13f7SAndroid Build Coastguard Worker   case IceType_v8i1:
5325*03ce13f7SAndroid Build Coastguard Worker   case IceType_v8i16: {
5326*03ce13f7SAndroid Build Coastguard Worker     static constexpr SizeT ExpectedNumElements = 8;
5327*03ce13f7SAndroid Build Coastguard Worker     assert(ExpectedNumElements == Instr->getNumIndexes());
5328*03ce13f7SAndroid Build Coastguard Worker     (void)ExpectedNumElements;
5329*03ce13f7SAndroid Build Coastguard Worker 
5330*03ce13f7SAndroid Build Coastguard Worker     if (Instr->indexesAre(0, 0, 1, 1, 2, 2, 3, 3)) {
5331*03ce13f7SAndroid Build Coastguard Worker       auto *T = makeReg(DestTy);
5332*03ce13f7SAndroid Build Coastguard Worker       auto *Src0RM = legalize(Src0, Legal_Reg | Legal_Mem);
5333*03ce13f7SAndroid Build Coastguard Worker       _movp(T, Src0RM);
5334*03ce13f7SAndroid Build Coastguard Worker       _punpckl(T, Src0RM);
5335*03ce13f7SAndroid Build Coastguard Worker       _movp(Dest, T);
5336*03ce13f7SAndroid Build Coastguard Worker       return;
5337*03ce13f7SAndroid Build Coastguard Worker     }
5338*03ce13f7SAndroid Build Coastguard Worker 
5339*03ce13f7SAndroid Build Coastguard Worker     if (Instr->indexesAre(0, 8, 1, 9, 2, 10, 3, 11)) {
5340*03ce13f7SAndroid Build Coastguard Worker       auto *T = makeReg(DestTy);
5341*03ce13f7SAndroid Build Coastguard Worker       auto *Src0RM = legalize(Src0, Legal_Reg | Legal_Mem);
5342*03ce13f7SAndroid Build Coastguard Worker       auto *Src1RM = legalize(Src1, Legal_Reg | Legal_Mem);
5343*03ce13f7SAndroid Build Coastguard Worker       _movp(T, Src0RM);
5344*03ce13f7SAndroid Build Coastguard Worker       _punpckl(T, Src1RM);
5345*03ce13f7SAndroid Build Coastguard Worker       _movp(Dest, T);
5346*03ce13f7SAndroid Build Coastguard Worker       return;
5347*03ce13f7SAndroid Build Coastguard Worker     }
5348*03ce13f7SAndroid Build Coastguard Worker 
5349*03ce13f7SAndroid Build Coastguard Worker     if (Instr->indexesAre(4, 4, 5, 5, 6, 6, 7, 7)) {
5350*03ce13f7SAndroid Build Coastguard Worker       auto *T = makeReg(DestTy);
5351*03ce13f7SAndroid Build Coastguard Worker       auto *Src0RM = legalize(Src0, Legal_Reg | Legal_Mem);
5352*03ce13f7SAndroid Build Coastguard Worker       _movp(T, Src0RM);
5353*03ce13f7SAndroid Build Coastguard Worker       _punpckh(T, Src0RM);
5354*03ce13f7SAndroid Build Coastguard Worker       _movp(Dest, T);
5355*03ce13f7SAndroid Build Coastguard Worker       return;
5356*03ce13f7SAndroid Build Coastguard Worker     }
5357*03ce13f7SAndroid Build Coastguard Worker 
5358*03ce13f7SAndroid Build Coastguard Worker     if (Instr->indexesAre(4, 12, 5, 13, 6, 14, 7, 15)) {
5359*03ce13f7SAndroid Build Coastguard Worker       auto *T = makeReg(DestTy);
5360*03ce13f7SAndroid Build Coastguard Worker       auto *Src0RM = legalize(Src0, Legal_Reg | Legal_Mem);
5361*03ce13f7SAndroid Build Coastguard Worker       auto *Src1RM = legalize(Src1, Legal_Reg | Legal_Mem);
5362*03ce13f7SAndroid Build Coastguard Worker       _movp(T, Src0RM);
5363*03ce13f7SAndroid Build Coastguard Worker       _punpckh(T, Src1RM);
5364*03ce13f7SAndroid Build Coastguard Worker       _movp(Dest, T);
5365*03ce13f7SAndroid Build Coastguard Worker       return;
5366*03ce13f7SAndroid Build Coastguard Worker     }
5367*03ce13f7SAndroid Build Coastguard Worker 
5368*03ce13f7SAndroid Build Coastguard Worker     if (InstructionSet < SSE4_1) {
5369*03ce13f7SAndroid Build Coastguard Worker       // TODO(jpp): figure out how to lower with sse2.
5370*03ce13f7SAndroid Build Coastguard Worker       break;
5371*03ce13f7SAndroid Build Coastguard Worker     }
5372*03ce13f7SAndroid Build Coastguard Worker 
5373*03ce13f7SAndroid Build Coastguard Worker     const SizeT Index0 = Instr->getIndexValue(0);
5374*03ce13f7SAndroid Build Coastguard Worker     const SizeT Index1 = Instr->getIndexValue(1);
5375*03ce13f7SAndroid Build Coastguard Worker     const SizeT Index2 = Instr->getIndexValue(2);
5376*03ce13f7SAndroid Build Coastguard Worker     const SizeT Index3 = Instr->getIndexValue(3);
5377*03ce13f7SAndroid Build Coastguard Worker     const SizeT Index4 = Instr->getIndexValue(4);
5378*03ce13f7SAndroid Build Coastguard Worker     const SizeT Index5 = Instr->getIndexValue(5);
5379*03ce13f7SAndroid Build Coastguard Worker     const SizeT Index6 = Instr->getIndexValue(6);
5380*03ce13f7SAndroid Build Coastguard Worker     const SizeT Index7 = Instr->getIndexValue(7);
5381*03ce13f7SAndroid Build Coastguard Worker 
5382*03ce13f7SAndroid Build Coastguard Worker #define TO_BYTE_INDEX(I) ((I) << 1)
5383*03ce13f7SAndroid Build Coastguard Worker     lowerShuffleVector_UsingPshufb(
5384*03ce13f7SAndroid Build Coastguard Worker         Dest, Src0, Src1, TO_BYTE_INDEX(Index0), TO_BYTE_INDEX(Index0) + 1,
5385*03ce13f7SAndroid Build Coastguard Worker         TO_BYTE_INDEX(Index1), TO_BYTE_INDEX(Index1) + 1, TO_BYTE_INDEX(Index2),
5386*03ce13f7SAndroid Build Coastguard Worker         TO_BYTE_INDEX(Index2) + 1, TO_BYTE_INDEX(Index3),
5387*03ce13f7SAndroid Build Coastguard Worker         TO_BYTE_INDEX(Index3) + 1, TO_BYTE_INDEX(Index4),
5388*03ce13f7SAndroid Build Coastguard Worker         TO_BYTE_INDEX(Index4) + 1, TO_BYTE_INDEX(Index5),
5389*03ce13f7SAndroid Build Coastguard Worker         TO_BYTE_INDEX(Index5) + 1, TO_BYTE_INDEX(Index6),
5390*03ce13f7SAndroid Build Coastguard Worker         TO_BYTE_INDEX(Index6) + 1, TO_BYTE_INDEX(Index7),
5391*03ce13f7SAndroid Build Coastguard Worker         TO_BYTE_INDEX(Index7) + 1);
5392*03ce13f7SAndroid Build Coastguard Worker #undef TO_BYTE_INDEX
5393*03ce13f7SAndroid Build Coastguard Worker     return;
5394*03ce13f7SAndroid Build Coastguard Worker   }
5395*03ce13f7SAndroid Build Coastguard Worker   case IceType_v4i1:
5396*03ce13f7SAndroid Build Coastguard Worker   case IceType_v4i32:
5397*03ce13f7SAndroid Build Coastguard Worker   case IceType_v4f32: {
5398*03ce13f7SAndroid Build Coastguard Worker     static constexpr SizeT ExpectedNumElements = 4;
5399*03ce13f7SAndroid Build Coastguard Worker     assert(ExpectedNumElements == Instr->getNumIndexes());
5400*03ce13f7SAndroid Build Coastguard Worker     const SizeT Index0 = Instr->getIndexValue(0);
5401*03ce13f7SAndroid Build Coastguard Worker     const SizeT Index1 = Instr->getIndexValue(1);
5402*03ce13f7SAndroid Build Coastguard Worker     const SizeT Index2 = Instr->getIndexValue(2);
5403*03ce13f7SAndroid Build Coastguard Worker     const SizeT Index3 = Instr->getIndexValue(3);
5404*03ce13f7SAndroid Build Coastguard Worker     Variable *T = nullptr;
5405*03ce13f7SAndroid Build Coastguard Worker     switch (makeSrcSwitchMask(Index0, Index1, Index2, Index3)) {
5406*03ce13f7SAndroid Build Coastguard Worker #define CASE_SRCS_IN(S0, S1, S2, S3)                                           \
5407*03ce13f7SAndroid Build Coastguard Worker   case (((S0) << 0) | ((S1) << 1) | ((S2) << 2) | ((S3) << 3))
5408*03ce13f7SAndroid Build Coastguard Worker       CASE_SRCS_IN(0, 0, 0, 0) : {
5409*03ce13f7SAndroid Build Coastguard Worker         T = lowerShuffleVector_AllFromSameSrc(Src0, Index0, Index1, Index2,
5410*03ce13f7SAndroid Build Coastguard Worker                                               Index3);
5411*03ce13f7SAndroid Build Coastguard Worker       }
5412*03ce13f7SAndroid Build Coastguard Worker       break;
5413*03ce13f7SAndroid Build Coastguard Worker       CASE_SRCS_IN(0, 0, 0, 1) : {
5414*03ce13f7SAndroid Build Coastguard Worker         auto *Unified = lowerShuffleVector_UnifyFromDifferentSrcs(Src0, Index2,
5415*03ce13f7SAndroid Build Coastguard Worker                                                                   Src1, Index3);
5416*03ce13f7SAndroid Build Coastguard Worker         T = lowerShuffleVector_TwoFromSameSrc(Src0, Index0, Index1, Unified,
5417*03ce13f7SAndroid Build Coastguard Worker                                               UNIFIED_INDEX_0, UNIFIED_INDEX_1);
5418*03ce13f7SAndroid Build Coastguard Worker       }
5419*03ce13f7SAndroid Build Coastguard Worker       break;
5420*03ce13f7SAndroid Build Coastguard Worker       CASE_SRCS_IN(0, 0, 1, 0) : {
5421*03ce13f7SAndroid Build Coastguard Worker         auto *Unified = lowerShuffleVector_UnifyFromDifferentSrcs(Src1, Index2,
5422*03ce13f7SAndroid Build Coastguard Worker                                                                   Src0, Index3);
5423*03ce13f7SAndroid Build Coastguard Worker         T = lowerShuffleVector_TwoFromSameSrc(Src0, Index0, Index1, Unified,
5424*03ce13f7SAndroid Build Coastguard Worker                                               UNIFIED_INDEX_0, UNIFIED_INDEX_1);
5425*03ce13f7SAndroid Build Coastguard Worker       }
5426*03ce13f7SAndroid Build Coastguard Worker       break;
5427*03ce13f7SAndroid Build Coastguard Worker       CASE_SRCS_IN(0, 0, 1, 1) : {
5428*03ce13f7SAndroid Build Coastguard Worker         T = lowerShuffleVector_TwoFromSameSrc(Src0, Index0, Index1, Src1,
5429*03ce13f7SAndroid Build Coastguard Worker                                               Index2, Index3);
5430*03ce13f7SAndroid Build Coastguard Worker       }
5431*03ce13f7SAndroid Build Coastguard Worker       break;
5432*03ce13f7SAndroid Build Coastguard Worker       CASE_SRCS_IN(0, 1, 0, 0) : {
5433*03ce13f7SAndroid Build Coastguard Worker         auto *Unified = lowerShuffleVector_UnifyFromDifferentSrcs(Src0, Index0,
5434*03ce13f7SAndroid Build Coastguard Worker                                                                   Src1, Index1);
5435*03ce13f7SAndroid Build Coastguard Worker         T = lowerShuffleVector_TwoFromSameSrc(
5436*03ce13f7SAndroid Build Coastguard Worker             Unified, UNIFIED_INDEX_0, UNIFIED_INDEX_1, Src0, Index2, Index3);
5437*03ce13f7SAndroid Build Coastguard Worker       }
5438*03ce13f7SAndroid Build Coastguard Worker       break;
5439*03ce13f7SAndroid Build Coastguard Worker       CASE_SRCS_IN(0, 1, 0, 1) : {
5440*03ce13f7SAndroid Build Coastguard Worker         if (Index0 == 0 && (Index1 - ExpectedNumElements) == 0 && Index2 == 1 &&
5441*03ce13f7SAndroid Build Coastguard Worker             (Index3 - ExpectedNumElements) == 1) {
5442*03ce13f7SAndroid Build Coastguard Worker           auto *Src1RM = legalize(Src1, Legal_Reg | Legal_Mem);
5443*03ce13f7SAndroid Build Coastguard Worker           auto *Src0R = legalizeToReg(Src0);
5444*03ce13f7SAndroid Build Coastguard Worker           T = makeReg(DestTy);
5445*03ce13f7SAndroid Build Coastguard Worker           _movp(T, Src0R);
5446*03ce13f7SAndroid Build Coastguard Worker           _punpckl(T, Src1RM);
5447*03ce13f7SAndroid Build Coastguard Worker         } else if (Index0 == Index2 && Index1 == Index3) {
5448*03ce13f7SAndroid Build Coastguard Worker           auto *Unified = lowerShuffleVector_UnifyFromDifferentSrcs(
5449*03ce13f7SAndroid Build Coastguard Worker               Src0, Index0, Src1, Index1);
5450*03ce13f7SAndroid Build Coastguard Worker           T = lowerShuffleVector_AllFromSameSrc(
5451*03ce13f7SAndroid Build Coastguard Worker               Unified, UNIFIED_INDEX_0, UNIFIED_INDEX_1, UNIFIED_INDEX_0,
5452*03ce13f7SAndroid Build Coastguard Worker               UNIFIED_INDEX_1);
5453*03ce13f7SAndroid Build Coastguard Worker         } else {
5454*03ce13f7SAndroid Build Coastguard Worker           auto *Unified0 = lowerShuffleVector_UnifyFromDifferentSrcs(
5455*03ce13f7SAndroid Build Coastguard Worker               Src0, Index0, Src1, Index1);
5456*03ce13f7SAndroid Build Coastguard Worker           auto *Unified1 = lowerShuffleVector_UnifyFromDifferentSrcs(
5457*03ce13f7SAndroid Build Coastguard Worker               Src0, Index2, Src1, Index3);
5458*03ce13f7SAndroid Build Coastguard Worker           T = lowerShuffleVector_TwoFromSameSrc(
5459*03ce13f7SAndroid Build Coastguard Worker               Unified0, UNIFIED_INDEX_0, UNIFIED_INDEX_1, Unified1,
5460*03ce13f7SAndroid Build Coastguard Worker               UNIFIED_INDEX_0, UNIFIED_INDEX_1);
5461*03ce13f7SAndroid Build Coastguard Worker         }
5462*03ce13f7SAndroid Build Coastguard Worker       }
5463*03ce13f7SAndroid Build Coastguard Worker       break;
5464*03ce13f7SAndroid Build Coastguard Worker       CASE_SRCS_IN(0, 1, 1, 0) : {
5465*03ce13f7SAndroid Build Coastguard Worker         if (Index0 == Index3 && Index1 == Index2) {
5466*03ce13f7SAndroid Build Coastguard Worker           auto *Unified = lowerShuffleVector_UnifyFromDifferentSrcs(
5467*03ce13f7SAndroid Build Coastguard Worker               Src0, Index0, Src1, Index1);
5468*03ce13f7SAndroid Build Coastguard Worker           T = lowerShuffleVector_AllFromSameSrc(
5469*03ce13f7SAndroid Build Coastguard Worker               Unified, UNIFIED_INDEX_0, UNIFIED_INDEX_1, UNIFIED_INDEX_1,
5470*03ce13f7SAndroid Build Coastguard Worker               UNIFIED_INDEX_0);
5471*03ce13f7SAndroid Build Coastguard Worker         } else {
5472*03ce13f7SAndroid Build Coastguard Worker           auto *Unified0 = lowerShuffleVector_UnifyFromDifferentSrcs(
5473*03ce13f7SAndroid Build Coastguard Worker               Src0, Index0, Src1, Index1);
5474*03ce13f7SAndroid Build Coastguard Worker           auto *Unified1 = lowerShuffleVector_UnifyFromDifferentSrcs(
5475*03ce13f7SAndroid Build Coastguard Worker               Src1, Index2, Src0, Index3);
5476*03ce13f7SAndroid Build Coastguard Worker           T = lowerShuffleVector_TwoFromSameSrc(
5477*03ce13f7SAndroid Build Coastguard Worker               Unified0, UNIFIED_INDEX_0, UNIFIED_INDEX_1, Unified1,
5478*03ce13f7SAndroid Build Coastguard Worker               UNIFIED_INDEX_0, UNIFIED_INDEX_1);
5479*03ce13f7SAndroid Build Coastguard Worker         }
5480*03ce13f7SAndroid Build Coastguard Worker       }
5481*03ce13f7SAndroid Build Coastguard Worker       break;
5482*03ce13f7SAndroid Build Coastguard Worker       CASE_SRCS_IN(0, 1, 1, 1) : {
5483*03ce13f7SAndroid Build Coastguard Worker         auto *Unified = lowerShuffleVector_UnifyFromDifferentSrcs(Src0, Index0,
5484*03ce13f7SAndroid Build Coastguard Worker                                                                   Src1, Index1);
5485*03ce13f7SAndroid Build Coastguard Worker         T = lowerShuffleVector_TwoFromSameSrc(
5486*03ce13f7SAndroid Build Coastguard Worker             Unified, UNIFIED_INDEX_0, UNIFIED_INDEX_1, Src1, Index2, Index3);
5487*03ce13f7SAndroid Build Coastguard Worker       }
5488*03ce13f7SAndroid Build Coastguard Worker       break;
5489*03ce13f7SAndroid Build Coastguard Worker       CASE_SRCS_IN(1, 0, 0, 0) : {
5490*03ce13f7SAndroid Build Coastguard Worker         auto *Unified = lowerShuffleVector_UnifyFromDifferentSrcs(Src1, Index0,
5491*03ce13f7SAndroid Build Coastguard Worker                                                                   Src0, Index1);
5492*03ce13f7SAndroid Build Coastguard Worker         T = lowerShuffleVector_TwoFromSameSrc(
5493*03ce13f7SAndroid Build Coastguard Worker             Unified, UNIFIED_INDEX_0, UNIFIED_INDEX_1, Src0, Index2, Index3);
5494*03ce13f7SAndroid Build Coastguard Worker       }
5495*03ce13f7SAndroid Build Coastguard Worker       break;
5496*03ce13f7SAndroid Build Coastguard Worker       CASE_SRCS_IN(1, 0, 0, 1) : {
5497*03ce13f7SAndroid Build Coastguard Worker         if (Index0 == Index3 && Index1 == Index2) {
5498*03ce13f7SAndroid Build Coastguard Worker           auto *Unified = lowerShuffleVector_UnifyFromDifferentSrcs(
5499*03ce13f7SAndroid Build Coastguard Worker               Src1, Index0, Src0, Index1);
5500*03ce13f7SAndroid Build Coastguard Worker           T = lowerShuffleVector_AllFromSameSrc(
5501*03ce13f7SAndroid Build Coastguard Worker               Unified, UNIFIED_INDEX_0, UNIFIED_INDEX_1, UNIFIED_INDEX_1,
5502*03ce13f7SAndroid Build Coastguard Worker               UNIFIED_INDEX_0);
5503*03ce13f7SAndroid Build Coastguard Worker         } else {
5504*03ce13f7SAndroid Build Coastguard Worker           auto *Unified0 = lowerShuffleVector_UnifyFromDifferentSrcs(
5505*03ce13f7SAndroid Build Coastguard Worker               Src1, Index0, Src0, Index1);
5506*03ce13f7SAndroid Build Coastguard Worker           auto *Unified1 = lowerShuffleVector_UnifyFromDifferentSrcs(
5507*03ce13f7SAndroid Build Coastguard Worker               Src0, Index2, Src1, Index3);
5508*03ce13f7SAndroid Build Coastguard Worker           T = lowerShuffleVector_TwoFromSameSrc(
5509*03ce13f7SAndroid Build Coastguard Worker               Unified0, UNIFIED_INDEX_0, UNIFIED_INDEX_1, Unified1,
5510*03ce13f7SAndroid Build Coastguard Worker               UNIFIED_INDEX_0, UNIFIED_INDEX_1);
5511*03ce13f7SAndroid Build Coastguard Worker         }
5512*03ce13f7SAndroid Build Coastguard Worker       }
5513*03ce13f7SAndroid Build Coastguard Worker       break;
5514*03ce13f7SAndroid Build Coastguard Worker       CASE_SRCS_IN(1, 0, 1, 0) : {
5515*03ce13f7SAndroid Build Coastguard Worker         if ((Index0 - ExpectedNumElements) == 0 && Index1 == 0 &&
5516*03ce13f7SAndroid Build Coastguard Worker             (Index2 - ExpectedNumElements) == 1 && Index3 == 1) {
5517*03ce13f7SAndroid Build Coastguard Worker           auto *Src1RM = legalize(Src0, Legal_Reg | Legal_Mem);
5518*03ce13f7SAndroid Build Coastguard Worker           auto *Src0R = legalizeToReg(Src1);
5519*03ce13f7SAndroid Build Coastguard Worker           T = makeReg(DestTy);
5520*03ce13f7SAndroid Build Coastguard Worker           _movp(T, Src0R);
5521*03ce13f7SAndroid Build Coastguard Worker           _punpckl(T, Src1RM);
5522*03ce13f7SAndroid Build Coastguard Worker         } else if (Index0 == Index2 && Index1 == Index3) {
5523*03ce13f7SAndroid Build Coastguard Worker           auto *Unified = lowerShuffleVector_UnifyFromDifferentSrcs(
5524*03ce13f7SAndroid Build Coastguard Worker               Src1, Index0, Src0, Index1);
5525*03ce13f7SAndroid Build Coastguard Worker           T = lowerShuffleVector_AllFromSameSrc(
5526*03ce13f7SAndroid Build Coastguard Worker               Unified, UNIFIED_INDEX_0, UNIFIED_INDEX_1, UNIFIED_INDEX_0,
5527*03ce13f7SAndroid Build Coastguard Worker               UNIFIED_INDEX_1);
5528*03ce13f7SAndroid Build Coastguard Worker         } else {
5529*03ce13f7SAndroid Build Coastguard Worker           auto *Unified0 = lowerShuffleVector_UnifyFromDifferentSrcs(
5530*03ce13f7SAndroid Build Coastguard Worker               Src1, Index0, Src0, Index1);
5531*03ce13f7SAndroid Build Coastguard Worker           auto *Unified1 = lowerShuffleVector_UnifyFromDifferentSrcs(
5532*03ce13f7SAndroid Build Coastguard Worker               Src1, Index2, Src0, Index3);
5533*03ce13f7SAndroid Build Coastguard Worker           T = lowerShuffleVector_TwoFromSameSrc(
5534*03ce13f7SAndroid Build Coastguard Worker               Unified0, UNIFIED_INDEX_0, UNIFIED_INDEX_1, Unified1,
5535*03ce13f7SAndroid Build Coastguard Worker               UNIFIED_INDEX_0, UNIFIED_INDEX_1);
5536*03ce13f7SAndroid Build Coastguard Worker         }
5537*03ce13f7SAndroid Build Coastguard Worker       }
5538*03ce13f7SAndroid Build Coastguard Worker       break;
5539*03ce13f7SAndroid Build Coastguard Worker       CASE_SRCS_IN(1, 0, 1, 1) : {
5540*03ce13f7SAndroid Build Coastguard Worker         auto *Unified = lowerShuffleVector_UnifyFromDifferentSrcs(Src1, Index0,
5541*03ce13f7SAndroid Build Coastguard Worker                                                                   Src0, Index1);
5542*03ce13f7SAndroid Build Coastguard Worker         T = lowerShuffleVector_TwoFromSameSrc(
5543*03ce13f7SAndroid Build Coastguard Worker             Unified, UNIFIED_INDEX_0, UNIFIED_INDEX_1, Src1, Index2, Index3);
5544*03ce13f7SAndroid Build Coastguard Worker       }
5545*03ce13f7SAndroid Build Coastguard Worker       break;
5546*03ce13f7SAndroid Build Coastguard Worker       CASE_SRCS_IN(1, 1, 0, 0) : {
5547*03ce13f7SAndroid Build Coastguard Worker         T = lowerShuffleVector_TwoFromSameSrc(Src1, Index0, Index1, Src0,
5548*03ce13f7SAndroid Build Coastguard Worker                                               Index2, Index3);
5549*03ce13f7SAndroid Build Coastguard Worker       }
5550*03ce13f7SAndroid Build Coastguard Worker       break;
5551*03ce13f7SAndroid Build Coastguard Worker       CASE_SRCS_IN(1, 1, 0, 1) : {
5552*03ce13f7SAndroid Build Coastguard Worker         auto *Unified = lowerShuffleVector_UnifyFromDifferentSrcs(Src0, Index2,
5553*03ce13f7SAndroid Build Coastguard Worker                                                                   Src1, Index3);
5554*03ce13f7SAndroid Build Coastguard Worker         T = lowerShuffleVector_TwoFromSameSrc(Src1, Index0, Index1, Unified,
5555*03ce13f7SAndroid Build Coastguard Worker                                               UNIFIED_INDEX_0, UNIFIED_INDEX_1);
5556*03ce13f7SAndroid Build Coastguard Worker       }
5557*03ce13f7SAndroid Build Coastguard Worker       break;
5558*03ce13f7SAndroid Build Coastguard Worker       CASE_SRCS_IN(1, 1, 1, 0) : {
5559*03ce13f7SAndroid Build Coastguard Worker         auto *Unified = lowerShuffleVector_UnifyFromDifferentSrcs(Src1, Index2,
5560*03ce13f7SAndroid Build Coastguard Worker                                                                   Src0, Index3);
5561*03ce13f7SAndroid Build Coastguard Worker         T = lowerShuffleVector_TwoFromSameSrc(Src1, Index0, Index1, Unified,
5562*03ce13f7SAndroid Build Coastguard Worker                                               UNIFIED_INDEX_0, UNIFIED_INDEX_1);
5563*03ce13f7SAndroid Build Coastguard Worker       }
5564*03ce13f7SAndroid Build Coastguard Worker       break;
5565*03ce13f7SAndroid Build Coastguard Worker       CASE_SRCS_IN(1, 1, 1, 1) : {
5566*03ce13f7SAndroid Build Coastguard Worker         T = lowerShuffleVector_AllFromSameSrc(Src1, Index0, Index1, Index2,
5567*03ce13f7SAndroid Build Coastguard Worker                                               Index3);
5568*03ce13f7SAndroid Build Coastguard Worker       }
5569*03ce13f7SAndroid Build Coastguard Worker       break;
5570*03ce13f7SAndroid Build Coastguard Worker #undef CASE_SRCS_IN
5571*03ce13f7SAndroid Build Coastguard Worker     }
5572*03ce13f7SAndroid Build Coastguard Worker 
5573*03ce13f7SAndroid Build Coastguard Worker     assert(T != nullptr);
5574*03ce13f7SAndroid Build Coastguard Worker     assert(T->getType() == DestTy);
5575*03ce13f7SAndroid Build Coastguard Worker     _movp(Dest, T);
5576*03ce13f7SAndroid Build Coastguard Worker     return;
5577*03ce13f7SAndroid Build Coastguard Worker   } break;
5578*03ce13f7SAndroid Build Coastguard Worker   }
5579*03ce13f7SAndroid Build Coastguard Worker 
5580*03ce13f7SAndroid Build Coastguard Worker   // Unoptimized shuffle. Perform a series of inserts and extracts.
5581*03ce13f7SAndroid Build Coastguard Worker   Context.insert<InstFakeDef>(T);
5582*03ce13f7SAndroid Build Coastguard Worker   const Type ElementType = typeElementType(DestTy);
5583*03ce13f7SAndroid Build Coastguard Worker   for (SizeT I = 0; I < Instr->getNumIndexes(); ++I) {
5584*03ce13f7SAndroid Build Coastguard Worker     auto *Index = Instr->getIndex(I);
5585*03ce13f7SAndroid Build Coastguard Worker     const SizeT Elem = Index->getValue();
5586*03ce13f7SAndroid Build Coastguard Worker     auto *ExtElmt = makeReg(ElementType);
5587*03ce13f7SAndroid Build Coastguard Worker     if (Elem < NumElements) {
5588*03ce13f7SAndroid Build Coastguard Worker       lowerExtractElement(
5589*03ce13f7SAndroid Build Coastguard Worker           InstExtractElement::create(Func, ExtElmt, Src0, Index));
5590*03ce13f7SAndroid Build Coastguard Worker     } else {
5591*03ce13f7SAndroid Build Coastguard Worker       lowerExtractElement(InstExtractElement::create(
5592*03ce13f7SAndroid Build Coastguard Worker           Func, ExtElmt, Src1, Ctx->getConstantInt32(Elem - NumElements)));
5593*03ce13f7SAndroid Build Coastguard Worker     }
5594*03ce13f7SAndroid Build Coastguard Worker     auto *NewT = makeReg(DestTy);
5595*03ce13f7SAndroid Build Coastguard Worker     lowerInsertElement(InstInsertElement::create(Func, NewT, T, ExtElmt,
5596*03ce13f7SAndroid Build Coastguard Worker                                                  Ctx->getConstantInt32(I)));
5597*03ce13f7SAndroid Build Coastguard Worker     T = NewT;
5598*03ce13f7SAndroid Build Coastguard Worker   }
5599*03ce13f7SAndroid Build Coastguard Worker   _movp(Dest, T);
5600*03ce13f7SAndroid Build Coastguard Worker }
5601*03ce13f7SAndroid Build Coastguard Worker 
lowerSelect(const InstSelect * Select)5602*03ce13f7SAndroid Build Coastguard Worker void TargetX8664::lowerSelect(const InstSelect *Select) {
5603*03ce13f7SAndroid Build Coastguard Worker   Variable *Dest = Select->getDest();
5604*03ce13f7SAndroid Build Coastguard Worker 
5605*03ce13f7SAndroid Build Coastguard Worker   Operand *Condition = Select->getCondition();
5606*03ce13f7SAndroid Build Coastguard Worker   // Handle folding opportunities.
5607*03ce13f7SAndroid Build Coastguard Worker   if (const Inst *Producer = FoldingInfo.getProducerFor(Condition)) {
5608*03ce13f7SAndroid Build Coastguard Worker     assert(Producer->isDeleted());
5609*03ce13f7SAndroid Build Coastguard Worker     switch (BoolFolding::getProducerKind(Producer)) {
5610*03ce13f7SAndroid Build Coastguard Worker     default:
5611*03ce13f7SAndroid Build Coastguard Worker       break;
5612*03ce13f7SAndroid Build Coastguard Worker     case BoolFolding::PK_Icmp32:
5613*03ce13f7SAndroid Build Coastguard Worker     case BoolFolding::PK_Icmp64: {
5614*03ce13f7SAndroid Build Coastguard Worker       lowerIcmpAndConsumer(llvm::cast<InstIcmp>(Producer), Select);
5615*03ce13f7SAndroid Build Coastguard Worker       return;
5616*03ce13f7SAndroid Build Coastguard Worker     }
5617*03ce13f7SAndroid Build Coastguard Worker     case BoolFolding::PK_Fcmp: {
5618*03ce13f7SAndroid Build Coastguard Worker       lowerFcmpAndConsumer(llvm::cast<InstFcmp>(Producer), Select);
5619*03ce13f7SAndroid Build Coastguard Worker       return;
5620*03ce13f7SAndroid Build Coastguard Worker     }
5621*03ce13f7SAndroid Build Coastguard Worker     }
5622*03ce13f7SAndroid Build Coastguard Worker   }
5623*03ce13f7SAndroid Build Coastguard Worker 
5624*03ce13f7SAndroid Build Coastguard Worker   if (isVectorType(Dest->getType())) {
5625*03ce13f7SAndroid Build Coastguard Worker     lowerSelectVector(Select);
5626*03ce13f7SAndroid Build Coastguard Worker     return;
5627*03ce13f7SAndroid Build Coastguard Worker   }
5628*03ce13f7SAndroid Build Coastguard Worker 
5629*03ce13f7SAndroid Build Coastguard Worker   Operand *CmpResult = legalize(Condition, Legal_Reg | Legal_Mem);
5630*03ce13f7SAndroid Build Coastguard Worker   Operand *Zero = Ctx->getConstantZero(IceType_i32);
5631*03ce13f7SAndroid Build Coastguard Worker   _cmp(CmpResult, Zero);
5632*03ce13f7SAndroid Build Coastguard Worker   Operand *SrcT = Select->getTrueOperand();
5633*03ce13f7SAndroid Build Coastguard Worker   Operand *SrcF = Select->getFalseOperand();
5634*03ce13f7SAndroid Build Coastguard Worker   const BrCond Cond = CondX86::Br_ne;
5635*03ce13f7SAndroid Build Coastguard Worker   lowerSelectMove(Dest, Cond, SrcT, SrcF);
5636*03ce13f7SAndroid Build Coastguard Worker }
5637*03ce13f7SAndroid Build Coastguard Worker 
lowerSelectMove(Variable * Dest,BrCond Cond,Operand * SrcT,Operand * SrcF)5638*03ce13f7SAndroid Build Coastguard Worker void TargetX8664::lowerSelectMove(Variable *Dest, BrCond Cond, Operand *SrcT,
5639*03ce13f7SAndroid Build Coastguard Worker                                   Operand *SrcF) {
5640*03ce13f7SAndroid Build Coastguard Worker   Type DestTy = Dest->getType();
5641*03ce13f7SAndroid Build Coastguard Worker   if (typeWidthInBytes(DestTy) == 1 || isFloatingType(DestTy)) {
5642*03ce13f7SAndroid Build Coastguard Worker     // The cmov instruction doesn't allow 8-bit or FP operands, so we need
5643*03ce13f7SAndroid Build Coastguard Worker     // explicit control flow.
5644*03ce13f7SAndroid Build Coastguard Worker     // d=cmp e,f; a=d?b:c ==> cmp e,f; a=b; jne L1; a=c; L1:
5645*03ce13f7SAndroid Build Coastguard Worker     auto *Label = InstX86Label::create(Func, this);
5646*03ce13f7SAndroid Build Coastguard Worker     SrcT = legalize(SrcT, Legal_Reg | Legal_Imm);
5647*03ce13f7SAndroid Build Coastguard Worker     _mov(Dest, SrcT);
5648*03ce13f7SAndroid Build Coastguard Worker     _br(Cond, Label);
5649*03ce13f7SAndroid Build Coastguard Worker     SrcF = legalize(SrcF, Legal_Reg | Legal_Imm);
5650*03ce13f7SAndroid Build Coastguard Worker     _redefined(_mov(Dest, SrcF));
5651*03ce13f7SAndroid Build Coastguard Worker     Context.insert(Label);
5652*03ce13f7SAndroid Build Coastguard Worker     return;
5653*03ce13f7SAndroid Build Coastguard Worker   }
5654*03ce13f7SAndroid Build Coastguard Worker   // mov t, SrcF; cmov_cond t, SrcT; mov dest, t
5655*03ce13f7SAndroid Build Coastguard Worker   // But if SrcT is immediate, we might be able to do better, as the cmov
5656*03ce13f7SAndroid Build Coastguard Worker   // instruction doesn't allow an immediate operand:
5657*03ce13f7SAndroid Build Coastguard Worker   // mov t, SrcT; cmov_!cond t, SrcF; mov dest, t
5658*03ce13f7SAndroid Build Coastguard Worker   if (llvm::isa<Constant>(SrcT) && !llvm::isa<Constant>(SrcF)) {
5659*03ce13f7SAndroid Build Coastguard Worker     std::swap(SrcT, SrcF);
5660*03ce13f7SAndroid Build Coastguard Worker     Cond = InstX86Base::getOppositeCondition(Cond);
5661*03ce13f7SAndroid Build Coastguard Worker   }
5662*03ce13f7SAndroid Build Coastguard Worker 
5663*03ce13f7SAndroid Build Coastguard Worker   assert(DestTy == IceType_i16 || DestTy == IceType_i32 ||
5664*03ce13f7SAndroid Build Coastguard Worker          DestTy == IceType_i64);
5665*03ce13f7SAndroid Build Coastguard Worker   lowerSelectIntMove(Dest, Cond, SrcT, SrcF);
5666*03ce13f7SAndroid Build Coastguard Worker }
5667*03ce13f7SAndroid Build Coastguard Worker 
lowerSelectIntMove(Variable * Dest,BrCond Cond,Operand * SrcT,Operand * SrcF)5668*03ce13f7SAndroid Build Coastguard Worker void TargetX8664::lowerSelectIntMove(Variable *Dest, BrCond Cond, Operand *SrcT,
5669*03ce13f7SAndroid Build Coastguard Worker                                      Operand *SrcF) {
5670*03ce13f7SAndroid Build Coastguard Worker   Variable *T = nullptr;
5671*03ce13f7SAndroid Build Coastguard Worker   SrcF = legalize(SrcF);
5672*03ce13f7SAndroid Build Coastguard Worker   _mov(T, SrcF);
5673*03ce13f7SAndroid Build Coastguard Worker   SrcT = legalize(SrcT, Legal_Reg | Legal_Mem);
5674*03ce13f7SAndroid Build Coastguard Worker   _cmov(T, SrcT, Cond);
5675*03ce13f7SAndroid Build Coastguard Worker   _mov(Dest, T);
5676*03ce13f7SAndroid Build Coastguard Worker }
5677*03ce13f7SAndroid Build Coastguard Worker 
lowerMove(Variable * Dest,Operand * Src,bool IsRedefinition)5678*03ce13f7SAndroid Build Coastguard Worker void TargetX8664::lowerMove(Variable *Dest, Operand *Src, bool IsRedefinition) {
5679*03ce13f7SAndroid Build Coastguard Worker   assert(Dest->getType() == Src->getType());
5680*03ce13f7SAndroid Build Coastguard Worker   assert(!Dest->isRematerializable());
5681*03ce13f7SAndroid Build Coastguard Worker   Operand *SrcLegal;
5682*03ce13f7SAndroid Build Coastguard Worker   if (Dest->hasReg()) {
5683*03ce13f7SAndroid Build Coastguard Worker     // If Dest already has a physical register, then only basic legalization
5684*03ce13f7SAndroid Build Coastguard Worker     // is needed, as the source operand can be a register, immediate, or
5685*03ce13f7SAndroid Build Coastguard Worker     // memory.
5686*03ce13f7SAndroid Build Coastguard Worker     SrcLegal = legalize(Src, Legal_Reg, Dest->getRegNum());
5687*03ce13f7SAndroid Build Coastguard Worker   } else {
5688*03ce13f7SAndroid Build Coastguard Worker     // If Dest could be a stack operand, then RI must be a physical register
5689*03ce13f7SAndroid Build Coastguard Worker     // or a scalar integer immediate.
5690*03ce13f7SAndroid Build Coastguard Worker     SrcLegal = legalize(Src, Legal_Reg | Legal_Imm);
5691*03ce13f7SAndroid Build Coastguard Worker   }
5692*03ce13f7SAndroid Build Coastguard Worker   if (isVectorType(Dest->getType())) {
5693*03ce13f7SAndroid Build Coastguard Worker     _redefined(_movp(Dest, SrcLegal), IsRedefinition);
5694*03ce13f7SAndroid Build Coastguard Worker   } else {
5695*03ce13f7SAndroid Build Coastguard Worker     _redefined(_mov(Dest, SrcLegal), IsRedefinition);
5696*03ce13f7SAndroid Build Coastguard Worker   }
5697*03ce13f7SAndroid Build Coastguard Worker }
5698*03ce13f7SAndroid Build Coastguard Worker 
lowerOptimizeFcmpSelect(const InstFcmp * Fcmp,const InstSelect * Select)5699*03ce13f7SAndroid Build Coastguard Worker bool TargetX8664::lowerOptimizeFcmpSelect(const InstFcmp *Fcmp,
5700*03ce13f7SAndroid Build Coastguard Worker                                           const InstSelect *Select) {
5701*03ce13f7SAndroid Build Coastguard Worker   Operand *CmpSrc0 = Fcmp->getSrc(0);
5702*03ce13f7SAndroid Build Coastguard Worker   Operand *CmpSrc1 = Fcmp->getSrc(1);
5703*03ce13f7SAndroid Build Coastguard Worker   Operand *SelectSrcT = Select->getTrueOperand();
5704*03ce13f7SAndroid Build Coastguard Worker   Operand *SelectSrcF = Select->getFalseOperand();
5705*03ce13f7SAndroid Build Coastguard Worker   Variable *SelectDest = Select->getDest();
5706*03ce13f7SAndroid Build Coastguard Worker 
5707*03ce13f7SAndroid Build Coastguard Worker   // TODO(capn): also handle swapped compare/select operand order.
5708*03ce13f7SAndroid Build Coastguard Worker   if (CmpSrc0 != SelectSrcT || CmpSrc1 != SelectSrcF)
5709*03ce13f7SAndroid Build Coastguard Worker     return false;
5710*03ce13f7SAndroid Build Coastguard Worker 
5711*03ce13f7SAndroid Build Coastguard Worker   // TODO(sehr, stichnot): fcmp/select patterns (e.g., minsd/maxss) go here.
5712*03ce13f7SAndroid Build Coastguard Worker   InstFcmp::FCond Condition = Fcmp->getCondition();
5713*03ce13f7SAndroid Build Coastguard Worker   switch (Condition) {
5714*03ce13f7SAndroid Build Coastguard Worker   default:
5715*03ce13f7SAndroid Build Coastguard Worker     return false;
5716*03ce13f7SAndroid Build Coastguard Worker   case InstFcmp::True:
5717*03ce13f7SAndroid Build Coastguard Worker     break;
5718*03ce13f7SAndroid Build Coastguard Worker   case InstFcmp::False:
5719*03ce13f7SAndroid Build Coastguard Worker     break;
5720*03ce13f7SAndroid Build Coastguard Worker   case InstFcmp::Ogt: {
5721*03ce13f7SAndroid Build Coastguard Worker     Variable *T = makeReg(SelectDest->getType());
5722*03ce13f7SAndroid Build Coastguard Worker     if (isScalarFloatingType(SelectSrcT->getType())) {
5723*03ce13f7SAndroid Build Coastguard Worker       _mov(T, legalize(SelectSrcT, Legal_Reg | Legal_Mem));
5724*03ce13f7SAndroid Build Coastguard Worker       _maxss(T, legalize(SelectSrcF, Legal_Reg | Legal_Mem));
5725*03ce13f7SAndroid Build Coastguard Worker       _mov(SelectDest, T);
5726*03ce13f7SAndroid Build Coastguard Worker     } else {
5727*03ce13f7SAndroid Build Coastguard Worker       _movp(T, legalize(SelectSrcT, Legal_Reg | Legal_Mem));
5728*03ce13f7SAndroid Build Coastguard Worker       _maxps(T, legalize(SelectSrcF, Legal_Reg | Legal_Mem));
5729*03ce13f7SAndroid Build Coastguard Worker       _movp(SelectDest, T);
5730*03ce13f7SAndroid Build Coastguard Worker     }
5731*03ce13f7SAndroid Build Coastguard Worker     return true;
5732*03ce13f7SAndroid Build Coastguard Worker   } break;
5733*03ce13f7SAndroid Build Coastguard Worker   case InstFcmp::Olt: {
5734*03ce13f7SAndroid Build Coastguard Worker     Variable *T = makeReg(SelectSrcT->getType());
5735*03ce13f7SAndroid Build Coastguard Worker     if (isScalarFloatingType(SelectSrcT->getType())) {
5736*03ce13f7SAndroid Build Coastguard Worker       _mov(T, legalize(SelectSrcT, Legal_Reg | Legal_Mem));
5737*03ce13f7SAndroid Build Coastguard Worker       _minss(T, legalize(SelectSrcF, Legal_Reg | Legal_Mem));
5738*03ce13f7SAndroid Build Coastguard Worker       _mov(SelectDest, T);
5739*03ce13f7SAndroid Build Coastguard Worker     } else {
5740*03ce13f7SAndroid Build Coastguard Worker       _movp(T, legalize(SelectSrcT, Legal_Reg | Legal_Mem));
5741*03ce13f7SAndroid Build Coastguard Worker       _minps(T, legalize(SelectSrcF, Legal_Reg | Legal_Mem));
5742*03ce13f7SAndroid Build Coastguard Worker       _movp(SelectDest, T);
5743*03ce13f7SAndroid Build Coastguard Worker     }
5744*03ce13f7SAndroid Build Coastguard Worker     return true;
5745*03ce13f7SAndroid Build Coastguard Worker   } break;
5746*03ce13f7SAndroid Build Coastguard Worker   }
5747*03ce13f7SAndroid Build Coastguard Worker   return false;
5748*03ce13f7SAndroid Build Coastguard Worker }
5749*03ce13f7SAndroid Build Coastguard Worker 
lowerIcmp(const InstIcmp * Icmp)5750*03ce13f7SAndroid Build Coastguard Worker void TargetX8664::lowerIcmp(const InstIcmp *Icmp) {
5751*03ce13f7SAndroid Build Coastguard Worker   Variable *Dest = Icmp->getDest();
5752*03ce13f7SAndroid Build Coastguard Worker   if (isVectorType(Dest->getType())) {
5753*03ce13f7SAndroid Build Coastguard Worker     lowerIcmpVector(Icmp);
5754*03ce13f7SAndroid Build Coastguard Worker   } else {
5755*03ce13f7SAndroid Build Coastguard Worker     constexpr Inst *Consumer = nullptr;
5756*03ce13f7SAndroid Build Coastguard Worker     lowerIcmpAndConsumer(Icmp, Consumer);
5757*03ce13f7SAndroid Build Coastguard Worker   }
5758*03ce13f7SAndroid Build Coastguard Worker }
5759*03ce13f7SAndroid Build Coastguard Worker 
lowerSelectVector(const InstSelect * Instr)5760*03ce13f7SAndroid Build Coastguard Worker void TargetX8664::lowerSelectVector(const InstSelect *Instr) {
5761*03ce13f7SAndroid Build Coastguard Worker   Variable *Dest = Instr->getDest();
5762*03ce13f7SAndroid Build Coastguard Worker   Type DestTy = Dest->getType();
5763*03ce13f7SAndroid Build Coastguard Worker   Operand *SrcT = Instr->getTrueOperand();
5764*03ce13f7SAndroid Build Coastguard Worker   Operand *SrcF = Instr->getFalseOperand();
5765*03ce13f7SAndroid Build Coastguard Worker   Operand *Condition = Instr->getCondition();
5766*03ce13f7SAndroid Build Coastguard Worker 
5767*03ce13f7SAndroid Build Coastguard Worker   if (!isVectorType(DestTy))
5768*03ce13f7SAndroid Build Coastguard Worker     llvm::report_fatal_error("Expected a vector select");
5769*03ce13f7SAndroid Build Coastguard Worker 
5770*03ce13f7SAndroid Build Coastguard Worker   Type SrcTy = SrcT->getType();
5771*03ce13f7SAndroid Build Coastguard Worker   Variable *T = makeReg(SrcTy);
5772*03ce13f7SAndroid Build Coastguard Worker   Operand *SrcTRM = legalize(SrcT, Legal_Reg | Legal_Mem);
5773*03ce13f7SAndroid Build Coastguard Worker   Operand *SrcFRM = legalize(SrcF, Legal_Reg | Legal_Mem);
5774*03ce13f7SAndroid Build Coastguard Worker 
5775*03ce13f7SAndroid Build Coastguard Worker   if (InstructionSet >= SSE4_1) {
5776*03ce13f7SAndroid Build Coastguard Worker     // TODO(wala): If the condition operand is a constant, use blendps or
5777*03ce13f7SAndroid Build Coastguard Worker     // pblendw.
5778*03ce13f7SAndroid Build Coastguard Worker     //
5779*03ce13f7SAndroid Build Coastguard Worker     // Use blendvps or pblendvb to implement select.
5780*03ce13f7SAndroid Build Coastguard Worker     if (SrcTy == IceType_v4i1 || SrcTy == IceType_v4i32 ||
5781*03ce13f7SAndroid Build Coastguard Worker         SrcTy == IceType_v4f32) {
5782*03ce13f7SAndroid Build Coastguard Worker       Operand *ConditionRM = legalize(Condition, Legal_Reg | Legal_Mem);
5783*03ce13f7SAndroid Build Coastguard Worker       Variable *xmm0 = makeReg(IceType_v4i32, RegX8664::Reg_xmm0);
5784*03ce13f7SAndroid Build Coastguard Worker       _movp(xmm0, ConditionRM);
5785*03ce13f7SAndroid Build Coastguard Worker       _psll(xmm0, Ctx->getConstantInt8(31));
5786*03ce13f7SAndroid Build Coastguard Worker       _movp(T, SrcFRM);
5787*03ce13f7SAndroid Build Coastguard Worker       _blendvps(T, SrcTRM, xmm0);
5788*03ce13f7SAndroid Build Coastguard Worker       _movp(Dest, T);
5789*03ce13f7SAndroid Build Coastguard Worker     } else {
5790*03ce13f7SAndroid Build Coastguard Worker       assert(typeNumElements(SrcTy) == 8 || typeNumElements(SrcTy) == 16);
5791*03ce13f7SAndroid Build Coastguard Worker       Type SignExtTy =
5792*03ce13f7SAndroid Build Coastguard Worker           Condition->getType() == IceType_v8i1 ? IceType_v8i16 : IceType_v16i8;
5793*03ce13f7SAndroid Build Coastguard Worker       Variable *xmm0 = makeReg(SignExtTy, RegX8664::Reg_xmm0);
5794*03ce13f7SAndroid Build Coastguard Worker       lowerCast(InstCast::create(Func, InstCast::Sext, xmm0, Condition));
5795*03ce13f7SAndroid Build Coastguard Worker       _movp(T, SrcFRM);
5796*03ce13f7SAndroid Build Coastguard Worker       _pblendvb(T, SrcTRM, xmm0);
5797*03ce13f7SAndroid Build Coastguard Worker       _movp(Dest, T);
5798*03ce13f7SAndroid Build Coastguard Worker     }
5799*03ce13f7SAndroid Build Coastguard Worker     return;
5800*03ce13f7SAndroid Build Coastguard Worker   }
5801*03ce13f7SAndroid Build Coastguard Worker   // Lower select without SSE4.1:
5802*03ce13f7SAndroid Build Coastguard Worker   // a=d?b:c ==>
5803*03ce13f7SAndroid Build Coastguard Worker   //   if elementtype(d) != i1:
5804*03ce13f7SAndroid Build Coastguard Worker   //      d=sext(d);
5805*03ce13f7SAndroid Build Coastguard Worker   //   a=(b&d)|(c&~d);
5806*03ce13f7SAndroid Build Coastguard Worker   Variable *T2 = makeReg(SrcTy);
5807*03ce13f7SAndroid Build Coastguard Worker   // Sign extend the condition operand if applicable.
5808*03ce13f7SAndroid Build Coastguard Worker   if (SrcTy == IceType_v4f32) {
5809*03ce13f7SAndroid Build Coastguard Worker     // The sext operation takes only integer arguments.
5810*03ce13f7SAndroid Build Coastguard Worker     Variable *T3 = Func->makeVariable(IceType_v4i32);
5811*03ce13f7SAndroid Build Coastguard Worker     lowerCast(InstCast::create(Func, InstCast::Sext, T3, Condition));
5812*03ce13f7SAndroid Build Coastguard Worker     _movp(T, T3);
5813*03ce13f7SAndroid Build Coastguard Worker   } else if (typeElementType(SrcTy) != IceType_i1) {
5814*03ce13f7SAndroid Build Coastguard Worker     lowerCast(InstCast::create(Func, InstCast::Sext, T, Condition));
5815*03ce13f7SAndroid Build Coastguard Worker   } else {
5816*03ce13f7SAndroid Build Coastguard Worker     Operand *ConditionRM = legalize(Condition, Legal_Reg | Legal_Mem);
5817*03ce13f7SAndroid Build Coastguard Worker     _movp(T, ConditionRM);
5818*03ce13f7SAndroid Build Coastguard Worker   }
5819*03ce13f7SAndroid Build Coastguard Worker   _movp(T2, T);
5820*03ce13f7SAndroid Build Coastguard Worker   _pand(T, SrcTRM);
5821*03ce13f7SAndroid Build Coastguard Worker   _pandn(T2, SrcFRM);
5822*03ce13f7SAndroid Build Coastguard Worker   _por(T, T2);
5823*03ce13f7SAndroid Build Coastguard Worker   _movp(Dest, T);
5824*03ce13f7SAndroid Build Coastguard Worker 
5825*03ce13f7SAndroid Build Coastguard Worker   return;
5826*03ce13f7SAndroid Build Coastguard Worker }
5827*03ce13f7SAndroid Build Coastguard Worker 
lowerStore(const InstStore * Instr)5828*03ce13f7SAndroid Build Coastguard Worker void TargetX8664::lowerStore(const InstStore *Instr) {
5829*03ce13f7SAndroid Build Coastguard Worker   Operand *Value = Instr->getData();
5830*03ce13f7SAndroid Build Coastguard Worker   Operand *Addr = Instr->getStoreAddress();
5831*03ce13f7SAndroid Build Coastguard Worker   X86OperandMem *NewAddr = formMemoryOperand(Addr, Value->getType());
5832*03ce13f7SAndroid Build Coastguard Worker   doMockBoundsCheck(NewAddr);
5833*03ce13f7SAndroid Build Coastguard Worker   Type Ty = NewAddr->getType();
5834*03ce13f7SAndroid Build Coastguard Worker 
5835*03ce13f7SAndroid Build Coastguard Worker   if (isVectorType(Ty)) {
5836*03ce13f7SAndroid Build Coastguard Worker     _storep(legalizeToReg(Value), NewAddr);
5837*03ce13f7SAndroid Build Coastguard Worker   } else {
5838*03ce13f7SAndroid Build Coastguard Worker     Value = legalize(Value, Legal_Reg | Legal_Imm);
5839*03ce13f7SAndroid Build Coastguard Worker     _store(Value, NewAddr);
5840*03ce13f7SAndroid Build Coastguard Worker   }
5841*03ce13f7SAndroid Build Coastguard Worker }
5842*03ce13f7SAndroid Build Coastguard Worker 
doAddressOptStore()5843*03ce13f7SAndroid Build Coastguard Worker void TargetX8664::doAddressOptStore() {
5844*03ce13f7SAndroid Build Coastguard Worker   auto *Instr = llvm::cast<InstStore>(Context.getCur());
5845*03ce13f7SAndroid Build Coastguard Worker   Operand *Addr = Instr->getStoreAddress();
5846*03ce13f7SAndroid Build Coastguard Worker   Operand *Data = Instr->getData();
5847*03ce13f7SAndroid Build Coastguard Worker   if (auto *OptAddr = computeAddressOpt(Instr, Data->getType(), Addr)) {
5848*03ce13f7SAndroid Build Coastguard Worker     Instr->setDeleted();
5849*03ce13f7SAndroid Build Coastguard Worker     auto *NewStore = Context.insert<InstStore>(Data, OptAddr);
5850*03ce13f7SAndroid Build Coastguard Worker     if (Instr->getDest())
5851*03ce13f7SAndroid Build Coastguard Worker       NewStore->setRmwBeacon(Instr->getRmwBeacon());
5852*03ce13f7SAndroid Build Coastguard Worker   }
5853*03ce13f7SAndroid Build Coastguard Worker }
5854*03ce13f7SAndroid Build Coastguard Worker 
doAddressOptStoreSubVector()5855*03ce13f7SAndroid Build Coastguard Worker void TargetX8664::doAddressOptStoreSubVector() {
5856*03ce13f7SAndroid Build Coastguard Worker   auto *Intrinsic = llvm::cast<InstIntrinsic>(Context.getCur());
5857*03ce13f7SAndroid Build Coastguard Worker   Operand *Addr = Intrinsic->getArg(1);
5858*03ce13f7SAndroid Build Coastguard Worker   Operand *Data = Intrinsic->getArg(0);
5859*03ce13f7SAndroid Build Coastguard Worker   if (auto *OptAddr = computeAddressOpt(Intrinsic, Data->getType(), Addr)) {
5860*03ce13f7SAndroid Build Coastguard Worker     Intrinsic->setDeleted();
5861*03ce13f7SAndroid Build Coastguard Worker     const Ice::Intrinsics::IntrinsicInfo Info = {
5862*03ce13f7SAndroid Build Coastguard Worker         Ice::Intrinsics::StoreSubVector, Ice::Intrinsics::SideEffects_T,
5863*03ce13f7SAndroid Build Coastguard Worker         Ice::Intrinsics::ReturnsTwice_F, Ice::Intrinsics::MemoryWrite_T};
5864*03ce13f7SAndroid Build Coastguard Worker     auto *NewStore = Context.insert<InstIntrinsic>(3, nullptr, Info);
5865*03ce13f7SAndroid Build Coastguard Worker     NewStore->addArg(Data);
5866*03ce13f7SAndroid Build Coastguard Worker     NewStore->addArg(OptAddr);
5867*03ce13f7SAndroid Build Coastguard Worker     NewStore->addArg(Intrinsic->getArg(2));
5868*03ce13f7SAndroid Build Coastguard Worker   }
5869*03ce13f7SAndroid Build Coastguard Worker }
5870*03ce13f7SAndroid Build Coastguard Worker 
lowerCmpRange(Operand * Comparison,uint64_t Min,uint64_t Max)5871*03ce13f7SAndroid Build Coastguard Worker Operand *TargetX8664::lowerCmpRange(Operand *Comparison, uint64_t Min,
5872*03ce13f7SAndroid Build Coastguard Worker                                     uint64_t Max) {
5873*03ce13f7SAndroid Build Coastguard Worker   // Subtracting 0 is a nop so don't do it
5874*03ce13f7SAndroid Build Coastguard Worker   if (Min != 0) {
5875*03ce13f7SAndroid Build Coastguard Worker     // Avoid clobbering the comparison by copying it
5876*03ce13f7SAndroid Build Coastguard Worker     Variable *T = nullptr;
5877*03ce13f7SAndroid Build Coastguard Worker     _mov(T, Comparison);
5878*03ce13f7SAndroid Build Coastguard Worker     _sub(T, Ctx->getConstantInt32(Min));
5879*03ce13f7SAndroid Build Coastguard Worker     Comparison = T;
5880*03ce13f7SAndroid Build Coastguard Worker   }
5881*03ce13f7SAndroid Build Coastguard Worker 
5882*03ce13f7SAndroid Build Coastguard Worker   _cmp(Comparison, Ctx->getConstantInt32(Max - Min));
5883*03ce13f7SAndroid Build Coastguard Worker 
5884*03ce13f7SAndroid Build Coastguard Worker   return Comparison;
5885*03ce13f7SAndroid Build Coastguard Worker }
5886*03ce13f7SAndroid Build Coastguard Worker 
lowerCaseCluster(const CaseCluster & Case,Operand * Comparison,bool DoneCmp,CfgNode * DefaultTarget)5887*03ce13f7SAndroid Build Coastguard Worker void TargetX8664::lowerCaseCluster(const CaseCluster &Case, Operand *Comparison,
5888*03ce13f7SAndroid Build Coastguard Worker                                    bool DoneCmp, CfgNode *DefaultTarget) {
5889*03ce13f7SAndroid Build Coastguard Worker   switch (Case.getKind()) {
5890*03ce13f7SAndroid Build Coastguard Worker   case CaseCluster::JumpTable: {
5891*03ce13f7SAndroid Build Coastguard Worker     InstX86Label *SkipJumpTable;
5892*03ce13f7SAndroid Build Coastguard Worker 
5893*03ce13f7SAndroid Build Coastguard Worker     Operand *RangeIndex =
5894*03ce13f7SAndroid Build Coastguard Worker         lowerCmpRange(Comparison, Case.getLow(), Case.getHigh());
5895*03ce13f7SAndroid Build Coastguard Worker     if (DefaultTarget == nullptr) {
5896*03ce13f7SAndroid Build Coastguard Worker       // Skip over jump table logic if comparison not in range and no default
5897*03ce13f7SAndroid Build Coastguard Worker       SkipJumpTable = InstX86Label::create(Func, this);
5898*03ce13f7SAndroid Build Coastguard Worker       _br(CondX86::Br_a, SkipJumpTable);
5899*03ce13f7SAndroid Build Coastguard Worker     } else {
5900*03ce13f7SAndroid Build Coastguard Worker       _br(CondX86::Br_a, DefaultTarget);
5901*03ce13f7SAndroid Build Coastguard Worker     }
5902*03ce13f7SAndroid Build Coastguard Worker 
5903*03ce13f7SAndroid Build Coastguard Worker     InstJumpTable *JumpTable = Case.getJumpTable();
5904*03ce13f7SAndroid Build Coastguard Worker     Context.insert(JumpTable);
5905*03ce13f7SAndroid Build Coastguard Worker 
5906*03ce13f7SAndroid Build Coastguard Worker     // Make sure the index is a register of the same width as the base
5907*03ce13f7SAndroid Build Coastguard Worker     Variable *Index;
5908*03ce13f7SAndroid Build Coastguard Worker     const Type PointerType = getPointerType();
5909*03ce13f7SAndroid Build Coastguard Worker     if (RangeIndex->getType() != PointerType) {
5910*03ce13f7SAndroid Build Coastguard Worker       Index = makeReg(PointerType);
5911*03ce13f7SAndroid Build Coastguard Worker       if (RangeIndex->getType() == IceType_i64) {
5912*03ce13f7SAndroid Build Coastguard Worker         _mov(Index, RangeIndex); // trunc
5913*03ce13f7SAndroid Build Coastguard Worker       } else {
5914*03ce13f7SAndroid Build Coastguard Worker         Operand *RangeIndexRM = legalize(RangeIndex, Legal_Reg | Legal_Mem);
5915*03ce13f7SAndroid Build Coastguard Worker         _movzx(Index, RangeIndexRM);
5916*03ce13f7SAndroid Build Coastguard Worker       }
5917*03ce13f7SAndroid Build Coastguard Worker     } else {
5918*03ce13f7SAndroid Build Coastguard Worker       Index = legalizeToReg(RangeIndex);
5919*03ce13f7SAndroid Build Coastguard Worker     }
5920*03ce13f7SAndroid Build Coastguard Worker 
5921*03ce13f7SAndroid Build Coastguard Worker     constexpr RelocOffsetT RelocOffset = 0;
5922*03ce13f7SAndroid Build Coastguard Worker     constexpr Variable *NoBase = nullptr;
5923*03ce13f7SAndroid Build Coastguard Worker     constexpr Constant *NoOffset = nullptr;
5924*03ce13f7SAndroid Build Coastguard Worker     auto JTName = GlobalString::createWithString(Ctx, JumpTable->getName());
5925*03ce13f7SAndroid Build Coastguard Worker     Constant *Offset = Ctx->getConstantSym(RelocOffset, JTName);
5926*03ce13f7SAndroid Build Coastguard Worker     uint16_t Shift = typeWidthInBytesLog2(PointerType);
5927*03ce13f7SAndroid Build Coastguard Worker     constexpr auto Segment = X86OperandMem::SegmentRegisters::DefaultSegment;
5928*03ce13f7SAndroid Build Coastguard Worker 
5929*03ce13f7SAndroid Build Coastguard Worker     Variable *Target = nullptr;
5930*03ce13f7SAndroid Build Coastguard Worker     if (PointerType == IceType_i32) {
5931*03ce13f7SAndroid Build Coastguard Worker       _mov(Target, X86OperandMem::create(Func, PointerType, NoBase, Offset,
5932*03ce13f7SAndroid Build Coastguard Worker                                          Index, Shift, Segment));
5933*03ce13f7SAndroid Build Coastguard Worker     } else {
5934*03ce13f7SAndroid Build Coastguard Worker       auto *Base = makeReg(IceType_i64);
5935*03ce13f7SAndroid Build Coastguard Worker       _lea(Base, X86OperandMem::create(Func, IceType_void, NoBase, Offset));
5936*03ce13f7SAndroid Build Coastguard Worker       _mov(Target, X86OperandMem::create(Func, PointerType, Base, NoOffset,
5937*03ce13f7SAndroid Build Coastguard Worker                                          Index, Shift, Segment));
5938*03ce13f7SAndroid Build Coastguard Worker     }
5939*03ce13f7SAndroid Build Coastguard Worker 
5940*03ce13f7SAndroid Build Coastguard Worker     lowerIndirectJump(Target);
5941*03ce13f7SAndroid Build Coastguard Worker 
5942*03ce13f7SAndroid Build Coastguard Worker     if (DefaultTarget == nullptr)
5943*03ce13f7SAndroid Build Coastguard Worker       Context.insert(SkipJumpTable);
5944*03ce13f7SAndroid Build Coastguard Worker     return;
5945*03ce13f7SAndroid Build Coastguard Worker   }
5946*03ce13f7SAndroid Build Coastguard Worker   case CaseCluster::Range: {
5947*03ce13f7SAndroid Build Coastguard Worker     if (Case.isUnitRange()) {
5948*03ce13f7SAndroid Build Coastguard Worker       // Single item
5949*03ce13f7SAndroid Build Coastguard Worker       if (!DoneCmp) {
5950*03ce13f7SAndroid Build Coastguard Worker         Constant *Value = Ctx->getConstantInt32(Case.getLow());
5951*03ce13f7SAndroid Build Coastguard Worker         _cmp(Comparison, Value);
5952*03ce13f7SAndroid Build Coastguard Worker       }
5953*03ce13f7SAndroid Build Coastguard Worker       _br(CondX86::Br_e, Case.getTarget());
5954*03ce13f7SAndroid Build Coastguard Worker     } else if (DoneCmp && Case.isPairRange()) {
5955*03ce13f7SAndroid Build Coastguard Worker       // Range of two items with first item aleady compared against
5956*03ce13f7SAndroid Build Coastguard Worker       _br(CondX86::Br_e, Case.getTarget());
5957*03ce13f7SAndroid Build Coastguard Worker       Constant *Value = Ctx->getConstantInt32(Case.getHigh());
5958*03ce13f7SAndroid Build Coastguard Worker       _cmp(Comparison, Value);
5959*03ce13f7SAndroid Build Coastguard Worker       _br(CondX86::Br_e, Case.getTarget());
5960*03ce13f7SAndroid Build Coastguard Worker     } else {
5961*03ce13f7SAndroid Build Coastguard Worker       // Range
5962*03ce13f7SAndroid Build Coastguard Worker       lowerCmpRange(Comparison, Case.getLow(), Case.getHigh());
5963*03ce13f7SAndroid Build Coastguard Worker       _br(CondX86::Br_be, Case.getTarget());
5964*03ce13f7SAndroid Build Coastguard Worker     }
5965*03ce13f7SAndroid Build Coastguard Worker     if (DefaultTarget != nullptr)
5966*03ce13f7SAndroid Build Coastguard Worker       _br(DefaultTarget);
5967*03ce13f7SAndroid Build Coastguard Worker     return;
5968*03ce13f7SAndroid Build Coastguard Worker   }
5969*03ce13f7SAndroid Build Coastguard Worker   }
5970*03ce13f7SAndroid Build Coastguard Worker }
5971*03ce13f7SAndroid Build Coastguard Worker 
lowerSwitch(const InstSwitch * Instr)5972*03ce13f7SAndroid Build Coastguard Worker void TargetX8664::lowerSwitch(const InstSwitch *Instr) {
5973*03ce13f7SAndroid Build Coastguard Worker   // Group cases together and navigate through them with a binary search
5974*03ce13f7SAndroid Build Coastguard Worker   CaseClusterArray CaseClusters = CaseCluster::clusterizeSwitch(Func, Instr);
5975*03ce13f7SAndroid Build Coastguard Worker   Operand *Src0 = Instr->getComparison();
5976*03ce13f7SAndroid Build Coastguard Worker   CfgNode *DefaultTarget = Instr->getLabelDefault();
5977*03ce13f7SAndroid Build Coastguard Worker 
5978*03ce13f7SAndroid Build Coastguard Worker   assert(CaseClusters.size() != 0); // Should always be at least one
5979*03ce13f7SAndroid Build Coastguard Worker 
5980*03ce13f7SAndroid Build Coastguard Worker   if (CaseClusters.size() == 1) {
5981*03ce13f7SAndroid Build Coastguard Worker     // Jump straight to default if needed. Currently a common case as jump
5982*03ce13f7SAndroid Build Coastguard Worker     // tables occur on their own.
5983*03ce13f7SAndroid Build Coastguard Worker     constexpr bool DoneCmp = false;
5984*03ce13f7SAndroid Build Coastguard Worker     lowerCaseCluster(CaseClusters.front(), Src0, DoneCmp, DefaultTarget);
5985*03ce13f7SAndroid Build Coastguard Worker     return;
5986*03ce13f7SAndroid Build Coastguard Worker   }
5987*03ce13f7SAndroid Build Coastguard Worker 
5988*03ce13f7SAndroid Build Coastguard Worker   // Going to be using multiple times so get it in a register early
5989*03ce13f7SAndroid Build Coastguard Worker   Variable *Comparison = legalizeToReg(Src0);
5990*03ce13f7SAndroid Build Coastguard Worker 
5991*03ce13f7SAndroid Build Coastguard Worker   // A span is over the clusters
5992*03ce13f7SAndroid Build Coastguard Worker   struct SearchSpan {
5993*03ce13f7SAndroid Build Coastguard Worker     SearchSpan(SizeT Begin, SizeT Size, InstX86Label *Label)
5994*03ce13f7SAndroid Build Coastguard Worker         : Begin(Begin), Size(Size), Label(Label) {}
5995*03ce13f7SAndroid Build Coastguard Worker 
5996*03ce13f7SAndroid Build Coastguard Worker     SizeT Begin;
5997*03ce13f7SAndroid Build Coastguard Worker     SizeT Size;
5998*03ce13f7SAndroid Build Coastguard Worker     InstX86Label *Label;
5999*03ce13f7SAndroid Build Coastguard Worker   };
6000*03ce13f7SAndroid Build Coastguard Worker   // The stack will only grow to the height of the tree so 12 should be plenty
6001*03ce13f7SAndroid Build Coastguard Worker   std::stack<SearchSpan, llvm::SmallVector<SearchSpan, 12>> SearchSpanStack;
6002*03ce13f7SAndroid Build Coastguard Worker   SearchSpanStack.emplace(0, CaseClusters.size(), nullptr);
6003*03ce13f7SAndroid Build Coastguard Worker   bool DoneCmp = false;
6004*03ce13f7SAndroid Build Coastguard Worker 
6005*03ce13f7SAndroid Build Coastguard Worker   while (!SearchSpanStack.empty()) {
6006*03ce13f7SAndroid Build Coastguard Worker     SearchSpan Span = SearchSpanStack.top();
6007*03ce13f7SAndroid Build Coastguard Worker     SearchSpanStack.pop();
6008*03ce13f7SAndroid Build Coastguard Worker 
6009*03ce13f7SAndroid Build Coastguard Worker     if (Span.Label != nullptr)
6010*03ce13f7SAndroid Build Coastguard Worker       Context.insert(Span.Label);
6011*03ce13f7SAndroid Build Coastguard Worker 
6012*03ce13f7SAndroid Build Coastguard Worker     switch (Span.Size) {
6013*03ce13f7SAndroid Build Coastguard Worker     case 0:
6014*03ce13f7SAndroid Build Coastguard Worker       llvm::report_fatal_error("Invalid SearchSpan size");
6015*03ce13f7SAndroid Build Coastguard Worker       break;
6016*03ce13f7SAndroid Build Coastguard Worker 
6017*03ce13f7SAndroid Build Coastguard Worker     case 1:
6018*03ce13f7SAndroid Build Coastguard Worker       lowerCaseCluster(CaseClusters[Span.Begin], Comparison, DoneCmp,
6019*03ce13f7SAndroid Build Coastguard Worker                        SearchSpanStack.empty() ? nullptr : DefaultTarget);
6020*03ce13f7SAndroid Build Coastguard Worker       DoneCmp = false;
6021*03ce13f7SAndroid Build Coastguard Worker       break;
6022*03ce13f7SAndroid Build Coastguard Worker 
6023*03ce13f7SAndroid Build Coastguard Worker     case 2: {
6024*03ce13f7SAndroid Build Coastguard Worker       const CaseCluster *CaseA = &CaseClusters[Span.Begin];
6025*03ce13f7SAndroid Build Coastguard Worker       const CaseCluster *CaseB = &CaseClusters[Span.Begin + 1];
6026*03ce13f7SAndroid Build Coastguard Worker 
6027*03ce13f7SAndroid Build Coastguard Worker       // Placing a range last may allow register clobbering during the range
6028*03ce13f7SAndroid Build Coastguard Worker       // test. That means there is no need to clone the register. If it is a
6029*03ce13f7SAndroid Build Coastguard Worker       // unit range the comparison may have already been done in the binary
6030*03ce13f7SAndroid Build Coastguard Worker       // search (DoneCmp) and so it should be placed first. If this is a range
6031*03ce13f7SAndroid Build Coastguard Worker       // of two items and the comparison with the low value has already been
6032*03ce13f7SAndroid Build Coastguard Worker       // done, comparing with the other element is cheaper than a range test.
6033*03ce13f7SAndroid Build Coastguard Worker       // If the low end of the range is zero then there is no subtraction and
6034*03ce13f7SAndroid Build Coastguard Worker       // nothing to be gained.
6035*03ce13f7SAndroid Build Coastguard Worker       if (!CaseA->isUnitRange() &&
6036*03ce13f7SAndroid Build Coastguard Worker           !(CaseA->getLow() == 0 || (DoneCmp && CaseA->isPairRange()))) {
6037*03ce13f7SAndroid Build Coastguard Worker         std::swap(CaseA, CaseB);
6038*03ce13f7SAndroid Build Coastguard Worker         DoneCmp = false;
6039*03ce13f7SAndroid Build Coastguard Worker       }
6040*03ce13f7SAndroid Build Coastguard Worker 
6041*03ce13f7SAndroid Build Coastguard Worker       lowerCaseCluster(*CaseA, Comparison, DoneCmp);
6042*03ce13f7SAndroid Build Coastguard Worker       DoneCmp = false;
6043*03ce13f7SAndroid Build Coastguard Worker       lowerCaseCluster(*CaseB, Comparison, DoneCmp,
6044*03ce13f7SAndroid Build Coastguard Worker                        SearchSpanStack.empty() ? nullptr : DefaultTarget);
6045*03ce13f7SAndroid Build Coastguard Worker     } break;
6046*03ce13f7SAndroid Build Coastguard Worker 
6047*03ce13f7SAndroid Build Coastguard Worker     default:
6048*03ce13f7SAndroid Build Coastguard Worker       // Pick the middle item and branch b or ae
6049*03ce13f7SAndroid Build Coastguard Worker       SizeT PivotIndex = Span.Begin + (Span.Size / 2);
6050*03ce13f7SAndroid Build Coastguard Worker       const CaseCluster &Pivot = CaseClusters[PivotIndex];
6051*03ce13f7SAndroid Build Coastguard Worker       Constant *Value = Ctx->getConstantInt32(Pivot.getLow());
6052*03ce13f7SAndroid Build Coastguard Worker       InstX86Label *Label = InstX86Label::create(Func, this);
6053*03ce13f7SAndroid Build Coastguard Worker       _cmp(Comparison, Value);
6054*03ce13f7SAndroid Build Coastguard Worker       // TODO(ascull): does it alway have to be far?
6055*03ce13f7SAndroid Build Coastguard Worker       _br(CondX86::Br_b, Label, InstX86Br::Far);
6056*03ce13f7SAndroid Build Coastguard Worker       // Lower the left and (pivot+right) sides, falling through to the right
6057*03ce13f7SAndroid Build Coastguard Worker       SearchSpanStack.emplace(Span.Begin, Span.Size / 2, Label);
6058*03ce13f7SAndroid Build Coastguard Worker       SearchSpanStack.emplace(PivotIndex, Span.Size - (Span.Size / 2), nullptr);
6059*03ce13f7SAndroid Build Coastguard Worker       DoneCmp = true;
6060*03ce13f7SAndroid Build Coastguard Worker       break;
6061*03ce13f7SAndroid Build Coastguard Worker     }
6062*03ce13f7SAndroid Build Coastguard Worker   }
6063*03ce13f7SAndroid Build Coastguard Worker 
6064*03ce13f7SAndroid Build Coastguard Worker   _br(DefaultTarget);
6065*03ce13f7SAndroid Build Coastguard Worker }
6066*03ce13f7SAndroid Build Coastguard Worker 
6067*03ce13f7SAndroid Build Coastguard Worker /// The following pattern occurs often in lowered C and C++ code:
6068*03ce13f7SAndroid Build Coastguard Worker ///
6069*03ce13f7SAndroid Build Coastguard Worker ///   %cmp     = fcmp/icmp pred <n x ty> %src0, %src1
6070*03ce13f7SAndroid Build Coastguard Worker ///   %cmp.ext = sext <n x i1> %cmp to <n x ty>
6071*03ce13f7SAndroid Build Coastguard Worker ///
6072*03ce13f7SAndroid Build Coastguard Worker /// We can eliminate the sext operation by copying the result of pcmpeqd,
6073*03ce13f7SAndroid Build Coastguard Worker /// pcmpgtd, or cmpps (which produce sign extended results) to the result of the
6074*03ce13f7SAndroid Build Coastguard Worker /// sext operation.
6075*03ce13f7SAndroid Build Coastguard Worker 
eliminateNextVectorSextInstruction(Variable * SignExtendedResult)6076*03ce13f7SAndroid Build Coastguard Worker void TargetX8664::eliminateNextVectorSextInstruction(
6077*03ce13f7SAndroid Build Coastguard Worker     Variable *SignExtendedResult) {
6078*03ce13f7SAndroid Build Coastguard Worker   if (auto *NextCast =
6079*03ce13f7SAndroid Build Coastguard Worker           llvm::dyn_cast_or_null<InstCast>(Context.getNextInst())) {
6080*03ce13f7SAndroid Build Coastguard Worker     if (NextCast->getCastKind() == InstCast::Sext &&
6081*03ce13f7SAndroid Build Coastguard Worker         NextCast->getSrc(0) == SignExtendedResult) {
6082*03ce13f7SAndroid Build Coastguard Worker       NextCast->setDeleted();
6083*03ce13f7SAndroid Build Coastguard Worker       _movp(NextCast->getDest(), legalizeToReg(SignExtendedResult));
6084*03ce13f7SAndroid Build Coastguard Worker       // Skip over the instruction.
6085*03ce13f7SAndroid Build Coastguard Worker       Context.advanceNext();
6086*03ce13f7SAndroid Build Coastguard Worker     }
6087*03ce13f7SAndroid Build Coastguard Worker   }
6088*03ce13f7SAndroid Build Coastguard Worker }
6089*03ce13f7SAndroid Build Coastguard Worker 
lowerUnreachable(const InstUnreachable *)6090*03ce13f7SAndroid Build Coastguard Worker void TargetX8664::lowerUnreachable(const InstUnreachable * /*Instr*/) {
6091*03ce13f7SAndroid Build Coastguard Worker   _ud2();
6092*03ce13f7SAndroid Build Coastguard Worker   // Add a fake use of esp to make sure esp adjustments after the unreachable
6093*03ce13f7SAndroid Build Coastguard Worker   // do not get dead-code eliminated.
6094*03ce13f7SAndroid Build Coastguard Worker   keepEspLiveAtExit();
6095*03ce13f7SAndroid Build Coastguard Worker }
6096*03ce13f7SAndroid Build Coastguard Worker 
lowerBreakpoint(const InstBreakpoint *)6097*03ce13f7SAndroid Build Coastguard Worker void TargetX8664::lowerBreakpoint(const InstBreakpoint * /*Instr*/) { _int3(); }
6098*03ce13f7SAndroid Build Coastguard Worker 
lowerRMW(const InstX86FakeRMW * RMW)6099*03ce13f7SAndroid Build Coastguard Worker void TargetX8664::lowerRMW(const InstX86FakeRMW *RMW) {
6100*03ce13f7SAndroid Build Coastguard Worker   // If the beacon variable's live range does not end in this instruction, then
6101*03ce13f7SAndroid Build Coastguard Worker   // it must end in the modified Store instruction that follows. This means
6102*03ce13f7SAndroid Build Coastguard Worker   // that the original Store instruction is still there, either because the
6103*03ce13f7SAndroid Build Coastguard Worker   // value being stored is used beyond the Store instruction, or because dead
6104*03ce13f7SAndroid Build Coastguard Worker   // code elimination did not happen. In either case, we cancel RMW lowering
6105*03ce13f7SAndroid Build Coastguard Worker   // (and the caller deletes the RMW instruction).
6106*03ce13f7SAndroid Build Coastguard Worker   if (!RMW->isLastUse(RMW->getBeacon()))
6107*03ce13f7SAndroid Build Coastguard Worker     return;
6108*03ce13f7SAndroid Build Coastguard Worker   Operand *Src = RMW->getData();
6109*03ce13f7SAndroid Build Coastguard Worker   Type Ty = Src->getType();
6110*03ce13f7SAndroid Build Coastguard Worker   X86OperandMem *Addr = formMemoryOperand(RMW->getAddr(), Ty);
6111*03ce13f7SAndroid Build Coastguard Worker   doMockBoundsCheck(Addr);
6112*03ce13f7SAndroid Build Coastguard Worker   switch (RMW->getOp()) {
6113*03ce13f7SAndroid Build Coastguard Worker   default:
6114*03ce13f7SAndroid Build Coastguard Worker     // TODO(stichnot): Implement other arithmetic operators.
6115*03ce13f7SAndroid Build Coastguard Worker     break;
6116*03ce13f7SAndroid Build Coastguard Worker   case InstArithmetic::Add:
6117*03ce13f7SAndroid Build Coastguard Worker     Src = legalize(Src, Legal_Reg | Legal_Imm);
6118*03ce13f7SAndroid Build Coastguard Worker     _add_rmw(Addr, Src);
6119*03ce13f7SAndroid Build Coastguard Worker     return;
6120*03ce13f7SAndroid Build Coastguard Worker   case InstArithmetic::Sub:
6121*03ce13f7SAndroid Build Coastguard Worker     Src = legalize(Src, Legal_Reg | Legal_Imm);
6122*03ce13f7SAndroid Build Coastguard Worker     _sub_rmw(Addr, Src);
6123*03ce13f7SAndroid Build Coastguard Worker     return;
6124*03ce13f7SAndroid Build Coastguard Worker   case InstArithmetic::And:
6125*03ce13f7SAndroid Build Coastguard Worker     Src = legalize(Src, Legal_Reg | Legal_Imm);
6126*03ce13f7SAndroid Build Coastguard Worker     _and_rmw(Addr, Src);
6127*03ce13f7SAndroid Build Coastguard Worker     return;
6128*03ce13f7SAndroid Build Coastguard Worker   case InstArithmetic::Or:
6129*03ce13f7SAndroid Build Coastguard Worker     Src = legalize(Src, Legal_Reg | Legal_Imm);
6130*03ce13f7SAndroid Build Coastguard Worker     _or_rmw(Addr, Src);
6131*03ce13f7SAndroid Build Coastguard Worker     return;
6132*03ce13f7SAndroid Build Coastguard Worker   case InstArithmetic::Xor:
6133*03ce13f7SAndroid Build Coastguard Worker     Src = legalize(Src, Legal_Reg | Legal_Imm);
6134*03ce13f7SAndroid Build Coastguard Worker     _xor_rmw(Addr, Src);
6135*03ce13f7SAndroid Build Coastguard Worker     return;
6136*03ce13f7SAndroid Build Coastguard Worker   }
6137*03ce13f7SAndroid Build Coastguard Worker   llvm::report_fatal_error("Couldn't lower RMW instruction");
6138*03ce13f7SAndroid Build Coastguard Worker }
6139*03ce13f7SAndroid Build Coastguard Worker 
lowerOther(const Inst * Instr)6140*03ce13f7SAndroid Build Coastguard Worker void TargetX8664::lowerOther(const Inst *Instr) {
6141*03ce13f7SAndroid Build Coastguard Worker   if (const auto *RMW = llvm::dyn_cast<InstX86FakeRMW>(Instr)) {
6142*03ce13f7SAndroid Build Coastguard Worker     lowerRMW(RMW);
6143*03ce13f7SAndroid Build Coastguard Worker   } else {
6144*03ce13f7SAndroid Build Coastguard Worker     TargetLowering::lowerOther(Instr);
6145*03ce13f7SAndroid Build Coastguard Worker   }
6146*03ce13f7SAndroid Build Coastguard Worker }
6147*03ce13f7SAndroid Build Coastguard Worker 
prelowerPhis()6148*03ce13f7SAndroid Build Coastguard Worker void TargetX8664::prelowerPhis() {
6149*03ce13f7SAndroid Build Coastguard Worker   // On x86-64 we don't need to prelower phis -- the architecture can handle
6150*03ce13f7SAndroid Build Coastguard Worker   // 64-bit integer natively.
6151*03ce13f7SAndroid Build Coastguard Worker   return;
6152*03ce13f7SAndroid Build Coastguard Worker }
6153*03ce13f7SAndroid Build Coastguard Worker 
genTargetHelperCallFor(Inst * Instr)6154*03ce13f7SAndroid Build Coastguard Worker void TargetX8664::genTargetHelperCallFor(Inst *Instr) {
6155*03ce13f7SAndroid Build Coastguard Worker   uint32_t StackArgumentsSize = 0;
6156*03ce13f7SAndroid Build Coastguard Worker   if (auto *Arith = llvm::dyn_cast<InstArithmetic>(Instr)) {
6157*03ce13f7SAndroid Build Coastguard Worker     RuntimeHelper HelperID = RuntimeHelper::H_Num;
6158*03ce13f7SAndroid Build Coastguard Worker     Variable *Dest = Arith->getDest();
6159*03ce13f7SAndroid Build Coastguard Worker     Type DestTy = Dest->getType();
6160*03ce13f7SAndroid Build Coastguard Worker     if (isVectorType(DestTy)) {
6161*03ce13f7SAndroid Build Coastguard Worker       Variable *Dest = Arith->getDest();
6162*03ce13f7SAndroid Build Coastguard Worker       Operand *Src0 = Arith->getSrc(0);
6163*03ce13f7SAndroid Build Coastguard Worker       Operand *Src1 = Arith->getSrc(1);
6164*03ce13f7SAndroid Build Coastguard Worker       switch (Arith->getOp()) {
6165*03ce13f7SAndroid Build Coastguard Worker       default:
6166*03ce13f7SAndroid Build Coastguard Worker         return;
6167*03ce13f7SAndroid Build Coastguard Worker       case InstArithmetic::Mul:
6168*03ce13f7SAndroid Build Coastguard Worker         if (DestTy == IceType_v16i8) {
6169*03ce13f7SAndroid Build Coastguard Worker           scalarizeArithmetic(Arith->getOp(), Dest, Src0, Src1);
6170*03ce13f7SAndroid Build Coastguard Worker           Arith->setDeleted();
6171*03ce13f7SAndroid Build Coastguard Worker         }
6172*03ce13f7SAndroid Build Coastguard Worker         return;
6173*03ce13f7SAndroid Build Coastguard Worker       case InstArithmetic::Shl:
6174*03ce13f7SAndroid Build Coastguard Worker       case InstArithmetic::Lshr:
6175*03ce13f7SAndroid Build Coastguard Worker       case InstArithmetic::Ashr:
6176*03ce13f7SAndroid Build Coastguard Worker         if (llvm::isa<Constant>(Src1)) {
6177*03ce13f7SAndroid Build Coastguard Worker           return;
6178*03ce13f7SAndroid Build Coastguard Worker         }
6179*03ce13f7SAndroid Build Coastguard Worker       case InstArithmetic::Udiv:
6180*03ce13f7SAndroid Build Coastguard Worker       case InstArithmetic::Urem:
6181*03ce13f7SAndroid Build Coastguard Worker       case InstArithmetic::Sdiv:
6182*03ce13f7SAndroid Build Coastguard Worker       case InstArithmetic::Srem:
6183*03ce13f7SAndroid Build Coastguard Worker       case InstArithmetic::Frem:
6184*03ce13f7SAndroid Build Coastguard Worker         scalarizeArithmetic(Arith->getOp(), Dest, Src0, Src1);
6185*03ce13f7SAndroid Build Coastguard Worker         Arith->setDeleted();
6186*03ce13f7SAndroid Build Coastguard Worker         return;
6187*03ce13f7SAndroid Build Coastguard Worker       }
6188*03ce13f7SAndroid Build Coastguard Worker     } else {
6189*03ce13f7SAndroid Build Coastguard Worker       switch (Arith->getOp()) {
6190*03ce13f7SAndroid Build Coastguard Worker       default:
6191*03ce13f7SAndroid Build Coastguard Worker         return;
6192*03ce13f7SAndroid Build Coastguard Worker       case InstArithmetic::Frem:
6193*03ce13f7SAndroid Build Coastguard Worker         if (isFloat32Asserting32Or64(DestTy))
6194*03ce13f7SAndroid Build Coastguard Worker           HelperID = RuntimeHelper::H_frem_f32;
6195*03ce13f7SAndroid Build Coastguard Worker         else
6196*03ce13f7SAndroid Build Coastguard Worker           HelperID = RuntimeHelper::H_frem_f64;
6197*03ce13f7SAndroid Build Coastguard Worker       }
6198*03ce13f7SAndroid Build Coastguard Worker     }
6199*03ce13f7SAndroid Build Coastguard Worker     constexpr SizeT MaxSrcs = 2;
6200*03ce13f7SAndroid Build Coastguard Worker     InstCall *Call = makeHelperCall(HelperID, Dest, MaxSrcs);
6201*03ce13f7SAndroid Build Coastguard Worker     Call->addArg(Arith->getSrc(0));
6202*03ce13f7SAndroid Build Coastguard Worker     Call->addArg(Arith->getSrc(1));
6203*03ce13f7SAndroid Build Coastguard Worker     StackArgumentsSize = getCallStackArgumentsSizeBytes(Call);
6204*03ce13f7SAndroid Build Coastguard Worker     Context.insert(Call);
6205*03ce13f7SAndroid Build Coastguard Worker     Arith->setDeleted();
6206*03ce13f7SAndroid Build Coastguard Worker   } else if (auto *Cast = llvm::dyn_cast<InstCast>(Instr)) {
6207*03ce13f7SAndroid Build Coastguard Worker     InstCast::OpKind CastKind = Cast->getCastKind();
6208*03ce13f7SAndroid Build Coastguard Worker     Operand *Src0 = Cast->getSrc(0);
6209*03ce13f7SAndroid Build Coastguard Worker     const Type SrcType = Src0->getType();
6210*03ce13f7SAndroid Build Coastguard Worker     Variable *Dest = Cast->getDest();
6211*03ce13f7SAndroid Build Coastguard Worker     const Type DestTy = Dest->getType();
6212*03ce13f7SAndroid Build Coastguard Worker     RuntimeHelper HelperID = RuntimeHelper::H_Num;
6213*03ce13f7SAndroid Build Coastguard Worker     Variable *CallDest = Dest;
6214*03ce13f7SAndroid Build Coastguard Worker     switch (CastKind) {
6215*03ce13f7SAndroid Build Coastguard Worker     default:
6216*03ce13f7SAndroid Build Coastguard Worker       return;
6217*03ce13f7SAndroid Build Coastguard Worker     case InstCast::Fptoui:
6218*03ce13f7SAndroid Build Coastguard Worker       if (isVectorType(DestTy)) {
6219*03ce13f7SAndroid Build Coastguard Worker         assert(DestTy == IceType_v4i32);
6220*03ce13f7SAndroid Build Coastguard Worker         assert(SrcType == IceType_v4f32);
6221*03ce13f7SAndroid Build Coastguard Worker         HelperID = RuntimeHelper::H_fptoui_4xi32_f32;
6222*03ce13f7SAndroid Build Coastguard Worker       } else if (DestTy == IceType_i64) {
6223*03ce13f7SAndroid Build Coastguard Worker         HelperID = isFloat32Asserting32Or64(SrcType)
6224*03ce13f7SAndroid Build Coastguard Worker                        ? RuntimeHelper::H_fptoui_f32_i64
6225*03ce13f7SAndroid Build Coastguard Worker                        : RuntimeHelper::H_fptoui_f64_i64;
6226*03ce13f7SAndroid Build Coastguard Worker       } else {
6227*03ce13f7SAndroid Build Coastguard Worker         return;
6228*03ce13f7SAndroid Build Coastguard Worker       }
6229*03ce13f7SAndroid Build Coastguard Worker       break;
6230*03ce13f7SAndroid Build Coastguard Worker     case InstCast::Uitofp:
6231*03ce13f7SAndroid Build Coastguard Worker       if (isVectorType(SrcType)) {
6232*03ce13f7SAndroid Build Coastguard Worker         assert(DestTy == IceType_v4f32);
6233*03ce13f7SAndroid Build Coastguard Worker         assert(SrcType == IceType_v4i32);
6234*03ce13f7SAndroid Build Coastguard Worker         HelperID = RuntimeHelper::H_uitofp_4xi32_4xf32;
6235*03ce13f7SAndroid Build Coastguard Worker       } else if (SrcType == IceType_i64) {
6236*03ce13f7SAndroid Build Coastguard Worker         if (isInt32Asserting32Or64(SrcType)) {
6237*03ce13f7SAndroid Build Coastguard Worker           HelperID = isFloat32Asserting32Or64(DestTy)
6238*03ce13f7SAndroid Build Coastguard Worker                          ? RuntimeHelper::H_uitofp_i32_f32
6239*03ce13f7SAndroid Build Coastguard Worker                          : RuntimeHelper::H_uitofp_i32_f64;
6240*03ce13f7SAndroid Build Coastguard Worker         } else {
6241*03ce13f7SAndroid Build Coastguard Worker           HelperID = isFloat32Asserting32Or64(DestTy)
6242*03ce13f7SAndroid Build Coastguard Worker                          ? RuntimeHelper::H_uitofp_i64_f32
6243*03ce13f7SAndroid Build Coastguard Worker                          : RuntimeHelper::H_uitofp_i64_f64;
6244*03ce13f7SAndroid Build Coastguard Worker         }
6245*03ce13f7SAndroid Build Coastguard Worker       } else {
6246*03ce13f7SAndroid Build Coastguard Worker         return;
6247*03ce13f7SAndroid Build Coastguard Worker       }
6248*03ce13f7SAndroid Build Coastguard Worker       break;
6249*03ce13f7SAndroid Build Coastguard Worker     case InstCast::Bitcast: {
6250*03ce13f7SAndroid Build Coastguard Worker       if (DestTy == Src0->getType())
6251*03ce13f7SAndroid Build Coastguard Worker         return;
6252*03ce13f7SAndroid Build Coastguard Worker       switch (DestTy) {
6253*03ce13f7SAndroid Build Coastguard Worker       default:
6254*03ce13f7SAndroid Build Coastguard Worker         return;
6255*03ce13f7SAndroid Build Coastguard Worker       case IceType_i8:
6256*03ce13f7SAndroid Build Coastguard Worker         assert(Src0->getType() == IceType_v8i1);
6257*03ce13f7SAndroid Build Coastguard Worker         HelperID = RuntimeHelper::H_bitcast_8xi1_i8;
6258*03ce13f7SAndroid Build Coastguard Worker         CallDest = Func->makeVariable(IceType_i32);
6259*03ce13f7SAndroid Build Coastguard Worker         break;
6260*03ce13f7SAndroid Build Coastguard Worker       case IceType_i16:
6261*03ce13f7SAndroid Build Coastguard Worker         assert(Src0->getType() == IceType_v16i1);
6262*03ce13f7SAndroid Build Coastguard Worker         HelperID = RuntimeHelper::H_bitcast_16xi1_i16;
6263*03ce13f7SAndroid Build Coastguard Worker         CallDest = Func->makeVariable(IceType_i32);
6264*03ce13f7SAndroid Build Coastguard Worker         break;
6265*03ce13f7SAndroid Build Coastguard Worker       case IceType_v8i1: {
6266*03ce13f7SAndroid Build Coastguard Worker         assert(Src0->getType() == IceType_i8);
6267*03ce13f7SAndroid Build Coastguard Worker         HelperID = RuntimeHelper::H_bitcast_i8_8xi1;
6268*03ce13f7SAndroid Build Coastguard Worker         Variable *Src0AsI32 = Func->makeVariable(stackSlotType());
6269*03ce13f7SAndroid Build Coastguard Worker         // Arguments to functions are required to be at least 32 bits wide.
6270*03ce13f7SAndroid Build Coastguard Worker         Context.insert<InstCast>(InstCast::Zext, Src0AsI32, Src0);
6271*03ce13f7SAndroid Build Coastguard Worker         Src0 = Src0AsI32;
6272*03ce13f7SAndroid Build Coastguard Worker       } break;
6273*03ce13f7SAndroid Build Coastguard Worker       case IceType_v16i1: {
6274*03ce13f7SAndroid Build Coastguard Worker         assert(Src0->getType() == IceType_i16);
6275*03ce13f7SAndroid Build Coastguard Worker         HelperID = RuntimeHelper::H_bitcast_i16_16xi1;
6276*03ce13f7SAndroid Build Coastguard Worker         Variable *Src0AsI32 = Func->makeVariable(stackSlotType());
6277*03ce13f7SAndroid Build Coastguard Worker         // Arguments to functions are required to be at least 32 bits wide.
6278*03ce13f7SAndroid Build Coastguard Worker         Context.insert<InstCast>(InstCast::Zext, Src0AsI32, Src0);
6279*03ce13f7SAndroid Build Coastguard Worker         Src0 = Src0AsI32;
6280*03ce13f7SAndroid Build Coastguard Worker       } break;
6281*03ce13f7SAndroid Build Coastguard Worker       }
6282*03ce13f7SAndroid Build Coastguard Worker     } break;
6283*03ce13f7SAndroid Build Coastguard Worker     }
6284*03ce13f7SAndroid Build Coastguard Worker     constexpr SizeT MaxSrcs = 1;
6285*03ce13f7SAndroid Build Coastguard Worker     InstCall *Call = makeHelperCall(HelperID, CallDest, MaxSrcs);
6286*03ce13f7SAndroid Build Coastguard Worker     Call->addArg(Src0);
6287*03ce13f7SAndroid Build Coastguard Worker     StackArgumentsSize = getCallStackArgumentsSizeBytes(Call);
6288*03ce13f7SAndroid Build Coastguard Worker     Context.insert(Call);
6289*03ce13f7SAndroid Build Coastguard Worker     // The PNaCl ABI disallows i8/i16 return types, so truncate the helper call
6290*03ce13f7SAndroid Build Coastguard Worker     // result to the appropriate type as necessary.
6291*03ce13f7SAndroid Build Coastguard Worker     if (CallDest->getType() != Dest->getType())
6292*03ce13f7SAndroid Build Coastguard Worker       Context.insert<InstCast>(InstCast::Trunc, Dest, CallDest);
6293*03ce13f7SAndroid Build Coastguard Worker     Cast->setDeleted();
6294*03ce13f7SAndroid Build Coastguard Worker   } else if (auto *Intrinsic = llvm::dyn_cast<InstIntrinsic>(Instr)) {
6295*03ce13f7SAndroid Build Coastguard Worker     CfgVector<Type> ArgTypes;
6296*03ce13f7SAndroid Build Coastguard Worker     Type ReturnType = IceType_void;
6297*03ce13f7SAndroid Build Coastguard Worker     switch (Intrinsic->getIntrinsicID()) {
6298*03ce13f7SAndroid Build Coastguard Worker     default:
6299*03ce13f7SAndroid Build Coastguard Worker       return;
6300*03ce13f7SAndroid Build Coastguard Worker     case Intrinsics::Ctpop: {
6301*03ce13f7SAndroid Build Coastguard Worker       Operand *Val = Intrinsic->getArg(0);
6302*03ce13f7SAndroid Build Coastguard Worker       Type ValTy = Val->getType();
6303*03ce13f7SAndroid Build Coastguard Worker       if (ValTy == IceType_i64)
6304*03ce13f7SAndroid Build Coastguard Worker         ArgTypes = {IceType_i64};
6305*03ce13f7SAndroid Build Coastguard Worker       else
6306*03ce13f7SAndroid Build Coastguard Worker         ArgTypes = {IceType_i32};
6307*03ce13f7SAndroid Build Coastguard Worker       ReturnType = IceType_i32;
6308*03ce13f7SAndroid Build Coastguard Worker     } break;
6309*03ce13f7SAndroid Build Coastguard Worker     case Intrinsics::Longjmp:
6310*03ce13f7SAndroid Build Coastguard Worker       ArgTypes = {IceType_i32, IceType_i32};
6311*03ce13f7SAndroid Build Coastguard Worker       ReturnType = IceType_void;
6312*03ce13f7SAndroid Build Coastguard Worker       break;
6313*03ce13f7SAndroid Build Coastguard Worker     case Intrinsics::Memcpy:
6314*03ce13f7SAndroid Build Coastguard Worker       ArgTypes = {IceType_i32, IceType_i32, IceType_i32};
6315*03ce13f7SAndroid Build Coastguard Worker       ReturnType = IceType_void;
6316*03ce13f7SAndroid Build Coastguard Worker       break;
6317*03ce13f7SAndroid Build Coastguard Worker     case Intrinsics::Memmove:
6318*03ce13f7SAndroid Build Coastguard Worker       ArgTypes = {IceType_i32, IceType_i32, IceType_i32};
6319*03ce13f7SAndroid Build Coastguard Worker       ReturnType = IceType_void;
6320*03ce13f7SAndroid Build Coastguard Worker       break;
6321*03ce13f7SAndroid Build Coastguard Worker     case Intrinsics::Memset:
6322*03ce13f7SAndroid Build Coastguard Worker       ArgTypes = {IceType_i32, IceType_i32, IceType_i32};
6323*03ce13f7SAndroid Build Coastguard Worker       ReturnType = IceType_void;
6324*03ce13f7SAndroid Build Coastguard Worker       break;
6325*03ce13f7SAndroid Build Coastguard Worker     case Intrinsics::Setjmp:
6326*03ce13f7SAndroid Build Coastguard Worker       ArgTypes = {IceType_i32};
6327*03ce13f7SAndroid Build Coastguard Worker       ReturnType = IceType_i32;
6328*03ce13f7SAndroid Build Coastguard Worker       break;
6329*03ce13f7SAndroid Build Coastguard Worker     }
6330*03ce13f7SAndroid Build Coastguard Worker     StackArgumentsSize = getCallStackArgumentsSizeBytes(ArgTypes, ReturnType);
6331*03ce13f7SAndroid Build Coastguard Worker   } else if (auto *Call = llvm::dyn_cast<InstCall>(Instr)) {
6332*03ce13f7SAndroid Build Coastguard Worker     StackArgumentsSize = getCallStackArgumentsSizeBytes(Call);
6333*03ce13f7SAndroid Build Coastguard Worker   } else if (auto *Ret = llvm::dyn_cast<InstRet>(Instr)) {
6334*03ce13f7SAndroid Build Coastguard Worker     if (!Ret->hasRetValue())
6335*03ce13f7SAndroid Build Coastguard Worker       return;
6336*03ce13f7SAndroid Build Coastguard Worker     Operand *RetValue = Ret->getRetValue();
6337*03ce13f7SAndroid Build Coastguard Worker     Type ReturnType = RetValue->getType();
6338*03ce13f7SAndroid Build Coastguard Worker     if (!isScalarFloatingType(ReturnType))
6339*03ce13f7SAndroid Build Coastguard Worker       return;
6340*03ce13f7SAndroid Build Coastguard Worker     StackArgumentsSize = typeWidthInBytes(ReturnType);
6341*03ce13f7SAndroid Build Coastguard Worker   } else {
6342*03ce13f7SAndroid Build Coastguard Worker     return;
6343*03ce13f7SAndroid Build Coastguard Worker   }
6344*03ce13f7SAndroid Build Coastguard Worker   StackArgumentsSize = applyStackAlignment(StackArgumentsSize);
6345*03ce13f7SAndroid Build Coastguard Worker   updateMaxOutArgsSizeBytes(StackArgumentsSize);
6346*03ce13f7SAndroid Build Coastguard Worker }
6347*03ce13f7SAndroid Build Coastguard Worker 
6348*03ce13f7SAndroid Build Coastguard Worker uint32_t
getCallStackArgumentsSizeBytes(const CfgVector<Type> & ArgTypes,Type ReturnType)6349*03ce13f7SAndroid Build Coastguard Worker TargetX8664::getCallStackArgumentsSizeBytes(const CfgVector<Type> &ArgTypes,
6350*03ce13f7SAndroid Build Coastguard Worker                                             Type ReturnType) {
6351*03ce13f7SAndroid Build Coastguard Worker   uint32_t OutArgumentsSizeBytes = 0;
6352*03ce13f7SAndroid Build Coastguard Worker   uint32_t XmmArgCount = 0;
6353*03ce13f7SAndroid Build Coastguard Worker   uint32_t GprArgCount = 0;
6354*03ce13f7SAndroid Build Coastguard Worker   for (SizeT i = 0, NumArgTypes = ArgTypes.size(); i < NumArgTypes; ++i) {
6355*03ce13f7SAndroid Build Coastguard Worker     Type Ty = ArgTypes[i];
6356*03ce13f7SAndroid Build Coastguard Worker     // The PNaCl ABI requires the width of arguments to be at least 32 bits.
6357*03ce13f7SAndroid Build Coastguard Worker     assert(typeWidthInBytes(Ty) >= 4);
6358*03ce13f7SAndroid Build Coastguard Worker     if (isVectorType(Ty) &&
6359*03ce13f7SAndroid Build Coastguard Worker         RegX8664::getRegisterForXmmArgNum(RegX8664::getArgIndex(i, XmmArgCount))
6360*03ce13f7SAndroid Build Coastguard Worker             .hasValue()) {
6361*03ce13f7SAndroid Build Coastguard Worker       ++XmmArgCount;
6362*03ce13f7SAndroid Build Coastguard Worker     } else if (isScalarFloatingType(Ty) &&
6363*03ce13f7SAndroid Build Coastguard Worker                RegX8664::getRegisterForXmmArgNum(
6364*03ce13f7SAndroid Build Coastguard Worker                    RegX8664::getArgIndex(i, XmmArgCount))
6365*03ce13f7SAndroid Build Coastguard Worker                    .hasValue()) {
6366*03ce13f7SAndroid Build Coastguard Worker       ++XmmArgCount;
6367*03ce13f7SAndroid Build Coastguard Worker     } else if (isScalarIntegerType(Ty) &&
6368*03ce13f7SAndroid Build Coastguard Worker                RegX8664::getRegisterForGprArgNum(
6369*03ce13f7SAndroid Build Coastguard Worker                    Ty, RegX8664::getArgIndex(i, GprArgCount))
6370*03ce13f7SAndroid Build Coastguard Worker                    .hasValue()) {
6371*03ce13f7SAndroid Build Coastguard Worker       // The 64 bit ABI allows some integers to be passed in GPRs.
6372*03ce13f7SAndroid Build Coastguard Worker       ++GprArgCount;
6373*03ce13f7SAndroid Build Coastguard Worker     } else {
6374*03ce13f7SAndroid Build Coastguard Worker       if (isVectorType(Ty)) {
6375*03ce13f7SAndroid Build Coastguard Worker         OutArgumentsSizeBytes = applyStackAlignment(OutArgumentsSizeBytes);
6376*03ce13f7SAndroid Build Coastguard Worker       }
6377*03ce13f7SAndroid Build Coastguard Worker       OutArgumentsSizeBytes += typeWidthInBytesOnStack(Ty);
6378*03ce13f7SAndroid Build Coastguard Worker     }
6379*03ce13f7SAndroid Build Coastguard Worker   }
6380*03ce13f7SAndroid Build Coastguard Worker   return OutArgumentsSizeBytes;
6381*03ce13f7SAndroid Build Coastguard Worker }
6382*03ce13f7SAndroid Build Coastguard Worker 
getCallStackArgumentsSizeBytes(const InstCall * Instr)6383*03ce13f7SAndroid Build Coastguard Worker uint32_t TargetX8664::getCallStackArgumentsSizeBytes(const InstCall *Instr) {
6384*03ce13f7SAndroid Build Coastguard Worker   // Build a vector of the arguments' types.
6385*03ce13f7SAndroid Build Coastguard Worker   const SizeT NumArgs = Instr->getNumArgs();
6386*03ce13f7SAndroid Build Coastguard Worker   CfgVector<Type> ArgTypes;
6387*03ce13f7SAndroid Build Coastguard Worker   ArgTypes.reserve(NumArgs);
6388*03ce13f7SAndroid Build Coastguard Worker   for (SizeT i = 0; i < NumArgs; ++i) {
6389*03ce13f7SAndroid Build Coastguard Worker     Operand *Arg = Instr->getArg(i);
6390*03ce13f7SAndroid Build Coastguard Worker     ArgTypes.emplace_back(Arg->getType());
6391*03ce13f7SAndroid Build Coastguard Worker   }
6392*03ce13f7SAndroid Build Coastguard Worker   // Compute the return type (if any);
6393*03ce13f7SAndroid Build Coastguard Worker   Type ReturnType = IceType_void;
6394*03ce13f7SAndroid Build Coastguard Worker   Variable *Dest = Instr->getDest();
6395*03ce13f7SAndroid Build Coastguard Worker   if (Dest != nullptr)
6396*03ce13f7SAndroid Build Coastguard Worker     ReturnType = Dest->getType();
6397*03ce13f7SAndroid Build Coastguard Worker   return getShadowStoreSize() +
6398*03ce13f7SAndroid Build Coastguard Worker          getCallStackArgumentsSizeBytes(ArgTypes, ReturnType);
6399*03ce13f7SAndroid Build Coastguard Worker }
6400*03ce13f7SAndroid Build Coastguard Worker 
makeZeroedRegister(Type Ty,RegNumT RegNum)6401*03ce13f7SAndroid Build Coastguard Worker Variable *TargetX8664::makeZeroedRegister(Type Ty, RegNumT RegNum) {
6402*03ce13f7SAndroid Build Coastguard Worker   Variable *Reg = makeReg(Ty, RegNum);
6403*03ce13f7SAndroid Build Coastguard Worker   switch (Ty) {
6404*03ce13f7SAndroid Build Coastguard Worker   case IceType_i1:
6405*03ce13f7SAndroid Build Coastguard Worker   case IceType_i8:
6406*03ce13f7SAndroid Build Coastguard Worker   case IceType_i16:
6407*03ce13f7SAndroid Build Coastguard Worker   case IceType_i32:
6408*03ce13f7SAndroid Build Coastguard Worker   case IceType_i64:
6409*03ce13f7SAndroid Build Coastguard Worker     // Conservatively do "mov reg, 0" to avoid modifying FLAGS.
6410*03ce13f7SAndroid Build Coastguard Worker     _mov(Reg, Ctx->getConstantZero(Ty));
6411*03ce13f7SAndroid Build Coastguard Worker     break;
6412*03ce13f7SAndroid Build Coastguard Worker   case IceType_f32:
6413*03ce13f7SAndroid Build Coastguard Worker   case IceType_f64:
6414*03ce13f7SAndroid Build Coastguard Worker     Context.insert<InstFakeDef>(Reg);
6415*03ce13f7SAndroid Build Coastguard Worker     _xorps(Reg, Reg);
6416*03ce13f7SAndroid Build Coastguard Worker     break;
6417*03ce13f7SAndroid Build Coastguard Worker   default:
6418*03ce13f7SAndroid Build Coastguard Worker     // All vector types use the same pxor instruction.
6419*03ce13f7SAndroid Build Coastguard Worker     assert(isVectorType(Ty));
6420*03ce13f7SAndroid Build Coastguard Worker     Context.insert<InstFakeDef>(Reg);
6421*03ce13f7SAndroid Build Coastguard Worker     _pxor(Reg, Reg);
6422*03ce13f7SAndroid Build Coastguard Worker     break;
6423*03ce13f7SAndroid Build Coastguard Worker   }
6424*03ce13f7SAndroid Build Coastguard Worker   return Reg;
6425*03ce13f7SAndroid Build Coastguard Worker }
6426*03ce13f7SAndroid Build Coastguard Worker 
6427*03ce13f7SAndroid Build Coastguard Worker // There is no support for loading or emitting vector constants, so the vector
6428*03ce13f7SAndroid Build Coastguard Worker // values returned from makeVectorOfZeros, makeVectorOfOnes, etc. are
6429*03ce13f7SAndroid Build Coastguard Worker // initialized with register operations.
6430*03ce13f7SAndroid Build Coastguard Worker //
6431*03ce13f7SAndroid Build Coastguard Worker // TODO(wala): Add limited support for vector constants so that complex
6432*03ce13f7SAndroid Build Coastguard Worker // initialization in registers is unnecessary.
6433*03ce13f7SAndroid Build Coastguard Worker 
makeVectorOfZeros(Type Ty,RegNumT RegNum)6434*03ce13f7SAndroid Build Coastguard Worker Variable *TargetX8664::makeVectorOfZeros(Type Ty, RegNumT RegNum) {
6435*03ce13f7SAndroid Build Coastguard Worker   return makeZeroedRegister(Ty, RegNum);
6436*03ce13f7SAndroid Build Coastguard Worker }
6437*03ce13f7SAndroid Build Coastguard Worker 
makeVectorOfMinusOnes(Type Ty,RegNumT RegNum)6438*03ce13f7SAndroid Build Coastguard Worker Variable *TargetX8664::makeVectorOfMinusOnes(Type Ty, RegNumT RegNum) {
6439*03ce13f7SAndroid Build Coastguard Worker   Variable *MinusOnes = makeReg(Ty, RegNum);
6440*03ce13f7SAndroid Build Coastguard Worker   // Insert a FakeDef so the live range of MinusOnes is not overestimated.
6441*03ce13f7SAndroid Build Coastguard Worker   Context.insert<InstFakeDef>(MinusOnes);
6442*03ce13f7SAndroid Build Coastguard Worker   if (Ty == IceType_f64)
6443*03ce13f7SAndroid Build Coastguard Worker     // Making a vector of minus ones of type f64 is currently only used for the
6444*03ce13f7SAndroid Build Coastguard Worker     // fabs intrinsic.  To use the f64 type to create this mask with pcmpeqq
6445*03ce13f7SAndroid Build Coastguard Worker     // requires SSE 4.1.  Since we're just creating a mask, pcmpeqd does the
6446*03ce13f7SAndroid Build Coastguard Worker     // same job and only requires SSE2.
6447*03ce13f7SAndroid Build Coastguard Worker     _pcmpeq(MinusOnes, MinusOnes, IceType_f32);
6448*03ce13f7SAndroid Build Coastguard Worker   else
6449*03ce13f7SAndroid Build Coastguard Worker     _pcmpeq(MinusOnes, MinusOnes);
6450*03ce13f7SAndroid Build Coastguard Worker   return MinusOnes;
6451*03ce13f7SAndroid Build Coastguard Worker }
6452*03ce13f7SAndroid Build Coastguard Worker 
makeVectorOfOnes(Type Ty,RegNumT RegNum)6453*03ce13f7SAndroid Build Coastguard Worker Variable *TargetX8664::makeVectorOfOnes(Type Ty, RegNumT RegNum) {
6454*03ce13f7SAndroid Build Coastguard Worker   Variable *Dest = makeVectorOfZeros(Ty, RegNum);
6455*03ce13f7SAndroid Build Coastguard Worker   Variable *MinusOne = makeVectorOfMinusOnes(Ty);
6456*03ce13f7SAndroid Build Coastguard Worker   _psub(Dest, MinusOne);
6457*03ce13f7SAndroid Build Coastguard Worker   return Dest;
6458*03ce13f7SAndroid Build Coastguard Worker }
6459*03ce13f7SAndroid Build Coastguard Worker 
makeVectorOfHighOrderBits(Type Ty,RegNumT RegNum)6460*03ce13f7SAndroid Build Coastguard Worker Variable *TargetX8664::makeVectorOfHighOrderBits(Type Ty, RegNumT RegNum) {
6461*03ce13f7SAndroid Build Coastguard Worker   assert(Ty == IceType_v4i32 || Ty == IceType_v4f32 || Ty == IceType_v8i16 ||
6462*03ce13f7SAndroid Build Coastguard Worker          Ty == IceType_v16i8);
6463*03ce13f7SAndroid Build Coastguard Worker   if (Ty == IceType_v4f32 || Ty == IceType_v4i32 || Ty == IceType_v8i16) {
6464*03ce13f7SAndroid Build Coastguard Worker     Variable *Reg = makeVectorOfOnes(Ty, RegNum);
6465*03ce13f7SAndroid Build Coastguard Worker     SizeT Shift = typeWidthInBytes(typeElementType(Ty)) * X86_CHAR_BIT - 1;
6466*03ce13f7SAndroid Build Coastguard Worker     _psll(Reg, Ctx->getConstantInt8(Shift));
6467*03ce13f7SAndroid Build Coastguard Worker     return Reg;
6468*03ce13f7SAndroid Build Coastguard Worker   } else {
6469*03ce13f7SAndroid Build Coastguard Worker     // SSE has no left shift operation for vectors of 8 bit integers.
6470*03ce13f7SAndroid Build Coastguard Worker     constexpr uint32_t HIGH_ORDER_BITS_MASK = 0x80808080;
6471*03ce13f7SAndroid Build Coastguard Worker     Constant *ConstantMask = Ctx->getConstantInt32(HIGH_ORDER_BITS_MASK);
6472*03ce13f7SAndroid Build Coastguard Worker     Variable *Reg = makeReg(Ty, RegNum);
6473*03ce13f7SAndroid Build Coastguard Worker     _movd(Reg, legalize(ConstantMask, Legal_Reg | Legal_Mem));
6474*03ce13f7SAndroid Build Coastguard Worker     _pshufd(Reg, Reg, Ctx->getConstantZero(IceType_i8));
6475*03ce13f7SAndroid Build Coastguard Worker     return Reg;
6476*03ce13f7SAndroid Build Coastguard Worker   }
6477*03ce13f7SAndroid Build Coastguard Worker }
6478*03ce13f7SAndroid Build Coastguard Worker 
6479*03ce13f7SAndroid Build Coastguard Worker /// Construct a mask in a register that can be and'ed with a floating-point
6480*03ce13f7SAndroid Build Coastguard Worker /// value to mask off its sign bit. The value will be <4 x 0x7fffffff> for f32
6481*03ce13f7SAndroid Build Coastguard Worker /// and v4f32, and <2 x 0x7fffffffffffffff> for f64. Construct it as vector of
6482*03ce13f7SAndroid Build Coastguard Worker /// ones logically right shifted one bit.
6483*03ce13f7SAndroid Build Coastguard Worker // TODO(stichnot): Fix the wala
6484*03ce13f7SAndroid Build Coastguard Worker // TODO: above, to represent vector constants in memory.
6485*03ce13f7SAndroid Build Coastguard Worker 
makeVectorOfFabsMask(Type Ty,RegNumT RegNum)6486*03ce13f7SAndroid Build Coastguard Worker Variable *TargetX8664::makeVectorOfFabsMask(Type Ty, RegNumT RegNum) {
6487*03ce13f7SAndroid Build Coastguard Worker   Variable *Reg = makeVectorOfMinusOnes(Ty, RegNum);
6488*03ce13f7SAndroid Build Coastguard Worker   _psrl(Reg, Ctx->getConstantInt8(1));
6489*03ce13f7SAndroid Build Coastguard Worker   return Reg;
6490*03ce13f7SAndroid Build Coastguard Worker }
6491*03ce13f7SAndroid Build Coastguard Worker 
getMemoryOperandForStackSlot(Type Ty,Variable * Slot,uint32_t Offset)6492*03ce13f7SAndroid Build Coastguard Worker X86OperandMem *TargetX8664::getMemoryOperandForStackSlot(Type Ty,
6493*03ce13f7SAndroid Build Coastguard Worker                                                          Variable *Slot,
6494*03ce13f7SAndroid Build Coastguard Worker                                                          uint32_t Offset) {
6495*03ce13f7SAndroid Build Coastguard Worker   // Ensure that Loc is a stack slot.
6496*03ce13f7SAndroid Build Coastguard Worker   assert(Slot->mustNotHaveReg());
6497*03ce13f7SAndroid Build Coastguard Worker   assert(Slot->getRegNum().hasNoValue());
6498*03ce13f7SAndroid Build Coastguard Worker   // Compute the location of Loc in memory.
6499*03ce13f7SAndroid Build Coastguard Worker   // TODO(wala,stichnot): lea should not
6500*03ce13f7SAndroid Build Coastguard Worker   // be required. The address of the stack slot is known at compile time
6501*03ce13f7SAndroid Build Coastguard Worker   // (although not until after addProlog()).
6502*03ce13f7SAndroid Build Coastguard Worker   const Type PointerType = getPointerType();
6503*03ce13f7SAndroid Build Coastguard Worker   Variable *Loc = makeReg(PointerType);
6504*03ce13f7SAndroid Build Coastguard Worker   _lea(Loc, Slot);
6505*03ce13f7SAndroid Build Coastguard Worker   Constant *ConstantOffset = Ctx->getConstantInt32(Offset);
6506*03ce13f7SAndroid Build Coastguard Worker   return X86OperandMem::create(Func, Ty, Loc, ConstantOffset);
6507*03ce13f7SAndroid Build Coastguard Worker }
6508*03ce13f7SAndroid Build Coastguard Worker 
6509*03ce13f7SAndroid Build Coastguard Worker /// Lowering helper to copy a scalar integer source operand into some 8-bit GPR.
6510*03ce13f7SAndroid Build Coastguard Worker /// Src is assumed to already be legalized.  If the source operand is known to
6511*03ce13f7SAndroid Build Coastguard Worker /// be a memory or immediate operand, a simple mov will suffice.  But if the
6512*03ce13f7SAndroid Build Coastguard Worker /// source operand can be a physical register, then it must first be copied into
6513*03ce13f7SAndroid Build Coastguard Worker /// a physical register that is truncable to 8-bit, then truncated into a
6514*03ce13f7SAndroid Build Coastguard Worker /// physical register that can receive a truncation, and finally copied into the
6515*03ce13f7SAndroid Build Coastguard Worker /// result 8-bit register (which in general can be any 8-bit register).  For
6516*03ce13f7SAndroid Build Coastguard Worker /// example, moving %ebp into %ah may be accomplished as:
6517*03ce13f7SAndroid Build Coastguard Worker ///   movl %ebp, %edx
6518*03ce13f7SAndroid Build Coastguard Worker ///   mov_trunc %edx, %dl  // this redundant assignment is ultimately elided
6519*03ce13f7SAndroid Build Coastguard Worker ///   movb %dl, %ah
6520*03ce13f7SAndroid Build Coastguard Worker /// On the other hand, moving a memory or immediate operand into ah:
6521*03ce13f7SAndroid Build Coastguard Worker ///   movb 4(%ebp), %ah
6522*03ce13f7SAndroid Build Coastguard Worker ///   movb $my_imm, %ah
6523*03ce13f7SAndroid Build Coastguard Worker ///
6524*03ce13f7SAndroid Build Coastguard Worker /// Note #1.  On a 64-bit target, the "movb 4(%ebp), %ah" is likely not
6525*03ce13f7SAndroid Build Coastguard Worker /// encodable, so RegNum=Reg_ah should NOT be given as an argument.  Instead,
6526*03ce13f7SAndroid Build Coastguard Worker /// use RegNum=RegNumT() and then let the caller do a separate copy into
6527*03ce13f7SAndroid Build Coastguard Worker /// Reg_ah.
6528*03ce13f7SAndroid Build Coastguard Worker ///
6529*03ce13f7SAndroid Build Coastguard Worker /// Note #2.  ConstantRelocatable operands are also put through this process
6530*03ce13f7SAndroid Build Coastguard Worker /// (not truncated directly) because our ELF emitter does R_386_32 relocations
6531*03ce13f7SAndroid Build Coastguard Worker /// but not R_386_8 relocations.
6532*03ce13f7SAndroid Build Coastguard Worker ///
6533*03ce13f7SAndroid Build Coastguard Worker /// Note #3.  If Src is a Variable, the result will be an infinite-weight i8
6534*03ce13f7SAndroid Build Coastguard Worker /// Variable with the RCX86_IsTrunc8Rcvr register class.  As such, this helper
6535*03ce13f7SAndroid Build Coastguard Worker /// is a convenient way to prevent ah/bh/ch/dh from being an (invalid) argument
6536*03ce13f7SAndroid Build Coastguard Worker /// to the pinsrb instruction.
6537*03ce13f7SAndroid Build Coastguard Worker 
copyToReg8(Operand * Src,RegNumT RegNum)6538*03ce13f7SAndroid Build Coastguard Worker Variable *TargetX8664::copyToReg8(Operand *Src, RegNumT RegNum) {
6539*03ce13f7SAndroid Build Coastguard Worker   Type Ty = Src->getType();
6540*03ce13f7SAndroid Build Coastguard Worker   assert(isScalarIntegerType(Ty));
6541*03ce13f7SAndroid Build Coastguard Worker   assert(Ty != IceType_i1);
6542*03ce13f7SAndroid Build Coastguard Worker   Variable *Reg = makeReg(IceType_i8, RegNum);
6543*03ce13f7SAndroid Build Coastguard Worker   Reg->setRegClass(RCX86_IsTrunc8Rcvr);
6544*03ce13f7SAndroid Build Coastguard Worker   if (llvm::isa<Variable>(Src) || llvm::isa<ConstantRelocatable>(Src)) {
6545*03ce13f7SAndroid Build Coastguard Worker     Variable *SrcTruncable = makeReg(Ty);
6546*03ce13f7SAndroid Build Coastguard Worker     switch (Ty) {
6547*03ce13f7SAndroid Build Coastguard Worker     case IceType_i64:
6548*03ce13f7SAndroid Build Coastguard Worker       SrcTruncable->setRegClass(RCX86_Is64To8);
6549*03ce13f7SAndroid Build Coastguard Worker       break;
6550*03ce13f7SAndroid Build Coastguard Worker     case IceType_i32:
6551*03ce13f7SAndroid Build Coastguard Worker       SrcTruncable->setRegClass(RCX86_Is32To8);
6552*03ce13f7SAndroid Build Coastguard Worker       break;
6553*03ce13f7SAndroid Build Coastguard Worker     case IceType_i16:
6554*03ce13f7SAndroid Build Coastguard Worker       SrcTruncable->setRegClass(RCX86_Is16To8);
6555*03ce13f7SAndroid Build Coastguard Worker       break;
6556*03ce13f7SAndroid Build Coastguard Worker     default:
6557*03ce13f7SAndroid Build Coastguard Worker       // i8 - just use default register class
6558*03ce13f7SAndroid Build Coastguard Worker       break;
6559*03ce13f7SAndroid Build Coastguard Worker     }
6560*03ce13f7SAndroid Build Coastguard Worker     Variable *SrcRcvr = makeReg(IceType_i8);
6561*03ce13f7SAndroid Build Coastguard Worker     SrcRcvr->setRegClass(RCX86_IsTrunc8Rcvr);
6562*03ce13f7SAndroid Build Coastguard Worker     _mov(SrcTruncable, Src);
6563*03ce13f7SAndroid Build Coastguard Worker     _mov(SrcRcvr, SrcTruncable);
6564*03ce13f7SAndroid Build Coastguard Worker     Src = SrcRcvr;
6565*03ce13f7SAndroid Build Coastguard Worker   }
6566*03ce13f7SAndroid Build Coastguard Worker   _mov(Reg, Src);
6567*03ce13f7SAndroid Build Coastguard Worker   return Reg;
6568*03ce13f7SAndroid Build Coastguard Worker }
6569*03ce13f7SAndroid Build Coastguard Worker 
6570*03ce13f7SAndroid Build Coastguard Worker /// Helper for legalize() to emit the right code to lower an operand to a
6571*03ce13f7SAndroid Build Coastguard Worker /// register of the appropriate type.
6572*03ce13f7SAndroid Build Coastguard Worker 
copyToReg(Operand * Src,RegNumT RegNum)6573*03ce13f7SAndroid Build Coastguard Worker Variable *TargetX8664::copyToReg(Operand *Src, RegNumT RegNum) {
6574*03ce13f7SAndroid Build Coastguard Worker   Type Ty = Src->getType();
6575*03ce13f7SAndroid Build Coastguard Worker   Variable *Reg = makeReg(Ty, RegNum);
6576*03ce13f7SAndroid Build Coastguard Worker   if (isVectorType(Ty)) {
6577*03ce13f7SAndroid Build Coastguard Worker     _movp(Reg, Src);
6578*03ce13f7SAndroid Build Coastguard Worker   } else {
6579*03ce13f7SAndroid Build Coastguard Worker     _mov(Reg, Src);
6580*03ce13f7SAndroid Build Coastguard Worker   }
6581*03ce13f7SAndroid Build Coastguard Worker   return Reg;
6582*03ce13f7SAndroid Build Coastguard Worker }
6583*03ce13f7SAndroid Build Coastguard Worker 
legalize(Operand * From,LegalMask Allowed,RegNumT RegNum)6584*03ce13f7SAndroid Build Coastguard Worker Operand *TargetX8664::legalize(Operand *From, LegalMask Allowed,
6585*03ce13f7SAndroid Build Coastguard Worker                                RegNumT RegNum) {
6586*03ce13f7SAndroid Build Coastguard Worker   const Type Ty = From->getType();
6587*03ce13f7SAndroid Build Coastguard Worker   // Assert that a physical register is allowed. To date, all calls to
6588*03ce13f7SAndroid Build Coastguard Worker   // legalize() allow a physical register. If a physical register needs to be
6589*03ce13f7SAndroid Build Coastguard Worker   // explicitly disallowed, then new code will need to be written to force a
6590*03ce13f7SAndroid Build Coastguard Worker   // spill.
6591*03ce13f7SAndroid Build Coastguard Worker   assert(Allowed & Legal_Reg);
6592*03ce13f7SAndroid Build Coastguard Worker   // If we're asking for a specific physical register, make sure we're not
6593*03ce13f7SAndroid Build Coastguard Worker   // allowing any other operand kinds. (This could be future work, e.g. allow
6594*03ce13f7SAndroid Build Coastguard Worker   // the shl shift amount to be either an immediate or in ecx.)
6595*03ce13f7SAndroid Build Coastguard Worker   assert(RegNum.hasNoValue() || Allowed == Legal_Reg);
6596*03ce13f7SAndroid Build Coastguard Worker 
6597*03ce13f7SAndroid Build Coastguard Worker   // Substitute with an available infinite-weight variable if possible.  Only do
6598*03ce13f7SAndroid Build Coastguard Worker   // this when we are not asking for a specific register, and when the
6599*03ce13f7SAndroid Build Coastguard Worker   // substitution is not locked to a specific register, and when the types
6600*03ce13f7SAndroid Build Coastguard Worker   // match, in order to capture the vast majority of opportunities and avoid
6601*03ce13f7SAndroid Build Coastguard Worker   // corner cases in the lowering.
6602*03ce13f7SAndroid Build Coastguard Worker   if (RegNum.hasNoValue()) {
6603*03ce13f7SAndroid Build Coastguard Worker     if (Variable *Subst = getContext().availabilityGet(From)) {
6604*03ce13f7SAndroid Build Coastguard Worker       // At this point we know there is a potential substitution available.
6605*03ce13f7SAndroid Build Coastguard Worker       if (Subst->mustHaveReg() && !Subst->hasReg()) {
6606*03ce13f7SAndroid Build Coastguard Worker         // At this point we know the substitution will have a register.
6607*03ce13f7SAndroid Build Coastguard Worker         if (From->getType() == Subst->getType()) {
6608*03ce13f7SAndroid Build Coastguard Worker           // At this point we know the substitution's register is compatible.
6609*03ce13f7SAndroid Build Coastguard Worker           return Subst;
6610*03ce13f7SAndroid Build Coastguard Worker         }
6611*03ce13f7SAndroid Build Coastguard Worker       }
6612*03ce13f7SAndroid Build Coastguard Worker     }
6613*03ce13f7SAndroid Build Coastguard Worker   }
6614*03ce13f7SAndroid Build Coastguard Worker 
6615*03ce13f7SAndroid Build Coastguard Worker   if (auto *Mem = llvm::dyn_cast<X86OperandMem>(From)) {
6616*03ce13f7SAndroid Build Coastguard Worker     // Before doing anything with a Mem operand, we need to ensure that the
6617*03ce13f7SAndroid Build Coastguard Worker     // Base and Index components are in physical registers.
6618*03ce13f7SAndroid Build Coastguard Worker     Variable *Base = Mem->getBase();
6619*03ce13f7SAndroid Build Coastguard Worker     Variable *Index = Mem->getIndex();
6620*03ce13f7SAndroid Build Coastguard Worker     Constant *Offset = Mem->getOffset();
6621*03ce13f7SAndroid Build Coastguard Worker     Variable *RegBase = nullptr;
6622*03ce13f7SAndroid Build Coastguard Worker     Variable *RegIndex = nullptr;
6623*03ce13f7SAndroid Build Coastguard Worker     uint16_t Shift = Mem->getShift();
6624*03ce13f7SAndroid Build Coastguard Worker     if (Base) {
6625*03ce13f7SAndroid Build Coastguard Worker       RegBase = llvm::cast<Variable>(
6626*03ce13f7SAndroid Build Coastguard Worker           legalize(Base, Legal_Reg | Legal_Rematerializable));
6627*03ce13f7SAndroid Build Coastguard Worker     }
6628*03ce13f7SAndroid Build Coastguard Worker     if (Index) {
6629*03ce13f7SAndroid Build Coastguard Worker       // TODO(jpp): perhaps we should only allow Legal_Reg if
6630*03ce13f7SAndroid Build Coastguard Worker       // Base->isRematerializable.
6631*03ce13f7SAndroid Build Coastguard Worker       RegIndex = llvm::cast<Variable>(
6632*03ce13f7SAndroid Build Coastguard Worker           legalize(Index, Legal_Reg | Legal_Rematerializable));
6633*03ce13f7SAndroid Build Coastguard Worker     }
6634*03ce13f7SAndroid Build Coastguard Worker 
6635*03ce13f7SAndroid Build Coastguard Worker     if (Base != RegBase || Index != RegIndex) {
6636*03ce13f7SAndroid Build Coastguard Worker       Mem = X86OperandMem::create(Func, Ty, RegBase, Offset, RegIndex, Shift,
6637*03ce13f7SAndroid Build Coastguard Worker                                   Mem->getSegmentRegister());
6638*03ce13f7SAndroid Build Coastguard Worker     }
6639*03ce13f7SAndroid Build Coastguard Worker 
6640*03ce13f7SAndroid Build Coastguard Worker     From = Mem;
6641*03ce13f7SAndroid Build Coastguard Worker 
6642*03ce13f7SAndroid Build Coastguard Worker     if (!(Allowed & Legal_Mem)) {
6643*03ce13f7SAndroid Build Coastguard Worker       From = copyToReg(From, RegNum);
6644*03ce13f7SAndroid Build Coastguard Worker     }
6645*03ce13f7SAndroid Build Coastguard Worker     return From;
6646*03ce13f7SAndroid Build Coastguard Worker   }
6647*03ce13f7SAndroid Build Coastguard Worker 
6648*03ce13f7SAndroid Build Coastguard Worker   if (auto *Const = llvm::dyn_cast<Constant>(From)) {
6649*03ce13f7SAndroid Build Coastguard Worker     if (llvm::isa<ConstantUndef>(Const)) {
6650*03ce13f7SAndroid Build Coastguard Worker       From = legalizeUndef(Const, RegNum);
6651*03ce13f7SAndroid Build Coastguard Worker       if (isVectorType(Ty))
6652*03ce13f7SAndroid Build Coastguard Worker         return From;
6653*03ce13f7SAndroid Build Coastguard Worker       Const = llvm::cast<Constant>(From);
6654*03ce13f7SAndroid Build Coastguard Worker     }
6655*03ce13f7SAndroid Build Coastguard Worker     // There should be no constants of vector type (other than undef).
6656*03ce13f7SAndroid Build Coastguard Worker     assert(!isVectorType(Ty));
6657*03ce13f7SAndroid Build Coastguard Worker 
6658*03ce13f7SAndroid Build Coastguard Worker     // If the operand is a 64 bit constant integer we need to legalize it to a
6659*03ce13f7SAndroid Build Coastguard Worker     // register in x86-64.
6660*03ce13f7SAndroid Build Coastguard Worker     if (auto *C64 = llvm::dyn_cast<ConstantInteger64>(Const)) {
6661*03ce13f7SAndroid Build Coastguard Worker       if (!Utils::IsInt(32, C64->getValue())) {
6662*03ce13f7SAndroid Build Coastguard Worker         if (RegNum.hasValue()) {
6663*03ce13f7SAndroid Build Coastguard Worker           assert(RegX8664::getGprForType(IceType_i64, RegNum) == RegNum);
6664*03ce13f7SAndroid Build Coastguard Worker         }
6665*03ce13f7SAndroid Build Coastguard Worker         return copyToReg(Const, RegNum);
6666*03ce13f7SAndroid Build Coastguard Worker       }
6667*03ce13f7SAndroid Build Coastguard Worker     }
6668*03ce13f7SAndroid Build Coastguard Worker 
6669*03ce13f7SAndroid Build Coastguard Worker     if (!llvm::dyn_cast<ConstantRelocatable>(Const)) {
6670*03ce13f7SAndroid Build Coastguard Worker       if (isScalarFloatingType(Ty)) {
6671*03ce13f7SAndroid Build Coastguard Worker         // Convert a scalar floating point constant into an explicit memory
6672*03ce13f7SAndroid Build Coastguard Worker         // operand.
6673*03ce13f7SAndroid Build Coastguard Worker         if (auto *ConstFloat = llvm::dyn_cast<ConstantFloat>(Const)) {
6674*03ce13f7SAndroid Build Coastguard Worker           if (Utils::isPositiveZero(ConstFloat->getValue()))
6675*03ce13f7SAndroid Build Coastguard Worker             return makeZeroedRegister(Ty, RegNum);
6676*03ce13f7SAndroid Build Coastguard Worker         } else if (auto *ConstDouble = llvm::dyn_cast<ConstantDouble>(Const)) {
6677*03ce13f7SAndroid Build Coastguard Worker           if (Utils::isPositiveZero(ConstDouble->getValue()))
6678*03ce13f7SAndroid Build Coastguard Worker             return makeZeroedRegister(Ty, RegNum);
6679*03ce13f7SAndroid Build Coastguard Worker         }
6680*03ce13f7SAndroid Build Coastguard Worker 
6681*03ce13f7SAndroid Build Coastguard Worker         auto *CFrom = llvm::cast<Constant>(From);
6682*03ce13f7SAndroid Build Coastguard Worker         assert(CFrom->getShouldBePooled());
6683*03ce13f7SAndroid Build Coastguard Worker         Constant *Offset = Ctx->getConstantSym(0, CFrom->getLabelName());
6684*03ce13f7SAndroid Build Coastguard Worker         auto *Mem = X86OperandMem::create(Func, Ty, nullptr, Offset);
6685*03ce13f7SAndroid Build Coastguard Worker         From = Mem;
6686*03ce13f7SAndroid Build Coastguard Worker       }
6687*03ce13f7SAndroid Build Coastguard Worker     }
6688*03ce13f7SAndroid Build Coastguard Worker 
6689*03ce13f7SAndroid Build Coastguard Worker     bool NeedsReg = false;
6690*03ce13f7SAndroid Build Coastguard Worker     if (!(Allowed & Legal_Imm) && !isScalarFloatingType(Ty))
6691*03ce13f7SAndroid Build Coastguard Worker       // Immediate specifically not allowed.
6692*03ce13f7SAndroid Build Coastguard Worker       NeedsReg = true;
6693*03ce13f7SAndroid Build Coastguard Worker     if (!(Allowed & Legal_Mem) && isScalarFloatingType(Ty))
6694*03ce13f7SAndroid Build Coastguard Worker       // On x86, FP constants are lowered to mem operands.
6695*03ce13f7SAndroid Build Coastguard Worker       NeedsReg = true;
6696*03ce13f7SAndroid Build Coastguard Worker     if (NeedsReg) {
6697*03ce13f7SAndroid Build Coastguard Worker       From = copyToReg(From, RegNum);
6698*03ce13f7SAndroid Build Coastguard Worker     }
6699*03ce13f7SAndroid Build Coastguard Worker     return From;
6700*03ce13f7SAndroid Build Coastguard Worker   }
6701*03ce13f7SAndroid Build Coastguard Worker 
6702*03ce13f7SAndroid Build Coastguard Worker   if (auto *Var = llvm::dyn_cast<Variable>(From)) {
6703*03ce13f7SAndroid Build Coastguard Worker     // Check if the variable is guaranteed a physical register. This can happen
6704*03ce13f7SAndroid Build Coastguard Worker     // either when the variable is pre-colored or when it is assigned infinite
6705*03ce13f7SAndroid Build Coastguard Worker     // weight.
6706*03ce13f7SAndroid Build Coastguard Worker     bool MustHaveRegister = (Var->hasReg() || Var->mustHaveReg());
6707*03ce13f7SAndroid Build Coastguard Worker     bool MustRematerialize =
6708*03ce13f7SAndroid Build Coastguard Worker         (Var->isRematerializable() && !(Allowed & Legal_Rematerializable));
6709*03ce13f7SAndroid Build Coastguard Worker     // We need a new physical register for the operand if:
6710*03ce13f7SAndroid Build Coastguard Worker     // - Mem is not allowed and Var isn't guaranteed a physical register, or
6711*03ce13f7SAndroid Build Coastguard Worker     // - RegNum is required and Var->getRegNum() doesn't match, or
6712*03ce13f7SAndroid Build Coastguard Worker     // - Var is a rematerializable variable and rematerializable pass-through is
6713*03ce13f7SAndroid Build Coastguard Worker     //   not allowed (in which case we need a lea instruction).
6714*03ce13f7SAndroid Build Coastguard Worker     if (MustRematerialize) {
6715*03ce13f7SAndroid Build Coastguard Worker       Variable *NewVar = makeReg(Ty, RegNum);
6716*03ce13f7SAndroid Build Coastguard Worker       // Since Var is rematerializable, the offset will be added when the lea is
6717*03ce13f7SAndroid Build Coastguard Worker       // emitted.
6718*03ce13f7SAndroid Build Coastguard Worker       constexpr Constant *NoOffset = nullptr;
6719*03ce13f7SAndroid Build Coastguard Worker       auto *Mem = X86OperandMem::create(Func, Ty, Var, NoOffset);
6720*03ce13f7SAndroid Build Coastguard Worker       _lea(NewVar, Mem);
6721*03ce13f7SAndroid Build Coastguard Worker       From = NewVar;
6722*03ce13f7SAndroid Build Coastguard Worker     } else if ((!(Allowed & Legal_Mem) && !MustHaveRegister) ||
6723*03ce13f7SAndroid Build Coastguard Worker                (RegNum.hasValue() && RegNum != Var->getRegNum())) {
6724*03ce13f7SAndroid Build Coastguard Worker       From = copyToReg(From, RegNum);
6725*03ce13f7SAndroid Build Coastguard Worker     }
6726*03ce13f7SAndroid Build Coastguard Worker     return From;
6727*03ce13f7SAndroid Build Coastguard Worker   }
6728*03ce13f7SAndroid Build Coastguard Worker 
6729*03ce13f7SAndroid Build Coastguard Worker   llvm::report_fatal_error("Unhandled operand kind in legalize()");
6730*03ce13f7SAndroid Build Coastguard Worker   return From;
6731*03ce13f7SAndroid Build Coastguard Worker }
6732*03ce13f7SAndroid Build Coastguard Worker 
6733*03ce13f7SAndroid Build Coastguard Worker /// Provide a trivial wrapper to legalize() for this common usage.
6734*03ce13f7SAndroid Build Coastguard Worker 
legalizeToReg(Operand * From,RegNumT RegNum)6735*03ce13f7SAndroid Build Coastguard Worker Variable *TargetX8664::legalizeToReg(Operand *From, RegNumT RegNum) {
6736*03ce13f7SAndroid Build Coastguard Worker   return llvm::cast<Variable>(legalize(From, Legal_Reg, RegNum));
6737*03ce13f7SAndroid Build Coastguard Worker }
6738*03ce13f7SAndroid Build Coastguard Worker 
6739*03ce13f7SAndroid Build Coastguard Worker /// Legalize undef values to concrete values.
6740*03ce13f7SAndroid Build Coastguard Worker 
legalizeUndef(Operand * From,RegNumT RegNum)6741*03ce13f7SAndroid Build Coastguard Worker Operand *TargetX8664::legalizeUndef(Operand *From, RegNumT RegNum) {
6742*03ce13f7SAndroid Build Coastguard Worker   Type Ty = From->getType();
6743*03ce13f7SAndroid Build Coastguard Worker   if (llvm::isa<ConstantUndef>(From)) {
6744*03ce13f7SAndroid Build Coastguard Worker     // Lower undefs to zero.  Another option is to lower undefs to an
6745*03ce13f7SAndroid Build Coastguard Worker     // uninitialized register; however, using an uninitialized register results
6746*03ce13f7SAndroid Build Coastguard Worker     // in less predictable code.
6747*03ce13f7SAndroid Build Coastguard Worker     //
6748*03ce13f7SAndroid Build Coastguard Worker     // If in the future the implementation is changed to lower undef values to
6749*03ce13f7SAndroid Build Coastguard Worker     // uninitialized registers, a FakeDef will be needed:
6750*03ce13f7SAndroid Build Coastguard Worker     //     Context.insert<InstFakeDef>(Reg);
6751*03ce13f7SAndroid Build Coastguard Worker     // This is in order to ensure that the live range of Reg is not
6752*03ce13f7SAndroid Build Coastguard Worker     // overestimated.  If the constant being lowered is a 64 bit value, then
6753*03ce13f7SAndroid Build Coastguard Worker     // the result should be split and the lo and hi components will need to go
6754*03ce13f7SAndroid Build Coastguard Worker     // in uninitialized registers.
6755*03ce13f7SAndroid Build Coastguard Worker     if (isVectorType(Ty))
6756*03ce13f7SAndroid Build Coastguard Worker       return makeVectorOfZeros(Ty, RegNum);
6757*03ce13f7SAndroid Build Coastguard Worker     return Ctx->getConstantZero(Ty);
6758*03ce13f7SAndroid Build Coastguard Worker   }
6759*03ce13f7SAndroid Build Coastguard Worker   return From;
6760*03ce13f7SAndroid Build Coastguard Worker }
6761*03ce13f7SAndroid Build Coastguard Worker 
6762*03ce13f7SAndroid Build Coastguard Worker /// For the cmp instruction, if Src1 is an immediate, or known to be a physical
6763*03ce13f7SAndroid Build Coastguard Worker /// register, we can allow Src0 to be a memory operand. Otherwise, Src0 must be
6764*03ce13f7SAndroid Build Coastguard Worker /// copied into a physical register. (Actually, either Src0 or Src1 can be
6765*03ce13f7SAndroid Build Coastguard Worker /// chosen for the physical register, but unfortunately we have to commit to one
6766*03ce13f7SAndroid Build Coastguard Worker /// or the other before register allocation.)
6767*03ce13f7SAndroid Build Coastguard Worker 
legalizeSrc0ForCmp(Operand * Src0,Operand * Src1)6768*03ce13f7SAndroid Build Coastguard Worker Operand *TargetX8664::legalizeSrc0ForCmp(Operand *Src0, Operand *Src1) {
6769*03ce13f7SAndroid Build Coastguard Worker   bool IsSrc1ImmOrReg = false;
6770*03ce13f7SAndroid Build Coastguard Worker   if (llvm::isa<Constant>(Src1)) {
6771*03ce13f7SAndroid Build Coastguard Worker     IsSrc1ImmOrReg = true;
6772*03ce13f7SAndroid Build Coastguard Worker   } else if (auto *Var = llvm::dyn_cast<Variable>(Src1)) {
6773*03ce13f7SAndroid Build Coastguard Worker     if (Var->hasReg())
6774*03ce13f7SAndroid Build Coastguard Worker       IsSrc1ImmOrReg = true;
6775*03ce13f7SAndroid Build Coastguard Worker   }
6776*03ce13f7SAndroid Build Coastguard Worker   return legalize(Src0, IsSrc1ImmOrReg ? (Legal_Reg | Legal_Mem) : Legal_Reg);
6777*03ce13f7SAndroid Build Coastguard Worker }
6778*03ce13f7SAndroid Build Coastguard Worker 
formMemoryOperand(Operand * Opnd,Type Ty,bool DoLegalize)6779*03ce13f7SAndroid Build Coastguard Worker X86OperandMem *TargetX8664::formMemoryOperand(Operand *Opnd, Type Ty,
6780*03ce13f7SAndroid Build Coastguard Worker                                               bool DoLegalize) {
6781*03ce13f7SAndroid Build Coastguard Worker   auto *Mem = llvm::dyn_cast<X86OperandMem>(Opnd);
6782*03ce13f7SAndroid Build Coastguard Worker   // It may be the case that address mode optimization already creates an
6783*03ce13f7SAndroid Build Coastguard Worker   // X86OperandMem, so in that case it wouldn't need another level of
6784*03ce13f7SAndroid Build Coastguard Worker   // transformation.
6785*03ce13f7SAndroid Build Coastguard Worker   if (!Mem) {
6786*03ce13f7SAndroid Build Coastguard Worker     auto *Base = llvm::dyn_cast<Variable>(Opnd);
6787*03ce13f7SAndroid Build Coastguard Worker     auto *Offset = llvm::dyn_cast<Constant>(Opnd);
6788*03ce13f7SAndroid Build Coastguard Worker     assert(Base || Offset);
6789*03ce13f7SAndroid Build Coastguard Worker     if (Offset) {
6790*03ce13f7SAndroid Build Coastguard Worker       if (!llvm::isa<ConstantRelocatable>(Offset)) {
6791*03ce13f7SAndroid Build Coastguard Worker         if (llvm::isa<ConstantInteger64>(Offset)) {
6792*03ce13f7SAndroid Build Coastguard Worker           // Memory operands cannot have 64-bit immediates, so they must be
6793*03ce13f7SAndroid Build Coastguard Worker           // legalized into a register only.
6794*03ce13f7SAndroid Build Coastguard Worker           Base = llvm::cast<Variable>(legalize(Offset, Legal_Reg));
6795*03ce13f7SAndroid Build Coastguard Worker           Offset = nullptr;
6796*03ce13f7SAndroid Build Coastguard Worker         } else {
6797*03ce13f7SAndroid Build Coastguard Worker           Offset = llvm::cast<Constant>(legalize(Offset));
6798*03ce13f7SAndroid Build Coastguard Worker 
6799*03ce13f7SAndroid Build Coastguard Worker           assert(llvm::isa<ConstantInteger32>(Offset) ||
6800*03ce13f7SAndroid Build Coastguard Worker                  llvm::isa<ConstantRelocatable>(Offset));
6801*03ce13f7SAndroid Build Coastguard Worker         }
6802*03ce13f7SAndroid Build Coastguard Worker       }
6803*03ce13f7SAndroid Build Coastguard Worker     }
6804*03ce13f7SAndroid Build Coastguard Worker     Mem = X86OperandMem::create(Func, Ty, Base, Offset);
6805*03ce13f7SAndroid Build Coastguard Worker   }
6806*03ce13f7SAndroid Build Coastguard Worker   return llvm::cast<X86OperandMem>(DoLegalize ? legalize(Mem) : Mem);
6807*03ce13f7SAndroid Build Coastguard Worker }
6808*03ce13f7SAndroid Build Coastguard Worker 
makeReg(Type Type,RegNumT RegNum)6809*03ce13f7SAndroid Build Coastguard Worker Variable *TargetX8664::makeReg(Type Type, RegNumT RegNum) {
6810*03ce13f7SAndroid Build Coastguard Worker   Variable *Reg = Func->makeVariable(Type);
6811*03ce13f7SAndroid Build Coastguard Worker   if (RegNum.hasValue())
6812*03ce13f7SAndroid Build Coastguard Worker     Reg->setRegNum(RegNum);
6813*03ce13f7SAndroid Build Coastguard Worker   else
6814*03ce13f7SAndroid Build Coastguard Worker     Reg->setMustHaveReg();
6815*03ce13f7SAndroid Build Coastguard Worker   return Reg;
6816*03ce13f7SAndroid Build Coastguard Worker }
6817*03ce13f7SAndroid Build Coastguard Worker 
6818*03ce13f7SAndroid Build Coastguard Worker const Type TypeForSize[] = {IceType_i8, IceType_i16, IceType_i32, IceType_f64,
6819*03ce13f7SAndroid Build Coastguard Worker                             IceType_v16i8};
6820*03ce13f7SAndroid Build Coastguard Worker 
largestTypeInSize(uint32_t Size,uint32_t MaxSize)6821*03ce13f7SAndroid Build Coastguard Worker Type TargetX8664::largestTypeInSize(uint32_t Size, uint32_t MaxSize) {
6822*03ce13f7SAndroid Build Coastguard Worker   assert(Size != 0);
6823*03ce13f7SAndroid Build Coastguard Worker   uint32_t TyIndex = llvm::findLastSet(Size, llvm::ZB_Undefined);
6824*03ce13f7SAndroid Build Coastguard Worker   uint32_t MaxIndex = MaxSize == NoSizeLimit
6825*03ce13f7SAndroid Build Coastguard Worker                           ? llvm::array_lengthof(TypeForSize) - 1
6826*03ce13f7SAndroid Build Coastguard Worker                           : llvm::findLastSet(MaxSize, llvm::ZB_Undefined);
6827*03ce13f7SAndroid Build Coastguard Worker   return TypeForSize[std::min(TyIndex, MaxIndex)];
6828*03ce13f7SAndroid Build Coastguard Worker }
6829*03ce13f7SAndroid Build Coastguard Worker 
firstTypeThatFitsSize(uint32_t Size,uint32_t MaxSize)6830*03ce13f7SAndroid Build Coastguard Worker Type TargetX8664::firstTypeThatFitsSize(uint32_t Size, uint32_t MaxSize) {
6831*03ce13f7SAndroid Build Coastguard Worker   assert(Size != 0);
6832*03ce13f7SAndroid Build Coastguard Worker   uint32_t TyIndex = llvm::findLastSet(Size, llvm::ZB_Undefined);
6833*03ce13f7SAndroid Build Coastguard Worker   if (!llvm::isPowerOf2_32(Size))
6834*03ce13f7SAndroid Build Coastguard Worker     ++TyIndex;
6835*03ce13f7SAndroid Build Coastguard Worker   uint32_t MaxIndex = MaxSize == NoSizeLimit
6836*03ce13f7SAndroid Build Coastguard Worker                           ? llvm::array_lengthof(TypeForSize) - 1
6837*03ce13f7SAndroid Build Coastguard Worker                           : llvm::findLastSet(MaxSize, llvm::ZB_Undefined);
6838*03ce13f7SAndroid Build Coastguard Worker   return TypeForSize[std::min(TyIndex, MaxIndex)];
6839*03ce13f7SAndroid Build Coastguard Worker }
6840*03ce13f7SAndroid Build Coastguard Worker 
postLower()6841*03ce13f7SAndroid Build Coastguard Worker void TargetX8664::postLower() {
6842*03ce13f7SAndroid Build Coastguard Worker   if (Func->getOptLevel() == Opt_m1)
6843*03ce13f7SAndroid Build Coastguard Worker     return;
6844*03ce13f7SAndroid Build Coastguard Worker   markRedefinitions();
6845*03ce13f7SAndroid Build Coastguard Worker   Context.availabilityUpdate();
6846*03ce13f7SAndroid Build Coastguard Worker }
6847*03ce13f7SAndroid Build Coastguard Worker 
emit(const ConstantInteger32 * C) const6848*03ce13f7SAndroid Build Coastguard Worker void TargetX8664::emit(const ConstantInteger32 *C) const {
6849*03ce13f7SAndroid Build Coastguard Worker   if (!BuildDefs::dump())
6850*03ce13f7SAndroid Build Coastguard Worker     return;
6851*03ce13f7SAndroid Build Coastguard Worker   Ostream &Str = Ctx->getStrEmit();
6852*03ce13f7SAndroid Build Coastguard Worker   Str << "$" << C->getValue();
6853*03ce13f7SAndroid Build Coastguard Worker }
6854*03ce13f7SAndroid Build Coastguard Worker 
emit(const ConstantInteger64 * C) const6855*03ce13f7SAndroid Build Coastguard Worker void TargetX8664::emit(const ConstantInteger64 *C) const {
6856*03ce13f7SAndroid Build Coastguard Worker   if (!BuildDefs::dump())
6857*03ce13f7SAndroid Build Coastguard Worker     return;
6858*03ce13f7SAndroid Build Coastguard Worker   Ostream &Str = Ctx->getStrEmit();
6859*03ce13f7SAndroid Build Coastguard Worker   Str << "$" << C->getValue();
6860*03ce13f7SAndroid Build Coastguard Worker }
6861*03ce13f7SAndroid Build Coastguard Worker 
emit(const ConstantFloat * C) const6862*03ce13f7SAndroid Build Coastguard Worker void TargetX8664::emit(const ConstantFloat *C) const {
6863*03ce13f7SAndroid Build Coastguard Worker   if (!BuildDefs::dump())
6864*03ce13f7SAndroid Build Coastguard Worker     return;
6865*03ce13f7SAndroid Build Coastguard Worker   Ostream &Str = Ctx->getStrEmit();
6866*03ce13f7SAndroid Build Coastguard Worker   Str << C->getLabelName();
6867*03ce13f7SAndroid Build Coastguard Worker }
6868*03ce13f7SAndroid Build Coastguard Worker 
emit(const ConstantDouble * C) const6869*03ce13f7SAndroid Build Coastguard Worker void TargetX8664::emit(const ConstantDouble *C) const {
6870*03ce13f7SAndroid Build Coastguard Worker   if (!BuildDefs::dump())
6871*03ce13f7SAndroid Build Coastguard Worker     return;
6872*03ce13f7SAndroid Build Coastguard Worker   Ostream &Str = Ctx->getStrEmit();
6873*03ce13f7SAndroid Build Coastguard Worker   Str << C->getLabelName();
6874*03ce13f7SAndroid Build Coastguard Worker }
6875*03ce13f7SAndroid Build Coastguard Worker 
emit(const ConstantUndef *) const6876*03ce13f7SAndroid Build Coastguard Worker void TargetX8664::emit(const ConstantUndef *) const {
6877*03ce13f7SAndroid Build Coastguard Worker   llvm::report_fatal_error("undef value encountered by emitter.");
6878*03ce13f7SAndroid Build Coastguard Worker }
6879*03ce13f7SAndroid Build Coastguard Worker 
emit(const ConstantRelocatable * C) const6880*03ce13f7SAndroid Build Coastguard Worker void TargetX8664::emit(const ConstantRelocatable *C) const {
6881*03ce13f7SAndroid Build Coastguard Worker   if (!BuildDefs::dump())
6882*03ce13f7SAndroid Build Coastguard Worker     return;
6883*03ce13f7SAndroid Build Coastguard Worker   Ostream &Str = Ctx->getStrEmit();
6884*03ce13f7SAndroid Build Coastguard Worker   Str << "$";
6885*03ce13f7SAndroid Build Coastguard Worker   emitWithoutPrefix(C);
6886*03ce13f7SAndroid Build Coastguard Worker }
6887*03ce13f7SAndroid Build Coastguard Worker 
emitJumpTable(const Cfg *,const InstJumpTable * JumpTable) const6888*03ce13f7SAndroid Build Coastguard Worker void TargetX8664::emitJumpTable(const Cfg *,
6889*03ce13f7SAndroid Build Coastguard Worker                                 const InstJumpTable *JumpTable) const {
6890*03ce13f7SAndroid Build Coastguard Worker   if (!BuildDefs::dump())
6891*03ce13f7SAndroid Build Coastguard Worker     return;
6892*03ce13f7SAndroid Build Coastguard Worker   Ostream &Str = Ctx->getStrEmit();
6893*03ce13f7SAndroid Build Coastguard Worker   Str << "\t.section\t.rodata." << JumpTable->getSectionName()
6894*03ce13f7SAndroid Build Coastguard Worker       << ",\"a\",@progbits\n"
6895*03ce13f7SAndroid Build Coastguard Worker          "\t.align\t"
6896*03ce13f7SAndroid Build Coastguard Worker       << typeWidthInBytes(getPointerType()) << "\n"
6897*03ce13f7SAndroid Build Coastguard Worker       << JumpTable->getName() << ":";
6898*03ce13f7SAndroid Build Coastguard Worker 
6899*03ce13f7SAndroid Build Coastguard Worker   for (SizeT I = 0; I < JumpTable->getNumTargets(); ++I)
6900*03ce13f7SAndroid Build Coastguard Worker     Str << "\n\t.var\t" << JumpTable->getTarget(I)->getAsmName();
6901*03ce13f7SAndroid Build Coastguard Worker   Str << "\n";
6902*03ce13f7SAndroid Build Coastguard Worker }
6903*03ce13f7SAndroid Build Coastguard Worker 
6904*03ce13f7SAndroid Build Coastguard Worker const TargetX8664::TableFcmpType TargetX8664::TableFcmp[] = {
6905*03ce13f7SAndroid Build Coastguard Worker #define X(val, dflt, swapS, C1, C2, swapV, pred)                               \
6906*03ce13f7SAndroid Build Coastguard Worker   {dflt, swapS, CondX86::C1, CondX86::C2, swapV, CondX86::pred},
6907*03ce13f7SAndroid Build Coastguard Worker     FCMPX8664_TABLE
6908*03ce13f7SAndroid Build Coastguard Worker #undef X
6909*03ce13f7SAndroid Build Coastguard Worker };
6910*03ce13f7SAndroid Build Coastguard Worker 
6911*03ce13f7SAndroid Build Coastguard Worker const size_t TargetX8664::TableFcmpSize = llvm::array_lengthof(TableFcmp);
6912*03ce13f7SAndroid Build Coastguard Worker 
6913*03ce13f7SAndroid Build Coastguard Worker const TargetX8664::TableIcmp32Type TargetX8664::TableIcmp32[] = {
6914*03ce13f7SAndroid Build Coastguard Worker #define X(val, C_32, C1_64, C2_64, C3_64) {CondX86::C_32},
6915*03ce13f7SAndroid Build Coastguard Worker     ICMPX8664_TABLE
6916*03ce13f7SAndroid Build Coastguard Worker #undef X
6917*03ce13f7SAndroid Build Coastguard Worker };
6918*03ce13f7SAndroid Build Coastguard Worker 
6919*03ce13f7SAndroid Build Coastguard Worker const size_t TargetX8664::TableIcmp32Size = llvm::array_lengthof(TableIcmp32);
6920*03ce13f7SAndroid Build Coastguard Worker 
6921*03ce13f7SAndroid Build Coastguard Worker std::array<SmallBitVector, RCX86_NUM> TargetX8664::TypeToRegisterSet = {{}};
6922*03ce13f7SAndroid Build Coastguard Worker 
6923*03ce13f7SAndroid Build Coastguard Worker std::array<SmallBitVector, RCX86_NUM> TargetX8664::TypeToRegisterSetUnfiltered =
6924*03ce13f7SAndroid Build Coastguard Worker     {{}};
6925*03ce13f7SAndroid Build Coastguard Worker 
6926*03ce13f7SAndroid Build Coastguard Worker std::array<SmallBitVector, RegX8664::Reg_NUM> TargetX8664::RegisterAliases = {
6927*03ce13f7SAndroid Build Coastguard Worker     {}};
6928*03ce13f7SAndroid Build Coastguard Worker 
6929*03ce13f7SAndroid Build Coastguard Worker template <typename T>
emitConstantPool(GlobalContext * Ctx)6930*03ce13f7SAndroid Build Coastguard Worker void TargetDataX8664::emitConstantPool(GlobalContext *Ctx) {
6931*03ce13f7SAndroid Build Coastguard Worker   if (!BuildDefs::dump())
6932*03ce13f7SAndroid Build Coastguard Worker     return;
6933*03ce13f7SAndroid Build Coastguard Worker   Ostream &Str = Ctx->getStrEmit();
6934*03ce13f7SAndroid Build Coastguard Worker   Type Ty = T::Ty;
6935*03ce13f7SAndroid Build Coastguard Worker   SizeT Align = typeAlignInBytes(Ty);
6936*03ce13f7SAndroid Build Coastguard Worker   ConstantList Pool = Ctx->getConstantPool(Ty);
6937*03ce13f7SAndroid Build Coastguard Worker 
6938*03ce13f7SAndroid Build Coastguard Worker   Str << "\t.section\t.rodata.cst" << Align << ",\"aM\",@progbits," << Align
6939*03ce13f7SAndroid Build Coastguard Worker       << "\n";
6940*03ce13f7SAndroid Build Coastguard Worker   Str << "\t.align\t" << Align << "\n";
6941*03ce13f7SAndroid Build Coastguard Worker 
6942*03ce13f7SAndroid Build Coastguard Worker   for (Constant *C : Pool) {
6943*03ce13f7SAndroid Build Coastguard Worker     if (!C->getShouldBePooled())
6944*03ce13f7SAndroid Build Coastguard Worker       continue;
6945*03ce13f7SAndroid Build Coastguard Worker     auto *Const = llvm::cast<typename T::IceType>(C);
6946*03ce13f7SAndroid Build Coastguard Worker     typename T::IceType::PrimType Value = Const->getValue();
6947*03ce13f7SAndroid Build Coastguard Worker     // Use memcpy() to copy bits from Value into RawValue in a way that avoids
6948*03ce13f7SAndroid Build Coastguard Worker     // breaking strict-aliasing rules.
6949*03ce13f7SAndroid Build Coastguard Worker     typename T::PrimitiveIntType RawValue;
6950*03ce13f7SAndroid Build Coastguard Worker     memcpy(&RawValue, &Value, sizeof(Value));
6951*03ce13f7SAndroid Build Coastguard Worker     char buf[30];
6952*03ce13f7SAndroid Build Coastguard Worker     int CharsPrinted =
6953*03ce13f7SAndroid Build Coastguard Worker         snprintf(buf, llvm::array_lengthof(buf), T::PrintfString, RawValue);
6954*03ce13f7SAndroid Build Coastguard Worker     assert(CharsPrinted >= 0);
6955*03ce13f7SAndroid Build Coastguard Worker     assert((size_t)CharsPrinted < llvm::array_lengthof(buf));
6956*03ce13f7SAndroid Build Coastguard Worker     (void)CharsPrinted; // avoid warnings if asserts are disabled
6957*03ce13f7SAndroid Build Coastguard Worker     Str << Const->getLabelName();
6958*03ce13f7SAndroid Build Coastguard Worker     Str << ":\n\t" << T::AsmTag << "\t" << buf << "\t/* " << T::TypeName << " "
6959*03ce13f7SAndroid Build Coastguard Worker         << Value << " */\n";
6960*03ce13f7SAndroid Build Coastguard Worker   }
6961*03ce13f7SAndroid Build Coastguard Worker }
6962*03ce13f7SAndroid Build Coastguard Worker 
lowerConstants()6963*03ce13f7SAndroid Build Coastguard Worker void TargetDataX8664::lowerConstants() {
6964*03ce13f7SAndroid Build Coastguard Worker   if (getFlags().getDisableTranslation())
6965*03ce13f7SAndroid Build Coastguard Worker     return;
6966*03ce13f7SAndroid Build Coastguard Worker   switch (getFlags().getOutFileType()) {
6967*03ce13f7SAndroid Build Coastguard Worker   case FT_Elf: {
6968*03ce13f7SAndroid Build Coastguard Worker     ELFObjectWriter *Writer = Ctx->getObjectWriter();
6969*03ce13f7SAndroid Build Coastguard Worker 
6970*03ce13f7SAndroid Build Coastguard Worker     Writer->writeConstantPool<ConstantInteger32>(IceType_i8);
6971*03ce13f7SAndroid Build Coastguard Worker     Writer->writeConstantPool<ConstantInteger32>(IceType_i16);
6972*03ce13f7SAndroid Build Coastguard Worker     Writer->writeConstantPool<ConstantInteger32>(IceType_i32);
6973*03ce13f7SAndroid Build Coastguard Worker 
6974*03ce13f7SAndroid Build Coastguard Worker     Writer->writeConstantPool<ConstantFloat>(IceType_f32);
6975*03ce13f7SAndroid Build Coastguard Worker     Writer->writeConstantPool<ConstantDouble>(IceType_f64);
6976*03ce13f7SAndroid Build Coastguard Worker   } break;
6977*03ce13f7SAndroid Build Coastguard Worker   case FT_Asm:
6978*03ce13f7SAndroid Build Coastguard Worker   case FT_Iasm: {
6979*03ce13f7SAndroid Build Coastguard Worker     OstreamLocker L(Ctx);
6980*03ce13f7SAndroid Build Coastguard Worker 
6981*03ce13f7SAndroid Build Coastguard Worker     emitConstantPool<PoolTypeConverter<uint8_t>>(Ctx);
6982*03ce13f7SAndroid Build Coastguard Worker     emitConstantPool<PoolTypeConverter<uint16_t>>(Ctx);
6983*03ce13f7SAndroid Build Coastguard Worker     emitConstantPool<PoolTypeConverter<uint32_t>>(Ctx);
6984*03ce13f7SAndroid Build Coastguard Worker 
6985*03ce13f7SAndroid Build Coastguard Worker     emitConstantPool<PoolTypeConverter<float>>(Ctx);
6986*03ce13f7SAndroid Build Coastguard Worker     emitConstantPool<PoolTypeConverter<double>>(Ctx);
6987*03ce13f7SAndroid Build Coastguard Worker   } break;
6988*03ce13f7SAndroid Build Coastguard Worker   }
6989*03ce13f7SAndroid Build Coastguard Worker }
6990*03ce13f7SAndroid Build Coastguard Worker 
lowerJumpTables()6991*03ce13f7SAndroid Build Coastguard Worker void TargetDataX8664::lowerJumpTables() {
6992*03ce13f7SAndroid Build Coastguard Worker   const bool IsPIC = false;
6993*03ce13f7SAndroid Build Coastguard Worker   switch (getFlags().getOutFileType()) {
6994*03ce13f7SAndroid Build Coastguard Worker   case FT_Elf: {
6995*03ce13f7SAndroid Build Coastguard Worker     ELFObjectWriter *Writer = Ctx->getObjectWriter();
6996*03ce13f7SAndroid Build Coastguard Worker     constexpr FixupKind FK_Abs64 = llvm::ELF::R_X86_64_64;
6997*03ce13f7SAndroid Build Coastguard Worker     const FixupKind RelocationKind =
6998*03ce13f7SAndroid Build Coastguard Worker         (getPointerType() == IceType_i32) ? FK_Abs : FK_Abs64;
6999*03ce13f7SAndroid Build Coastguard Worker     for (const JumpTableData &JT : Ctx->getJumpTables())
7000*03ce13f7SAndroid Build Coastguard Worker       Writer->writeJumpTable(JT, RelocationKind, IsPIC);
7001*03ce13f7SAndroid Build Coastguard Worker   } break;
7002*03ce13f7SAndroid Build Coastguard Worker   case FT_Asm:
7003*03ce13f7SAndroid Build Coastguard Worker     // Already emitted from Cfg
7004*03ce13f7SAndroid Build Coastguard Worker     break;
7005*03ce13f7SAndroid Build Coastguard Worker   case FT_Iasm: {
7006*03ce13f7SAndroid Build Coastguard Worker     if (!BuildDefs::dump())
7007*03ce13f7SAndroid Build Coastguard Worker       return;
7008*03ce13f7SAndroid Build Coastguard Worker     Ostream &Str = Ctx->getStrEmit();
7009*03ce13f7SAndroid Build Coastguard Worker     const char *Prefix = IsPIC ? ".data.rel.ro." : ".rodata.";
7010*03ce13f7SAndroid Build Coastguard Worker     for (const JumpTableData &JT : Ctx->getJumpTables()) {
7011*03ce13f7SAndroid Build Coastguard Worker       Str << "\t.section\t" << Prefix << JT.getSectionName()
7012*03ce13f7SAndroid Build Coastguard Worker           << ",\"a\",@progbits\n"
7013*03ce13f7SAndroid Build Coastguard Worker              "\t.align\t"
7014*03ce13f7SAndroid Build Coastguard Worker           << typeWidthInBytes(getPointerType()) << "\n"
7015*03ce13f7SAndroid Build Coastguard Worker           << JT.getName().toString() << ":";
7016*03ce13f7SAndroid Build Coastguard Worker 
7017*03ce13f7SAndroid Build Coastguard Worker       // On X8664 ILP32 pointers are 32-bit hence the use of .long
7018*03ce13f7SAndroid Build Coastguard Worker       for (intptr_t TargetOffset : JT.getTargetOffsets())
7019*03ce13f7SAndroid Build Coastguard Worker         Str << "\n\t.long\t" << JT.getFunctionName() << "+" << TargetOffset;
7020*03ce13f7SAndroid Build Coastguard Worker       Str << "\n";
7021*03ce13f7SAndroid Build Coastguard Worker     }
7022*03ce13f7SAndroid Build Coastguard Worker   } break;
7023*03ce13f7SAndroid Build Coastguard Worker   }
7024*03ce13f7SAndroid Build Coastguard Worker }
7025*03ce13f7SAndroid Build Coastguard Worker 
lowerGlobals(const VariableDeclarationList & Vars,const std::string & SectionSuffix)7026*03ce13f7SAndroid Build Coastguard Worker void TargetDataX8664::lowerGlobals(const VariableDeclarationList &Vars,
7027*03ce13f7SAndroid Build Coastguard Worker                                    const std::string &SectionSuffix) {
7028*03ce13f7SAndroid Build Coastguard Worker   const bool IsPIC = false;
7029*03ce13f7SAndroid Build Coastguard Worker   switch (getFlags().getOutFileType()) {
7030*03ce13f7SAndroid Build Coastguard Worker   case FT_Elf: {
7031*03ce13f7SAndroid Build Coastguard Worker     ELFObjectWriter *Writer = Ctx->getObjectWriter();
7032*03ce13f7SAndroid Build Coastguard Worker     Writer->writeDataSection(Vars, FK_Abs, SectionSuffix, IsPIC);
7033*03ce13f7SAndroid Build Coastguard Worker   } break;
7034*03ce13f7SAndroid Build Coastguard Worker   case FT_Asm:
7035*03ce13f7SAndroid Build Coastguard Worker   case FT_Iasm: {
7036*03ce13f7SAndroid Build Coastguard Worker     OstreamLocker L(Ctx);
7037*03ce13f7SAndroid Build Coastguard Worker     for (const VariableDeclaration *Var : Vars) {
7038*03ce13f7SAndroid Build Coastguard Worker       if (getFlags().matchTranslateOnly(Var->getName(), 0)) {
7039*03ce13f7SAndroid Build Coastguard Worker         emitGlobal(*Var, SectionSuffix);
7040*03ce13f7SAndroid Build Coastguard Worker       }
7041*03ce13f7SAndroid Build Coastguard Worker     }
7042*03ce13f7SAndroid Build Coastguard Worker   } break;
7043*03ce13f7SAndroid Build Coastguard Worker   }
7044*03ce13f7SAndroid Build Coastguard Worker }
7045*03ce13f7SAndroid Build Coastguard Worker 
7046*03ce13f7SAndroid Build Coastguard Worker //------------------------------------------------------------------------------
7047*03ce13f7SAndroid Build Coastguard Worker //     __      ______  __     __  ______  ______  __  __   __  ______
7048*03ce13f7SAndroid Build Coastguard Worker //    /\ \    /\  __ \/\ \  _ \ \/\  ___\/\  == \/\ \/\ "-.\ \/\  ___\
7049*03ce13f7SAndroid Build Coastguard Worker //    \ \ \___\ \ \/\ \ \ \/ ".\ \ \  __\\ \  __<\ \ \ \ \-.  \ \ \__ \
7050*03ce13f7SAndroid Build Coastguard Worker //     \ \_____\ \_____\ \__/".~\_\ \_____\ \_\ \_\ \_\ \_\\"\_\ \_____\
7051*03ce13f7SAndroid Build Coastguard Worker //      \/_____/\/_____/\/_/   \/_/\/_____/\/_/ /_/\/_/\/_/ \/_/\/_____/
7052*03ce13f7SAndroid Build Coastguard Worker //
7053*03ce13f7SAndroid Build Coastguard Worker //------------------------------------------------------------------------------
_add_sp(Operand * Adjustment)7054*03ce13f7SAndroid Build Coastguard Worker void TargetX8664::_add_sp(Operand *Adjustment) {
7055*03ce13f7SAndroid Build Coastguard Worker   Variable *rsp = getPhysicalRegister(RegX8664::Reg_rsp, IceType_i64);
7056*03ce13f7SAndroid Build Coastguard Worker   _add(rsp, Adjustment);
7057*03ce13f7SAndroid Build Coastguard Worker }
7058*03ce13f7SAndroid Build Coastguard Worker 
_mov_sp(Operand * NewValue)7059*03ce13f7SAndroid Build Coastguard Worker void TargetX8664::_mov_sp(Operand *NewValue) {
7060*03ce13f7SAndroid Build Coastguard Worker   Variable *rsp = getPhysicalRegister(RegX8664::Reg_rsp, IceType_i64);
7061*03ce13f7SAndroid Build Coastguard Worker   _redefined(_mov(rsp, NewValue));
7062*03ce13f7SAndroid Build Coastguard Worker }
7063*03ce13f7SAndroid Build Coastguard Worker 
_link_bp()7064*03ce13f7SAndroid Build Coastguard Worker void TargetX8664::_link_bp() {
7065*03ce13f7SAndroid Build Coastguard Worker   Variable *rsp = getPhysicalRegister(RegX8664::Reg_rsp, WordType);
7066*03ce13f7SAndroid Build Coastguard Worker   Variable *rbp = getPhysicalRegister(RegX8664::Reg_rbp, WordType);
7067*03ce13f7SAndroid Build Coastguard Worker 
7068*03ce13f7SAndroid Build Coastguard Worker   _push(rbp);
7069*03ce13f7SAndroid Build Coastguard Worker   _mov(rbp, rsp);
7070*03ce13f7SAndroid Build Coastguard Worker   // Keep ebp live for late-stage liveness analysis (e.g. asm-verbose mode).
7071*03ce13f7SAndroid Build Coastguard Worker   Context.insert<InstFakeUse>(rbp);
7072*03ce13f7SAndroid Build Coastguard Worker }
7073*03ce13f7SAndroid Build Coastguard Worker 
_unlink_bp()7074*03ce13f7SAndroid Build Coastguard Worker void TargetX8664::_unlink_bp() {
7075*03ce13f7SAndroid Build Coastguard Worker   Variable *rsp = getPhysicalRegister(RegX8664::Reg_rsp, IceType_i64);
7076*03ce13f7SAndroid Build Coastguard Worker   Variable *rbp = getPhysicalRegister(RegX8664::Reg_rbp, IceType_i64);
7077*03ce13f7SAndroid Build Coastguard Worker   // For late-stage liveness analysis (e.g. asm-verbose mode), adding a fake
7078*03ce13f7SAndroid Build Coastguard Worker   // use of rsp before the assignment of rsp=rbp keeps previous rsp
7079*03ce13f7SAndroid Build Coastguard Worker   // adjustments from being dead-code eliminated.
7080*03ce13f7SAndroid Build Coastguard Worker   Context.insert<InstFakeUse>(rsp);
7081*03ce13f7SAndroid Build Coastguard Worker 
7082*03ce13f7SAndroid Build Coastguard Worker   _mov(rsp, rbp);
7083*03ce13f7SAndroid Build Coastguard Worker   _pop(rbp);
7084*03ce13f7SAndroid Build Coastguard Worker }
7085*03ce13f7SAndroid Build Coastguard Worker 
_push_reg(RegNumT RegNum)7086*03ce13f7SAndroid Build Coastguard Worker void TargetX8664::_push_reg(RegNumT RegNum) {
7087*03ce13f7SAndroid Build Coastguard Worker   if (RegX8664::isXmm(RegNum)) {
7088*03ce13f7SAndroid Build Coastguard Worker     Variable *reg = getPhysicalRegister(RegNum, IceType_v4f32);
7089*03ce13f7SAndroid Build Coastguard Worker     Variable *rsp = getPhysicalRegister(RegX8664::Reg_rsp, WordType);
7090*03ce13f7SAndroid Build Coastguard Worker     auto *address = X86OperandMem::create(Func, reg->getType(), rsp, nullptr);
7091*03ce13f7SAndroid Build Coastguard Worker     _sub_sp(
7092*03ce13f7SAndroid Build Coastguard Worker         Ctx->getConstantInt32(16)); // TODO(capn): accumulate all the offsets
7093*03ce13f7SAndroid Build Coastguard Worker                                     // and adjust the stack pointer once.
7094*03ce13f7SAndroid Build Coastguard Worker     _storep(reg, address);
7095*03ce13f7SAndroid Build Coastguard Worker   } else {
7096*03ce13f7SAndroid Build Coastguard Worker     _push(getPhysicalRegister(RegNum, WordType));
7097*03ce13f7SAndroid Build Coastguard Worker   }
7098*03ce13f7SAndroid Build Coastguard Worker }
7099*03ce13f7SAndroid Build Coastguard Worker 
_pop_reg(RegNumT RegNum)7100*03ce13f7SAndroid Build Coastguard Worker void TargetX8664::_pop_reg(RegNumT RegNum) {
7101*03ce13f7SAndroid Build Coastguard Worker   if (RegX8664::isXmm(RegNum)) {
7102*03ce13f7SAndroid Build Coastguard Worker     Variable *reg = getPhysicalRegister(RegNum, IceType_v4f32);
7103*03ce13f7SAndroid Build Coastguard Worker     Variable *rsp = getPhysicalRegister(RegX8664::Reg_rsp, WordType);
7104*03ce13f7SAndroid Build Coastguard Worker     auto *address = X86OperandMem::create(Func, reg->getType(), rsp, nullptr);
7105*03ce13f7SAndroid Build Coastguard Worker     _movp(reg, address);
7106*03ce13f7SAndroid Build Coastguard Worker     _add_sp(
7107*03ce13f7SAndroid Build Coastguard Worker         Ctx->getConstantInt32(16)); // TODO(capn): accumulate all the offsets
7108*03ce13f7SAndroid Build Coastguard Worker                                     // and adjust the stack pointer once.
7109*03ce13f7SAndroid Build Coastguard Worker   } else {
7110*03ce13f7SAndroid Build Coastguard Worker     _pop(getPhysicalRegister(RegNum, WordType));
7111*03ce13f7SAndroid Build Coastguard Worker   }
7112*03ce13f7SAndroid Build Coastguard Worker }
7113*03ce13f7SAndroid Build Coastguard Worker 
_sub_sp(Operand * Adjustment)7114*03ce13f7SAndroid Build Coastguard Worker void TargetX8664::_sub_sp(Operand *Adjustment) {
7115*03ce13f7SAndroid Build Coastguard Worker   Variable *rsp = getPhysicalRegister(RegX8664::Reg_rsp, WordType);
7116*03ce13f7SAndroid Build Coastguard Worker 
7117*03ce13f7SAndroid Build Coastguard Worker   _sub(rsp, Adjustment);
7118*03ce13f7SAndroid Build Coastguard Worker 
7119*03ce13f7SAndroid Build Coastguard Worker   // Add a fake use of the stack pointer, to prevent the stack pointer adustment
7120*03ce13f7SAndroid Build Coastguard Worker   // from being dead-code eliminated in a function that doesn't return.
7121*03ce13f7SAndroid Build Coastguard Worker   Context.insert<InstFakeUse>(rsp);
7122*03ce13f7SAndroid Build Coastguard Worker }
7123*03ce13f7SAndroid Build Coastguard Worker 
lowerIndirectJump(Variable * JumpTarget)7124*03ce13f7SAndroid Build Coastguard Worker void TargetX8664::lowerIndirectJump(Variable *JumpTarget) {
7125*03ce13f7SAndroid Build Coastguard Worker   if (JumpTarget->getType() != IceType_i64) {
7126*03ce13f7SAndroid Build Coastguard Worker     Variable *T = makeReg(IceType_i64);
7127*03ce13f7SAndroid Build Coastguard Worker     _movzx(T, JumpTarget);
7128*03ce13f7SAndroid Build Coastguard Worker     JumpTarget = T;
7129*03ce13f7SAndroid Build Coastguard Worker   }
7130*03ce13f7SAndroid Build Coastguard Worker 
7131*03ce13f7SAndroid Build Coastguard Worker   _jmp(JumpTarget);
7132*03ce13f7SAndroid Build Coastguard Worker }
7133*03ce13f7SAndroid Build Coastguard Worker 
emitCallToTarget(Operand * CallTarget,Variable * ReturnReg,size_t NumVariadicFpArgs)7134*03ce13f7SAndroid Build Coastguard Worker Inst *TargetX8664::emitCallToTarget(Operand *CallTarget, Variable *ReturnReg,
7135*03ce13f7SAndroid Build Coastguard Worker                                     size_t NumVariadicFpArgs) {
7136*03ce13f7SAndroid Build Coastguard Worker   if (CallTarget->getType() == IceType_i64) {
7137*03ce13f7SAndroid Build Coastguard Worker     // x86-64 does not support 64-bit direct calls, so write the value to a
7138*03ce13f7SAndroid Build Coastguard Worker     // register and make an indirect call for Constant call targets.
7139*03ce13f7SAndroid Build Coastguard Worker     RegNumT TargetReg = {};
7140*03ce13f7SAndroid Build Coastguard Worker 
7141*03ce13f7SAndroid Build Coastguard Worker     // System V: force r11 when calling a variadic function so that rax isn't
7142*03ce13f7SAndroid Build Coastguard Worker     // used, since rax stores the number of FP args (see NumVariadicFpArgs
7143*03ce13f7SAndroid Build Coastguard Worker     // usage below).
7144*03ce13f7SAndroid Build Coastguard Worker #if !defined(SUBZERO_USE_MICROSOFT_ABI)
7145*03ce13f7SAndroid Build Coastguard Worker     if (NumVariadicFpArgs > 0)
7146*03ce13f7SAndroid Build Coastguard Worker       TargetReg = RegX8664::Reg_r11;
7147*03ce13f7SAndroid Build Coastguard Worker #endif
7148*03ce13f7SAndroid Build Coastguard Worker 
7149*03ce13f7SAndroid Build Coastguard Worker     if (llvm::isa<Constant>(CallTarget)) {
7150*03ce13f7SAndroid Build Coastguard Worker       Variable *T = makeReg(IceType_i64, TargetReg);
7151*03ce13f7SAndroid Build Coastguard Worker       _mov(T, CallTarget);
7152*03ce13f7SAndroid Build Coastguard Worker       CallTarget = T;
7153*03ce13f7SAndroid Build Coastguard Worker     } else if (llvm::isa<Variable>(CallTarget)) {
7154*03ce13f7SAndroid Build Coastguard Worker       Operand *T = legalizeToReg(CallTarget, TargetReg);
7155*03ce13f7SAndroid Build Coastguard Worker       CallTarget = T;
7156*03ce13f7SAndroid Build Coastguard Worker     }
7157*03ce13f7SAndroid Build Coastguard Worker   }
7158*03ce13f7SAndroid Build Coastguard Worker 
7159*03ce13f7SAndroid Build Coastguard Worker   // System V: store number of FP args in RAX for variadic calls
7160*03ce13f7SAndroid Build Coastguard Worker #if !defined(SUBZERO_USE_MICROSOFT_ABI)
7161*03ce13f7SAndroid Build Coastguard Worker   if (NumVariadicFpArgs > 0) {
7162*03ce13f7SAndroid Build Coastguard Worker     // Store number of FP args (stored in XMM registers) in RAX for variadic
7163*03ce13f7SAndroid Build Coastguard Worker     // calls
7164*03ce13f7SAndroid Build Coastguard Worker     auto *NumFpArgs = Ctx->getConstantInt64(NumVariadicFpArgs);
7165*03ce13f7SAndroid Build Coastguard Worker     Variable *NumFpArgsReg = legalizeToReg(NumFpArgs, RegX8664::Reg_rax);
7166*03ce13f7SAndroid Build Coastguard Worker     Context.insert<InstFakeUse>(NumFpArgsReg);
7167*03ce13f7SAndroid Build Coastguard Worker   }
7168*03ce13f7SAndroid Build Coastguard Worker #endif
7169*03ce13f7SAndroid Build Coastguard Worker 
7170*03ce13f7SAndroid Build Coastguard Worker   return Context.insert<Insts::Call>(ReturnReg, CallTarget);
7171*03ce13f7SAndroid Build Coastguard Worker }
7172*03ce13f7SAndroid Build Coastguard Worker 
moveReturnValueToRegister(Operand * Value,Type ReturnType)7173*03ce13f7SAndroid Build Coastguard Worker Variable *TargetX8664::moveReturnValueToRegister(Operand *Value,
7174*03ce13f7SAndroid Build Coastguard Worker                                                  Type ReturnType) {
7175*03ce13f7SAndroid Build Coastguard Worker   if (isVectorType(ReturnType) || isScalarFloatingType(ReturnType)) {
7176*03ce13f7SAndroid Build Coastguard Worker     return legalizeToReg(Value, RegX8664::Reg_xmm0);
7177*03ce13f7SAndroid Build Coastguard Worker   } else {
7178*03ce13f7SAndroid Build Coastguard Worker     assert(ReturnType == IceType_i32 || ReturnType == IceType_i64);
7179*03ce13f7SAndroid Build Coastguard Worker     Variable *Reg = nullptr;
7180*03ce13f7SAndroid Build Coastguard Worker     _mov(Reg, Value, RegX8664::getGprForType(ReturnType, RegX8664::Reg_rax));
7181*03ce13f7SAndroid Build Coastguard Worker     return Reg;
7182*03ce13f7SAndroid Build Coastguard Worker   }
7183*03ce13f7SAndroid Build Coastguard Worker }
7184*03ce13f7SAndroid Build Coastguard Worker 
emitStackProbe(size_t StackSizeBytes)7185*03ce13f7SAndroid Build Coastguard Worker void TargetX8664::emitStackProbe(size_t StackSizeBytes) {
7186*03ce13f7SAndroid Build Coastguard Worker #if defined(_WIN64)
7187*03ce13f7SAndroid Build Coastguard Worker   // Mirroring the behavior of MSVC here, which emits a _chkstk when locals are
7188*03ce13f7SAndroid Build Coastguard Worker   // >= 4KB, rather than the 8KB claimed by the docs.
7189*03ce13f7SAndroid Build Coastguard Worker   if (StackSizeBytes >= 4096) {
7190*03ce13f7SAndroid Build Coastguard Worker     // __chkstk on Win64 probes the stack up to RSP - EAX, but does not clobber
7191*03ce13f7SAndroid Build Coastguard Worker     // RSP, so we don't need to save and restore it.
7192*03ce13f7SAndroid Build Coastguard Worker 
7193*03ce13f7SAndroid Build Coastguard Worker     Variable *EAX = makeReg(IceType_i32, RegX8664::Reg_eax);
7194*03ce13f7SAndroid Build Coastguard Worker     _mov(EAX, Ctx->getConstantInt32(StackSizeBytes));
7195*03ce13f7SAndroid Build Coastguard Worker 
7196*03ce13f7SAndroid Build Coastguard Worker     auto *CallTarget =
7197*03ce13f7SAndroid Build Coastguard Worker         Ctx->getConstantInt64(reinterpret_cast<int64_t>(&__chkstk));
7198*03ce13f7SAndroid Build Coastguard Worker     Operand *CallTargetReg = legalizeToReg(CallTarget, RegX8664::Reg_r11);
7199*03ce13f7SAndroid Build Coastguard Worker     emitCallToTarget(CallTargetReg, nullptr);
7200*03ce13f7SAndroid Build Coastguard Worker   }
7201*03ce13f7SAndroid Build Coastguard Worker #endif
7202*03ce13f7SAndroid Build Coastguard Worker }
7203*03ce13f7SAndroid Build Coastguard Worker 
7204*03ce13f7SAndroid Build Coastguard Worker // In some cases, there are x-macros tables for both high-level and low-level
7205*03ce13f7SAndroid Build Coastguard Worker // instructions/operands that use the same enum key value. The tables are kept
7206*03ce13f7SAndroid Build Coastguard Worker // separate to maintain a proper separation between abstraction layers. There
7207*03ce13f7SAndroid Build Coastguard Worker // is a risk that the tables could get out of sync if enum values are reordered
7208*03ce13f7SAndroid Build Coastguard Worker // or if entries are added or deleted. The following dummy namespaces use
7209*03ce13f7SAndroid Build Coastguard Worker // static_asserts to ensure everything is kept in sync.
7210*03ce13f7SAndroid Build Coastguard Worker 
7211*03ce13f7SAndroid Build Coastguard Worker namespace {
7212*03ce13f7SAndroid Build Coastguard Worker // Validate the enum values in FCMPX8664_TABLE.
7213*03ce13f7SAndroid Build Coastguard Worker namespace dummy1 {
7214*03ce13f7SAndroid Build Coastguard Worker // Define a temporary set of enum values based on low-level table entries.
7215*03ce13f7SAndroid Build Coastguard Worker enum _tmp_enum {
7216*03ce13f7SAndroid Build Coastguard Worker #define X(val, dflt, swapS, C1, C2, swapV, pred) _tmp_##val,
7217*03ce13f7SAndroid Build Coastguard Worker   FCMPX8664_TABLE
7218*03ce13f7SAndroid Build Coastguard Worker #undef X
7219*03ce13f7SAndroid Build Coastguard Worker       _num
7220*03ce13f7SAndroid Build Coastguard Worker };
7221*03ce13f7SAndroid Build Coastguard Worker // Define a set of constants based on high-level table entries.
7222*03ce13f7SAndroid Build Coastguard Worker #define X(tag, str) static const int _table1_##tag = InstFcmp::tag;
7223*03ce13f7SAndroid Build Coastguard Worker ICEINSTFCMP_TABLE
7224*03ce13f7SAndroid Build Coastguard Worker #undef X
7225*03ce13f7SAndroid Build Coastguard Worker // Define a set of constants based on low-level table entries, and ensure the
7226*03ce13f7SAndroid Build Coastguard Worker // table entry keys are consistent.
7227*03ce13f7SAndroid Build Coastguard Worker #define X(val, dflt, swapS, C1, C2, swapV, pred)                               \
7228*03ce13f7SAndroid Build Coastguard Worker   static const int _table2_##val = _tmp_##val;                                 \
7229*03ce13f7SAndroid Build Coastguard Worker   static_assert(                                                               \
7230*03ce13f7SAndroid Build Coastguard Worker       _table1_##val == _table2_##val,                                          \
7231*03ce13f7SAndroid Build Coastguard Worker       "Inconsistency between FCMPX8664_TABLE and ICEINSTFCMP_TABLE");
7232*03ce13f7SAndroid Build Coastguard Worker FCMPX8664_TABLE
7233*03ce13f7SAndroid Build Coastguard Worker #undef X
7234*03ce13f7SAndroid Build Coastguard Worker // Repeat the static asserts with respect to the high-level table entries in
7235*03ce13f7SAndroid Build Coastguard Worker // case the high-level table has extra entries.
7236*03ce13f7SAndroid Build Coastguard Worker #define X(tag, str)                                                            \
7237*03ce13f7SAndroid Build Coastguard Worker   static_assert(                                                               \
7238*03ce13f7SAndroid Build Coastguard Worker       _table1_##tag == _table2_##tag,                                          \
7239*03ce13f7SAndroid Build Coastguard Worker       "Inconsistency between FCMPX8664_TABLE and ICEINSTFCMP_TABLE");
7240*03ce13f7SAndroid Build Coastguard Worker ICEINSTFCMP_TABLE
7241*03ce13f7SAndroid Build Coastguard Worker #undef X
7242*03ce13f7SAndroid Build Coastguard Worker } // end of namespace dummy1
7243*03ce13f7SAndroid Build Coastguard Worker 
7244*03ce13f7SAndroid Build Coastguard Worker // Validate the enum values in ICMPX8664_TABLE.
7245*03ce13f7SAndroid Build Coastguard Worker namespace dummy2 {
7246*03ce13f7SAndroid Build Coastguard Worker // Define a temporary set of enum values based on low-level table entries.
7247*03ce13f7SAndroid Build Coastguard Worker enum _tmp_enum {
7248*03ce13f7SAndroid Build Coastguard Worker #define X(val, C_32, C1_64, C2_64, C3_64) _tmp_##val,
7249*03ce13f7SAndroid Build Coastguard Worker   ICMPX8664_TABLE
7250*03ce13f7SAndroid Build Coastguard Worker #undef X
7251*03ce13f7SAndroid Build Coastguard Worker       _num
7252*03ce13f7SAndroid Build Coastguard Worker };
7253*03ce13f7SAndroid Build Coastguard Worker // Define a set of constants based on high-level table entries.
7254*03ce13f7SAndroid Build Coastguard Worker #define X(tag, reverse, str) static const int _table1_##tag = InstIcmp::tag;
7255*03ce13f7SAndroid Build Coastguard Worker ICEINSTICMP_TABLE
7256*03ce13f7SAndroid Build Coastguard Worker #undef X
7257*03ce13f7SAndroid Build Coastguard Worker // Define a set of constants based on low-level table entries, and ensure the
7258*03ce13f7SAndroid Build Coastguard Worker // table entry keys are consistent.
7259*03ce13f7SAndroid Build Coastguard Worker #define X(val, C_32, C1_64, C2_64, C3_64)                                      \
7260*03ce13f7SAndroid Build Coastguard Worker   static const int _table2_##val = _tmp_##val;                                 \
7261*03ce13f7SAndroid Build Coastguard Worker   static_assert(                                                               \
7262*03ce13f7SAndroid Build Coastguard Worker       _table1_##val == _table2_##val,                                          \
7263*03ce13f7SAndroid Build Coastguard Worker       "Inconsistency between ICMPX8664_TABLE and ICEINSTICMP_TABLE");
7264*03ce13f7SAndroid Build Coastguard Worker ICMPX8664_TABLE
7265*03ce13f7SAndroid Build Coastguard Worker #undef X
7266*03ce13f7SAndroid Build Coastguard Worker // Repeat the static asserts with respect to the high-level table entries in
7267*03ce13f7SAndroid Build Coastguard Worker // case the high-level table has extra entries.
7268*03ce13f7SAndroid Build Coastguard Worker #define X(tag, reverse, str)                                                   \
7269*03ce13f7SAndroid Build Coastguard Worker   static_assert(                                                               \
7270*03ce13f7SAndroid Build Coastguard Worker       _table1_##tag == _table2_##tag,                                          \
7271*03ce13f7SAndroid Build Coastguard Worker       "Inconsistency between ICMPX8664_TABLE and ICEINSTICMP_TABLE");
7272*03ce13f7SAndroid Build Coastguard Worker ICEINSTICMP_TABLE
7273*03ce13f7SAndroid Build Coastguard Worker #undef X
7274*03ce13f7SAndroid Build Coastguard Worker } // end of namespace dummy2
7275*03ce13f7SAndroid Build Coastguard Worker 
7276*03ce13f7SAndroid Build Coastguard Worker // Validate the enum values in ICETYPEX86_TABLE.
7277*03ce13f7SAndroid Build Coastguard Worker namespace dummy3 {
7278*03ce13f7SAndroid Build Coastguard Worker // Define a temporary set of enum values based on low-level table entries.
7279*03ce13f7SAndroid Build Coastguard Worker enum _tmp_enum {
7280*03ce13f7SAndroid Build Coastguard Worker #define X(tag, elty, cvt, sdss, pdps, spsd, int_, unpack, pack, width, fld)    \
7281*03ce13f7SAndroid Build Coastguard Worker   _tmp_##tag,
7282*03ce13f7SAndroid Build Coastguard Worker   ICETYPEX86_TABLE
7283*03ce13f7SAndroid Build Coastguard Worker #undef X
7284*03ce13f7SAndroid Build Coastguard Worker       _num
7285*03ce13f7SAndroid Build Coastguard Worker };
7286*03ce13f7SAndroid Build Coastguard Worker // Define a set of constants based on high-level table entries.
7287*03ce13f7SAndroid Build Coastguard Worker #define X(tag, sizeLog2, align, elts, elty, str, rcstr)                        \
7288*03ce13f7SAndroid Build Coastguard Worker   static const int _table1_##tag = IceType_##tag;
7289*03ce13f7SAndroid Build Coastguard Worker ICETYPE_TABLE
7290*03ce13f7SAndroid Build Coastguard Worker #undef X
7291*03ce13f7SAndroid Build Coastguard Worker // Define a set of constants based on low-level table entries, and ensure the
7292*03ce13f7SAndroid Build Coastguard Worker // table entry keys are consistent.
7293*03ce13f7SAndroid Build Coastguard Worker #define X(tag, elty, cvt, sdss, pdps, spsd, int_, unpack, pack, width, fld)    \
7294*03ce13f7SAndroid Build Coastguard Worker   static const int _table2_##tag = _tmp_##tag;                                 \
7295*03ce13f7SAndroid Build Coastguard Worker   static_assert(_table1_##tag == _table2_##tag,                                \
7296*03ce13f7SAndroid Build Coastguard Worker                 "Inconsistency between ICETYPEX86_TABLE and ICETYPE_TABLE");
7297*03ce13f7SAndroid Build Coastguard Worker ICETYPEX86_TABLE
7298*03ce13f7SAndroid Build Coastguard Worker #undef X
7299*03ce13f7SAndroid Build Coastguard Worker // Repeat the static asserts with respect to the high-level table entries in
7300*03ce13f7SAndroid Build Coastguard Worker // case the high-level table has extra entries.
7301*03ce13f7SAndroid Build Coastguard Worker #define X(tag, sizeLog2, align, elts, elty, str, rcstr)                        \
7302*03ce13f7SAndroid Build Coastguard Worker   static_assert(_table1_##tag == _table2_##tag,                                \
7303*03ce13f7SAndroid Build Coastguard Worker                 "Inconsistency between ICETYPEX86_TABLE and ICETYPE_TABLE");
7304*03ce13f7SAndroid Build Coastguard Worker ICETYPE_TABLE
7305*03ce13f7SAndroid Build Coastguard Worker #undef X
7306*03ce13f7SAndroid Build Coastguard Worker 
7307*03ce13f7SAndroid Build Coastguard Worker } // end of namespace dummy3
7308*03ce13f7SAndroid Build Coastguard Worker } // end of anonymous namespace
7309*03ce13f7SAndroid Build Coastguard Worker 
7310*03ce13f7SAndroid Build Coastguard Worker } // end of namespace X8664
7311*03ce13f7SAndroid Build Coastguard Worker } // end of namespace Ice
7312