1*03ce13f7SAndroid Build Coastguard Worker //===- subzero/src/IceTargetLoweringX8632.cpp - x86-32 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 TargetLoweringX8632 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
16*03ce13f7SAndroid Build Coastguard Worker #include "IceTargetLoweringX8632.h"
17*03ce13f7SAndroid Build Coastguard Worker
18*03ce13f7SAndroid Build Coastguard Worker #include "IceCfg.h"
19*03ce13f7SAndroid Build Coastguard Worker #include "IceCfgNode.h"
20*03ce13f7SAndroid Build Coastguard Worker #include "IceClFlags.h"
21*03ce13f7SAndroid Build Coastguard Worker #include "IceDefs.h"
22*03ce13f7SAndroid Build Coastguard Worker #include "IceELFObjectWriter.h"
23*03ce13f7SAndroid Build Coastguard Worker #include "IceGlobalInits.h"
24*03ce13f7SAndroid Build Coastguard Worker #include "IceInstVarIter.h"
25*03ce13f7SAndroid Build Coastguard Worker #include "IceInstX8632.h"
26*03ce13f7SAndroid Build Coastguard Worker #include "IceLiveness.h"
27*03ce13f7SAndroid Build Coastguard Worker #include "IceOperand.h"
28*03ce13f7SAndroid Build Coastguard Worker #include "IcePhiLoweringImpl.h"
29*03ce13f7SAndroid Build Coastguard Worker #include "IceTargetLoweringX8632.def"
30*03ce13f7SAndroid Build Coastguard Worker #include "IceUtils.h"
31*03ce13f7SAndroid Build Coastguard Worker #include "IceVariableSplitting.h"
32*03ce13f7SAndroid Build Coastguard Worker
33*03ce13f7SAndroid Build Coastguard Worker #include "llvm/Support/MathExtras.h"
34*03ce13f7SAndroid Build Coastguard Worker
35*03ce13f7SAndroid Build Coastguard Worker #include <stack>
36*03ce13f7SAndroid Build Coastguard Worker
37*03ce13f7SAndroid Build Coastguard Worker #if defined(_WIN32)
38*03ce13f7SAndroid Build Coastguard Worker extern "C" void _chkstk();
39*03ce13f7SAndroid Build Coastguard Worker #endif
40*03ce13f7SAndroid Build Coastguard Worker
41*03ce13f7SAndroid Build Coastguard Worker namespace X8632 {
42*03ce13f7SAndroid Build Coastguard Worker
createTargetLowering(::Ice::Cfg * Func)43*03ce13f7SAndroid Build Coastguard Worker std::unique_ptr<::Ice::TargetLowering> createTargetLowering(::Ice::Cfg *Func) {
44*03ce13f7SAndroid Build Coastguard Worker return ::Ice::X8632::TargetX8632::create(Func);
45*03ce13f7SAndroid Build Coastguard Worker }
46*03ce13f7SAndroid Build Coastguard Worker
47*03ce13f7SAndroid Build Coastguard Worker std::unique_ptr<::Ice::TargetDataLowering>
createTargetDataLowering(::Ice::GlobalContext * Ctx)48*03ce13f7SAndroid Build Coastguard Worker createTargetDataLowering(::Ice::GlobalContext *Ctx) {
49*03ce13f7SAndroid Build Coastguard Worker return ::Ice::X8632::TargetDataX8632::create(Ctx);
50*03ce13f7SAndroid Build Coastguard Worker }
51*03ce13f7SAndroid Build Coastguard Worker
52*03ce13f7SAndroid Build Coastguard Worker std::unique_ptr<::Ice::TargetHeaderLowering>
createTargetHeaderLowering(::Ice::GlobalContext * Ctx)53*03ce13f7SAndroid Build Coastguard Worker createTargetHeaderLowering(::Ice::GlobalContext *Ctx) {
54*03ce13f7SAndroid Build Coastguard Worker return ::Ice::X8632::TargetHeaderX86::create(Ctx);
55*03ce13f7SAndroid Build Coastguard Worker }
56*03ce13f7SAndroid Build Coastguard Worker
staticInit(::Ice::GlobalContext * Ctx)57*03ce13f7SAndroid Build Coastguard Worker void staticInit(::Ice::GlobalContext *Ctx) {
58*03ce13f7SAndroid Build Coastguard Worker ::Ice::X8632::TargetX8632::staticInit(Ctx);
59*03ce13f7SAndroid Build Coastguard Worker }
60*03ce13f7SAndroid Build Coastguard Worker
shouldBePooled(const class::Ice::Constant * C)61*03ce13f7SAndroid Build Coastguard Worker bool shouldBePooled(const class ::Ice::Constant *C) {
62*03ce13f7SAndroid Build Coastguard Worker return ::Ice::X8632::TargetX8632::shouldBePooled(C);
63*03ce13f7SAndroid Build Coastguard Worker }
64*03ce13f7SAndroid Build Coastguard Worker
getPointerType()65*03ce13f7SAndroid Build Coastguard Worker ::Ice::Type getPointerType() { return ::Ice::Type::IceType_i32; }
66*03ce13f7SAndroid Build Coastguard Worker
67*03ce13f7SAndroid Build Coastguard Worker } // end of namespace X8632
68*03ce13f7SAndroid Build Coastguard Worker
69*03ce13f7SAndroid Build Coastguard Worker namespace Ice {
70*03ce13f7SAndroid Build Coastguard Worker namespace X8632 {
71*03ce13f7SAndroid Build Coastguard Worker
72*03ce13f7SAndroid Build Coastguard Worker /// The number of bits in a byte
73*03ce13f7SAndroid Build Coastguard Worker static constexpr uint32_t X86_CHAR_BIT = 8;
74*03ce13f7SAndroid Build Coastguard Worker /// Size of the return address on the stack
75*03ce13f7SAndroid Build Coastguard Worker static constexpr uint32_t X86_RET_IP_SIZE_BYTES = 4;
76*03ce13f7SAndroid Build Coastguard Worker
77*03ce13f7SAndroid Build Coastguard Worker /// \name Limits for unrolling memory intrinsics.
78*03ce13f7SAndroid Build Coastguard Worker /// @{
79*03ce13f7SAndroid Build Coastguard Worker static constexpr uint32_t MEMCPY_UNROLL_LIMIT = 8;
80*03ce13f7SAndroid Build Coastguard Worker static constexpr uint32_t MEMMOVE_UNROLL_LIMIT = 8;
81*03ce13f7SAndroid Build Coastguard Worker static constexpr uint32_t MEMSET_UNROLL_LIMIT = 8;
82*03ce13f7SAndroid Build Coastguard Worker /// @}
83*03ce13f7SAndroid Build Coastguard Worker
BoolFoldingEntry(Inst * I)84*03ce13f7SAndroid Build Coastguard Worker BoolFoldingEntry::BoolFoldingEntry(Inst *I)
85*03ce13f7SAndroid Build Coastguard Worker : Instr(I), IsComplex(BoolFolding::hasComplexLowering(I)) {}
86*03ce13f7SAndroid Build Coastguard Worker
87*03ce13f7SAndroid Build Coastguard Worker BoolFolding::BoolFoldingProducerKind
getProducerKind(const Inst * Instr)88*03ce13f7SAndroid Build Coastguard Worker BoolFolding::getProducerKind(const Inst *Instr) {
89*03ce13f7SAndroid Build Coastguard Worker if (llvm::isa<InstIcmp>(Instr)) {
90*03ce13f7SAndroid Build Coastguard Worker if (Instr->getSrc(0)->getType() != IceType_i64)
91*03ce13f7SAndroid Build Coastguard Worker return PK_Icmp32;
92*03ce13f7SAndroid Build Coastguard Worker return PK_Icmp64;
93*03ce13f7SAndroid Build Coastguard Worker }
94*03ce13f7SAndroid Build Coastguard Worker if (llvm::isa<InstFcmp>(Instr))
95*03ce13f7SAndroid Build Coastguard Worker return PK_Fcmp;
96*03ce13f7SAndroid Build Coastguard Worker if (auto *Arith = llvm::dyn_cast<InstArithmetic>(Instr)) {
97*03ce13f7SAndroid Build Coastguard Worker if (Arith->getSrc(0)->getType() != IceType_i64) {
98*03ce13f7SAndroid Build Coastguard Worker switch (Arith->getOp()) {
99*03ce13f7SAndroid Build Coastguard Worker default:
100*03ce13f7SAndroid Build Coastguard Worker return PK_None;
101*03ce13f7SAndroid Build Coastguard Worker case InstArithmetic::And:
102*03ce13f7SAndroid Build Coastguard Worker case InstArithmetic::Or:
103*03ce13f7SAndroid Build Coastguard Worker return PK_Arith;
104*03ce13f7SAndroid Build Coastguard Worker }
105*03ce13f7SAndroid Build Coastguard Worker }
106*03ce13f7SAndroid Build Coastguard Worker }
107*03ce13f7SAndroid Build Coastguard Worker return PK_None; // TODO(stichnot): remove this
108*03ce13f7SAndroid Build Coastguard Worker
109*03ce13f7SAndroid Build Coastguard Worker if (auto *Cast = llvm::dyn_cast<InstCast>(Instr)) {
110*03ce13f7SAndroid Build Coastguard Worker switch (Cast->getCastKind()) {
111*03ce13f7SAndroid Build Coastguard Worker default:
112*03ce13f7SAndroid Build Coastguard Worker return PK_None;
113*03ce13f7SAndroid Build Coastguard Worker case InstCast::Trunc:
114*03ce13f7SAndroid Build Coastguard Worker return PK_Trunc;
115*03ce13f7SAndroid Build Coastguard Worker }
116*03ce13f7SAndroid Build Coastguard Worker }
117*03ce13f7SAndroid Build Coastguard Worker return PK_None;
118*03ce13f7SAndroid Build Coastguard Worker }
119*03ce13f7SAndroid Build Coastguard Worker
120*03ce13f7SAndroid Build Coastguard Worker BoolFolding::BoolFoldingConsumerKind
getConsumerKind(const Inst * Instr)121*03ce13f7SAndroid Build Coastguard Worker BoolFolding::getConsumerKind(const Inst *Instr) {
122*03ce13f7SAndroid Build Coastguard Worker if (llvm::isa<InstBr>(Instr))
123*03ce13f7SAndroid Build Coastguard Worker return CK_Br;
124*03ce13f7SAndroid Build Coastguard Worker if (llvm::isa<InstSelect>(Instr))
125*03ce13f7SAndroid Build Coastguard Worker return CK_Select;
126*03ce13f7SAndroid Build Coastguard Worker return CK_None; // TODO(stichnot): remove this
127*03ce13f7SAndroid Build Coastguard Worker
128*03ce13f7SAndroid Build Coastguard Worker if (auto *Cast = llvm::dyn_cast<InstCast>(Instr)) {
129*03ce13f7SAndroid Build Coastguard Worker switch (Cast->getCastKind()) {
130*03ce13f7SAndroid Build Coastguard Worker default:
131*03ce13f7SAndroid Build Coastguard Worker return CK_None;
132*03ce13f7SAndroid Build Coastguard Worker case InstCast::Sext:
133*03ce13f7SAndroid Build Coastguard Worker return CK_Sext;
134*03ce13f7SAndroid Build Coastguard Worker case InstCast::Zext:
135*03ce13f7SAndroid Build Coastguard Worker return CK_Zext;
136*03ce13f7SAndroid Build Coastguard Worker }
137*03ce13f7SAndroid Build Coastguard Worker }
138*03ce13f7SAndroid Build Coastguard Worker return CK_None;
139*03ce13f7SAndroid Build Coastguard Worker }
140*03ce13f7SAndroid Build Coastguard Worker
141*03ce13f7SAndroid Build Coastguard Worker /// Returns true if the producing instruction has a "complex" lowering sequence.
142*03ce13f7SAndroid Build Coastguard Worker /// This generally means that its lowering sequence requires more than one
143*03ce13f7SAndroid Build Coastguard Worker /// conditional branch, namely 64-bit integer compares and some floating-point
144*03ce13f7SAndroid Build Coastguard Worker /// compares. When this is true, and there is more than one consumer, we prefer
145*03ce13f7SAndroid Build Coastguard Worker /// to disable the folding optimization because it minimizes branches.
146*03ce13f7SAndroid Build Coastguard Worker
hasComplexLowering(const Inst * Instr)147*03ce13f7SAndroid Build Coastguard Worker bool BoolFolding::hasComplexLowering(const Inst *Instr) {
148*03ce13f7SAndroid Build Coastguard Worker switch (getProducerKind(Instr)) {
149*03ce13f7SAndroid Build Coastguard Worker default:
150*03ce13f7SAndroid Build Coastguard Worker return false;
151*03ce13f7SAndroid Build Coastguard Worker case PK_Icmp64:
152*03ce13f7SAndroid Build Coastguard Worker return true;
153*03ce13f7SAndroid Build Coastguard Worker case PK_Fcmp:
154*03ce13f7SAndroid Build Coastguard Worker return TargetX8632::TableFcmp[llvm::cast<InstFcmp>(Instr)->getCondition()]
155*03ce13f7SAndroid Build Coastguard Worker .C2 != CondX86::Br_None;
156*03ce13f7SAndroid Build Coastguard Worker }
157*03ce13f7SAndroid Build Coastguard Worker }
158*03ce13f7SAndroid Build Coastguard Worker
isValidFolding(BoolFolding::BoolFoldingProducerKind ProducerKind,BoolFolding::BoolFoldingConsumerKind ConsumerKind)159*03ce13f7SAndroid Build Coastguard Worker bool BoolFolding::isValidFolding(
160*03ce13f7SAndroid Build Coastguard Worker BoolFolding::BoolFoldingProducerKind ProducerKind,
161*03ce13f7SAndroid Build Coastguard Worker BoolFolding::BoolFoldingConsumerKind ConsumerKind) {
162*03ce13f7SAndroid Build Coastguard Worker switch (ProducerKind) {
163*03ce13f7SAndroid Build Coastguard Worker default:
164*03ce13f7SAndroid Build Coastguard Worker return false;
165*03ce13f7SAndroid Build Coastguard Worker case PK_Icmp32:
166*03ce13f7SAndroid Build Coastguard Worker case PK_Icmp64:
167*03ce13f7SAndroid Build Coastguard Worker case PK_Fcmp:
168*03ce13f7SAndroid Build Coastguard Worker return (ConsumerKind == CK_Br) || (ConsumerKind == CK_Select);
169*03ce13f7SAndroid Build Coastguard Worker case PK_Arith:
170*03ce13f7SAndroid Build Coastguard Worker return ConsumerKind == CK_Br;
171*03ce13f7SAndroid Build Coastguard Worker }
172*03ce13f7SAndroid Build Coastguard Worker }
173*03ce13f7SAndroid Build Coastguard Worker
init(CfgNode * Node)174*03ce13f7SAndroid Build Coastguard Worker void BoolFolding::init(CfgNode *Node) {
175*03ce13f7SAndroid Build Coastguard Worker Producers.clear();
176*03ce13f7SAndroid Build Coastguard Worker for (Inst &Instr : Node->getInsts()) {
177*03ce13f7SAndroid Build Coastguard Worker if (Instr.isDeleted())
178*03ce13f7SAndroid Build Coastguard Worker continue;
179*03ce13f7SAndroid Build Coastguard Worker invalidateProducersOnStore(&Instr);
180*03ce13f7SAndroid Build Coastguard Worker // Check whether Instr is a valid producer.
181*03ce13f7SAndroid Build Coastguard Worker Variable *Var = Instr.getDest();
182*03ce13f7SAndroid Build Coastguard Worker if (Var) { // only consider instructions with an actual dest var
183*03ce13f7SAndroid Build Coastguard Worker if (isBooleanType(Var->getType())) { // only bool-type dest vars
184*03ce13f7SAndroid Build Coastguard Worker if (getProducerKind(&Instr) != PK_None) { // white-listed instructions
185*03ce13f7SAndroid Build Coastguard Worker Producers[Var->getIndex()] = BoolFoldingEntry(&Instr);
186*03ce13f7SAndroid Build Coastguard Worker }
187*03ce13f7SAndroid Build Coastguard Worker }
188*03ce13f7SAndroid Build Coastguard Worker }
189*03ce13f7SAndroid Build Coastguard Worker // Check each src variable against the map.
190*03ce13f7SAndroid Build Coastguard Worker FOREACH_VAR_IN_INST(Var, Instr) {
191*03ce13f7SAndroid Build Coastguard Worker SizeT VarNum = Var->getIndex();
192*03ce13f7SAndroid Build Coastguard Worker if (!containsValid(VarNum))
193*03ce13f7SAndroid Build Coastguard Worker continue;
194*03ce13f7SAndroid Build Coastguard Worker // All valid consumers use Var as the first source operand
195*03ce13f7SAndroid Build Coastguard Worker if (IndexOfVarOperandInInst(Var) != 0) {
196*03ce13f7SAndroid Build Coastguard Worker setInvalid(VarNum);
197*03ce13f7SAndroid Build Coastguard Worker continue;
198*03ce13f7SAndroid Build Coastguard Worker }
199*03ce13f7SAndroid Build Coastguard Worker // Consumer instructions must be white-listed
200*03ce13f7SAndroid Build Coastguard Worker BoolFolding::BoolFoldingConsumerKind ConsumerKind =
201*03ce13f7SAndroid Build Coastguard Worker getConsumerKind(&Instr);
202*03ce13f7SAndroid Build Coastguard Worker if (ConsumerKind == CK_None) {
203*03ce13f7SAndroid Build Coastguard Worker setInvalid(VarNum);
204*03ce13f7SAndroid Build Coastguard Worker continue;
205*03ce13f7SAndroid Build Coastguard Worker }
206*03ce13f7SAndroid Build Coastguard Worker BoolFolding::BoolFoldingProducerKind ProducerKind =
207*03ce13f7SAndroid Build Coastguard Worker getProducerKind(Producers[VarNum].Instr);
208*03ce13f7SAndroid Build Coastguard Worker if (!isValidFolding(ProducerKind, ConsumerKind)) {
209*03ce13f7SAndroid Build Coastguard Worker setInvalid(VarNum);
210*03ce13f7SAndroid Build Coastguard Worker continue;
211*03ce13f7SAndroid Build Coastguard Worker }
212*03ce13f7SAndroid Build Coastguard Worker // Avoid creating multiple copies of complex producer instructions.
213*03ce13f7SAndroid Build Coastguard Worker if (Producers[VarNum].IsComplex && Producers[VarNum].NumUses > 0) {
214*03ce13f7SAndroid Build Coastguard Worker setInvalid(VarNum);
215*03ce13f7SAndroid Build Coastguard Worker continue;
216*03ce13f7SAndroid Build Coastguard Worker }
217*03ce13f7SAndroid Build Coastguard Worker ++Producers[VarNum].NumUses;
218*03ce13f7SAndroid Build Coastguard Worker if (Instr.isLastUse(Var)) {
219*03ce13f7SAndroid Build Coastguard Worker Producers[VarNum].IsLiveOut = false;
220*03ce13f7SAndroid Build Coastguard Worker }
221*03ce13f7SAndroid Build Coastguard Worker }
222*03ce13f7SAndroid Build Coastguard Worker }
223*03ce13f7SAndroid Build Coastguard Worker for (auto &I : Producers) {
224*03ce13f7SAndroid Build Coastguard Worker // Ignore entries previously marked invalid.
225*03ce13f7SAndroid Build Coastguard Worker if (I.second.Instr == nullptr)
226*03ce13f7SAndroid Build Coastguard Worker continue;
227*03ce13f7SAndroid Build Coastguard Worker // Disable the producer if its dest may be live beyond this block.
228*03ce13f7SAndroid Build Coastguard Worker if (I.second.IsLiveOut) {
229*03ce13f7SAndroid Build Coastguard Worker setInvalid(I.first);
230*03ce13f7SAndroid Build Coastguard Worker continue;
231*03ce13f7SAndroid Build Coastguard Worker }
232*03ce13f7SAndroid Build Coastguard Worker // Mark as "dead" rather than outright deleting. This is so that other
233*03ce13f7SAndroid Build Coastguard Worker // peephole style optimizations during or before lowering have access to
234*03ce13f7SAndroid Build Coastguard Worker // this instruction in undeleted form. See for example
235*03ce13f7SAndroid Build Coastguard Worker // tryOptimizedCmpxchgCmpBr().
236*03ce13f7SAndroid Build Coastguard Worker I.second.Instr->setDead();
237*03ce13f7SAndroid Build Coastguard Worker }
238*03ce13f7SAndroid Build Coastguard Worker }
239*03ce13f7SAndroid Build Coastguard Worker
getProducerFor(const Operand * Opnd) const240*03ce13f7SAndroid Build Coastguard Worker const Inst *BoolFolding::getProducerFor(const Operand *Opnd) const {
241*03ce13f7SAndroid Build Coastguard Worker auto *Var = llvm::dyn_cast<const Variable>(Opnd);
242*03ce13f7SAndroid Build Coastguard Worker if (Var == nullptr)
243*03ce13f7SAndroid Build Coastguard Worker return nullptr;
244*03ce13f7SAndroid Build Coastguard Worker SizeT VarNum = Var->getIndex();
245*03ce13f7SAndroid Build Coastguard Worker auto Element = Producers.find(VarNum);
246*03ce13f7SAndroid Build Coastguard Worker if (Element == Producers.end())
247*03ce13f7SAndroid Build Coastguard Worker return nullptr;
248*03ce13f7SAndroid Build Coastguard Worker return Element->second.Instr;
249*03ce13f7SAndroid Build Coastguard Worker }
250*03ce13f7SAndroid Build Coastguard Worker
dump(const Cfg * Func) const251*03ce13f7SAndroid Build Coastguard Worker void BoolFolding::dump(const Cfg *Func) const {
252*03ce13f7SAndroid Build Coastguard Worker if (!BuildDefs::dump() || !Func->isVerbose(IceV_Folding))
253*03ce13f7SAndroid Build Coastguard Worker return;
254*03ce13f7SAndroid Build Coastguard Worker OstreamLocker L(Func->getContext());
255*03ce13f7SAndroid Build Coastguard Worker Ostream &Str = Func->getContext()->getStrDump();
256*03ce13f7SAndroid Build Coastguard Worker for (auto &I : Producers) {
257*03ce13f7SAndroid Build Coastguard Worker if (I.second.Instr == nullptr)
258*03ce13f7SAndroid Build Coastguard Worker continue;
259*03ce13f7SAndroid Build Coastguard Worker Str << "Found foldable producer:\n ";
260*03ce13f7SAndroid Build Coastguard Worker I.second.Instr->dump(Func);
261*03ce13f7SAndroid Build Coastguard Worker Str << "\n";
262*03ce13f7SAndroid Build Coastguard Worker }
263*03ce13f7SAndroid Build Coastguard Worker }
264*03ce13f7SAndroid Build Coastguard Worker
265*03ce13f7SAndroid Build Coastguard Worker /// If the given instruction has potential memory side effects (e.g. store, rmw,
266*03ce13f7SAndroid Build Coastguard Worker /// or a call instruction with potential memory side effects), then we must not
267*03ce13f7SAndroid Build Coastguard Worker /// allow a pre-store Producer instruction with memory operands to be folded
268*03ce13f7SAndroid Build Coastguard Worker /// into a post-store Consumer instruction. If this is detected, the Producer
269*03ce13f7SAndroid Build Coastguard Worker /// is invalidated.
270*03ce13f7SAndroid Build Coastguard Worker ///
271*03ce13f7SAndroid Build Coastguard Worker /// We use the Producer's IsLiveOut field to determine whether any potential
272*03ce13f7SAndroid Build Coastguard Worker /// Consumers come after this store instruction. The IsLiveOut field is
273*03ce13f7SAndroid Build Coastguard Worker /// initialized to true, and BoolFolding::init() sets IsLiveOut to false when it
274*03ce13f7SAndroid Build Coastguard Worker /// sees the variable's definitive last use (indicating the variable is not in
275*03ce13f7SAndroid Build Coastguard Worker /// the node's live-out set). Thus if we see here that IsLiveOut is false, we
276*03ce13f7SAndroid Build Coastguard Worker /// know that there can be no consumers after the store, and therefore we know
277*03ce13f7SAndroid Build Coastguard Worker /// the folding is safe despite the store instruction.
278*03ce13f7SAndroid Build Coastguard Worker
invalidateProducersOnStore(const Inst * Instr)279*03ce13f7SAndroid Build Coastguard Worker void BoolFolding::invalidateProducersOnStore(const Inst *Instr) {
280*03ce13f7SAndroid Build Coastguard Worker if (!Instr->isMemoryWrite())
281*03ce13f7SAndroid Build Coastguard Worker return;
282*03ce13f7SAndroid Build Coastguard Worker for (auto &ProducerPair : Producers) {
283*03ce13f7SAndroid Build Coastguard Worker if (!ProducerPair.second.IsLiveOut)
284*03ce13f7SAndroid Build Coastguard Worker continue;
285*03ce13f7SAndroid Build Coastguard Worker Inst *PInst = ProducerPair.second.Instr;
286*03ce13f7SAndroid Build Coastguard Worker if (PInst == nullptr)
287*03ce13f7SAndroid Build Coastguard Worker continue;
288*03ce13f7SAndroid Build Coastguard Worker bool HasMemOperand = false;
289*03ce13f7SAndroid Build Coastguard Worker const SizeT SrcSize = PInst->getSrcSize();
290*03ce13f7SAndroid Build Coastguard Worker for (SizeT I = 0; I < SrcSize; ++I) {
291*03ce13f7SAndroid Build Coastguard Worker if (llvm::isa<X86OperandMem>(PInst->getSrc(I))) {
292*03ce13f7SAndroid Build Coastguard Worker HasMemOperand = true;
293*03ce13f7SAndroid Build Coastguard Worker break;
294*03ce13f7SAndroid Build Coastguard Worker }
295*03ce13f7SAndroid Build Coastguard Worker }
296*03ce13f7SAndroid Build Coastguard Worker if (!HasMemOperand)
297*03ce13f7SAndroid Build Coastguard Worker continue;
298*03ce13f7SAndroid Build Coastguard Worker setInvalid(ProducerPair.first);
299*03ce13f7SAndroid Build Coastguard Worker }
300*03ce13f7SAndroid Build Coastguard Worker }
301*03ce13f7SAndroid Build Coastguard Worker
initNodeForLowering(CfgNode * Node)302*03ce13f7SAndroid Build Coastguard Worker void TargetX8632::initNodeForLowering(CfgNode *Node) {
303*03ce13f7SAndroid Build Coastguard Worker FoldingInfo.init(Node);
304*03ce13f7SAndroid Build Coastguard Worker FoldingInfo.dump(Func);
305*03ce13f7SAndroid Build Coastguard Worker }
306*03ce13f7SAndroid Build Coastguard Worker
TargetX8632(Cfg * Func)307*03ce13f7SAndroid Build Coastguard Worker TargetX8632::TargetX8632(Cfg *Func) : TargetX86(Func) {}
308*03ce13f7SAndroid Build Coastguard Worker
staticInit(GlobalContext * Ctx)309*03ce13f7SAndroid Build Coastguard Worker void TargetX8632::staticInit(GlobalContext *Ctx) {
310*03ce13f7SAndroid Build Coastguard Worker RegNumT::setLimit(RegX8632::Reg_NUM);
311*03ce13f7SAndroid Build Coastguard Worker RegX8632::initRegisterSet(getFlags(), &TypeToRegisterSet, &RegisterAliases);
312*03ce13f7SAndroid Build Coastguard Worker for (size_t i = 0; i < TypeToRegisterSet.size(); ++i)
313*03ce13f7SAndroid Build Coastguard Worker TypeToRegisterSetUnfiltered[i] = TypeToRegisterSet[i];
314*03ce13f7SAndroid Build Coastguard Worker filterTypeToRegisterSet(Ctx, RegX8632::Reg_NUM, TypeToRegisterSet.data(),
315*03ce13f7SAndroid Build Coastguard Worker TypeToRegisterSet.size(), RegX8632::getRegName,
316*03ce13f7SAndroid Build Coastguard Worker getRegClassName);
317*03ce13f7SAndroid Build Coastguard Worker }
318*03ce13f7SAndroid Build Coastguard Worker
shouldBePooled(const Constant * C)319*03ce13f7SAndroid Build Coastguard Worker bool TargetX8632::shouldBePooled(const Constant *C) {
320*03ce13f7SAndroid Build Coastguard Worker if (auto *ConstFloat = llvm::dyn_cast<ConstantFloat>(C)) {
321*03ce13f7SAndroid Build Coastguard Worker return !Utils::isPositiveZero(ConstFloat->getValue());
322*03ce13f7SAndroid Build Coastguard Worker }
323*03ce13f7SAndroid Build Coastguard Worker if (auto *ConstDouble = llvm::dyn_cast<ConstantDouble>(C)) {
324*03ce13f7SAndroid Build Coastguard Worker return !Utils::isPositiveZero(ConstDouble->getValue());
325*03ce13f7SAndroid Build Coastguard Worker }
326*03ce13f7SAndroid Build Coastguard Worker return false;
327*03ce13f7SAndroid Build Coastguard Worker }
328*03ce13f7SAndroid Build Coastguard Worker
getPointerType()329*03ce13f7SAndroid Build Coastguard Worker Type TargetX8632::getPointerType() { return IceType_i32; }
330*03ce13f7SAndroid Build Coastguard Worker
translateO2()331*03ce13f7SAndroid Build Coastguard Worker void TargetX8632::translateO2() {
332*03ce13f7SAndroid Build Coastguard Worker TimerMarker T(TimerStack::TT_O2, Func);
333*03ce13f7SAndroid Build Coastguard Worker
334*03ce13f7SAndroid Build Coastguard Worker genTargetHelperCalls();
335*03ce13f7SAndroid Build Coastguard Worker Func->dump("After target helper call insertion");
336*03ce13f7SAndroid Build Coastguard Worker
337*03ce13f7SAndroid Build Coastguard Worker // Merge Alloca instructions, and lay out the stack.
338*03ce13f7SAndroid Build Coastguard Worker static constexpr bool SortAndCombineAllocas = true;
339*03ce13f7SAndroid Build Coastguard Worker Func->processAllocas(SortAndCombineAllocas);
340*03ce13f7SAndroid Build Coastguard Worker Func->dump("After Alloca processing");
341*03ce13f7SAndroid Build Coastguard Worker
342*03ce13f7SAndroid Build Coastguard Worker // Run this early so it can be used to focus optimizations on potentially hot
343*03ce13f7SAndroid Build Coastguard Worker // code.
344*03ce13f7SAndroid Build Coastguard Worker // TODO(stichnot,ascull): currently only used for regalloc not
345*03ce13f7SAndroid Build Coastguard Worker // expensive high level optimizations which could be focused on potentially
346*03ce13f7SAndroid Build Coastguard Worker // hot code.
347*03ce13f7SAndroid Build Coastguard Worker Func->generateLoopInfo();
348*03ce13f7SAndroid Build Coastguard Worker Func->dump("After loop analysis");
349*03ce13f7SAndroid Build Coastguard Worker if (getFlags().getLoopInvariantCodeMotion()) {
350*03ce13f7SAndroid Build Coastguard Worker Func->loopInvariantCodeMotion();
351*03ce13f7SAndroid Build Coastguard Worker Func->dump("After LICM");
352*03ce13f7SAndroid Build Coastguard Worker }
353*03ce13f7SAndroid Build Coastguard Worker
354*03ce13f7SAndroid Build Coastguard Worker if (getFlags().getLocalCSE() != Ice::LCSE_Disabled) {
355*03ce13f7SAndroid Build Coastguard Worker Func->localCSE(getFlags().getLocalCSE() == Ice::LCSE_EnabledSSA);
356*03ce13f7SAndroid Build Coastguard Worker Func->dump("After Local CSE");
357*03ce13f7SAndroid Build Coastguard Worker Func->floatConstantCSE();
358*03ce13f7SAndroid Build Coastguard Worker }
359*03ce13f7SAndroid Build Coastguard Worker if (getFlags().getEnableShortCircuit()) {
360*03ce13f7SAndroid Build Coastguard Worker Func->shortCircuitJumps();
361*03ce13f7SAndroid Build Coastguard Worker Func->dump("After Short Circuiting");
362*03ce13f7SAndroid Build Coastguard Worker }
363*03ce13f7SAndroid Build Coastguard Worker
364*03ce13f7SAndroid Build Coastguard Worker if (!getFlags().getEnablePhiEdgeSplit()) {
365*03ce13f7SAndroid Build Coastguard Worker // Lower Phi instructions.
366*03ce13f7SAndroid Build Coastguard Worker Func->placePhiLoads();
367*03ce13f7SAndroid Build Coastguard Worker if (Func->hasError())
368*03ce13f7SAndroid Build Coastguard Worker return;
369*03ce13f7SAndroid Build Coastguard Worker Func->placePhiStores();
370*03ce13f7SAndroid Build Coastguard Worker if (Func->hasError())
371*03ce13f7SAndroid Build Coastguard Worker return;
372*03ce13f7SAndroid Build Coastguard Worker Func->deletePhis();
373*03ce13f7SAndroid Build Coastguard Worker if (Func->hasError())
374*03ce13f7SAndroid Build Coastguard Worker return;
375*03ce13f7SAndroid Build Coastguard Worker Func->dump("After Phi lowering");
376*03ce13f7SAndroid Build Coastguard Worker }
377*03ce13f7SAndroid Build Coastguard Worker
378*03ce13f7SAndroid Build Coastguard Worker // Address mode optimization.
379*03ce13f7SAndroid Build Coastguard Worker Func->getVMetadata()->init(VMK_SingleDefs);
380*03ce13f7SAndroid Build Coastguard Worker Func->doAddressOpt();
381*03ce13f7SAndroid Build Coastguard Worker Func->materializeVectorShuffles();
382*03ce13f7SAndroid Build Coastguard Worker
383*03ce13f7SAndroid Build Coastguard Worker // Find read-modify-write opportunities. Do this after address mode
384*03ce13f7SAndroid Build Coastguard Worker // optimization so that doAddressOpt() doesn't need to be applied to RMW
385*03ce13f7SAndroid Build Coastguard Worker // instructions as well.
386*03ce13f7SAndroid Build Coastguard Worker findRMW();
387*03ce13f7SAndroid Build Coastguard Worker Func->dump("After RMW transform");
388*03ce13f7SAndroid Build Coastguard Worker
389*03ce13f7SAndroid Build Coastguard Worker // Argument lowering
390*03ce13f7SAndroid Build Coastguard Worker Func->doArgLowering();
391*03ce13f7SAndroid Build Coastguard Worker
392*03ce13f7SAndroid Build Coastguard Worker // Target lowering. This requires liveness analysis for some parts of the
393*03ce13f7SAndroid Build Coastguard Worker // lowering decisions, such as compare/branch fusing. If non-lightweight
394*03ce13f7SAndroid Build Coastguard Worker // liveness analysis is used, the instructions need to be renumbered first
395*03ce13f7SAndroid Build Coastguard Worker // TODO: This renumbering should only be necessary if we're actually
396*03ce13f7SAndroid Build Coastguard Worker // calculating live intervals, which we only do for register allocation.
397*03ce13f7SAndroid Build Coastguard Worker Func->renumberInstructions();
398*03ce13f7SAndroid Build Coastguard Worker if (Func->hasError())
399*03ce13f7SAndroid Build Coastguard Worker return;
400*03ce13f7SAndroid Build Coastguard Worker
401*03ce13f7SAndroid Build Coastguard Worker // TODO: It should be sufficient to use the fastest liveness calculation,
402*03ce13f7SAndroid Build Coastguard Worker // i.e. livenessLightweight(). However, for some reason that slows down the
403*03ce13f7SAndroid Build Coastguard Worker // rest of the translation. Investigate.
404*03ce13f7SAndroid Build Coastguard Worker Func->liveness(Liveness_Basic);
405*03ce13f7SAndroid Build Coastguard Worker if (Func->hasError())
406*03ce13f7SAndroid Build Coastguard Worker return;
407*03ce13f7SAndroid Build Coastguard Worker Func->dump("After x86 address mode opt");
408*03ce13f7SAndroid Build Coastguard Worker
409*03ce13f7SAndroid Build Coastguard Worker doLoadOpt();
410*03ce13f7SAndroid Build Coastguard Worker
411*03ce13f7SAndroid Build Coastguard Worker Func->genCode();
412*03ce13f7SAndroid Build Coastguard Worker if (Func->hasError())
413*03ce13f7SAndroid Build Coastguard Worker return;
414*03ce13f7SAndroid Build Coastguard Worker Func->dump("After x86 codegen");
415*03ce13f7SAndroid Build Coastguard Worker splitBlockLocalVariables(Func);
416*03ce13f7SAndroid Build Coastguard Worker
417*03ce13f7SAndroid Build Coastguard Worker // Register allocation. This requires instruction renumbering and full
418*03ce13f7SAndroid Build Coastguard Worker // liveness analysis. Loops must be identified before liveness so variable
419*03ce13f7SAndroid Build Coastguard Worker // use weights are correct.
420*03ce13f7SAndroid Build Coastguard Worker Func->renumberInstructions();
421*03ce13f7SAndroid Build Coastguard Worker if (Func->hasError())
422*03ce13f7SAndroid Build Coastguard Worker return;
423*03ce13f7SAndroid Build Coastguard Worker Func->liveness(Liveness_Intervals);
424*03ce13f7SAndroid Build Coastguard Worker if (Func->hasError())
425*03ce13f7SAndroid Build Coastguard Worker return;
426*03ce13f7SAndroid Build Coastguard Worker // The post-codegen dump is done here, after liveness analysis and associated
427*03ce13f7SAndroid Build Coastguard Worker // cleanup, to make the dump cleaner and more useful.
428*03ce13f7SAndroid Build Coastguard Worker Func->dump("After initial x86 codegen");
429*03ce13f7SAndroid Build Coastguard Worker // Validate the live range computations. The expensive validation call is
430*03ce13f7SAndroid Build Coastguard Worker // deliberately only made when assertions are enabled.
431*03ce13f7SAndroid Build Coastguard Worker assert(Func->validateLiveness());
432*03ce13f7SAndroid Build Coastguard Worker Func->getVMetadata()->init(VMK_All);
433*03ce13f7SAndroid Build Coastguard Worker regAlloc(RAK_Global);
434*03ce13f7SAndroid Build Coastguard Worker if (Func->hasError())
435*03ce13f7SAndroid Build Coastguard Worker return;
436*03ce13f7SAndroid Build Coastguard Worker Func->dump("After linear scan regalloc");
437*03ce13f7SAndroid Build Coastguard Worker
438*03ce13f7SAndroid Build Coastguard Worker if (getFlags().getEnablePhiEdgeSplit()) {
439*03ce13f7SAndroid Build Coastguard Worker Func->advancedPhiLowering();
440*03ce13f7SAndroid Build Coastguard Worker Func->dump("After advanced Phi lowering");
441*03ce13f7SAndroid Build Coastguard Worker }
442*03ce13f7SAndroid Build Coastguard Worker
443*03ce13f7SAndroid Build Coastguard Worker // Stack frame mapping.
444*03ce13f7SAndroid Build Coastguard Worker Func->genFrame();
445*03ce13f7SAndroid Build Coastguard Worker if (Func->hasError())
446*03ce13f7SAndroid Build Coastguard Worker return;
447*03ce13f7SAndroid Build Coastguard Worker Func->dump("After stack frame mapping");
448*03ce13f7SAndroid Build Coastguard Worker
449*03ce13f7SAndroid Build Coastguard Worker Func->contractEmptyNodes();
450*03ce13f7SAndroid Build Coastguard Worker Func->reorderNodes();
451*03ce13f7SAndroid Build Coastguard Worker
452*03ce13f7SAndroid Build Coastguard Worker // Branch optimization. This needs to be done just before code emission. In
453*03ce13f7SAndroid Build Coastguard Worker // particular, no transformations that insert or reorder CfgNodes should be
454*03ce13f7SAndroid Build Coastguard Worker // done after branch optimization. We go ahead and do it before nop insertion
455*03ce13f7SAndroid Build Coastguard Worker // to reduce the amount of work needed for searching for opportunities.
456*03ce13f7SAndroid Build Coastguard Worker Func->doBranchOpt();
457*03ce13f7SAndroid Build Coastguard Worker Func->dump("After branch optimization");
458*03ce13f7SAndroid Build Coastguard Worker }
459*03ce13f7SAndroid Build Coastguard Worker
translateOm1()460*03ce13f7SAndroid Build Coastguard Worker void TargetX8632::translateOm1() {
461*03ce13f7SAndroid Build Coastguard Worker TimerMarker T(TimerStack::TT_Om1, Func);
462*03ce13f7SAndroid Build Coastguard Worker
463*03ce13f7SAndroid Build Coastguard Worker genTargetHelperCalls();
464*03ce13f7SAndroid Build Coastguard Worker
465*03ce13f7SAndroid Build Coastguard Worker // Do not merge Alloca instructions, and lay out the stack.
466*03ce13f7SAndroid Build Coastguard Worker // static constexpr bool SortAndCombineAllocas = false;
467*03ce13f7SAndroid Build Coastguard Worker static constexpr bool SortAndCombineAllocas =
468*03ce13f7SAndroid Build Coastguard Worker true; // TODO(b/171222930): Fix Win32 bug when this is false
469*03ce13f7SAndroid Build Coastguard Worker Func->processAllocas(SortAndCombineAllocas);
470*03ce13f7SAndroid Build Coastguard Worker Func->dump("After Alloca processing");
471*03ce13f7SAndroid Build Coastguard Worker
472*03ce13f7SAndroid Build Coastguard Worker Func->placePhiLoads();
473*03ce13f7SAndroid Build Coastguard Worker if (Func->hasError())
474*03ce13f7SAndroid Build Coastguard Worker return;
475*03ce13f7SAndroid Build Coastguard Worker Func->placePhiStores();
476*03ce13f7SAndroid Build Coastguard Worker if (Func->hasError())
477*03ce13f7SAndroid Build Coastguard Worker return;
478*03ce13f7SAndroid Build Coastguard Worker Func->deletePhis();
479*03ce13f7SAndroid Build Coastguard Worker if (Func->hasError())
480*03ce13f7SAndroid Build Coastguard Worker return;
481*03ce13f7SAndroid Build Coastguard Worker Func->dump("After Phi lowering");
482*03ce13f7SAndroid Build Coastguard Worker
483*03ce13f7SAndroid Build Coastguard Worker Func->doArgLowering();
484*03ce13f7SAndroid Build Coastguard Worker Func->genCode();
485*03ce13f7SAndroid Build Coastguard Worker if (Func->hasError())
486*03ce13f7SAndroid Build Coastguard Worker return;
487*03ce13f7SAndroid Build Coastguard Worker Func->dump("After initial x86 codegen");
488*03ce13f7SAndroid Build Coastguard Worker
489*03ce13f7SAndroid Build Coastguard Worker regAlloc(RAK_InfOnly);
490*03ce13f7SAndroid Build Coastguard Worker if (Func->hasError())
491*03ce13f7SAndroid Build Coastguard Worker return;
492*03ce13f7SAndroid Build Coastguard Worker Func->dump("After regalloc of infinite-weight variables");
493*03ce13f7SAndroid Build Coastguard Worker
494*03ce13f7SAndroid Build Coastguard Worker Func->genFrame();
495*03ce13f7SAndroid Build Coastguard Worker if (Func->hasError())
496*03ce13f7SAndroid Build Coastguard Worker return;
497*03ce13f7SAndroid Build Coastguard Worker Func->dump("After stack frame mapping");
498*03ce13f7SAndroid Build Coastguard Worker }
499*03ce13f7SAndroid Build Coastguard Worker
canRMW(const InstArithmetic * Arith)500*03ce13f7SAndroid Build Coastguard Worker inline bool canRMW(const InstArithmetic *Arith) {
501*03ce13f7SAndroid Build Coastguard Worker Type Ty = Arith->getDest()->getType();
502*03ce13f7SAndroid Build Coastguard Worker // X86 vector instructions write to a register and have no RMW option.
503*03ce13f7SAndroid Build Coastguard Worker if (isVectorType(Ty))
504*03ce13f7SAndroid Build Coastguard Worker return false;
505*03ce13f7SAndroid Build Coastguard Worker bool isI64 = Ty == IceType_i64;
506*03ce13f7SAndroid Build Coastguard Worker
507*03ce13f7SAndroid Build Coastguard Worker switch (Arith->getOp()) {
508*03ce13f7SAndroid Build Coastguard Worker // Not handled for lack of simple lowering:
509*03ce13f7SAndroid Build Coastguard Worker // shift on i64
510*03ce13f7SAndroid Build Coastguard Worker // mul, udiv, urem, sdiv, srem, frem
511*03ce13f7SAndroid Build Coastguard Worker // Not handled for lack of RMW instructions:
512*03ce13f7SAndroid Build Coastguard Worker // fadd, fsub, fmul, fdiv (also vector types)
513*03ce13f7SAndroid Build Coastguard Worker default:
514*03ce13f7SAndroid Build Coastguard Worker return false;
515*03ce13f7SAndroid Build Coastguard Worker case InstArithmetic::Add:
516*03ce13f7SAndroid Build Coastguard Worker case InstArithmetic::Sub:
517*03ce13f7SAndroid Build Coastguard Worker case InstArithmetic::And:
518*03ce13f7SAndroid Build Coastguard Worker case InstArithmetic::Or:
519*03ce13f7SAndroid Build Coastguard Worker case InstArithmetic::Xor:
520*03ce13f7SAndroid Build Coastguard Worker return true;
521*03ce13f7SAndroid Build Coastguard Worker case InstArithmetic::Shl:
522*03ce13f7SAndroid Build Coastguard Worker case InstArithmetic::Lshr:
523*03ce13f7SAndroid Build Coastguard Worker case InstArithmetic::Ashr:
524*03ce13f7SAndroid Build Coastguard Worker return false; // TODO(stichnot): implement
525*03ce13f7SAndroid Build Coastguard Worker return !isI64;
526*03ce13f7SAndroid Build Coastguard Worker }
527*03ce13f7SAndroid Build Coastguard Worker }
528*03ce13f7SAndroid Build Coastguard Worker
isSameMemAddressOperand(const Operand * A,const Operand * B)529*03ce13f7SAndroid Build Coastguard Worker bool isSameMemAddressOperand(const Operand *A, const Operand *B) {
530*03ce13f7SAndroid Build Coastguard Worker if (A == B)
531*03ce13f7SAndroid Build Coastguard Worker return true;
532*03ce13f7SAndroid Build Coastguard Worker if (auto *MemA = llvm::dyn_cast<X86OperandMem>(A)) {
533*03ce13f7SAndroid Build Coastguard Worker if (auto *MemB = llvm::dyn_cast<X86OperandMem>(B)) {
534*03ce13f7SAndroid Build Coastguard Worker return MemA->getBase() == MemB->getBase() &&
535*03ce13f7SAndroid Build Coastguard Worker MemA->getOffset() == MemB->getOffset() &&
536*03ce13f7SAndroid Build Coastguard Worker MemA->getIndex() == MemB->getIndex() &&
537*03ce13f7SAndroid Build Coastguard Worker MemA->getShift() == MemB->getShift() &&
538*03ce13f7SAndroid Build Coastguard Worker MemA->getSegmentRegister() == MemB->getSegmentRegister();
539*03ce13f7SAndroid Build Coastguard Worker }
540*03ce13f7SAndroid Build Coastguard Worker }
541*03ce13f7SAndroid Build Coastguard Worker return false;
542*03ce13f7SAndroid Build Coastguard Worker }
543*03ce13f7SAndroid Build Coastguard Worker
findRMW()544*03ce13f7SAndroid Build Coastguard Worker void TargetX8632::findRMW() {
545*03ce13f7SAndroid Build Coastguard Worker TimerMarker _(TimerStack::TT_findRMW, Func);
546*03ce13f7SAndroid Build Coastguard Worker Func->dump("Before RMW");
547*03ce13f7SAndroid Build Coastguard Worker if (Func->isVerbose(IceV_RMW))
548*03ce13f7SAndroid Build Coastguard Worker Func->getContext()->lockStr();
549*03ce13f7SAndroid Build Coastguard Worker for (CfgNode *Node : Func->getNodes()) {
550*03ce13f7SAndroid Build Coastguard Worker // Walk through the instructions, considering each sequence of 3
551*03ce13f7SAndroid Build Coastguard Worker // instructions, and look for the particular RMW pattern. Note that this
552*03ce13f7SAndroid Build Coastguard Worker // search can be "broken" (false negatives) if there are intervening
553*03ce13f7SAndroid Build Coastguard Worker // deleted instructions, or intervening instructions that could be safely
554*03ce13f7SAndroid Build Coastguard Worker // moved out of the way to reveal an RMW pattern.
555*03ce13f7SAndroid Build Coastguard Worker auto E = Node->getInsts().end();
556*03ce13f7SAndroid Build Coastguard Worker auto I1 = E, I2 = E, I3 = Node->getInsts().begin();
557*03ce13f7SAndroid Build Coastguard Worker for (; I3 != E; I1 = I2, I2 = I3, ++I3) {
558*03ce13f7SAndroid Build Coastguard Worker // Make I3 skip over deleted instructions.
559*03ce13f7SAndroid Build Coastguard Worker while (I3 != E && I3->isDeleted())
560*03ce13f7SAndroid Build Coastguard Worker ++I3;
561*03ce13f7SAndroid Build Coastguard Worker if (I1 == E || I2 == E || I3 == E)
562*03ce13f7SAndroid Build Coastguard Worker continue;
563*03ce13f7SAndroid Build Coastguard Worker assert(!I1->isDeleted());
564*03ce13f7SAndroid Build Coastguard Worker assert(!I2->isDeleted());
565*03ce13f7SAndroid Build Coastguard Worker assert(!I3->isDeleted());
566*03ce13f7SAndroid Build Coastguard Worker auto *Load = llvm::dyn_cast<InstLoad>(I1);
567*03ce13f7SAndroid Build Coastguard Worker auto *Arith = llvm::dyn_cast<InstArithmetic>(I2);
568*03ce13f7SAndroid Build Coastguard Worker auto *Store = llvm::dyn_cast<InstStore>(I3);
569*03ce13f7SAndroid Build Coastguard Worker if (!Load || !Arith || !Store)
570*03ce13f7SAndroid Build Coastguard Worker continue;
571*03ce13f7SAndroid Build Coastguard Worker // Look for:
572*03ce13f7SAndroid Build Coastguard Worker // a = Load addr
573*03ce13f7SAndroid Build Coastguard Worker // b = <op> a, other
574*03ce13f7SAndroid Build Coastguard Worker // Store b, addr
575*03ce13f7SAndroid Build Coastguard Worker // Change to:
576*03ce13f7SAndroid Build Coastguard Worker // a = Load addr
577*03ce13f7SAndroid Build Coastguard Worker // b = <op> a, other
578*03ce13f7SAndroid Build Coastguard Worker // x = FakeDef
579*03ce13f7SAndroid Build Coastguard Worker // RMW <op>, addr, other, x
580*03ce13f7SAndroid Build Coastguard Worker // b = Store b, addr, x
581*03ce13f7SAndroid Build Coastguard Worker // Note that inferTwoAddress() makes sure setDestRedefined() gets called
582*03ce13f7SAndroid Build Coastguard Worker // on the updated Store instruction, to avoid liveness problems later.
583*03ce13f7SAndroid Build Coastguard Worker //
584*03ce13f7SAndroid Build Coastguard Worker // With this transformation, the Store instruction acquires a Dest
585*03ce13f7SAndroid Build Coastguard Worker // variable and is now subject to dead code elimination if there are no
586*03ce13f7SAndroid Build Coastguard Worker // more uses of "b". Variable "x" is a beacon for determining whether the
587*03ce13f7SAndroid Build Coastguard Worker // Store instruction gets dead-code eliminated. If the Store instruction
588*03ce13f7SAndroid Build Coastguard Worker // is eliminated, then it must be the case that the RMW instruction ends
589*03ce13f7SAndroid Build Coastguard Worker // x's live range, and therefore the RMW instruction will be retained and
590*03ce13f7SAndroid Build Coastguard Worker // later lowered. On the other hand, if the RMW instruction does not end
591*03ce13f7SAndroid Build Coastguard Worker // x's live range, then the Store instruction must still be present, and
592*03ce13f7SAndroid Build Coastguard Worker // therefore the RMW instruction is ignored during lowering because it is
593*03ce13f7SAndroid Build Coastguard Worker // redundant with the Store instruction.
594*03ce13f7SAndroid Build Coastguard Worker //
595*03ce13f7SAndroid Build Coastguard Worker // Note that if "a" has further uses, the RMW transformation may still
596*03ce13f7SAndroid Build Coastguard Worker // trigger, resulting in two loads and one store, which is worse than the
597*03ce13f7SAndroid Build Coastguard Worker // original one load and one store. However, this is probably rare, and
598*03ce13f7SAndroid Build Coastguard Worker // caching probably keeps it just as fast.
599*03ce13f7SAndroid Build Coastguard Worker if (!isSameMemAddressOperand(Load->getLoadAddress(),
600*03ce13f7SAndroid Build Coastguard Worker Store->getStoreAddress()))
601*03ce13f7SAndroid Build Coastguard Worker continue;
602*03ce13f7SAndroid Build Coastguard Worker Operand *ArithSrcFromLoad = Arith->getSrc(0);
603*03ce13f7SAndroid Build Coastguard Worker Operand *ArithSrcOther = Arith->getSrc(1);
604*03ce13f7SAndroid Build Coastguard Worker if (ArithSrcFromLoad != Load->getDest()) {
605*03ce13f7SAndroid Build Coastguard Worker if (!Arith->isCommutative() || ArithSrcOther != Load->getDest())
606*03ce13f7SAndroid Build Coastguard Worker continue;
607*03ce13f7SAndroid Build Coastguard Worker std::swap(ArithSrcFromLoad, ArithSrcOther);
608*03ce13f7SAndroid Build Coastguard Worker }
609*03ce13f7SAndroid Build Coastguard Worker if (Arith->getDest() != Store->getData())
610*03ce13f7SAndroid Build Coastguard Worker continue;
611*03ce13f7SAndroid Build Coastguard Worker if (!canRMW(Arith))
612*03ce13f7SAndroid Build Coastguard Worker continue;
613*03ce13f7SAndroid Build Coastguard Worker if (Func->isVerbose(IceV_RMW)) {
614*03ce13f7SAndroid Build Coastguard Worker Ostream &Str = Func->getContext()->getStrDump();
615*03ce13f7SAndroid Build Coastguard Worker Str << "Found RMW in " << Func->getFunctionName() << ":\n ";
616*03ce13f7SAndroid Build Coastguard Worker Load->dump(Func);
617*03ce13f7SAndroid Build Coastguard Worker Str << "\n ";
618*03ce13f7SAndroid Build Coastguard Worker Arith->dump(Func);
619*03ce13f7SAndroid Build Coastguard Worker Str << "\n ";
620*03ce13f7SAndroid Build Coastguard Worker Store->dump(Func);
621*03ce13f7SAndroid Build Coastguard Worker Str << "\n";
622*03ce13f7SAndroid Build Coastguard Worker }
623*03ce13f7SAndroid Build Coastguard Worker Variable *Beacon = Func->makeVariable(IceType_i32);
624*03ce13f7SAndroid Build Coastguard Worker Beacon->setMustNotHaveReg();
625*03ce13f7SAndroid Build Coastguard Worker Store->setRmwBeacon(Beacon);
626*03ce13f7SAndroid Build Coastguard Worker auto *BeaconDef = InstFakeDef::create(Func, Beacon);
627*03ce13f7SAndroid Build Coastguard Worker Node->getInsts().insert(I3, BeaconDef);
628*03ce13f7SAndroid Build Coastguard Worker auto *RMW =
629*03ce13f7SAndroid Build Coastguard Worker InstX86FakeRMW::create(Func, ArithSrcOther, Store->getStoreAddress(),
630*03ce13f7SAndroid Build Coastguard Worker Beacon, Arith->getOp());
631*03ce13f7SAndroid Build Coastguard Worker Node->getInsts().insert(I3, RMW);
632*03ce13f7SAndroid Build Coastguard Worker }
633*03ce13f7SAndroid Build Coastguard Worker }
634*03ce13f7SAndroid Build Coastguard Worker if (Func->isVerbose(IceV_RMW))
635*03ce13f7SAndroid Build Coastguard Worker Func->getContext()->unlockStr();
636*03ce13f7SAndroid Build Coastguard Worker }
637*03ce13f7SAndroid Build Coastguard Worker
638*03ce13f7SAndroid Build Coastguard Worker /// Value is in bytes. Return Value adjusted to the next highest multiple of
639*03ce13f7SAndroid Build Coastguard Worker /// the stack alignment.
applyStackAlignment(uint32_t Value)640*03ce13f7SAndroid Build Coastguard Worker uint32_t TargetX8632::applyStackAlignment(uint32_t Value) {
641*03ce13f7SAndroid Build Coastguard Worker return Utils::applyAlignment(Value, X86_STACK_ALIGNMENT_BYTES);
642*03ce13f7SAndroid Build Coastguard Worker }
643*03ce13f7SAndroid Build Coastguard Worker
644*03ce13f7SAndroid Build Coastguard Worker // Converts a ConstantInteger32 operand into its constant value, or
645*03ce13f7SAndroid Build Coastguard Worker // MemoryOrderInvalid if the operand is not a ConstantInteger32.
getConstantMemoryOrder(Operand * Opnd)646*03ce13f7SAndroid Build Coastguard Worker inline uint64_t getConstantMemoryOrder(Operand *Opnd) {
647*03ce13f7SAndroid Build Coastguard Worker if (auto *Integer = llvm::dyn_cast<ConstantInteger32>(Opnd))
648*03ce13f7SAndroid Build Coastguard Worker return Integer->getValue();
649*03ce13f7SAndroid Build Coastguard Worker return Intrinsics::MemoryOrderInvalid;
650*03ce13f7SAndroid Build Coastguard Worker }
651*03ce13f7SAndroid Build Coastguard Worker
652*03ce13f7SAndroid Build Coastguard Worker /// Determines whether the dest of a Load instruction can be folded into one of
653*03ce13f7SAndroid Build Coastguard Worker /// the src operands of a 2-operand instruction. This is true as long as the
654*03ce13f7SAndroid Build Coastguard Worker /// load dest matches exactly one of the binary instruction's src operands.
655*03ce13f7SAndroid Build Coastguard Worker /// Replaces Src0 or Src1 with LoadSrc if the answer is true.
canFoldLoadIntoBinaryInst(Operand * LoadSrc,Variable * LoadDest,Operand * & Src0,Operand * & Src1)656*03ce13f7SAndroid Build Coastguard Worker inline bool canFoldLoadIntoBinaryInst(Operand *LoadSrc, Variable *LoadDest,
657*03ce13f7SAndroid Build Coastguard Worker Operand *&Src0, Operand *&Src1) {
658*03ce13f7SAndroid Build Coastguard Worker if (Src0 == LoadDest && Src1 != LoadDest) {
659*03ce13f7SAndroid Build Coastguard Worker Src0 = LoadSrc;
660*03ce13f7SAndroid Build Coastguard Worker return true;
661*03ce13f7SAndroid Build Coastguard Worker }
662*03ce13f7SAndroid Build Coastguard Worker if (Src0 != LoadDest && Src1 == LoadDest) {
663*03ce13f7SAndroid Build Coastguard Worker Src1 = LoadSrc;
664*03ce13f7SAndroid Build Coastguard Worker return true;
665*03ce13f7SAndroid Build Coastguard Worker }
666*03ce13f7SAndroid Build Coastguard Worker return false;
667*03ce13f7SAndroid Build Coastguard Worker }
668*03ce13f7SAndroid Build Coastguard Worker
doLoadOpt()669*03ce13f7SAndroid Build Coastguard Worker void TargetX8632::doLoadOpt() {
670*03ce13f7SAndroid Build Coastguard Worker TimerMarker _(TimerStack::TT_loadOpt, Func);
671*03ce13f7SAndroid Build Coastguard Worker for (CfgNode *Node : Func->getNodes()) {
672*03ce13f7SAndroid Build Coastguard Worker Context.init(Node);
673*03ce13f7SAndroid Build Coastguard Worker while (!Context.atEnd()) {
674*03ce13f7SAndroid Build Coastguard Worker Variable *LoadDest = nullptr;
675*03ce13f7SAndroid Build Coastguard Worker Operand *LoadSrc = nullptr;
676*03ce13f7SAndroid Build Coastguard Worker Inst *CurInst = iteratorToInst(Context.getCur());
677*03ce13f7SAndroid Build Coastguard Worker Inst *Next = Context.getNextInst();
678*03ce13f7SAndroid Build Coastguard Worker // Determine whether the current instruction is a Load instruction or
679*03ce13f7SAndroid Build Coastguard Worker // equivalent.
680*03ce13f7SAndroid Build Coastguard Worker if (auto *Load = llvm::dyn_cast<InstLoad>(CurInst)) {
681*03ce13f7SAndroid Build Coastguard Worker // An InstLoad qualifies unless it uses a 64-bit absolute address,
682*03ce13f7SAndroid Build Coastguard Worker // which requires legalization to insert a copy to register.
683*03ce13f7SAndroid Build Coastguard Worker // TODO(b/148272103): Fold these after legalization.
684*03ce13f7SAndroid Build Coastguard Worker LoadDest = Load->getDest();
685*03ce13f7SAndroid Build Coastguard Worker constexpr bool DoLegalize = false;
686*03ce13f7SAndroid Build Coastguard Worker LoadSrc = formMemoryOperand(Load->getLoadAddress(), LoadDest->getType(),
687*03ce13f7SAndroid Build Coastguard Worker DoLegalize);
688*03ce13f7SAndroid Build Coastguard Worker } else if (auto *Intrin = llvm::dyn_cast<InstIntrinsic>(CurInst)) {
689*03ce13f7SAndroid Build Coastguard Worker // An AtomicLoad intrinsic qualifies as long as it has a valid memory
690*03ce13f7SAndroid Build Coastguard Worker // ordering, and can be implemented in a single instruction (i.e., not
691*03ce13f7SAndroid Build Coastguard Worker // i64 on x86-32).
692*03ce13f7SAndroid Build Coastguard Worker Intrinsics::IntrinsicID ID = Intrin->getIntrinsicID();
693*03ce13f7SAndroid Build Coastguard Worker if (ID == Intrinsics::AtomicLoad &&
694*03ce13f7SAndroid Build Coastguard Worker (Intrin->getDest()->getType() != IceType_i64) &&
695*03ce13f7SAndroid Build Coastguard Worker Intrinsics::isMemoryOrderValid(
696*03ce13f7SAndroid Build Coastguard Worker ID, getConstantMemoryOrder(Intrin->getArg(1)))) {
697*03ce13f7SAndroid Build Coastguard Worker LoadDest = Intrin->getDest();
698*03ce13f7SAndroid Build Coastguard Worker constexpr bool DoLegalize = false;
699*03ce13f7SAndroid Build Coastguard Worker LoadSrc = formMemoryOperand(Intrin->getArg(0), LoadDest->getType(),
700*03ce13f7SAndroid Build Coastguard Worker DoLegalize);
701*03ce13f7SAndroid Build Coastguard Worker }
702*03ce13f7SAndroid Build Coastguard Worker }
703*03ce13f7SAndroid Build Coastguard Worker // A Load instruction can be folded into the following instruction only
704*03ce13f7SAndroid Build Coastguard Worker // if the following instruction ends the Load's Dest variable's live
705*03ce13f7SAndroid Build Coastguard Worker // range.
706*03ce13f7SAndroid Build Coastguard Worker if (LoadDest && Next && Next->isLastUse(LoadDest)) {
707*03ce13f7SAndroid Build Coastguard Worker assert(LoadSrc);
708*03ce13f7SAndroid Build Coastguard Worker Inst *NewInst = nullptr;
709*03ce13f7SAndroid Build Coastguard Worker if (auto *Arith = llvm::dyn_cast<InstArithmetic>(Next)) {
710*03ce13f7SAndroid Build Coastguard Worker Operand *Src0 = Arith->getSrc(0);
711*03ce13f7SAndroid Build Coastguard Worker Operand *Src1 = Arith->getSrc(1);
712*03ce13f7SAndroid Build Coastguard Worker if (canFoldLoadIntoBinaryInst(LoadSrc, LoadDest, Src0, Src1)) {
713*03ce13f7SAndroid Build Coastguard Worker NewInst = InstArithmetic::create(Func, Arith->getOp(),
714*03ce13f7SAndroid Build Coastguard Worker Arith->getDest(), Src0, Src1);
715*03ce13f7SAndroid Build Coastguard Worker }
716*03ce13f7SAndroid Build Coastguard Worker } else if (auto *Icmp = llvm::dyn_cast<InstIcmp>(Next)) {
717*03ce13f7SAndroid Build Coastguard Worker Operand *Src0 = Icmp->getSrc(0);
718*03ce13f7SAndroid Build Coastguard Worker Operand *Src1 = Icmp->getSrc(1);
719*03ce13f7SAndroid Build Coastguard Worker if (canFoldLoadIntoBinaryInst(LoadSrc, LoadDest, Src0, Src1)) {
720*03ce13f7SAndroid Build Coastguard Worker NewInst = InstIcmp::create(Func, Icmp->getCondition(),
721*03ce13f7SAndroid Build Coastguard Worker Icmp->getDest(), Src0, Src1);
722*03ce13f7SAndroid Build Coastguard Worker }
723*03ce13f7SAndroid Build Coastguard Worker } else if (auto *Fcmp = llvm::dyn_cast<InstFcmp>(Next)) {
724*03ce13f7SAndroid Build Coastguard Worker Operand *Src0 = Fcmp->getSrc(0);
725*03ce13f7SAndroid Build Coastguard Worker Operand *Src1 = Fcmp->getSrc(1);
726*03ce13f7SAndroid Build Coastguard Worker if (canFoldLoadIntoBinaryInst(LoadSrc, LoadDest, Src0, Src1)) {
727*03ce13f7SAndroid Build Coastguard Worker NewInst = InstFcmp::create(Func, Fcmp->getCondition(),
728*03ce13f7SAndroid Build Coastguard Worker Fcmp->getDest(), Src0, Src1);
729*03ce13f7SAndroid Build Coastguard Worker }
730*03ce13f7SAndroid Build Coastguard Worker } else if (auto *Select = llvm::dyn_cast<InstSelect>(Next)) {
731*03ce13f7SAndroid Build Coastguard Worker Operand *Src0 = Select->getTrueOperand();
732*03ce13f7SAndroid Build Coastguard Worker Operand *Src1 = Select->getFalseOperand();
733*03ce13f7SAndroid Build Coastguard Worker if (canFoldLoadIntoBinaryInst(LoadSrc, LoadDest, Src0, Src1)) {
734*03ce13f7SAndroid Build Coastguard Worker NewInst = InstSelect::create(Func, Select->getDest(),
735*03ce13f7SAndroid Build Coastguard Worker Select->getCondition(), Src0, Src1);
736*03ce13f7SAndroid Build Coastguard Worker }
737*03ce13f7SAndroid Build Coastguard Worker } else if (auto *Cast = llvm::dyn_cast<InstCast>(Next)) {
738*03ce13f7SAndroid Build Coastguard Worker // The load dest can always be folded into a Cast instruction.
739*03ce13f7SAndroid Build Coastguard Worker auto *Src0 = llvm::dyn_cast<Variable>(Cast->getSrc(0));
740*03ce13f7SAndroid Build Coastguard Worker if (Src0 == LoadDest) {
741*03ce13f7SAndroid Build Coastguard Worker NewInst = InstCast::create(Func, Cast->getCastKind(),
742*03ce13f7SAndroid Build Coastguard Worker Cast->getDest(), LoadSrc);
743*03ce13f7SAndroid Build Coastguard Worker }
744*03ce13f7SAndroid Build Coastguard Worker }
745*03ce13f7SAndroid Build Coastguard Worker if (NewInst) {
746*03ce13f7SAndroid Build Coastguard Worker CurInst->setDeleted();
747*03ce13f7SAndroid Build Coastguard Worker Next->setDeleted();
748*03ce13f7SAndroid Build Coastguard Worker Context.insert(NewInst);
749*03ce13f7SAndroid Build Coastguard Worker // Update NewInst->LiveRangesEnded so that target lowering may
750*03ce13f7SAndroid Build Coastguard Worker // benefit. Also update NewInst->HasSideEffects.
751*03ce13f7SAndroid Build Coastguard Worker NewInst->spliceLivenessInfo(Next, CurInst);
752*03ce13f7SAndroid Build Coastguard Worker }
753*03ce13f7SAndroid Build Coastguard Worker }
754*03ce13f7SAndroid Build Coastguard Worker Context.advanceCur();
755*03ce13f7SAndroid Build Coastguard Worker Context.advanceNext();
756*03ce13f7SAndroid Build Coastguard Worker }
757*03ce13f7SAndroid Build Coastguard Worker }
758*03ce13f7SAndroid Build Coastguard Worker Func->dump("After load optimization");
759*03ce13f7SAndroid Build Coastguard Worker }
760*03ce13f7SAndroid Build Coastguard Worker
doBranchOpt(Inst * I,const CfgNode * NextNode)761*03ce13f7SAndroid Build Coastguard Worker bool TargetX8632::doBranchOpt(Inst *I, const CfgNode *NextNode) {
762*03ce13f7SAndroid Build Coastguard Worker if (auto *Br = llvm::dyn_cast<InstX86Br>(I)) {
763*03ce13f7SAndroid Build Coastguard Worker return Br->optimizeBranch(NextNode);
764*03ce13f7SAndroid Build Coastguard Worker }
765*03ce13f7SAndroid Build Coastguard Worker return false;
766*03ce13f7SAndroid Build Coastguard Worker }
767*03ce13f7SAndroid Build Coastguard Worker
getPhysicalRegister(RegNumT RegNum,Type Ty)768*03ce13f7SAndroid Build Coastguard Worker Variable *TargetX8632::getPhysicalRegister(RegNumT RegNum, Type Ty) {
769*03ce13f7SAndroid Build Coastguard Worker if (Ty == IceType_void)
770*03ce13f7SAndroid Build Coastguard Worker Ty = IceType_i32;
771*03ce13f7SAndroid Build Coastguard Worker if (PhysicalRegisters[Ty].empty())
772*03ce13f7SAndroid Build Coastguard Worker PhysicalRegisters[Ty].resize(RegX8632::Reg_NUM);
773*03ce13f7SAndroid Build Coastguard Worker assert(unsigned(RegNum) < PhysicalRegisters[Ty].size());
774*03ce13f7SAndroid Build Coastguard Worker Variable *Reg = PhysicalRegisters[Ty][RegNum];
775*03ce13f7SAndroid Build Coastguard Worker if (Reg == nullptr) {
776*03ce13f7SAndroid Build Coastguard Worker Reg = Func->makeVariable(Ty);
777*03ce13f7SAndroid Build Coastguard Worker Reg->setRegNum(RegNum);
778*03ce13f7SAndroid Build Coastguard Worker PhysicalRegisters[Ty][RegNum] = Reg;
779*03ce13f7SAndroid Build Coastguard Worker // Specially mark a named physical register as an "argument" so that it is
780*03ce13f7SAndroid Build Coastguard Worker // considered live upon function entry. Otherwise it's possible to get
781*03ce13f7SAndroid Build Coastguard Worker // liveness validation errors for saving callee-save registers.
782*03ce13f7SAndroid Build Coastguard Worker Func->addImplicitArg(Reg);
783*03ce13f7SAndroid Build Coastguard Worker // Don't bother tracking the live range of a named physical register.
784*03ce13f7SAndroid Build Coastguard Worker Reg->setIgnoreLiveness();
785*03ce13f7SAndroid Build Coastguard Worker }
786*03ce13f7SAndroid Build Coastguard Worker assert(RegX8632::getGprForType(Ty, RegNum) == RegNum);
787*03ce13f7SAndroid Build Coastguard Worker return Reg;
788*03ce13f7SAndroid Build Coastguard Worker }
789*03ce13f7SAndroid Build Coastguard Worker
getRegName(RegNumT RegNum,Type Ty) const790*03ce13f7SAndroid Build Coastguard Worker const char *TargetX8632::getRegName(RegNumT RegNum, Type Ty) const {
791*03ce13f7SAndroid Build Coastguard Worker return RegX8632::getRegName(RegX8632::getGprForType(Ty, RegNum));
792*03ce13f7SAndroid Build Coastguard Worker }
793*03ce13f7SAndroid Build Coastguard Worker
emitVariable(const Variable * Var) const794*03ce13f7SAndroid Build Coastguard Worker void TargetX8632::emitVariable(const Variable *Var) const {
795*03ce13f7SAndroid Build Coastguard Worker if (!BuildDefs::dump())
796*03ce13f7SAndroid Build Coastguard Worker return;
797*03ce13f7SAndroid Build Coastguard Worker Ostream &Str = Ctx->getStrEmit();
798*03ce13f7SAndroid Build Coastguard Worker if (Var->hasReg()) {
799*03ce13f7SAndroid Build Coastguard Worker Str << "%" << getRegName(Var->getRegNum(), Var->getType());
800*03ce13f7SAndroid Build Coastguard Worker return;
801*03ce13f7SAndroid Build Coastguard Worker }
802*03ce13f7SAndroid Build Coastguard Worker if (Var->mustHaveReg()) {
803*03ce13f7SAndroid Build Coastguard Worker llvm::report_fatal_error("Infinite-weight Variable (" + Var->getName() +
804*03ce13f7SAndroid Build Coastguard Worker ") has no register assigned - function " +
805*03ce13f7SAndroid Build Coastguard Worker Func->getFunctionName());
806*03ce13f7SAndroid Build Coastguard Worker }
807*03ce13f7SAndroid Build Coastguard Worker const int32_t Offset = Var->getStackOffset();
808*03ce13f7SAndroid Build Coastguard Worker auto BaseRegNum = Var->getBaseRegNum();
809*03ce13f7SAndroid Build Coastguard Worker if (BaseRegNum.hasNoValue())
810*03ce13f7SAndroid Build Coastguard Worker BaseRegNum = getFrameOrStackReg();
811*03ce13f7SAndroid Build Coastguard Worker
812*03ce13f7SAndroid Build Coastguard Worker // Print in the form "Offset(%reg)", omitting Offset when it is 0.
813*03ce13f7SAndroid Build Coastguard Worker if (getFlags().getDecorateAsm()) {
814*03ce13f7SAndroid Build Coastguard Worker Str << Var->getSymbolicStackOffset();
815*03ce13f7SAndroid Build Coastguard Worker } else if (Offset != 0) {
816*03ce13f7SAndroid Build Coastguard Worker Str << Offset;
817*03ce13f7SAndroid Build Coastguard Worker }
818*03ce13f7SAndroid Build Coastguard Worker const Type FrameSPTy = WordType;
819*03ce13f7SAndroid Build Coastguard Worker Str << "(%" << getRegName(BaseRegNum, FrameSPTy) << ")";
820*03ce13f7SAndroid Build Coastguard Worker }
821*03ce13f7SAndroid Build Coastguard Worker
addProlog(CfgNode * Node)822*03ce13f7SAndroid Build Coastguard Worker void TargetX8632::addProlog(CfgNode *Node) {
823*03ce13f7SAndroid Build Coastguard Worker // Stack frame layout:
824*03ce13f7SAndroid Build Coastguard Worker //
825*03ce13f7SAndroid Build Coastguard Worker // +------------------------+ ^ +
826*03ce13f7SAndroid Build Coastguard Worker // | 1. return address | |
827*03ce13f7SAndroid Build Coastguard Worker // +------------------------+ v -
828*03ce13f7SAndroid Build Coastguard Worker // | 2. preserved registers |
829*03ce13f7SAndroid Build Coastguard Worker // +------------------------+ <--- BasePointer (if used)
830*03ce13f7SAndroid Build Coastguard Worker // | 3. padding |
831*03ce13f7SAndroid Build Coastguard Worker // +------------------------+
832*03ce13f7SAndroid Build Coastguard Worker // | 4. global spill area |
833*03ce13f7SAndroid Build Coastguard Worker // +------------------------+
834*03ce13f7SAndroid Build Coastguard Worker // | 5. padding |
835*03ce13f7SAndroid Build Coastguard Worker // +------------------------+
836*03ce13f7SAndroid Build Coastguard Worker // | 6. local spill area |
837*03ce13f7SAndroid Build Coastguard Worker // +------------------------+
838*03ce13f7SAndroid Build Coastguard Worker // | 7. padding |
839*03ce13f7SAndroid Build Coastguard Worker // +------------------------+
840*03ce13f7SAndroid Build Coastguard Worker // | 7.5 shadow (WinX64) |
841*03ce13f7SAndroid Build Coastguard Worker // +------------------------+
842*03ce13f7SAndroid Build Coastguard Worker // | 8. allocas |
843*03ce13f7SAndroid Build Coastguard Worker // +------------------------+
844*03ce13f7SAndroid Build Coastguard Worker // | 9. padding |
845*03ce13f7SAndroid Build Coastguard Worker // +------------------------+
846*03ce13f7SAndroid Build Coastguard Worker // | 10. out args |
847*03ce13f7SAndroid Build Coastguard Worker // +------------------------+ <--- StackPointer
848*03ce13f7SAndroid Build Coastguard Worker //
849*03ce13f7SAndroid Build Coastguard Worker // The following variables record the size in bytes of the given areas:
850*03ce13f7SAndroid Build Coastguard Worker // * X86_RET_IP_SIZE_BYTES: area 1
851*03ce13f7SAndroid Build Coastguard Worker // * PreservedRegsSizeBytes: area 2
852*03ce13f7SAndroid Build Coastguard Worker // * SpillAreaPaddingBytes: area 3
853*03ce13f7SAndroid Build Coastguard Worker // * GlobalsSize: area 4
854*03ce13f7SAndroid Build Coastguard Worker // * LocalsSlotsPaddingBytes: area 5
855*03ce13f7SAndroid Build Coastguard Worker // * GlobalsAndSubsequentPaddingSize: areas 4 - 5
856*03ce13f7SAndroid Build Coastguard Worker // * LocalsSpillAreaSize: area 6
857*03ce13f7SAndroid Build Coastguard Worker // * FixedAllocaSizeBytes: areas 7 - 8
858*03ce13f7SAndroid Build Coastguard Worker // * SpillAreaSizeBytes: areas 3 - 10
859*03ce13f7SAndroid Build Coastguard Worker // * maxOutArgsSizeBytes(): areas 9 - 10
860*03ce13f7SAndroid Build Coastguard Worker
861*03ce13f7SAndroid Build Coastguard Worker // Determine stack frame offsets for each Variable without a register
862*03ce13f7SAndroid Build Coastguard Worker // assignment. This can be done as one variable per stack slot. Or, do
863*03ce13f7SAndroid Build Coastguard Worker // coalescing by running the register allocator again with an infinite set of
864*03ce13f7SAndroid Build Coastguard Worker // registers (as a side effect, this gives variables a second chance at
865*03ce13f7SAndroid Build Coastguard Worker // physical register assignment).
866*03ce13f7SAndroid Build Coastguard Worker //
867*03ce13f7SAndroid Build Coastguard Worker // A middle ground approach is to leverage sparsity and allocate one block of
868*03ce13f7SAndroid Build Coastguard Worker // space on the frame for globals (variables with multi-block lifetime), and
869*03ce13f7SAndroid Build Coastguard Worker // one block to share for locals (single-block lifetime).
870*03ce13f7SAndroid Build Coastguard Worker
871*03ce13f7SAndroid Build Coastguard Worker // StackPointer: points just past return address of calling function
872*03ce13f7SAndroid Build Coastguard Worker
873*03ce13f7SAndroid Build Coastguard Worker Context.init(Node);
874*03ce13f7SAndroid Build Coastguard Worker Context.setInsertPoint(Context.getCur());
875*03ce13f7SAndroid Build Coastguard Worker
876*03ce13f7SAndroid Build Coastguard Worker SmallBitVector CalleeSaves = getRegisterSet(RegSet_CalleeSave, RegSet_None);
877*03ce13f7SAndroid Build Coastguard Worker RegsUsed = SmallBitVector(CalleeSaves.size());
878*03ce13f7SAndroid Build Coastguard Worker VarList SortedSpilledVariables, VariablesLinkedToSpillSlots;
879*03ce13f7SAndroid Build Coastguard Worker size_t GlobalsSize = 0;
880*03ce13f7SAndroid Build Coastguard Worker // If there is a separate locals area, this represents that area. Otherwise
881*03ce13f7SAndroid Build Coastguard Worker // it counts any variable not counted by GlobalsSize.
882*03ce13f7SAndroid Build Coastguard Worker SpillAreaSizeBytes = 0;
883*03ce13f7SAndroid Build Coastguard Worker // If there is a separate locals area, this specifies the alignment for it.
884*03ce13f7SAndroid Build Coastguard Worker uint32_t LocalsSlotsAlignmentBytes = 0;
885*03ce13f7SAndroid Build Coastguard Worker // The entire spill locations area gets aligned to largest natural alignment
886*03ce13f7SAndroid Build Coastguard Worker // of the variables that have a spill slot.
887*03ce13f7SAndroid Build Coastguard Worker uint32_t SpillAreaAlignmentBytes = 0;
888*03ce13f7SAndroid Build Coastguard Worker // A spill slot linked to a variable with a stack slot should reuse that
889*03ce13f7SAndroid Build Coastguard Worker // stack slot.
890*03ce13f7SAndroid Build Coastguard Worker std::function<bool(Variable *)> TargetVarHook =
891*03ce13f7SAndroid Build Coastguard Worker [&VariablesLinkedToSpillSlots](Variable *Var) {
892*03ce13f7SAndroid Build Coastguard Worker // TODO(stichnot): Refactor this into the base class.
893*03ce13f7SAndroid Build Coastguard Worker Variable *Root = Var->getLinkedToStackRoot();
894*03ce13f7SAndroid Build Coastguard Worker if (Root != nullptr) {
895*03ce13f7SAndroid Build Coastguard Worker assert(!Root->hasReg());
896*03ce13f7SAndroid Build Coastguard Worker if (!Root->hasReg()) {
897*03ce13f7SAndroid Build Coastguard Worker VariablesLinkedToSpillSlots.push_back(Var);
898*03ce13f7SAndroid Build Coastguard Worker return true;
899*03ce13f7SAndroid Build Coastguard Worker }
900*03ce13f7SAndroid Build Coastguard Worker }
901*03ce13f7SAndroid Build Coastguard Worker return false;
902*03ce13f7SAndroid Build Coastguard Worker };
903*03ce13f7SAndroid Build Coastguard Worker
904*03ce13f7SAndroid Build Coastguard Worker // Compute the list of spilled variables and bounds for GlobalsSize, etc.
905*03ce13f7SAndroid Build Coastguard Worker getVarStackSlotParams(SortedSpilledVariables, RegsUsed, &GlobalsSize,
906*03ce13f7SAndroid Build Coastguard Worker &SpillAreaSizeBytes, &SpillAreaAlignmentBytes,
907*03ce13f7SAndroid Build Coastguard Worker &LocalsSlotsAlignmentBytes, TargetVarHook);
908*03ce13f7SAndroid Build Coastguard Worker uint32_t LocalsSpillAreaSize = SpillAreaSizeBytes;
909*03ce13f7SAndroid Build Coastguard Worker SpillAreaSizeBytes += GlobalsSize;
910*03ce13f7SAndroid Build Coastguard Worker
911*03ce13f7SAndroid Build Coastguard Worker // Add push instructions for preserved registers.
912*03ce13f7SAndroid Build Coastguard Worker uint32_t NumCallee = 0;
913*03ce13f7SAndroid Build Coastguard Worker size_t PreservedRegsSizeBytes = 0;
914*03ce13f7SAndroid Build Coastguard Worker SmallBitVector Pushed(CalleeSaves.size());
915*03ce13f7SAndroid Build Coastguard Worker for (RegNumT i : RegNumBVIter(CalleeSaves)) {
916*03ce13f7SAndroid Build Coastguard Worker const auto Canonical = RegX8632::getBaseReg(i);
917*03ce13f7SAndroid Build Coastguard Worker assert(Canonical == RegX8632::getBaseReg(Canonical));
918*03ce13f7SAndroid Build Coastguard Worker if (RegsUsed[i]) {
919*03ce13f7SAndroid Build Coastguard Worker Pushed[Canonical] = true;
920*03ce13f7SAndroid Build Coastguard Worker }
921*03ce13f7SAndroid Build Coastguard Worker }
922*03ce13f7SAndroid Build Coastguard Worker for (RegNumT RegNum : RegNumBVIter(Pushed)) {
923*03ce13f7SAndroid Build Coastguard Worker assert(RegNum == RegX8632::getBaseReg(RegNum));
924*03ce13f7SAndroid Build Coastguard Worker ++NumCallee;
925*03ce13f7SAndroid Build Coastguard Worker if (RegX8632::isXmm(RegNum)) {
926*03ce13f7SAndroid Build Coastguard Worker PreservedRegsSizeBytes += 16;
927*03ce13f7SAndroid Build Coastguard Worker } else {
928*03ce13f7SAndroid Build Coastguard Worker PreservedRegsSizeBytes += typeWidthInBytes(WordType);
929*03ce13f7SAndroid Build Coastguard Worker }
930*03ce13f7SAndroid Build Coastguard Worker _push_reg(RegNum);
931*03ce13f7SAndroid Build Coastguard Worker }
932*03ce13f7SAndroid Build Coastguard Worker Ctx->statsUpdateRegistersSaved(NumCallee);
933*03ce13f7SAndroid Build Coastguard Worker
934*03ce13f7SAndroid Build Coastguard Worker // StackPointer: points past preserved registers at start of spill area
935*03ce13f7SAndroid Build Coastguard Worker
936*03ce13f7SAndroid Build Coastguard Worker // Generate "push frameptr; mov frameptr, stackptr"
937*03ce13f7SAndroid Build Coastguard Worker if (IsEbpBasedFrame) {
938*03ce13f7SAndroid Build Coastguard Worker assert(
939*03ce13f7SAndroid Build Coastguard Worker (RegsUsed & getRegisterSet(RegSet_FramePointer, RegSet_None)).count() ==
940*03ce13f7SAndroid Build Coastguard Worker 0);
941*03ce13f7SAndroid Build Coastguard Worker PreservedRegsSizeBytes += typeWidthInBytes(WordType);
942*03ce13f7SAndroid Build Coastguard Worker _link_bp();
943*03ce13f7SAndroid Build Coastguard Worker }
944*03ce13f7SAndroid Build Coastguard Worker
945*03ce13f7SAndroid Build Coastguard Worker // Align the variables area. SpillAreaPaddingBytes is the size of the region
946*03ce13f7SAndroid Build Coastguard Worker // after the preserved registers and before the spill areas.
947*03ce13f7SAndroid Build Coastguard Worker // LocalsSlotsPaddingBytes is the amount of padding between the globals and
948*03ce13f7SAndroid Build Coastguard Worker // locals area if they are separate.
949*03ce13f7SAndroid Build Coastguard Worker assert(LocalsSlotsAlignmentBytes <= SpillAreaAlignmentBytes);
950*03ce13f7SAndroid Build Coastguard Worker uint32_t SpillAreaPaddingBytes = 0;
951*03ce13f7SAndroid Build Coastguard Worker uint32_t LocalsSlotsPaddingBytes = 0;
952*03ce13f7SAndroid Build Coastguard Worker alignStackSpillAreas(X86_RET_IP_SIZE_BYTES + PreservedRegsSizeBytes,
953*03ce13f7SAndroid Build Coastguard Worker SpillAreaAlignmentBytes, GlobalsSize,
954*03ce13f7SAndroid Build Coastguard Worker LocalsSlotsAlignmentBytes, &SpillAreaPaddingBytes,
955*03ce13f7SAndroid Build Coastguard Worker &LocalsSlotsPaddingBytes);
956*03ce13f7SAndroid Build Coastguard Worker SpillAreaSizeBytes += SpillAreaPaddingBytes + LocalsSlotsPaddingBytes;
957*03ce13f7SAndroid Build Coastguard Worker uint32_t GlobalsAndSubsequentPaddingSize =
958*03ce13f7SAndroid Build Coastguard Worker GlobalsSize + LocalsSlotsPaddingBytes;
959*03ce13f7SAndroid Build Coastguard Worker
960*03ce13f7SAndroid Build Coastguard Worker // Functions returning scalar floating point types may need to convert values
961*03ce13f7SAndroid Build Coastguard Worker // from an in-register xmm value to the top of the x87 floating point stack.
962*03ce13f7SAndroid Build Coastguard Worker // This is done by a movp[sd] and an fld[sd]. Ensure there is enough scratch
963*03ce13f7SAndroid Build Coastguard Worker // space on the stack for this.
964*03ce13f7SAndroid Build Coastguard Worker const Type ReturnType = Func->getReturnType();
965*03ce13f7SAndroid Build Coastguard Worker if (isScalarFloatingType(ReturnType)) {
966*03ce13f7SAndroid Build Coastguard Worker // Avoid misaligned double-precision load/store.
967*03ce13f7SAndroid Build Coastguard Worker RequiredStackAlignment =
968*03ce13f7SAndroid Build Coastguard Worker std::max<size_t>(RequiredStackAlignment, X86_STACK_ALIGNMENT_BYTES);
969*03ce13f7SAndroid Build Coastguard Worker SpillAreaSizeBytes =
970*03ce13f7SAndroid Build Coastguard Worker std::max(typeWidthInBytesOnStack(ReturnType), SpillAreaSizeBytes);
971*03ce13f7SAndroid Build Coastguard Worker }
972*03ce13f7SAndroid Build Coastguard Worker
973*03ce13f7SAndroid Build Coastguard Worker RequiredStackAlignment =
974*03ce13f7SAndroid Build Coastguard Worker std::max<size_t>(RequiredStackAlignment, SpillAreaAlignmentBytes);
975*03ce13f7SAndroid Build Coastguard Worker
976*03ce13f7SAndroid Build Coastguard Worker if (PrologEmitsFixedAllocas) {
977*03ce13f7SAndroid Build Coastguard Worker RequiredStackAlignment =
978*03ce13f7SAndroid Build Coastguard Worker std::max(RequiredStackAlignment, FixedAllocaAlignBytes);
979*03ce13f7SAndroid Build Coastguard Worker }
980*03ce13f7SAndroid Build Coastguard Worker
981*03ce13f7SAndroid Build Coastguard Worker // Combine fixed allocations into SpillAreaSizeBytes if we are emitting the
982*03ce13f7SAndroid Build Coastguard Worker // fixed allocations in the prolog.
983*03ce13f7SAndroid Build Coastguard Worker if (PrologEmitsFixedAllocas)
984*03ce13f7SAndroid Build Coastguard Worker SpillAreaSizeBytes += FixedAllocaSizeBytes;
985*03ce13f7SAndroid Build Coastguard Worker
986*03ce13f7SAndroid Build Coastguard Worker // Entering the function has made the stack pointer unaligned. Re-align it by
987*03ce13f7SAndroid Build Coastguard Worker // adjusting the stack size.
988*03ce13f7SAndroid Build Coastguard Worker // Note that StackOffset does not include spill area. It's the offset from the
989*03ce13f7SAndroid Build Coastguard Worker // base stack pointer (epb), whether we set it or not, to the the first stack
990*03ce13f7SAndroid Build Coastguard Worker // arg (if any). StackSize, on the other hand, does include the spill area.
991*03ce13f7SAndroid Build Coastguard Worker const uint32_t StackOffset = X86_RET_IP_SIZE_BYTES + PreservedRegsSizeBytes;
992*03ce13f7SAndroid Build Coastguard Worker uint32_t StackSize = Utils::applyAlignment(StackOffset + SpillAreaSizeBytes,
993*03ce13f7SAndroid Build Coastguard Worker RequiredStackAlignment);
994*03ce13f7SAndroid Build Coastguard Worker StackSize = Utils::applyAlignment(StackSize + maxOutArgsSizeBytes(),
995*03ce13f7SAndroid Build Coastguard Worker RequiredStackAlignment);
996*03ce13f7SAndroid Build Coastguard Worker SpillAreaSizeBytes = StackSize - StackOffset; // Adjust for alignment, if any
997*03ce13f7SAndroid Build Coastguard Worker
998*03ce13f7SAndroid Build Coastguard Worker if (SpillAreaSizeBytes) {
999*03ce13f7SAndroid Build Coastguard Worker auto *Func = Node->getCfg();
1000*03ce13f7SAndroid Build Coastguard Worker if (SpillAreaSizeBytes > Func->getStackSizeLimit()) {
1001*03ce13f7SAndroid Build Coastguard Worker Func->setError("Stack size limit exceeded");
1002*03ce13f7SAndroid Build Coastguard Worker }
1003*03ce13f7SAndroid Build Coastguard Worker
1004*03ce13f7SAndroid Build Coastguard Worker emitStackProbe(SpillAreaSizeBytes);
1005*03ce13f7SAndroid Build Coastguard Worker
1006*03ce13f7SAndroid Build Coastguard Worker // Generate "sub stackptr, SpillAreaSizeBytes"
1007*03ce13f7SAndroid Build Coastguard Worker _sub_sp(Ctx->getConstantInt32(SpillAreaSizeBytes));
1008*03ce13f7SAndroid Build Coastguard Worker }
1009*03ce13f7SAndroid Build Coastguard Worker
1010*03ce13f7SAndroid Build Coastguard Worker // StackPointer: points just past the spill area (end of stack frame)
1011*03ce13f7SAndroid Build Coastguard Worker
1012*03ce13f7SAndroid Build Coastguard Worker // If the required alignment is greater than the stack pointer's guaranteed
1013*03ce13f7SAndroid Build Coastguard Worker // alignment, align the stack pointer accordingly.
1014*03ce13f7SAndroid Build Coastguard Worker if (RequiredStackAlignment > X86_STACK_ALIGNMENT_BYTES) {
1015*03ce13f7SAndroid Build Coastguard Worker assert(IsEbpBasedFrame);
1016*03ce13f7SAndroid Build Coastguard Worker _and(getPhysicalRegister(getStackReg(), WordType),
1017*03ce13f7SAndroid Build Coastguard Worker Ctx->getConstantInt32(-RequiredStackAlignment));
1018*03ce13f7SAndroid Build Coastguard Worker }
1019*03ce13f7SAndroid Build Coastguard Worker
1020*03ce13f7SAndroid Build Coastguard Worker // StackPointer: may have just been offset for alignment
1021*03ce13f7SAndroid Build Coastguard Worker
1022*03ce13f7SAndroid Build Coastguard Worker // Account for known-frame-offset alloca instructions that were not already
1023*03ce13f7SAndroid Build Coastguard Worker // combined into the prolog.
1024*03ce13f7SAndroid Build Coastguard Worker if (!PrologEmitsFixedAllocas)
1025*03ce13f7SAndroid Build Coastguard Worker SpillAreaSizeBytes += FixedAllocaSizeBytes;
1026*03ce13f7SAndroid Build Coastguard Worker
1027*03ce13f7SAndroid Build Coastguard Worker Ctx->statsUpdateFrameBytes(SpillAreaSizeBytes);
1028*03ce13f7SAndroid Build Coastguard Worker
1029*03ce13f7SAndroid Build Coastguard Worker // Fill in stack offsets for stack args, and copy args into registers for
1030*03ce13f7SAndroid Build Coastguard Worker // those that were register-allocated. Args are pushed right to left, so
1031*03ce13f7SAndroid Build Coastguard Worker // Arg[0] is closest to the stack/frame pointer.
1032*03ce13f7SAndroid Build Coastguard Worker RegNumT FrameOrStackReg = IsEbpBasedFrame ? getFrameReg() : getStackReg();
1033*03ce13f7SAndroid Build Coastguard Worker Variable *FramePtr = getPhysicalRegister(FrameOrStackReg, WordType);
1034*03ce13f7SAndroid Build Coastguard Worker size_t BasicFrameOffset = StackOffset;
1035*03ce13f7SAndroid Build Coastguard Worker if (!IsEbpBasedFrame)
1036*03ce13f7SAndroid Build Coastguard Worker BasicFrameOffset += SpillAreaSizeBytes;
1037*03ce13f7SAndroid Build Coastguard Worker
1038*03ce13f7SAndroid Build Coastguard Worker const VarList &Args = Func->getArgs();
1039*03ce13f7SAndroid Build Coastguard Worker size_t InArgsSizeBytes = 0;
1040*03ce13f7SAndroid Build Coastguard Worker unsigned NumXmmArgs = 0;
1041*03ce13f7SAndroid Build Coastguard Worker unsigned NumGPRArgs = 0;
1042*03ce13f7SAndroid Build Coastguard Worker for (SizeT i = 0, NumArgs = Args.size(); i < NumArgs; ++i) {
1043*03ce13f7SAndroid Build Coastguard Worker Variable *Arg = Args[i];
1044*03ce13f7SAndroid Build Coastguard Worker // Skip arguments passed in registers.
1045*03ce13f7SAndroid Build Coastguard Worker if (isVectorType(Arg->getType())) {
1046*03ce13f7SAndroid Build Coastguard Worker if (RegX8632::getRegisterForXmmArgNum(
1047*03ce13f7SAndroid Build Coastguard Worker RegX8632::getArgIndex(i, NumXmmArgs))
1048*03ce13f7SAndroid Build Coastguard Worker .hasValue()) {
1049*03ce13f7SAndroid Build Coastguard Worker ++NumXmmArgs;
1050*03ce13f7SAndroid Build Coastguard Worker continue;
1051*03ce13f7SAndroid Build Coastguard Worker }
1052*03ce13f7SAndroid Build Coastguard Worker } else if (!isScalarFloatingType(Arg->getType())) {
1053*03ce13f7SAndroid Build Coastguard Worker assert(isScalarIntegerType(Arg->getType()));
1054*03ce13f7SAndroid Build Coastguard Worker if (RegX8632::getRegisterForGprArgNum(
1055*03ce13f7SAndroid Build Coastguard Worker WordType, RegX8632::getArgIndex(i, NumGPRArgs))
1056*03ce13f7SAndroid Build Coastguard Worker .hasValue()) {
1057*03ce13f7SAndroid Build Coastguard Worker ++NumGPRArgs;
1058*03ce13f7SAndroid Build Coastguard Worker continue;
1059*03ce13f7SAndroid Build Coastguard Worker }
1060*03ce13f7SAndroid Build Coastguard Worker }
1061*03ce13f7SAndroid Build Coastguard Worker // For esp-based frames where the allocas are done outside the prolog, the
1062*03ce13f7SAndroid Build Coastguard Worker // esp value may not stabilize to its home value until after all the
1063*03ce13f7SAndroid Build Coastguard Worker // fixed-size alloca instructions have executed. In this case, a stack
1064*03ce13f7SAndroid Build Coastguard Worker // adjustment is needed when accessing in-args in order to copy them into
1065*03ce13f7SAndroid Build Coastguard Worker // registers.
1066*03ce13f7SAndroid Build Coastguard Worker size_t StackAdjBytes = 0;
1067*03ce13f7SAndroid Build Coastguard Worker if (!IsEbpBasedFrame && !PrologEmitsFixedAllocas)
1068*03ce13f7SAndroid Build Coastguard Worker StackAdjBytes -= FixedAllocaSizeBytes;
1069*03ce13f7SAndroid Build Coastguard Worker finishArgumentLowering(Arg, FramePtr, BasicFrameOffset, StackAdjBytes,
1070*03ce13f7SAndroid Build Coastguard Worker InArgsSizeBytes);
1071*03ce13f7SAndroid Build Coastguard Worker }
1072*03ce13f7SAndroid Build Coastguard Worker
1073*03ce13f7SAndroid Build Coastguard Worker // Fill in stack offsets for locals.
1074*03ce13f7SAndroid Build Coastguard Worker assignVarStackSlots(SortedSpilledVariables, SpillAreaPaddingBytes,
1075*03ce13f7SAndroid Build Coastguard Worker SpillAreaSizeBytes, GlobalsAndSubsequentPaddingSize,
1076*03ce13f7SAndroid Build Coastguard Worker IsEbpBasedFrame && !needsStackPointerAlignment());
1077*03ce13f7SAndroid Build Coastguard Worker // Assign stack offsets to variables that have been linked to spilled
1078*03ce13f7SAndroid Build Coastguard Worker // variables.
1079*03ce13f7SAndroid Build Coastguard Worker for (Variable *Var : VariablesLinkedToSpillSlots) {
1080*03ce13f7SAndroid Build Coastguard Worker const Variable *Root = Var->getLinkedToStackRoot();
1081*03ce13f7SAndroid Build Coastguard Worker assert(Root != nullptr);
1082*03ce13f7SAndroid Build Coastguard Worker Var->setStackOffset(Root->getStackOffset());
1083*03ce13f7SAndroid Build Coastguard Worker
1084*03ce13f7SAndroid Build Coastguard Worker // If the stack root variable is an arg, make this variable an arg too so
1085*03ce13f7SAndroid Build Coastguard Worker // that stackVarToAsmAddress uses the correct base pointer (e.g. ebp on
1086*03ce13f7SAndroid Build Coastguard Worker // x86).
1087*03ce13f7SAndroid Build Coastguard Worker Var->setIsArg(Root->getIsArg());
1088*03ce13f7SAndroid Build Coastguard Worker }
1089*03ce13f7SAndroid Build Coastguard Worker this->HasComputedFrame = true;
1090*03ce13f7SAndroid Build Coastguard Worker
1091*03ce13f7SAndroid Build Coastguard Worker if (BuildDefs::dump() && Func->isVerbose(IceV_Frame)) {
1092*03ce13f7SAndroid Build Coastguard Worker OstreamLocker L(Func->getContext());
1093*03ce13f7SAndroid Build Coastguard Worker Ostream &Str = Func->getContext()->getStrDump();
1094*03ce13f7SAndroid Build Coastguard Worker
1095*03ce13f7SAndroid Build Coastguard Worker Str << "Stack layout:\n";
1096*03ce13f7SAndroid Build Coastguard Worker uint32_t EspAdjustmentPaddingSize =
1097*03ce13f7SAndroid Build Coastguard Worker SpillAreaSizeBytes - LocalsSpillAreaSize -
1098*03ce13f7SAndroid Build Coastguard Worker GlobalsAndSubsequentPaddingSize - SpillAreaPaddingBytes -
1099*03ce13f7SAndroid Build Coastguard Worker maxOutArgsSizeBytes();
1100*03ce13f7SAndroid Build Coastguard Worker Str << " in-args = " << InArgsSizeBytes << " bytes\n"
1101*03ce13f7SAndroid Build Coastguard Worker << " return address = " << X86_RET_IP_SIZE_BYTES << " bytes\n"
1102*03ce13f7SAndroid Build Coastguard Worker << " preserved registers = " << PreservedRegsSizeBytes << " bytes\n"
1103*03ce13f7SAndroid Build Coastguard Worker << " spill area padding = " << SpillAreaPaddingBytes << " bytes\n"
1104*03ce13f7SAndroid Build Coastguard Worker << " globals spill area = " << GlobalsSize << " bytes\n"
1105*03ce13f7SAndroid Build Coastguard Worker << " globals-locals spill areas intermediate padding = "
1106*03ce13f7SAndroid Build Coastguard Worker << GlobalsAndSubsequentPaddingSize - GlobalsSize << " bytes\n"
1107*03ce13f7SAndroid Build Coastguard Worker << " locals spill area = " << LocalsSpillAreaSize << " bytes\n"
1108*03ce13f7SAndroid Build Coastguard Worker << " esp alignment padding = " << EspAdjustmentPaddingSize
1109*03ce13f7SAndroid Build Coastguard Worker << " bytes\n";
1110*03ce13f7SAndroid Build Coastguard Worker
1111*03ce13f7SAndroid Build Coastguard Worker Str << "Stack details:\n"
1112*03ce13f7SAndroid Build Coastguard Worker << " esp adjustment = " << SpillAreaSizeBytes << " bytes\n"
1113*03ce13f7SAndroid Build Coastguard Worker << " spill area alignment = " << SpillAreaAlignmentBytes << " bytes\n"
1114*03ce13f7SAndroid Build Coastguard Worker << " outgoing args size = " << maxOutArgsSizeBytes() << " bytes\n"
1115*03ce13f7SAndroid Build Coastguard Worker << " locals spill area alignment = " << LocalsSlotsAlignmentBytes
1116*03ce13f7SAndroid Build Coastguard Worker << " bytes\n"
1117*03ce13f7SAndroid Build Coastguard Worker << " is ebp based = " << IsEbpBasedFrame << "\n";
1118*03ce13f7SAndroid Build Coastguard Worker }
1119*03ce13f7SAndroid Build Coastguard Worker }
1120*03ce13f7SAndroid Build Coastguard Worker
1121*03ce13f7SAndroid Build Coastguard Worker /// Helper function for addProlog().
1122*03ce13f7SAndroid Build Coastguard Worker ///
1123*03ce13f7SAndroid Build Coastguard Worker /// This assumes Arg is an argument passed on the stack. This sets the frame
1124*03ce13f7SAndroid Build Coastguard Worker /// offset for Arg and updates InArgsSizeBytes according to Arg's width. For an
1125*03ce13f7SAndroid Build Coastguard Worker /// I64 arg that has been split into Lo and Hi components, it calls itself
1126*03ce13f7SAndroid Build Coastguard Worker /// recursively on the components, taking care to handle Lo first because of the
1127*03ce13f7SAndroid Build Coastguard Worker /// little-endian architecture. Lastly, this function generates an instruction
1128*03ce13f7SAndroid Build Coastguard Worker /// to copy Arg into its assigned register if applicable.
1129*03ce13f7SAndroid Build Coastguard Worker
finishArgumentLowering(Variable * Arg,Variable * FramePtr,size_t BasicFrameOffset,size_t StackAdjBytes,size_t & InArgsSizeBytes)1130*03ce13f7SAndroid Build Coastguard Worker void TargetX8632::finishArgumentLowering(Variable *Arg, Variable *FramePtr,
1131*03ce13f7SAndroid Build Coastguard Worker size_t BasicFrameOffset,
1132*03ce13f7SAndroid Build Coastguard Worker size_t StackAdjBytes,
1133*03ce13f7SAndroid Build Coastguard Worker size_t &InArgsSizeBytes) {
1134*03ce13f7SAndroid Build Coastguard Worker if (auto *Arg64On32 = llvm::dyn_cast<Variable64On32>(Arg)) {
1135*03ce13f7SAndroid Build Coastguard Worker Variable *Lo = Arg64On32->getLo();
1136*03ce13f7SAndroid Build Coastguard Worker Variable *Hi = Arg64On32->getHi();
1137*03ce13f7SAndroid Build Coastguard Worker finishArgumentLowering(Lo, FramePtr, BasicFrameOffset, StackAdjBytes,
1138*03ce13f7SAndroid Build Coastguard Worker InArgsSizeBytes);
1139*03ce13f7SAndroid Build Coastguard Worker finishArgumentLowering(Hi, FramePtr, BasicFrameOffset, StackAdjBytes,
1140*03ce13f7SAndroid Build Coastguard Worker InArgsSizeBytes);
1141*03ce13f7SAndroid Build Coastguard Worker return;
1142*03ce13f7SAndroid Build Coastguard Worker }
1143*03ce13f7SAndroid Build Coastguard Worker Type Ty = Arg->getType();
1144*03ce13f7SAndroid Build Coastguard Worker if (isVectorType(Ty)) {
1145*03ce13f7SAndroid Build Coastguard Worker InArgsSizeBytes = applyStackAlignment(InArgsSizeBytes);
1146*03ce13f7SAndroid Build Coastguard Worker }
1147*03ce13f7SAndroid Build Coastguard Worker Arg->setStackOffset(BasicFrameOffset + InArgsSizeBytes);
1148*03ce13f7SAndroid Build Coastguard Worker InArgsSizeBytes += typeWidthInBytesOnStack(Ty);
1149*03ce13f7SAndroid Build Coastguard Worker if (Arg->hasReg()) {
1150*03ce13f7SAndroid Build Coastguard Worker assert(Ty != IceType_i64);
1151*03ce13f7SAndroid Build Coastguard Worker auto *Mem = X86OperandMem::create(
1152*03ce13f7SAndroid Build Coastguard Worker Func, Ty, FramePtr,
1153*03ce13f7SAndroid Build Coastguard Worker Ctx->getConstantInt32(Arg->getStackOffset() + StackAdjBytes));
1154*03ce13f7SAndroid Build Coastguard Worker if (isVectorType(Arg->getType())) {
1155*03ce13f7SAndroid Build Coastguard Worker _movp(Arg, Mem);
1156*03ce13f7SAndroid Build Coastguard Worker } else {
1157*03ce13f7SAndroid Build Coastguard Worker _mov(Arg, Mem);
1158*03ce13f7SAndroid Build Coastguard Worker }
1159*03ce13f7SAndroid Build Coastguard Worker // This argument-copying instruction uses an explicit X86OperandMem
1160*03ce13f7SAndroid Build Coastguard Worker // operand instead of a Variable, so its fill-from-stack operation has to
1161*03ce13f7SAndroid Build Coastguard Worker // be tracked separately for statistics.
1162*03ce13f7SAndroid Build Coastguard Worker Ctx->statsUpdateFills();
1163*03ce13f7SAndroid Build Coastguard Worker }
1164*03ce13f7SAndroid Build Coastguard Worker }
1165*03ce13f7SAndroid Build Coastguard Worker
addEpilog(CfgNode * Node)1166*03ce13f7SAndroid Build Coastguard Worker void TargetX8632::addEpilog(CfgNode *Node) {
1167*03ce13f7SAndroid Build Coastguard Worker InstList &Insts = Node->getInsts();
1168*03ce13f7SAndroid Build Coastguard Worker InstList::reverse_iterator RI, E;
1169*03ce13f7SAndroid Build Coastguard Worker for (RI = Insts.rbegin(), E = Insts.rend(); RI != E; ++RI) {
1170*03ce13f7SAndroid Build Coastguard Worker if (llvm::isa<Insts::Ret>(*RI))
1171*03ce13f7SAndroid Build Coastguard Worker break;
1172*03ce13f7SAndroid Build Coastguard Worker }
1173*03ce13f7SAndroid Build Coastguard Worker if (RI == E)
1174*03ce13f7SAndroid Build Coastguard Worker return;
1175*03ce13f7SAndroid Build Coastguard Worker
1176*03ce13f7SAndroid Build Coastguard Worker // Convert the reverse_iterator position into its corresponding (forward)
1177*03ce13f7SAndroid Build Coastguard Worker // iterator position.
1178*03ce13f7SAndroid Build Coastguard Worker InstList::iterator InsertPoint = reverseToForwardIterator(RI);
1179*03ce13f7SAndroid Build Coastguard Worker --InsertPoint;
1180*03ce13f7SAndroid Build Coastguard Worker Context.init(Node);
1181*03ce13f7SAndroid Build Coastguard Worker Context.setInsertPoint(InsertPoint);
1182*03ce13f7SAndroid Build Coastguard Worker
1183*03ce13f7SAndroid Build Coastguard Worker if (IsEbpBasedFrame) {
1184*03ce13f7SAndroid Build Coastguard Worker _unlink_bp();
1185*03ce13f7SAndroid Build Coastguard Worker } else {
1186*03ce13f7SAndroid Build Coastguard Worker // add stackptr, SpillAreaSizeBytes
1187*03ce13f7SAndroid Build Coastguard Worker if (SpillAreaSizeBytes != 0) {
1188*03ce13f7SAndroid Build Coastguard Worker _add_sp(Ctx->getConstantInt32(SpillAreaSizeBytes));
1189*03ce13f7SAndroid Build Coastguard Worker }
1190*03ce13f7SAndroid Build Coastguard Worker }
1191*03ce13f7SAndroid Build Coastguard Worker
1192*03ce13f7SAndroid Build Coastguard Worker // Add pop instructions for preserved registers.
1193*03ce13f7SAndroid Build Coastguard Worker SmallBitVector CalleeSaves = getRegisterSet(RegSet_CalleeSave, RegSet_None);
1194*03ce13f7SAndroid Build Coastguard Worker SmallBitVector Popped(CalleeSaves.size());
1195*03ce13f7SAndroid Build Coastguard Worker for (int32_t i = CalleeSaves.size() - 1; i >= 0; --i) {
1196*03ce13f7SAndroid Build Coastguard Worker const auto RegNum = RegNumT::fromInt(i);
1197*03ce13f7SAndroid Build Coastguard Worker if (RegNum == getFrameReg() && IsEbpBasedFrame)
1198*03ce13f7SAndroid Build Coastguard Worker continue;
1199*03ce13f7SAndroid Build Coastguard Worker const RegNumT Canonical = RegX8632::getBaseReg(RegNum);
1200*03ce13f7SAndroid Build Coastguard Worker if (CalleeSaves[i] && RegsUsed[i]) {
1201*03ce13f7SAndroid Build Coastguard Worker Popped[Canonical] = true;
1202*03ce13f7SAndroid Build Coastguard Worker }
1203*03ce13f7SAndroid Build Coastguard Worker }
1204*03ce13f7SAndroid Build Coastguard Worker for (int32_t i = Popped.size() - 1; i >= 0; --i) {
1205*03ce13f7SAndroid Build Coastguard Worker if (!Popped[i])
1206*03ce13f7SAndroid Build Coastguard Worker continue;
1207*03ce13f7SAndroid Build Coastguard Worker const auto RegNum = RegNumT::fromInt(i);
1208*03ce13f7SAndroid Build Coastguard Worker assert(RegNum == RegX8632::getBaseReg(RegNum));
1209*03ce13f7SAndroid Build Coastguard Worker _pop_reg(RegNum);
1210*03ce13f7SAndroid Build Coastguard Worker }
1211*03ce13f7SAndroid Build Coastguard Worker }
1212*03ce13f7SAndroid Build Coastguard Worker
stackSlotType()1213*03ce13f7SAndroid Build Coastguard Worker Type TargetX8632::stackSlotType() { return WordType; }
1214*03ce13f7SAndroid Build Coastguard Worker
loOperand(Operand * Operand)1215*03ce13f7SAndroid Build Coastguard Worker Operand *TargetX8632::loOperand(Operand *Operand) {
1216*03ce13f7SAndroid Build Coastguard Worker assert(Operand->getType() == IceType_i64 ||
1217*03ce13f7SAndroid Build Coastguard Worker Operand->getType() == IceType_f64);
1218*03ce13f7SAndroid Build Coastguard Worker if (Operand->getType() != IceType_i64 && Operand->getType() != IceType_f64)
1219*03ce13f7SAndroid Build Coastguard Worker return Operand;
1220*03ce13f7SAndroid Build Coastguard Worker if (auto *Var64On32 = llvm::dyn_cast<Variable64On32>(Operand))
1221*03ce13f7SAndroid Build Coastguard Worker return Var64On32->getLo();
1222*03ce13f7SAndroid Build Coastguard Worker if (auto *Const = llvm::dyn_cast<ConstantInteger64>(Operand)) {
1223*03ce13f7SAndroid Build Coastguard Worker auto *ConstInt = llvm::dyn_cast<ConstantInteger32>(
1224*03ce13f7SAndroid Build Coastguard Worker Ctx->getConstantInt32(static_cast<int32_t>(Const->getValue())));
1225*03ce13f7SAndroid Build Coastguard Worker // Check if we need to blind/pool the constant.
1226*03ce13f7SAndroid Build Coastguard Worker return legalize(ConstInt);
1227*03ce13f7SAndroid Build Coastguard Worker }
1228*03ce13f7SAndroid Build Coastguard Worker if (auto *Mem = llvm::dyn_cast<X86OperandMem>(Operand)) {
1229*03ce13f7SAndroid Build Coastguard Worker auto *MemOperand = X86OperandMem::create(
1230*03ce13f7SAndroid Build Coastguard Worker Func, IceType_i32, Mem->getBase(), Mem->getOffset(), Mem->getIndex(),
1231*03ce13f7SAndroid Build Coastguard Worker Mem->getShift(), Mem->getSegmentRegister(), Mem->getIsRebased());
1232*03ce13f7SAndroid Build Coastguard Worker // Test if we should randomize or pool the offset, if so randomize it or
1233*03ce13f7SAndroid Build Coastguard Worker // pool it then create mem operand with the blinded/pooled constant.
1234*03ce13f7SAndroid Build Coastguard Worker // Otherwise, return the mem operand as ordinary mem operand.
1235*03ce13f7SAndroid Build Coastguard Worker return legalize(MemOperand);
1236*03ce13f7SAndroid Build Coastguard Worker }
1237*03ce13f7SAndroid Build Coastguard Worker llvm_unreachable("Unsupported operand type");
1238*03ce13f7SAndroid Build Coastguard Worker return nullptr;
1239*03ce13f7SAndroid Build Coastguard Worker }
1240*03ce13f7SAndroid Build Coastguard Worker
hiOperand(Operand * Operand)1241*03ce13f7SAndroid Build Coastguard Worker Operand *TargetX8632::hiOperand(Operand *Operand) {
1242*03ce13f7SAndroid Build Coastguard Worker assert(Operand->getType() == IceType_i64 ||
1243*03ce13f7SAndroid Build Coastguard Worker Operand->getType() == IceType_f64);
1244*03ce13f7SAndroid Build Coastguard Worker if (Operand->getType() != IceType_i64 && Operand->getType() != IceType_f64)
1245*03ce13f7SAndroid Build Coastguard Worker return Operand;
1246*03ce13f7SAndroid Build Coastguard Worker if (auto *Var64On32 = llvm::dyn_cast<Variable64On32>(Operand))
1247*03ce13f7SAndroid Build Coastguard Worker return Var64On32->getHi();
1248*03ce13f7SAndroid Build Coastguard Worker if (auto *Const = llvm::dyn_cast<ConstantInteger64>(Operand)) {
1249*03ce13f7SAndroid Build Coastguard Worker auto *ConstInt = llvm::dyn_cast<ConstantInteger32>(
1250*03ce13f7SAndroid Build Coastguard Worker Ctx->getConstantInt32(static_cast<int32_t>(Const->getValue() >> 32)));
1251*03ce13f7SAndroid Build Coastguard Worker // Check if we need to blind/pool the constant.
1252*03ce13f7SAndroid Build Coastguard Worker return legalize(ConstInt);
1253*03ce13f7SAndroid Build Coastguard Worker }
1254*03ce13f7SAndroid Build Coastguard Worker if (auto *Mem = llvm::dyn_cast<X86OperandMem>(Operand)) {
1255*03ce13f7SAndroid Build Coastguard Worker Constant *Offset = Mem->getOffset();
1256*03ce13f7SAndroid Build Coastguard Worker if (Offset == nullptr) {
1257*03ce13f7SAndroid Build Coastguard Worker Offset = Ctx->getConstantInt32(4);
1258*03ce13f7SAndroid Build Coastguard Worker } else if (auto *IntOffset = llvm::dyn_cast<ConstantInteger32>(Offset)) {
1259*03ce13f7SAndroid Build Coastguard Worker Offset = Ctx->getConstantInt32(4 + IntOffset->getValue());
1260*03ce13f7SAndroid Build Coastguard Worker } else if (auto *SymOffset = llvm::dyn_cast<ConstantRelocatable>(Offset)) {
1261*03ce13f7SAndroid Build Coastguard Worker assert(!Utils::WouldOverflowAdd(SymOffset->getOffset(), 4));
1262*03ce13f7SAndroid Build Coastguard Worker Offset =
1263*03ce13f7SAndroid Build Coastguard Worker Ctx->getConstantSym(4 + SymOffset->getOffset(), SymOffset->getName());
1264*03ce13f7SAndroid Build Coastguard Worker }
1265*03ce13f7SAndroid Build Coastguard Worker auto *MemOperand = X86OperandMem::create(
1266*03ce13f7SAndroid Build Coastguard Worker Func, IceType_i32, Mem->getBase(), Offset, Mem->getIndex(),
1267*03ce13f7SAndroid Build Coastguard Worker Mem->getShift(), Mem->getSegmentRegister(), Mem->getIsRebased());
1268*03ce13f7SAndroid Build Coastguard Worker // Test if the Offset is an eligible i32 constants for randomization and
1269*03ce13f7SAndroid Build Coastguard Worker // pooling. Blind/pool it if it is. Otherwise return as oridinary mem
1270*03ce13f7SAndroid Build Coastguard Worker // operand.
1271*03ce13f7SAndroid Build Coastguard Worker return legalize(MemOperand);
1272*03ce13f7SAndroid Build Coastguard Worker }
1273*03ce13f7SAndroid Build Coastguard Worker llvm_unreachable("Unsupported operand type");
1274*03ce13f7SAndroid Build Coastguard Worker return nullptr;
1275*03ce13f7SAndroid Build Coastguard Worker }
1276*03ce13f7SAndroid Build Coastguard Worker
getRegisterSet(RegSetMask Include,RegSetMask Exclude) const1277*03ce13f7SAndroid Build Coastguard Worker SmallBitVector TargetX8632::getRegisterSet(RegSetMask Include,
1278*03ce13f7SAndroid Build Coastguard Worker RegSetMask Exclude) const {
1279*03ce13f7SAndroid Build Coastguard Worker return RegX8632::getRegisterSet(getFlags(), Include, Exclude);
1280*03ce13f7SAndroid Build Coastguard Worker }
1281*03ce13f7SAndroid Build Coastguard Worker
lowerAlloca(const InstAlloca * Instr)1282*03ce13f7SAndroid Build Coastguard Worker void TargetX8632::lowerAlloca(const InstAlloca *Instr) {
1283*03ce13f7SAndroid Build Coastguard Worker // Conservatively require the stack to be aligned. Some stack adjustment
1284*03ce13f7SAndroid Build Coastguard Worker // operations implemented below assume that the stack is aligned before the
1285*03ce13f7SAndroid Build Coastguard Worker // alloca. All the alloca code ensures that the stack alignment is preserved
1286*03ce13f7SAndroid Build Coastguard Worker // after the alloca. The stack alignment restriction can be relaxed in some
1287*03ce13f7SAndroid Build Coastguard Worker // cases.
1288*03ce13f7SAndroid Build Coastguard Worker RequiredStackAlignment =
1289*03ce13f7SAndroid Build Coastguard Worker std::max<size_t>(RequiredStackAlignment, X86_STACK_ALIGNMENT_BYTES);
1290*03ce13f7SAndroid Build Coastguard Worker
1291*03ce13f7SAndroid Build Coastguard Worker // For default align=0, set it to the real value 1, to avoid any
1292*03ce13f7SAndroid Build Coastguard Worker // bit-manipulation problems below.
1293*03ce13f7SAndroid Build Coastguard Worker const uint32_t AlignmentParam = std::max(1u, Instr->getAlignInBytes());
1294*03ce13f7SAndroid Build Coastguard Worker
1295*03ce13f7SAndroid Build Coastguard Worker // LLVM enforces power of 2 alignment.
1296*03ce13f7SAndroid Build Coastguard Worker assert(llvm::isPowerOf2_32(AlignmentParam));
1297*03ce13f7SAndroid Build Coastguard Worker assert(llvm::isPowerOf2_32(X86_STACK_ALIGNMENT_BYTES));
1298*03ce13f7SAndroid Build Coastguard Worker
1299*03ce13f7SAndroid Build Coastguard Worker const uint32_t Alignment =
1300*03ce13f7SAndroid Build Coastguard Worker std::max(AlignmentParam, X86_STACK_ALIGNMENT_BYTES);
1301*03ce13f7SAndroid Build Coastguard Worker const bool OverAligned = Alignment > X86_STACK_ALIGNMENT_BYTES;
1302*03ce13f7SAndroid Build Coastguard Worker const bool OptM1 = Func->getOptLevel() == Opt_m1;
1303*03ce13f7SAndroid Build Coastguard Worker const bool AllocaWithKnownOffset = Instr->getKnownFrameOffset();
1304*03ce13f7SAndroid Build Coastguard Worker const bool UseFramePointer =
1305*03ce13f7SAndroid Build Coastguard Worker hasFramePointer() || OverAligned || !AllocaWithKnownOffset || OptM1;
1306*03ce13f7SAndroid Build Coastguard Worker
1307*03ce13f7SAndroid Build Coastguard Worker if (UseFramePointer)
1308*03ce13f7SAndroid Build Coastguard Worker setHasFramePointer();
1309*03ce13f7SAndroid Build Coastguard Worker
1310*03ce13f7SAndroid Build Coastguard Worker Variable *esp = getPhysicalRegister(getStackReg(), WordType);
1311*03ce13f7SAndroid Build Coastguard Worker if (OverAligned) {
1312*03ce13f7SAndroid Build Coastguard Worker _and(esp, Ctx->getConstantInt32(-Alignment));
1313*03ce13f7SAndroid Build Coastguard Worker }
1314*03ce13f7SAndroid Build Coastguard Worker
1315*03ce13f7SAndroid Build Coastguard Worker Variable *Dest = Instr->getDest();
1316*03ce13f7SAndroid Build Coastguard Worker Operand *TotalSize = legalize(Instr->getSizeInBytes());
1317*03ce13f7SAndroid Build Coastguard Worker
1318*03ce13f7SAndroid Build Coastguard Worker if (const auto *ConstantTotalSize =
1319*03ce13f7SAndroid Build Coastguard Worker llvm::dyn_cast<ConstantInteger32>(TotalSize)) {
1320*03ce13f7SAndroid Build Coastguard Worker const uint32_t Value =
1321*03ce13f7SAndroid Build Coastguard Worker Utils::applyAlignment(ConstantTotalSize->getValue(), Alignment);
1322*03ce13f7SAndroid Build Coastguard Worker if (UseFramePointer) {
1323*03ce13f7SAndroid Build Coastguard Worker _sub_sp(Ctx->getConstantInt32(Value));
1324*03ce13f7SAndroid Build Coastguard Worker } else {
1325*03ce13f7SAndroid Build Coastguard Worker // If we don't need a Frame Pointer, this alloca has a known offset to the
1326*03ce13f7SAndroid Build Coastguard Worker // stack pointer. We don't need adjust the stack pointer, nor assign any
1327*03ce13f7SAndroid Build Coastguard Worker // value to Dest, as Dest is rematerializable.
1328*03ce13f7SAndroid Build Coastguard Worker assert(Dest->isRematerializable());
1329*03ce13f7SAndroid Build Coastguard Worker FixedAllocaSizeBytes += Value;
1330*03ce13f7SAndroid Build Coastguard Worker Context.insert<InstFakeDef>(Dest);
1331*03ce13f7SAndroid Build Coastguard Worker }
1332*03ce13f7SAndroid Build Coastguard Worker } else {
1333*03ce13f7SAndroid Build Coastguard Worker // Non-constant sizes need to be adjusted to the next highest multiple of
1334*03ce13f7SAndroid Build Coastguard Worker // the required alignment at runtime.
1335*03ce13f7SAndroid Build Coastguard Worker Variable *T = makeReg(IceType_i32);
1336*03ce13f7SAndroid Build Coastguard Worker _mov(T, TotalSize);
1337*03ce13f7SAndroid Build Coastguard Worker _add(T, Ctx->getConstantInt32(Alignment - 1));
1338*03ce13f7SAndroid Build Coastguard Worker _and(T, Ctx->getConstantInt32(-Alignment));
1339*03ce13f7SAndroid Build Coastguard Worker _sub_sp(T);
1340*03ce13f7SAndroid Build Coastguard Worker }
1341*03ce13f7SAndroid Build Coastguard Worker // Add enough to the returned address to account for the out args area.
1342*03ce13f7SAndroid Build Coastguard Worker uint32_t OutArgsSize = maxOutArgsSizeBytes();
1343*03ce13f7SAndroid Build Coastguard Worker if (OutArgsSize > 0) {
1344*03ce13f7SAndroid Build Coastguard Worker Variable *T = makeReg(Dest->getType());
1345*03ce13f7SAndroid Build Coastguard Worker auto *CalculateOperand = X86OperandMem::create(
1346*03ce13f7SAndroid Build Coastguard Worker Func, IceType_void, esp, Ctx->getConstantInt(IceType_i32, OutArgsSize));
1347*03ce13f7SAndroid Build Coastguard Worker _lea(T, CalculateOperand);
1348*03ce13f7SAndroid Build Coastguard Worker _mov(Dest, T);
1349*03ce13f7SAndroid Build Coastguard Worker } else {
1350*03ce13f7SAndroid Build Coastguard Worker _mov(Dest, esp);
1351*03ce13f7SAndroid Build Coastguard Worker }
1352*03ce13f7SAndroid Build Coastguard Worker }
1353*03ce13f7SAndroid Build Coastguard Worker
lowerArguments()1354*03ce13f7SAndroid Build Coastguard Worker void TargetX8632::lowerArguments() {
1355*03ce13f7SAndroid Build Coastguard Worker const bool OptM1 = Func->getOptLevel() == Opt_m1;
1356*03ce13f7SAndroid Build Coastguard Worker VarList &Args = Func->getArgs();
1357*03ce13f7SAndroid Build Coastguard Worker unsigned NumXmmArgs = 0;
1358*03ce13f7SAndroid Build Coastguard Worker bool XmmSlotsRemain = true;
1359*03ce13f7SAndroid Build Coastguard Worker unsigned NumGprArgs = 0;
1360*03ce13f7SAndroid Build Coastguard Worker bool GprSlotsRemain = true;
1361*03ce13f7SAndroid Build Coastguard Worker
1362*03ce13f7SAndroid Build Coastguard Worker Context.init(Func->getEntryNode());
1363*03ce13f7SAndroid Build Coastguard Worker Context.setInsertPoint(Context.getCur());
1364*03ce13f7SAndroid Build Coastguard Worker
1365*03ce13f7SAndroid Build Coastguard Worker for (SizeT i = 0, End = Args.size();
1366*03ce13f7SAndroid Build Coastguard Worker i < End && (XmmSlotsRemain || GprSlotsRemain); ++i) {
1367*03ce13f7SAndroid Build Coastguard Worker Variable *Arg = Args[i];
1368*03ce13f7SAndroid Build Coastguard Worker Type Ty = Arg->getType();
1369*03ce13f7SAndroid Build Coastguard Worker Variable *RegisterArg = nullptr;
1370*03ce13f7SAndroid Build Coastguard Worker RegNumT RegNum;
1371*03ce13f7SAndroid Build Coastguard Worker if (isVectorType(Ty)) {
1372*03ce13f7SAndroid Build Coastguard Worker RegNum = RegX8632::getRegisterForXmmArgNum(
1373*03ce13f7SAndroid Build Coastguard Worker RegX8632::getArgIndex(i, NumXmmArgs));
1374*03ce13f7SAndroid Build Coastguard Worker if (RegNum.hasNoValue()) {
1375*03ce13f7SAndroid Build Coastguard Worker XmmSlotsRemain = false;
1376*03ce13f7SAndroid Build Coastguard Worker continue;
1377*03ce13f7SAndroid Build Coastguard Worker }
1378*03ce13f7SAndroid Build Coastguard Worker ++NumXmmArgs;
1379*03ce13f7SAndroid Build Coastguard Worker RegisterArg = Func->makeVariable(Ty);
1380*03ce13f7SAndroid Build Coastguard Worker } else if (isScalarFloatingType(Ty)) {
1381*03ce13f7SAndroid Build Coastguard Worker continue;
1382*03ce13f7SAndroid Build Coastguard Worker } else if (isScalarIntegerType(Ty)) {
1383*03ce13f7SAndroid Build Coastguard Worker RegNum = RegX8632::getRegisterForGprArgNum(
1384*03ce13f7SAndroid Build Coastguard Worker Ty, RegX8632::getArgIndex(i, NumGprArgs));
1385*03ce13f7SAndroid Build Coastguard Worker if (RegNum.hasNoValue()) {
1386*03ce13f7SAndroid Build Coastguard Worker GprSlotsRemain = false;
1387*03ce13f7SAndroid Build Coastguard Worker continue;
1388*03ce13f7SAndroid Build Coastguard Worker }
1389*03ce13f7SAndroid Build Coastguard Worker ++NumGprArgs;
1390*03ce13f7SAndroid Build Coastguard Worker RegisterArg = Func->makeVariable(Ty);
1391*03ce13f7SAndroid Build Coastguard Worker }
1392*03ce13f7SAndroid Build Coastguard Worker assert(RegNum.hasValue());
1393*03ce13f7SAndroid Build Coastguard Worker assert(RegisterArg != nullptr);
1394*03ce13f7SAndroid Build Coastguard Worker // Replace Arg in the argument list with the home register. Then generate
1395*03ce13f7SAndroid Build Coastguard Worker // an instruction in the prolog to copy the home register to the assigned
1396*03ce13f7SAndroid Build Coastguard Worker // location of Arg.
1397*03ce13f7SAndroid Build Coastguard Worker if (BuildDefs::dump())
1398*03ce13f7SAndroid Build Coastguard Worker RegisterArg->setName(Func, "home_reg:" + Arg->getName());
1399*03ce13f7SAndroid Build Coastguard Worker RegisterArg->setRegNum(RegNum);
1400*03ce13f7SAndroid Build Coastguard Worker RegisterArg->setIsArg();
1401*03ce13f7SAndroid Build Coastguard Worker Arg->setIsArg(false);
1402*03ce13f7SAndroid Build Coastguard Worker
1403*03ce13f7SAndroid Build Coastguard Worker Args[i] = RegisterArg;
1404*03ce13f7SAndroid Build Coastguard Worker // When not Om1, do the assignment through a temporary, instead of directly
1405*03ce13f7SAndroid Build Coastguard Worker // from the pre-colored variable, so that a subsequent availabilityGet()
1406*03ce13f7SAndroid Build Coastguard Worker // call has a chance to work. (In Om1, don't bother creating extra
1407*03ce13f7SAndroid Build Coastguard Worker // instructions with extra variables to register-allocate.)
1408*03ce13f7SAndroid Build Coastguard Worker if (OptM1) {
1409*03ce13f7SAndroid Build Coastguard Worker Context.insert<InstAssign>(Arg, RegisterArg);
1410*03ce13f7SAndroid Build Coastguard Worker } else {
1411*03ce13f7SAndroid Build Coastguard Worker Variable *Tmp = makeReg(RegisterArg->getType());
1412*03ce13f7SAndroid Build Coastguard Worker Context.insert<InstAssign>(Tmp, RegisterArg);
1413*03ce13f7SAndroid Build Coastguard Worker Context.insert<InstAssign>(Arg, Tmp);
1414*03ce13f7SAndroid Build Coastguard Worker }
1415*03ce13f7SAndroid Build Coastguard Worker }
1416*03ce13f7SAndroid Build Coastguard Worker if (!OptM1)
1417*03ce13f7SAndroid Build Coastguard Worker Context.availabilityUpdate();
1418*03ce13f7SAndroid Build Coastguard Worker }
1419*03ce13f7SAndroid Build Coastguard Worker
1420*03ce13f7SAndroid Build Coastguard Worker /// Strength-reduce scalar integer multiplication by a constant (for i32 or
1421*03ce13f7SAndroid Build Coastguard Worker /// narrower) for certain constants. The lea instruction can be used to multiply
1422*03ce13f7SAndroid Build Coastguard Worker /// by 3, 5, or 9, and the lsh instruction can be used to multiply by powers of
1423*03ce13f7SAndroid Build Coastguard Worker /// 2. These can be combined such that e.g. multiplying by 100 can be done as 2
1424*03ce13f7SAndroid Build Coastguard Worker /// lea-based multiplies by 5, combined with left-shifting by 2.
1425*03ce13f7SAndroid Build Coastguard Worker
optimizeScalarMul(Variable * Dest,Operand * Src0,int32_t Src1)1426*03ce13f7SAndroid Build Coastguard Worker bool TargetX8632::optimizeScalarMul(Variable *Dest, Operand *Src0,
1427*03ce13f7SAndroid Build Coastguard Worker int32_t Src1) {
1428*03ce13f7SAndroid Build Coastguard Worker // Disable this optimization for Om1 and O0, just to keep things simple
1429*03ce13f7SAndroid Build Coastguard Worker // there.
1430*03ce13f7SAndroid Build Coastguard Worker if (Func->getOptLevel() < Opt_1)
1431*03ce13f7SAndroid Build Coastguard Worker return false;
1432*03ce13f7SAndroid Build Coastguard Worker Type Ty = Dest->getType();
1433*03ce13f7SAndroid Build Coastguard Worker if (Src1 == -1) {
1434*03ce13f7SAndroid Build Coastguard Worker Variable *T = nullptr;
1435*03ce13f7SAndroid Build Coastguard Worker _mov(T, Src0);
1436*03ce13f7SAndroid Build Coastguard Worker _neg(T);
1437*03ce13f7SAndroid Build Coastguard Worker _mov(Dest, T);
1438*03ce13f7SAndroid Build Coastguard Worker return true;
1439*03ce13f7SAndroid Build Coastguard Worker }
1440*03ce13f7SAndroid Build Coastguard Worker if (Src1 == 0) {
1441*03ce13f7SAndroid Build Coastguard Worker _mov(Dest, Ctx->getConstantZero(Ty));
1442*03ce13f7SAndroid Build Coastguard Worker return true;
1443*03ce13f7SAndroid Build Coastguard Worker }
1444*03ce13f7SAndroid Build Coastguard Worker if (Src1 == 1) {
1445*03ce13f7SAndroid Build Coastguard Worker Variable *T = nullptr;
1446*03ce13f7SAndroid Build Coastguard Worker _mov(T, Src0);
1447*03ce13f7SAndroid Build Coastguard Worker _mov(Dest, T);
1448*03ce13f7SAndroid Build Coastguard Worker return true;
1449*03ce13f7SAndroid Build Coastguard Worker }
1450*03ce13f7SAndroid Build Coastguard Worker // Don't bother with the edge case where Src1 == MININT.
1451*03ce13f7SAndroid Build Coastguard Worker if (Src1 == -Src1)
1452*03ce13f7SAndroid Build Coastguard Worker return false;
1453*03ce13f7SAndroid Build Coastguard Worker const bool Src1IsNegative = Src1 < 0;
1454*03ce13f7SAndroid Build Coastguard Worker if (Src1IsNegative)
1455*03ce13f7SAndroid Build Coastguard Worker Src1 = -Src1;
1456*03ce13f7SAndroid Build Coastguard Worker uint32_t Count9 = 0;
1457*03ce13f7SAndroid Build Coastguard Worker uint32_t Count5 = 0;
1458*03ce13f7SAndroid Build Coastguard Worker uint32_t Count3 = 0;
1459*03ce13f7SAndroid Build Coastguard Worker uint32_t Count2 = 0;
1460*03ce13f7SAndroid Build Coastguard Worker uint32_t CountOps = 0;
1461*03ce13f7SAndroid Build Coastguard Worker while (Src1 > 1) {
1462*03ce13f7SAndroid Build Coastguard Worker if (Src1 % 9 == 0) {
1463*03ce13f7SAndroid Build Coastguard Worker ++CountOps;
1464*03ce13f7SAndroid Build Coastguard Worker ++Count9;
1465*03ce13f7SAndroid Build Coastguard Worker Src1 /= 9;
1466*03ce13f7SAndroid Build Coastguard Worker } else if (Src1 % 5 == 0) {
1467*03ce13f7SAndroid Build Coastguard Worker ++CountOps;
1468*03ce13f7SAndroid Build Coastguard Worker ++Count5;
1469*03ce13f7SAndroid Build Coastguard Worker Src1 /= 5;
1470*03ce13f7SAndroid Build Coastguard Worker } else if (Src1 % 3 == 0) {
1471*03ce13f7SAndroid Build Coastguard Worker ++CountOps;
1472*03ce13f7SAndroid Build Coastguard Worker ++Count3;
1473*03ce13f7SAndroid Build Coastguard Worker Src1 /= 3;
1474*03ce13f7SAndroid Build Coastguard Worker } else if (Src1 % 2 == 0) {
1475*03ce13f7SAndroid Build Coastguard Worker if (Count2 == 0)
1476*03ce13f7SAndroid Build Coastguard Worker ++CountOps;
1477*03ce13f7SAndroid Build Coastguard Worker ++Count2;
1478*03ce13f7SAndroid Build Coastguard Worker Src1 /= 2;
1479*03ce13f7SAndroid Build Coastguard Worker } else {
1480*03ce13f7SAndroid Build Coastguard Worker return false;
1481*03ce13f7SAndroid Build Coastguard Worker }
1482*03ce13f7SAndroid Build Coastguard Worker }
1483*03ce13f7SAndroid Build Coastguard Worker // Lea optimization only works for i16 and i32 types, not i8.
1484*03ce13f7SAndroid Build Coastguard Worker if (Ty != IceType_i32 && (Count3 || Count5 || Count9))
1485*03ce13f7SAndroid Build Coastguard Worker return false;
1486*03ce13f7SAndroid Build Coastguard Worker // Limit the number of lea/shl operations for a single multiply, to a
1487*03ce13f7SAndroid Build Coastguard Worker // somewhat arbitrary choice of 3.
1488*03ce13f7SAndroid Build Coastguard Worker constexpr uint32_t MaxOpsForOptimizedMul = 3;
1489*03ce13f7SAndroid Build Coastguard Worker if (CountOps > MaxOpsForOptimizedMul)
1490*03ce13f7SAndroid Build Coastguard Worker return false;
1491*03ce13f7SAndroid Build Coastguard Worker Variable *T = makeReg(WordType);
1492*03ce13f7SAndroid Build Coastguard Worker if (typeWidthInBytes(Src0->getType()) < typeWidthInBytes(T->getType())) {
1493*03ce13f7SAndroid Build Coastguard Worker Operand *Src0RM = legalize(Src0, Legal_Reg | Legal_Mem);
1494*03ce13f7SAndroid Build Coastguard Worker _movzx(T, Src0RM);
1495*03ce13f7SAndroid Build Coastguard Worker } else {
1496*03ce13f7SAndroid Build Coastguard Worker _mov(T, Src0);
1497*03ce13f7SAndroid Build Coastguard Worker }
1498*03ce13f7SAndroid Build Coastguard Worker Constant *Zero = Ctx->getConstantZero(IceType_i32);
1499*03ce13f7SAndroid Build Coastguard Worker for (uint32_t i = 0; i < Count9; ++i) {
1500*03ce13f7SAndroid Build Coastguard Worker constexpr uint16_t Shift = 3; // log2(9-1)
1501*03ce13f7SAndroid Build Coastguard Worker _lea(T, X86OperandMem::create(Func, IceType_void, T, Zero, T, Shift));
1502*03ce13f7SAndroid Build Coastguard Worker }
1503*03ce13f7SAndroid Build Coastguard Worker for (uint32_t i = 0; i < Count5; ++i) {
1504*03ce13f7SAndroid Build Coastguard Worker constexpr uint16_t Shift = 2; // log2(5-1)
1505*03ce13f7SAndroid Build Coastguard Worker _lea(T, X86OperandMem::create(Func, IceType_void, T, Zero, T, Shift));
1506*03ce13f7SAndroid Build Coastguard Worker }
1507*03ce13f7SAndroid Build Coastguard Worker for (uint32_t i = 0; i < Count3; ++i) {
1508*03ce13f7SAndroid Build Coastguard Worker constexpr uint16_t Shift = 1; // log2(3-1)
1509*03ce13f7SAndroid Build Coastguard Worker _lea(T, X86OperandMem::create(Func, IceType_void, T, Zero, T, Shift));
1510*03ce13f7SAndroid Build Coastguard Worker }
1511*03ce13f7SAndroid Build Coastguard Worker if (Count2) {
1512*03ce13f7SAndroid Build Coastguard Worker _shl(T, Ctx->getConstantInt(Ty, Count2));
1513*03ce13f7SAndroid Build Coastguard Worker }
1514*03ce13f7SAndroid Build Coastguard Worker if (Src1IsNegative)
1515*03ce13f7SAndroid Build Coastguard Worker _neg(T);
1516*03ce13f7SAndroid Build Coastguard Worker _mov(Dest, T);
1517*03ce13f7SAndroid Build Coastguard Worker return true;
1518*03ce13f7SAndroid Build Coastguard Worker }
1519*03ce13f7SAndroid Build Coastguard Worker
lowerShift64(InstArithmetic::OpKind Op,Operand * Src0Lo,Operand * Src0Hi,Operand * Src1Lo,Variable * DestLo,Variable * DestHi)1520*03ce13f7SAndroid Build Coastguard Worker void TargetX8632::lowerShift64(InstArithmetic::OpKind Op, Operand *Src0Lo,
1521*03ce13f7SAndroid Build Coastguard Worker Operand *Src0Hi, Operand *Src1Lo,
1522*03ce13f7SAndroid Build Coastguard Worker Variable *DestLo, Variable *DestHi) {
1523*03ce13f7SAndroid Build Coastguard Worker // TODO: Refactor the similarities between Shl, Lshr, and Ashr.
1524*03ce13f7SAndroid Build Coastguard Worker Variable *T_1 = nullptr, *T_2 = nullptr, *T_3 = nullptr;
1525*03ce13f7SAndroid Build Coastguard Worker Constant *Zero = Ctx->getConstantZero(IceType_i32);
1526*03ce13f7SAndroid Build Coastguard Worker Constant *SignExtend = Ctx->getConstantInt32(0x1f);
1527*03ce13f7SAndroid Build Coastguard Worker if (auto *ConstantShiftAmount = llvm::dyn_cast<ConstantInteger32>(Src1Lo)) {
1528*03ce13f7SAndroid Build Coastguard Worker uint32_t ShiftAmount = ConstantShiftAmount->getValue();
1529*03ce13f7SAndroid Build Coastguard Worker if (ShiftAmount > 32) {
1530*03ce13f7SAndroid Build Coastguard Worker Constant *ReducedShift = Ctx->getConstantInt32(ShiftAmount - 32);
1531*03ce13f7SAndroid Build Coastguard Worker switch (Op) {
1532*03ce13f7SAndroid Build Coastguard Worker default:
1533*03ce13f7SAndroid Build Coastguard Worker assert(0 && "non-shift op");
1534*03ce13f7SAndroid Build Coastguard Worker break;
1535*03ce13f7SAndroid Build Coastguard Worker case InstArithmetic::Shl: {
1536*03ce13f7SAndroid Build Coastguard Worker // a=b<<c ==>
1537*03ce13f7SAndroid Build Coastguard Worker // t2 = b.lo
1538*03ce13f7SAndroid Build Coastguard Worker // t2 = shl t2, ShiftAmount-32
1539*03ce13f7SAndroid Build Coastguard Worker // t3 = t2
1540*03ce13f7SAndroid Build Coastguard Worker // t2 = 0
1541*03ce13f7SAndroid Build Coastguard Worker _mov(T_2, Src0Lo);
1542*03ce13f7SAndroid Build Coastguard Worker _shl(T_2, ReducedShift);
1543*03ce13f7SAndroid Build Coastguard Worker _mov(DestHi, T_2);
1544*03ce13f7SAndroid Build Coastguard Worker _mov(DestLo, Zero);
1545*03ce13f7SAndroid Build Coastguard Worker } break;
1546*03ce13f7SAndroid Build Coastguard Worker case InstArithmetic::Lshr: {
1547*03ce13f7SAndroid Build Coastguard Worker // a=b>>c (unsigned) ==>
1548*03ce13f7SAndroid Build Coastguard Worker // t2 = b.hi
1549*03ce13f7SAndroid Build Coastguard Worker // t2 = shr t2, ShiftAmount-32
1550*03ce13f7SAndroid Build Coastguard Worker // a.lo = t2
1551*03ce13f7SAndroid Build Coastguard Worker // a.hi = 0
1552*03ce13f7SAndroid Build Coastguard Worker _mov(T_2, Src0Hi);
1553*03ce13f7SAndroid Build Coastguard Worker _shr(T_2, ReducedShift);
1554*03ce13f7SAndroid Build Coastguard Worker _mov(DestLo, T_2);
1555*03ce13f7SAndroid Build Coastguard Worker _mov(DestHi, Zero);
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 // t3 = b.hi
1560*03ce13f7SAndroid Build Coastguard Worker // t3 = sar t3, 0x1f
1561*03ce13f7SAndroid Build Coastguard Worker // t2 = b.hi
1562*03ce13f7SAndroid Build Coastguard Worker // t2 = shrd t2, t3, ShiftAmount-32
1563*03ce13f7SAndroid Build Coastguard Worker // a.lo = t2
1564*03ce13f7SAndroid Build Coastguard Worker // a.hi = t3
1565*03ce13f7SAndroid Build Coastguard Worker _mov(T_3, Src0Hi);
1566*03ce13f7SAndroid Build Coastguard Worker _sar(T_3, SignExtend);
1567*03ce13f7SAndroid Build Coastguard Worker _mov(T_2, Src0Hi);
1568*03ce13f7SAndroid Build Coastguard Worker _shrd(T_2, T_3, ReducedShift);
1569*03ce13f7SAndroid Build Coastguard Worker _mov(DestLo, T_2);
1570*03ce13f7SAndroid Build Coastguard Worker _mov(DestHi, T_3);
1571*03ce13f7SAndroid Build Coastguard Worker } break;
1572*03ce13f7SAndroid Build Coastguard Worker }
1573*03ce13f7SAndroid Build Coastguard Worker } else if (ShiftAmount == 32) {
1574*03ce13f7SAndroid Build Coastguard Worker switch (Op) {
1575*03ce13f7SAndroid Build Coastguard Worker default:
1576*03ce13f7SAndroid Build Coastguard Worker assert(0 && "non-shift op");
1577*03ce13f7SAndroid Build Coastguard Worker break;
1578*03ce13f7SAndroid Build Coastguard Worker case InstArithmetic::Shl: {
1579*03ce13f7SAndroid Build Coastguard Worker // a=b<<c ==>
1580*03ce13f7SAndroid Build Coastguard Worker // t2 = b.lo
1581*03ce13f7SAndroid Build Coastguard Worker // a.hi = t2
1582*03ce13f7SAndroid Build Coastguard Worker // a.lo = 0
1583*03ce13f7SAndroid Build Coastguard Worker _mov(T_2, Src0Lo);
1584*03ce13f7SAndroid Build Coastguard Worker _mov(DestHi, T_2);
1585*03ce13f7SAndroid Build Coastguard Worker _mov(DestLo, Zero);
1586*03ce13f7SAndroid Build Coastguard Worker } break;
1587*03ce13f7SAndroid Build Coastguard Worker case InstArithmetic::Lshr: {
1588*03ce13f7SAndroid Build Coastguard Worker // a=b>>c (unsigned) ==>
1589*03ce13f7SAndroid Build Coastguard Worker // t2 = b.hi
1590*03ce13f7SAndroid Build Coastguard Worker // a.lo = t2
1591*03ce13f7SAndroid Build Coastguard Worker // a.hi = 0
1592*03ce13f7SAndroid Build Coastguard Worker _mov(T_2, Src0Hi);
1593*03ce13f7SAndroid Build Coastguard Worker _mov(DestLo, T_2);
1594*03ce13f7SAndroid Build Coastguard Worker _mov(DestHi, Zero);
1595*03ce13f7SAndroid Build Coastguard Worker } break;
1596*03ce13f7SAndroid Build Coastguard Worker case InstArithmetic::Ashr: {
1597*03ce13f7SAndroid Build Coastguard Worker // a=b>>c (signed) ==>
1598*03ce13f7SAndroid Build Coastguard Worker // t2 = b.hi
1599*03ce13f7SAndroid Build Coastguard Worker // a.lo = t2
1600*03ce13f7SAndroid Build Coastguard Worker // t3 = b.hi
1601*03ce13f7SAndroid Build Coastguard Worker // t3 = sar t3, 0x1f
1602*03ce13f7SAndroid Build Coastguard Worker // a.hi = t3
1603*03ce13f7SAndroid Build Coastguard Worker _mov(T_2, Src0Hi);
1604*03ce13f7SAndroid Build Coastguard Worker _mov(DestLo, T_2);
1605*03ce13f7SAndroid Build Coastguard Worker _mov(T_3, Src0Hi);
1606*03ce13f7SAndroid Build Coastguard Worker _sar(T_3, SignExtend);
1607*03ce13f7SAndroid Build Coastguard Worker _mov(DestHi, T_3);
1608*03ce13f7SAndroid Build Coastguard Worker } break;
1609*03ce13f7SAndroid Build Coastguard Worker }
1610*03ce13f7SAndroid Build Coastguard Worker } else {
1611*03ce13f7SAndroid Build Coastguard Worker // COMMON PREFIX OF: a=b SHIFT_OP c ==>
1612*03ce13f7SAndroid Build Coastguard Worker // t2 = b.lo
1613*03ce13f7SAndroid Build Coastguard Worker // t3 = b.hi
1614*03ce13f7SAndroid Build Coastguard Worker _mov(T_2, Src0Lo);
1615*03ce13f7SAndroid Build Coastguard Worker _mov(T_3, Src0Hi);
1616*03ce13f7SAndroid Build Coastguard Worker switch (Op) {
1617*03ce13f7SAndroid Build Coastguard Worker default:
1618*03ce13f7SAndroid Build Coastguard Worker assert(0 && "non-shift op");
1619*03ce13f7SAndroid Build Coastguard Worker break;
1620*03ce13f7SAndroid Build Coastguard Worker case InstArithmetic::Shl: {
1621*03ce13f7SAndroid Build Coastguard Worker // a=b<<c ==>
1622*03ce13f7SAndroid Build Coastguard Worker // t3 = shld t3, t2, ShiftAmount
1623*03ce13f7SAndroid Build Coastguard Worker // t2 = shl t2, ShiftAmount
1624*03ce13f7SAndroid Build Coastguard Worker _shld(T_3, T_2, ConstantShiftAmount);
1625*03ce13f7SAndroid Build Coastguard Worker _shl(T_2, ConstantShiftAmount);
1626*03ce13f7SAndroid Build Coastguard Worker } break;
1627*03ce13f7SAndroid Build Coastguard Worker case InstArithmetic::Lshr: {
1628*03ce13f7SAndroid Build Coastguard Worker // a=b>>c (unsigned) ==>
1629*03ce13f7SAndroid Build Coastguard Worker // t2 = shrd t2, t3, ShiftAmount
1630*03ce13f7SAndroid Build Coastguard Worker // t3 = shr t3, ShiftAmount
1631*03ce13f7SAndroid Build Coastguard Worker _shrd(T_2, T_3, ConstantShiftAmount);
1632*03ce13f7SAndroid Build Coastguard Worker _shr(T_3, ConstantShiftAmount);
1633*03ce13f7SAndroid Build Coastguard Worker } break;
1634*03ce13f7SAndroid Build Coastguard Worker case InstArithmetic::Ashr: {
1635*03ce13f7SAndroid Build Coastguard Worker // a=b>>c (signed) ==>
1636*03ce13f7SAndroid Build Coastguard Worker // t2 = shrd t2, t3, ShiftAmount
1637*03ce13f7SAndroid Build Coastguard Worker // t3 = sar t3, ShiftAmount
1638*03ce13f7SAndroid Build Coastguard Worker _shrd(T_2, T_3, ConstantShiftAmount);
1639*03ce13f7SAndroid Build Coastguard Worker _sar(T_3, ConstantShiftAmount);
1640*03ce13f7SAndroid Build Coastguard Worker } break;
1641*03ce13f7SAndroid Build Coastguard Worker }
1642*03ce13f7SAndroid Build Coastguard Worker // COMMON SUFFIX OF: a=b SHIFT_OP c ==>
1643*03ce13f7SAndroid Build Coastguard Worker // a.lo = t2
1644*03ce13f7SAndroid Build Coastguard Worker // a.hi = t3
1645*03ce13f7SAndroid Build Coastguard Worker _mov(DestLo, T_2);
1646*03ce13f7SAndroid Build Coastguard Worker _mov(DestHi, T_3);
1647*03ce13f7SAndroid Build Coastguard Worker }
1648*03ce13f7SAndroid Build Coastguard Worker } else {
1649*03ce13f7SAndroid Build Coastguard Worker // NON-CONSTANT CASES.
1650*03ce13f7SAndroid Build Coastguard Worker Constant *BitTest = Ctx->getConstantInt32(0x20);
1651*03ce13f7SAndroid Build Coastguard Worker InstX86Label *Label = InstX86Label::create(Func, this);
1652*03ce13f7SAndroid Build Coastguard Worker // COMMON PREFIX OF: a=b SHIFT_OP c ==>
1653*03ce13f7SAndroid Build Coastguard Worker // t1:ecx = c.lo & 0xff
1654*03ce13f7SAndroid Build Coastguard Worker // t2 = b.lo
1655*03ce13f7SAndroid Build Coastguard Worker // t3 = b.hi
1656*03ce13f7SAndroid Build Coastguard Worker T_1 = copyToReg8(Src1Lo, RegX8632::Reg_cl);
1657*03ce13f7SAndroid Build Coastguard Worker _mov(T_2, Src0Lo);
1658*03ce13f7SAndroid Build Coastguard Worker _mov(T_3, Src0Hi);
1659*03ce13f7SAndroid Build Coastguard Worker switch (Op) {
1660*03ce13f7SAndroid Build Coastguard Worker default:
1661*03ce13f7SAndroid Build Coastguard Worker assert(0 && "non-shift op");
1662*03ce13f7SAndroid Build Coastguard Worker break;
1663*03ce13f7SAndroid Build Coastguard Worker case InstArithmetic::Shl: {
1664*03ce13f7SAndroid Build Coastguard Worker // a=b<<c ==>
1665*03ce13f7SAndroid Build Coastguard Worker // t3 = shld t3, t2, t1
1666*03ce13f7SAndroid Build Coastguard Worker // t2 = shl t2, t1
1667*03ce13f7SAndroid Build Coastguard Worker // test t1, 0x20
1668*03ce13f7SAndroid Build Coastguard Worker // je L1
1669*03ce13f7SAndroid Build Coastguard Worker // use(t3)
1670*03ce13f7SAndroid Build Coastguard Worker // t3 = t2
1671*03ce13f7SAndroid Build Coastguard Worker // t2 = 0
1672*03ce13f7SAndroid Build Coastguard Worker _shld(T_3, T_2, T_1);
1673*03ce13f7SAndroid Build Coastguard Worker _shl(T_2, T_1);
1674*03ce13f7SAndroid Build Coastguard Worker _test(T_1, BitTest);
1675*03ce13f7SAndroid Build Coastguard Worker _br(CondX86::Br_e, Label);
1676*03ce13f7SAndroid Build Coastguard Worker // T_2 and T_3 are being assigned again because of the intra-block control
1677*03ce13f7SAndroid Build Coastguard Worker // flow, so we need to use _redefined to avoid liveness problems.
1678*03ce13f7SAndroid Build Coastguard Worker _redefined(_mov(T_3, T_2));
1679*03ce13f7SAndroid Build Coastguard Worker _redefined(_mov(T_2, Zero));
1680*03ce13f7SAndroid Build Coastguard Worker } break;
1681*03ce13f7SAndroid Build Coastguard Worker case InstArithmetic::Lshr: {
1682*03ce13f7SAndroid Build Coastguard Worker // a=b>>c (unsigned) ==>
1683*03ce13f7SAndroid Build Coastguard Worker // t2 = shrd t2, t3, t1
1684*03ce13f7SAndroid Build Coastguard Worker // t3 = shr t3, t1
1685*03ce13f7SAndroid Build Coastguard Worker // test t1, 0x20
1686*03ce13f7SAndroid Build Coastguard Worker // je L1
1687*03ce13f7SAndroid Build Coastguard Worker // use(t2)
1688*03ce13f7SAndroid Build Coastguard Worker // t2 = t3
1689*03ce13f7SAndroid Build Coastguard Worker // t3 = 0
1690*03ce13f7SAndroid Build Coastguard Worker _shrd(T_2, T_3, T_1);
1691*03ce13f7SAndroid Build Coastguard Worker _shr(T_3, T_1);
1692*03ce13f7SAndroid Build Coastguard Worker _test(T_1, BitTest);
1693*03ce13f7SAndroid Build Coastguard Worker _br(CondX86::Br_e, Label);
1694*03ce13f7SAndroid Build Coastguard Worker // T_2 and T_3 are being assigned again because of the intra-block control
1695*03ce13f7SAndroid Build Coastguard Worker // flow, so we need to use _redefined to avoid liveness problems.
1696*03ce13f7SAndroid Build Coastguard Worker _redefined(_mov(T_2, T_3));
1697*03ce13f7SAndroid Build Coastguard Worker _redefined(_mov(T_3, Zero));
1698*03ce13f7SAndroid Build Coastguard Worker } break;
1699*03ce13f7SAndroid Build Coastguard Worker case InstArithmetic::Ashr: {
1700*03ce13f7SAndroid Build Coastguard Worker // a=b>>c (signed) ==>
1701*03ce13f7SAndroid Build Coastguard Worker // t2 = shrd t2, t3, t1
1702*03ce13f7SAndroid Build Coastguard Worker // t3 = sar t3, t1
1703*03ce13f7SAndroid Build Coastguard Worker // test t1, 0x20
1704*03ce13f7SAndroid Build Coastguard Worker // je L1
1705*03ce13f7SAndroid Build Coastguard Worker // use(t2)
1706*03ce13f7SAndroid Build Coastguard Worker // t2 = t3
1707*03ce13f7SAndroid Build Coastguard Worker // t3 = sar t3, 0x1f
1708*03ce13f7SAndroid Build Coastguard Worker Constant *SignExtend = Ctx->getConstantInt32(0x1f);
1709*03ce13f7SAndroid Build Coastguard Worker _shrd(T_2, T_3, T_1);
1710*03ce13f7SAndroid Build Coastguard Worker _sar(T_3, T_1);
1711*03ce13f7SAndroid Build Coastguard Worker _test(T_1, BitTest);
1712*03ce13f7SAndroid Build Coastguard Worker _br(CondX86::Br_e, Label);
1713*03ce13f7SAndroid Build Coastguard Worker // T_2 and T_3 are being assigned again because of the intra-block control
1714*03ce13f7SAndroid Build Coastguard Worker // flow, so T_2 needs to use _redefined to avoid liveness problems. T_3
1715*03ce13f7SAndroid Build Coastguard Worker // doesn't need special treatment because it is reassigned via _sar
1716*03ce13f7SAndroid Build Coastguard Worker // instead of _mov.
1717*03ce13f7SAndroid Build Coastguard Worker _redefined(_mov(T_2, T_3));
1718*03ce13f7SAndroid Build Coastguard Worker _sar(T_3, SignExtend);
1719*03ce13f7SAndroid Build Coastguard Worker } break;
1720*03ce13f7SAndroid Build Coastguard Worker }
1721*03ce13f7SAndroid Build Coastguard Worker // COMMON SUFFIX OF: a=b SHIFT_OP c ==>
1722*03ce13f7SAndroid Build Coastguard Worker // L1:
1723*03ce13f7SAndroid Build Coastguard Worker // a.lo = t2
1724*03ce13f7SAndroid Build Coastguard Worker // a.hi = t3
1725*03ce13f7SAndroid Build Coastguard Worker Context.insert(Label);
1726*03ce13f7SAndroid Build Coastguard Worker _mov(DestLo, T_2);
1727*03ce13f7SAndroid Build Coastguard Worker _mov(DestHi, T_3);
1728*03ce13f7SAndroid Build Coastguard Worker }
1729*03ce13f7SAndroid Build Coastguard Worker }
1730*03ce13f7SAndroid Build Coastguard Worker
lowerArithmetic(const InstArithmetic * Instr)1731*03ce13f7SAndroid Build Coastguard Worker void TargetX8632::lowerArithmetic(const InstArithmetic *Instr) {
1732*03ce13f7SAndroid Build Coastguard Worker Variable *Dest = Instr->getDest();
1733*03ce13f7SAndroid Build Coastguard Worker if (Dest->isRematerializable()) {
1734*03ce13f7SAndroid Build Coastguard Worker Context.insert<InstFakeDef>(Dest);
1735*03ce13f7SAndroid Build Coastguard Worker return;
1736*03ce13f7SAndroid Build Coastguard Worker }
1737*03ce13f7SAndroid Build Coastguard Worker Type Ty = Dest->getType();
1738*03ce13f7SAndroid Build Coastguard Worker Operand *Src0 = legalize(Instr->getSrc(0));
1739*03ce13f7SAndroid Build Coastguard Worker Operand *Src1 = legalize(Instr->getSrc(1));
1740*03ce13f7SAndroid Build Coastguard Worker if (Instr->isCommutative()) {
1741*03ce13f7SAndroid Build Coastguard Worker uint32_t SwapCount = 0;
1742*03ce13f7SAndroid Build Coastguard Worker if (!llvm::isa<Variable>(Src0) && llvm::isa<Variable>(Src1)) {
1743*03ce13f7SAndroid Build Coastguard Worker std::swap(Src0, Src1);
1744*03ce13f7SAndroid Build Coastguard Worker ++SwapCount;
1745*03ce13f7SAndroid Build Coastguard Worker }
1746*03ce13f7SAndroid Build Coastguard Worker if (llvm::isa<Constant>(Src0) && !llvm::isa<Constant>(Src1)) {
1747*03ce13f7SAndroid Build Coastguard Worker std::swap(Src0, Src1);
1748*03ce13f7SAndroid Build Coastguard Worker ++SwapCount;
1749*03ce13f7SAndroid Build Coastguard Worker }
1750*03ce13f7SAndroid Build Coastguard Worker // Improve two-address code patterns by avoiding a copy to the dest
1751*03ce13f7SAndroid Build Coastguard Worker // register when one of the source operands ends its lifetime here.
1752*03ce13f7SAndroid Build Coastguard Worker if (!Instr->isLastUse(Src0) && Instr->isLastUse(Src1)) {
1753*03ce13f7SAndroid Build Coastguard Worker std::swap(Src0, Src1);
1754*03ce13f7SAndroid Build Coastguard Worker ++SwapCount;
1755*03ce13f7SAndroid Build Coastguard Worker }
1756*03ce13f7SAndroid Build Coastguard Worker assert(SwapCount <= 1);
1757*03ce13f7SAndroid Build Coastguard Worker (void)SwapCount;
1758*03ce13f7SAndroid Build Coastguard Worker }
1759*03ce13f7SAndroid Build Coastguard Worker if (Ty == IceType_i64) {
1760*03ce13f7SAndroid Build Coastguard Worker // These x86-32 helper-call-involved instructions are lowered in this
1761*03ce13f7SAndroid Build Coastguard Worker // separate switch. This is because loOperand() and hiOperand() may insert
1762*03ce13f7SAndroid Build Coastguard Worker // redundant instructions for constant blinding and pooling. Such redundant
1763*03ce13f7SAndroid Build Coastguard Worker // instructions will fail liveness analysis under -Om1 setting. And,
1764*03ce13f7SAndroid Build Coastguard Worker // actually these arguments do not need to be processed with loOperand()
1765*03ce13f7SAndroid Build Coastguard Worker // and hiOperand() to be used.
1766*03ce13f7SAndroid Build Coastguard Worker switch (Instr->getOp()) {
1767*03ce13f7SAndroid Build Coastguard Worker case InstArithmetic::Udiv:
1768*03ce13f7SAndroid Build Coastguard Worker case InstArithmetic::Sdiv:
1769*03ce13f7SAndroid Build Coastguard Worker case InstArithmetic::Urem:
1770*03ce13f7SAndroid Build Coastguard Worker case InstArithmetic::Srem:
1771*03ce13f7SAndroid Build Coastguard Worker llvm::report_fatal_error("Helper call was expected");
1772*03ce13f7SAndroid Build Coastguard Worker return;
1773*03ce13f7SAndroid Build Coastguard Worker default:
1774*03ce13f7SAndroid Build Coastguard Worker break;
1775*03ce13f7SAndroid Build Coastguard Worker }
1776*03ce13f7SAndroid Build Coastguard Worker
1777*03ce13f7SAndroid Build Coastguard Worker auto *DestLo = llvm::cast<Variable>(loOperand(Dest));
1778*03ce13f7SAndroid Build Coastguard Worker auto *DestHi = llvm::cast<Variable>(hiOperand(Dest));
1779*03ce13f7SAndroid Build Coastguard Worker Operand *Src0Lo = loOperand(Src0);
1780*03ce13f7SAndroid Build Coastguard Worker Operand *Src0Hi = hiOperand(Src0);
1781*03ce13f7SAndroid Build Coastguard Worker Operand *Src1Lo = loOperand(Src1);
1782*03ce13f7SAndroid Build Coastguard Worker Operand *Src1Hi = hiOperand(Src1);
1783*03ce13f7SAndroid Build Coastguard Worker Variable *T_Lo = nullptr, *T_Hi = nullptr;
1784*03ce13f7SAndroid Build Coastguard Worker switch (Instr->getOp()) {
1785*03ce13f7SAndroid Build Coastguard Worker case InstArithmetic::_num:
1786*03ce13f7SAndroid Build Coastguard Worker llvm_unreachable("Unknown arithmetic operator");
1787*03ce13f7SAndroid Build Coastguard Worker break;
1788*03ce13f7SAndroid Build Coastguard Worker case InstArithmetic::Add:
1789*03ce13f7SAndroid Build Coastguard Worker _mov(T_Lo, Src0Lo);
1790*03ce13f7SAndroid Build Coastguard Worker _add(T_Lo, Src1Lo);
1791*03ce13f7SAndroid Build Coastguard Worker _mov(DestLo, T_Lo);
1792*03ce13f7SAndroid Build Coastguard Worker _mov(T_Hi, Src0Hi);
1793*03ce13f7SAndroid Build Coastguard Worker _adc(T_Hi, Src1Hi);
1794*03ce13f7SAndroid Build Coastguard Worker _mov(DestHi, T_Hi);
1795*03ce13f7SAndroid Build Coastguard Worker break;
1796*03ce13f7SAndroid Build Coastguard Worker case InstArithmetic::And:
1797*03ce13f7SAndroid Build Coastguard Worker _mov(T_Lo, Src0Lo);
1798*03ce13f7SAndroid Build Coastguard Worker _and(T_Lo, Src1Lo);
1799*03ce13f7SAndroid Build Coastguard Worker _mov(DestLo, T_Lo);
1800*03ce13f7SAndroid Build Coastguard Worker _mov(T_Hi, Src0Hi);
1801*03ce13f7SAndroid Build Coastguard Worker _and(T_Hi, Src1Hi);
1802*03ce13f7SAndroid Build Coastguard Worker _mov(DestHi, T_Hi);
1803*03ce13f7SAndroid Build Coastguard Worker break;
1804*03ce13f7SAndroid Build Coastguard Worker case InstArithmetic::Or:
1805*03ce13f7SAndroid Build Coastguard Worker _mov(T_Lo, Src0Lo);
1806*03ce13f7SAndroid Build Coastguard Worker _or(T_Lo, Src1Lo);
1807*03ce13f7SAndroid Build Coastguard Worker _mov(DestLo, T_Lo);
1808*03ce13f7SAndroid Build Coastguard Worker _mov(T_Hi, Src0Hi);
1809*03ce13f7SAndroid Build Coastguard Worker _or(T_Hi, Src1Hi);
1810*03ce13f7SAndroid Build Coastguard Worker _mov(DestHi, T_Hi);
1811*03ce13f7SAndroid Build Coastguard Worker break;
1812*03ce13f7SAndroid Build Coastguard Worker case InstArithmetic::Xor:
1813*03ce13f7SAndroid Build Coastguard Worker _mov(T_Lo, Src0Lo);
1814*03ce13f7SAndroid Build Coastguard Worker _xor(T_Lo, Src1Lo);
1815*03ce13f7SAndroid Build Coastguard Worker _mov(DestLo, T_Lo);
1816*03ce13f7SAndroid Build Coastguard Worker _mov(T_Hi, Src0Hi);
1817*03ce13f7SAndroid Build Coastguard Worker _xor(T_Hi, Src1Hi);
1818*03ce13f7SAndroid Build Coastguard Worker _mov(DestHi, T_Hi);
1819*03ce13f7SAndroid Build Coastguard Worker break;
1820*03ce13f7SAndroid Build Coastguard Worker case InstArithmetic::Sub:
1821*03ce13f7SAndroid Build Coastguard Worker _mov(T_Lo, Src0Lo);
1822*03ce13f7SAndroid Build Coastguard Worker _sub(T_Lo, Src1Lo);
1823*03ce13f7SAndroid Build Coastguard Worker _mov(DestLo, T_Lo);
1824*03ce13f7SAndroid Build Coastguard Worker _mov(T_Hi, Src0Hi);
1825*03ce13f7SAndroid Build Coastguard Worker _sbb(T_Hi, Src1Hi);
1826*03ce13f7SAndroid Build Coastguard Worker _mov(DestHi, T_Hi);
1827*03ce13f7SAndroid Build Coastguard Worker break;
1828*03ce13f7SAndroid Build Coastguard Worker case InstArithmetic::Mul: {
1829*03ce13f7SAndroid Build Coastguard Worker Variable *T_1 = nullptr, *T_2 = nullptr, *T_3 = nullptr;
1830*03ce13f7SAndroid Build Coastguard Worker Variable *T_4Lo = makeReg(IceType_i32, RegX8632::Reg_eax);
1831*03ce13f7SAndroid Build Coastguard Worker Variable *T_4Hi = makeReg(IceType_i32, RegX8632::Reg_edx);
1832*03ce13f7SAndroid Build Coastguard Worker // gcc does the following:
1833*03ce13f7SAndroid Build Coastguard Worker // a=b*c ==>
1834*03ce13f7SAndroid Build Coastguard Worker // t1 = b.hi; t1 *=(imul) c.lo
1835*03ce13f7SAndroid Build Coastguard Worker // t2 = c.hi; t2 *=(imul) b.lo
1836*03ce13f7SAndroid Build Coastguard Worker // t3:eax = b.lo
1837*03ce13f7SAndroid Build Coastguard Worker // t4.hi:edx,t4.lo:eax = t3:eax *(mul) c.lo
1838*03ce13f7SAndroid Build Coastguard Worker // a.lo = t4.lo
1839*03ce13f7SAndroid Build Coastguard Worker // t4.hi += t1
1840*03ce13f7SAndroid Build Coastguard Worker // t4.hi += t2
1841*03ce13f7SAndroid Build Coastguard Worker // a.hi = t4.hi
1842*03ce13f7SAndroid Build Coastguard Worker // The mul instruction cannot take an immediate operand.
1843*03ce13f7SAndroid Build Coastguard Worker Src1Lo = legalize(Src1Lo, Legal_Reg | Legal_Mem);
1844*03ce13f7SAndroid Build Coastguard Worker _mov(T_1, Src0Hi);
1845*03ce13f7SAndroid Build Coastguard Worker _imul(T_1, Src1Lo);
1846*03ce13f7SAndroid Build Coastguard Worker _mov(T_3, Src0Lo, RegX8632::Reg_eax);
1847*03ce13f7SAndroid Build Coastguard Worker _mul(T_4Lo, T_3, Src1Lo);
1848*03ce13f7SAndroid Build Coastguard Worker // The mul instruction produces two dest variables, edx:eax. We create a
1849*03ce13f7SAndroid Build Coastguard Worker // fake definition of edx to account for this.
1850*03ce13f7SAndroid Build Coastguard Worker Context.insert<InstFakeDef>(T_4Hi, T_4Lo);
1851*03ce13f7SAndroid Build Coastguard Worker Context.insert<InstFakeUse>(T_4Hi);
1852*03ce13f7SAndroid Build Coastguard Worker _mov(DestLo, T_4Lo);
1853*03ce13f7SAndroid Build Coastguard Worker _add(T_4Hi, T_1);
1854*03ce13f7SAndroid Build Coastguard Worker _mov(T_2, Src1Hi);
1855*03ce13f7SAndroid Build Coastguard Worker Src0Lo = legalize(Src0Lo, Legal_Reg | Legal_Mem);
1856*03ce13f7SAndroid Build Coastguard Worker _imul(T_2, Src0Lo);
1857*03ce13f7SAndroid Build Coastguard Worker _add(T_4Hi, T_2);
1858*03ce13f7SAndroid Build Coastguard Worker _mov(DestHi, T_4Hi);
1859*03ce13f7SAndroid Build Coastguard Worker } break;
1860*03ce13f7SAndroid Build Coastguard Worker case InstArithmetic::Shl:
1861*03ce13f7SAndroid Build Coastguard Worker case InstArithmetic::Lshr:
1862*03ce13f7SAndroid Build Coastguard Worker case InstArithmetic::Ashr:
1863*03ce13f7SAndroid Build Coastguard Worker lowerShift64(Instr->getOp(), Src0Lo, Src0Hi, Src1Lo, DestLo, DestHi);
1864*03ce13f7SAndroid Build Coastguard Worker break;
1865*03ce13f7SAndroid Build Coastguard Worker case InstArithmetic::Fadd:
1866*03ce13f7SAndroid Build Coastguard Worker case InstArithmetic::Fsub:
1867*03ce13f7SAndroid Build Coastguard Worker case InstArithmetic::Fmul:
1868*03ce13f7SAndroid Build Coastguard Worker case InstArithmetic::Fdiv:
1869*03ce13f7SAndroid Build Coastguard Worker case InstArithmetic::Frem:
1870*03ce13f7SAndroid Build Coastguard Worker llvm_unreachable("FP instruction with i64 type");
1871*03ce13f7SAndroid Build Coastguard Worker break;
1872*03ce13f7SAndroid Build Coastguard Worker case InstArithmetic::Udiv:
1873*03ce13f7SAndroid Build Coastguard Worker case InstArithmetic::Sdiv:
1874*03ce13f7SAndroid Build Coastguard Worker case InstArithmetic::Urem:
1875*03ce13f7SAndroid Build Coastguard Worker case InstArithmetic::Srem:
1876*03ce13f7SAndroid Build Coastguard Worker llvm_unreachable("Call-helper-involved instruction for i64 type \
1877*03ce13f7SAndroid Build Coastguard Worker should have already been handled before");
1878*03ce13f7SAndroid Build Coastguard Worker break;
1879*03ce13f7SAndroid Build Coastguard Worker }
1880*03ce13f7SAndroid Build Coastguard Worker return;
1881*03ce13f7SAndroid Build Coastguard Worker }
1882*03ce13f7SAndroid Build Coastguard Worker if (isVectorType(Ty)) {
1883*03ce13f7SAndroid Build Coastguard Worker // TODO: Trap on integer divide and integer modulo by zero. See:
1884*03ce13f7SAndroid Build Coastguard Worker // https://code.google.com/p/nativeclient/issues/detail?id=3899
1885*03ce13f7SAndroid Build Coastguard Worker if (llvm::isa<X86OperandMem>(Src1))
1886*03ce13f7SAndroid Build Coastguard Worker Src1 = legalizeToReg(Src1);
1887*03ce13f7SAndroid Build Coastguard Worker switch (Instr->getOp()) {
1888*03ce13f7SAndroid Build Coastguard Worker case InstArithmetic::_num:
1889*03ce13f7SAndroid Build Coastguard Worker llvm_unreachable("Unknown arithmetic operator");
1890*03ce13f7SAndroid Build Coastguard Worker break;
1891*03ce13f7SAndroid Build Coastguard Worker case InstArithmetic::Add: {
1892*03ce13f7SAndroid Build Coastguard Worker Variable *T = makeReg(Ty);
1893*03ce13f7SAndroid Build Coastguard Worker _movp(T, Src0);
1894*03ce13f7SAndroid Build Coastguard Worker _padd(T, Src1);
1895*03ce13f7SAndroid Build Coastguard Worker _movp(Dest, T);
1896*03ce13f7SAndroid Build Coastguard Worker } break;
1897*03ce13f7SAndroid Build Coastguard Worker case InstArithmetic::And: {
1898*03ce13f7SAndroid Build Coastguard Worker Variable *T = makeReg(Ty);
1899*03ce13f7SAndroid Build Coastguard Worker _movp(T, Src0);
1900*03ce13f7SAndroid Build Coastguard Worker _pand(T, Src1);
1901*03ce13f7SAndroid Build Coastguard Worker _movp(Dest, T);
1902*03ce13f7SAndroid Build Coastguard Worker } break;
1903*03ce13f7SAndroid Build Coastguard Worker case InstArithmetic::Or: {
1904*03ce13f7SAndroid Build Coastguard Worker Variable *T = makeReg(Ty);
1905*03ce13f7SAndroid Build Coastguard Worker _movp(T, Src0);
1906*03ce13f7SAndroid Build Coastguard Worker _por(T, Src1);
1907*03ce13f7SAndroid Build Coastguard Worker _movp(Dest, T);
1908*03ce13f7SAndroid Build Coastguard Worker } break;
1909*03ce13f7SAndroid Build Coastguard Worker case InstArithmetic::Xor: {
1910*03ce13f7SAndroid Build Coastguard Worker Variable *T = makeReg(Ty);
1911*03ce13f7SAndroid Build Coastguard Worker _movp(T, Src0);
1912*03ce13f7SAndroid Build Coastguard Worker _pxor(T, Src1);
1913*03ce13f7SAndroid Build Coastguard Worker _movp(Dest, T);
1914*03ce13f7SAndroid Build Coastguard Worker } break;
1915*03ce13f7SAndroid Build Coastguard Worker case InstArithmetic::Sub: {
1916*03ce13f7SAndroid Build Coastguard Worker Variable *T = makeReg(Ty);
1917*03ce13f7SAndroid Build Coastguard Worker _movp(T, Src0);
1918*03ce13f7SAndroid Build Coastguard Worker _psub(T, Src1);
1919*03ce13f7SAndroid Build Coastguard Worker _movp(Dest, T);
1920*03ce13f7SAndroid Build Coastguard Worker } break;
1921*03ce13f7SAndroid Build Coastguard Worker case InstArithmetic::Mul: {
1922*03ce13f7SAndroid Build Coastguard Worker bool TypesAreValidForPmull = Ty == IceType_v4i32 || Ty == IceType_v8i16;
1923*03ce13f7SAndroid Build Coastguard Worker bool InstructionSetIsValidForPmull =
1924*03ce13f7SAndroid Build Coastguard Worker Ty == IceType_v8i16 || InstructionSet >= SSE4_1;
1925*03ce13f7SAndroid Build Coastguard Worker if (TypesAreValidForPmull && InstructionSetIsValidForPmull) {
1926*03ce13f7SAndroid Build Coastguard Worker Variable *T = makeReg(Ty);
1927*03ce13f7SAndroid Build Coastguard Worker _movp(T, Src0);
1928*03ce13f7SAndroid Build Coastguard Worker _pmull(T, Src0 == Src1 ? T : Src1);
1929*03ce13f7SAndroid Build Coastguard Worker _movp(Dest, T);
1930*03ce13f7SAndroid Build Coastguard Worker } else if (Ty == IceType_v4i32) {
1931*03ce13f7SAndroid Build Coastguard Worker // Lowering sequence:
1932*03ce13f7SAndroid Build Coastguard Worker // Note: The mask arguments have index 0 on the left.
1933*03ce13f7SAndroid Build Coastguard Worker //
1934*03ce13f7SAndroid Build Coastguard Worker // movups T1, Src0
1935*03ce13f7SAndroid Build Coastguard Worker // pshufd T2, Src0, {1,0,3,0}
1936*03ce13f7SAndroid Build Coastguard Worker // pshufd T3, Src1, {1,0,3,0}
1937*03ce13f7SAndroid Build Coastguard Worker // # T1 = {Src0[0] * Src1[0], Src0[2] * Src1[2]}
1938*03ce13f7SAndroid Build Coastguard Worker // pmuludq T1, Src1
1939*03ce13f7SAndroid Build Coastguard Worker // # T2 = {Src0[1] * Src1[1], Src0[3] * Src1[3]}
1940*03ce13f7SAndroid Build Coastguard Worker // pmuludq T2, T3
1941*03ce13f7SAndroid Build Coastguard Worker // # T1 = {lo(T1[0]), lo(T1[2]), lo(T2[0]), lo(T2[2])}
1942*03ce13f7SAndroid Build Coastguard Worker // shufps T1, T2, {0,2,0,2}
1943*03ce13f7SAndroid Build Coastguard Worker // pshufd T4, T1, {0,2,1,3}
1944*03ce13f7SAndroid Build Coastguard Worker // movups Dest, T4
1945*03ce13f7SAndroid Build Coastguard Worker
1946*03ce13f7SAndroid Build Coastguard Worker // Mask that directs pshufd to create a vector with entries
1947*03ce13f7SAndroid Build Coastguard Worker // Src[1, 0, 3, 0]
1948*03ce13f7SAndroid Build Coastguard Worker constexpr unsigned Constant1030 = 0x31;
1949*03ce13f7SAndroid Build Coastguard Worker Constant *Mask1030 = Ctx->getConstantInt32(Constant1030);
1950*03ce13f7SAndroid Build Coastguard Worker // Mask that directs shufps to create a vector with entries
1951*03ce13f7SAndroid Build Coastguard Worker // Dest[0, 2], Src[0, 2]
1952*03ce13f7SAndroid Build Coastguard Worker constexpr unsigned Mask0202 = 0x88;
1953*03ce13f7SAndroid Build Coastguard Worker // Mask that directs pshufd to create a vector with entries
1954*03ce13f7SAndroid Build Coastguard Worker // Src[0, 2, 1, 3]
1955*03ce13f7SAndroid Build Coastguard Worker constexpr unsigned Mask0213 = 0xd8;
1956*03ce13f7SAndroid Build Coastguard Worker Variable *T1 = makeReg(IceType_v4i32);
1957*03ce13f7SAndroid Build Coastguard Worker Variable *T2 = makeReg(IceType_v4i32);
1958*03ce13f7SAndroid Build Coastguard Worker Variable *T3 = makeReg(IceType_v4i32);
1959*03ce13f7SAndroid Build Coastguard Worker Variable *T4 = makeReg(IceType_v4i32);
1960*03ce13f7SAndroid Build Coastguard Worker _movp(T1, Src0);
1961*03ce13f7SAndroid Build Coastguard Worker _pshufd(T2, Src0, Mask1030);
1962*03ce13f7SAndroid Build Coastguard Worker _pshufd(T3, Src1, Mask1030);
1963*03ce13f7SAndroid Build Coastguard Worker _pmuludq(T1, Src1);
1964*03ce13f7SAndroid Build Coastguard Worker _pmuludq(T2, T3);
1965*03ce13f7SAndroid Build Coastguard Worker _shufps(T1, T2, Ctx->getConstantInt32(Mask0202));
1966*03ce13f7SAndroid Build Coastguard Worker _pshufd(T4, T1, Ctx->getConstantInt32(Mask0213));
1967*03ce13f7SAndroid Build Coastguard Worker _movp(Dest, T4);
1968*03ce13f7SAndroid Build Coastguard Worker } else if (Ty == IceType_v16i8) {
1969*03ce13f7SAndroid Build Coastguard Worker llvm::report_fatal_error("Scalarized operation was expected");
1970*03ce13f7SAndroid Build Coastguard Worker } else {
1971*03ce13f7SAndroid Build Coastguard Worker llvm::report_fatal_error("Invalid vector multiply type");
1972*03ce13f7SAndroid Build Coastguard Worker }
1973*03ce13f7SAndroid Build Coastguard Worker } break;
1974*03ce13f7SAndroid Build Coastguard Worker case InstArithmetic::Shl: {
1975*03ce13f7SAndroid Build Coastguard Worker assert(llvm::isa<Constant>(Src1) && "Non-constant shift not scalarized");
1976*03ce13f7SAndroid Build Coastguard Worker Variable *T = makeReg(Ty);
1977*03ce13f7SAndroid Build Coastguard Worker _movp(T, Src0);
1978*03ce13f7SAndroid Build Coastguard Worker _psll(T, Src1);
1979*03ce13f7SAndroid Build Coastguard Worker _movp(Dest, T);
1980*03ce13f7SAndroid Build Coastguard Worker } break;
1981*03ce13f7SAndroid Build Coastguard Worker case InstArithmetic::Lshr: {
1982*03ce13f7SAndroid Build Coastguard Worker assert(llvm::isa<Constant>(Src1) && "Non-constant shift not scalarized");
1983*03ce13f7SAndroid Build Coastguard Worker Variable *T = makeReg(Ty);
1984*03ce13f7SAndroid Build Coastguard Worker _movp(T, Src0);
1985*03ce13f7SAndroid Build Coastguard Worker _psrl(T, Src1);
1986*03ce13f7SAndroid Build Coastguard Worker _movp(Dest, T);
1987*03ce13f7SAndroid Build Coastguard Worker } break;
1988*03ce13f7SAndroid Build Coastguard Worker case InstArithmetic::Ashr: {
1989*03ce13f7SAndroid Build Coastguard Worker assert(llvm::isa<Constant>(Src1) && "Non-constant shift not scalarized");
1990*03ce13f7SAndroid Build Coastguard Worker Variable *T = makeReg(Ty);
1991*03ce13f7SAndroid Build Coastguard Worker _movp(T, Src0);
1992*03ce13f7SAndroid Build Coastguard Worker _psra(T, Src1);
1993*03ce13f7SAndroid Build Coastguard Worker _movp(Dest, T);
1994*03ce13f7SAndroid Build Coastguard Worker } break;
1995*03ce13f7SAndroid Build Coastguard Worker case InstArithmetic::Udiv:
1996*03ce13f7SAndroid Build Coastguard Worker case InstArithmetic::Urem:
1997*03ce13f7SAndroid Build Coastguard Worker case InstArithmetic::Sdiv:
1998*03ce13f7SAndroid Build Coastguard Worker case InstArithmetic::Srem:
1999*03ce13f7SAndroid Build Coastguard Worker llvm::report_fatal_error("Scalarized operation was expected");
2000*03ce13f7SAndroid Build Coastguard Worker break;
2001*03ce13f7SAndroid Build Coastguard Worker case InstArithmetic::Fadd: {
2002*03ce13f7SAndroid Build Coastguard Worker Variable *T = makeReg(Ty);
2003*03ce13f7SAndroid Build Coastguard Worker _movp(T, Src0);
2004*03ce13f7SAndroid Build Coastguard Worker _addps(T, Src1);
2005*03ce13f7SAndroid Build Coastguard Worker _movp(Dest, T);
2006*03ce13f7SAndroid Build Coastguard Worker } break;
2007*03ce13f7SAndroid Build Coastguard Worker case InstArithmetic::Fsub: {
2008*03ce13f7SAndroid Build Coastguard Worker Variable *T = makeReg(Ty);
2009*03ce13f7SAndroid Build Coastguard Worker _movp(T, Src0);
2010*03ce13f7SAndroid Build Coastguard Worker _subps(T, Src1);
2011*03ce13f7SAndroid Build Coastguard Worker _movp(Dest, T);
2012*03ce13f7SAndroid Build Coastguard Worker } break;
2013*03ce13f7SAndroid Build Coastguard Worker case InstArithmetic::Fmul: {
2014*03ce13f7SAndroid Build Coastguard Worker Variable *T = makeReg(Ty);
2015*03ce13f7SAndroid Build Coastguard Worker _movp(T, Src0);
2016*03ce13f7SAndroid Build Coastguard Worker _mulps(T, Src0 == Src1 ? T : Src1);
2017*03ce13f7SAndroid Build Coastguard Worker _movp(Dest, T);
2018*03ce13f7SAndroid Build Coastguard Worker } break;
2019*03ce13f7SAndroid Build Coastguard Worker case InstArithmetic::Fdiv: {
2020*03ce13f7SAndroid Build Coastguard Worker Variable *T = makeReg(Ty);
2021*03ce13f7SAndroid Build Coastguard Worker _movp(T, Src0);
2022*03ce13f7SAndroid Build Coastguard Worker _divps(T, Src1);
2023*03ce13f7SAndroid Build Coastguard Worker _movp(Dest, T);
2024*03ce13f7SAndroid Build Coastguard Worker } break;
2025*03ce13f7SAndroid Build Coastguard Worker case InstArithmetic::Frem:
2026*03ce13f7SAndroid Build Coastguard Worker llvm::report_fatal_error("Scalarized operation was expected");
2027*03ce13f7SAndroid Build Coastguard Worker break;
2028*03ce13f7SAndroid Build Coastguard Worker }
2029*03ce13f7SAndroid Build Coastguard Worker return;
2030*03ce13f7SAndroid Build Coastguard Worker }
2031*03ce13f7SAndroid Build Coastguard Worker Variable *T_edx = nullptr;
2032*03ce13f7SAndroid Build Coastguard Worker Variable *T = nullptr;
2033*03ce13f7SAndroid Build Coastguard Worker switch (Instr->getOp()) {
2034*03ce13f7SAndroid Build Coastguard Worker case InstArithmetic::_num:
2035*03ce13f7SAndroid Build Coastguard Worker llvm_unreachable("Unknown arithmetic operator");
2036*03ce13f7SAndroid Build Coastguard Worker break;
2037*03ce13f7SAndroid Build Coastguard Worker case InstArithmetic::Add: {
2038*03ce13f7SAndroid Build Coastguard Worker const bool ValidType = Ty == IceType_i32;
2039*03ce13f7SAndroid Build Coastguard Worker auto *Const = llvm::dyn_cast<Constant>(Instr->getSrc(1));
2040*03ce13f7SAndroid Build Coastguard Worker const bool ValidKind =
2041*03ce13f7SAndroid Build Coastguard Worker Const != nullptr && (llvm::isa<ConstantInteger32>(Const) ||
2042*03ce13f7SAndroid Build Coastguard Worker llvm::isa<ConstantRelocatable>(Const));
2043*03ce13f7SAndroid Build Coastguard Worker if (getFlags().getAggressiveLea() && ValidType && ValidKind) {
2044*03ce13f7SAndroid Build Coastguard Worker auto *Var = legalizeToReg(Src0);
2045*03ce13f7SAndroid Build Coastguard Worker auto *Mem = X86OperandMem::create(Func, IceType_void, Var, Const);
2046*03ce13f7SAndroid Build Coastguard Worker T = makeReg(Ty);
2047*03ce13f7SAndroid Build Coastguard Worker _lea(T, Mem);
2048*03ce13f7SAndroid Build Coastguard Worker _mov(Dest, T);
2049*03ce13f7SAndroid Build Coastguard Worker break;
2050*03ce13f7SAndroid Build Coastguard Worker }
2051*03ce13f7SAndroid Build Coastguard Worker _mov(T, Src0);
2052*03ce13f7SAndroid Build Coastguard Worker _add(T, Src1);
2053*03ce13f7SAndroid Build Coastguard Worker _mov(Dest, T);
2054*03ce13f7SAndroid Build Coastguard Worker } break;
2055*03ce13f7SAndroid Build Coastguard Worker case InstArithmetic::And:
2056*03ce13f7SAndroid Build Coastguard Worker _mov(T, Src0);
2057*03ce13f7SAndroid Build Coastguard Worker _and(T, Src1);
2058*03ce13f7SAndroid Build Coastguard Worker _mov(Dest, T);
2059*03ce13f7SAndroid Build Coastguard Worker break;
2060*03ce13f7SAndroid Build Coastguard Worker case InstArithmetic::Or:
2061*03ce13f7SAndroid Build Coastguard Worker _mov(T, Src0);
2062*03ce13f7SAndroid Build Coastguard Worker _or(T, Src1);
2063*03ce13f7SAndroid Build Coastguard Worker _mov(Dest, T);
2064*03ce13f7SAndroid Build Coastguard Worker break;
2065*03ce13f7SAndroid Build Coastguard Worker case InstArithmetic::Xor:
2066*03ce13f7SAndroid Build Coastguard Worker _mov(T, Src0);
2067*03ce13f7SAndroid Build Coastguard Worker _xor(T, Src1);
2068*03ce13f7SAndroid Build Coastguard Worker _mov(Dest, T);
2069*03ce13f7SAndroid Build Coastguard Worker break;
2070*03ce13f7SAndroid Build Coastguard Worker case InstArithmetic::Sub:
2071*03ce13f7SAndroid Build Coastguard Worker _mov(T, Src0);
2072*03ce13f7SAndroid Build Coastguard Worker _sub(T, Src1);
2073*03ce13f7SAndroid Build Coastguard Worker _mov(Dest, T);
2074*03ce13f7SAndroid Build Coastguard Worker break;
2075*03ce13f7SAndroid Build Coastguard Worker case InstArithmetic::Mul:
2076*03ce13f7SAndroid Build Coastguard Worker if (auto *C = llvm::dyn_cast<ConstantInteger32>(Src1)) {
2077*03ce13f7SAndroid Build Coastguard Worker if (optimizeScalarMul(Dest, Src0, C->getValue()))
2078*03ce13f7SAndroid Build Coastguard Worker return;
2079*03ce13f7SAndroid Build Coastguard Worker }
2080*03ce13f7SAndroid Build Coastguard Worker // The 8-bit version of imul only allows the form "imul r/m8" where T must
2081*03ce13f7SAndroid Build Coastguard Worker // be in al.
2082*03ce13f7SAndroid Build Coastguard Worker if (isByteSizedArithType(Ty)) {
2083*03ce13f7SAndroid Build Coastguard Worker _mov(T, Src0, RegX8632::Reg_al);
2084*03ce13f7SAndroid Build Coastguard Worker Src1 = legalize(Src1, Legal_Reg | Legal_Mem);
2085*03ce13f7SAndroid Build Coastguard Worker _imul(T, Src0 == Src1 ? T : Src1);
2086*03ce13f7SAndroid Build Coastguard Worker _mov(Dest, T);
2087*03ce13f7SAndroid Build Coastguard Worker } else if (auto *ImmConst = llvm::dyn_cast<ConstantInteger32>(Src1)) {
2088*03ce13f7SAndroid Build Coastguard Worker T = makeReg(Ty);
2089*03ce13f7SAndroid Build Coastguard Worker Src0 = legalize(Src0, Legal_Reg | Legal_Mem);
2090*03ce13f7SAndroid Build Coastguard Worker _imul_imm(T, Src0, ImmConst);
2091*03ce13f7SAndroid Build Coastguard Worker _mov(Dest, T);
2092*03ce13f7SAndroid Build Coastguard Worker } else {
2093*03ce13f7SAndroid Build Coastguard Worker _mov(T, Src0);
2094*03ce13f7SAndroid Build Coastguard Worker // No need to legalize Src1 to Reg | Mem because the Imm case is handled
2095*03ce13f7SAndroid Build Coastguard Worker // already by the ConstantInteger32 case above.
2096*03ce13f7SAndroid Build Coastguard Worker _imul(T, Src0 == Src1 ? T : Src1);
2097*03ce13f7SAndroid Build Coastguard Worker _mov(Dest, T);
2098*03ce13f7SAndroid Build Coastguard Worker }
2099*03ce13f7SAndroid Build Coastguard Worker break;
2100*03ce13f7SAndroid Build Coastguard Worker case InstArithmetic::Shl:
2101*03ce13f7SAndroid Build Coastguard Worker _mov(T, Src0);
2102*03ce13f7SAndroid Build Coastguard Worker if (!llvm::isa<ConstantInteger32>(Src1) &&
2103*03ce13f7SAndroid Build Coastguard Worker !llvm::isa<ConstantInteger64>(Src1))
2104*03ce13f7SAndroid Build Coastguard Worker Src1 = copyToReg8(Src1, RegX8632::Reg_cl);
2105*03ce13f7SAndroid Build Coastguard Worker _shl(T, Src1);
2106*03ce13f7SAndroid Build Coastguard Worker _mov(Dest, T);
2107*03ce13f7SAndroid Build Coastguard Worker break;
2108*03ce13f7SAndroid Build Coastguard Worker case InstArithmetic::Lshr:
2109*03ce13f7SAndroid Build Coastguard Worker _mov(T, Src0);
2110*03ce13f7SAndroid Build Coastguard Worker if (!llvm::isa<ConstantInteger32>(Src1) &&
2111*03ce13f7SAndroid Build Coastguard Worker !llvm::isa<ConstantInteger64>(Src1))
2112*03ce13f7SAndroid Build Coastguard Worker Src1 = copyToReg8(Src1, RegX8632::Reg_cl);
2113*03ce13f7SAndroid Build Coastguard Worker _shr(T, Src1);
2114*03ce13f7SAndroid Build Coastguard Worker _mov(Dest, T);
2115*03ce13f7SAndroid Build Coastguard Worker break;
2116*03ce13f7SAndroid Build Coastguard Worker case InstArithmetic::Ashr:
2117*03ce13f7SAndroid Build Coastguard Worker _mov(T, Src0);
2118*03ce13f7SAndroid Build Coastguard Worker if (!llvm::isa<ConstantInteger32>(Src1) &&
2119*03ce13f7SAndroid Build Coastguard Worker !llvm::isa<ConstantInteger64>(Src1))
2120*03ce13f7SAndroid Build Coastguard Worker Src1 = copyToReg8(Src1, RegX8632::Reg_cl);
2121*03ce13f7SAndroid Build Coastguard Worker _sar(T, Src1);
2122*03ce13f7SAndroid Build Coastguard Worker _mov(Dest, T);
2123*03ce13f7SAndroid Build Coastguard Worker break;
2124*03ce13f7SAndroid Build Coastguard Worker case InstArithmetic::Udiv: {
2125*03ce13f7SAndroid Build Coastguard Worker // div and idiv are the few arithmetic operators that do not allow
2126*03ce13f7SAndroid Build Coastguard Worker // immediates as the operand.
2127*03ce13f7SAndroid Build Coastguard Worker Src1 = legalize(Src1, Legal_Reg | Legal_Mem);
2128*03ce13f7SAndroid Build Coastguard Worker RegNumT Eax;
2129*03ce13f7SAndroid Build Coastguard Worker RegNumT Edx;
2130*03ce13f7SAndroid Build Coastguard Worker switch (Ty) {
2131*03ce13f7SAndroid Build Coastguard Worker default:
2132*03ce13f7SAndroid Build Coastguard Worker llvm::report_fatal_error("Bad type for udiv");
2133*03ce13f7SAndroid Build Coastguard Worker case IceType_i32:
2134*03ce13f7SAndroid Build Coastguard Worker Eax = RegX8632::Reg_eax;
2135*03ce13f7SAndroid Build Coastguard Worker Edx = RegX8632::Reg_edx;
2136*03ce13f7SAndroid Build Coastguard Worker break;
2137*03ce13f7SAndroid Build Coastguard Worker case IceType_i16:
2138*03ce13f7SAndroid Build Coastguard Worker Eax = RegX8632::Reg_ax;
2139*03ce13f7SAndroid Build Coastguard Worker Edx = RegX8632::Reg_dx;
2140*03ce13f7SAndroid Build Coastguard Worker break;
2141*03ce13f7SAndroid Build Coastguard Worker case IceType_i8:
2142*03ce13f7SAndroid Build Coastguard Worker Eax = RegX8632::Reg_al;
2143*03ce13f7SAndroid Build Coastguard Worker Edx = RegX8632::Reg_ah;
2144*03ce13f7SAndroid Build Coastguard Worker break;
2145*03ce13f7SAndroid Build Coastguard Worker }
2146*03ce13f7SAndroid Build Coastguard Worker T_edx = makeReg(Ty, Edx);
2147*03ce13f7SAndroid Build Coastguard Worker _mov(T, Src0, Eax);
2148*03ce13f7SAndroid Build Coastguard Worker _mov(T_edx, Ctx->getConstantZero(Ty));
2149*03ce13f7SAndroid Build Coastguard Worker _div(T_edx, Src1, T);
2150*03ce13f7SAndroid Build Coastguard Worker _redefined(Context.insert<InstFakeDef>(T, T_edx));
2151*03ce13f7SAndroid Build Coastguard Worker _mov(Dest, T);
2152*03ce13f7SAndroid Build Coastguard Worker } break;
2153*03ce13f7SAndroid Build Coastguard Worker case InstArithmetic::Sdiv:
2154*03ce13f7SAndroid Build Coastguard Worker // TODO(stichnot): Enable this after doing better performance and cross
2155*03ce13f7SAndroid Build Coastguard Worker // testing.
2156*03ce13f7SAndroid Build Coastguard Worker if (false && Func->getOptLevel() >= Opt_1) {
2157*03ce13f7SAndroid Build Coastguard Worker // Optimize division by constant power of 2, but not for Om1 or O0, just
2158*03ce13f7SAndroid Build Coastguard Worker // to keep things simple there.
2159*03ce13f7SAndroid Build Coastguard Worker if (auto *C = llvm::dyn_cast<ConstantInteger32>(Src1)) {
2160*03ce13f7SAndroid Build Coastguard Worker const int32_t Divisor = C->getValue();
2161*03ce13f7SAndroid Build Coastguard Worker const uint32_t UDivisor = Divisor;
2162*03ce13f7SAndroid Build Coastguard Worker if (Divisor > 0 && llvm::isPowerOf2_32(UDivisor)) {
2163*03ce13f7SAndroid Build Coastguard Worker uint32_t LogDiv = llvm::Log2_32(UDivisor);
2164*03ce13f7SAndroid Build Coastguard Worker // LLVM does the following for dest=src/(1<<log):
2165*03ce13f7SAndroid Build Coastguard Worker // t=src
2166*03ce13f7SAndroid Build Coastguard Worker // sar t,typewidth-1 // -1 if src is negative, 0 if not
2167*03ce13f7SAndroid Build Coastguard Worker // shr t,typewidth-log
2168*03ce13f7SAndroid Build Coastguard Worker // add t,src
2169*03ce13f7SAndroid Build Coastguard Worker // sar t,log
2170*03ce13f7SAndroid Build Coastguard Worker // dest=t
2171*03ce13f7SAndroid Build Coastguard Worker uint32_t TypeWidth = X86_CHAR_BIT * typeWidthInBytes(Ty);
2172*03ce13f7SAndroid Build Coastguard Worker _mov(T, Src0);
2173*03ce13f7SAndroid Build Coastguard Worker // If for some reason we are dividing by 1, just treat it like an
2174*03ce13f7SAndroid Build Coastguard Worker // assignment.
2175*03ce13f7SAndroid Build Coastguard Worker if (LogDiv > 0) {
2176*03ce13f7SAndroid Build Coastguard Worker // The initial sar is unnecessary when dividing by 2.
2177*03ce13f7SAndroid Build Coastguard Worker if (LogDiv > 1)
2178*03ce13f7SAndroid Build Coastguard Worker _sar(T, Ctx->getConstantInt(Ty, TypeWidth - 1));
2179*03ce13f7SAndroid Build Coastguard Worker _shr(T, Ctx->getConstantInt(Ty, TypeWidth - LogDiv));
2180*03ce13f7SAndroid Build Coastguard Worker _add(T, Src0);
2181*03ce13f7SAndroid Build Coastguard Worker _sar(T, Ctx->getConstantInt(Ty, LogDiv));
2182*03ce13f7SAndroid Build Coastguard Worker }
2183*03ce13f7SAndroid Build Coastguard Worker _mov(Dest, T);
2184*03ce13f7SAndroid Build Coastguard Worker return;
2185*03ce13f7SAndroid Build Coastguard Worker }
2186*03ce13f7SAndroid Build Coastguard Worker }
2187*03ce13f7SAndroid Build Coastguard Worker }
2188*03ce13f7SAndroid Build Coastguard Worker Src1 = legalize(Src1, Legal_Reg | Legal_Mem);
2189*03ce13f7SAndroid Build Coastguard Worker switch (Ty) {
2190*03ce13f7SAndroid Build Coastguard Worker default:
2191*03ce13f7SAndroid Build Coastguard Worker llvm::report_fatal_error("Bad type for sdiv");
2192*03ce13f7SAndroid Build Coastguard Worker case IceType_i32:
2193*03ce13f7SAndroid Build Coastguard Worker T_edx = makeReg(Ty, RegX8632::Reg_edx);
2194*03ce13f7SAndroid Build Coastguard Worker _mov(T, Src0, RegX8632::Reg_eax);
2195*03ce13f7SAndroid Build Coastguard Worker break;
2196*03ce13f7SAndroid Build Coastguard Worker case IceType_i16:
2197*03ce13f7SAndroid Build Coastguard Worker T_edx = makeReg(Ty, RegX8632::Reg_dx);
2198*03ce13f7SAndroid Build Coastguard Worker _mov(T, Src0, RegX8632::Reg_ax);
2199*03ce13f7SAndroid Build Coastguard Worker break;
2200*03ce13f7SAndroid Build Coastguard Worker case IceType_i8:
2201*03ce13f7SAndroid Build Coastguard Worker T_edx = makeReg(IceType_i16, RegX8632::Reg_ax);
2202*03ce13f7SAndroid Build Coastguard Worker _mov(T, Src0, RegX8632::Reg_al);
2203*03ce13f7SAndroid Build Coastguard Worker break;
2204*03ce13f7SAndroid Build Coastguard Worker }
2205*03ce13f7SAndroid Build Coastguard Worker _cbwdq(T_edx, T);
2206*03ce13f7SAndroid Build Coastguard Worker _idiv(T_edx, Src1, T);
2207*03ce13f7SAndroid Build Coastguard Worker _redefined(Context.insert<InstFakeDef>(T, T_edx));
2208*03ce13f7SAndroid Build Coastguard Worker _mov(Dest, T);
2209*03ce13f7SAndroid Build Coastguard Worker break;
2210*03ce13f7SAndroid Build Coastguard Worker case InstArithmetic::Urem: {
2211*03ce13f7SAndroid Build Coastguard Worker Src1 = legalize(Src1, Legal_Reg | Legal_Mem);
2212*03ce13f7SAndroid Build Coastguard Worker RegNumT Eax;
2213*03ce13f7SAndroid Build Coastguard Worker RegNumT Edx;
2214*03ce13f7SAndroid Build Coastguard Worker switch (Ty) {
2215*03ce13f7SAndroid Build Coastguard Worker default:
2216*03ce13f7SAndroid Build Coastguard Worker llvm::report_fatal_error("Bad type for urem");
2217*03ce13f7SAndroid Build Coastguard Worker case IceType_i32:
2218*03ce13f7SAndroid Build Coastguard Worker Eax = RegX8632::Reg_eax;
2219*03ce13f7SAndroid Build Coastguard Worker Edx = RegX8632::Reg_edx;
2220*03ce13f7SAndroid Build Coastguard Worker break;
2221*03ce13f7SAndroid Build Coastguard Worker case IceType_i16:
2222*03ce13f7SAndroid Build Coastguard Worker Eax = RegX8632::Reg_ax;
2223*03ce13f7SAndroid Build Coastguard Worker Edx = RegX8632::Reg_dx;
2224*03ce13f7SAndroid Build Coastguard Worker break;
2225*03ce13f7SAndroid Build Coastguard Worker case IceType_i8:
2226*03ce13f7SAndroid Build Coastguard Worker Eax = RegX8632::Reg_al;
2227*03ce13f7SAndroid Build Coastguard Worker Edx = RegX8632::Reg_ah;
2228*03ce13f7SAndroid Build Coastguard Worker break;
2229*03ce13f7SAndroid Build Coastguard Worker }
2230*03ce13f7SAndroid Build Coastguard Worker T_edx = makeReg(Ty, Edx);
2231*03ce13f7SAndroid Build Coastguard Worker _mov(T_edx, Ctx->getConstantZero(Ty));
2232*03ce13f7SAndroid Build Coastguard Worker _mov(T, Src0, Eax);
2233*03ce13f7SAndroid Build Coastguard Worker _div(T, Src1, T_edx);
2234*03ce13f7SAndroid Build Coastguard Worker _redefined(Context.insert<InstFakeDef>(T_edx, T));
2235*03ce13f7SAndroid Build Coastguard Worker if (Ty == IceType_i8) {
2236*03ce13f7SAndroid Build Coastguard Worker // Register ah must be moved into one of {al,bl,cl,dl} before it can be
2237*03ce13f7SAndroid Build Coastguard Worker // moved into a general 8-bit register.
2238*03ce13f7SAndroid Build Coastguard Worker auto *T_AhRcvr = makeReg(Ty);
2239*03ce13f7SAndroid Build Coastguard Worker T_AhRcvr->setRegClass(RCX86_IsAhRcvr);
2240*03ce13f7SAndroid Build Coastguard Worker _mov(T_AhRcvr, T_edx);
2241*03ce13f7SAndroid Build Coastguard Worker T_edx = T_AhRcvr;
2242*03ce13f7SAndroid Build Coastguard Worker }
2243*03ce13f7SAndroid Build Coastguard Worker _mov(Dest, T_edx);
2244*03ce13f7SAndroid Build Coastguard Worker } break;
2245*03ce13f7SAndroid Build Coastguard Worker case InstArithmetic::Srem: {
2246*03ce13f7SAndroid Build Coastguard Worker // TODO(stichnot): Enable this after doing better performance and cross
2247*03ce13f7SAndroid Build Coastguard Worker // testing.
2248*03ce13f7SAndroid Build Coastguard Worker if (false && Func->getOptLevel() >= Opt_1) {
2249*03ce13f7SAndroid Build Coastguard Worker // Optimize mod by constant power of 2, but not for Om1 or O0, just to
2250*03ce13f7SAndroid Build Coastguard Worker // keep things simple there.
2251*03ce13f7SAndroid Build Coastguard Worker if (auto *C = llvm::dyn_cast<ConstantInteger32>(Src1)) {
2252*03ce13f7SAndroid Build Coastguard Worker const int32_t Divisor = C->getValue();
2253*03ce13f7SAndroid Build Coastguard Worker const uint32_t UDivisor = Divisor;
2254*03ce13f7SAndroid Build Coastguard Worker if (Divisor > 0 && llvm::isPowerOf2_32(UDivisor)) {
2255*03ce13f7SAndroid Build Coastguard Worker uint32_t LogDiv = llvm::Log2_32(UDivisor);
2256*03ce13f7SAndroid Build Coastguard Worker // LLVM does the following for dest=src%(1<<log):
2257*03ce13f7SAndroid Build Coastguard Worker // t=src
2258*03ce13f7SAndroid Build Coastguard Worker // sar t,typewidth-1 // -1 if src is negative, 0 if not
2259*03ce13f7SAndroid Build Coastguard Worker // shr t,typewidth-log
2260*03ce13f7SAndroid Build Coastguard Worker // add t,src
2261*03ce13f7SAndroid Build Coastguard Worker // and t, -(1<<log)
2262*03ce13f7SAndroid Build Coastguard Worker // sub t,src
2263*03ce13f7SAndroid Build Coastguard Worker // neg t
2264*03ce13f7SAndroid Build Coastguard Worker // dest=t
2265*03ce13f7SAndroid Build Coastguard Worker uint32_t TypeWidth = X86_CHAR_BIT * typeWidthInBytes(Ty);
2266*03ce13f7SAndroid Build Coastguard Worker // If for some reason we are dividing by 1, just assign 0.
2267*03ce13f7SAndroid Build Coastguard Worker if (LogDiv == 0) {
2268*03ce13f7SAndroid Build Coastguard Worker _mov(Dest, Ctx->getConstantZero(Ty));
2269*03ce13f7SAndroid Build Coastguard Worker return;
2270*03ce13f7SAndroid Build Coastguard Worker }
2271*03ce13f7SAndroid Build Coastguard Worker _mov(T, Src0);
2272*03ce13f7SAndroid Build Coastguard Worker // The initial sar is unnecessary when dividing by 2.
2273*03ce13f7SAndroid Build Coastguard Worker if (LogDiv > 1)
2274*03ce13f7SAndroid Build Coastguard Worker _sar(T, Ctx->getConstantInt(Ty, TypeWidth - 1));
2275*03ce13f7SAndroid Build Coastguard Worker _shr(T, Ctx->getConstantInt(Ty, TypeWidth - LogDiv));
2276*03ce13f7SAndroid Build Coastguard Worker _add(T, Src0);
2277*03ce13f7SAndroid Build Coastguard Worker _and(T, Ctx->getConstantInt(Ty, -(1 << LogDiv)));
2278*03ce13f7SAndroid Build Coastguard Worker _sub(T, Src0);
2279*03ce13f7SAndroid Build Coastguard Worker _neg(T);
2280*03ce13f7SAndroid Build Coastguard Worker _mov(Dest, T);
2281*03ce13f7SAndroid Build Coastguard Worker return;
2282*03ce13f7SAndroid Build Coastguard Worker }
2283*03ce13f7SAndroid Build Coastguard Worker }
2284*03ce13f7SAndroid Build Coastguard Worker }
2285*03ce13f7SAndroid Build Coastguard Worker Src1 = legalize(Src1, Legal_Reg | Legal_Mem);
2286*03ce13f7SAndroid Build Coastguard Worker RegNumT Eax;
2287*03ce13f7SAndroid Build Coastguard Worker RegNumT Edx;
2288*03ce13f7SAndroid Build Coastguard Worker switch (Ty) {
2289*03ce13f7SAndroid Build Coastguard Worker default:
2290*03ce13f7SAndroid Build Coastguard Worker llvm::report_fatal_error("Bad type for srem");
2291*03ce13f7SAndroid Build Coastguard Worker case IceType_i32:
2292*03ce13f7SAndroid Build Coastguard Worker Eax = RegX8632::Reg_eax;
2293*03ce13f7SAndroid Build Coastguard Worker Edx = RegX8632::Reg_edx;
2294*03ce13f7SAndroid Build Coastguard Worker break;
2295*03ce13f7SAndroid Build Coastguard Worker case IceType_i16:
2296*03ce13f7SAndroid Build Coastguard Worker Eax = RegX8632::Reg_ax;
2297*03ce13f7SAndroid Build Coastguard Worker Edx = RegX8632::Reg_dx;
2298*03ce13f7SAndroid Build Coastguard Worker break;
2299*03ce13f7SAndroid Build Coastguard Worker case IceType_i8:
2300*03ce13f7SAndroid Build Coastguard Worker Eax = RegX8632::Reg_al;
2301*03ce13f7SAndroid Build Coastguard Worker Edx = RegX8632::Reg_ah;
2302*03ce13f7SAndroid Build Coastguard Worker break;
2303*03ce13f7SAndroid Build Coastguard Worker }
2304*03ce13f7SAndroid Build Coastguard Worker T_edx = makeReg(Ty, Edx);
2305*03ce13f7SAndroid Build Coastguard Worker _mov(T, Src0, Eax);
2306*03ce13f7SAndroid Build Coastguard Worker _cbwdq(T_edx, T);
2307*03ce13f7SAndroid Build Coastguard Worker _idiv(T, Src1, T_edx);
2308*03ce13f7SAndroid Build Coastguard Worker _redefined(Context.insert<InstFakeDef>(T_edx, T));
2309*03ce13f7SAndroid Build Coastguard Worker if (Ty == IceType_i8) {
2310*03ce13f7SAndroid Build Coastguard Worker // Register ah must be moved into one of {al,bl,cl,dl} before it can be
2311*03ce13f7SAndroid Build Coastguard Worker // moved into a general 8-bit register.
2312*03ce13f7SAndroid Build Coastguard Worker auto *T_AhRcvr = makeReg(Ty);
2313*03ce13f7SAndroid Build Coastguard Worker T_AhRcvr->setRegClass(RCX86_IsAhRcvr);
2314*03ce13f7SAndroid Build Coastguard Worker _mov(T_AhRcvr, T_edx);
2315*03ce13f7SAndroid Build Coastguard Worker T_edx = T_AhRcvr;
2316*03ce13f7SAndroid Build Coastguard Worker }
2317*03ce13f7SAndroid Build Coastguard Worker _mov(Dest, T_edx);
2318*03ce13f7SAndroid Build Coastguard Worker } break;
2319*03ce13f7SAndroid Build Coastguard Worker case InstArithmetic::Fadd:
2320*03ce13f7SAndroid Build Coastguard Worker _mov(T, Src0);
2321*03ce13f7SAndroid Build Coastguard Worker _addss(T, Src1);
2322*03ce13f7SAndroid Build Coastguard Worker _mov(Dest, T);
2323*03ce13f7SAndroid Build Coastguard Worker break;
2324*03ce13f7SAndroid Build Coastguard Worker case InstArithmetic::Fsub:
2325*03ce13f7SAndroid Build Coastguard Worker _mov(T, Src0);
2326*03ce13f7SAndroid Build Coastguard Worker _subss(T, Src1);
2327*03ce13f7SAndroid Build Coastguard Worker _mov(Dest, T);
2328*03ce13f7SAndroid Build Coastguard Worker break;
2329*03ce13f7SAndroid Build Coastguard Worker case InstArithmetic::Fmul:
2330*03ce13f7SAndroid Build Coastguard Worker _mov(T, Src0);
2331*03ce13f7SAndroid Build Coastguard Worker _mulss(T, Src0 == Src1 ? T : Src1);
2332*03ce13f7SAndroid Build Coastguard Worker _mov(Dest, T);
2333*03ce13f7SAndroid Build Coastguard Worker break;
2334*03ce13f7SAndroid Build Coastguard Worker case InstArithmetic::Fdiv:
2335*03ce13f7SAndroid Build Coastguard Worker _mov(T, Src0);
2336*03ce13f7SAndroid Build Coastguard Worker _divss(T, Src1);
2337*03ce13f7SAndroid Build Coastguard Worker _mov(Dest, T);
2338*03ce13f7SAndroid Build Coastguard Worker break;
2339*03ce13f7SAndroid Build Coastguard Worker case InstArithmetic::Frem:
2340*03ce13f7SAndroid Build Coastguard Worker llvm::report_fatal_error("Helper call was expected");
2341*03ce13f7SAndroid Build Coastguard Worker break;
2342*03ce13f7SAndroid Build Coastguard Worker }
2343*03ce13f7SAndroid Build Coastguard Worker }
2344*03ce13f7SAndroid Build Coastguard Worker
lowerAssign(const InstAssign * Instr)2345*03ce13f7SAndroid Build Coastguard Worker void TargetX8632::lowerAssign(const InstAssign *Instr) {
2346*03ce13f7SAndroid Build Coastguard Worker Variable *Dest = Instr->getDest();
2347*03ce13f7SAndroid Build Coastguard Worker if (Dest->isRematerializable()) {
2348*03ce13f7SAndroid Build Coastguard Worker Context.insert<InstFakeDef>(Dest);
2349*03ce13f7SAndroid Build Coastguard Worker return;
2350*03ce13f7SAndroid Build Coastguard Worker }
2351*03ce13f7SAndroid Build Coastguard Worker Operand *Src = Instr->getSrc(0);
2352*03ce13f7SAndroid Build Coastguard Worker assert(Dest->getType() == Src->getType());
2353*03ce13f7SAndroid Build Coastguard Worker lowerMove(Dest, Src, false);
2354*03ce13f7SAndroid Build Coastguard Worker }
2355*03ce13f7SAndroid Build Coastguard Worker
lowerBr(const InstBr * Br)2356*03ce13f7SAndroid Build Coastguard Worker void TargetX8632::lowerBr(const InstBr *Br) {
2357*03ce13f7SAndroid Build Coastguard Worker if (Br->isUnconditional()) {
2358*03ce13f7SAndroid Build Coastguard Worker _br(Br->getTargetUnconditional());
2359*03ce13f7SAndroid Build Coastguard Worker return;
2360*03ce13f7SAndroid Build Coastguard Worker }
2361*03ce13f7SAndroid Build Coastguard Worker Operand *Cond = Br->getCondition();
2362*03ce13f7SAndroid Build Coastguard Worker
2363*03ce13f7SAndroid Build Coastguard Worker // Handle folding opportunities.
2364*03ce13f7SAndroid Build Coastguard Worker if (const Inst *Producer = FoldingInfo.getProducerFor(Cond)) {
2365*03ce13f7SAndroid Build Coastguard Worker assert(Producer->isDeleted());
2366*03ce13f7SAndroid Build Coastguard Worker switch (BoolFolding::getProducerKind(Producer)) {
2367*03ce13f7SAndroid Build Coastguard Worker default:
2368*03ce13f7SAndroid Build Coastguard Worker break;
2369*03ce13f7SAndroid Build Coastguard Worker case BoolFolding::PK_Icmp32:
2370*03ce13f7SAndroid Build Coastguard Worker case BoolFolding::PK_Icmp64: {
2371*03ce13f7SAndroid Build Coastguard Worker lowerIcmpAndConsumer(llvm::cast<InstIcmp>(Producer), Br);
2372*03ce13f7SAndroid Build Coastguard Worker return;
2373*03ce13f7SAndroid Build Coastguard Worker }
2374*03ce13f7SAndroid Build Coastguard Worker case BoolFolding::PK_Fcmp: {
2375*03ce13f7SAndroid Build Coastguard Worker lowerFcmpAndConsumer(llvm::cast<InstFcmp>(Producer), Br);
2376*03ce13f7SAndroid Build Coastguard Worker return;
2377*03ce13f7SAndroid Build Coastguard Worker }
2378*03ce13f7SAndroid Build Coastguard Worker case BoolFolding::PK_Arith: {
2379*03ce13f7SAndroid Build Coastguard Worker lowerArithAndConsumer(llvm::cast<InstArithmetic>(Producer), Br);
2380*03ce13f7SAndroid Build Coastguard Worker return;
2381*03ce13f7SAndroid Build Coastguard Worker }
2382*03ce13f7SAndroid Build Coastguard Worker }
2383*03ce13f7SAndroid Build Coastguard Worker }
2384*03ce13f7SAndroid Build Coastguard Worker Operand *Src0 = legalize(Cond, Legal_Reg | Legal_Mem);
2385*03ce13f7SAndroid Build Coastguard Worker Constant *Zero = Ctx->getConstantZero(IceType_i32);
2386*03ce13f7SAndroid Build Coastguard Worker _cmp(Src0, Zero);
2387*03ce13f7SAndroid Build Coastguard Worker _br(CondX86::Br_ne, Br->getTargetTrue(), Br->getTargetFalse());
2388*03ce13f7SAndroid Build Coastguard Worker }
2389*03ce13f7SAndroid Build Coastguard Worker
2390*03ce13f7SAndroid Build Coastguard Worker // constexprMax returns a (constexpr) max(S0, S1), and it is used for defining
2391*03ce13f7SAndroid Build Coastguard Worker // OperandList in lowerCall. std::max() is supposed to work, but it doesn't.
constexprMax(SizeT S0,SizeT S1)2392*03ce13f7SAndroid Build Coastguard Worker inline constexpr SizeT constexprMax(SizeT S0, SizeT S1) {
2393*03ce13f7SAndroid Build Coastguard Worker return S0 < S1 ? S1 : S0;
2394*03ce13f7SAndroid Build Coastguard Worker }
2395*03ce13f7SAndroid Build Coastguard Worker
lowerCall(const InstCall * Instr)2396*03ce13f7SAndroid Build Coastguard Worker void TargetX8632::lowerCall(const InstCall *Instr) {
2397*03ce13f7SAndroid Build Coastguard Worker // System V x86-32 calling convention lowering:
2398*03ce13f7SAndroid Build Coastguard Worker //
2399*03ce13f7SAndroid Build Coastguard Worker // * At the point before the call, the stack must be aligned to 16 bytes.
2400*03ce13f7SAndroid Build Coastguard Worker //
2401*03ce13f7SAndroid Build Coastguard Worker // * Non-register arguments are pushed onto the stack in right-to-left order,
2402*03ce13f7SAndroid Build Coastguard Worker // such that the left-most argument ends up on the top of the stack at the
2403*03ce13f7SAndroid Build Coastguard Worker // lowest memory address.
2404*03ce13f7SAndroid Build Coastguard Worker //
2405*03ce13f7SAndroid Build Coastguard Worker // * Stack arguments of vector type are aligned to start at the next highest
2406*03ce13f7SAndroid Build Coastguard Worker // multiple of 16 bytes. Other stack arguments are aligned to the next word
2407*03ce13f7SAndroid Build Coastguard Worker // size boundary (4 or 8 bytes, respectively).
2408*03ce13f7SAndroid Build Coastguard Worker //
2409*03ce13f7SAndroid Build Coastguard Worker // This is compatible with the Microsoft x86-32 'cdecl' calling convention,
2410*03ce13f7SAndroid Build Coastguard Worker // which doesn't have a 16-byte stack alignment requirement.
2411*03ce13f7SAndroid Build Coastguard Worker
2412*03ce13f7SAndroid Build Coastguard Worker RequiredStackAlignment =
2413*03ce13f7SAndroid Build Coastguard Worker std::max<size_t>(RequiredStackAlignment, X86_STACK_ALIGNMENT_BYTES);
2414*03ce13f7SAndroid Build Coastguard Worker
2415*03ce13f7SAndroid Build Coastguard Worker constexpr SizeT MaxOperands =
2416*03ce13f7SAndroid Build Coastguard Worker constexprMax(RegX8632::X86_MAX_XMM_ARGS, RegX8632::X86_MAX_GPR_ARGS);
2417*03ce13f7SAndroid Build Coastguard Worker using OperandList = llvm::SmallVector<Operand *, MaxOperands>;
2418*03ce13f7SAndroid Build Coastguard Worker
2419*03ce13f7SAndroid Build Coastguard Worker OperandList XmmArgs;
2420*03ce13f7SAndroid Build Coastguard Worker llvm::SmallVector<SizeT, MaxOperands> XmmArgIndices;
2421*03ce13f7SAndroid Build Coastguard Worker CfgVector<std::pair<const Type, Operand *>> GprArgs;
2422*03ce13f7SAndroid Build Coastguard Worker CfgVector<SizeT> GprArgIndices;
2423*03ce13f7SAndroid Build Coastguard Worker OperandList StackArgs, StackArgLocations;
2424*03ce13f7SAndroid Build Coastguard Worker uint32_t ParameterAreaSizeBytes = 0;
2425*03ce13f7SAndroid Build Coastguard Worker
2426*03ce13f7SAndroid Build Coastguard Worker // Classify each argument operand according to the location where the argument
2427*03ce13f7SAndroid Build Coastguard Worker // is passed.
2428*03ce13f7SAndroid Build Coastguard Worker for (SizeT i = 0, NumArgs = Instr->getNumArgs(); i < NumArgs; ++i) {
2429*03ce13f7SAndroid Build Coastguard Worker Operand *Arg = Instr->getArg(i);
2430*03ce13f7SAndroid Build Coastguard Worker const Type Ty = Arg->getType();
2431*03ce13f7SAndroid Build Coastguard Worker // The PNaCl ABI requires the width of arguments to be at least 32 bits.
2432*03ce13f7SAndroid Build Coastguard Worker assert(typeWidthInBytes(Ty) >= 4);
2433*03ce13f7SAndroid Build Coastguard Worker if (isVectorType(Ty) && RegX8632::getRegisterForXmmArgNum(
2434*03ce13f7SAndroid Build Coastguard Worker RegX8632::getArgIndex(i, XmmArgs.size()))
2435*03ce13f7SAndroid Build Coastguard Worker .hasValue()) {
2436*03ce13f7SAndroid Build Coastguard Worker XmmArgs.push_back(Arg);
2437*03ce13f7SAndroid Build Coastguard Worker XmmArgIndices.push_back(i);
2438*03ce13f7SAndroid Build Coastguard Worker } else if (isScalarIntegerType(Ty) &&
2439*03ce13f7SAndroid Build Coastguard Worker RegX8632::getRegisterForGprArgNum(
2440*03ce13f7SAndroid Build Coastguard Worker Ty, RegX8632::getArgIndex(i, GprArgs.size()))
2441*03ce13f7SAndroid Build Coastguard Worker .hasValue()) {
2442*03ce13f7SAndroid Build Coastguard Worker GprArgs.emplace_back(Ty, Arg);
2443*03ce13f7SAndroid Build Coastguard Worker GprArgIndices.push_back(i);
2444*03ce13f7SAndroid Build Coastguard Worker } else {
2445*03ce13f7SAndroid Build Coastguard Worker // Place on stack.
2446*03ce13f7SAndroid Build Coastguard Worker StackArgs.push_back(Arg);
2447*03ce13f7SAndroid Build Coastguard Worker if (isVectorType(Arg->getType())) {
2448*03ce13f7SAndroid Build Coastguard Worker ParameterAreaSizeBytes = applyStackAlignment(ParameterAreaSizeBytes);
2449*03ce13f7SAndroid Build Coastguard Worker }
2450*03ce13f7SAndroid Build Coastguard Worker Variable *esp = getPhysicalRegister(getStackReg(), WordType);
2451*03ce13f7SAndroid Build Coastguard Worker Constant *Loc = Ctx->getConstantInt32(ParameterAreaSizeBytes);
2452*03ce13f7SAndroid Build Coastguard Worker StackArgLocations.push_back(X86OperandMem::create(Func, Ty, esp, Loc));
2453*03ce13f7SAndroid Build Coastguard Worker ParameterAreaSizeBytes += typeWidthInBytesOnStack(Arg->getType());
2454*03ce13f7SAndroid Build Coastguard Worker }
2455*03ce13f7SAndroid Build Coastguard Worker }
2456*03ce13f7SAndroid Build Coastguard Worker // Ensure there is enough space for the fstp/movs for floating returns.
2457*03ce13f7SAndroid Build Coastguard Worker Variable *Dest = Instr->getDest();
2458*03ce13f7SAndroid Build Coastguard Worker const Type DestTy = Dest ? Dest->getType() : IceType_void;
2459*03ce13f7SAndroid Build Coastguard Worker if (isScalarFloatingType(DestTy)) {
2460*03ce13f7SAndroid Build Coastguard Worker ParameterAreaSizeBytes =
2461*03ce13f7SAndroid Build Coastguard Worker std::max(static_cast<size_t>(ParameterAreaSizeBytes),
2462*03ce13f7SAndroid Build Coastguard Worker typeWidthInBytesOnStack(DestTy));
2463*03ce13f7SAndroid Build Coastguard Worker }
2464*03ce13f7SAndroid Build Coastguard Worker // Adjust the parameter area so that the stack is aligned. It is assumed that
2465*03ce13f7SAndroid Build Coastguard Worker // the stack is already aligned at the start of the calling sequence.
2466*03ce13f7SAndroid Build Coastguard Worker ParameterAreaSizeBytes = applyStackAlignment(ParameterAreaSizeBytes);
2467*03ce13f7SAndroid Build Coastguard Worker assert(ParameterAreaSizeBytes <= maxOutArgsSizeBytes());
2468*03ce13f7SAndroid Build Coastguard Worker // Copy arguments that are passed on the stack to the appropriate stack
2469*03ce13f7SAndroid Build Coastguard Worker // locations. We make sure legalize() is called on each argument at this
2470*03ce13f7SAndroid Build Coastguard Worker // point, to allow availabilityGet() to work.
2471*03ce13f7SAndroid Build Coastguard Worker for (SizeT i = 0, NumStackArgs = StackArgs.size(); i < NumStackArgs; ++i) {
2472*03ce13f7SAndroid Build Coastguard Worker lowerStore(
2473*03ce13f7SAndroid Build Coastguard Worker InstStore::create(Func, legalize(StackArgs[i]), StackArgLocations[i]));
2474*03ce13f7SAndroid Build Coastguard Worker }
2475*03ce13f7SAndroid Build Coastguard Worker // Copy arguments to be passed in registers to the appropriate registers.
2476*03ce13f7SAndroid Build Coastguard Worker for (SizeT i = 0, NumXmmArgs = XmmArgs.size(); i < NumXmmArgs; ++i) {
2477*03ce13f7SAndroid Build Coastguard Worker XmmArgs[i] = legalizeToReg(legalize(XmmArgs[i]),
2478*03ce13f7SAndroid Build Coastguard Worker RegX8632::getRegisterForXmmArgNum(
2479*03ce13f7SAndroid Build Coastguard Worker RegX8632::getArgIndex(XmmArgIndices[i], i)));
2480*03ce13f7SAndroid Build Coastguard Worker }
2481*03ce13f7SAndroid Build Coastguard Worker // Materialize moves for arguments passed in GPRs.
2482*03ce13f7SAndroid Build Coastguard Worker for (SizeT i = 0, NumGprArgs = GprArgs.size(); i < NumGprArgs; ++i) {
2483*03ce13f7SAndroid Build Coastguard Worker const Type SignatureTy = GprArgs[i].first;
2484*03ce13f7SAndroid Build Coastguard Worker Operand *Arg =
2485*03ce13f7SAndroid Build Coastguard Worker legalize(GprArgs[i].second, Legal_Default | Legal_Rematerializable);
2486*03ce13f7SAndroid Build Coastguard Worker GprArgs[i].second = legalizeToReg(
2487*03ce13f7SAndroid Build Coastguard Worker Arg, RegX8632::getRegisterForGprArgNum(
2488*03ce13f7SAndroid Build Coastguard Worker Arg->getType(), RegX8632::getArgIndex(GprArgIndices[i], i)));
2489*03ce13f7SAndroid Build Coastguard Worker assert(SignatureTy == IceType_i64 || SignatureTy == IceType_i32);
2490*03ce13f7SAndroid Build Coastguard Worker assert(SignatureTy == Arg->getType());
2491*03ce13f7SAndroid Build Coastguard Worker (void)SignatureTy;
2492*03ce13f7SAndroid Build Coastguard Worker }
2493*03ce13f7SAndroid Build Coastguard Worker // Generate a FakeUse of register arguments so that they do not get dead code
2494*03ce13f7SAndroid Build Coastguard Worker // eliminated as a result of the FakeKill of scratch registers after the call.
2495*03ce13f7SAndroid Build Coastguard Worker // These need to be right before the call instruction.
2496*03ce13f7SAndroid Build Coastguard Worker for (auto *Arg : XmmArgs) {
2497*03ce13f7SAndroid Build Coastguard Worker Context.insert<InstFakeUse>(llvm::cast<Variable>(Arg));
2498*03ce13f7SAndroid Build Coastguard Worker }
2499*03ce13f7SAndroid Build Coastguard Worker for (auto &ArgPair : GprArgs) {
2500*03ce13f7SAndroid Build Coastguard Worker Context.insert<InstFakeUse>(llvm::cast<Variable>(ArgPair.second));
2501*03ce13f7SAndroid Build Coastguard Worker }
2502*03ce13f7SAndroid Build Coastguard Worker // Generate the call instruction. Assign its result to a temporary with high
2503*03ce13f7SAndroid Build Coastguard Worker // register allocation weight.
2504*03ce13f7SAndroid Build Coastguard Worker // ReturnReg doubles as ReturnRegLo as necessary.
2505*03ce13f7SAndroid Build Coastguard Worker Variable *ReturnReg = nullptr;
2506*03ce13f7SAndroid Build Coastguard Worker Variable *ReturnRegHi = nullptr;
2507*03ce13f7SAndroid Build Coastguard Worker if (Dest) {
2508*03ce13f7SAndroid Build Coastguard Worker switch (DestTy) {
2509*03ce13f7SAndroid Build Coastguard Worker case IceType_NUM:
2510*03ce13f7SAndroid Build Coastguard Worker case IceType_void:
2511*03ce13f7SAndroid Build Coastguard Worker case IceType_i1:
2512*03ce13f7SAndroid Build Coastguard Worker case IceType_i8:
2513*03ce13f7SAndroid Build Coastguard Worker case IceType_i16:
2514*03ce13f7SAndroid Build Coastguard Worker llvm::report_fatal_error("Invalid Call dest type");
2515*03ce13f7SAndroid Build Coastguard Worker break;
2516*03ce13f7SAndroid Build Coastguard Worker case IceType_i32:
2517*03ce13f7SAndroid Build Coastguard Worker ReturnReg = makeReg(DestTy, RegX8632::Reg_eax);
2518*03ce13f7SAndroid Build Coastguard Worker break;
2519*03ce13f7SAndroid Build Coastguard Worker case IceType_i64:
2520*03ce13f7SAndroid Build Coastguard Worker ReturnReg = makeReg(IceType_i32, RegX8632::Reg_eax);
2521*03ce13f7SAndroid Build Coastguard Worker ReturnRegHi = makeReg(IceType_i32, RegX8632::Reg_edx);
2522*03ce13f7SAndroid Build Coastguard Worker break;
2523*03ce13f7SAndroid Build Coastguard Worker case IceType_f32:
2524*03ce13f7SAndroid Build Coastguard Worker case IceType_f64:
2525*03ce13f7SAndroid Build Coastguard Worker // Leave ReturnReg==ReturnRegHi==nullptr, and capture the result with
2526*03ce13f7SAndroid Build Coastguard Worker // the fstp instruction.
2527*03ce13f7SAndroid Build Coastguard Worker break;
2528*03ce13f7SAndroid Build Coastguard Worker // Fallthrough intended.
2529*03ce13f7SAndroid Build Coastguard Worker case IceType_v4i1:
2530*03ce13f7SAndroid Build Coastguard Worker case IceType_v8i1:
2531*03ce13f7SAndroid Build Coastguard Worker case IceType_v16i1:
2532*03ce13f7SAndroid Build Coastguard Worker case IceType_v16i8:
2533*03ce13f7SAndroid Build Coastguard Worker case IceType_v8i16:
2534*03ce13f7SAndroid Build Coastguard Worker case IceType_v4i32:
2535*03ce13f7SAndroid Build Coastguard Worker case IceType_v4f32:
2536*03ce13f7SAndroid Build Coastguard Worker ReturnReg = makeReg(DestTy, RegX8632::Reg_xmm0);
2537*03ce13f7SAndroid Build Coastguard Worker break;
2538*03ce13f7SAndroid Build Coastguard Worker }
2539*03ce13f7SAndroid Build Coastguard Worker }
2540*03ce13f7SAndroid Build Coastguard Worker // Emit the call to the function.
2541*03ce13f7SAndroid Build Coastguard Worker Operand *CallTarget =
2542*03ce13f7SAndroid Build Coastguard Worker legalize(Instr->getCallTarget(), Legal_Reg | Legal_Imm | Legal_AddrAbs);
2543*03ce13f7SAndroid Build Coastguard Worker size_t NumVariadicFpArgs = Instr->isVariadic() ? XmmArgs.size() : 0;
2544*03ce13f7SAndroid Build Coastguard Worker Inst *NewCall = emitCallToTarget(CallTarget, ReturnReg, NumVariadicFpArgs);
2545*03ce13f7SAndroid Build Coastguard Worker // Keep the upper return register live on 32-bit platform.
2546*03ce13f7SAndroid Build Coastguard Worker if (ReturnRegHi)
2547*03ce13f7SAndroid Build Coastguard Worker Context.insert<InstFakeDef>(ReturnRegHi);
2548*03ce13f7SAndroid Build Coastguard Worker // Mark the call as killing all the caller-save registers.
2549*03ce13f7SAndroid Build Coastguard Worker Context.insert<InstFakeKill>(NewCall);
2550*03ce13f7SAndroid Build Coastguard Worker // Handle x86-32 floating point returns.
2551*03ce13f7SAndroid Build Coastguard Worker if (Dest != nullptr && isScalarFloatingType(DestTy)) {
2552*03ce13f7SAndroid Build Coastguard Worker // Special treatment for an FP function which returns its result in st(0).
2553*03ce13f7SAndroid Build Coastguard Worker // If Dest ends up being a physical xmm register, the fstp emit code will
2554*03ce13f7SAndroid Build Coastguard Worker // route st(0) through the space reserved in the function argument area
2555*03ce13f7SAndroid Build Coastguard Worker // we allocated.
2556*03ce13f7SAndroid Build Coastguard Worker _fstp(Dest);
2557*03ce13f7SAndroid Build Coastguard Worker // Create a fake use of Dest in case it actually isn't used, because st(0)
2558*03ce13f7SAndroid Build Coastguard Worker // still needs to be popped.
2559*03ce13f7SAndroid Build Coastguard Worker Context.insert<InstFakeUse>(Dest);
2560*03ce13f7SAndroid Build Coastguard Worker }
2561*03ce13f7SAndroid Build Coastguard Worker // Generate a FakeUse to keep the call live if necessary.
2562*03ce13f7SAndroid Build Coastguard Worker if (Instr->hasSideEffects() && ReturnReg) {
2563*03ce13f7SAndroid Build Coastguard Worker Context.insert<InstFakeUse>(ReturnReg);
2564*03ce13f7SAndroid Build Coastguard Worker }
2565*03ce13f7SAndroid Build Coastguard Worker // Process the return value, if any.
2566*03ce13f7SAndroid Build Coastguard Worker if (Dest == nullptr)
2567*03ce13f7SAndroid Build Coastguard Worker return;
2568*03ce13f7SAndroid Build Coastguard Worker // Assign the result of the call to Dest. Route it through a temporary so
2569*03ce13f7SAndroid Build Coastguard Worker // that the local register availability peephole can be subsequently used.
2570*03ce13f7SAndroid Build Coastguard Worker Variable *Tmp = nullptr;
2571*03ce13f7SAndroid Build Coastguard Worker if (isVectorType(DestTy)) {
2572*03ce13f7SAndroid Build Coastguard Worker assert(ReturnReg && "Vector type requires a return register");
2573*03ce13f7SAndroid Build Coastguard Worker Tmp = makeReg(DestTy);
2574*03ce13f7SAndroid Build Coastguard Worker _movp(Tmp, ReturnReg);
2575*03ce13f7SAndroid Build Coastguard Worker _movp(Dest, Tmp);
2576*03ce13f7SAndroid Build Coastguard Worker } else if (!isScalarFloatingType(DestTy)) {
2577*03ce13f7SAndroid Build Coastguard Worker assert(isScalarIntegerType(DestTy));
2578*03ce13f7SAndroid Build Coastguard Worker assert(ReturnReg && "Integer type requires a return register");
2579*03ce13f7SAndroid Build Coastguard Worker if (DestTy == IceType_i64) {
2580*03ce13f7SAndroid Build Coastguard Worker assert(ReturnRegHi && "64-bit type requires two return registers");
2581*03ce13f7SAndroid Build Coastguard Worker auto *Dest64On32 = llvm::cast<Variable64On32>(Dest);
2582*03ce13f7SAndroid Build Coastguard Worker Variable *DestLo = Dest64On32->getLo();
2583*03ce13f7SAndroid Build Coastguard Worker Variable *DestHi = Dest64On32->getHi();
2584*03ce13f7SAndroid Build Coastguard Worker _mov(Tmp, ReturnReg);
2585*03ce13f7SAndroid Build Coastguard Worker _mov(DestLo, Tmp);
2586*03ce13f7SAndroid Build Coastguard Worker Variable *TmpHi = nullptr;
2587*03ce13f7SAndroid Build Coastguard Worker _mov(TmpHi, ReturnRegHi);
2588*03ce13f7SAndroid Build Coastguard Worker _mov(DestHi, TmpHi);
2589*03ce13f7SAndroid Build Coastguard Worker } else {
2590*03ce13f7SAndroid Build Coastguard Worker _mov(Tmp, ReturnReg);
2591*03ce13f7SAndroid Build Coastguard Worker _mov(Dest, Tmp);
2592*03ce13f7SAndroid Build Coastguard Worker }
2593*03ce13f7SAndroid Build Coastguard Worker }
2594*03ce13f7SAndroid Build Coastguard Worker }
2595*03ce13f7SAndroid Build Coastguard Worker
lowerCast(const InstCast * Instr)2596*03ce13f7SAndroid Build Coastguard Worker void TargetX8632::lowerCast(const InstCast *Instr) {
2597*03ce13f7SAndroid Build Coastguard Worker // a = cast(b) ==> t=cast(b); a=t; (link t->b, link a->t, no overlap)
2598*03ce13f7SAndroid Build Coastguard Worker InstCast::OpKind CastKind = Instr->getCastKind();
2599*03ce13f7SAndroid Build Coastguard Worker Variable *Dest = Instr->getDest();
2600*03ce13f7SAndroid Build Coastguard Worker Type DestTy = Dest->getType();
2601*03ce13f7SAndroid Build Coastguard Worker switch (CastKind) {
2602*03ce13f7SAndroid Build Coastguard Worker default:
2603*03ce13f7SAndroid Build Coastguard Worker Func->setError("Cast type not supported");
2604*03ce13f7SAndroid Build Coastguard Worker return;
2605*03ce13f7SAndroid Build Coastguard Worker case InstCast::Sext: {
2606*03ce13f7SAndroid Build Coastguard Worker // Src0RM is the source operand legalized to physical register or memory,
2607*03ce13f7SAndroid Build Coastguard Worker // but not immediate, since the relevant x86 native instructions don't
2608*03ce13f7SAndroid Build Coastguard Worker // allow an immediate operand. If the operand is an immediate, we could
2609*03ce13f7SAndroid Build Coastguard Worker // consider computing the strength-reduced result at translation time, but
2610*03ce13f7SAndroid Build Coastguard Worker // we're unlikely to see something like that in the bitcode that the
2611*03ce13f7SAndroid Build Coastguard Worker // optimizer wouldn't have already taken care of.
2612*03ce13f7SAndroid Build Coastguard Worker Operand *Src0RM = legalize(Instr->getSrc(0), Legal_Reg | Legal_Mem);
2613*03ce13f7SAndroid Build Coastguard Worker if (isVectorType(DestTy)) {
2614*03ce13f7SAndroid Build Coastguard Worker if (DestTy == IceType_v16i8) {
2615*03ce13f7SAndroid Build Coastguard Worker // onemask = materialize(1,1,...); dst = (src & onemask) > 0
2616*03ce13f7SAndroid Build Coastguard Worker Variable *OneMask = makeVectorOfOnes(DestTy);
2617*03ce13f7SAndroid Build Coastguard Worker Variable *T = makeReg(DestTy);
2618*03ce13f7SAndroid Build Coastguard Worker _movp(T, Src0RM);
2619*03ce13f7SAndroid Build Coastguard Worker _pand(T, OneMask);
2620*03ce13f7SAndroid Build Coastguard Worker Variable *Zeros = makeVectorOfZeros(DestTy);
2621*03ce13f7SAndroid Build Coastguard Worker _pcmpgt(T, Zeros);
2622*03ce13f7SAndroid Build Coastguard Worker _movp(Dest, T);
2623*03ce13f7SAndroid Build Coastguard Worker } else {
2624*03ce13f7SAndroid Build Coastguard Worker /// width = width(elty) - 1; dest = (src << width) >> width
2625*03ce13f7SAndroid Build Coastguard Worker SizeT ShiftAmount =
2626*03ce13f7SAndroid Build Coastguard Worker X86_CHAR_BIT * typeWidthInBytes(typeElementType(DestTy)) - 1;
2627*03ce13f7SAndroid Build Coastguard Worker Constant *ShiftConstant = Ctx->getConstantInt8(ShiftAmount);
2628*03ce13f7SAndroid Build Coastguard Worker Variable *T = makeReg(DestTy);
2629*03ce13f7SAndroid Build Coastguard Worker _movp(T, Src0RM);
2630*03ce13f7SAndroid Build Coastguard Worker _psll(T, ShiftConstant);
2631*03ce13f7SAndroid Build Coastguard Worker _psra(T, ShiftConstant);
2632*03ce13f7SAndroid Build Coastguard Worker _movp(Dest, T);
2633*03ce13f7SAndroid Build Coastguard Worker }
2634*03ce13f7SAndroid Build Coastguard Worker } else if (DestTy == IceType_i64) {
2635*03ce13f7SAndroid Build Coastguard Worker // t1=movsx src; t2=t1; t2=sar t2, 31; dst.lo=t1; dst.hi=t2
2636*03ce13f7SAndroid Build Coastguard Worker Constant *Shift = Ctx->getConstantInt32(31);
2637*03ce13f7SAndroid Build Coastguard Worker auto *DestLo = llvm::cast<Variable>(loOperand(Dest));
2638*03ce13f7SAndroid Build Coastguard Worker auto *DestHi = llvm::cast<Variable>(hiOperand(Dest));
2639*03ce13f7SAndroid Build Coastguard Worker Variable *T_Lo = makeReg(DestLo->getType());
2640*03ce13f7SAndroid Build Coastguard Worker if (Src0RM->getType() == IceType_i32) {
2641*03ce13f7SAndroid Build Coastguard Worker _mov(T_Lo, Src0RM);
2642*03ce13f7SAndroid Build Coastguard Worker } else if (Src0RM->getType() == IceType_i1) {
2643*03ce13f7SAndroid Build Coastguard Worker _movzx(T_Lo, Src0RM);
2644*03ce13f7SAndroid Build Coastguard Worker _shl(T_Lo, Shift);
2645*03ce13f7SAndroid Build Coastguard Worker _sar(T_Lo, Shift);
2646*03ce13f7SAndroid Build Coastguard Worker } else {
2647*03ce13f7SAndroid Build Coastguard Worker _movsx(T_Lo, Src0RM);
2648*03ce13f7SAndroid Build Coastguard Worker }
2649*03ce13f7SAndroid Build Coastguard Worker _mov(DestLo, T_Lo);
2650*03ce13f7SAndroid Build Coastguard Worker Variable *T_Hi = nullptr;
2651*03ce13f7SAndroid Build Coastguard Worker _mov(T_Hi, T_Lo);
2652*03ce13f7SAndroid Build Coastguard Worker if (Src0RM->getType() != IceType_i1)
2653*03ce13f7SAndroid Build Coastguard Worker // For i1, the sar instruction is already done above.
2654*03ce13f7SAndroid Build Coastguard Worker _sar(T_Hi, Shift);
2655*03ce13f7SAndroid Build Coastguard Worker _mov(DestHi, T_Hi);
2656*03ce13f7SAndroid Build Coastguard Worker } else if (Src0RM->getType() == IceType_i1) {
2657*03ce13f7SAndroid Build Coastguard Worker // t1 = src
2658*03ce13f7SAndroid Build Coastguard Worker // shl t1, dst_bitwidth - 1
2659*03ce13f7SAndroid Build Coastguard Worker // sar t1, dst_bitwidth - 1
2660*03ce13f7SAndroid Build Coastguard Worker // dst = t1
2661*03ce13f7SAndroid Build Coastguard Worker size_t DestBits = X86_CHAR_BIT * typeWidthInBytes(DestTy);
2662*03ce13f7SAndroid Build Coastguard Worker Constant *ShiftAmount = Ctx->getConstantInt32(DestBits - 1);
2663*03ce13f7SAndroid Build Coastguard Worker Variable *T = makeReg(DestTy);
2664*03ce13f7SAndroid Build Coastguard Worker if (typeWidthInBytes(DestTy) <= typeWidthInBytes(Src0RM->getType())) {
2665*03ce13f7SAndroid Build Coastguard Worker _mov(T, Src0RM);
2666*03ce13f7SAndroid Build Coastguard Worker } else {
2667*03ce13f7SAndroid Build Coastguard Worker // Widen the source using movsx or movzx. (It doesn't matter which one,
2668*03ce13f7SAndroid Build Coastguard Worker // since the following shl/sar overwrite the bits.)
2669*03ce13f7SAndroid Build Coastguard Worker _movzx(T, Src0RM);
2670*03ce13f7SAndroid Build Coastguard Worker }
2671*03ce13f7SAndroid Build Coastguard Worker _shl(T, ShiftAmount);
2672*03ce13f7SAndroid Build Coastguard Worker _sar(T, ShiftAmount);
2673*03ce13f7SAndroid Build Coastguard Worker _mov(Dest, T);
2674*03ce13f7SAndroid Build Coastguard Worker } else {
2675*03ce13f7SAndroid Build Coastguard Worker // t1 = movsx src; dst = t1
2676*03ce13f7SAndroid Build Coastguard Worker Variable *T = makeReg(DestTy);
2677*03ce13f7SAndroid Build Coastguard Worker _movsx(T, Src0RM);
2678*03ce13f7SAndroid Build Coastguard Worker _mov(Dest, T);
2679*03ce13f7SAndroid Build Coastguard Worker }
2680*03ce13f7SAndroid Build Coastguard Worker break;
2681*03ce13f7SAndroid Build Coastguard Worker }
2682*03ce13f7SAndroid Build Coastguard Worker case InstCast::Zext: {
2683*03ce13f7SAndroid Build Coastguard Worker Operand *Src0RM = legalize(Instr->getSrc(0), Legal_Reg | Legal_Mem);
2684*03ce13f7SAndroid Build Coastguard Worker if (isVectorType(DestTy)) {
2685*03ce13f7SAndroid Build Coastguard Worker // onemask = materialize(1,1,...); dest = onemask & src
2686*03ce13f7SAndroid Build Coastguard Worker Variable *OneMask = makeVectorOfOnes(DestTy);
2687*03ce13f7SAndroid Build Coastguard Worker Variable *T = makeReg(DestTy);
2688*03ce13f7SAndroid Build Coastguard Worker _movp(T, Src0RM);
2689*03ce13f7SAndroid Build Coastguard Worker _pand(T, OneMask);
2690*03ce13f7SAndroid Build Coastguard Worker _movp(Dest, T);
2691*03ce13f7SAndroid Build Coastguard Worker } else if (DestTy == IceType_i64) {
2692*03ce13f7SAndroid Build Coastguard Worker // t1=movzx src; dst.lo=t1; dst.hi=0
2693*03ce13f7SAndroid Build Coastguard Worker Constant *Zero = Ctx->getConstantZero(IceType_i32);
2694*03ce13f7SAndroid Build Coastguard Worker auto *DestLo = llvm::cast<Variable>(loOperand(Dest));
2695*03ce13f7SAndroid Build Coastguard Worker auto *DestHi = llvm::cast<Variable>(hiOperand(Dest));
2696*03ce13f7SAndroid Build Coastguard Worker Variable *Tmp = makeReg(DestLo->getType());
2697*03ce13f7SAndroid Build Coastguard Worker if (Src0RM->getType() == IceType_i32) {
2698*03ce13f7SAndroid Build Coastguard Worker _mov(Tmp, Src0RM);
2699*03ce13f7SAndroid Build Coastguard Worker } else {
2700*03ce13f7SAndroid Build Coastguard Worker _movzx(Tmp, Src0RM);
2701*03ce13f7SAndroid Build Coastguard Worker }
2702*03ce13f7SAndroid Build Coastguard Worker _mov(DestLo, Tmp);
2703*03ce13f7SAndroid Build Coastguard Worker _mov(DestHi, Zero);
2704*03ce13f7SAndroid Build Coastguard Worker } else if (Src0RM->getType() == IceType_i1) {
2705*03ce13f7SAndroid Build Coastguard Worker // t = Src0RM; Dest = t
2706*03ce13f7SAndroid Build Coastguard Worker Variable *T = nullptr;
2707*03ce13f7SAndroid Build Coastguard Worker if (DestTy == IceType_i8) {
2708*03ce13f7SAndroid Build Coastguard Worker _mov(T, Src0RM);
2709*03ce13f7SAndroid Build Coastguard Worker } else {
2710*03ce13f7SAndroid Build Coastguard Worker assert(DestTy != IceType_i1);
2711*03ce13f7SAndroid Build Coastguard Worker assert(DestTy != IceType_i64);
2712*03ce13f7SAndroid Build Coastguard Worker // Use 32-bit for both 16-bit and 32-bit, since 32-bit ops are shorter.
2713*03ce13f7SAndroid Build Coastguard Worker // In x86-64 we need to widen T to 64-bits to ensure that T -- if
2714*03ce13f7SAndroid Build Coastguard Worker // written to the stack (i.e., in -Om1) will be fully zero-extended.
2715*03ce13f7SAndroid Build Coastguard Worker T = makeReg(DestTy == IceType_i64 ? IceType_i64 : IceType_i32);
2716*03ce13f7SAndroid Build Coastguard Worker _movzx(T, Src0RM);
2717*03ce13f7SAndroid Build Coastguard Worker }
2718*03ce13f7SAndroid Build Coastguard Worker _mov(Dest, T);
2719*03ce13f7SAndroid Build Coastguard Worker } else {
2720*03ce13f7SAndroid Build Coastguard Worker // t1 = movzx src; dst = t1
2721*03ce13f7SAndroid Build Coastguard Worker Variable *T = makeReg(DestTy);
2722*03ce13f7SAndroid Build Coastguard Worker _movzx(T, Src0RM);
2723*03ce13f7SAndroid Build Coastguard Worker _mov(Dest, T);
2724*03ce13f7SAndroid Build Coastguard Worker }
2725*03ce13f7SAndroid Build Coastguard Worker break;
2726*03ce13f7SAndroid Build Coastguard Worker }
2727*03ce13f7SAndroid Build Coastguard Worker case InstCast::Trunc: {
2728*03ce13f7SAndroid Build Coastguard Worker if (isVectorType(DestTy)) {
2729*03ce13f7SAndroid Build Coastguard Worker // onemask = materialize(1,1,...); dst = src & onemask
2730*03ce13f7SAndroid Build Coastguard Worker Operand *Src0RM = legalize(Instr->getSrc(0), Legal_Reg | Legal_Mem);
2731*03ce13f7SAndroid Build Coastguard Worker Type Src0Ty = Src0RM->getType();
2732*03ce13f7SAndroid Build Coastguard Worker Variable *OneMask = makeVectorOfOnes(Src0Ty);
2733*03ce13f7SAndroid Build Coastguard Worker Variable *T = makeReg(DestTy);
2734*03ce13f7SAndroid Build Coastguard Worker _movp(T, Src0RM);
2735*03ce13f7SAndroid Build Coastguard Worker _pand(T, OneMask);
2736*03ce13f7SAndroid Build Coastguard Worker _movp(Dest, T);
2737*03ce13f7SAndroid Build Coastguard Worker } else if (DestTy == IceType_i1 || DestTy == IceType_i8) {
2738*03ce13f7SAndroid Build Coastguard Worker // Make sure we truncate from and into valid registers.
2739*03ce13f7SAndroid Build Coastguard Worker Operand *Src0 = legalizeUndef(Instr->getSrc(0));
2740*03ce13f7SAndroid Build Coastguard Worker if (Src0->getType() == IceType_i64)
2741*03ce13f7SAndroid Build Coastguard Worker Src0 = loOperand(Src0);
2742*03ce13f7SAndroid Build Coastguard Worker Operand *Src0RM = legalize(Src0, Legal_Reg | Legal_Mem);
2743*03ce13f7SAndroid Build Coastguard Worker Variable *T = copyToReg8(Src0RM);
2744*03ce13f7SAndroid Build Coastguard Worker if (DestTy == IceType_i1)
2745*03ce13f7SAndroid Build Coastguard Worker _and(T, Ctx->getConstantInt1(1));
2746*03ce13f7SAndroid Build Coastguard Worker _mov(Dest, T);
2747*03ce13f7SAndroid Build Coastguard Worker } else {
2748*03ce13f7SAndroid Build Coastguard Worker Operand *Src0 = legalizeUndef(Instr->getSrc(0));
2749*03ce13f7SAndroid Build Coastguard Worker if (Src0->getType() == IceType_i64)
2750*03ce13f7SAndroid Build Coastguard Worker Src0 = loOperand(Src0);
2751*03ce13f7SAndroid Build Coastguard Worker Operand *Src0RM = legalize(Src0, Legal_Reg | Legal_Mem);
2752*03ce13f7SAndroid Build Coastguard Worker // t1 = trunc Src0RM; Dest = t1
2753*03ce13f7SAndroid Build Coastguard Worker Variable *T = makeReg(DestTy);
2754*03ce13f7SAndroid Build Coastguard Worker _mov(T, Src0RM);
2755*03ce13f7SAndroid Build Coastguard Worker _mov(Dest, T);
2756*03ce13f7SAndroid Build Coastguard Worker }
2757*03ce13f7SAndroid Build Coastguard Worker break;
2758*03ce13f7SAndroid Build Coastguard Worker }
2759*03ce13f7SAndroid Build Coastguard Worker case InstCast::Fptrunc:
2760*03ce13f7SAndroid Build Coastguard Worker case InstCast::Fpext: {
2761*03ce13f7SAndroid Build Coastguard Worker Operand *Src0RM = legalize(Instr->getSrc(0), Legal_Reg | Legal_Mem);
2762*03ce13f7SAndroid Build Coastguard Worker // t1 = cvt Src0RM; Dest = t1
2763*03ce13f7SAndroid Build Coastguard Worker Variable *T = makeReg(DestTy);
2764*03ce13f7SAndroid Build Coastguard Worker _cvt(T, Src0RM, Insts::Cvt::Float2float);
2765*03ce13f7SAndroid Build Coastguard Worker _mov(Dest, T);
2766*03ce13f7SAndroid Build Coastguard Worker break;
2767*03ce13f7SAndroid Build Coastguard Worker }
2768*03ce13f7SAndroid Build Coastguard Worker case InstCast::Fptosi:
2769*03ce13f7SAndroid Build Coastguard Worker if (isVectorType(DestTy)) {
2770*03ce13f7SAndroid Build Coastguard Worker assert(DestTy == IceType_v4i32);
2771*03ce13f7SAndroid Build Coastguard Worker assert(Instr->getSrc(0)->getType() == IceType_v4f32);
2772*03ce13f7SAndroid Build Coastguard Worker Operand *Src0R = legalizeToReg(Instr->getSrc(0));
2773*03ce13f7SAndroid Build Coastguard Worker Variable *T = makeReg(DestTy);
2774*03ce13f7SAndroid Build Coastguard Worker _cvt(T, Src0R, Insts::Cvt::Tps2dq);
2775*03ce13f7SAndroid Build Coastguard Worker _movp(Dest, T);
2776*03ce13f7SAndroid Build Coastguard Worker } else if (DestTy == IceType_i64) {
2777*03ce13f7SAndroid Build Coastguard Worker llvm::report_fatal_error("Helper call was expected");
2778*03ce13f7SAndroid Build Coastguard Worker } else {
2779*03ce13f7SAndroid Build Coastguard Worker Operand *Src0RM = legalize(Instr->getSrc(0), Legal_Reg | Legal_Mem);
2780*03ce13f7SAndroid Build Coastguard Worker // t1.i32 = cvt Src0RM; t2.dest_type = t1; Dest = t2.dest_type
2781*03ce13f7SAndroid Build Coastguard Worker Variable *T_1 = nullptr;
2782*03ce13f7SAndroid Build Coastguard Worker assert(DestTy != IceType_i64);
2783*03ce13f7SAndroid Build Coastguard Worker T_1 = makeReg(IceType_i32);
2784*03ce13f7SAndroid Build Coastguard Worker // cvt() requires its integer argument to be a GPR.
2785*03ce13f7SAndroid Build Coastguard Worker Variable *T_2 = makeReg(DestTy);
2786*03ce13f7SAndroid Build Coastguard Worker if (isByteSizedType(DestTy)) {
2787*03ce13f7SAndroid Build Coastguard Worker assert(T_1->getType() == IceType_i32);
2788*03ce13f7SAndroid Build Coastguard Worker T_1->setRegClass(RCX86_Is32To8);
2789*03ce13f7SAndroid Build Coastguard Worker T_2->setRegClass(RCX86_IsTrunc8Rcvr);
2790*03ce13f7SAndroid Build Coastguard Worker }
2791*03ce13f7SAndroid Build Coastguard Worker _cvt(T_1, Src0RM, Insts::Cvt::Tss2si);
2792*03ce13f7SAndroid Build Coastguard Worker _mov(T_2, T_1); // T_1 and T_2 may have different integer types
2793*03ce13f7SAndroid Build Coastguard Worker if (DestTy == IceType_i1)
2794*03ce13f7SAndroid Build Coastguard Worker _and(T_2, Ctx->getConstantInt1(1));
2795*03ce13f7SAndroid Build Coastguard Worker _mov(Dest, T_2);
2796*03ce13f7SAndroid Build Coastguard Worker }
2797*03ce13f7SAndroid Build Coastguard Worker break;
2798*03ce13f7SAndroid Build Coastguard Worker case InstCast::Fptoui:
2799*03ce13f7SAndroid Build Coastguard Worker if (isVectorType(DestTy)) {
2800*03ce13f7SAndroid Build Coastguard Worker llvm::report_fatal_error("Helper call was expected");
2801*03ce13f7SAndroid Build Coastguard Worker } else if (DestTy == IceType_i64 || DestTy == IceType_i32) {
2802*03ce13f7SAndroid Build Coastguard Worker llvm::report_fatal_error("Helper call was expected");
2803*03ce13f7SAndroid Build Coastguard Worker } else {
2804*03ce13f7SAndroid Build Coastguard Worker Operand *Src0RM = legalize(Instr->getSrc(0), Legal_Reg | Legal_Mem);
2805*03ce13f7SAndroid Build Coastguard Worker // t1.i32 = cvt Src0RM; t2.dest_type = t1; Dest = t2.dest_type
2806*03ce13f7SAndroid Build Coastguard Worker assert(DestTy != IceType_i64);
2807*03ce13f7SAndroid Build Coastguard Worker Variable *T_1 = nullptr;
2808*03ce13f7SAndroid Build Coastguard Worker assert(DestTy != IceType_i32);
2809*03ce13f7SAndroid Build Coastguard Worker T_1 = makeReg(IceType_i32);
2810*03ce13f7SAndroid Build Coastguard Worker Variable *T_2 = makeReg(DestTy);
2811*03ce13f7SAndroid Build Coastguard Worker if (isByteSizedType(DestTy)) {
2812*03ce13f7SAndroid Build Coastguard Worker assert(T_1->getType() == IceType_i32);
2813*03ce13f7SAndroid Build Coastguard Worker T_1->setRegClass(RCX86_Is32To8);
2814*03ce13f7SAndroid Build Coastguard Worker T_2->setRegClass(RCX86_IsTrunc8Rcvr);
2815*03ce13f7SAndroid Build Coastguard Worker }
2816*03ce13f7SAndroid Build Coastguard Worker _cvt(T_1, Src0RM, Insts::Cvt::Tss2si);
2817*03ce13f7SAndroid Build Coastguard Worker _mov(T_2, T_1); // T_1 and T_2 may have different integer types
2818*03ce13f7SAndroid Build Coastguard Worker if (DestTy == IceType_i1)
2819*03ce13f7SAndroid Build Coastguard Worker _and(T_2, Ctx->getConstantInt1(1));
2820*03ce13f7SAndroid Build Coastguard Worker _mov(Dest, T_2);
2821*03ce13f7SAndroid Build Coastguard Worker }
2822*03ce13f7SAndroid Build Coastguard Worker break;
2823*03ce13f7SAndroid Build Coastguard Worker case InstCast::Sitofp:
2824*03ce13f7SAndroid Build Coastguard Worker if (isVectorType(DestTy)) {
2825*03ce13f7SAndroid Build Coastguard Worker assert(DestTy == IceType_v4f32);
2826*03ce13f7SAndroid Build Coastguard Worker assert(Instr->getSrc(0)->getType() == IceType_v4i32);
2827*03ce13f7SAndroid Build Coastguard Worker Operand *Src0R = legalizeToReg(Instr->getSrc(0));
2828*03ce13f7SAndroid Build Coastguard Worker Variable *T = makeReg(DestTy);
2829*03ce13f7SAndroid Build Coastguard Worker _cvt(T, Src0R, Insts::Cvt::Dq2ps);
2830*03ce13f7SAndroid Build Coastguard Worker _movp(Dest, T);
2831*03ce13f7SAndroid Build Coastguard Worker } else if (Instr->getSrc(0)->getType() == IceType_i64) {
2832*03ce13f7SAndroid Build Coastguard Worker llvm::report_fatal_error("Helper call was expected");
2833*03ce13f7SAndroid Build Coastguard Worker } else {
2834*03ce13f7SAndroid Build Coastguard Worker Operand *Src0RM = legalize(Instr->getSrc(0), Legal_Reg | Legal_Mem);
2835*03ce13f7SAndroid Build Coastguard Worker // Sign-extend the operand.
2836*03ce13f7SAndroid Build Coastguard Worker // t1.i32 = movsx Src0RM; t2 = Cvt t1.i32; Dest = t2
2837*03ce13f7SAndroid Build Coastguard Worker Variable *T_1 = nullptr;
2838*03ce13f7SAndroid Build Coastguard Worker assert(Src0RM->getType() != IceType_i64);
2839*03ce13f7SAndroid Build Coastguard Worker T_1 = makeReg(IceType_i32);
2840*03ce13f7SAndroid Build Coastguard Worker Variable *T_2 = makeReg(DestTy);
2841*03ce13f7SAndroid Build Coastguard Worker if (Src0RM->getType() == T_1->getType())
2842*03ce13f7SAndroid Build Coastguard Worker _mov(T_1, Src0RM);
2843*03ce13f7SAndroid Build Coastguard Worker else
2844*03ce13f7SAndroid Build Coastguard Worker _movsx(T_1, Src0RM);
2845*03ce13f7SAndroid Build Coastguard Worker _cvt(T_2, T_1, Insts::Cvt::Si2ss);
2846*03ce13f7SAndroid Build Coastguard Worker _mov(Dest, T_2);
2847*03ce13f7SAndroid Build Coastguard Worker }
2848*03ce13f7SAndroid Build Coastguard Worker break;
2849*03ce13f7SAndroid Build Coastguard Worker case InstCast::Uitofp: {
2850*03ce13f7SAndroid Build Coastguard Worker Operand *Src0 = Instr->getSrc(0);
2851*03ce13f7SAndroid Build Coastguard Worker if (isVectorType(Src0->getType())) {
2852*03ce13f7SAndroid Build Coastguard Worker llvm::report_fatal_error("Helper call was expected");
2853*03ce13f7SAndroid Build Coastguard Worker } else if (Src0->getType() == IceType_i64 ||
2854*03ce13f7SAndroid Build Coastguard Worker Src0->getType() == IceType_i32) {
2855*03ce13f7SAndroid Build Coastguard Worker llvm::report_fatal_error("Helper call was expected");
2856*03ce13f7SAndroid Build Coastguard Worker } else {
2857*03ce13f7SAndroid Build Coastguard Worker Operand *Src0RM = legalize(Src0, Legal_Reg | Legal_Mem);
2858*03ce13f7SAndroid Build Coastguard Worker // Zero-extend the operand.
2859*03ce13f7SAndroid Build Coastguard Worker // t1.i32 = movzx Src0RM; t2 = Cvt t1.i32; Dest = t2
2860*03ce13f7SAndroid Build Coastguard Worker Variable *T_1 = nullptr;
2861*03ce13f7SAndroid Build Coastguard Worker assert(Src0RM->getType() != IceType_i64);
2862*03ce13f7SAndroid Build Coastguard Worker assert(Src0RM->getType() != IceType_i32);
2863*03ce13f7SAndroid Build Coastguard Worker T_1 = makeReg(IceType_i32);
2864*03ce13f7SAndroid Build Coastguard Worker Variable *T_2 = makeReg(DestTy);
2865*03ce13f7SAndroid Build Coastguard Worker if (Src0RM->getType() == T_1->getType())
2866*03ce13f7SAndroid Build Coastguard Worker _mov(T_1, Src0RM);
2867*03ce13f7SAndroid Build Coastguard Worker else
2868*03ce13f7SAndroid Build Coastguard Worker _movzx(T_1, Src0RM)->setMustKeep();
2869*03ce13f7SAndroid Build Coastguard Worker _cvt(T_2, T_1, Insts::Cvt::Si2ss);
2870*03ce13f7SAndroid Build Coastguard Worker _mov(Dest, T_2);
2871*03ce13f7SAndroid Build Coastguard Worker }
2872*03ce13f7SAndroid Build Coastguard Worker break;
2873*03ce13f7SAndroid Build Coastguard Worker }
2874*03ce13f7SAndroid Build Coastguard Worker case InstCast::Bitcast: {
2875*03ce13f7SAndroid Build Coastguard Worker Operand *Src0 = Instr->getSrc(0);
2876*03ce13f7SAndroid Build Coastguard Worker if (DestTy == Src0->getType()) {
2877*03ce13f7SAndroid Build Coastguard Worker auto *Assign = InstAssign::create(Func, Dest, Src0);
2878*03ce13f7SAndroid Build Coastguard Worker lowerAssign(Assign);
2879*03ce13f7SAndroid Build Coastguard Worker return;
2880*03ce13f7SAndroid Build Coastguard Worker }
2881*03ce13f7SAndroid Build Coastguard Worker switch (DestTy) {
2882*03ce13f7SAndroid Build Coastguard Worker default:
2883*03ce13f7SAndroid Build Coastguard Worker llvm_unreachable("Unexpected Bitcast dest type");
2884*03ce13f7SAndroid Build Coastguard Worker case IceType_i8: {
2885*03ce13f7SAndroid Build Coastguard Worker llvm::report_fatal_error("Helper call was expected");
2886*03ce13f7SAndroid Build Coastguard Worker } break;
2887*03ce13f7SAndroid Build Coastguard Worker case IceType_i16: {
2888*03ce13f7SAndroid Build Coastguard Worker llvm::report_fatal_error("Helper call was expected");
2889*03ce13f7SAndroid Build Coastguard Worker } break;
2890*03ce13f7SAndroid Build Coastguard Worker case IceType_i32:
2891*03ce13f7SAndroid Build Coastguard Worker case IceType_f32: {
2892*03ce13f7SAndroid Build Coastguard Worker Variable *Src0R = legalizeToReg(Src0);
2893*03ce13f7SAndroid Build Coastguard Worker Variable *T = makeReg(DestTy);
2894*03ce13f7SAndroid Build Coastguard Worker _movd(T, Src0R);
2895*03ce13f7SAndroid Build Coastguard Worker _mov(Dest, T);
2896*03ce13f7SAndroid Build Coastguard Worker } break;
2897*03ce13f7SAndroid Build Coastguard Worker case IceType_i64: {
2898*03ce13f7SAndroid Build Coastguard Worker assert(Src0->getType() == IceType_f64);
2899*03ce13f7SAndroid Build Coastguard Worker Operand *Src0RM = legalize(Src0, Legal_Reg | Legal_Mem);
2900*03ce13f7SAndroid Build Coastguard Worker // a.i64 = bitcast b.f64 ==>
2901*03ce13f7SAndroid Build Coastguard Worker // s.f64 = spill b.f64
2902*03ce13f7SAndroid Build Coastguard Worker // t_lo.i32 = lo(s.f64)
2903*03ce13f7SAndroid Build Coastguard Worker // a_lo.i32 = t_lo.i32
2904*03ce13f7SAndroid Build Coastguard Worker // t_hi.i32 = hi(s.f64)
2905*03ce13f7SAndroid Build Coastguard Worker // a_hi.i32 = t_hi.i32
2906*03ce13f7SAndroid Build Coastguard Worker Operand *SpillLo, *SpillHi;
2907*03ce13f7SAndroid Build Coastguard Worker if (auto *Src0Var = llvm::dyn_cast<Variable>(Src0RM)) {
2908*03ce13f7SAndroid Build Coastguard Worker Variable *Spill = Func->makeVariable(IceType_f64);
2909*03ce13f7SAndroid Build Coastguard Worker Spill->setLinkedTo(Src0Var);
2910*03ce13f7SAndroid Build Coastguard Worker Spill->setMustNotHaveReg();
2911*03ce13f7SAndroid Build Coastguard Worker _movq(Spill, Src0RM);
2912*03ce13f7SAndroid Build Coastguard Worker SpillLo = VariableSplit::create(Func, Spill, VariableSplit::Low);
2913*03ce13f7SAndroid Build Coastguard Worker SpillHi = VariableSplit::create(Func, Spill, VariableSplit::High);
2914*03ce13f7SAndroid Build Coastguard Worker } else {
2915*03ce13f7SAndroid Build Coastguard Worker SpillLo = loOperand(Src0RM);
2916*03ce13f7SAndroid Build Coastguard Worker SpillHi = hiOperand(Src0RM);
2917*03ce13f7SAndroid Build Coastguard Worker }
2918*03ce13f7SAndroid Build Coastguard Worker
2919*03ce13f7SAndroid Build Coastguard Worker auto *DestLo = llvm::cast<Variable>(loOperand(Dest));
2920*03ce13f7SAndroid Build Coastguard Worker auto *DestHi = llvm::cast<Variable>(hiOperand(Dest));
2921*03ce13f7SAndroid Build Coastguard Worker Variable *T_Lo = makeReg(IceType_i32);
2922*03ce13f7SAndroid Build Coastguard Worker Variable *T_Hi = makeReg(IceType_i32);
2923*03ce13f7SAndroid Build Coastguard Worker
2924*03ce13f7SAndroid Build Coastguard Worker _mov(T_Lo, SpillLo);
2925*03ce13f7SAndroid Build Coastguard Worker _mov(DestLo, T_Lo);
2926*03ce13f7SAndroid Build Coastguard Worker _mov(T_Hi, SpillHi);
2927*03ce13f7SAndroid Build Coastguard Worker _mov(DestHi, T_Hi);
2928*03ce13f7SAndroid Build Coastguard Worker } break;
2929*03ce13f7SAndroid Build Coastguard Worker case IceType_f64: {
2930*03ce13f7SAndroid Build Coastguard Worker assert(Src0->getType() == IceType_i64);
2931*03ce13f7SAndroid Build Coastguard Worker Src0 = legalize(Src0);
2932*03ce13f7SAndroid Build Coastguard Worker if (llvm::isa<X86OperandMem>(Src0)) {
2933*03ce13f7SAndroid Build Coastguard Worker Variable *T = makeReg(DestTy);
2934*03ce13f7SAndroid Build Coastguard Worker _movq(T, Src0);
2935*03ce13f7SAndroid Build Coastguard Worker _movq(Dest, T);
2936*03ce13f7SAndroid Build Coastguard Worker break;
2937*03ce13f7SAndroid Build Coastguard Worker }
2938*03ce13f7SAndroid Build Coastguard Worker // a.f64 = bitcast b.i64 ==>
2939*03ce13f7SAndroid Build Coastguard Worker // t_lo.i32 = b_lo.i32
2940*03ce13f7SAndroid Build Coastguard Worker // FakeDef(s.f64)
2941*03ce13f7SAndroid Build Coastguard Worker // lo(s.f64) = t_lo.i32
2942*03ce13f7SAndroid Build Coastguard Worker // t_hi.i32 = b_hi.i32
2943*03ce13f7SAndroid Build Coastguard Worker // hi(s.f64) = t_hi.i32
2944*03ce13f7SAndroid Build Coastguard Worker // a.f64 = s.f64
2945*03ce13f7SAndroid Build Coastguard Worker Variable *Spill = Func->makeVariable(IceType_f64);
2946*03ce13f7SAndroid Build Coastguard Worker Spill->setLinkedTo(Dest);
2947*03ce13f7SAndroid Build Coastguard Worker Spill->setMustNotHaveReg();
2948*03ce13f7SAndroid Build Coastguard Worker
2949*03ce13f7SAndroid Build Coastguard Worker Variable *T_Lo = nullptr, *T_Hi = nullptr;
2950*03ce13f7SAndroid Build Coastguard Worker auto *SpillLo = VariableSplit::create(Func, Spill, VariableSplit::Low);
2951*03ce13f7SAndroid Build Coastguard Worker auto *SpillHi = VariableSplit::create(Func, Spill, VariableSplit::High);
2952*03ce13f7SAndroid Build Coastguard Worker _mov(T_Lo, loOperand(Src0));
2953*03ce13f7SAndroid Build Coastguard Worker // Technically, the Spill is defined after the _store happens, but
2954*03ce13f7SAndroid Build Coastguard Worker // SpillLo is considered a "use" of Spill so define Spill before it is
2955*03ce13f7SAndroid Build Coastguard Worker // used.
2956*03ce13f7SAndroid Build Coastguard Worker Context.insert<InstFakeDef>(Spill);
2957*03ce13f7SAndroid Build Coastguard Worker _store(T_Lo, SpillLo);
2958*03ce13f7SAndroid Build Coastguard Worker _mov(T_Hi, hiOperand(Src0));
2959*03ce13f7SAndroid Build Coastguard Worker _store(T_Hi, SpillHi);
2960*03ce13f7SAndroid Build Coastguard Worker _movq(Dest, Spill);
2961*03ce13f7SAndroid Build Coastguard Worker } break;
2962*03ce13f7SAndroid Build Coastguard Worker case IceType_v8i1: {
2963*03ce13f7SAndroid Build Coastguard Worker llvm::report_fatal_error("Helper call was expected");
2964*03ce13f7SAndroid Build Coastguard Worker } break;
2965*03ce13f7SAndroid Build Coastguard Worker case IceType_v16i1: {
2966*03ce13f7SAndroid Build Coastguard Worker llvm::report_fatal_error("Helper call was expected");
2967*03ce13f7SAndroid Build Coastguard Worker } break;
2968*03ce13f7SAndroid Build Coastguard Worker case IceType_v8i16:
2969*03ce13f7SAndroid Build Coastguard Worker case IceType_v16i8:
2970*03ce13f7SAndroid Build Coastguard Worker case IceType_v4i32:
2971*03ce13f7SAndroid Build Coastguard Worker case IceType_v4f32: {
2972*03ce13f7SAndroid Build Coastguard Worker if (Src0->getType() == IceType_i32) {
2973*03ce13f7SAndroid Build Coastguard Worker // Bitcast requires equal type sizes, which isn't strictly the case
2974*03ce13f7SAndroid Build Coastguard Worker // between scalars and vectors, but to emulate v4i8 vectors one has to
2975*03ce13f7SAndroid Build Coastguard Worker // use v16i8 vectors.
2976*03ce13f7SAndroid Build Coastguard Worker Operand *Src0RM = legalize(Src0, Legal_Reg | Legal_Mem);
2977*03ce13f7SAndroid Build Coastguard Worker Variable *T = makeReg(DestTy);
2978*03ce13f7SAndroid Build Coastguard Worker _movd(T, Src0RM);
2979*03ce13f7SAndroid Build Coastguard Worker _mov(Dest, T);
2980*03ce13f7SAndroid Build Coastguard Worker } else {
2981*03ce13f7SAndroid Build Coastguard Worker _movp(Dest, legalizeToReg(Src0));
2982*03ce13f7SAndroid Build Coastguard Worker }
2983*03ce13f7SAndroid Build Coastguard Worker } break;
2984*03ce13f7SAndroid Build Coastguard Worker }
2985*03ce13f7SAndroid Build Coastguard Worker break;
2986*03ce13f7SAndroid Build Coastguard Worker }
2987*03ce13f7SAndroid Build Coastguard Worker }
2988*03ce13f7SAndroid Build Coastguard Worker }
2989*03ce13f7SAndroid Build Coastguard Worker
lowerExtractElement(const InstExtractElement * Instr)2990*03ce13f7SAndroid Build Coastguard Worker void TargetX8632::lowerExtractElement(const InstExtractElement *Instr) {
2991*03ce13f7SAndroid Build Coastguard Worker Operand *SourceVectNotLegalized = Instr->getSrc(0);
2992*03ce13f7SAndroid Build Coastguard Worker auto *ElementIndex = llvm::dyn_cast<ConstantInteger32>(Instr->getSrc(1));
2993*03ce13f7SAndroid Build Coastguard Worker // Only constant indices are allowed in PNaCl IR.
2994*03ce13f7SAndroid Build Coastguard Worker assert(ElementIndex);
2995*03ce13f7SAndroid Build Coastguard Worker
2996*03ce13f7SAndroid Build Coastguard Worker unsigned Index = ElementIndex->getValue();
2997*03ce13f7SAndroid Build Coastguard Worker Type Ty = SourceVectNotLegalized->getType();
2998*03ce13f7SAndroid Build Coastguard Worker Type ElementTy = typeElementType(Ty);
2999*03ce13f7SAndroid Build Coastguard Worker Type InVectorElementTy = InstX86Base::getInVectorElementType(Ty);
3000*03ce13f7SAndroid Build Coastguard Worker
3001*03ce13f7SAndroid Build Coastguard Worker // TODO(wala): Determine the best lowering sequences for each type.
3002*03ce13f7SAndroid Build Coastguard Worker bool CanUsePextr = Ty == IceType_v8i16 || Ty == IceType_v8i1 ||
3003*03ce13f7SAndroid Build Coastguard Worker (InstructionSet >= SSE4_1 && Ty != IceType_v4f32);
3004*03ce13f7SAndroid Build Coastguard Worker Variable *ExtractedElementR =
3005*03ce13f7SAndroid Build Coastguard Worker makeReg(CanUsePextr ? IceType_i32 : InVectorElementTy);
3006*03ce13f7SAndroid Build Coastguard Worker if (CanUsePextr) {
3007*03ce13f7SAndroid Build Coastguard Worker // Use pextrb, pextrw, or pextrd. The "b" and "w" versions clear the upper
3008*03ce13f7SAndroid Build Coastguard Worker // bits of the destination register, so we represent this by always
3009*03ce13f7SAndroid Build Coastguard Worker // extracting into an i32 register. The _mov into Dest below will do
3010*03ce13f7SAndroid Build Coastguard Worker // truncation as necessary.
3011*03ce13f7SAndroid Build Coastguard Worker Constant *Mask = Ctx->getConstantInt32(Index);
3012*03ce13f7SAndroid Build Coastguard Worker Variable *SourceVectR = legalizeToReg(SourceVectNotLegalized);
3013*03ce13f7SAndroid Build Coastguard Worker _pextr(ExtractedElementR, SourceVectR, Mask);
3014*03ce13f7SAndroid Build Coastguard Worker } else if (Ty == IceType_v4i32 || Ty == IceType_v4f32 || Ty == IceType_v4i1) {
3015*03ce13f7SAndroid Build Coastguard Worker // Use pshufd and movd/movss.
3016*03ce13f7SAndroid Build Coastguard Worker Variable *T = nullptr;
3017*03ce13f7SAndroid Build Coastguard Worker if (Index) {
3018*03ce13f7SAndroid Build Coastguard Worker // The shuffle only needs to occur if the element to be extracted is not
3019*03ce13f7SAndroid Build Coastguard Worker // at the lowest index.
3020*03ce13f7SAndroid Build Coastguard Worker Constant *Mask = Ctx->getConstantInt32(Index);
3021*03ce13f7SAndroid Build Coastguard Worker T = makeReg(Ty);
3022*03ce13f7SAndroid Build Coastguard Worker _pshufd(T, legalize(SourceVectNotLegalized, Legal_Reg | Legal_Mem), Mask);
3023*03ce13f7SAndroid Build Coastguard Worker } else {
3024*03ce13f7SAndroid Build Coastguard Worker T = legalizeToReg(SourceVectNotLegalized);
3025*03ce13f7SAndroid Build Coastguard Worker }
3026*03ce13f7SAndroid Build Coastguard Worker
3027*03ce13f7SAndroid Build Coastguard Worker if (InVectorElementTy == IceType_i32) {
3028*03ce13f7SAndroid Build Coastguard Worker _movd(ExtractedElementR, T);
3029*03ce13f7SAndroid Build Coastguard Worker } else { // Ty == IceType_f32
3030*03ce13f7SAndroid Build Coastguard Worker // TODO(wala): _movss is only used here because _mov does not allow a
3031*03ce13f7SAndroid Build Coastguard Worker // vector source and a scalar destination. _mov should be able to be
3032*03ce13f7SAndroid Build Coastguard Worker // used here.
3033*03ce13f7SAndroid Build Coastguard Worker // _movss is a binary instruction, so the FakeDef is needed to keep the
3034*03ce13f7SAndroid Build Coastguard Worker // live range analysis consistent.
3035*03ce13f7SAndroid Build Coastguard Worker Context.insert<InstFakeDef>(ExtractedElementR);
3036*03ce13f7SAndroid Build Coastguard Worker _movss(ExtractedElementR, T);
3037*03ce13f7SAndroid Build Coastguard Worker }
3038*03ce13f7SAndroid Build Coastguard Worker } else {
3039*03ce13f7SAndroid Build Coastguard Worker assert(Ty == IceType_v16i8 || Ty == IceType_v16i1);
3040*03ce13f7SAndroid Build Coastguard Worker // Spill the value to a stack slot and do the extraction in memory.
3041*03ce13f7SAndroid Build Coastguard Worker //
3042*03ce13f7SAndroid Build Coastguard Worker // TODO(wala): use legalize(SourceVectNotLegalized, Legal_Mem) when support
3043*03ce13f7SAndroid Build Coastguard Worker // for legalizing to mem is implemented.
3044*03ce13f7SAndroid Build Coastguard Worker Variable *Slot = Func->makeVariable(Ty);
3045*03ce13f7SAndroid Build Coastguard Worker Slot->setMustNotHaveReg();
3046*03ce13f7SAndroid Build Coastguard Worker _movp(Slot, legalizeToReg(SourceVectNotLegalized));
3047*03ce13f7SAndroid Build Coastguard Worker
3048*03ce13f7SAndroid Build Coastguard Worker // Compute the location of the element in memory.
3049*03ce13f7SAndroid Build Coastguard Worker unsigned Offset = Index * typeWidthInBytes(InVectorElementTy);
3050*03ce13f7SAndroid Build Coastguard Worker X86OperandMem *Loc =
3051*03ce13f7SAndroid Build Coastguard Worker getMemoryOperandForStackSlot(InVectorElementTy, Slot, Offset);
3052*03ce13f7SAndroid Build Coastguard Worker _mov(ExtractedElementR, Loc);
3053*03ce13f7SAndroid Build Coastguard Worker }
3054*03ce13f7SAndroid Build Coastguard Worker
3055*03ce13f7SAndroid Build Coastguard Worker if (ElementTy == IceType_i1) {
3056*03ce13f7SAndroid Build Coastguard Worker // Truncate extracted integers to i1s if necessary.
3057*03ce13f7SAndroid Build Coastguard Worker Variable *T = makeReg(IceType_i1);
3058*03ce13f7SAndroid Build Coastguard Worker InstCast *Cast =
3059*03ce13f7SAndroid Build Coastguard Worker InstCast::create(Func, InstCast::Trunc, T, ExtractedElementR);
3060*03ce13f7SAndroid Build Coastguard Worker lowerCast(Cast);
3061*03ce13f7SAndroid Build Coastguard Worker ExtractedElementR = T;
3062*03ce13f7SAndroid Build Coastguard Worker }
3063*03ce13f7SAndroid Build Coastguard Worker
3064*03ce13f7SAndroid Build Coastguard Worker // Copy the element to the destination.
3065*03ce13f7SAndroid Build Coastguard Worker Variable *Dest = Instr->getDest();
3066*03ce13f7SAndroid Build Coastguard Worker _mov(Dest, ExtractedElementR);
3067*03ce13f7SAndroid Build Coastguard Worker }
3068*03ce13f7SAndroid Build Coastguard Worker
lowerFcmp(const InstFcmp * Fcmp)3069*03ce13f7SAndroid Build Coastguard Worker void TargetX8632::lowerFcmp(const InstFcmp *Fcmp) {
3070*03ce13f7SAndroid Build Coastguard Worker Variable *Dest = Fcmp->getDest();
3071*03ce13f7SAndroid Build Coastguard Worker
3072*03ce13f7SAndroid Build Coastguard Worker if (isVectorType(Dest->getType())) {
3073*03ce13f7SAndroid Build Coastguard Worker lowerFcmpVector(Fcmp);
3074*03ce13f7SAndroid Build Coastguard Worker } else {
3075*03ce13f7SAndroid Build Coastguard Worker constexpr Inst *Consumer = nullptr;
3076*03ce13f7SAndroid Build Coastguard Worker lowerFcmpAndConsumer(Fcmp, Consumer);
3077*03ce13f7SAndroid Build Coastguard Worker }
3078*03ce13f7SAndroid Build Coastguard Worker }
3079*03ce13f7SAndroid Build Coastguard Worker
lowerFcmpAndConsumer(const InstFcmp * Fcmp,const Inst * Consumer)3080*03ce13f7SAndroid Build Coastguard Worker void TargetX8632::lowerFcmpAndConsumer(const InstFcmp *Fcmp,
3081*03ce13f7SAndroid Build Coastguard Worker const Inst *Consumer) {
3082*03ce13f7SAndroid Build Coastguard Worker Operand *Src0 = Fcmp->getSrc(0);
3083*03ce13f7SAndroid Build Coastguard Worker Operand *Src1 = Fcmp->getSrc(1);
3084*03ce13f7SAndroid Build Coastguard Worker Variable *Dest = Fcmp->getDest();
3085*03ce13f7SAndroid Build Coastguard Worker
3086*03ce13f7SAndroid Build Coastguard Worker if (Consumer != nullptr) {
3087*03ce13f7SAndroid Build Coastguard Worker if (auto *Select = llvm::dyn_cast<InstSelect>(Consumer)) {
3088*03ce13f7SAndroid Build Coastguard Worker if (lowerOptimizeFcmpSelect(Fcmp, Select))
3089*03ce13f7SAndroid Build Coastguard Worker return;
3090*03ce13f7SAndroid Build Coastguard Worker }
3091*03ce13f7SAndroid Build Coastguard Worker }
3092*03ce13f7SAndroid Build Coastguard Worker
3093*03ce13f7SAndroid Build Coastguard Worker if (isVectorType(Dest->getType())) {
3094*03ce13f7SAndroid Build Coastguard Worker lowerFcmp(Fcmp);
3095*03ce13f7SAndroid Build Coastguard Worker if (Consumer != nullptr)
3096*03ce13f7SAndroid Build Coastguard Worker lowerSelectVector(llvm::cast<InstSelect>(Consumer));
3097*03ce13f7SAndroid Build Coastguard Worker return;
3098*03ce13f7SAndroid Build Coastguard Worker }
3099*03ce13f7SAndroid Build Coastguard Worker
3100*03ce13f7SAndroid Build Coastguard Worker // Lowering a = fcmp cond, b, c
3101*03ce13f7SAndroid Build Coastguard Worker // ucomiss b, c /* only if C1 != Br_None */
3102*03ce13f7SAndroid Build Coastguard Worker // /* but swap b,c order if SwapOperands==true */
3103*03ce13f7SAndroid Build Coastguard Worker // mov a, <default>
3104*03ce13f7SAndroid Build Coastguard Worker // j<C1> label /* only if C1 != Br_None */
3105*03ce13f7SAndroid Build Coastguard Worker // j<C2> label /* only if C2 != Br_None */
3106*03ce13f7SAndroid Build Coastguard Worker // FakeUse(a) /* only if C1 != Br_None */
3107*03ce13f7SAndroid Build Coastguard Worker // mov a, !<default> /* only if C1 != Br_None */
3108*03ce13f7SAndroid Build Coastguard Worker // label: /* only if C1 != Br_None */
3109*03ce13f7SAndroid Build Coastguard Worker //
3110*03ce13f7SAndroid Build Coastguard Worker // setcc lowering when C1 != Br_None && C2 == Br_None:
3111*03ce13f7SAndroid Build Coastguard Worker // ucomiss b, c /* but swap b,c order if SwapOperands==true */
3112*03ce13f7SAndroid Build Coastguard Worker // setcc a, C1
3113*03ce13f7SAndroid Build Coastguard Worker InstFcmp::FCond Condition = Fcmp->getCondition();
3114*03ce13f7SAndroid Build Coastguard Worker assert(static_cast<size_t>(Condition) < TableFcmpSize);
3115*03ce13f7SAndroid Build Coastguard Worker if (TableFcmp[Condition].SwapScalarOperands)
3116*03ce13f7SAndroid Build Coastguard Worker std::swap(Src0, Src1);
3117*03ce13f7SAndroid Build Coastguard Worker const bool HasC1 = (TableFcmp[Condition].C1 != CondX86::Br_None);
3118*03ce13f7SAndroid Build Coastguard Worker const bool HasC2 = (TableFcmp[Condition].C2 != CondX86::Br_None);
3119*03ce13f7SAndroid Build Coastguard Worker if (HasC1) {
3120*03ce13f7SAndroid Build Coastguard Worker Src0 = legalize(Src0);
3121*03ce13f7SAndroid Build Coastguard Worker Operand *Src1RM = legalize(Src1, Legal_Reg | Legal_Mem);
3122*03ce13f7SAndroid Build Coastguard Worker Variable *T = nullptr;
3123*03ce13f7SAndroid Build Coastguard Worker _mov(T, Src0);
3124*03ce13f7SAndroid Build Coastguard Worker _ucomiss(T, Src1RM);
3125*03ce13f7SAndroid Build Coastguard Worker if (!HasC2) {
3126*03ce13f7SAndroid Build Coastguard Worker assert(TableFcmp[Condition].Default);
3127*03ce13f7SAndroid Build Coastguard Worker setccOrConsumer(TableFcmp[Condition].C1, Dest, Consumer);
3128*03ce13f7SAndroid Build Coastguard Worker return;
3129*03ce13f7SAndroid Build Coastguard Worker }
3130*03ce13f7SAndroid Build Coastguard Worker }
3131*03ce13f7SAndroid Build Coastguard Worker int32_t IntDefault = TableFcmp[Condition].Default;
3132*03ce13f7SAndroid Build Coastguard Worker if (Consumer == nullptr) {
3133*03ce13f7SAndroid Build Coastguard Worker Constant *Default = Ctx->getConstantInt(Dest->getType(), IntDefault);
3134*03ce13f7SAndroid Build Coastguard Worker _mov(Dest, Default);
3135*03ce13f7SAndroid Build Coastguard Worker if (HasC1) {
3136*03ce13f7SAndroid Build Coastguard Worker InstX86Label *Label = InstX86Label::create(Func, this);
3137*03ce13f7SAndroid Build Coastguard Worker _br(TableFcmp[Condition].C1, Label);
3138*03ce13f7SAndroid Build Coastguard Worker if (HasC2) {
3139*03ce13f7SAndroid Build Coastguard Worker _br(TableFcmp[Condition].C2, Label);
3140*03ce13f7SAndroid Build Coastguard Worker }
3141*03ce13f7SAndroid Build Coastguard Worker Constant *NonDefault = Ctx->getConstantInt(Dest->getType(), !IntDefault);
3142*03ce13f7SAndroid Build Coastguard Worker _redefined(_mov(Dest, NonDefault));
3143*03ce13f7SAndroid Build Coastguard Worker Context.insert(Label);
3144*03ce13f7SAndroid Build Coastguard Worker }
3145*03ce13f7SAndroid Build Coastguard Worker return;
3146*03ce13f7SAndroid Build Coastguard Worker }
3147*03ce13f7SAndroid Build Coastguard Worker if (const auto *Br = llvm::dyn_cast<InstBr>(Consumer)) {
3148*03ce13f7SAndroid Build Coastguard Worker CfgNode *TrueSucc = Br->getTargetTrue();
3149*03ce13f7SAndroid Build Coastguard Worker CfgNode *FalseSucc = Br->getTargetFalse();
3150*03ce13f7SAndroid Build Coastguard Worker if (IntDefault != 0)
3151*03ce13f7SAndroid Build Coastguard Worker std::swap(TrueSucc, FalseSucc);
3152*03ce13f7SAndroid Build Coastguard Worker if (HasC1) {
3153*03ce13f7SAndroid Build Coastguard Worker _br(TableFcmp[Condition].C1, FalseSucc);
3154*03ce13f7SAndroid Build Coastguard Worker if (HasC2) {
3155*03ce13f7SAndroid Build Coastguard Worker _br(TableFcmp[Condition].C2, FalseSucc);
3156*03ce13f7SAndroid Build Coastguard Worker }
3157*03ce13f7SAndroid Build Coastguard Worker _br(TrueSucc);
3158*03ce13f7SAndroid Build Coastguard Worker return;
3159*03ce13f7SAndroid Build Coastguard Worker }
3160*03ce13f7SAndroid Build Coastguard Worker _br(FalseSucc);
3161*03ce13f7SAndroid Build Coastguard Worker return;
3162*03ce13f7SAndroid Build Coastguard Worker }
3163*03ce13f7SAndroid Build Coastguard Worker if (auto *Select = llvm::dyn_cast<InstSelect>(Consumer)) {
3164*03ce13f7SAndroid Build Coastguard Worker Operand *SrcT = Select->getTrueOperand();
3165*03ce13f7SAndroid Build Coastguard Worker Operand *SrcF = Select->getFalseOperand();
3166*03ce13f7SAndroid Build Coastguard Worker Variable *SelectDest = Select->getDest();
3167*03ce13f7SAndroid Build Coastguard Worker if (IntDefault != 0)
3168*03ce13f7SAndroid Build Coastguard Worker std::swap(SrcT, SrcF);
3169*03ce13f7SAndroid Build Coastguard Worker lowerMove(SelectDest, SrcF, false);
3170*03ce13f7SAndroid Build Coastguard Worker if (HasC1) {
3171*03ce13f7SAndroid Build Coastguard Worker InstX86Label *Label = InstX86Label::create(Func, this);
3172*03ce13f7SAndroid Build Coastguard Worker _br(TableFcmp[Condition].C1, Label);
3173*03ce13f7SAndroid Build Coastguard Worker if (HasC2) {
3174*03ce13f7SAndroid Build Coastguard Worker _br(TableFcmp[Condition].C2, Label);
3175*03ce13f7SAndroid Build Coastguard Worker }
3176*03ce13f7SAndroid Build Coastguard Worker static constexpr bool IsRedefinition = true;
3177*03ce13f7SAndroid Build Coastguard Worker lowerMove(SelectDest, SrcT, IsRedefinition);
3178*03ce13f7SAndroid Build Coastguard Worker Context.insert(Label);
3179*03ce13f7SAndroid Build Coastguard Worker }
3180*03ce13f7SAndroid Build Coastguard Worker return;
3181*03ce13f7SAndroid Build Coastguard Worker }
3182*03ce13f7SAndroid Build Coastguard Worker llvm::report_fatal_error("Unexpected consumer type");
3183*03ce13f7SAndroid Build Coastguard Worker }
3184*03ce13f7SAndroid Build Coastguard Worker
lowerFcmpVector(const InstFcmp * Fcmp)3185*03ce13f7SAndroid Build Coastguard Worker void TargetX8632::lowerFcmpVector(const InstFcmp *Fcmp) {
3186*03ce13f7SAndroid Build Coastguard Worker Operand *Src0 = Fcmp->getSrc(0);
3187*03ce13f7SAndroid Build Coastguard Worker Operand *Src1 = Fcmp->getSrc(1);
3188*03ce13f7SAndroid Build Coastguard Worker Variable *Dest = Fcmp->getDest();
3189*03ce13f7SAndroid Build Coastguard Worker
3190*03ce13f7SAndroid Build Coastguard Worker if (!isVectorType(Dest->getType()))
3191*03ce13f7SAndroid Build Coastguard Worker llvm::report_fatal_error("Expected vector compare");
3192*03ce13f7SAndroid Build Coastguard Worker
3193*03ce13f7SAndroid Build Coastguard Worker InstFcmp::FCond Condition = Fcmp->getCondition();
3194*03ce13f7SAndroid Build Coastguard Worker assert(static_cast<size_t>(Condition) < TableFcmpSize);
3195*03ce13f7SAndroid Build Coastguard Worker
3196*03ce13f7SAndroid Build Coastguard Worker if (TableFcmp[Condition].SwapVectorOperands)
3197*03ce13f7SAndroid Build Coastguard Worker std::swap(Src0, Src1);
3198*03ce13f7SAndroid Build Coastguard Worker
3199*03ce13f7SAndroid Build Coastguard Worker Variable *T = nullptr;
3200*03ce13f7SAndroid Build Coastguard Worker
3201*03ce13f7SAndroid Build Coastguard Worker if (Condition == InstFcmp::True) {
3202*03ce13f7SAndroid Build Coastguard Worker // makeVectorOfOnes() requires an integer vector type.
3203*03ce13f7SAndroid Build Coastguard Worker T = makeVectorOfMinusOnes(IceType_v4i32);
3204*03ce13f7SAndroid Build Coastguard Worker } else if (Condition == InstFcmp::False) {
3205*03ce13f7SAndroid Build Coastguard Worker T = makeVectorOfZeros(Dest->getType());
3206*03ce13f7SAndroid Build Coastguard Worker } else {
3207*03ce13f7SAndroid Build Coastguard Worker Operand *Src0RM = legalize(Src0, Legal_Reg | Legal_Mem);
3208*03ce13f7SAndroid Build Coastguard Worker Operand *Src1RM = legalize(Src1, Legal_Reg | Legal_Mem);
3209*03ce13f7SAndroid Build Coastguard Worker if (llvm::isa<X86OperandMem>(Src1RM))
3210*03ce13f7SAndroid Build Coastguard Worker Src1RM = legalizeToReg(Src1RM);
3211*03ce13f7SAndroid Build Coastguard Worker
3212*03ce13f7SAndroid Build Coastguard Worker switch (Condition) {
3213*03ce13f7SAndroid Build Coastguard Worker default: {
3214*03ce13f7SAndroid Build Coastguard Worker const CmppsCond Predicate = TableFcmp[Condition].Predicate;
3215*03ce13f7SAndroid Build Coastguard Worker assert(Predicate != CondX86::Cmpps_Invalid);
3216*03ce13f7SAndroid Build Coastguard Worker T = makeReg(Src0RM->getType());
3217*03ce13f7SAndroid Build Coastguard Worker _movp(T, Src0RM);
3218*03ce13f7SAndroid Build Coastguard Worker _cmpps(T, Src1RM, Predicate);
3219*03ce13f7SAndroid Build Coastguard Worker } break;
3220*03ce13f7SAndroid Build Coastguard Worker case InstFcmp::One: {
3221*03ce13f7SAndroid Build Coastguard Worker // Check both unequal and ordered.
3222*03ce13f7SAndroid Build Coastguard Worker T = makeReg(Src0RM->getType());
3223*03ce13f7SAndroid Build Coastguard Worker Variable *T2 = makeReg(Src0RM->getType());
3224*03ce13f7SAndroid Build Coastguard Worker _movp(T, Src0RM);
3225*03ce13f7SAndroid Build Coastguard Worker _cmpps(T, Src1RM, CondX86::Cmpps_neq);
3226*03ce13f7SAndroid Build Coastguard Worker _movp(T2, Src0RM);
3227*03ce13f7SAndroid Build Coastguard Worker _cmpps(T2, Src1RM, CondX86::Cmpps_ord);
3228*03ce13f7SAndroid Build Coastguard Worker _pand(T, T2);
3229*03ce13f7SAndroid Build Coastguard Worker } break;
3230*03ce13f7SAndroid Build Coastguard Worker case InstFcmp::Ueq: {
3231*03ce13f7SAndroid Build Coastguard Worker // Check both equal or unordered.
3232*03ce13f7SAndroid Build Coastguard Worker T = makeReg(Src0RM->getType());
3233*03ce13f7SAndroid Build Coastguard Worker Variable *T2 = makeReg(Src0RM->getType());
3234*03ce13f7SAndroid Build Coastguard Worker _movp(T, Src0RM);
3235*03ce13f7SAndroid Build Coastguard Worker _cmpps(T, Src1RM, CondX86::Cmpps_eq);
3236*03ce13f7SAndroid Build Coastguard Worker _movp(T2, Src0RM);
3237*03ce13f7SAndroid Build Coastguard Worker _cmpps(T2, Src1RM, CondX86::Cmpps_unord);
3238*03ce13f7SAndroid Build Coastguard Worker _por(T, T2);
3239*03ce13f7SAndroid Build Coastguard Worker } break;
3240*03ce13f7SAndroid Build Coastguard Worker }
3241*03ce13f7SAndroid Build Coastguard Worker }
3242*03ce13f7SAndroid Build Coastguard Worker
3243*03ce13f7SAndroid Build Coastguard Worker assert(T != nullptr);
3244*03ce13f7SAndroid Build Coastguard Worker _movp(Dest, T);
3245*03ce13f7SAndroid Build Coastguard Worker eliminateNextVectorSextInstruction(Dest);
3246*03ce13f7SAndroid Build Coastguard Worker }
3247*03ce13f7SAndroid Build Coastguard Worker
isZero(const Operand * Opnd)3248*03ce13f7SAndroid Build Coastguard Worker inline bool isZero(const Operand *Opnd) {
3249*03ce13f7SAndroid Build Coastguard Worker if (auto *C64 = llvm::dyn_cast<ConstantInteger64>(Opnd))
3250*03ce13f7SAndroid Build Coastguard Worker return C64->getValue() == 0;
3251*03ce13f7SAndroid Build Coastguard Worker if (auto *C32 = llvm::dyn_cast<ConstantInteger32>(Opnd))
3252*03ce13f7SAndroid Build Coastguard Worker return C32->getValue() == 0;
3253*03ce13f7SAndroid Build Coastguard Worker return false;
3254*03ce13f7SAndroid Build Coastguard Worker }
3255*03ce13f7SAndroid Build Coastguard Worker
lowerIcmpAndConsumer(const InstIcmp * Icmp,const Inst * Consumer)3256*03ce13f7SAndroid Build Coastguard Worker void TargetX8632::lowerIcmpAndConsumer(const InstIcmp *Icmp,
3257*03ce13f7SAndroid Build Coastguard Worker const Inst *Consumer) {
3258*03ce13f7SAndroid Build Coastguard Worker Operand *Src0 = legalize(Icmp->getSrc(0));
3259*03ce13f7SAndroid Build Coastguard Worker Operand *Src1 = legalize(Icmp->getSrc(1));
3260*03ce13f7SAndroid Build Coastguard Worker Variable *Dest = Icmp->getDest();
3261*03ce13f7SAndroid Build Coastguard Worker
3262*03ce13f7SAndroid Build Coastguard Worker if (isVectorType(Dest->getType())) {
3263*03ce13f7SAndroid Build Coastguard Worker lowerIcmp(Icmp);
3264*03ce13f7SAndroid Build Coastguard Worker if (Consumer != nullptr)
3265*03ce13f7SAndroid Build Coastguard Worker lowerSelectVector(llvm::cast<InstSelect>(Consumer));
3266*03ce13f7SAndroid Build Coastguard Worker return;
3267*03ce13f7SAndroid Build Coastguard Worker }
3268*03ce13f7SAndroid Build Coastguard Worker
3269*03ce13f7SAndroid Build Coastguard Worker if (Src0->getType() == IceType_i64) {
3270*03ce13f7SAndroid Build Coastguard Worker lowerIcmp64(Icmp, Consumer);
3271*03ce13f7SAndroid Build Coastguard Worker return;
3272*03ce13f7SAndroid Build Coastguard Worker }
3273*03ce13f7SAndroid Build Coastguard Worker
3274*03ce13f7SAndroid Build Coastguard Worker // cmp b, c
3275*03ce13f7SAndroid Build Coastguard Worker if (isZero(Src1)) {
3276*03ce13f7SAndroid Build Coastguard Worker switch (Icmp->getCondition()) {
3277*03ce13f7SAndroid Build Coastguard Worker default:
3278*03ce13f7SAndroid Build Coastguard Worker break;
3279*03ce13f7SAndroid Build Coastguard Worker case InstIcmp::Uge:
3280*03ce13f7SAndroid Build Coastguard Worker movOrConsumer(true, Dest, Consumer);
3281*03ce13f7SAndroid Build Coastguard Worker return;
3282*03ce13f7SAndroid Build Coastguard Worker case InstIcmp::Ult:
3283*03ce13f7SAndroid Build Coastguard Worker movOrConsumer(false, Dest, Consumer);
3284*03ce13f7SAndroid Build Coastguard Worker return;
3285*03ce13f7SAndroid Build Coastguard Worker }
3286*03ce13f7SAndroid Build Coastguard Worker }
3287*03ce13f7SAndroid Build Coastguard Worker Operand *Src0RM = legalizeSrc0ForCmp(Src0, Src1);
3288*03ce13f7SAndroid Build Coastguard Worker _cmp(Src0RM, Src1);
3289*03ce13f7SAndroid Build Coastguard Worker setccOrConsumer(getIcmp32Mapping(Icmp->getCondition()), Dest, Consumer);
3290*03ce13f7SAndroid Build Coastguard Worker }
3291*03ce13f7SAndroid Build Coastguard Worker
lowerIcmpVector(const InstIcmp * Icmp)3292*03ce13f7SAndroid Build Coastguard Worker void TargetX8632::lowerIcmpVector(const InstIcmp *Icmp) {
3293*03ce13f7SAndroid Build Coastguard Worker Operand *Src0 = legalize(Icmp->getSrc(0));
3294*03ce13f7SAndroid Build Coastguard Worker Operand *Src1 = legalize(Icmp->getSrc(1));
3295*03ce13f7SAndroid Build Coastguard Worker Variable *Dest = Icmp->getDest();
3296*03ce13f7SAndroid Build Coastguard Worker
3297*03ce13f7SAndroid Build Coastguard Worker if (!isVectorType(Dest->getType()))
3298*03ce13f7SAndroid Build Coastguard Worker llvm::report_fatal_error("Expected a vector compare");
3299*03ce13f7SAndroid Build Coastguard Worker
3300*03ce13f7SAndroid Build Coastguard Worker Type Ty = Src0->getType();
3301*03ce13f7SAndroid Build Coastguard Worker // Promote i1 vectors to 128 bit integer vector types.
3302*03ce13f7SAndroid Build Coastguard Worker if (typeElementType(Ty) == IceType_i1) {
3303*03ce13f7SAndroid Build Coastguard Worker Type NewTy = IceType_NUM;
3304*03ce13f7SAndroid Build Coastguard Worker switch (Ty) {
3305*03ce13f7SAndroid Build Coastguard Worker default:
3306*03ce13f7SAndroid Build Coastguard Worker llvm::report_fatal_error("unexpected type");
3307*03ce13f7SAndroid Build Coastguard Worker break;
3308*03ce13f7SAndroid Build Coastguard Worker case IceType_v4i1:
3309*03ce13f7SAndroid Build Coastguard Worker NewTy = IceType_v4i32;
3310*03ce13f7SAndroid Build Coastguard Worker break;
3311*03ce13f7SAndroid Build Coastguard Worker case IceType_v8i1:
3312*03ce13f7SAndroid Build Coastguard Worker NewTy = IceType_v8i16;
3313*03ce13f7SAndroid Build Coastguard Worker break;
3314*03ce13f7SAndroid Build Coastguard Worker case IceType_v16i1:
3315*03ce13f7SAndroid Build Coastguard Worker NewTy = IceType_v16i8;
3316*03ce13f7SAndroid Build Coastguard Worker break;
3317*03ce13f7SAndroid Build Coastguard Worker }
3318*03ce13f7SAndroid Build Coastguard Worker Variable *NewSrc0 = Func->makeVariable(NewTy);
3319*03ce13f7SAndroid Build Coastguard Worker Variable *NewSrc1 = Func->makeVariable(NewTy);
3320*03ce13f7SAndroid Build Coastguard Worker lowerCast(InstCast::create(Func, InstCast::Sext, NewSrc0, Src0));
3321*03ce13f7SAndroid Build Coastguard Worker lowerCast(InstCast::create(Func, InstCast::Sext, NewSrc1, Src1));
3322*03ce13f7SAndroid Build Coastguard Worker Src0 = NewSrc0;
3323*03ce13f7SAndroid Build Coastguard Worker Src1 = NewSrc1;
3324*03ce13f7SAndroid Build Coastguard Worker Ty = NewTy;
3325*03ce13f7SAndroid Build Coastguard Worker }
3326*03ce13f7SAndroid Build Coastguard Worker
3327*03ce13f7SAndroid Build Coastguard Worker InstIcmp::ICond Condition = Icmp->getCondition();
3328*03ce13f7SAndroid Build Coastguard Worker
3329*03ce13f7SAndroid Build Coastguard Worker Operand *Src0RM = legalize(Src0, Legal_Reg | Legal_Mem);
3330*03ce13f7SAndroid Build Coastguard Worker Operand *Src1RM = legalize(Src1, Legal_Reg | Legal_Mem);
3331*03ce13f7SAndroid Build Coastguard Worker
3332*03ce13f7SAndroid Build Coastguard Worker // SSE2 only has signed comparison operations. Transform unsigned inputs in
3333*03ce13f7SAndroid Build Coastguard Worker // a manner that allows for the use of signed comparison operations by
3334*03ce13f7SAndroid Build Coastguard Worker // flipping the high order bits.
3335*03ce13f7SAndroid Build Coastguard Worker if (Condition == InstIcmp::Ugt || Condition == InstIcmp::Uge ||
3336*03ce13f7SAndroid Build Coastguard Worker Condition == InstIcmp::Ult || Condition == InstIcmp::Ule) {
3337*03ce13f7SAndroid Build Coastguard Worker Variable *T0 = makeReg(Ty);
3338*03ce13f7SAndroid Build Coastguard Worker Variable *T1 = makeReg(Ty);
3339*03ce13f7SAndroid Build Coastguard Worker Variable *HighOrderBits = makeVectorOfHighOrderBits(Ty);
3340*03ce13f7SAndroid Build Coastguard Worker _movp(T0, Src0RM);
3341*03ce13f7SAndroid Build Coastguard Worker _pxor(T0, HighOrderBits);
3342*03ce13f7SAndroid Build Coastguard Worker _movp(T1, Src1RM);
3343*03ce13f7SAndroid Build Coastguard Worker _pxor(T1, HighOrderBits);
3344*03ce13f7SAndroid Build Coastguard Worker Src0RM = T0;
3345*03ce13f7SAndroid Build Coastguard Worker Src1RM = T1;
3346*03ce13f7SAndroid Build Coastguard Worker }
3347*03ce13f7SAndroid Build Coastguard Worker
3348*03ce13f7SAndroid Build Coastguard Worker Variable *T = makeReg(Ty);
3349*03ce13f7SAndroid Build Coastguard Worker switch (Condition) {
3350*03ce13f7SAndroid Build Coastguard Worker default:
3351*03ce13f7SAndroid Build Coastguard Worker llvm_unreachable("unexpected condition");
3352*03ce13f7SAndroid Build Coastguard Worker break;
3353*03ce13f7SAndroid Build Coastguard Worker case InstIcmp::Eq: {
3354*03ce13f7SAndroid Build Coastguard Worker if (llvm::isa<X86OperandMem>(Src1RM))
3355*03ce13f7SAndroid Build Coastguard Worker Src1RM = legalizeToReg(Src1RM);
3356*03ce13f7SAndroid Build Coastguard Worker _movp(T, Src0RM);
3357*03ce13f7SAndroid Build Coastguard Worker _pcmpeq(T, Src1RM);
3358*03ce13f7SAndroid Build Coastguard Worker } break;
3359*03ce13f7SAndroid Build Coastguard Worker case InstIcmp::Ne: {
3360*03ce13f7SAndroid Build Coastguard Worker if (llvm::isa<X86OperandMem>(Src1RM))
3361*03ce13f7SAndroid Build Coastguard Worker Src1RM = legalizeToReg(Src1RM);
3362*03ce13f7SAndroid Build Coastguard Worker _movp(T, Src0RM);
3363*03ce13f7SAndroid Build Coastguard Worker _pcmpeq(T, Src1RM);
3364*03ce13f7SAndroid Build Coastguard Worker Variable *MinusOne = makeVectorOfMinusOnes(Ty);
3365*03ce13f7SAndroid Build Coastguard Worker _pxor(T, MinusOne);
3366*03ce13f7SAndroid Build Coastguard Worker } break;
3367*03ce13f7SAndroid Build Coastguard Worker case InstIcmp::Ugt:
3368*03ce13f7SAndroid Build Coastguard Worker case InstIcmp::Sgt: {
3369*03ce13f7SAndroid Build Coastguard Worker if (llvm::isa<X86OperandMem>(Src1RM))
3370*03ce13f7SAndroid Build Coastguard Worker Src1RM = legalizeToReg(Src1RM);
3371*03ce13f7SAndroid Build Coastguard Worker _movp(T, Src0RM);
3372*03ce13f7SAndroid Build Coastguard Worker _pcmpgt(T, Src1RM);
3373*03ce13f7SAndroid Build Coastguard Worker } break;
3374*03ce13f7SAndroid Build Coastguard Worker case InstIcmp::Uge:
3375*03ce13f7SAndroid Build Coastguard Worker case InstIcmp::Sge: {
3376*03ce13f7SAndroid Build Coastguard Worker // !(Src1RM > Src0RM)
3377*03ce13f7SAndroid Build Coastguard Worker if (llvm::isa<X86OperandMem>(Src0RM))
3378*03ce13f7SAndroid Build Coastguard Worker Src0RM = legalizeToReg(Src0RM);
3379*03ce13f7SAndroid Build Coastguard Worker _movp(T, Src1RM);
3380*03ce13f7SAndroid Build Coastguard Worker _pcmpgt(T, Src0RM);
3381*03ce13f7SAndroid Build Coastguard Worker Variable *MinusOne = makeVectorOfMinusOnes(Ty);
3382*03ce13f7SAndroid Build Coastguard Worker _pxor(T, MinusOne);
3383*03ce13f7SAndroid Build Coastguard Worker } break;
3384*03ce13f7SAndroid Build Coastguard Worker case InstIcmp::Ult:
3385*03ce13f7SAndroid Build Coastguard Worker case InstIcmp::Slt: {
3386*03ce13f7SAndroid Build Coastguard Worker if (llvm::isa<X86OperandMem>(Src0RM))
3387*03ce13f7SAndroid Build Coastguard Worker Src0RM = legalizeToReg(Src0RM);
3388*03ce13f7SAndroid Build Coastguard Worker _movp(T, Src1RM);
3389*03ce13f7SAndroid Build Coastguard Worker _pcmpgt(T, Src0RM);
3390*03ce13f7SAndroid Build Coastguard Worker } break;
3391*03ce13f7SAndroid Build Coastguard Worker case InstIcmp::Ule:
3392*03ce13f7SAndroid Build Coastguard Worker case InstIcmp::Sle: {
3393*03ce13f7SAndroid Build Coastguard Worker // !(Src0RM > Src1RM)
3394*03ce13f7SAndroid Build Coastguard Worker if (llvm::isa<X86OperandMem>(Src1RM))
3395*03ce13f7SAndroid Build Coastguard Worker Src1RM = legalizeToReg(Src1RM);
3396*03ce13f7SAndroid Build Coastguard Worker _movp(T, Src0RM);
3397*03ce13f7SAndroid Build Coastguard Worker _pcmpgt(T, Src1RM);
3398*03ce13f7SAndroid Build Coastguard Worker Variable *MinusOne = makeVectorOfMinusOnes(Ty);
3399*03ce13f7SAndroid Build Coastguard Worker _pxor(T, MinusOne);
3400*03ce13f7SAndroid Build Coastguard Worker } break;
3401*03ce13f7SAndroid Build Coastguard Worker }
3402*03ce13f7SAndroid Build Coastguard Worker
3403*03ce13f7SAndroid Build Coastguard Worker _movp(Dest, T);
3404*03ce13f7SAndroid Build Coastguard Worker eliminateNextVectorSextInstruction(Dest);
3405*03ce13f7SAndroid Build Coastguard Worker }
3406*03ce13f7SAndroid Build Coastguard Worker
lowerIcmp64(const InstIcmp * Icmp,const Inst * Consumer)3407*03ce13f7SAndroid Build Coastguard Worker void TargetX8632::lowerIcmp64(const InstIcmp *Icmp, const Inst *Consumer) {
3408*03ce13f7SAndroid Build Coastguard Worker // a=icmp cond, b, c ==> cmp b,c; a=1; br cond,L1; FakeUse(a); a=0; L1:
3409*03ce13f7SAndroid Build Coastguard Worker Operand *Src0 = legalize(Icmp->getSrc(0));
3410*03ce13f7SAndroid Build Coastguard Worker Operand *Src1 = legalize(Icmp->getSrc(1));
3411*03ce13f7SAndroid Build Coastguard Worker Variable *Dest = Icmp->getDest();
3412*03ce13f7SAndroid Build Coastguard Worker InstIcmp::ICond Condition = Icmp->getCondition();
3413*03ce13f7SAndroid Build Coastguard Worker assert(static_cast<size_t>(Condition) < TableIcmp64Size);
3414*03ce13f7SAndroid Build Coastguard Worker Operand *Src0LoRM = nullptr;
3415*03ce13f7SAndroid Build Coastguard Worker Operand *Src0HiRM = nullptr;
3416*03ce13f7SAndroid Build Coastguard Worker // Legalize the portions of Src0 that are going to be needed.
3417*03ce13f7SAndroid Build Coastguard Worker if (isZero(Src1)) {
3418*03ce13f7SAndroid Build Coastguard Worker switch (Condition) {
3419*03ce13f7SAndroid Build Coastguard Worker default:
3420*03ce13f7SAndroid Build Coastguard Worker llvm_unreachable("unexpected condition");
3421*03ce13f7SAndroid Build Coastguard Worker break;
3422*03ce13f7SAndroid Build Coastguard Worker // These two are not optimized, so we fall through to the general case,
3423*03ce13f7SAndroid Build Coastguard Worker // which needs the upper and lower halves legalized.
3424*03ce13f7SAndroid Build Coastguard Worker case InstIcmp::Sgt:
3425*03ce13f7SAndroid Build Coastguard Worker case InstIcmp::Sle:
3426*03ce13f7SAndroid Build Coastguard Worker // These four compare after performing an "or" of the high and low half, so
3427*03ce13f7SAndroid Build Coastguard Worker // they need the upper and lower halves legalized.
3428*03ce13f7SAndroid Build Coastguard Worker case InstIcmp::Eq:
3429*03ce13f7SAndroid Build Coastguard Worker case InstIcmp::Ule:
3430*03ce13f7SAndroid Build Coastguard Worker case InstIcmp::Ne:
3431*03ce13f7SAndroid Build Coastguard Worker case InstIcmp::Ugt:
3432*03ce13f7SAndroid Build Coastguard Worker Src0LoRM = legalize(loOperand(Src0), Legal_Reg | Legal_Mem);
3433*03ce13f7SAndroid Build Coastguard Worker // These two test only the high half's sign bit, so they need only
3434*03ce13f7SAndroid Build Coastguard Worker // the upper half legalized.
3435*03ce13f7SAndroid Build Coastguard Worker case InstIcmp::Sge:
3436*03ce13f7SAndroid Build Coastguard Worker case InstIcmp::Slt:
3437*03ce13f7SAndroid Build Coastguard Worker Src0HiRM = legalize(hiOperand(Src0), Legal_Reg | Legal_Mem);
3438*03ce13f7SAndroid Build Coastguard Worker break;
3439*03ce13f7SAndroid Build Coastguard Worker
3440*03ce13f7SAndroid Build Coastguard Worker // These two move constants and hence need no legalization.
3441*03ce13f7SAndroid Build Coastguard Worker case InstIcmp::Uge:
3442*03ce13f7SAndroid Build Coastguard Worker case InstIcmp::Ult:
3443*03ce13f7SAndroid Build Coastguard Worker break;
3444*03ce13f7SAndroid Build Coastguard Worker }
3445*03ce13f7SAndroid Build Coastguard Worker } else {
3446*03ce13f7SAndroid Build Coastguard Worker Src0LoRM = legalize(loOperand(Src0), Legal_Reg | Legal_Mem);
3447*03ce13f7SAndroid Build Coastguard Worker Src0HiRM = legalize(hiOperand(Src0), Legal_Reg | Legal_Mem);
3448*03ce13f7SAndroid Build Coastguard Worker }
3449*03ce13f7SAndroid Build Coastguard Worker // Optimize comparisons with zero.
3450*03ce13f7SAndroid Build Coastguard Worker if (isZero(Src1)) {
3451*03ce13f7SAndroid Build Coastguard Worker Constant *SignMask = Ctx->getConstantInt32(0x80000000);
3452*03ce13f7SAndroid Build Coastguard Worker Variable *Temp = nullptr;
3453*03ce13f7SAndroid Build Coastguard Worker switch (Condition) {
3454*03ce13f7SAndroid Build Coastguard Worker default:
3455*03ce13f7SAndroid Build Coastguard Worker llvm_unreachable("unexpected condition");
3456*03ce13f7SAndroid Build Coastguard Worker break;
3457*03ce13f7SAndroid Build Coastguard Worker case InstIcmp::Eq:
3458*03ce13f7SAndroid Build Coastguard Worker case InstIcmp::Ule:
3459*03ce13f7SAndroid Build Coastguard Worker // Mov Src0HiRM first, because it was legalized most recently, and will
3460*03ce13f7SAndroid Build Coastguard Worker // sometimes avoid a move before the OR.
3461*03ce13f7SAndroid Build Coastguard Worker _mov(Temp, Src0HiRM);
3462*03ce13f7SAndroid Build Coastguard Worker _or(Temp, Src0LoRM);
3463*03ce13f7SAndroid Build Coastguard Worker Context.insert<InstFakeUse>(Temp);
3464*03ce13f7SAndroid Build Coastguard Worker setccOrConsumer(CondX86::Br_e, Dest, Consumer);
3465*03ce13f7SAndroid Build Coastguard Worker return;
3466*03ce13f7SAndroid Build Coastguard Worker case InstIcmp::Ne:
3467*03ce13f7SAndroid Build Coastguard Worker case InstIcmp::Ugt:
3468*03ce13f7SAndroid Build Coastguard Worker // Mov Src0HiRM first, because it was legalized most recently, and will
3469*03ce13f7SAndroid Build Coastguard Worker // sometimes avoid a move before the OR.
3470*03ce13f7SAndroid Build Coastguard Worker _mov(Temp, Src0HiRM);
3471*03ce13f7SAndroid Build Coastguard Worker _or(Temp, Src0LoRM);
3472*03ce13f7SAndroid Build Coastguard Worker Context.insert<InstFakeUse>(Temp);
3473*03ce13f7SAndroid Build Coastguard Worker setccOrConsumer(CondX86::Br_ne, Dest, Consumer);
3474*03ce13f7SAndroid Build Coastguard Worker return;
3475*03ce13f7SAndroid Build Coastguard Worker case InstIcmp::Uge:
3476*03ce13f7SAndroid Build Coastguard Worker movOrConsumer(true, Dest, Consumer);
3477*03ce13f7SAndroid Build Coastguard Worker return;
3478*03ce13f7SAndroid Build Coastguard Worker case InstIcmp::Ult:
3479*03ce13f7SAndroid Build Coastguard Worker movOrConsumer(false, Dest, Consumer);
3480*03ce13f7SAndroid Build Coastguard Worker return;
3481*03ce13f7SAndroid Build Coastguard Worker case InstIcmp::Sgt:
3482*03ce13f7SAndroid Build Coastguard Worker break;
3483*03ce13f7SAndroid Build Coastguard Worker case InstIcmp::Sge:
3484*03ce13f7SAndroid Build Coastguard Worker _test(Src0HiRM, SignMask);
3485*03ce13f7SAndroid Build Coastguard Worker setccOrConsumer(CondX86::Br_e, Dest, Consumer);
3486*03ce13f7SAndroid Build Coastguard Worker return;
3487*03ce13f7SAndroid Build Coastguard Worker case InstIcmp::Slt:
3488*03ce13f7SAndroid Build Coastguard Worker _test(Src0HiRM, SignMask);
3489*03ce13f7SAndroid Build Coastguard Worker setccOrConsumer(CondX86::Br_ne, Dest, Consumer);
3490*03ce13f7SAndroid Build Coastguard Worker return;
3491*03ce13f7SAndroid Build Coastguard Worker case InstIcmp::Sle:
3492*03ce13f7SAndroid Build Coastguard Worker break;
3493*03ce13f7SAndroid Build Coastguard Worker }
3494*03ce13f7SAndroid Build Coastguard Worker }
3495*03ce13f7SAndroid Build Coastguard Worker // Handle general compares.
3496*03ce13f7SAndroid Build Coastguard Worker Operand *Src1LoRI = legalize(loOperand(Src1), Legal_Reg | Legal_Imm);
3497*03ce13f7SAndroid Build Coastguard Worker Operand *Src1HiRI = legalize(hiOperand(Src1), Legal_Reg | Legal_Imm);
3498*03ce13f7SAndroid Build Coastguard Worker if (Consumer == nullptr) {
3499*03ce13f7SAndroid Build Coastguard Worker Constant *Zero = Ctx->getConstantInt(Dest->getType(), 0);
3500*03ce13f7SAndroid Build Coastguard Worker Constant *One = Ctx->getConstantInt(Dest->getType(), 1);
3501*03ce13f7SAndroid Build Coastguard Worker InstX86Label *LabelFalse = InstX86Label::create(Func, this);
3502*03ce13f7SAndroid Build Coastguard Worker InstX86Label *LabelTrue = InstX86Label::create(Func, this);
3503*03ce13f7SAndroid Build Coastguard Worker _mov(Dest, One);
3504*03ce13f7SAndroid Build Coastguard Worker _cmp(Src0HiRM, Src1HiRI);
3505*03ce13f7SAndroid Build Coastguard Worker if (TableIcmp64[Condition].C1 != CondX86::Br_None)
3506*03ce13f7SAndroid Build Coastguard Worker _br(TableIcmp64[Condition].C1, LabelTrue);
3507*03ce13f7SAndroid Build Coastguard Worker if (TableIcmp64[Condition].C2 != CondX86::Br_None)
3508*03ce13f7SAndroid Build Coastguard Worker _br(TableIcmp64[Condition].C2, LabelFalse);
3509*03ce13f7SAndroid Build Coastguard Worker _cmp(Src0LoRM, Src1LoRI);
3510*03ce13f7SAndroid Build Coastguard Worker _br(TableIcmp64[Condition].C3, LabelTrue);
3511*03ce13f7SAndroid Build Coastguard Worker Context.insert(LabelFalse);
3512*03ce13f7SAndroid Build Coastguard Worker _redefined(_mov(Dest, Zero));
3513*03ce13f7SAndroid Build Coastguard Worker Context.insert(LabelTrue);
3514*03ce13f7SAndroid Build Coastguard Worker return;
3515*03ce13f7SAndroid Build Coastguard Worker }
3516*03ce13f7SAndroid Build Coastguard Worker if (const auto *Br = llvm::dyn_cast<InstBr>(Consumer)) {
3517*03ce13f7SAndroid Build Coastguard Worker _cmp(Src0HiRM, Src1HiRI);
3518*03ce13f7SAndroid Build Coastguard Worker if (TableIcmp64[Condition].C1 != CondX86::Br_None)
3519*03ce13f7SAndroid Build Coastguard Worker _br(TableIcmp64[Condition].C1, Br->getTargetTrue());
3520*03ce13f7SAndroid Build Coastguard Worker if (TableIcmp64[Condition].C2 != CondX86::Br_None)
3521*03ce13f7SAndroid Build Coastguard Worker _br(TableIcmp64[Condition].C2, Br->getTargetFalse());
3522*03ce13f7SAndroid Build Coastguard Worker _cmp(Src0LoRM, Src1LoRI);
3523*03ce13f7SAndroid Build Coastguard Worker _br(TableIcmp64[Condition].C3, Br->getTargetTrue(), Br->getTargetFalse());
3524*03ce13f7SAndroid Build Coastguard Worker return;
3525*03ce13f7SAndroid Build Coastguard Worker }
3526*03ce13f7SAndroid Build Coastguard Worker if (auto *Select = llvm::dyn_cast<InstSelect>(Consumer)) {
3527*03ce13f7SAndroid Build Coastguard Worker Operand *SrcT = Select->getTrueOperand();
3528*03ce13f7SAndroid Build Coastguard Worker Operand *SrcF = Select->getFalseOperand();
3529*03ce13f7SAndroid Build Coastguard Worker Variable *SelectDest = Select->getDest();
3530*03ce13f7SAndroid Build Coastguard Worker InstX86Label *LabelFalse = InstX86Label::create(Func, this);
3531*03ce13f7SAndroid Build Coastguard Worker InstX86Label *LabelTrue = InstX86Label::create(Func, this);
3532*03ce13f7SAndroid Build Coastguard Worker lowerMove(SelectDest, SrcT, false);
3533*03ce13f7SAndroid Build Coastguard Worker _cmp(Src0HiRM, Src1HiRI);
3534*03ce13f7SAndroid Build Coastguard Worker if (TableIcmp64[Condition].C1 != CondX86::Br_None)
3535*03ce13f7SAndroid Build Coastguard Worker _br(TableIcmp64[Condition].C1, LabelTrue);
3536*03ce13f7SAndroid Build Coastguard Worker if (TableIcmp64[Condition].C2 != CondX86::Br_None)
3537*03ce13f7SAndroid Build Coastguard Worker _br(TableIcmp64[Condition].C2, LabelFalse);
3538*03ce13f7SAndroid Build Coastguard Worker _cmp(Src0LoRM, Src1LoRI);
3539*03ce13f7SAndroid Build Coastguard Worker _br(TableIcmp64[Condition].C3, LabelTrue);
3540*03ce13f7SAndroid Build Coastguard Worker Context.insert(LabelFalse);
3541*03ce13f7SAndroid Build Coastguard Worker static constexpr bool IsRedefinition = true;
3542*03ce13f7SAndroid Build Coastguard Worker lowerMove(SelectDest, SrcF, IsRedefinition);
3543*03ce13f7SAndroid Build Coastguard Worker Context.insert(LabelTrue);
3544*03ce13f7SAndroid Build Coastguard Worker return;
3545*03ce13f7SAndroid Build Coastguard Worker }
3546*03ce13f7SAndroid Build Coastguard Worker llvm::report_fatal_error("Unexpected consumer type");
3547*03ce13f7SAndroid Build Coastguard Worker }
3548*03ce13f7SAndroid Build Coastguard Worker
setccOrConsumer(BrCond Condition,Variable * Dest,const Inst * Consumer)3549*03ce13f7SAndroid Build Coastguard Worker void TargetX8632::setccOrConsumer(BrCond Condition, Variable *Dest,
3550*03ce13f7SAndroid Build Coastguard Worker const Inst *Consumer) {
3551*03ce13f7SAndroid Build Coastguard Worker if (Consumer == nullptr) {
3552*03ce13f7SAndroid Build Coastguard Worker _setcc(Dest, Condition);
3553*03ce13f7SAndroid Build Coastguard Worker return;
3554*03ce13f7SAndroid Build Coastguard Worker }
3555*03ce13f7SAndroid Build Coastguard Worker if (const auto *Br = llvm::dyn_cast<InstBr>(Consumer)) {
3556*03ce13f7SAndroid Build Coastguard Worker _br(Condition, Br->getTargetTrue(), Br->getTargetFalse());
3557*03ce13f7SAndroid Build Coastguard Worker return;
3558*03ce13f7SAndroid Build Coastguard Worker }
3559*03ce13f7SAndroid Build Coastguard Worker if (const auto *Select = llvm::dyn_cast<InstSelect>(Consumer)) {
3560*03ce13f7SAndroid Build Coastguard Worker Operand *SrcT = Select->getTrueOperand();
3561*03ce13f7SAndroid Build Coastguard Worker Operand *SrcF = Select->getFalseOperand();
3562*03ce13f7SAndroid Build Coastguard Worker Variable *SelectDest = Select->getDest();
3563*03ce13f7SAndroid Build Coastguard Worker lowerSelectMove(SelectDest, Condition, SrcT, SrcF);
3564*03ce13f7SAndroid Build Coastguard Worker return;
3565*03ce13f7SAndroid Build Coastguard Worker }
3566*03ce13f7SAndroid Build Coastguard Worker llvm::report_fatal_error("Unexpected consumer type");
3567*03ce13f7SAndroid Build Coastguard Worker }
3568*03ce13f7SAndroid Build Coastguard Worker
movOrConsumer(bool IcmpResult,Variable * Dest,const Inst * Consumer)3569*03ce13f7SAndroid Build Coastguard Worker void TargetX8632::movOrConsumer(bool IcmpResult, Variable *Dest,
3570*03ce13f7SAndroid Build Coastguard Worker const Inst *Consumer) {
3571*03ce13f7SAndroid Build Coastguard Worker if (Consumer == nullptr) {
3572*03ce13f7SAndroid Build Coastguard Worker _mov(Dest, Ctx->getConstantInt(Dest->getType(), (IcmpResult ? 1 : 0)));
3573*03ce13f7SAndroid Build Coastguard Worker return;
3574*03ce13f7SAndroid Build Coastguard Worker }
3575*03ce13f7SAndroid Build Coastguard Worker if (const auto *Br = llvm::dyn_cast<InstBr>(Consumer)) {
3576*03ce13f7SAndroid Build Coastguard Worker // TODO(sehr,stichnot): This could be done with a single unconditional
3577*03ce13f7SAndroid Build Coastguard Worker // branch instruction, but subzero doesn't know how to handle the resulting
3578*03ce13f7SAndroid Build Coastguard Worker // control flow graph changes now. Make it do so to eliminate mov and cmp.
3579*03ce13f7SAndroid Build Coastguard Worker _mov(Dest, Ctx->getConstantInt(Dest->getType(), (IcmpResult ? 1 : 0)));
3580*03ce13f7SAndroid Build Coastguard Worker _cmp(Dest, Ctx->getConstantInt(Dest->getType(), 0));
3581*03ce13f7SAndroid Build Coastguard Worker _br(CondX86::Br_ne, Br->getTargetTrue(), Br->getTargetFalse());
3582*03ce13f7SAndroid Build Coastguard Worker return;
3583*03ce13f7SAndroid Build Coastguard Worker }
3584*03ce13f7SAndroid Build Coastguard Worker if (const auto *Select = llvm::dyn_cast<InstSelect>(Consumer)) {
3585*03ce13f7SAndroid Build Coastguard Worker Operand *Src = nullptr;
3586*03ce13f7SAndroid Build Coastguard Worker if (IcmpResult) {
3587*03ce13f7SAndroid Build Coastguard Worker Src = legalize(Select->getTrueOperand(), Legal_Reg | Legal_Imm);
3588*03ce13f7SAndroid Build Coastguard Worker } else {
3589*03ce13f7SAndroid Build Coastguard Worker Src = legalize(Select->getFalseOperand(), Legal_Reg | Legal_Imm);
3590*03ce13f7SAndroid Build Coastguard Worker }
3591*03ce13f7SAndroid Build Coastguard Worker Variable *SelectDest = Select->getDest();
3592*03ce13f7SAndroid Build Coastguard Worker lowerMove(SelectDest, Src, false);
3593*03ce13f7SAndroid Build Coastguard Worker return;
3594*03ce13f7SAndroid Build Coastguard Worker }
3595*03ce13f7SAndroid Build Coastguard Worker llvm::report_fatal_error("Unexpected consumer type");
3596*03ce13f7SAndroid Build Coastguard Worker }
3597*03ce13f7SAndroid Build Coastguard Worker
lowerArithAndConsumer(const InstArithmetic * Arith,const Inst * Consumer)3598*03ce13f7SAndroid Build Coastguard Worker void TargetX8632::lowerArithAndConsumer(const InstArithmetic *Arith,
3599*03ce13f7SAndroid Build Coastguard Worker const Inst *Consumer) {
3600*03ce13f7SAndroid Build Coastguard Worker Variable *T = nullptr;
3601*03ce13f7SAndroid Build Coastguard Worker Operand *Src0 = legalize(Arith->getSrc(0));
3602*03ce13f7SAndroid Build Coastguard Worker Operand *Src1 = legalize(Arith->getSrc(1));
3603*03ce13f7SAndroid Build Coastguard Worker Variable *Dest = Arith->getDest();
3604*03ce13f7SAndroid Build Coastguard Worker switch (Arith->getOp()) {
3605*03ce13f7SAndroid Build Coastguard Worker default:
3606*03ce13f7SAndroid Build Coastguard Worker llvm_unreachable("arithmetic operator not AND or OR");
3607*03ce13f7SAndroid Build Coastguard Worker break;
3608*03ce13f7SAndroid Build Coastguard Worker case InstArithmetic::And:
3609*03ce13f7SAndroid Build Coastguard Worker _mov(T, Src0);
3610*03ce13f7SAndroid Build Coastguard Worker // Test cannot have an address in the second position. Since T is
3611*03ce13f7SAndroid Build Coastguard Worker // guaranteed to be a register and Src1 could be a memory load, ensure
3612*03ce13f7SAndroid Build Coastguard Worker // that the second argument is a register.
3613*03ce13f7SAndroid Build Coastguard Worker if (llvm::isa<Constant>(Src1))
3614*03ce13f7SAndroid Build Coastguard Worker _test(T, Src1);
3615*03ce13f7SAndroid Build Coastguard Worker else
3616*03ce13f7SAndroid Build Coastguard Worker _test(Src1, T);
3617*03ce13f7SAndroid Build Coastguard Worker break;
3618*03ce13f7SAndroid Build Coastguard Worker case InstArithmetic::Or:
3619*03ce13f7SAndroid Build Coastguard Worker _mov(T, Src0);
3620*03ce13f7SAndroid Build Coastguard Worker _or(T, Src1);
3621*03ce13f7SAndroid Build Coastguard Worker break;
3622*03ce13f7SAndroid Build Coastguard Worker }
3623*03ce13f7SAndroid Build Coastguard Worker
3624*03ce13f7SAndroid Build Coastguard Worker if (Consumer == nullptr) {
3625*03ce13f7SAndroid Build Coastguard Worker llvm::report_fatal_error("Expected a consumer instruction");
3626*03ce13f7SAndroid Build Coastguard Worker }
3627*03ce13f7SAndroid Build Coastguard Worker if (const auto *Br = llvm::dyn_cast<InstBr>(Consumer)) {
3628*03ce13f7SAndroid Build Coastguard Worker Context.insert<InstFakeUse>(T);
3629*03ce13f7SAndroid Build Coastguard Worker Context.insert<InstFakeDef>(Dest);
3630*03ce13f7SAndroid Build Coastguard Worker _br(CondX86::Br_ne, Br->getTargetTrue(), Br->getTargetFalse());
3631*03ce13f7SAndroid Build Coastguard Worker return;
3632*03ce13f7SAndroid Build Coastguard Worker }
3633*03ce13f7SAndroid Build Coastguard Worker llvm::report_fatal_error("Unexpected consumer type");
3634*03ce13f7SAndroid Build Coastguard Worker }
3635*03ce13f7SAndroid Build Coastguard Worker
lowerInsertElement(const InstInsertElement * Instr)3636*03ce13f7SAndroid Build Coastguard Worker void TargetX8632::lowerInsertElement(const InstInsertElement *Instr) {
3637*03ce13f7SAndroid Build Coastguard Worker Operand *SourceVectNotLegalized = Instr->getSrc(0);
3638*03ce13f7SAndroid Build Coastguard Worker Operand *ElementToInsertNotLegalized = Instr->getSrc(1);
3639*03ce13f7SAndroid Build Coastguard Worker auto *ElementIndex = llvm::dyn_cast<ConstantInteger32>(Instr->getSrc(2));
3640*03ce13f7SAndroid Build Coastguard Worker // Only constant indices are allowed in PNaCl IR.
3641*03ce13f7SAndroid Build Coastguard Worker assert(ElementIndex);
3642*03ce13f7SAndroid Build Coastguard Worker unsigned Index = ElementIndex->getValue();
3643*03ce13f7SAndroid Build Coastguard Worker assert(Index < typeNumElements(SourceVectNotLegalized->getType()));
3644*03ce13f7SAndroid Build Coastguard Worker
3645*03ce13f7SAndroid Build Coastguard Worker Type Ty = SourceVectNotLegalized->getType();
3646*03ce13f7SAndroid Build Coastguard Worker Type ElementTy = typeElementType(Ty);
3647*03ce13f7SAndroid Build Coastguard Worker Type InVectorElementTy = InstX86Base::getInVectorElementType(Ty);
3648*03ce13f7SAndroid Build Coastguard Worker
3649*03ce13f7SAndroid Build Coastguard Worker if (ElementTy == IceType_i1) {
3650*03ce13f7SAndroid Build Coastguard Worker // Expand the element to the appropriate size for it to be inserted in the
3651*03ce13f7SAndroid Build Coastguard Worker // vector.
3652*03ce13f7SAndroid Build Coastguard Worker Variable *Expanded = Func->makeVariable(InVectorElementTy);
3653*03ce13f7SAndroid Build Coastguard Worker auto *Cast = InstCast::create(Func, InstCast::Zext, Expanded,
3654*03ce13f7SAndroid Build Coastguard Worker ElementToInsertNotLegalized);
3655*03ce13f7SAndroid Build Coastguard Worker lowerCast(Cast);
3656*03ce13f7SAndroid Build Coastguard Worker ElementToInsertNotLegalized = Expanded;
3657*03ce13f7SAndroid Build Coastguard Worker }
3658*03ce13f7SAndroid Build Coastguard Worker
3659*03ce13f7SAndroid Build Coastguard Worker if (Ty == IceType_v8i16 || Ty == IceType_v8i1 || InstructionSet >= SSE4_1) {
3660*03ce13f7SAndroid Build Coastguard Worker // Use insertps, pinsrb, pinsrw, or pinsrd.
3661*03ce13f7SAndroid Build Coastguard Worker Operand *ElementRM =
3662*03ce13f7SAndroid Build Coastguard Worker legalize(ElementToInsertNotLegalized, Legal_Reg | Legal_Mem);
3663*03ce13f7SAndroid Build Coastguard Worker Operand *SourceVectRM =
3664*03ce13f7SAndroid Build Coastguard Worker legalize(SourceVectNotLegalized, Legal_Reg | Legal_Mem);
3665*03ce13f7SAndroid Build Coastguard Worker Variable *T = makeReg(Ty);
3666*03ce13f7SAndroid Build Coastguard Worker _movp(T, SourceVectRM);
3667*03ce13f7SAndroid Build Coastguard Worker if (Ty == IceType_v4f32) {
3668*03ce13f7SAndroid Build Coastguard Worker _insertps(T, ElementRM, Ctx->getConstantInt32(Index << 4));
3669*03ce13f7SAndroid Build Coastguard Worker } else {
3670*03ce13f7SAndroid Build Coastguard Worker // For the pinsrb and pinsrw instructions, when the source operand is a
3671*03ce13f7SAndroid Build Coastguard Worker // register, it must be a full r32 register like eax, and not ax/al/ah.
3672*03ce13f7SAndroid Build Coastguard Worker // For filetype=asm, InstX86Pinsr::emit() compensates for
3673*03ce13f7SAndroid Build Coastguard Worker // the use
3674*03ce13f7SAndroid Build Coastguard Worker // of r16 and r8 by converting them through getBaseReg(), while emitIAS()
3675*03ce13f7SAndroid Build Coastguard Worker // validates that the original and base register encodings are the same.
3676*03ce13f7SAndroid Build Coastguard Worker if (ElementRM->getType() == IceType_i8 &&
3677*03ce13f7SAndroid Build Coastguard Worker llvm::isa<Variable>(ElementRM)) {
3678*03ce13f7SAndroid Build Coastguard Worker // Don't use ah/bh/ch/dh for pinsrb.
3679*03ce13f7SAndroid Build Coastguard Worker ElementRM = copyToReg8(ElementRM);
3680*03ce13f7SAndroid Build Coastguard Worker }
3681*03ce13f7SAndroid Build Coastguard Worker _pinsr(T, ElementRM, Ctx->getConstantInt32(Index));
3682*03ce13f7SAndroid Build Coastguard Worker }
3683*03ce13f7SAndroid Build Coastguard Worker _movp(Instr->getDest(), T);
3684*03ce13f7SAndroid Build Coastguard Worker } else if (Ty == IceType_v4i32 || Ty == IceType_v4f32 || Ty == IceType_v4i1) {
3685*03ce13f7SAndroid Build Coastguard Worker // Use shufps or movss.
3686*03ce13f7SAndroid Build Coastguard Worker Variable *ElementR = nullptr;
3687*03ce13f7SAndroid Build Coastguard Worker Operand *SourceVectRM =
3688*03ce13f7SAndroid Build Coastguard Worker legalize(SourceVectNotLegalized, Legal_Reg | Legal_Mem);
3689*03ce13f7SAndroid Build Coastguard Worker
3690*03ce13f7SAndroid Build Coastguard Worker if (InVectorElementTy == IceType_f32) {
3691*03ce13f7SAndroid Build Coastguard Worker // ElementR will be in an XMM register since it is floating point.
3692*03ce13f7SAndroid Build Coastguard Worker ElementR = legalizeToReg(ElementToInsertNotLegalized);
3693*03ce13f7SAndroid Build Coastguard Worker } else {
3694*03ce13f7SAndroid Build Coastguard Worker // Copy an integer to an XMM register.
3695*03ce13f7SAndroid Build Coastguard Worker Operand *T = legalize(ElementToInsertNotLegalized, Legal_Reg | Legal_Mem);
3696*03ce13f7SAndroid Build Coastguard Worker ElementR = makeReg(Ty);
3697*03ce13f7SAndroid Build Coastguard Worker _movd(ElementR, T);
3698*03ce13f7SAndroid Build Coastguard Worker }
3699*03ce13f7SAndroid Build Coastguard Worker
3700*03ce13f7SAndroid Build Coastguard Worker if (Index == 0) {
3701*03ce13f7SAndroid Build Coastguard Worker Variable *T = makeReg(Ty);
3702*03ce13f7SAndroid Build Coastguard Worker _movp(T, SourceVectRM);
3703*03ce13f7SAndroid Build Coastguard Worker _movss(T, ElementR);
3704*03ce13f7SAndroid Build Coastguard Worker _movp(Instr->getDest(), T);
3705*03ce13f7SAndroid Build Coastguard Worker return;
3706*03ce13f7SAndroid Build Coastguard Worker }
3707*03ce13f7SAndroid Build Coastguard Worker
3708*03ce13f7SAndroid Build Coastguard Worker // shufps treats the source and destination operands as vectors of four
3709*03ce13f7SAndroid Build Coastguard Worker // doublewords. The destination's two high doublewords are selected from
3710*03ce13f7SAndroid Build Coastguard Worker // the source operand and the two low doublewords are selected from the
3711*03ce13f7SAndroid Build Coastguard Worker // (original value of) the destination operand. An insertelement operation
3712*03ce13f7SAndroid Build Coastguard Worker // can be effected with a sequence of two shufps operations with
3713*03ce13f7SAndroid Build Coastguard Worker // appropriate masks. In all cases below, Element[0] is being inserted into
3714*03ce13f7SAndroid Build Coastguard Worker // SourceVectOperand. Indices are ordered from left to right.
3715*03ce13f7SAndroid Build Coastguard Worker //
3716*03ce13f7SAndroid Build Coastguard Worker // insertelement into index 1 (result is stored in ElementR):
3717*03ce13f7SAndroid Build Coastguard Worker // ElementR := ElementR[0, 0] SourceVectRM[0, 0]
3718*03ce13f7SAndroid Build Coastguard Worker // ElementR := ElementR[3, 0] SourceVectRM[2, 3]
3719*03ce13f7SAndroid Build Coastguard Worker //
3720*03ce13f7SAndroid Build Coastguard Worker // insertelement into index 2 (result is stored in T):
3721*03ce13f7SAndroid Build Coastguard Worker // T := SourceVectRM
3722*03ce13f7SAndroid Build Coastguard Worker // ElementR := ElementR[0, 0] T[0, 3]
3723*03ce13f7SAndroid Build Coastguard Worker // T := T[0, 1] ElementR[0, 3]
3724*03ce13f7SAndroid Build Coastguard Worker //
3725*03ce13f7SAndroid Build Coastguard Worker // insertelement into index 3 (result is stored in T):
3726*03ce13f7SAndroid Build Coastguard Worker // T := SourceVectRM
3727*03ce13f7SAndroid Build Coastguard Worker // ElementR := ElementR[0, 0] T[0, 2]
3728*03ce13f7SAndroid Build Coastguard Worker // T := T[0, 1] ElementR[3, 0]
3729*03ce13f7SAndroid Build Coastguard Worker const unsigned char Mask1[3] = {0, 192, 128};
3730*03ce13f7SAndroid Build Coastguard Worker const unsigned char Mask2[3] = {227, 196, 52};
3731*03ce13f7SAndroid Build Coastguard Worker
3732*03ce13f7SAndroid Build Coastguard Worker Constant *Mask1Constant = Ctx->getConstantInt32(Mask1[Index - 1]);
3733*03ce13f7SAndroid Build Coastguard Worker Constant *Mask2Constant = Ctx->getConstantInt32(Mask2[Index - 1]);
3734*03ce13f7SAndroid Build Coastguard Worker
3735*03ce13f7SAndroid Build Coastguard Worker if (Index == 1) {
3736*03ce13f7SAndroid Build Coastguard Worker _shufps(ElementR, SourceVectRM, Mask1Constant);
3737*03ce13f7SAndroid Build Coastguard Worker _shufps(ElementR, SourceVectRM, Mask2Constant);
3738*03ce13f7SAndroid Build Coastguard Worker _movp(Instr->getDest(), ElementR);
3739*03ce13f7SAndroid Build Coastguard Worker } else {
3740*03ce13f7SAndroid Build Coastguard Worker Variable *T = makeReg(Ty);
3741*03ce13f7SAndroid Build Coastguard Worker _movp(T, SourceVectRM);
3742*03ce13f7SAndroid Build Coastguard Worker _shufps(ElementR, T, Mask1Constant);
3743*03ce13f7SAndroid Build Coastguard Worker _shufps(T, ElementR, Mask2Constant);
3744*03ce13f7SAndroid Build Coastguard Worker _movp(Instr->getDest(), T);
3745*03ce13f7SAndroid Build Coastguard Worker }
3746*03ce13f7SAndroid Build Coastguard Worker } else {
3747*03ce13f7SAndroid Build Coastguard Worker assert(Ty == IceType_v16i8 || Ty == IceType_v16i1);
3748*03ce13f7SAndroid Build Coastguard Worker // Spill the value to a stack slot and perform the insertion in memory.
3749*03ce13f7SAndroid Build Coastguard Worker //
3750*03ce13f7SAndroid Build Coastguard Worker // TODO(wala): use legalize(SourceVectNotLegalized, Legal_Mem) when support
3751*03ce13f7SAndroid Build Coastguard Worker // for legalizing to mem is implemented.
3752*03ce13f7SAndroid Build Coastguard Worker Variable *Slot = Func->makeVariable(Ty);
3753*03ce13f7SAndroid Build Coastguard Worker Slot->setMustNotHaveReg();
3754*03ce13f7SAndroid Build Coastguard Worker _movp(Slot, legalizeToReg(SourceVectNotLegalized));
3755*03ce13f7SAndroid Build Coastguard Worker
3756*03ce13f7SAndroid Build Coastguard Worker // Compute the location of the position to insert in memory.
3757*03ce13f7SAndroid Build Coastguard Worker unsigned Offset = Index * typeWidthInBytes(InVectorElementTy);
3758*03ce13f7SAndroid Build Coastguard Worker X86OperandMem *Loc =
3759*03ce13f7SAndroid Build Coastguard Worker getMemoryOperandForStackSlot(InVectorElementTy, Slot, Offset);
3760*03ce13f7SAndroid Build Coastguard Worker _store(legalizeToReg(ElementToInsertNotLegalized), Loc);
3761*03ce13f7SAndroid Build Coastguard Worker
3762*03ce13f7SAndroid Build Coastguard Worker Variable *T = makeReg(Ty);
3763*03ce13f7SAndroid Build Coastguard Worker _movp(T, Slot);
3764*03ce13f7SAndroid Build Coastguard Worker _movp(Instr->getDest(), T);
3765*03ce13f7SAndroid Build Coastguard Worker }
3766*03ce13f7SAndroid Build Coastguard Worker }
3767*03ce13f7SAndroid Build Coastguard Worker
lowerIntrinsic(const InstIntrinsic * Instr)3768*03ce13f7SAndroid Build Coastguard Worker void TargetX8632::lowerIntrinsic(const InstIntrinsic *Instr) {
3769*03ce13f7SAndroid Build Coastguard Worker switch (Intrinsics::IntrinsicID ID = Instr->getIntrinsicID()) {
3770*03ce13f7SAndroid Build Coastguard Worker case Intrinsics::AtomicCmpxchg: {
3771*03ce13f7SAndroid Build Coastguard Worker if (!Intrinsics::isMemoryOrderValid(
3772*03ce13f7SAndroid Build Coastguard Worker ID, getConstantMemoryOrder(Instr->getArg(3)),
3773*03ce13f7SAndroid Build Coastguard Worker getConstantMemoryOrder(Instr->getArg(4)))) {
3774*03ce13f7SAndroid Build Coastguard Worker Func->setError("Unexpected memory ordering for AtomicCmpxchg");
3775*03ce13f7SAndroid Build Coastguard Worker return;
3776*03ce13f7SAndroid Build Coastguard Worker }
3777*03ce13f7SAndroid Build Coastguard Worker Variable *DestPrev = Instr->getDest();
3778*03ce13f7SAndroid Build Coastguard Worker Operand *PtrToMem = legalize(Instr->getArg(0));
3779*03ce13f7SAndroid Build Coastguard Worker Operand *Expected = legalize(Instr->getArg(1));
3780*03ce13f7SAndroid Build Coastguard Worker Operand *Desired = legalize(Instr->getArg(2));
3781*03ce13f7SAndroid Build Coastguard Worker if (tryOptimizedCmpxchgCmpBr(DestPrev, PtrToMem, Expected, Desired))
3782*03ce13f7SAndroid Build Coastguard Worker return;
3783*03ce13f7SAndroid Build Coastguard Worker lowerAtomicCmpxchg(DestPrev, PtrToMem, Expected, Desired);
3784*03ce13f7SAndroid Build Coastguard Worker return;
3785*03ce13f7SAndroid Build Coastguard Worker }
3786*03ce13f7SAndroid Build Coastguard Worker case Intrinsics::AtomicFence:
3787*03ce13f7SAndroid Build Coastguard Worker if (!Intrinsics::isMemoryOrderValid(
3788*03ce13f7SAndroid Build Coastguard Worker ID, getConstantMemoryOrder(Instr->getArg(0)))) {
3789*03ce13f7SAndroid Build Coastguard Worker Func->setError("Unexpected memory ordering for AtomicFence");
3790*03ce13f7SAndroid Build Coastguard Worker return;
3791*03ce13f7SAndroid Build Coastguard Worker }
3792*03ce13f7SAndroid Build Coastguard Worker _mfence();
3793*03ce13f7SAndroid Build Coastguard Worker return;
3794*03ce13f7SAndroid Build Coastguard Worker case Intrinsics::AtomicFenceAll:
3795*03ce13f7SAndroid Build Coastguard Worker // NOTE: FenceAll should prevent and load/store from being moved across the
3796*03ce13f7SAndroid Build Coastguard Worker // fence (both atomic and non-atomic). The InstX8632Mfence instruction is
3797*03ce13f7SAndroid Build Coastguard Worker // currently marked coarsely as "HasSideEffects".
3798*03ce13f7SAndroid Build Coastguard Worker _mfence();
3799*03ce13f7SAndroid Build Coastguard Worker return;
3800*03ce13f7SAndroid Build Coastguard Worker case Intrinsics::AtomicIsLockFree: {
3801*03ce13f7SAndroid Build Coastguard Worker // X86 is always lock free for 8/16/32/64 bit accesses.
3802*03ce13f7SAndroid Build Coastguard Worker // TODO(jvoung): Since the result is constant when given a constant byte
3803*03ce13f7SAndroid Build Coastguard Worker // size, this opens up DCE opportunities.
3804*03ce13f7SAndroid Build Coastguard Worker Operand *ByteSize = Instr->getArg(0);
3805*03ce13f7SAndroid Build Coastguard Worker Variable *Dest = Instr->getDest();
3806*03ce13f7SAndroid Build Coastguard Worker if (auto *CI = llvm::dyn_cast<ConstantInteger32>(ByteSize)) {
3807*03ce13f7SAndroid Build Coastguard Worker Constant *Result;
3808*03ce13f7SAndroid Build Coastguard Worker switch (CI->getValue()) {
3809*03ce13f7SAndroid Build Coastguard Worker default:
3810*03ce13f7SAndroid Build Coastguard Worker // Some x86-64 processors support the cmpxchg16b instruction, which can
3811*03ce13f7SAndroid Build Coastguard Worker // make 16-byte operations lock free (when used with the LOCK prefix).
3812*03ce13f7SAndroid Build Coastguard Worker // However, that's not supported in 32-bit mode, so just return 0 even
3813*03ce13f7SAndroid Build Coastguard Worker // for large sizes.
3814*03ce13f7SAndroid Build Coastguard Worker Result = Ctx->getConstantZero(IceType_i32);
3815*03ce13f7SAndroid Build Coastguard Worker break;
3816*03ce13f7SAndroid Build Coastguard Worker case 1:
3817*03ce13f7SAndroid Build Coastguard Worker case 2:
3818*03ce13f7SAndroid Build Coastguard Worker case 4:
3819*03ce13f7SAndroid Build Coastguard Worker case 8:
3820*03ce13f7SAndroid Build Coastguard Worker Result = Ctx->getConstantInt32(1);
3821*03ce13f7SAndroid Build Coastguard Worker break;
3822*03ce13f7SAndroid Build Coastguard Worker }
3823*03ce13f7SAndroid Build Coastguard Worker _mov(Dest, Result);
3824*03ce13f7SAndroid Build Coastguard Worker return;
3825*03ce13f7SAndroid Build Coastguard Worker }
3826*03ce13f7SAndroid Build Coastguard Worker // The PNaCl ABI requires the byte size to be a compile-time constant.
3827*03ce13f7SAndroid Build Coastguard Worker Func->setError("AtomicIsLockFree byte size should be compile-time const");
3828*03ce13f7SAndroid Build Coastguard Worker return;
3829*03ce13f7SAndroid Build Coastguard Worker }
3830*03ce13f7SAndroid Build Coastguard Worker case Intrinsics::AtomicLoad: {
3831*03ce13f7SAndroid Build Coastguard Worker // We require the memory address to be naturally aligned. Given that is the
3832*03ce13f7SAndroid Build Coastguard Worker // case, then normal loads are atomic.
3833*03ce13f7SAndroid Build Coastguard Worker if (!Intrinsics::isMemoryOrderValid(
3834*03ce13f7SAndroid Build Coastguard Worker ID, getConstantMemoryOrder(Instr->getArg(1)))) {
3835*03ce13f7SAndroid Build Coastguard Worker Func->setError("Unexpected memory ordering for AtomicLoad");
3836*03ce13f7SAndroid Build Coastguard Worker return;
3837*03ce13f7SAndroid Build Coastguard Worker }
3838*03ce13f7SAndroid Build Coastguard Worker Variable *Dest = Instr->getDest();
3839*03ce13f7SAndroid Build Coastguard Worker if (auto *Dest64On32 = llvm::dyn_cast<Variable64On32>(Dest)) {
3840*03ce13f7SAndroid Build Coastguard Worker // Follow what GCC does and use a movq instead of what lowerLoad()
3841*03ce13f7SAndroid Build Coastguard Worker // normally does (split the load into two). Thus, this skips
3842*03ce13f7SAndroid Build Coastguard Worker // load/arithmetic op folding. Load/arithmetic folding can't happen
3843*03ce13f7SAndroid Build Coastguard Worker // anyway, since this is x86-32 and integer arithmetic only happens on
3844*03ce13f7SAndroid Build Coastguard Worker // 32-bit quantities.
3845*03ce13f7SAndroid Build Coastguard Worker Variable *T = makeReg(IceType_f64);
3846*03ce13f7SAndroid Build Coastguard Worker X86OperandMem *Addr = formMemoryOperand(Instr->getArg(0), IceType_f64);
3847*03ce13f7SAndroid Build Coastguard Worker _movq(T, Addr);
3848*03ce13f7SAndroid Build Coastguard Worker // Then cast the bits back out of the XMM register to the i64 Dest.
3849*03ce13f7SAndroid Build Coastguard Worker auto *Cast = InstCast::create(Func, InstCast::Bitcast, Dest, T);
3850*03ce13f7SAndroid Build Coastguard Worker lowerCast(Cast);
3851*03ce13f7SAndroid Build Coastguard Worker // Make sure that the atomic load isn't elided when unused.
3852*03ce13f7SAndroid Build Coastguard Worker Context.insert<InstFakeUse>(Dest64On32->getLo());
3853*03ce13f7SAndroid Build Coastguard Worker Context.insert<InstFakeUse>(Dest64On32->getHi());
3854*03ce13f7SAndroid Build Coastguard Worker return;
3855*03ce13f7SAndroid Build Coastguard Worker }
3856*03ce13f7SAndroid Build Coastguard Worker auto *Load = InstLoad::create(Func, Dest, Instr->getArg(0));
3857*03ce13f7SAndroid Build Coastguard Worker lowerLoad(Load);
3858*03ce13f7SAndroid Build Coastguard Worker // Make sure the atomic load isn't elided when unused, by adding a FakeUse.
3859*03ce13f7SAndroid Build Coastguard Worker // Since lowerLoad may fuse the load w/ an arithmetic instruction, insert
3860*03ce13f7SAndroid Build Coastguard Worker // the FakeUse on the last-inserted instruction's dest.
3861*03ce13f7SAndroid Build Coastguard Worker Context.insert<InstFakeUse>(Context.getLastInserted()->getDest());
3862*03ce13f7SAndroid Build Coastguard Worker return;
3863*03ce13f7SAndroid Build Coastguard Worker }
3864*03ce13f7SAndroid Build Coastguard Worker case Intrinsics::AtomicRMW:
3865*03ce13f7SAndroid Build Coastguard Worker if (!Intrinsics::isMemoryOrderValid(
3866*03ce13f7SAndroid Build Coastguard Worker ID, getConstantMemoryOrder(Instr->getArg(3)))) {
3867*03ce13f7SAndroid Build Coastguard Worker Func->setError("Unexpected memory ordering for AtomicRMW");
3868*03ce13f7SAndroid Build Coastguard Worker return;
3869*03ce13f7SAndroid Build Coastguard Worker }
3870*03ce13f7SAndroid Build Coastguard Worker lowerAtomicRMW(
3871*03ce13f7SAndroid Build Coastguard Worker Instr->getDest(),
3872*03ce13f7SAndroid Build Coastguard Worker static_cast<uint32_t>(
3873*03ce13f7SAndroid Build Coastguard Worker llvm::cast<ConstantInteger32>(Instr->getArg(0))->getValue()),
3874*03ce13f7SAndroid Build Coastguard Worker Instr->getArg(1), Instr->getArg(2));
3875*03ce13f7SAndroid Build Coastguard Worker return;
3876*03ce13f7SAndroid Build Coastguard Worker case Intrinsics::AtomicStore: {
3877*03ce13f7SAndroid Build Coastguard Worker if (!Intrinsics::isMemoryOrderValid(
3878*03ce13f7SAndroid Build Coastguard Worker ID, getConstantMemoryOrder(Instr->getArg(2)))) {
3879*03ce13f7SAndroid Build Coastguard Worker Func->setError("Unexpected memory ordering for AtomicStore");
3880*03ce13f7SAndroid Build Coastguard Worker return;
3881*03ce13f7SAndroid Build Coastguard Worker }
3882*03ce13f7SAndroid Build Coastguard Worker // We require the memory address to be naturally aligned. Given that is the
3883*03ce13f7SAndroid Build Coastguard Worker // case, then normal stores are atomic. Add a fence after the store to make
3884*03ce13f7SAndroid Build Coastguard Worker // it visible.
3885*03ce13f7SAndroid Build Coastguard Worker Operand *Value = Instr->getArg(0);
3886*03ce13f7SAndroid Build Coastguard Worker Operand *Ptr = Instr->getArg(1);
3887*03ce13f7SAndroid Build Coastguard Worker if (Value->getType() == IceType_i64) {
3888*03ce13f7SAndroid Build Coastguard Worker // Use a movq instead of what lowerStore() normally does (split the store
3889*03ce13f7SAndroid Build Coastguard Worker // into two), following what GCC does. Cast the bits from int -> to an
3890*03ce13f7SAndroid Build Coastguard Worker // xmm register first.
3891*03ce13f7SAndroid Build Coastguard Worker Variable *T = makeReg(IceType_f64);
3892*03ce13f7SAndroid Build Coastguard Worker auto *Cast = InstCast::create(Func, InstCast::Bitcast, T, Value);
3893*03ce13f7SAndroid Build Coastguard Worker lowerCast(Cast);
3894*03ce13f7SAndroid Build Coastguard Worker // Then store XMM w/ a movq.
3895*03ce13f7SAndroid Build Coastguard Worker X86OperandMem *Addr = formMemoryOperand(Ptr, IceType_f64);
3896*03ce13f7SAndroid Build Coastguard Worker _storeq(T, Addr);
3897*03ce13f7SAndroid Build Coastguard Worker _mfence();
3898*03ce13f7SAndroid Build Coastguard Worker return;
3899*03ce13f7SAndroid Build Coastguard Worker }
3900*03ce13f7SAndroid Build Coastguard Worker auto *Store = InstStore::create(Func, Value, Ptr);
3901*03ce13f7SAndroid Build Coastguard Worker lowerStore(Store);
3902*03ce13f7SAndroid Build Coastguard Worker _mfence();
3903*03ce13f7SAndroid Build Coastguard Worker return;
3904*03ce13f7SAndroid Build Coastguard Worker }
3905*03ce13f7SAndroid Build Coastguard Worker case Intrinsics::Bswap: {
3906*03ce13f7SAndroid Build Coastguard Worker Variable *Dest = Instr->getDest();
3907*03ce13f7SAndroid Build Coastguard Worker Operand *Val = Instr->getArg(0);
3908*03ce13f7SAndroid Build Coastguard Worker // In 32-bit mode, bswap only works on 32-bit arguments, and the argument
3909*03ce13f7SAndroid Build Coastguard Worker // must be a register. Use rotate left for 16-bit bswap.
3910*03ce13f7SAndroid Build Coastguard Worker if (Val->getType() == IceType_i64) {
3911*03ce13f7SAndroid Build Coastguard Worker Val = legalizeUndef(Val);
3912*03ce13f7SAndroid Build Coastguard Worker Variable *T_Lo = legalizeToReg(loOperand(Val));
3913*03ce13f7SAndroid Build Coastguard Worker Variable *T_Hi = legalizeToReg(hiOperand(Val));
3914*03ce13f7SAndroid Build Coastguard Worker auto *DestLo = llvm::cast<Variable>(loOperand(Dest));
3915*03ce13f7SAndroid Build Coastguard Worker auto *DestHi = llvm::cast<Variable>(hiOperand(Dest));
3916*03ce13f7SAndroid Build Coastguard Worker _bswap(T_Lo);
3917*03ce13f7SAndroid Build Coastguard Worker _bswap(T_Hi);
3918*03ce13f7SAndroid Build Coastguard Worker _mov(DestLo, T_Hi);
3919*03ce13f7SAndroid Build Coastguard Worker _mov(DestHi, T_Lo);
3920*03ce13f7SAndroid Build Coastguard Worker } else if (Val->getType() == IceType_i32) {
3921*03ce13f7SAndroid Build Coastguard Worker Variable *T = legalizeToReg(Val);
3922*03ce13f7SAndroid Build Coastguard Worker _bswap(T);
3923*03ce13f7SAndroid Build Coastguard Worker _mov(Dest, T);
3924*03ce13f7SAndroid Build Coastguard Worker } else {
3925*03ce13f7SAndroid Build Coastguard Worker assert(Val->getType() == IceType_i16);
3926*03ce13f7SAndroid Build Coastguard Worker Constant *Eight = Ctx->getConstantInt16(8);
3927*03ce13f7SAndroid Build Coastguard Worker Variable *T = nullptr;
3928*03ce13f7SAndroid Build Coastguard Worker Val = legalize(Val);
3929*03ce13f7SAndroid Build Coastguard Worker _mov(T, Val);
3930*03ce13f7SAndroid Build Coastguard Worker _rol(T, Eight);
3931*03ce13f7SAndroid Build Coastguard Worker _mov(Dest, T);
3932*03ce13f7SAndroid Build Coastguard Worker }
3933*03ce13f7SAndroid Build Coastguard Worker return;
3934*03ce13f7SAndroid Build Coastguard Worker }
3935*03ce13f7SAndroid Build Coastguard Worker case Intrinsics::Ctpop: {
3936*03ce13f7SAndroid Build Coastguard Worker Variable *Dest = Instr->getDest();
3937*03ce13f7SAndroid Build Coastguard Worker Operand *Val = Instr->getArg(0);
3938*03ce13f7SAndroid Build Coastguard Worker Type ValTy = Val->getType();
3939*03ce13f7SAndroid Build Coastguard Worker assert(ValTy == IceType_i32 || ValTy == IceType_i64);
3940*03ce13f7SAndroid Build Coastguard Worker
3941*03ce13f7SAndroid Build Coastguard Worker InstCall *Call =
3942*03ce13f7SAndroid Build Coastguard Worker makeHelperCall(ValTy == IceType_i32 ? RuntimeHelper::H_call_ctpop_i32
3943*03ce13f7SAndroid Build Coastguard Worker : RuntimeHelper::H_call_ctpop_i64,
3944*03ce13f7SAndroid Build Coastguard Worker Dest, 1);
3945*03ce13f7SAndroid Build Coastguard Worker Call->addArg(Val);
3946*03ce13f7SAndroid Build Coastguard Worker lowerCall(Call);
3947*03ce13f7SAndroid Build Coastguard Worker // The popcount helpers always return 32-bit values, while the intrinsic's
3948*03ce13f7SAndroid Build Coastguard Worker // signature matches the native POPCNT instruction and fills a 64-bit reg
3949*03ce13f7SAndroid Build Coastguard Worker // (in 64-bit mode). Thus, clear the upper bits of the dest just in case
3950*03ce13f7SAndroid Build Coastguard Worker // the user doesn't do that in the IR. If the user does that in the IR,
3951*03ce13f7SAndroid Build Coastguard Worker // then this zero'ing instruction is dead and gets optimized out.
3952*03ce13f7SAndroid Build Coastguard Worker if (Val->getType() == IceType_i64) {
3953*03ce13f7SAndroid Build Coastguard Worker auto *DestHi = llvm::cast<Variable>(hiOperand(Dest));
3954*03ce13f7SAndroid Build Coastguard Worker Constant *Zero = Ctx->getConstantZero(IceType_i32);
3955*03ce13f7SAndroid Build Coastguard Worker _mov(DestHi, Zero);
3956*03ce13f7SAndroid Build Coastguard Worker }
3957*03ce13f7SAndroid Build Coastguard Worker return;
3958*03ce13f7SAndroid Build Coastguard Worker }
3959*03ce13f7SAndroid Build Coastguard Worker case Intrinsics::Ctlz: {
3960*03ce13f7SAndroid Build Coastguard Worker // The "is zero undef" parameter is ignored and we always return a
3961*03ce13f7SAndroid Build Coastguard Worker // well-defined value.
3962*03ce13f7SAndroid Build Coastguard Worker Operand *Val = legalize(Instr->getArg(0));
3963*03ce13f7SAndroid Build Coastguard Worker Operand *FirstVal;
3964*03ce13f7SAndroid Build Coastguard Worker Operand *SecondVal = nullptr;
3965*03ce13f7SAndroid Build Coastguard Worker if (Val->getType() == IceType_i64) {
3966*03ce13f7SAndroid Build Coastguard Worker FirstVal = loOperand(Val);
3967*03ce13f7SAndroid Build Coastguard Worker SecondVal = hiOperand(Val);
3968*03ce13f7SAndroid Build Coastguard Worker } else {
3969*03ce13f7SAndroid Build Coastguard Worker FirstVal = Val;
3970*03ce13f7SAndroid Build Coastguard Worker }
3971*03ce13f7SAndroid Build Coastguard Worker constexpr bool IsCttz = false;
3972*03ce13f7SAndroid Build Coastguard Worker lowerCountZeros(IsCttz, Val->getType(), Instr->getDest(), FirstVal,
3973*03ce13f7SAndroid Build Coastguard Worker SecondVal);
3974*03ce13f7SAndroid Build Coastguard Worker return;
3975*03ce13f7SAndroid Build Coastguard Worker }
3976*03ce13f7SAndroid Build Coastguard Worker case Intrinsics::Cttz: {
3977*03ce13f7SAndroid Build Coastguard Worker // The "is zero undef" parameter is ignored and we always return a
3978*03ce13f7SAndroid Build Coastguard Worker // well-defined value.
3979*03ce13f7SAndroid Build Coastguard Worker Operand *Val = legalize(Instr->getArg(0));
3980*03ce13f7SAndroid Build Coastguard Worker Operand *FirstVal;
3981*03ce13f7SAndroid Build Coastguard Worker Operand *SecondVal = nullptr;
3982*03ce13f7SAndroid Build Coastguard Worker if (Val->getType() == IceType_i64) {
3983*03ce13f7SAndroid Build Coastguard Worker FirstVal = hiOperand(Val);
3984*03ce13f7SAndroid Build Coastguard Worker SecondVal = loOperand(Val);
3985*03ce13f7SAndroid Build Coastguard Worker } else {
3986*03ce13f7SAndroid Build Coastguard Worker FirstVal = Val;
3987*03ce13f7SAndroid Build Coastguard Worker }
3988*03ce13f7SAndroid Build Coastguard Worker constexpr bool IsCttz = true;
3989*03ce13f7SAndroid Build Coastguard Worker lowerCountZeros(IsCttz, Val->getType(), Instr->getDest(), FirstVal,
3990*03ce13f7SAndroid Build Coastguard Worker SecondVal);
3991*03ce13f7SAndroid Build Coastguard Worker return;
3992*03ce13f7SAndroid Build Coastguard Worker }
3993*03ce13f7SAndroid Build Coastguard Worker case Intrinsics::Fabs: {
3994*03ce13f7SAndroid Build Coastguard Worker Operand *Src = legalize(Instr->getArg(0));
3995*03ce13f7SAndroid Build Coastguard Worker Type Ty = Src->getType();
3996*03ce13f7SAndroid Build Coastguard Worker Variable *Dest = Instr->getDest();
3997*03ce13f7SAndroid Build Coastguard Worker Variable *T = makeVectorOfFabsMask(Ty);
3998*03ce13f7SAndroid Build Coastguard Worker // The pand instruction operates on an m128 memory operand, so if Src is an
3999*03ce13f7SAndroid Build Coastguard Worker // f32 or f64, we need to make sure it's in a register.
4000*03ce13f7SAndroid Build Coastguard Worker if (isVectorType(Ty)) {
4001*03ce13f7SAndroid Build Coastguard Worker if (llvm::isa<X86OperandMem>(Src))
4002*03ce13f7SAndroid Build Coastguard Worker Src = legalizeToReg(Src);
4003*03ce13f7SAndroid Build Coastguard Worker } else {
4004*03ce13f7SAndroid Build Coastguard Worker Src = legalizeToReg(Src);
4005*03ce13f7SAndroid Build Coastguard Worker }
4006*03ce13f7SAndroid Build Coastguard Worker _pand(T, Src);
4007*03ce13f7SAndroid Build Coastguard Worker if (isVectorType(Ty))
4008*03ce13f7SAndroid Build Coastguard Worker _movp(Dest, T);
4009*03ce13f7SAndroid Build Coastguard Worker else
4010*03ce13f7SAndroid Build Coastguard Worker _mov(Dest, T);
4011*03ce13f7SAndroid Build Coastguard Worker return;
4012*03ce13f7SAndroid Build Coastguard Worker }
4013*03ce13f7SAndroid Build Coastguard Worker case Intrinsics::Longjmp: {
4014*03ce13f7SAndroid Build Coastguard Worker InstCall *Call = makeHelperCall(RuntimeHelper::H_call_longjmp, nullptr, 2);
4015*03ce13f7SAndroid Build Coastguard Worker Call->addArg(Instr->getArg(0));
4016*03ce13f7SAndroid Build Coastguard Worker Call->addArg(Instr->getArg(1));
4017*03ce13f7SAndroid Build Coastguard Worker lowerCall(Call);
4018*03ce13f7SAndroid Build Coastguard Worker return;
4019*03ce13f7SAndroid Build Coastguard Worker }
4020*03ce13f7SAndroid Build Coastguard Worker case Intrinsics::Memcpy: {
4021*03ce13f7SAndroid Build Coastguard Worker lowerMemcpy(Instr->getArg(0), Instr->getArg(1), Instr->getArg(2));
4022*03ce13f7SAndroid Build Coastguard Worker return;
4023*03ce13f7SAndroid Build Coastguard Worker }
4024*03ce13f7SAndroid Build Coastguard Worker case Intrinsics::Memmove: {
4025*03ce13f7SAndroid Build Coastguard Worker lowerMemmove(Instr->getArg(0), Instr->getArg(1), Instr->getArg(2));
4026*03ce13f7SAndroid Build Coastguard Worker return;
4027*03ce13f7SAndroid Build Coastguard Worker }
4028*03ce13f7SAndroid Build Coastguard Worker case Intrinsics::Memset: {
4029*03ce13f7SAndroid Build Coastguard Worker lowerMemset(Instr->getArg(0), Instr->getArg(1), Instr->getArg(2));
4030*03ce13f7SAndroid Build Coastguard Worker return;
4031*03ce13f7SAndroid Build Coastguard Worker }
4032*03ce13f7SAndroid Build Coastguard Worker case Intrinsics::Setjmp: {
4033*03ce13f7SAndroid Build Coastguard Worker InstCall *Call =
4034*03ce13f7SAndroid Build Coastguard Worker makeHelperCall(RuntimeHelper::H_call_setjmp, Instr->getDest(), 1);
4035*03ce13f7SAndroid Build Coastguard Worker Call->addArg(Instr->getArg(0));
4036*03ce13f7SAndroid Build Coastguard Worker lowerCall(Call);
4037*03ce13f7SAndroid Build Coastguard Worker return;
4038*03ce13f7SAndroid Build Coastguard Worker }
4039*03ce13f7SAndroid Build Coastguard Worker case Intrinsics::Sqrt: {
4040*03ce13f7SAndroid Build Coastguard Worker Operand *Src = legalize(Instr->getArg(0));
4041*03ce13f7SAndroid Build Coastguard Worker Variable *Dest = Instr->getDest();
4042*03ce13f7SAndroid Build Coastguard Worker Variable *T = makeReg(Dest->getType());
4043*03ce13f7SAndroid Build Coastguard Worker _sqrt(T, Src);
4044*03ce13f7SAndroid Build Coastguard Worker if (isVectorType(Dest->getType())) {
4045*03ce13f7SAndroid Build Coastguard Worker _movp(Dest, T);
4046*03ce13f7SAndroid Build Coastguard Worker } else {
4047*03ce13f7SAndroid Build Coastguard Worker _mov(Dest, T);
4048*03ce13f7SAndroid Build Coastguard Worker }
4049*03ce13f7SAndroid Build Coastguard Worker return;
4050*03ce13f7SAndroid Build Coastguard Worker }
4051*03ce13f7SAndroid Build Coastguard Worker case Intrinsics::Stacksave: {
4052*03ce13f7SAndroid Build Coastguard Worker Variable *esp =
4053*03ce13f7SAndroid Build Coastguard Worker Func->getTarget()->getPhysicalRegister(getStackReg(), WordType);
4054*03ce13f7SAndroid Build Coastguard Worker Variable *Dest = Instr->getDest();
4055*03ce13f7SAndroid Build Coastguard Worker _mov(Dest, esp);
4056*03ce13f7SAndroid Build Coastguard Worker return;
4057*03ce13f7SAndroid Build Coastguard Worker }
4058*03ce13f7SAndroid Build Coastguard Worker case Intrinsics::Stackrestore: {
4059*03ce13f7SAndroid Build Coastguard Worker Operand *Src = Instr->getArg(0);
4060*03ce13f7SAndroid Build Coastguard Worker _mov_sp(Src);
4061*03ce13f7SAndroid Build Coastguard Worker return;
4062*03ce13f7SAndroid Build Coastguard Worker }
4063*03ce13f7SAndroid Build Coastguard Worker
4064*03ce13f7SAndroid Build Coastguard Worker case Intrinsics::Trap:
4065*03ce13f7SAndroid Build Coastguard Worker _ud2();
4066*03ce13f7SAndroid Build Coastguard Worker return;
4067*03ce13f7SAndroid Build Coastguard Worker case Intrinsics::LoadSubVector: {
4068*03ce13f7SAndroid Build Coastguard Worker assert(llvm::isa<ConstantInteger32>(Instr->getArg(1)) &&
4069*03ce13f7SAndroid Build Coastguard Worker "LoadSubVector second argument must be a constant");
4070*03ce13f7SAndroid Build Coastguard Worker Variable *Dest = Instr->getDest();
4071*03ce13f7SAndroid Build Coastguard Worker Type Ty = Dest->getType();
4072*03ce13f7SAndroid Build Coastguard Worker auto *SubVectorSize = llvm::cast<ConstantInteger32>(Instr->getArg(1));
4073*03ce13f7SAndroid Build Coastguard Worker Operand *Addr = Instr->getArg(0);
4074*03ce13f7SAndroid Build Coastguard Worker X86OperandMem *Src = formMemoryOperand(Addr, Ty);
4075*03ce13f7SAndroid Build Coastguard Worker doMockBoundsCheck(Src);
4076*03ce13f7SAndroid Build Coastguard Worker
4077*03ce13f7SAndroid Build Coastguard Worker if (Dest->isRematerializable()) {
4078*03ce13f7SAndroid Build Coastguard Worker Context.insert<InstFakeDef>(Dest);
4079*03ce13f7SAndroid Build Coastguard Worker return;
4080*03ce13f7SAndroid Build Coastguard Worker }
4081*03ce13f7SAndroid Build Coastguard Worker
4082*03ce13f7SAndroid Build Coastguard Worker auto *T = makeReg(Ty);
4083*03ce13f7SAndroid Build Coastguard Worker switch (SubVectorSize->getValue()) {
4084*03ce13f7SAndroid Build Coastguard Worker case 4:
4085*03ce13f7SAndroid Build Coastguard Worker _movd(T, Src);
4086*03ce13f7SAndroid Build Coastguard Worker break;
4087*03ce13f7SAndroid Build Coastguard Worker case 8:
4088*03ce13f7SAndroid Build Coastguard Worker _movq(T, Src);
4089*03ce13f7SAndroid Build Coastguard Worker break;
4090*03ce13f7SAndroid Build Coastguard Worker default:
4091*03ce13f7SAndroid Build Coastguard Worker Func->setError("Unexpected size for LoadSubVector");
4092*03ce13f7SAndroid Build Coastguard Worker return;
4093*03ce13f7SAndroid Build Coastguard Worker }
4094*03ce13f7SAndroid Build Coastguard Worker _movp(Dest, T);
4095*03ce13f7SAndroid Build Coastguard Worker return;
4096*03ce13f7SAndroid Build Coastguard Worker }
4097*03ce13f7SAndroid Build Coastguard Worker case Intrinsics::StoreSubVector: {
4098*03ce13f7SAndroid Build Coastguard Worker assert(llvm::isa<ConstantInteger32>(Instr->getArg(2)) &&
4099*03ce13f7SAndroid Build Coastguard Worker "StoreSubVector third argument must be a constant");
4100*03ce13f7SAndroid Build Coastguard Worker auto *SubVectorSize = llvm::cast<ConstantInteger32>(Instr->getArg(2));
4101*03ce13f7SAndroid Build Coastguard Worker Operand *Value = Instr->getArg(0);
4102*03ce13f7SAndroid Build Coastguard Worker Operand *Addr = Instr->getArg(1);
4103*03ce13f7SAndroid Build Coastguard Worker X86OperandMem *NewAddr = formMemoryOperand(Addr, Value->getType());
4104*03ce13f7SAndroid Build Coastguard Worker doMockBoundsCheck(NewAddr);
4105*03ce13f7SAndroid Build Coastguard Worker
4106*03ce13f7SAndroid Build Coastguard Worker Value = legalizeToReg(Value);
4107*03ce13f7SAndroid Build Coastguard Worker
4108*03ce13f7SAndroid Build Coastguard Worker switch (SubVectorSize->getValue()) {
4109*03ce13f7SAndroid Build Coastguard Worker case 4:
4110*03ce13f7SAndroid Build Coastguard Worker _stored(Value, NewAddr);
4111*03ce13f7SAndroid Build Coastguard Worker break;
4112*03ce13f7SAndroid Build Coastguard Worker case 8:
4113*03ce13f7SAndroid Build Coastguard Worker _storeq(Value, NewAddr);
4114*03ce13f7SAndroid Build Coastguard Worker break;
4115*03ce13f7SAndroid Build Coastguard Worker default:
4116*03ce13f7SAndroid Build Coastguard Worker Func->setError("Unexpected size for StoreSubVector");
4117*03ce13f7SAndroid Build Coastguard Worker return;
4118*03ce13f7SAndroid Build Coastguard Worker }
4119*03ce13f7SAndroid Build Coastguard Worker return;
4120*03ce13f7SAndroid Build Coastguard Worker }
4121*03ce13f7SAndroid Build Coastguard Worker case Intrinsics::VectorPackSigned: {
4122*03ce13f7SAndroid Build Coastguard Worker Operand *Src0 = Instr->getArg(0);
4123*03ce13f7SAndroid Build Coastguard Worker Operand *Src1 = Instr->getArg(1);
4124*03ce13f7SAndroid Build Coastguard Worker Variable *Dest = Instr->getDest();
4125*03ce13f7SAndroid Build Coastguard Worker auto *T = makeReg(Src0->getType());
4126*03ce13f7SAndroid Build Coastguard Worker auto *Src0RM = legalize(Src0, Legal_Reg | Legal_Mem);
4127*03ce13f7SAndroid Build Coastguard Worker auto *Src1RM = legalize(Src1, Legal_Reg | Legal_Mem);
4128*03ce13f7SAndroid Build Coastguard Worker _movp(T, Src0RM);
4129*03ce13f7SAndroid Build Coastguard Worker _packss(T, Src1RM);
4130*03ce13f7SAndroid Build Coastguard Worker _movp(Dest, T);
4131*03ce13f7SAndroid Build Coastguard Worker return;
4132*03ce13f7SAndroid Build Coastguard Worker }
4133*03ce13f7SAndroid Build Coastguard Worker case Intrinsics::VectorPackUnsigned: {
4134*03ce13f7SAndroid Build Coastguard Worker Operand *Src0 = Instr->getArg(0);
4135*03ce13f7SAndroid Build Coastguard Worker Operand *Src1 = Instr->getArg(1);
4136*03ce13f7SAndroid Build Coastguard Worker Variable *Dest = Instr->getDest();
4137*03ce13f7SAndroid Build Coastguard Worker auto *T = makeReg(Src0->getType());
4138*03ce13f7SAndroid Build Coastguard Worker auto *Src0RM = legalize(Src0, Legal_Reg | Legal_Mem);
4139*03ce13f7SAndroid Build Coastguard Worker auto *Src1RM = legalize(Src1, Legal_Reg | Legal_Mem);
4140*03ce13f7SAndroid Build Coastguard Worker _movp(T, Src0RM);
4141*03ce13f7SAndroid Build Coastguard Worker _packus(T, Src1RM);
4142*03ce13f7SAndroid Build Coastguard Worker _movp(Dest, T);
4143*03ce13f7SAndroid Build Coastguard Worker return;
4144*03ce13f7SAndroid Build Coastguard Worker }
4145*03ce13f7SAndroid Build Coastguard Worker case Intrinsics::SignMask: {
4146*03ce13f7SAndroid Build Coastguard Worker Operand *SrcReg = legalizeToReg(Instr->getArg(0));
4147*03ce13f7SAndroid Build Coastguard Worker Variable *Dest = Instr->getDest();
4148*03ce13f7SAndroid Build Coastguard Worker Variable *T = makeReg(IceType_i32);
4149*03ce13f7SAndroid Build Coastguard Worker if (SrcReg->getType() == IceType_v4f32 ||
4150*03ce13f7SAndroid Build Coastguard Worker SrcReg->getType() == IceType_v4i32 ||
4151*03ce13f7SAndroid Build Coastguard Worker SrcReg->getType() == IceType_v16i8) {
4152*03ce13f7SAndroid Build Coastguard Worker _movmsk(T, SrcReg);
4153*03ce13f7SAndroid Build Coastguard Worker } else {
4154*03ce13f7SAndroid Build Coastguard Worker // TODO(capn): We could implement v8i16 sign mask using packsswb/pmovmskb
4155*03ce13f7SAndroid Build Coastguard Worker llvm::report_fatal_error("Invalid type for SignMask intrinsic");
4156*03ce13f7SAndroid Build Coastguard Worker }
4157*03ce13f7SAndroid Build Coastguard Worker _mov(Dest, T);
4158*03ce13f7SAndroid Build Coastguard Worker return;
4159*03ce13f7SAndroid Build Coastguard Worker }
4160*03ce13f7SAndroid Build Coastguard Worker case Intrinsics::MultiplyHighSigned: {
4161*03ce13f7SAndroid Build Coastguard Worker Operand *Src0 = Instr->getArg(0);
4162*03ce13f7SAndroid Build Coastguard Worker Operand *Src1 = Instr->getArg(1);
4163*03ce13f7SAndroid Build Coastguard Worker Variable *Dest = Instr->getDest();
4164*03ce13f7SAndroid Build Coastguard Worker auto *T = makeReg(Dest->getType());
4165*03ce13f7SAndroid Build Coastguard Worker auto *Src0RM = legalize(Src0, Legal_Reg | Legal_Mem);
4166*03ce13f7SAndroid Build Coastguard Worker auto *Src1RM = legalize(Src1, Legal_Reg | Legal_Mem);
4167*03ce13f7SAndroid Build Coastguard Worker _movp(T, Src0RM);
4168*03ce13f7SAndroid Build Coastguard Worker _pmulhw(T, Src1RM);
4169*03ce13f7SAndroid Build Coastguard Worker _movp(Dest, T);
4170*03ce13f7SAndroid Build Coastguard Worker return;
4171*03ce13f7SAndroid Build Coastguard Worker }
4172*03ce13f7SAndroid Build Coastguard Worker case Intrinsics::MultiplyHighUnsigned: {
4173*03ce13f7SAndroid Build Coastguard Worker Operand *Src0 = Instr->getArg(0);
4174*03ce13f7SAndroid Build Coastguard Worker Operand *Src1 = Instr->getArg(1);
4175*03ce13f7SAndroid Build Coastguard Worker Variable *Dest = Instr->getDest();
4176*03ce13f7SAndroid Build Coastguard Worker auto *T = makeReg(Dest->getType());
4177*03ce13f7SAndroid Build Coastguard Worker auto *Src0RM = legalize(Src0, Legal_Reg | Legal_Mem);
4178*03ce13f7SAndroid Build Coastguard Worker auto *Src1RM = legalize(Src1, Legal_Reg | Legal_Mem);
4179*03ce13f7SAndroid Build Coastguard Worker _movp(T, Src0RM);
4180*03ce13f7SAndroid Build Coastguard Worker _pmulhuw(T, Src1RM);
4181*03ce13f7SAndroid Build Coastguard Worker _movp(Dest, T);
4182*03ce13f7SAndroid Build Coastguard Worker return;
4183*03ce13f7SAndroid Build Coastguard Worker }
4184*03ce13f7SAndroid Build Coastguard Worker case Intrinsics::MultiplyAddPairs: {
4185*03ce13f7SAndroid Build Coastguard Worker Operand *Src0 = Instr->getArg(0);
4186*03ce13f7SAndroid Build Coastguard Worker Operand *Src1 = Instr->getArg(1);
4187*03ce13f7SAndroid Build Coastguard Worker Variable *Dest = Instr->getDest();
4188*03ce13f7SAndroid Build Coastguard Worker auto *T = makeReg(Dest->getType());
4189*03ce13f7SAndroid Build Coastguard Worker auto *Src0RM = legalize(Src0, Legal_Reg | Legal_Mem);
4190*03ce13f7SAndroid Build Coastguard Worker auto *Src1RM = legalize(Src1, Legal_Reg | Legal_Mem);
4191*03ce13f7SAndroid Build Coastguard Worker _movp(T, Src0RM);
4192*03ce13f7SAndroid Build Coastguard Worker _pmaddwd(T, Src1RM);
4193*03ce13f7SAndroid Build Coastguard Worker _movp(Dest, T);
4194*03ce13f7SAndroid Build Coastguard Worker return;
4195*03ce13f7SAndroid Build Coastguard Worker }
4196*03ce13f7SAndroid Build Coastguard Worker case Intrinsics::AddSaturateSigned: {
4197*03ce13f7SAndroid Build Coastguard Worker Operand *Src0 = Instr->getArg(0);
4198*03ce13f7SAndroid Build Coastguard Worker Operand *Src1 = Instr->getArg(1);
4199*03ce13f7SAndroid Build Coastguard Worker Variable *Dest = Instr->getDest();
4200*03ce13f7SAndroid Build Coastguard Worker auto *T = makeReg(Dest->getType());
4201*03ce13f7SAndroid Build Coastguard Worker auto *Src0RM = legalize(Src0, Legal_Reg | Legal_Mem);
4202*03ce13f7SAndroid Build Coastguard Worker auto *Src1RM = legalize(Src1, Legal_Reg | Legal_Mem);
4203*03ce13f7SAndroid Build Coastguard Worker _movp(T, Src0RM);
4204*03ce13f7SAndroid Build Coastguard Worker _padds(T, Src1RM);
4205*03ce13f7SAndroid Build Coastguard Worker _movp(Dest, T);
4206*03ce13f7SAndroid Build Coastguard Worker return;
4207*03ce13f7SAndroid Build Coastguard Worker }
4208*03ce13f7SAndroid Build Coastguard Worker case Intrinsics::SubtractSaturateSigned: {
4209*03ce13f7SAndroid Build Coastguard Worker Operand *Src0 = Instr->getArg(0);
4210*03ce13f7SAndroid Build Coastguard Worker Operand *Src1 = Instr->getArg(1);
4211*03ce13f7SAndroid Build Coastguard Worker Variable *Dest = Instr->getDest();
4212*03ce13f7SAndroid Build Coastguard Worker auto *T = makeReg(Dest->getType());
4213*03ce13f7SAndroid Build Coastguard Worker auto *Src0RM = legalize(Src0, Legal_Reg | Legal_Mem);
4214*03ce13f7SAndroid Build Coastguard Worker auto *Src1RM = legalize(Src1, Legal_Reg | Legal_Mem);
4215*03ce13f7SAndroid Build Coastguard Worker _movp(T, Src0RM);
4216*03ce13f7SAndroid Build Coastguard Worker _psubs(T, Src1RM);
4217*03ce13f7SAndroid Build Coastguard Worker _movp(Dest, T);
4218*03ce13f7SAndroid Build Coastguard Worker return;
4219*03ce13f7SAndroid Build Coastguard Worker }
4220*03ce13f7SAndroid Build Coastguard Worker case Intrinsics::AddSaturateUnsigned: {
4221*03ce13f7SAndroid Build Coastguard Worker Operand *Src0 = Instr->getArg(0);
4222*03ce13f7SAndroid Build Coastguard Worker Operand *Src1 = Instr->getArg(1);
4223*03ce13f7SAndroid Build Coastguard Worker Variable *Dest = Instr->getDest();
4224*03ce13f7SAndroid Build Coastguard Worker auto *T = makeReg(Dest->getType());
4225*03ce13f7SAndroid Build Coastguard Worker auto *Src0RM = legalize(Src0, Legal_Reg | Legal_Mem);
4226*03ce13f7SAndroid Build Coastguard Worker auto *Src1RM = legalize(Src1, Legal_Reg | Legal_Mem);
4227*03ce13f7SAndroid Build Coastguard Worker _movp(T, Src0RM);
4228*03ce13f7SAndroid Build Coastguard Worker _paddus(T, Src1RM);
4229*03ce13f7SAndroid Build Coastguard Worker _movp(Dest, T);
4230*03ce13f7SAndroid Build Coastguard Worker return;
4231*03ce13f7SAndroid Build Coastguard Worker }
4232*03ce13f7SAndroid Build Coastguard Worker case Intrinsics::SubtractSaturateUnsigned: {
4233*03ce13f7SAndroid Build Coastguard Worker Operand *Src0 = Instr->getArg(0);
4234*03ce13f7SAndroid Build Coastguard Worker Operand *Src1 = Instr->getArg(1);
4235*03ce13f7SAndroid Build Coastguard Worker Variable *Dest = Instr->getDest();
4236*03ce13f7SAndroid Build Coastguard Worker auto *T = makeReg(Dest->getType());
4237*03ce13f7SAndroid Build Coastguard Worker auto *Src0RM = legalize(Src0, Legal_Reg | Legal_Mem);
4238*03ce13f7SAndroid Build Coastguard Worker auto *Src1RM = legalize(Src1, Legal_Reg | Legal_Mem);
4239*03ce13f7SAndroid Build Coastguard Worker _movp(T, Src0RM);
4240*03ce13f7SAndroid Build Coastguard Worker _psubus(T, Src1RM);
4241*03ce13f7SAndroid Build Coastguard Worker _movp(Dest, T);
4242*03ce13f7SAndroid Build Coastguard Worker return;
4243*03ce13f7SAndroid Build Coastguard Worker }
4244*03ce13f7SAndroid Build Coastguard Worker case Intrinsics::Nearbyint: {
4245*03ce13f7SAndroid Build Coastguard Worker Operand *Src = Instr->getArg(0);
4246*03ce13f7SAndroid Build Coastguard Worker Variable *Dest = Instr->getDest();
4247*03ce13f7SAndroid Build Coastguard Worker Type DestTy = Dest->getType();
4248*03ce13f7SAndroid Build Coastguard Worker if (isVectorType(DestTy)) {
4249*03ce13f7SAndroid Build Coastguard Worker assert(DestTy == IceType_v4i32);
4250*03ce13f7SAndroid Build Coastguard Worker assert(Src->getType() == IceType_v4f32);
4251*03ce13f7SAndroid Build Coastguard Worker Operand *Src0R = legalizeToReg(Src);
4252*03ce13f7SAndroid Build Coastguard Worker Variable *T = makeReg(DestTy);
4253*03ce13f7SAndroid Build Coastguard Worker _cvt(T, Src0R, Insts::Cvt::Ps2dq);
4254*03ce13f7SAndroid Build Coastguard Worker _movp(Dest, T);
4255*03ce13f7SAndroid Build Coastguard Worker } else if (DestTy == IceType_i64) {
4256*03ce13f7SAndroid Build Coastguard Worker llvm::report_fatal_error("Helper call was expected");
4257*03ce13f7SAndroid Build Coastguard Worker } else {
4258*03ce13f7SAndroid Build Coastguard Worker Operand *Src0RM = legalize(Src, Legal_Reg | Legal_Mem);
4259*03ce13f7SAndroid Build Coastguard Worker // t1.i32 = cvt Src0RM; t2.dest_type = t1; Dest = t2.dest_type
4260*03ce13f7SAndroid Build Coastguard Worker assert(DestTy != IceType_i64);
4261*03ce13f7SAndroid Build Coastguard Worker Variable *T_1 = makeReg(IceType_i32);
4262*03ce13f7SAndroid Build Coastguard Worker // cvt() requires its integer argument to be a GPR.
4263*03ce13f7SAndroid Build Coastguard Worker Variable *T_2 = makeReg(DestTy);
4264*03ce13f7SAndroid Build Coastguard Worker if (isByteSizedType(DestTy)) {
4265*03ce13f7SAndroid Build Coastguard Worker assert(T_1->getType() == IceType_i32);
4266*03ce13f7SAndroid Build Coastguard Worker T_1->setRegClass(RCX86_Is32To8);
4267*03ce13f7SAndroid Build Coastguard Worker T_2->setRegClass(RCX86_IsTrunc8Rcvr);
4268*03ce13f7SAndroid Build Coastguard Worker }
4269*03ce13f7SAndroid Build Coastguard Worker _cvt(T_1, Src0RM, Insts::Cvt::Ss2si);
4270*03ce13f7SAndroid Build Coastguard Worker _mov(T_2, T_1); // T_1 and T_2 may have different integer types
4271*03ce13f7SAndroid Build Coastguard Worker if (DestTy == IceType_i1)
4272*03ce13f7SAndroid Build Coastguard Worker _and(T_2, Ctx->getConstantInt1(1));
4273*03ce13f7SAndroid Build Coastguard Worker _mov(Dest, T_2);
4274*03ce13f7SAndroid Build Coastguard Worker }
4275*03ce13f7SAndroid Build Coastguard Worker return;
4276*03ce13f7SAndroid Build Coastguard Worker }
4277*03ce13f7SAndroid Build Coastguard Worker case Intrinsics::Round: {
4278*03ce13f7SAndroid Build Coastguard Worker assert(InstructionSet >= SSE4_1);
4279*03ce13f7SAndroid Build Coastguard Worker Variable *Dest = Instr->getDest();
4280*03ce13f7SAndroid Build Coastguard Worker Operand *Src = Instr->getArg(0);
4281*03ce13f7SAndroid Build Coastguard Worker Operand *Mode = Instr->getArg(1);
4282*03ce13f7SAndroid Build Coastguard Worker assert(llvm::isa<ConstantInteger32>(Mode) &&
4283*03ce13f7SAndroid Build Coastguard Worker "Round last argument must be a constant");
4284*03ce13f7SAndroid Build Coastguard Worker auto *SrcRM = legalize(Src, Legal_Reg | Legal_Mem);
4285*03ce13f7SAndroid Build Coastguard Worker int32_t Imm = llvm::cast<ConstantInteger32>(Mode)->getValue();
4286*03ce13f7SAndroid Build Coastguard Worker (void)Imm;
4287*03ce13f7SAndroid Build Coastguard Worker assert(Imm >= 0 && Imm < 4 && "Invalid rounding mode");
4288*03ce13f7SAndroid Build Coastguard Worker auto *T = makeReg(Dest->getType());
4289*03ce13f7SAndroid Build Coastguard Worker _round(T, SrcRM, Mode);
4290*03ce13f7SAndroid Build Coastguard Worker _movp(Dest, T);
4291*03ce13f7SAndroid Build Coastguard Worker return;
4292*03ce13f7SAndroid Build Coastguard Worker }
4293*03ce13f7SAndroid Build Coastguard Worker default: // UnknownIntrinsic
4294*03ce13f7SAndroid Build Coastguard Worker Func->setError("Unexpected intrinsic");
4295*03ce13f7SAndroid Build Coastguard Worker return;
4296*03ce13f7SAndroid Build Coastguard Worker }
4297*03ce13f7SAndroid Build Coastguard Worker return;
4298*03ce13f7SAndroid Build Coastguard Worker }
4299*03ce13f7SAndroid Build Coastguard Worker
lowerAtomicCmpxchg(Variable * DestPrev,Operand * Ptr,Operand * Expected,Operand * Desired)4300*03ce13f7SAndroid Build Coastguard Worker void TargetX8632::lowerAtomicCmpxchg(Variable *DestPrev, Operand *Ptr,
4301*03ce13f7SAndroid Build Coastguard Worker Operand *Expected, Operand *Desired) {
4302*03ce13f7SAndroid Build Coastguard Worker Type Ty = Expected->getType();
4303*03ce13f7SAndroid Build Coastguard Worker if (Ty == IceType_i64) {
4304*03ce13f7SAndroid Build Coastguard Worker // Reserve the pre-colored registers first, before adding any more
4305*03ce13f7SAndroid Build Coastguard Worker // infinite-weight variables from formMemoryOperand's legalization.
4306*03ce13f7SAndroid Build Coastguard Worker Variable *T_edx = makeReg(IceType_i32, RegX8632::Reg_edx);
4307*03ce13f7SAndroid Build Coastguard Worker Variable *T_eax = makeReg(IceType_i32, RegX8632::Reg_eax);
4308*03ce13f7SAndroid Build Coastguard Worker Variable *T_ecx = makeReg(IceType_i32, RegX8632::Reg_ecx);
4309*03ce13f7SAndroid Build Coastguard Worker Variable *T_ebx = makeReg(IceType_i32, RegX8632::Reg_ebx);
4310*03ce13f7SAndroid Build Coastguard Worker _mov(T_eax, loOperand(Expected));
4311*03ce13f7SAndroid Build Coastguard Worker _mov(T_edx, hiOperand(Expected));
4312*03ce13f7SAndroid Build Coastguard Worker _mov(T_ebx, loOperand(Desired));
4313*03ce13f7SAndroid Build Coastguard Worker _mov(T_ecx, hiOperand(Desired));
4314*03ce13f7SAndroid Build Coastguard Worker X86OperandMem *Addr = formMemoryOperand(Ptr, Ty);
4315*03ce13f7SAndroid Build Coastguard Worker constexpr bool Locked = true;
4316*03ce13f7SAndroid Build Coastguard Worker _cmpxchg8b(Addr, T_edx, T_eax, T_ecx, T_ebx, Locked);
4317*03ce13f7SAndroid Build Coastguard Worker auto *DestLo = llvm::cast<Variable>(loOperand(DestPrev));
4318*03ce13f7SAndroid Build Coastguard Worker auto *DestHi = llvm::cast<Variable>(hiOperand(DestPrev));
4319*03ce13f7SAndroid Build Coastguard Worker _mov(DestLo, T_eax);
4320*03ce13f7SAndroid Build Coastguard Worker _mov(DestHi, T_edx);
4321*03ce13f7SAndroid Build Coastguard Worker return;
4322*03ce13f7SAndroid Build Coastguard Worker }
4323*03ce13f7SAndroid Build Coastguard Worker RegNumT Eax;
4324*03ce13f7SAndroid Build Coastguard Worker switch (Ty) {
4325*03ce13f7SAndroid Build Coastguard Worker default:
4326*03ce13f7SAndroid Build Coastguard Worker llvm::report_fatal_error("Bad type for cmpxchg");
4327*03ce13f7SAndroid Build Coastguard Worker case IceType_i32:
4328*03ce13f7SAndroid Build Coastguard Worker Eax = RegX8632::Reg_eax;
4329*03ce13f7SAndroid Build Coastguard Worker break;
4330*03ce13f7SAndroid Build Coastguard Worker case IceType_i16:
4331*03ce13f7SAndroid Build Coastguard Worker Eax = RegX8632::Reg_ax;
4332*03ce13f7SAndroid Build Coastguard Worker break;
4333*03ce13f7SAndroid Build Coastguard Worker case IceType_i8:
4334*03ce13f7SAndroid Build Coastguard Worker Eax = RegX8632::Reg_al;
4335*03ce13f7SAndroid Build Coastguard Worker break;
4336*03ce13f7SAndroid Build Coastguard Worker }
4337*03ce13f7SAndroid Build Coastguard Worker Variable *T_eax = makeReg(Ty, Eax);
4338*03ce13f7SAndroid Build Coastguard Worker _mov(T_eax, Expected);
4339*03ce13f7SAndroid Build Coastguard Worker X86OperandMem *Addr = formMemoryOperand(Ptr, Ty);
4340*03ce13f7SAndroid Build Coastguard Worker Variable *DesiredReg = legalizeToReg(Desired);
4341*03ce13f7SAndroid Build Coastguard Worker constexpr bool Locked = true;
4342*03ce13f7SAndroid Build Coastguard Worker _cmpxchg(Addr, T_eax, DesiredReg, Locked);
4343*03ce13f7SAndroid Build Coastguard Worker _mov(DestPrev, T_eax);
4344*03ce13f7SAndroid Build Coastguard Worker }
4345*03ce13f7SAndroid Build Coastguard Worker
tryOptimizedCmpxchgCmpBr(Variable * Dest,Operand * PtrToMem,Operand * Expected,Operand * Desired)4346*03ce13f7SAndroid Build Coastguard Worker bool TargetX8632::tryOptimizedCmpxchgCmpBr(Variable *Dest, Operand *PtrToMem,
4347*03ce13f7SAndroid Build Coastguard Worker Operand *Expected,
4348*03ce13f7SAndroid Build Coastguard Worker Operand *Desired) {
4349*03ce13f7SAndroid Build Coastguard Worker if (Func->getOptLevel() == Opt_m1)
4350*03ce13f7SAndroid Build Coastguard Worker return false;
4351*03ce13f7SAndroid Build Coastguard Worker // Peek ahead a few instructions and see how Dest is used.
4352*03ce13f7SAndroid Build Coastguard Worker // It's very common to have:
4353*03ce13f7SAndroid Build Coastguard Worker //
4354*03ce13f7SAndroid Build Coastguard Worker // %x = call i32 @llvm.nacl.atomic.cmpxchg.i32(i32* ptr, i32 %expected, ...)
4355*03ce13f7SAndroid Build Coastguard Worker // [%y_phi = ...] // list of phi stores
4356*03ce13f7SAndroid Build Coastguard Worker // %p = icmp eq i32 %x, %expected
4357*03ce13f7SAndroid Build Coastguard Worker // br i1 %p, label %l1, label %l2
4358*03ce13f7SAndroid Build Coastguard Worker //
4359*03ce13f7SAndroid Build Coastguard Worker // which we can optimize into:
4360*03ce13f7SAndroid Build Coastguard Worker //
4361*03ce13f7SAndroid Build Coastguard Worker // %x = <cmpxchg code>
4362*03ce13f7SAndroid Build Coastguard Worker // [%y_phi = ...] // list of phi stores
4363*03ce13f7SAndroid Build Coastguard Worker // br eq, %l1, %l2
4364*03ce13f7SAndroid Build Coastguard Worker InstList::iterator I = Context.getCur();
4365*03ce13f7SAndroid Build Coastguard Worker // I is currently the InstIntrinsic. Peek past that.
4366*03ce13f7SAndroid Build Coastguard Worker // This assumes that the atomic cmpxchg has not been lowered yet,
4367*03ce13f7SAndroid Build Coastguard Worker // so that the instructions seen in the scan from "Cur" is simple.
4368*03ce13f7SAndroid Build Coastguard Worker assert(llvm::isa<InstIntrinsic>(*I));
4369*03ce13f7SAndroid Build Coastguard Worker Inst *NextInst = Context.getNextInst(I);
4370*03ce13f7SAndroid Build Coastguard Worker if (!NextInst)
4371*03ce13f7SAndroid Build Coastguard Worker return false;
4372*03ce13f7SAndroid Build Coastguard Worker // There might be phi assignments right before the compare+branch, since
4373*03ce13f7SAndroid Build Coastguard Worker // this could be a backward branch for a loop. This placement of assignments
4374*03ce13f7SAndroid Build Coastguard Worker // is determined by placePhiStores().
4375*03ce13f7SAndroid Build Coastguard Worker CfgVector<InstAssign *> PhiAssigns;
4376*03ce13f7SAndroid Build Coastguard Worker while (auto *PhiAssign = llvm::dyn_cast<InstAssign>(NextInst)) {
4377*03ce13f7SAndroid Build Coastguard Worker if (PhiAssign->getDest() == Dest)
4378*03ce13f7SAndroid Build Coastguard Worker return false;
4379*03ce13f7SAndroid Build Coastguard Worker PhiAssigns.push_back(PhiAssign);
4380*03ce13f7SAndroid Build Coastguard Worker NextInst = Context.getNextInst(I);
4381*03ce13f7SAndroid Build Coastguard Worker if (!NextInst)
4382*03ce13f7SAndroid Build Coastguard Worker return false;
4383*03ce13f7SAndroid Build Coastguard Worker }
4384*03ce13f7SAndroid Build Coastguard Worker if (auto *NextCmp = llvm::dyn_cast<InstIcmp>(NextInst)) {
4385*03ce13f7SAndroid Build Coastguard Worker if (!(NextCmp->getCondition() == InstIcmp::Eq &&
4386*03ce13f7SAndroid Build Coastguard Worker ((NextCmp->getSrc(0) == Dest && NextCmp->getSrc(1) == Expected) ||
4387*03ce13f7SAndroid Build Coastguard Worker (NextCmp->getSrc(1) == Dest && NextCmp->getSrc(0) == Expected)))) {
4388*03ce13f7SAndroid Build Coastguard Worker return false;
4389*03ce13f7SAndroid Build Coastguard Worker }
4390*03ce13f7SAndroid Build Coastguard Worker NextInst = Context.getNextInst(I);
4391*03ce13f7SAndroid Build Coastguard Worker if (!NextInst)
4392*03ce13f7SAndroid Build Coastguard Worker return false;
4393*03ce13f7SAndroid Build Coastguard Worker if (auto *NextBr = llvm::dyn_cast<InstBr>(NextInst)) {
4394*03ce13f7SAndroid Build Coastguard Worker if (!NextBr->isUnconditional() &&
4395*03ce13f7SAndroid Build Coastguard Worker NextCmp->getDest() == NextBr->getCondition() &&
4396*03ce13f7SAndroid Build Coastguard Worker NextBr->isLastUse(NextCmp->getDest())) {
4397*03ce13f7SAndroid Build Coastguard Worker lowerAtomicCmpxchg(Dest, PtrToMem, Expected, Desired);
4398*03ce13f7SAndroid Build Coastguard Worker for (size_t i = 0; i < PhiAssigns.size(); ++i) {
4399*03ce13f7SAndroid Build Coastguard Worker // Lower the phi assignments now, before the branch (same placement
4400*03ce13f7SAndroid Build Coastguard Worker // as before).
4401*03ce13f7SAndroid Build Coastguard Worker InstAssign *PhiAssign = PhiAssigns[i];
4402*03ce13f7SAndroid Build Coastguard Worker PhiAssign->setDeleted();
4403*03ce13f7SAndroid Build Coastguard Worker lowerAssign(PhiAssign);
4404*03ce13f7SAndroid Build Coastguard Worker Context.advanceNext();
4405*03ce13f7SAndroid Build Coastguard Worker }
4406*03ce13f7SAndroid Build Coastguard Worker _br(CondX86::Br_e, NextBr->getTargetTrue(), NextBr->getTargetFalse());
4407*03ce13f7SAndroid Build Coastguard Worker // Skip over the old compare and branch, by deleting them.
4408*03ce13f7SAndroid Build Coastguard Worker NextCmp->setDeleted();
4409*03ce13f7SAndroid Build Coastguard Worker NextBr->setDeleted();
4410*03ce13f7SAndroid Build Coastguard Worker Context.advanceNext();
4411*03ce13f7SAndroid Build Coastguard Worker Context.advanceNext();
4412*03ce13f7SAndroid Build Coastguard Worker return true;
4413*03ce13f7SAndroid Build Coastguard Worker }
4414*03ce13f7SAndroid Build Coastguard Worker }
4415*03ce13f7SAndroid Build Coastguard Worker }
4416*03ce13f7SAndroid Build Coastguard Worker return false;
4417*03ce13f7SAndroid Build Coastguard Worker }
4418*03ce13f7SAndroid Build Coastguard Worker
lowerAtomicRMW(Variable * Dest,uint32_t Operation,Operand * Ptr,Operand * Val)4419*03ce13f7SAndroid Build Coastguard Worker void TargetX8632::lowerAtomicRMW(Variable *Dest, uint32_t Operation,
4420*03ce13f7SAndroid Build Coastguard Worker Operand *Ptr, Operand *Val) {
4421*03ce13f7SAndroid Build Coastguard Worker bool NeedsCmpxchg = false;
4422*03ce13f7SAndroid Build Coastguard Worker LowerBinOp Op_Lo = nullptr;
4423*03ce13f7SAndroid Build Coastguard Worker LowerBinOp Op_Hi = nullptr;
4424*03ce13f7SAndroid Build Coastguard Worker switch (Operation) {
4425*03ce13f7SAndroid Build Coastguard Worker default:
4426*03ce13f7SAndroid Build Coastguard Worker Func->setError("Unknown AtomicRMW operation");
4427*03ce13f7SAndroid Build Coastguard Worker return;
4428*03ce13f7SAndroid Build Coastguard Worker case Intrinsics::AtomicAdd: {
4429*03ce13f7SAndroid Build Coastguard Worker if (Dest->getType() == IceType_i64) {
4430*03ce13f7SAndroid Build Coastguard Worker // All the fall-through paths must set this to true, but use this
4431*03ce13f7SAndroid Build Coastguard Worker // for asserting.
4432*03ce13f7SAndroid Build Coastguard Worker NeedsCmpxchg = true;
4433*03ce13f7SAndroid Build Coastguard Worker Op_Lo = &TargetX8632::_add;
4434*03ce13f7SAndroid Build Coastguard Worker Op_Hi = &TargetX8632::_adc;
4435*03ce13f7SAndroid Build Coastguard Worker break;
4436*03ce13f7SAndroid Build Coastguard Worker }
4437*03ce13f7SAndroid Build Coastguard Worker X86OperandMem *Addr = formMemoryOperand(Ptr, Dest->getType());
4438*03ce13f7SAndroid Build Coastguard Worker constexpr bool Locked = true;
4439*03ce13f7SAndroid Build Coastguard Worker Variable *T = nullptr;
4440*03ce13f7SAndroid Build Coastguard Worker _mov(T, Val);
4441*03ce13f7SAndroid Build Coastguard Worker _xadd(Addr, T, Locked);
4442*03ce13f7SAndroid Build Coastguard Worker _mov(Dest, T);
4443*03ce13f7SAndroid Build Coastguard Worker return;
4444*03ce13f7SAndroid Build Coastguard Worker }
4445*03ce13f7SAndroid Build Coastguard Worker case Intrinsics::AtomicSub: {
4446*03ce13f7SAndroid Build Coastguard Worker if (Dest->getType() == IceType_i64) {
4447*03ce13f7SAndroid Build Coastguard Worker NeedsCmpxchg = true;
4448*03ce13f7SAndroid Build Coastguard Worker Op_Lo = &TargetX8632::_sub;
4449*03ce13f7SAndroid Build Coastguard Worker Op_Hi = &TargetX8632::_sbb;
4450*03ce13f7SAndroid Build Coastguard Worker break;
4451*03ce13f7SAndroid Build Coastguard Worker }
4452*03ce13f7SAndroid Build Coastguard Worker X86OperandMem *Addr = formMemoryOperand(Ptr, Dest->getType());
4453*03ce13f7SAndroid Build Coastguard Worker constexpr bool Locked = true;
4454*03ce13f7SAndroid Build Coastguard Worker Variable *T = nullptr;
4455*03ce13f7SAndroid Build Coastguard Worker _mov(T, Val);
4456*03ce13f7SAndroid Build Coastguard Worker _neg(T);
4457*03ce13f7SAndroid Build Coastguard Worker _xadd(Addr, T, Locked);
4458*03ce13f7SAndroid Build Coastguard Worker _mov(Dest, T);
4459*03ce13f7SAndroid Build Coastguard Worker return;
4460*03ce13f7SAndroid Build Coastguard Worker }
4461*03ce13f7SAndroid Build Coastguard Worker case Intrinsics::AtomicOr:
4462*03ce13f7SAndroid Build Coastguard Worker // TODO(jvoung): If Dest is null or dead, then some of these
4463*03ce13f7SAndroid Build Coastguard Worker // operations do not need an "exchange", but just a locked op.
4464*03ce13f7SAndroid Build Coastguard Worker // That appears to be "worth" it for sub, or, and, and xor.
4465*03ce13f7SAndroid Build Coastguard Worker // xadd is probably fine vs lock add for add, and xchg is fine
4466*03ce13f7SAndroid Build Coastguard Worker // vs an atomic store.
4467*03ce13f7SAndroid Build Coastguard Worker NeedsCmpxchg = true;
4468*03ce13f7SAndroid Build Coastguard Worker Op_Lo = &TargetX8632::_or;
4469*03ce13f7SAndroid Build Coastguard Worker Op_Hi = &TargetX8632::_or;
4470*03ce13f7SAndroid Build Coastguard Worker break;
4471*03ce13f7SAndroid Build Coastguard Worker case Intrinsics::AtomicAnd:
4472*03ce13f7SAndroid Build Coastguard Worker NeedsCmpxchg = true;
4473*03ce13f7SAndroid Build Coastguard Worker Op_Lo = &TargetX8632::_and;
4474*03ce13f7SAndroid Build Coastguard Worker Op_Hi = &TargetX8632::_and;
4475*03ce13f7SAndroid Build Coastguard Worker break;
4476*03ce13f7SAndroid Build Coastguard Worker case Intrinsics::AtomicXor:
4477*03ce13f7SAndroid Build Coastguard Worker NeedsCmpxchg = true;
4478*03ce13f7SAndroid Build Coastguard Worker Op_Lo = &TargetX8632::_xor;
4479*03ce13f7SAndroid Build Coastguard Worker Op_Hi = &TargetX8632::_xor;
4480*03ce13f7SAndroid Build Coastguard Worker break;
4481*03ce13f7SAndroid Build Coastguard Worker case Intrinsics::AtomicExchange:
4482*03ce13f7SAndroid Build Coastguard Worker if (Dest->getType() == IceType_i64) {
4483*03ce13f7SAndroid Build Coastguard Worker NeedsCmpxchg = true;
4484*03ce13f7SAndroid Build Coastguard Worker // NeedsCmpxchg, but no real Op_Lo/Op_Hi need to be done. The values
4485*03ce13f7SAndroid Build Coastguard Worker // just need to be moved to the ecx and ebx registers.
4486*03ce13f7SAndroid Build Coastguard Worker Op_Lo = nullptr;
4487*03ce13f7SAndroid Build Coastguard Worker Op_Hi = nullptr;
4488*03ce13f7SAndroid Build Coastguard Worker break;
4489*03ce13f7SAndroid Build Coastguard Worker }
4490*03ce13f7SAndroid Build Coastguard Worker X86OperandMem *Addr = formMemoryOperand(Ptr, Dest->getType());
4491*03ce13f7SAndroid Build Coastguard Worker Variable *T = nullptr;
4492*03ce13f7SAndroid Build Coastguard Worker _mov(T, Val);
4493*03ce13f7SAndroid Build Coastguard Worker _xchg(Addr, T);
4494*03ce13f7SAndroid Build Coastguard Worker _mov(Dest, T);
4495*03ce13f7SAndroid Build Coastguard Worker return;
4496*03ce13f7SAndroid Build Coastguard Worker }
4497*03ce13f7SAndroid Build Coastguard Worker // Otherwise, we need a cmpxchg loop.
4498*03ce13f7SAndroid Build Coastguard Worker (void)NeedsCmpxchg;
4499*03ce13f7SAndroid Build Coastguard Worker assert(NeedsCmpxchg);
4500*03ce13f7SAndroid Build Coastguard Worker expandAtomicRMWAsCmpxchg(Op_Lo, Op_Hi, Dest, Ptr, Val);
4501*03ce13f7SAndroid Build Coastguard Worker }
4502*03ce13f7SAndroid Build Coastguard Worker
expandAtomicRMWAsCmpxchg(LowerBinOp Op_Lo,LowerBinOp Op_Hi,Variable * Dest,Operand * Ptr,Operand * Val)4503*03ce13f7SAndroid Build Coastguard Worker void TargetX8632::expandAtomicRMWAsCmpxchg(LowerBinOp Op_Lo, LowerBinOp Op_Hi,
4504*03ce13f7SAndroid Build Coastguard Worker Variable *Dest, Operand *Ptr,
4505*03ce13f7SAndroid Build Coastguard Worker Operand *Val) {
4506*03ce13f7SAndroid Build Coastguard Worker // Expand a more complex RMW operation as a cmpxchg loop:
4507*03ce13f7SAndroid Build Coastguard Worker // For 64-bit:
4508*03ce13f7SAndroid Build Coastguard Worker // mov eax, [ptr]
4509*03ce13f7SAndroid Build Coastguard Worker // mov edx, [ptr + 4]
4510*03ce13f7SAndroid Build Coastguard Worker // .LABEL:
4511*03ce13f7SAndroid Build Coastguard Worker // mov ebx, eax
4512*03ce13f7SAndroid Build Coastguard Worker // <Op_Lo> ebx, <desired_adj_lo>
4513*03ce13f7SAndroid Build Coastguard Worker // mov ecx, edx
4514*03ce13f7SAndroid Build Coastguard Worker // <Op_Hi> ecx, <desired_adj_hi>
4515*03ce13f7SAndroid Build Coastguard Worker // lock cmpxchg8b [ptr]
4516*03ce13f7SAndroid Build Coastguard Worker // jne .LABEL
4517*03ce13f7SAndroid Build Coastguard Worker // mov <dest_lo>, eax
4518*03ce13f7SAndroid Build Coastguard Worker // mov <dest_lo>, edx
4519*03ce13f7SAndroid Build Coastguard Worker //
4520*03ce13f7SAndroid Build Coastguard Worker // For 32-bit:
4521*03ce13f7SAndroid Build Coastguard Worker // mov eax, [ptr]
4522*03ce13f7SAndroid Build Coastguard Worker // .LABEL:
4523*03ce13f7SAndroid Build Coastguard Worker // mov <reg>, eax
4524*03ce13f7SAndroid Build Coastguard Worker // op <reg>, [desired_adj]
4525*03ce13f7SAndroid Build Coastguard Worker // lock cmpxchg [ptr], <reg>
4526*03ce13f7SAndroid Build Coastguard Worker // jne .LABEL
4527*03ce13f7SAndroid Build Coastguard Worker // mov <dest>, eax
4528*03ce13f7SAndroid Build Coastguard Worker //
4529*03ce13f7SAndroid Build Coastguard Worker // If Op_{Lo,Hi} are nullptr, then just copy the value.
4530*03ce13f7SAndroid Build Coastguard Worker Val = legalize(Val);
4531*03ce13f7SAndroid Build Coastguard Worker Type Ty = Val->getType();
4532*03ce13f7SAndroid Build Coastguard Worker if (Ty == IceType_i64) {
4533*03ce13f7SAndroid Build Coastguard Worker Variable *T_edx = makeReg(IceType_i32, RegX8632::Reg_edx);
4534*03ce13f7SAndroid Build Coastguard Worker Variable *T_eax = makeReg(IceType_i32, RegX8632::Reg_eax);
4535*03ce13f7SAndroid Build Coastguard Worker X86OperandMem *Addr = formMemoryOperand(Ptr, Ty);
4536*03ce13f7SAndroid Build Coastguard Worker _mov(T_eax, loOperand(Addr));
4537*03ce13f7SAndroid Build Coastguard Worker _mov(T_edx, hiOperand(Addr));
4538*03ce13f7SAndroid Build Coastguard Worker Variable *T_ecx = makeReg(IceType_i32, RegX8632::Reg_ecx);
4539*03ce13f7SAndroid Build Coastguard Worker Variable *T_ebx = makeReg(IceType_i32, RegX8632::Reg_ebx);
4540*03ce13f7SAndroid Build Coastguard Worker InstX86Label *Label = InstX86Label::create(Func, this);
4541*03ce13f7SAndroid Build Coastguard Worker const bool IsXchg8b = Op_Lo == nullptr && Op_Hi == nullptr;
4542*03ce13f7SAndroid Build Coastguard Worker if (!IsXchg8b) {
4543*03ce13f7SAndroid Build Coastguard Worker Context.insert(Label);
4544*03ce13f7SAndroid Build Coastguard Worker _mov(T_ebx, T_eax);
4545*03ce13f7SAndroid Build Coastguard Worker (this->*Op_Lo)(T_ebx, loOperand(Val));
4546*03ce13f7SAndroid Build Coastguard Worker _mov(T_ecx, T_edx);
4547*03ce13f7SAndroid Build Coastguard Worker (this->*Op_Hi)(T_ecx, hiOperand(Val));
4548*03ce13f7SAndroid Build Coastguard Worker } else {
4549*03ce13f7SAndroid Build Coastguard Worker // This is for xchg, which doesn't need an actual Op_Lo/Op_Hi.
4550*03ce13f7SAndroid Build Coastguard Worker // It just needs the Val loaded into ebx and ecx.
4551*03ce13f7SAndroid Build Coastguard Worker // That can also be done before the loop.
4552*03ce13f7SAndroid Build Coastguard Worker _mov(T_ebx, loOperand(Val));
4553*03ce13f7SAndroid Build Coastguard Worker _mov(T_ecx, hiOperand(Val));
4554*03ce13f7SAndroid Build Coastguard Worker Context.insert(Label);
4555*03ce13f7SAndroid Build Coastguard Worker }
4556*03ce13f7SAndroid Build Coastguard Worker constexpr bool Locked = true;
4557*03ce13f7SAndroid Build Coastguard Worker _cmpxchg8b(Addr, T_edx, T_eax, T_ecx, T_ebx, Locked);
4558*03ce13f7SAndroid Build Coastguard Worker _br(CondX86::Br_ne, Label);
4559*03ce13f7SAndroid Build Coastguard Worker if (!IsXchg8b) {
4560*03ce13f7SAndroid Build Coastguard Worker // If Val is a variable, model the extended live range of Val through
4561*03ce13f7SAndroid Build Coastguard Worker // the end of the loop, since it will be re-used by the loop.
4562*03ce13f7SAndroid Build Coastguard Worker if (auto *ValVar = llvm::dyn_cast<Variable>(Val)) {
4563*03ce13f7SAndroid Build Coastguard Worker auto *ValLo = llvm::cast<Variable>(loOperand(ValVar));
4564*03ce13f7SAndroid Build Coastguard Worker auto *ValHi = llvm::cast<Variable>(hiOperand(ValVar));
4565*03ce13f7SAndroid Build Coastguard Worker Context.insert<InstFakeUse>(ValLo);
4566*03ce13f7SAndroid Build Coastguard Worker Context.insert<InstFakeUse>(ValHi);
4567*03ce13f7SAndroid Build Coastguard Worker }
4568*03ce13f7SAndroid Build Coastguard Worker } else {
4569*03ce13f7SAndroid Build Coastguard Worker // For xchg, the loop is slightly smaller and ebx/ecx are used.
4570*03ce13f7SAndroid Build Coastguard Worker Context.insert<InstFakeUse>(T_ebx);
4571*03ce13f7SAndroid Build Coastguard Worker Context.insert<InstFakeUse>(T_ecx);
4572*03ce13f7SAndroid Build Coastguard Worker }
4573*03ce13f7SAndroid Build Coastguard Worker // The address base (if any) is also reused in the loop.
4574*03ce13f7SAndroid Build Coastguard Worker if (Variable *Base = Addr->getBase())
4575*03ce13f7SAndroid Build Coastguard Worker Context.insert<InstFakeUse>(Base);
4576*03ce13f7SAndroid Build Coastguard Worker auto *DestLo = llvm::cast<Variable>(loOperand(Dest));
4577*03ce13f7SAndroid Build Coastguard Worker auto *DestHi = llvm::cast<Variable>(hiOperand(Dest));
4578*03ce13f7SAndroid Build Coastguard Worker _mov(DestLo, T_eax);
4579*03ce13f7SAndroid Build Coastguard Worker _mov(DestHi, T_edx);
4580*03ce13f7SAndroid Build Coastguard Worker return;
4581*03ce13f7SAndroid Build Coastguard Worker }
4582*03ce13f7SAndroid Build Coastguard Worker X86OperandMem *Addr = formMemoryOperand(Ptr, Ty);
4583*03ce13f7SAndroid Build Coastguard Worker RegNumT Eax;
4584*03ce13f7SAndroid Build Coastguard Worker switch (Ty) {
4585*03ce13f7SAndroid Build Coastguard Worker default:
4586*03ce13f7SAndroid Build Coastguard Worker llvm::report_fatal_error("Bad type for atomicRMW");
4587*03ce13f7SAndroid Build Coastguard Worker case IceType_i32:
4588*03ce13f7SAndroid Build Coastguard Worker Eax = RegX8632::Reg_eax;
4589*03ce13f7SAndroid Build Coastguard Worker break;
4590*03ce13f7SAndroid Build Coastguard Worker case IceType_i16:
4591*03ce13f7SAndroid Build Coastguard Worker Eax = RegX8632::Reg_ax;
4592*03ce13f7SAndroid Build Coastguard Worker break;
4593*03ce13f7SAndroid Build Coastguard Worker case IceType_i8:
4594*03ce13f7SAndroid Build Coastguard Worker Eax = RegX8632::Reg_al;
4595*03ce13f7SAndroid Build Coastguard Worker break;
4596*03ce13f7SAndroid Build Coastguard Worker }
4597*03ce13f7SAndroid Build Coastguard Worker Variable *T_eax = makeReg(Ty, Eax);
4598*03ce13f7SAndroid Build Coastguard Worker _mov(T_eax, Addr);
4599*03ce13f7SAndroid Build Coastguard Worker auto *Label = Context.insert<InstX86Label>(this);
4600*03ce13f7SAndroid Build Coastguard Worker // We want to pick a different register for T than Eax, so don't use
4601*03ce13f7SAndroid Build Coastguard Worker // _mov(T == nullptr, T_eax).
4602*03ce13f7SAndroid Build Coastguard Worker Variable *T = makeReg(Ty);
4603*03ce13f7SAndroid Build Coastguard Worker _mov(T, T_eax);
4604*03ce13f7SAndroid Build Coastguard Worker (this->*Op_Lo)(T, Val);
4605*03ce13f7SAndroid Build Coastguard Worker constexpr bool Locked = true;
4606*03ce13f7SAndroid Build Coastguard Worker _cmpxchg(Addr, T_eax, T, Locked);
4607*03ce13f7SAndroid Build Coastguard Worker _br(CondX86::Br_ne, Label);
4608*03ce13f7SAndroid Build Coastguard Worker // If Val is a variable, model the extended live range of Val through
4609*03ce13f7SAndroid Build Coastguard Worker // the end of the loop, since it will be re-used by the loop.
4610*03ce13f7SAndroid Build Coastguard Worker if (auto *ValVar = llvm::dyn_cast<Variable>(Val)) {
4611*03ce13f7SAndroid Build Coastguard Worker Context.insert<InstFakeUse>(ValVar);
4612*03ce13f7SAndroid Build Coastguard Worker }
4613*03ce13f7SAndroid Build Coastguard Worker // The address base (if any) is also reused in the loop.
4614*03ce13f7SAndroid Build Coastguard Worker if (Variable *Base = Addr->getBase())
4615*03ce13f7SAndroid Build Coastguard Worker Context.insert<InstFakeUse>(Base);
4616*03ce13f7SAndroid Build Coastguard Worker _mov(Dest, T_eax);
4617*03ce13f7SAndroid Build Coastguard Worker }
4618*03ce13f7SAndroid Build Coastguard Worker
4619*03ce13f7SAndroid Build Coastguard Worker /// Lowers count {trailing, leading} zeros intrinsic.
4620*03ce13f7SAndroid Build Coastguard Worker ///
4621*03ce13f7SAndroid Build Coastguard Worker /// We could do constant folding here, but that should have
4622*03ce13f7SAndroid Build Coastguard Worker /// been done by the front-end/middle-end optimizations.
4623*03ce13f7SAndroid Build Coastguard Worker
lowerCountZeros(bool Cttz,Type Ty,Variable * Dest,Operand * FirstVal,Operand * SecondVal)4624*03ce13f7SAndroid Build Coastguard Worker void TargetX8632::lowerCountZeros(bool Cttz, Type Ty, Variable *Dest,
4625*03ce13f7SAndroid Build Coastguard Worker Operand *FirstVal, Operand *SecondVal) {
4626*03ce13f7SAndroid Build Coastguard Worker // TODO(jvoung): Determine if the user CPU supports LZCNT (BMI).
4627*03ce13f7SAndroid Build Coastguard Worker // Then the instructions will handle the Val == 0 case much more simply
4628*03ce13f7SAndroid Build Coastguard Worker // and won't require conversion from bit position to number of zeros.
4629*03ce13f7SAndroid Build Coastguard Worker //
4630*03ce13f7SAndroid Build Coastguard Worker // Otherwise:
4631*03ce13f7SAndroid Build Coastguard Worker // bsr IF_NOT_ZERO, Val
4632*03ce13f7SAndroid Build Coastguard Worker // mov T_DEST, ((Ty == i32) ? 63 : 127)
4633*03ce13f7SAndroid Build Coastguard Worker // cmovne T_DEST, IF_NOT_ZERO
4634*03ce13f7SAndroid Build Coastguard Worker // xor T_DEST, ((Ty == i32) ? 31 : 63)
4635*03ce13f7SAndroid Build Coastguard Worker // mov DEST, T_DEST
4636*03ce13f7SAndroid Build Coastguard Worker //
4637*03ce13f7SAndroid Build Coastguard Worker // NOTE: T_DEST must be a register because cmov requires its dest to be a
4638*03ce13f7SAndroid Build Coastguard Worker // register. Also, bsf and bsr require their dest to be a register.
4639*03ce13f7SAndroid Build Coastguard Worker //
4640*03ce13f7SAndroid Build Coastguard Worker // The xor DEST, C(31|63) converts a bit position to # of leading zeroes.
4641*03ce13f7SAndroid Build Coastguard Worker // E.g., for 000... 00001100, bsr will say that the most significant bit
4642*03ce13f7SAndroid Build Coastguard Worker // set is at position 3, while the number of leading zeros is 28. Xor is
4643*03ce13f7SAndroid Build Coastguard Worker // like (M - N) for N <= M, and converts 63 to 32, and 127 to 64 (for the
4644*03ce13f7SAndroid Build Coastguard Worker // all-zeros case).
4645*03ce13f7SAndroid Build Coastguard Worker //
4646*03ce13f7SAndroid Build Coastguard Worker // X8632 only: Similar for 64-bit, but start w/ speculating that the upper
4647*03ce13f7SAndroid Build Coastguard Worker // 32 bits are all zero, and compute the result for that case (checking the
4648*03ce13f7SAndroid Build Coastguard Worker // lower 32 bits). Then actually compute the result for the upper bits and
4649*03ce13f7SAndroid Build Coastguard Worker // cmov in the result from the lower computation if the earlier speculation
4650*03ce13f7SAndroid Build Coastguard Worker // was correct.
4651*03ce13f7SAndroid Build Coastguard Worker //
4652*03ce13f7SAndroid Build Coastguard Worker // Cttz, is similar, but uses bsf instead, and doesn't require the xor
4653*03ce13f7SAndroid Build Coastguard Worker // bit position conversion, and the speculation is reversed.
4654*03ce13f7SAndroid Build Coastguard Worker
4655*03ce13f7SAndroid Build Coastguard Worker // TODO(jpp): refactor this method.
4656*03ce13f7SAndroid Build Coastguard Worker assert(Ty == IceType_i32 || Ty == IceType_i64);
4657*03ce13f7SAndroid Build Coastguard Worker const Type DestTy = IceType_i32;
4658*03ce13f7SAndroid Build Coastguard Worker Variable *T = makeReg(DestTy);
4659*03ce13f7SAndroid Build Coastguard Worker Operand *FirstValRM = legalize(FirstVal, Legal_Mem | Legal_Reg);
4660*03ce13f7SAndroid Build Coastguard Worker if (Cttz) {
4661*03ce13f7SAndroid Build Coastguard Worker _bsf(T, FirstValRM);
4662*03ce13f7SAndroid Build Coastguard Worker } else {
4663*03ce13f7SAndroid Build Coastguard Worker _bsr(T, FirstValRM);
4664*03ce13f7SAndroid Build Coastguard Worker }
4665*03ce13f7SAndroid Build Coastguard Worker Variable *T_Dest = makeReg(DestTy);
4666*03ce13f7SAndroid Build Coastguard Worker Constant *_31 = Ctx->getConstantInt32(31);
4667*03ce13f7SAndroid Build Coastguard Worker Constant *_32 = Ctx->getConstantInt(DestTy, 32);
4668*03ce13f7SAndroid Build Coastguard Worker Constant *_63 = Ctx->getConstantInt(DestTy, 63);
4669*03ce13f7SAndroid Build Coastguard Worker Constant *_64 = Ctx->getConstantInt(DestTy, 64);
4670*03ce13f7SAndroid Build Coastguard Worker if (Cttz) {
4671*03ce13f7SAndroid Build Coastguard Worker if (DestTy == IceType_i64) {
4672*03ce13f7SAndroid Build Coastguard Worker _mov(T_Dest, _64);
4673*03ce13f7SAndroid Build Coastguard Worker } else {
4674*03ce13f7SAndroid Build Coastguard Worker _mov(T_Dest, _32);
4675*03ce13f7SAndroid Build Coastguard Worker }
4676*03ce13f7SAndroid Build Coastguard Worker } else {
4677*03ce13f7SAndroid Build Coastguard Worker Constant *_127 = Ctx->getConstantInt(DestTy, 127);
4678*03ce13f7SAndroid Build Coastguard Worker if (DestTy == IceType_i64) {
4679*03ce13f7SAndroid Build Coastguard Worker _mov(T_Dest, _127);
4680*03ce13f7SAndroid Build Coastguard Worker } else {
4681*03ce13f7SAndroid Build Coastguard Worker _mov(T_Dest, _63);
4682*03ce13f7SAndroid Build Coastguard Worker }
4683*03ce13f7SAndroid Build Coastguard Worker }
4684*03ce13f7SAndroid Build Coastguard Worker _cmov(T_Dest, T, CondX86::Br_ne);
4685*03ce13f7SAndroid Build Coastguard Worker if (!Cttz) {
4686*03ce13f7SAndroid Build Coastguard Worker if (DestTy == IceType_i64) {
4687*03ce13f7SAndroid Build Coastguard Worker // Even though there's a _63 available at this point, that constant
4688*03ce13f7SAndroid Build Coastguard Worker // might not be an i32, which will cause the xor emission to fail.
4689*03ce13f7SAndroid Build Coastguard Worker Constant *_63 = Ctx->getConstantInt32(63);
4690*03ce13f7SAndroid Build Coastguard Worker _xor(T_Dest, _63);
4691*03ce13f7SAndroid Build Coastguard Worker } else {
4692*03ce13f7SAndroid Build Coastguard Worker _xor(T_Dest, _31);
4693*03ce13f7SAndroid Build Coastguard Worker }
4694*03ce13f7SAndroid Build Coastguard Worker }
4695*03ce13f7SAndroid Build Coastguard Worker if (Ty == IceType_i32) {
4696*03ce13f7SAndroid Build Coastguard Worker _mov(Dest, T_Dest);
4697*03ce13f7SAndroid Build Coastguard Worker return;
4698*03ce13f7SAndroid Build Coastguard Worker }
4699*03ce13f7SAndroid Build Coastguard Worker _add(T_Dest, _32);
4700*03ce13f7SAndroid Build Coastguard Worker auto *DestLo = llvm::cast<Variable>(loOperand(Dest));
4701*03ce13f7SAndroid Build Coastguard Worker auto *DestHi = llvm::cast<Variable>(hiOperand(Dest));
4702*03ce13f7SAndroid Build Coastguard Worker // Will be using "test" on this, so we need a registerized variable.
4703*03ce13f7SAndroid Build Coastguard Worker Variable *SecondVar = legalizeToReg(SecondVal);
4704*03ce13f7SAndroid Build Coastguard Worker Variable *T_Dest2 = makeReg(IceType_i32);
4705*03ce13f7SAndroid Build Coastguard Worker if (Cttz) {
4706*03ce13f7SAndroid Build Coastguard Worker _bsf(T_Dest2, SecondVar);
4707*03ce13f7SAndroid Build Coastguard Worker } else {
4708*03ce13f7SAndroid Build Coastguard Worker _bsr(T_Dest2, SecondVar);
4709*03ce13f7SAndroid Build Coastguard Worker _xor(T_Dest2, _31);
4710*03ce13f7SAndroid Build Coastguard Worker }
4711*03ce13f7SAndroid Build Coastguard Worker _test(SecondVar, SecondVar);
4712*03ce13f7SAndroid Build Coastguard Worker _cmov(T_Dest2, T_Dest, CondX86::Br_e);
4713*03ce13f7SAndroid Build Coastguard Worker _mov(DestLo, T_Dest2);
4714*03ce13f7SAndroid Build Coastguard Worker _mov(DestHi, Ctx->getConstantZero(IceType_i32));
4715*03ce13f7SAndroid Build Coastguard Worker }
4716*03ce13f7SAndroid Build Coastguard Worker
typedLoad(Type Ty,Variable * Dest,Variable * Base,Constant * Offset)4717*03ce13f7SAndroid Build Coastguard Worker void TargetX8632::typedLoad(Type Ty, Variable *Dest, Variable *Base,
4718*03ce13f7SAndroid Build Coastguard Worker Constant *Offset) {
4719*03ce13f7SAndroid Build Coastguard Worker // If Offset is a ConstantRelocatable in Non-SFI mode, we will need to
4720*03ce13f7SAndroid Build Coastguard Worker // legalize Mem properly.
4721*03ce13f7SAndroid Build Coastguard Worker if (Offset)
4722*03ce13f7SAndroid Build Coastguard Worker assert(!llvm::isa<ConstantRelocatable>(Offset));
4723*03ce13f7SAndroid Build Coastguard Worker
4724*03ce13f7SAndroid Build Coastguard Worker auto *Mem = X86OperandMem::create(Func, Ty, Base, Offset);
4725*03ce13f7SAndroid Build Coastguard Worker
4726*03ce13f7SAndroid Build Coastguard Worker if (isVectorType(Ty))
4727*03ce13f7SAndroid Build Coastguard Worker _movp(Dest, Mem);
4728*03ce13f7SAndroid Build Coastguard Worker else if (Ty == IceType_f64)
4729*03ce13f7SAndroid Build Coastguard Worker _movq(Dest, Mem);
4730*03ce13f7SAndroid Build Coastguard Worker else
4731*03ce13f7SAndroid Build Coastguard Worker _mov(Dest, Mem);
4732*03ce13f7SAndroid Build Coastguard Worker }
4733*03ce13f7SAndroid Build Coastguard Worker
typedStore(Type Ty,Variable * Value,Variable * Base,Constant * Offset)4734*03ce13f7SAndroid Build Coastguard Worker void TargetX8632::typedStore(Type Ty, Variable *Value, Variable *Base,
4735*03ce13f7SAndroid Build Coastguard Worker Constant *Offset) {
4736*03ce13f7SAndroid Build Coastguard Worker // If Offset is a ConstantRelocatable in Non-SFI mode, we will need to
4737*03ce13f7SAndroid Build Coastguard Worker // legalize Mem properly.
4738*03ce13f7SAndroid Build Coastguard Worker if (Offset)
4739*03ce13f7SAndroid Build Coastguard Worker assert(!llvm::isa<ConstantRelocatable>(Offset));
4740*03ce13f7SAndroid Build Coastguard Worker
4741*03ce13f7SAndroid Build Coastguard Worker auto *Mem = X86OperandMem::create(Func, Ty, Base, Offset);
4742*03ce13f7SAndroid Build Coastguard Worker
4743*03ce13f7SAndroid Build Coastguard Worker if (isVectorType(Ty))
4744*03ce13f7SAndroid Build Coastguard Worker _storep(Value, Mem);
4745*03ce13f7SAndroid Build Coastguard Worker else if (Ty == IceType_f64)
4746*03ce13f7SAndroid Build Coastguard Worker _storeq(Value, Mem);
4747*03ce13f7SAndroid Build Coastguard Worker else
4748*03ce13f7SAndroid Build Coastguard Worker _store(Value, Mem);
4749*03ce13f7SAndroid Build Coastguard Worker }
4750*03ce13f7SAndroid Build Coastguard Worker
copyMemory(Type Ty,Variable * Dest,Variable * Src,int32_t OffsetAmt)4751*03ce13f7SAndroid Build Coastguard Worker void TargetX8632::copyMemory(Type Ty, Variable *Dest, Variable *Src,
4752*03ce13f7SAndroid Build Coastguard Worker int32_t OffsetAmt) {
4753*03ce13f7SAndroid Build Coastguard Worker Constant *Offset = OffsetAmt ? Ctx->getConstantInt32(OffsetAmt) : nullptr;
4754*03ce13f7SAndroid Build Coastguard Worker // TODO(ascull): this or add nullptr test to _movp, _movq
4755*03ce13f7SAndroid Build Coastguard Worker Variable *Data = makeReg(Ty);
4756*03ce13f7SAndroid Build Coastguard Worker
4757*03ce13f7SAndroid Build Coastguard Worker typedLoad(Ty, Data, Src, Offset);
4758*03ce13f7SAndroid Build Coastguard Worker typedStore(Ty, Data, Dest, Offset);
4759*03ce13f7SAndroid Build Coastguard Worker }
4760*03ce13f7SAndroid Build Coastguard Worker
lowerMemcpy(Operand * Dest,Operand * Src,Operand * Count)4761*03ce13f7SAndroid Build Coastguard Worker void TargetX8632::lowerMemcpy(Operand *Dest, Operand *Src, Operand *Count) {
4762*03ce13f7SAndroid Build Coastguard Worker // There is a load and store for each chunk in the unroll
4763*03ce13f7SAndroid Build Coastguard Worker constexpr uint32_t BytesPerStorep = 16;
4764*03ce13f7SAndroid Build Coastguard Worker
4765*03ce13f7SAndroid Build Coastguard Worker // Check if the operands are constants
4766*03ce13f7SAndroid Build Coastguard Worker const auto *CountConst = llvm::dyn_cast<const ConstantInteger32>(Count);
4767*03ce13f7SAndroid Build Coastguard Worker const bool IsCountConst = CountConst != nullptr;
4768*03ce13f7SAndroid Build Coastguard Worker const uint32_t CountValue = IsCountConst ? CountConst->getValue() : 0;
4769*03ce13f7SAndroid Build Coastguard Worker
4770*03ce13f7SAndroid Build Coastguard Worker if (shouldOptimizeMemIntrins() && IsCountConst &&
4771*03ce13f7SAndroid Build Coastguard Worker CountValue <= BytesPerStorep * MEMCPY_UNROLL_LIMIT) {
4772*03ce13f7SAndroid Build Coastguard Worker // Unlikely, but nothing to do if it does happen
4773*03ce13f7SAndroid Build Coastguard Worker if (CountValue == 0)
4774*03ce13f7SAndroid Build Coastguard Worker return;
4775*03ce13f7SAndroid Build Coastguard Worker
4776*03ce13f7SAndroid Build Coastguard Worker Variable *SrcBase = legalizeToReg(Src);
4777*03ce13f7SAndroid Build Coastguard Worker Variable *DestBase = legalizeToReg(Dest);
4778*03ce13f7SAndroid Build Coastguard Worker
4779*03ce13f7SAndroid Build Coastguard Worker // Find the largest type that can be used and use it as much as possible
4780*03ce13f7SAndroid Build Coastguard Worker // in reverse order. Then handle any remainder with overlapping copies.
4781*03ce13f7SAndroid Build Coastguard Worker // Since the remainder will be at the end, there will be reduced pressure
4782*03ce13f7SAndroid Build Coastguard Worker // on the memory unit as the accesses to the same memory are far apart.
4783*03ce13f7SAndroid Build Coastguard Worker Type Ty = largestTypeInSize(CountValue);
4784*03ce13f7SAndroid Build Coastguard Worker uint32_t TyWidth = typeWidthInBytes(Ty);
4785*03ce13f7SAndroid Build Coastguard Worker
4786*03ce13f7SAndroid Build Coastguard Worker uint32_t RemainingBytes = CountValue;
4787*03ce13f7SAndroid Build Coastguard Worker int32_t Offset = (CountValue & ~(TyWidth - 1)) - TyWidth;
4788*03ce13f7SAndroid Build Coastguard Worker while (RemainingBytes >= TyWidth) {
4789*03ce13f7SAndroid Build Coastguard Worker copyMemory(Ty, DestBase, SrcBase, Offset);
4790*03ce13f7SAndroid Build Coastguard Worker RemainingBytes -= TyWidth;
4791*03ce13f7SAndroid Build Coastguard Worker Offset -= TyWidth;
4792*03ce13f7SAndroid Build Coastguard Worker }
4793*03ce13f7SAndroid Build Coastguard Worker
4794*03ce13f7SAndroid Build Coastguard Worker if (RemainingBytes == 0)
4795*03ce13f7SAndroid Build Coastguard Worker return;
4796*03ce13f7SAndroid Build Coastguard Worker
4797*03ce13f7SAndroid Build Coastguard Worker // Lower the remaining bytes. Adjust to larger types in order to make use
4798*03ce13f7SAndroid Build Coastguard Worker // of overlaps in the copies.
4799*03ce13f7SAndroid Build Coastguard Worker Type LeftOverTy = firstTypeThatFitsSize(RemainingBytes);
4800*03ce13f7SAndroid Build Coastguard Worker Offset = CountValue - typeWidthInBytes(LeftOverTy);
4801*03ce13f7SAndroid Build Coastguard Worker copyMemory(LeftOverTy, DestBase, SrcBase, Offset);
4802*03ce13f7SAndroid Build Coastguard Worker return;
4803*03ce13f7SAndroid Build Coastguard Worker }
4804*03ce13f7SAndroid Build Coastguard Worker
4805*03ce13f7SAndroid Build Coastguard Worker // Fall back on a function call
4806*03ce13f7SAndroid Build Coastguard Worker InstCall *Call = makeHelperCall(RuntimeHelper::H_call_memcpy, nullptr, 3);
4807*03ce13f7SAndroid Build Coastguard Worker Call->addArg(Dest);
4808*03ce13f7SAndroid Build Coastguard Worker Call->addArg(Src);
4809*03ce13f7SAndroid Build Coastguard Worker Call->addArg(Count);
4810*03ce13f7SAndroid Build Coastguard Worker lowerCall(Call);
4811*03ce13f7SAndroid Build Coastguard Worker }
4812*03ce13f7SAndroid Build Coastguard Worker
lowerMemmove(Operand * Dest,Operand * Src,Operand * Count)4813*03ce13f7SAndroid Build Coastguard Worker void TargetX8632::lowerMemmove(Operand *Dest, Operand *Src, Operand *Count) {
4814*03ce13f7SAndroid Build Coastguard Worker // There is a load and store for each chunk in the unroll
4815*03ce13f7SAndroid Build Coastguard Worker constexpr uint32_t BytesPerStorep = 16;
4816*03ce13f7SAndroid Build Coastguard Worker
4817*03ce13f7SAndroid Build Coastguard Worker // Check if the operands are constants
4818*03ce13f7SAndroid Build Coastguard Worker const auto *CountConst = llvm::dyn_cast<const ConstantInteger32>(Count);
4819*03ce13f7SAndroid Build Coastguard Worker const bool IsCountConst = CountConst != nullptr;
4820*03ce13f7SAndroid Build Coastguard Worker const uint32_t CountValue = IsCountConst ? CountConst->getValue() : 0;
4821*03ce13f7SAndroid Build Coastguard Worker
4822*03ce13f7SAndroid Build Coastguard Worker if (shouldOptimizeMemIntrins() && IsCountConst &&
4823*03ce13f7SAndroid Build Coastguard Worker CountValue <= BytesPerStorep * MEMMOVE_UNROLL_LIMIT) {
4824*03ce13f7SAndroid Build Coastguard Worker // Unlikely, but nothing to do if it does happen
4825*03ce13f7SAndroid Build Coastguard Worker if (CountValue == 0)
4826*03ce13f7SAndroid Build Coastguard Worker return;
4827*03ce13f7SAndroid Build Coastguard Worker
4828*03ce13f7SAndroid Build Coastguard Worker Variable *SrcBase = legalizeToReg(Src);
4829*03ce13f7SAndroid Build Coastguard Worker Variable *DestBase = legalizeToReg(Dest);
4830*03ce13f7SAndroid Build Coastguard Worker
4831*03ce13f7SAndroid Build Coastguard Worker std::tuple<Type, Constant *, Variable *> Moves[MEMMOVE_UNROLL_LIMIT];
4832*03ce13f7SAndroid Build Coastguard Worker Constant *Offset;
4833*03ce13f7SAndroid Build Coastguard Worker Variable *Reg;
4834*03ce13f7SAndroid Build Coastguard Worker
4835*03ce13f7SAndroid Build Coastguard Worker // Copy the data into registers as the source and destination could
4836*03ce13f7SAndroid Build Coastguard Worker // overlap so make sure not to clobber the memory. This also means
4837*03ce13f7SAndroid Build Coastguard Worker // overlapping moves can be used as we are taking a safe snapshot of the
4838*03ce13f7SAndroid Build Coastguard Worker // memory.
4839*03ce13f7SAndroid Build Coastguard Worker Type Ty = largestTypeInSize(CountValue);
4840*03ce13f7SAndroid Build Coastguard Worker uint32_t TyWidth = typeWidthInBytes(Ty);
4841*03ce13f7SAndroid Build Coastguard Worker
4842*03ce13f7SAndroid Build Coastguard Worker uint32_t RemainingBytes = CountValue;
4843*03ce13f7SAndroid Build Coastguard Worker int32_t OffsetAmt = (CountValue & ~(TyWidth - 1)) - TyWidth;
4844*03ce13f7SAndroid Build Coastguard Worker size_t N = 0;
4845*03ce13f7SAndroid Build Coastguard Worker while (RemainingBytes >= TyWidth) {
4846*03ce13f7SAndroid Build Coastguard Worker assert(N <= MEMMOVE_UNROLL_LIMIT);
4847*03ce13f7SAndroid Build Coastguard Worker Offset = Ctx->getConstantInt32(OffsetAmt);
4848*03ce13f7SAndroid Build Coastguard Worker Reg = makeReg(Ty);
4849*03ce13f7SAndroid Build Coastguard Worker typedLoad(Ty, Reg, SrcBase, Offset);
4850*03ce13f7SAndroid Build Coastguard Worker RemainingBytes -= TyWidth;
4851*03ce13f7SAndroid Build Coastguard Worker OffsetAmt -= TyWidth;
4852*03ce13f7SAndroid Build Coastguard Worker Moves[N++] = std::make_tuple(Ty, Offset, Reg);
4853*03ce13f7SAndroid Build Coastguard Worker }
4854*03ce13f7SAndroid Build Coastguard Worker
4855*03ce13f7SAndroid Build Coastguard Worker if (RemainingBytes != 0) {
4856*03ce13f7SAndroid Build Coastguard Worker // Lower the remaining bytes. Adjust to larger types in order to make
4857*03ce13f7SAndroid Build Coastguard Worker // use of overlaps in the copies.
4858*03ce13f7SAndroid Build Coastguard Worker assert(N <= MEMMOVE_UNROLL_LIMIT);
4859*03ce13f7SAndroid Build Coastguard Worker Ty = firstTypeThatFitsSize(RemainingBytes);
4860*03ce13f7SAndroid Build Coastguard Worker Offset = Ctx->getConstantInt32(CountValue - typeWidthInBytes(Ty));
4861*03ce13f7SAndroid Build Coastguard Worker Reg = makeReg(Ty);
4862*03ce13f7SAndroid Build Coastguard Worker typedLoad(Ty, Reg, SrcBase, Offset);
4863*03ce13f7SAndroid Build Coastguard Worker Moves[N++] = std::make_tuple(Ty, Offset, Reg);
4864*03ce13f7SAndroid Build Coastguard Worker }
4865*03ce13f7SAndroid Build Coastguard Worker
4866*03ce13f7SAndroid Build Coastguard Worker // Copy the data out into the destination memory
4867*03ce13f7SAndroid Build Coastguard Worker for (size_t i = 0; i < N; ++i) {
4868*03ce13f7SAndroid Build Coastguard Worker std::tie(Ty, Offset, Reg) = Moves[i];
4869*03ce13f7SAndroid Build Coastguard Worker typedStore(Ty, Reg, DestBase, Offset);
4870*03ce13f7SAndroid Build Coastguard Worker }
4871*03ce13f7SAndroid Build Coastguard Worker
4872*03ce13f7SAndroid Build Coastguard Worker return;
4873*03ce13f7SAndroid Build Coastguard Worker }
4874*03ce13f7SAndroid Build Coastguard Worker
4875*03ce13f7SAndroid Build Coastguard Worker // Fall back on a function call
4876*03ce13f7SAndroid Build Coastguard Worker InstCall *Call = makeHelperCall(RuntimeHelper::H_call_memmove, nullptr, 3);
4877*03ce13f7SAndroid Build Coastguard Worker Call->addArg(Dest);
4878*03ce13f7SAndroid Build Coastguard Worker Call->addArg(Src);
4879*03ce13f7SAndroid Build Coastguard Worker Call->addArg(Count);
4880*03ce13f7SAndroid Build Coastguard Worker lowerCall(Call);
4881*03ce13f7SAndroid Build Coastguard Worker }
4882*03ce13f7SAndroid Build Coastguard Worker
lowerMemset(Operand * Dest,Operand * Val,Operand * Count)4883*03ce13f7SAndroid Build Coastguard Worker void TargetX8632::lowerMemset(Operand *Dest, Operand *Val, Operand *Count) {
4884*03ce13f7SAndroid Build Coastguard Worker constexpr uint32_t BytesPerStorep = 16;
4885*03ce13f7SAndroid Build Coastguard Worker constexpr uint32_t BytesPerStoreq = 8;
4886*03ce13f7SAndroid Build Coastguard Worker constexpr uint32_t BytesPerStorei32 = 4;
4887*03ce13f7SAndroid Build Coastguard Worker assert(Val->getType() == IceType_i8);
4888*03ce13f7SAndroid Build Coastguard Worker
4889*03ce13f7SAndroid Build Coastguard Worker // Check if the operands are constants
4890*03ce13f7SAndroid Build Coastguard Worker const auto *CountConst = llvm::dyn_cast<const ConstantInteger32>(Count);
4891*03ce13f7SAndroid Build Coastguard Worker const auto *ValConst = llvm::dyn_cast<const ConstantInteger32>(Val);
4892*03ce13f7SAndroid Build Coastguard Worker const bool IsCountConst = CountConst != nullptr;
4893*03ce13f7SAndroid Build Coastguard Worker const bool IsValConst = ValConst != nullptr;
4894*03ce13f7SAndroid Build Coastguard Worker const uint32_t CountValue = IsCountConst ? CountConst->getValue() : 0;
4895*03ce13f7SAndroid Build Coastguard Worker const uint32_t ValValue = IsValConst ? ValConst->getValue() : 0;
4896*03ce13f7SAndroid Build Coastguard Worker
4897*03ce13f7SAndroid Build Coastguard Worker // Unlikely, but nothing to do if it does happen
4898*03ce13f7SAndroid Build Coastguard Worker if (IsCountConst && CountValue == 0)
4899*03ce13f7SAndroid Build Coastguard Worker return;
4900*03ce13f7SAndroid Build Coastguard Worker
4901*03ce13f7SAndroid Build Coastguard Worker // TODO(ascull): if the count is constant but val is not it would be
4902*03ce13f7SAndroid Build Coastguard Worker // possible to inline by spreading the value across 4 bytes and accessing
4903*03ce13f7SAndroid Build Coastguard Worker // subregs e.g. eax, ax and al.
4904*03ce13f7SAndroid Build Coastguard Worker if (shouldOptimizeMemIntrins() && IsCountConst && IsValConst) {
4905*03ce13f7SAndroid Build Coastguard Worker Variable *Base = nullptr;
4906*03ce13f7SAndroid Build Coastguard Worker Variable *VecReg = nullptr;
4907*03ce13f7SAndroid Build Coastguard Worker const uint32_t MaskValue = (ValValue & 0xff);
4908*03ce13f7SAndroid Build Coastguard Worker const uint32_t SpreadValue =
4909*03ce13f7SAndroid Build Coastguard Worker (MaskValue << 24) | (MaskValue << 16) | (MaskValue << 8) | MaskValue;
4910*03ce13f7SAndroid Build Coastguard Worker
4911*03ce13f7SAndroid Build Coastguard Worker auto lowerSet = [this, &Base, SpreadValue, &VecReg](Type Ty,
4912*03ce13f7SAndroid Build Coastguard Worker uint32_t OffsetAmt) {
4913*03ce13f7SAndroid Build Coastguard Worker assert(Base != nullptr);
4914*03ce13f7SAndroid Build Coastguard Worker Constant *Offset = OffsetAmt ? Ctx->getConstantInt32(OffsetAmt) : nullptr;
4915*03ce13f7SAndroid Build Coastguard Worker
4916*03ce13f7SAndroid Build Coastguard Worker // TODO(ascull): is 64-bit better with vector or scalar movq?
4917*03ce13f7SAndroid Build Coastguard Worker auto *Mem = X86OperandMem::create(Func, Ty, Base, Offset);
4918*03ce13f7SAndroid Build Coastguard Worker if (isVectorType(Ty)) {
4919*03ce13f7SAndroid Build Coastguard Worker assert(VecReg != nullptr);
4920*03ce13f7SAndroid Build Coastguard Worker _storep(VecReg, Mem);
4921*03ce13f7SAndroid Build Coastguard Worker } else if (Ty == IceType_f64) {
4922*03ce13f7SAndroid Build Coastguard Worker assert(VecReg != nullptr);
4923*03ce13f7SAndroid Build Coastguard Worker _storeq(VecReg, Mem);
4924*03ce13f7SAndroid Build Coastguard Worker } else {
4925*03ce13f7SAndroid Build Coastguard Worker assert(Ty != IceType_i64);
4926*03ce13f7SAndroid Build Coastguard Worker _store(Ctx->getConstantInt(Ty, SpreadValue), Mem);
4927*03ce13f7SAndroid Build Coastguard Worker }
4928*03ce13f7SAndroid Build Coastguard Worker };
4929*03ce13f7SAndroid Build Coastguard Worker
4930*03ce13f7SAndroid Build Coastguard Worker // Find the largest type that can be used and use it as much as possible
4931*03ce13f7SAndroid Build Coastguard Worker // in reverse order. Then handle any remainder with overlapping copies.
4932*03ce13f7SAndroid Build Coastguard Worker // Since the remainder will be at the end, there will be reduces pressure
4933*03ce13f7SAndroid Build Coastguard Worker // on the memory unit as the access to the same memory are far apart.
4934*03ce13f7SAndroid Build Coastguard Worker Type Ty = IceType_void;
4935*03ce13f7SAndroid Build Coastguard Worker if (ValValue == 0 && CountValue >= BytesPerStoreq &&
4936*03ce13f7SAndroid Build Coastguard Worker CountValue <= BytesPerStorep * MEMSET_UNROLL_LIMIT) {
4937*03ce13f7SAndroid Build Coastguard Worker // When the value is zero it can be loaded into a vector register
4938*03ce13f7SAndroid Build Coastguard Worker // cheaply using the xor trick.
4939*03ce13f7SAndroid Build Coastguard Worker Base = legalizeToReg(Dest);
4940*03ce13f7SAndroid Build Coastguard Worker VecReg = makeVectorOfZeros(IceType_v16i8);
4941*03ce13f7SAndroid Build Coastguard Worker Ty = largestTypeInSize(CountValue);
4942*03ce13f7SAndroid Build Coastguard Worker } else if (CountValue <= BytesPerStorei32 * MEMSET_UNROLL_LIMIT) {
4943*03ce13f7SAndroid Build Coastguard Worker // When the value is non-zero or the count is small we can't use vector
4944*03ce13f7SAndroid Build Coastguard Worker // instructions so are limited to 32-bit stores.
4945*03ce13f7SAndroid Build Coastguard Worker Base = legalizeToReg(Dest);
4946*03ce13f7SAndroid Build Coastguard Worker constexpr uint32_t MaxSize = 4;
4947*03ce13f7SAndroid Build Coastguard Worker Ty = largestTypeInSize(CountValue, MaxSize);
4948*03ce13f7SAndroid Build Coastguard Worker }
4949*03ce13f7SAndroid Build Coastguard Worker
4950*03ce13f7SAndroid Build Coastguard Worker if (Base) {
4951*03ce13f7SAndroid Build Coastguard Worker uint32_t TyWidth = typeWidthInBytes(Ty);
4952*03ce13f7SAndroid Build Coastguard Worker
4953*03ce13f7SAndroid Build Coastguard Worker uint32_t RemainingBytes = CountValue;
4954*03ce13f7SAndroid Build Coastguard Worker uint32_t Offset = (CountValue & ~(TyWidth - 1)) - TyWidth;
4955*03ce13f7SAndroid Build Coastguard Worker while (RemainingBytes >= TyWidth) {
4956*03ce13f7SAndroid Build Coastguard Worker lowerSet(Ty, Offset);
4957*03ce13f7SAndroid Build Coastguard Worker RemainingBytes -= TyWidth;
4958*03ce13f7SAndroid Build Coastguard Worker Offset -= TyWidth;
4959*03ce13f7SAndroid Build Coastguard Worker }
4960*03ce13f7SAndroid Build Coastguard Worker
4961*03ce13f7SAndroid Build Coastguard Worker if (RemainingBytes == 0)
4962*03ce13f7SAndroid Build Coastguard Worker return;
4963*03ce13f7SAndroid Build Coastguard Worker
4964*03ce13f7SAndroid Build Coastguard Worker // Lower the remaining bytes. Adjust to larger types in order to make
4965*03ce13f7SAndroid Build Coastguard Worker // use of overlaps in the copies.
4966*03ce13f7SAndroid Build Coastguard Worker Type LeftOverTy = firstTypeThatFitsSize(RemainingBytes);
4967*03ce13f7SAndroid Build Coastguard Worker Offset = CountValue - typeWidthInBytes(LeftOverTy);
4968*03ce13f7SAndroid Build Coastguard Worker lowerSet(LeftOverTy, Offset);
4969*03ce13f7SAndroid Build Coastguard Worker return;
4970*03ce13f7SAndroid Build Coastguard Worker }
4971*03ce13f7SAndroid Build Coastguard Worker }
4972*03ce13f7SAndroid Build Coastguard Worker
4973*03ce13f7SAndroid Build Coastguard Worker // Fall back on calling the memset function. The value operand needs to be
4974*03ce13f7SAndroid Build Coastguard Worker // extended to a stack slot size because the PNaCl ABI requires arguments to
4975*03ce13f7SAndroid Build Coastguard Worker // be at least 32 bits wide.
4976*03ce13f7SAndroid Build Coastguard Worker Operand *ValExt;
4977*03ce13f7SAndroid Build Coastguard Worker if (IsValConst) {
4978*03ce13f7SAndroid Build Coastguard Worker ValExt = Ctx->getConstantInt(stackSlotType(), ValValue);
4979*03ce13f7SAndroid Build Coastguard Worker } else {
4980*03ce13f7SAndroid Build Coastguard Worker Variable *ValExtVar = Func->makeVariable(stackSlotType());
4981*03ce13f7SAndroid Build Coastguard Worker lowerCast(InstCast::create(Func, InstCast::Zext, ValExtVar, Val));
4982*03ce13f7SAndroid Build Coastguard Worker ValExt = ValExtVar;
4983*03ce13f7SAndroid Build Coastguard Worker }
4984*03ce13f7SAndroid Build Coastguard Worker InstCall *Call = makeHelperCall(RuntimeHelper::H_call_memset, nullptr, 3);
4985*03ce13f7SAndroid Build Coastguard Worker Call->addArg(Dest);
4986*03ce13f7SAndroid Build Coastguard Worker Call->addArg(ValExt);
4987*03ce13f7SAndroid Build Coastguard Worker Call->addArg(Count);
4988*03ce13f7SAndroid Build Coastguard Worker lowerCall(Call);
4989*03ce13f7SAndroid Build Coastguard Worker }
4990*03ce13f7SAndroid Build Coastguard Worker
4991*03ce13f7SAndroid Build Coastguard Worker class AddressOptimizer {
4992*03ce13f7SAndroid Build Coastguard Worker AddressOptimizer() = delete;
4993*03ce13f7SAndroid Build Coastguard Worker AddressOptimizer(const AddressOptimizer &) = delete;
4994*03ce13f7SAndroid Build Coastguard Worker AddressOptimizer &operator=(const AddressOptimizer &) = delete;
4995*03ce13f7SAndroid Build Coastguard Worker
4996*03ce13f7SAndroid Build Coastguard Worker public:
AddressOptimizer(const Cfg * Func)4997*03ce13f7SAndroid Build Coastguard Worker explicit AddressOptimizer(const Cfg *Func)
4998*03ce13f7SAndroid Build Coastguard Worker : Func(Func), VMetadata(Func->getVMetadata()) {}
4999*03ce13f7SAndroid Build Coastguard Worker
5000*03ce13f7SAndroid Build Coastguard Worker inline void dumpAddressOpt(const ConstantRelocatable *const Relocatable,
5001*03ce13f7SAndroid Build Coastguard Worker int32_t Offset, const Variable *Base,
5002*03ce13f7SAndroid Build Coastguard Worker const Variable *Index, uint16_t Shift,
5003*03ce13f7SAndroid Build Coastguard Worker const Inst *Reason) const;
5004*03ce13f7SAndroid Build Coastguard Worker
5005*03ce13f7SAndroid Build Coastguard Worker inline const Inst *matchAssign(Variable **Var,
5006*03ce13f7SAndroid Build Coastguard Worker ConstantRelocatable **Relocatable,
5007*03ce13f7SAndroid Build Coastguard Worker int32_t *Offset);
5008*03ce13f7SAndroid Build Coastguard Worker
5009*03ce13f7SAndroid Build Coastguard Worker inline const Inst *matchCombinedBaseIndex(Variable **Base, Variable **Index,
5010*03ce13f7SAndroid Build Coastguard Worker uint16_t *Shift);
5011*03ce13f7SAndroid Build Coastguard Worker
5012*03ce13f7SAndroid Build Coastguard Worker inline const Inst *matchShiftedIndex(Variable **Index, uint16_t *Shift);
5013*03ce13f7SAndroid Build Coastguard Worker
5014*03ce13f7SAndroid Build Coastguard Worker inline const Inst *matchOffsetIndexOrBase(Variable **IndexOrBase,
5015*03ce13f7SAndroid Build Coastguard Worker const uint16_t Shift,
5016*03ce13f7SAndroid Build Coastguard Worker ConstantRelocatable **Relocatable,
5017*03ce13f7SAndroid Build Coastguard Worker int32_t *Offset);
5018*03ce13f7SAndroid Build Coastguard Worker
5019*03ce13f7SAndroid Build Coastguard Worker private:
5020*03ce13f7SAndroid Build Coastguard Worker const Cfg *const Func;
5021*03ce13f7SAndroid Build Coastguard Worker const VariablesMetadata *const VMetadata;
5022*03ce13f7SAndroid Build Coastguard Worker
isAdd(const Inst * Instr)5023*03ce13f7SAndroid Build Coastguard Worker static bool isAdd(const Inst *Instr) {
5024*03ce13f7SAndroid Build Coastguard Worker if (auto *Arith = llvm::dyn_cast_or_null<const InstArithmetic>(Instr)) {
5025*03ce13f7SAndroid Build Coastguard Worker return (Arith->getOp() == InstArithmetic::Add);
5026*03ce13f7SAndroid Build Coastguard Worker }
5027*03ce13f7SAndroid Build Coastguard Worker return false;
5028*03ce13f7SAndroid Build Coastguard Worker }
5029*03ce13f7SAndroid Build Coastguard Worker };
5030*03ce13f7SAndroid Build Coastguard Worker
dumpAddressOpt(const ConstantRelocatable * const Relocatable,int32_t Offset,const Variable * Base,const Variable * Index,uint16_t Shift,const Inst * Reason) const5031*03ce13f7SAndroid Build Coastguard Worker void AddressOptimizer::dumpAddressOpt(
5032*03ce13f7SAndroid Build Coastguard Worker const ConstantRelocatable *const Relocatable, int32_t Offset,
5033*03ce13f7SAndroid Build Coastguard Worker const Variable *Base, const Variable *Index, uint16_t Shift,
5034*03ce13f7SAndroid Build Coastguard Worker const Inst *Reason) const {
5035*03ce13f7SAndroid Build Coastguard Worker if (!BuildDefs::dump())
5036*03ce13f7SAndroid Build Coastguard Worker return;
5037*03ce13f7SAndroid Build Coastguard Worker if (!Func->isVerbose(IceV_AddrOpt))
5038*03ce13f7SAndroid Build Coastguard Worker return;
5039*03ce13f7SAndroid Build Coastguard Worker OstreamLocker L(Func->getContext());
5040*03ce13f7SAndroid Build Coastguard Worker Ostream &Str = Func->getContext()->getStrDump();
5041*03ce13f7SAndroid Build Coastguard Worker Str << "Instruction: ";
5042*03ce13f7SAndroid Build Coastguard Worker Reason->dumpDecorated(Func);
5043*03ce13f7SAndroid Build Coastguard Worker Str << " results in Base=";
5044*03ce13f7SAndroid Build Coastguard Worker if (Base)
5045*03ce13f7SAndroid Build Coastguard Worker Base->dump(Func);
5046*03ce13f7SAndroid Build Coastguard Worker else
5047*03ce13f7SAndroid Build Coastguard Worker Str << "<null>";
5048*03ce13f7SAndroid Build Coastguard Worker Str << ", Index=";
5049*03ce13f7SAndroid Build Coastguard Worker if (Index)
5050*03ce13f7SAndroid Build Coastguard Worker Index->dump(Func);
5051*03ce13f7SAndroid Build Coastguard Worker else
5052*03ce13f7SAndroid Build Coastguard Worker Str << "<null>";
5053*03ce13f7SAndroid Build Coastguard Worker Str << ", Shift=" << Shift << ", Offset=" << Offset
5054*03ce13f7SAndroid Build Coastguard Worker << ", Relocatable=" << Relocatable << "\n";
5055*03ce13f7SAndroid Build Coastguard Worker }
5056*03ce13f7SAndroid Build Coastguard Worker
matchAssign(Variable ** Var,ConstantRelocatable ** Relocatable,int32_t * Offset)5057*03ce13f7SAndroid Build Coastguard Worker const Inst *AddressOptimizer::matchAssign(Variable **Var,
5058*03ce13f7SAndroid Build Coastguard Worker ConstantRelocatable **Relocatable,
5059*03ce13f7SAndroid Build Coastguard Worker int32_t *Offset) {
5060*03ce13f7SAndroid Build Coastguard Worker // Var originates from Var=SrcVar ==> set Var:=SrcVar
5061*03ce13f7SAndroid Build Coastguard Worker if (*Var == nullptr)
5062*03ce13f7SAndroid Build Coastguard Worker return nullptr;
5063*03ce13f7SAndroid Build Coastguard Worker if (const Inst *VarAssign = VMetadata->getSingleDefinition(*Var)) {
5064*03ce13f7SAndroid Build Coastguard Worker assert(!VMetadata->isMultiDef(*Var));
5065*03ce13f7SAndroid Build Coastguard Worker if (llvm::isa<InstAssign>(VarAssign)) {
5066*03ce13f7SAndroid Build Coastguard Worker Operand *SrcOp = VarAssign->getSrc(0);
5067*03ce13f7SAndroid Build Coastguard Worker assert(SrcOp);
5068*03ce13f7SAndroid Build Coastguard Worker if (auto *SrcVar = llvm::dyn_cast<Variable>(SrcOp)) {
5069*03ce13f7SAndroid Build Coastguard Worker if (!VMetadata->isMultiDef(SrcVar) &&
5070*03ce13f7SAndroid Build Coastguard Worker // TODO: ensure SrcVar stays single-BB
5071*03ce13f7SAndroid Build Coastguard Worker true) {
5072*03ce13f7SAndroid Build Coastguard Worker *Var = SrcVar;
5073*03ce13f7SAndroid Build Coastguard Worker return VarAssign;
5074*03ce13f7SAndroid Build Coastguard Worker }
5075*03ce13f7SAndroid Build Coastguard Worker } else if (auto *Const = llvm::dyn_cast<ConstantInteger32>(SrcOp)) {
5076*03ce13f7SAndroid Build Coastguard Worker int32_t MoreOffset = Const->getValue();
5077*03ce13f7SAndroid Build Coastguard Worker if (Utils::WouldOverflowAdd(*Offset, MoreOffset))
5078*03ce13f7SAndroid Build Coastguard Worker return nullptr;
5079*03ce13f7SAndroid Build Coastguard Worker *Var = nullptr;
5080*03ce13f7SAndroid Build Coastguard Worker *Offset += MoreOffset;
5081*03ce13f7SAndroid Build Coastguard Worker return VarAssign;
5082*03ce13f7SAndroid Build Coastguard Worker } else if (auto *AddReloc = llvm::dyn_cast<ConstantRelocatable>(SrcOp)) {
5083*03ce13f7SAndroid Build Coastguard Worker if (*Relocatable == nullptr) {
5084*03ce13f7SAndroid Build Coastguard Worker // It is always safe to fold a relocatable through assignment -- the
5085*03ce13f7SAndroid Build Coastguard Worker // assignment frees a slot in the address operand that can be used
5086*03ce13f7SAndroid Build Coastguard Worker // to hold the Sandbox Pointer -- if any.
5087*03ce13f7SAndroid Build Coastguard Worker *Var = nullptr;
5088*03ce13f7SAndroid Build Coastguard Worker *Relocatable = AddReloc;
5089*03ce13f7SAndroid Build Coastguard Worker return VarAssign;
5090*03ce13f7SAndroid Build Coastguard Worker }
5091*03ce13f7SAndroid Build Coastguard Worker }
5092*03ce13f7SAndroid Build Coastguard Worker }
5093*03ce13f7SAndroid Build Coastguard Worker }
5094*03ce13f7SAndroid Build Coastguard Worker return nullptr;
5095*03ce13f7SAndroid Build Coastguard Worker }
5096*03ce13f7SAndroid Build Coastguard Worker
matchCombinedBaseIndex(Variable ** Base,Variable ** Index,uint16_t * Shift)5097*03ce13f7SAndroid Build Coastguard Worker const Inst *AddressOptimizer::matchCombinedBaseIndex(Variable **Base,
5098*03ce13f7SAndroid Build Coastguard Worker Variable **Index,
5099*03ce13f7SAndroid Build Coastguard Worker uint16_t *Shift) {
5100*03ce13f7SAndroid Build Coastguard Worker // Index==nullptr && Base is Base=Var1+Var2 ==>
5101*03ce13f7SAndroid Build Coastguard Worker // set Base=Var1, Index=Var2, Shift=0
5102*03ce13f7SAndroid Build Coastguard Worker if (*Base == nullptr)
5103*03ce13f7SAndroid Build Coastguard Worker return nullptr;
5104*03ce13f7SAndroid Build Coastguard Worker if (*Index != nullptr)
5105*03ce13f7SAndroid Build Coastguard Worker return nullptr;
5106*03ce13f7SAndroid Build Coastguard Worker auto *BaseInst = VMetadata->getSingleDefinition(*Base);
5107*03ce13f7SAndroid Build Coastguard Worker if (BaseInst == nullptr)
5108*03ce13f7SAndroid Build Coastguard Worker return nullptr;
5109*03ce13f7SAndroid Build Coastguard Worker assert(!VMetadata->isMultiDef(*Base));
5110*03ce13f7SAndroid Build Coastguard Worker if (BaseInst->getSrcSize() < 2)
5111*03ce13f7SAndroid Build Coastguard Worker return nullptr;
5112*03ce13f7SAndroid Build Coastguard Worker if (auto *Var1 = llvm::dyn_cast<Variable>(BaseInst->getSrc(0))) {
5113*03ce13f7SAndroid Build Coastguard Worker if (VMetadata->isMultiDef(Var1))
5114*03ce13f7SAndroid Build Coastguard Worker return nullptr;
5115*03ce13f7SAndroid Build Coastguard Worker if (auto *Var2 = llvm::dyn_cast<Variable>(BaseInst->getSrc(1))) {
5116*03ce13f7SAndroid Build Coastguard Worker if (VMetadata->isMultiDef(Var2))
5117*03ce13f7SAndroid Build Coastguard Worker return nullptr;
5118*03ce13f7SAndroid Build Coastguard Worker if (isAdd(BaseInst) &&
5119*03ce13f7SAndroid Build Coastguard Worker // TODO: ensure Var1 and Var2 stay single-BB
5120*03ce13f7SAndroid Build Coastguard Worker true) {
5121*03ce13f7SAndroid Build Coastguard Worker *Base = Var1;
5122*03ce13f7SAndroid Build Coastguard Worker *Index = Var2;
5123*03ce13f7SAndroid Build Coastguard Worker *Shift = 0; // should already have been 0
5124*03ce13f7SAndroid Build Coastguard Worker return BaseInst;
5125*03ce13f7SAndroid Build Coastguard Worker }
5126*03ce13f7SAndroid Build Coastguard Worker }
5127*03ce13f7SAndroid Build Coastguard Worker }
5128*03ce13f7SAndroid Build Coastguard Worker return nullptr;
5129*03ce13f7SAndroid Build Coastguard Worker }
5130*03ce13f7SAndroid Build Coastguard Worker
matchShiftedIndex(Variable ** Index,uint16_t * Shift)5131*03ce13f7SAndroid Build Coastguard Worker const Inst *AddressOptimizer::matchShiftedIndex(Variable **Index,
5132*03ce13f7SAndroid Build Coastguard Worker uint16_t *Shift) {
5133*03ce13f7SAndroid Build Coastguard Worker // Index is Index=Var*Const && log2(Const)+Shift<=3 ==>
5134*03ce13f7SAndroid Build Coastguard Worker // Index=Var, Shift+=log2(Const)
5135*03ce13f7SAndroid Build Coastguard Worker if (*Index == nullptr)
5136*03ce13f7SAndroid Build Coastguard Worker return nullptr;
5137*03ce13f7SAndroid Build Coastguard Worker auto *IndexInst = VMetadata->getSingleDefinition(*Index);
5138*03ce13f7SAndroid Build Coastguard Worker if (IndexInst == nullptr)
5139*03ce13f7SAndroid Build Coastguard Worker return nullptr;
5140*03ce13f7SAndroid Build Coastguard Worker assert(!VMetadata->isMultiDef(*Index));
5141*03ce13f7SAndroid Build Coastguard Worker
5142*03ce13f7SAndroid Build Coastguard Worker // When using an unsigned 32-bit array index on x64, it gets zero-extended
5143*03ce13f7SAndroid Build Coastguard Worker // before the shift & add. The explicit zero extension can be eliminated
5144*03ce13f7SAndroid Build Coastguard Worker // because x86 32-bit operations automatically get zero-extended into the
5145*03ce13f7SAndroid Build Coastguard Worker // corresponding 64-bit register.
5146*03ce13f7SAndroid Build Coastguard Worker if (auto *CastInst = llvm::dyn_cast<InstCast>(IndexInst)) {
5147*03ce13f7SAndroid Build Coastguard Worker if (CastInst->getCastKind() == InstCast::Zext) {
5148*03ce13f7SAndroid Build Coastguard Worker if (auto *Var = llvm::dyn_cast<Variable>(CastInst->getSrc(0))) {
5149*03ce13f7SAndroid Build Coastguard Worker if (Var->getType() == IceType_i32 &&
5150*03ce13f7SAndroid Build Coastguard Worker CastInst->getDest()->getType() == IceType_i64) {
5151*03ce13f7SAndroid Build Coastguard Worker IndexInst = VMetadata->getSingleDefinition(Var);
5152*03ce13f7SAndroid Build Coastguard Worker }
5153*03ce13f7SAndroid Build Coastguard Worker }
5154*03ce13f7SAndroid Build Coastguard Worker }
5155*03ce13f7SAndroid Build Coastguard Worker }
5156*03ce13f7SAndroid Build Coastguard Worker
5157*03ce13f7SAndroid Build Coastguard Worker if (IndexInst->getSrcSize() < 2)
5158*03ce13f7SAndroid Build Coastguard Worker return nullptr;
5159*03ce13f7SAndroid Build Coastguard Worker if (auto *ArithInst = llvm::dyn_cast<InstArithmetic>(IndexInst)) {
5160*03ce13f7SAndroid Build Coastguard Worker if (auto *Var = llvm::dyn_cast<Variable>(ArithInst->getSrc(0))) {
5161*03ce13f7SAndroid Build Coastguard Worker if (auto *Const =
5162*03ce13f7SAndroid Build Coastguard Worker llvm::dyn_cast<ConstantInteger32>(ArithInst->getSrc(1))) {
5163*03ce13f7SAndroid Build Coastguard Worker if (VMetadata->isMultiDef(Var) || Const->getType() != IceType_i32)
5164*03ce13f7SAndroid Build Coastguard Worker return nullptr;
5165*03ce13f7SAndroid Build Coastguard Worker switch (ArithInst->getOp()) {
5166*03ce13f7SAndroid Build Coastguard Worker default:
5167*03ce13f7SAndroid Build Coastguard Worker return nullptr;
5168*03ce13f7SAndroid Build Coastguard Worker case InstArithmetic::Mul: {
5169*03ce13f7SAndroid Build Coastguard Worker uint32_t Mult = Const->getValue();
5170*03ce13f7SAndroid Build Coastguard Worker uint32_t LogMult;
5171*03ce13f7SAndroid Build Coastguard Worker switch (Mult) {
5172*03ce13f7SAndroid Build Coastguard Worker case 1:
5173*03ce13f7SAndroid Build Coastguard Worker LogMult = 0;
5174*03ce13f7SAndroid Build Coastguard Worker break;
5175*03ce13f7SAndroid Build Coastguard Worker case 2:
5176*03ce13f7SAndroid Build Coastguard Worker LogMult = 1;
5177*03ce13f7SAndroid Build Coastguard Worker break;
5178*03ce13f7SAndroid Build Coastguard Worker case 4:
5179*03ce13f7SAndroid Build Coastguard Worker LogMult = 2;
5180*03ce13f7SAndroid Build Coastguard Worker break;
5181*03ce13f7SAndroid Build Coastguard Worker case 8:
5182*03ce13f7SAndroid Build Coastguard Worker LogMult = 3;
5183*03ce13f7SAndroid Build Coastguard Worker break;
5184*03ce13f7SAndroid Build Coastguard Worker default:
5185*03ce13f7SAndroid Build Coastguard Worker return nullptr;
5186*03ce13f7SAndroid Build Coastguard Worker }
5187*03ce13f7SAndroid Build Coastguard Worker if (*Shift + LogMult <= 3) {
5188*03ce13f7SAndroid Build Coastguard Worker *Index = Var;
5189*03ce13f7SAndroid Build Coastguard Worker *Shift += LogMult;
5190*03ce13f7SAndroid Build Coastguard Worker return IndexInst;
5191*03ce13f7SAndroid Build Coastguard Worker }
5192*03ce13f7SAndroid Build Coastguard Worker }
5193*03ce13f7SAndroid Build Coastguard Worker case InstArithmetic::Shl: {
5194*03ce13f7SAndroid Build Coastguard Worker uint32_t ShiftAmount = Const->getValue();
5195*03ce13f7SAndroid Build Coastguard Worker switch (ShiftAmount) {
5196*03ce13f7SAndroid Build Coastguard Worker case 0:
5197*03ce13f7SAndroid Build Coastguard Worker case 1:
5198*03ce13f7SAndroid Build Coastguard Worker case 2:
5199*03ce13f7SAndroid Build Coastguard Worker case 3:
5200*03ce13f7SAndroid Build Coastguard Worker break;
5201*03ce13f7SAndroid Build Coastguard Worker default:
5202*03ce13f7SAndroid Build Coastguard Worker return nullptr;
5203*03ce13f7SAndroid Build Coastguard Worker }
5204*03ce13f7SAndroid Build Coastguard Worker if (*Shift + ShiftAmount <= 3) {
5205*03ce13f7SAndroid Build Coastguard Worker *Index = Var;
5206*03ce13f7SAndroid Build Coastguard Worker *Shift += ShiftAmount;
5207*03ce13f7SAndroid Build Coastguard Worker return IndexInst;
5208*03ce13f7SAndroid Build Coastguard Worker }
5209*03ce13f7SAndroid Build Coastguard Worker }
5210*03ce13f7SAndroid Build Coastguard Worker }
5211*03ce13f7SAndroid Build Coastguard Worker }
5212*03ce13f7SAndroid Build Coastguard Worker }
5213*03ce13f7SAndroid Build Coastguard Worker }
5214*03ce13f7SAndroid Build Coastguard Worker return nullptr;
5215*03ce13f7SAndroid Build Coastguard Worker }
5216*03ce13f7SAndroid Build Coastguard Worker
matchOffsetIndexOrBase(Variable ** IndexOrBase,const uint16_t Shift,ConstantRelocatable ** Relocatable,int32_t * Offset)5217*03ce13f7SAndroid Build Coastguard Worker const Inst *AddressOptimizer::matchOffsetIndexOrBase(
5218*03ce13f7SAndroid Build Coastguard Worker Variable **IndexOrBase, const uint16_t Shift,
5219*03ce13f7SAndroid Build Coastguard Worker ConstantRelocatable **Relocatable, int32_t *Offset) {
5220*03ce13f7SAndroid Build Coastguard Worker // Base is Base=Var+Const || Base is Base=Const+Var ==>
5221*03ce13f7SAndroid Build Coastguard Worker // set Base=Var, Offset+=Const
5222*03ce13f7SAndroid Build Coastguard Worker // Base is Base=Var-Const ==>
5223*03ce13f7SAndroid Build Coastguard Worker // set Base=Var, Offset-=Const
5224*03ce13f7SAndroid Build Coastguard Worker // Index is Index=Var+Const ==>
5225*03ce13f7SAndroid Build Coastguard Worker // set Index=Var, Offset+=(Const<<Shift)
5226*03ce13f7SAndroid Build Coastguard Worker // Index is Index=Const+Var ==>
5227*03ce13f7SAndroid Build Coastguard Worker // set Index=Var, Offset+=(Const<<Shift)
5228*03ce13f7SAndroid Build Coastguard Worker // Index is Index=Var-Const ==>
5229*03ce13f7SAndroid Build Coastguard Worker // set Index=Var, Offset-=(Const<<Shift)
5230*03ce13f7SAndroid Build Coastguard Worker // Treat Index=Var Or Const as Index=Var + Const
5231*03ce13f7SAndroid Build Coastguard Worker // when Var = Var' << N and log2(Const) <= N
5232*03ce13f7SAndroid Build Coastguard Worker // or when Var = (2^M) * (2^N) and log2(Const) <= (M+N)
5233*03ce13f7SAndroid Build Coastguard Worker
5234*03ce13f7SAndroid Build Coastguard Worker if (*IndexOrBase == nullptr) {
5235*03ce13f7SAndroid Build Coastguard Worker return nullptr;
5236*03ce13f7SAndroid Build Coastguard Worker }
5237*03ce13f7SAndroid Build Coastguard Worker const Inst *Definition = VMetadata->getSingleDefinition(*IndexOrBase);
5238*03ce13f7SAndroid Build Coastguard Worker if (Definition == nullptr) {
5239*03ce13f7SAndroid Build Coastguard Worker return nullptr;
5240*03ce13f7SAndroid Build Coastguard Worker }
5241*03ce13f7SAndroid Build Coastguard Worker assert(!VMetadata->isMultiDef(*IndexOrBase));
5242*03ce13f7SAndroid Build Coastguard Worker if (auto *ArithInst = llvm::dyn_cast<const InstArithmetic>(Definition)) {
5243*03ce13f7SAndroid Build Coastguard Worker switch (ArithInst->getOp()) {
5244*03ce13f7SAndroid Build Coastguard Worker case InstArithmetic::Add:
5245*03ce13f7SAndroid Build Coastguard Worker case InstArithmetic::Sub:
5246*03ce13f7SAndroid Build Coastguard Worker case InstArithmetic::Or:
5247*03ce13f7SAndroid Build Coastguard Worker break;
5248*03ce13f7SAndroid Build Coastguard Worker default:
5249*03ce13f7SAndroid Build Coastguard Worker return nullptr;
5250*03ce13f7SAndroid Build Coastguard Worker }
5251*03ce13f7SAndroid Build Coastguard Worker
5252*03ce13f7SAndroid Build Coastguard Worker Operand *Src0 = ArithInst->getSrc(0);
5253*03ce13f7SAndroid Build Coastguard Worker Operand *Src1 = ArithInst->getSrc(1);
5254*03ce13f7SAndroid Build Coastguard Worker auto *Var0 = llvm::dyn_cast<Variable>(Src0);
5255*03ce13f7SAndroid Build Coastguard Worker auto *Var1 = llvm::dyn_cast<Variable>(Src1);
5256*03ce13f7SAndroid Build Coastguard Worker auto *Const0 = llvm::dyn_cast<ConstantInteger32>(Src0);
5257*03ce13f7SAndroid Build Coastguard Worker auto *Const1 = llvm::dyn_cast<ConstantInteger32>(Src1);
5258*03ce13f7SAndroid Build Coastguard Worker auto *Reloc0 = llvm::dyn_cast<ConstantRelocatable>(Src0);
5259*03ce13f7SAndroid Build Coastguard Worker auto *Reloc1 = llvm::dyn_cast<ConstantRelocatable>(Src1);
5260*03ce13f7SAndroid Build Coastguard Worker
5261*03ce13f7SAndroid Build Coastguard Worker bool IsAdd = false;
5262*03ce13f7SAndroid Build Coastguard Worker if (ArithInst->getOp() == InstArithmetic::Or) {
5263*03ce13f7SAndroid Build Coastguard Worker Variable *Var = nullptr;
5264*03ce13f7SAndroid Build Coastguard Worker ConstantInteger32 *Const = nullptr;
5265*03ce13f7SAndroid Build Coastguard Worker if (Var0 && Const1) {
5266*03ce13f7SAndroid Build Coastguard Worker Var = Var0;
5267*03ce13f7SAndroid Build Coastguard Worker Const = Const1;
5268*03ce13f7SAndroid Build Coastguard Worker } else if (Const0 && Var1) {
5269*03ce13f7SAndroid Build Coastguard Worker Var = Var1;
5270*03ce13f7SAndroid Build Coastguard Worker Const = Const0;
5271*03ce13f7SAndroid Build Coastguard Worker } else {
5272*03ce13f7SAndroid Build Coastguard Worker return nullptr;
5273*03ce13f7SAndroid Build Coastguard Worker }
5274*03ce13f7SAndroid Build Coastguard Worker auto *VarDef =
5275*03ce13f7SAndroid Build Coastguard Worker llvm::dyn_cast<InstArithmetic>(VMetadata->getSingleDefinition(Var));
5276*03ce13f7SAndroid Build Coastguard Worker if (VarDef == nullptr)
5277*03ce13f7SAndroid Build Coastguard Worker return nullptr;
5278*03ce13f7SAndroid Build Coastguard Worker
5279*03ce13f7SAndroid Build Coastguard Worker SizeT ZeroesAvailable = 0;
5280*03ce13f7SAndroid Build Coastguard Worker if (VarDef->getOp() == InstArithmetic::Shl) {
5281*03ce13f7SAndroid Build Coastguard Worker if (auto *ConstInt =
5282*03ce13f7SAndroid Build Coastguard Worker llvm::dyn_cast<ConstantInteger32>(VarDef->getSrc(1))) {
5283*03ce13f7SAndroid Build Coastguard Worker ZeroesAvailable = ConstInt->getValue();
5284*03ce13f7SAndroid Build Coastguard Worker }
5285*03ce13f7SAndroid Build Coastguard Worker } else if (VarDef->getOp() == InstArithmetic::Mul) {
5286*03ce13f7SAndroid Build Coastguard Worker SizeT PowerOfTwo = 0;
5287*03ce13f7SAndroid Build Coastguard Worker if (auto *MultConst =
5288*03ce13f7SAndroid Build Coastguard Worker llvm::dyn_cast<ConstantInteger32>(VarDef->getSrc(0))) {
5289*03ce13f7SAndroid Build Coastguard Worker if (llvm::isPowerOf2_32(MultConst->getValue())) {
5290*03ce13f7SAndroid Build Coastguard Worker PowerOfTwo += MultConst->getValue();
5291*03ce13f7SAndroid Build Coastguard Worker }
5292*03ce13f7SAndroid Build Coastguard Worker }
5293*03ce13f7SAndroid Build Coastguard Worker if (auto *MultConst =
5294*03ce13f7SAndroid Build Coastguard Worker llvm::dyn_cast<ConstantInteger32>(VarDef->getSrc(1))) {
5295*03ce13f7SAndroid Build Coastguard Worker if (llvm::isPowerOf2_32(MultConst->getValue())) {
5296*03ce13f7SAndroid Build Coastguard Worker PowerOfTwo += MultConst->getValue();
5297*03ce13f7SAndroid Build Coastguard Worker }
5298*03ce13f7SAndroid Build Coastguard Worker }
5299*03ce13f7SAndroid Build Coastguard Worker ZeroesAvailable = llvm::Log2_32(PowerOfTwo) + 1;
5300*03ce13f7SAndroid Build Coastguard Worker }
5301*03ce13f7SAndroid Build Coastguard Worker SizeT ZeroesNeeded = llvm::Log2_32(Const->getValue()) + 1;
5302*03ce13f7SAndroid Build Coastguard Worker if (ZeroesNeeded == 0 || ZeroesNeeded > ZeroesAvailable)
5303*03ce13f7SAndroid Build Coastguard Worker return nullptr;
5304*03ce13f7SAndroid Build Coastguard Worker IsAdd = true; // treat it as an add if the above conditions hold
5305*03ce13f7SAndroid Build Coastguard Worker } else {
5306*03ce13f7SAndroid Build Coastguard Worker IsAdd = ArithInst->getOp() == InstArithmetic::Add;
5307*03ce13f7SAndroid Build Coastguard Worker }
5308*03ce13f7SAndroid Build Coastguard Worker
5309*03ce13f7SAndroid Build Coastguard Worker Variable *NewIndexOrBase = nullptr;
5310*03ce13f7SAndroid Build Coastguard Worker int32_t NewOffset = 0;
5311*03ce13f7SAndroid Build Coastguard Worker ConstantRelocatable *NewRelocatable = *Relocatable;
5312*03ce13f7SAndroid Build Coastguard Worker if (Var0 && Var1)
5313*03ce13f7SAndroid Build Coastguard Worker // TODO(sehr): merge base/index splitting into here.
5314*03ce13f7SAndroid Build Coastguard Worker return nullptr;
5315*03ce13f7SAndroid Build Coastguard Worker if (!IsAdd && Var1)
5316*03ce13f7SAndroid Build Coastguard Worker return nullptr;
5317*03ce13f7SAndroid Build Coastguard Worker if (Var0)
5318*03ce13f7SAndroid Build Coastguard Worker NewIndexOrBase = Var0;
5319*03ce13f7SAndroid Build Coastguard Worker else if (Var1)
5320*03ce13f7SAndroid Build Coastguard Worker NewIndexOrBase = Var1;
5321*03ce13f7SAndroid Build Coastguard Worker // Don't know how to add/subtract two relocatables.
5322*03ce13f7SAndroid Build Coastguard Worker if ((*Relocatable && (Reloc0 || Reloc1)) || (Reloc0 && Reloc1))
5323*03ce13f7SAndroid Build Coastguard Worker return nullptr;
5324*03ce13f7SAndroid Build Coastguard Worker // Don't know how to subtract a relocatable.
5325*03ce13f7SAndroid Build Coastguard Worker if (!IsAdd && Reloc1)
5326*03ce13f7SAndroid Build Coastguard Worker return nullptr;
5327*03ce13f7SAndroid Build Coastguard Worker // Incorporate ConstantRelocatables.
5328*03ce13f7SAndroid Build Coastguard Worker if (Reloc0)
5329*03ce13f7SAndroid Build Coastguard Worker NewRelocatable = Reloc0;
5330*03ce13f7SAndroid Build Coastguard Worker else if (Reloc1)
5331*03ce13f7SAndroid Build Coastguard Worker NewRelocatable = Reloc1;
5332*03ce13f7SAndroid Build Coastguard Worker // Compute the updated constant offset.
5333*03ce13f7SAndroid Build Coastguard Worker if (Const0) {
5334*03ce13f7SAndroid Build Coastguard Worker const int32_t MoreOffset =
5335*03ce13f7SAndroid Build Coastguard Worker IsAdd ? Const0->getValue() : -Const0->getValue();
5336*03ce13f7SAndroid Build Coastguard Worker if (Utils::WouldOverflowAdd(*Offset + NewOffset, MoreOffset))
5337*03ce13f7SAndroid Build Coastguard Worker return nullptr;
5338*03ce13f7SAndroid Build Coastguard Worker NewOffset += MoreOffset;
5339*03ce13f7SAndroid Build Coastguard Worker }
5340*03ce13f7SAndroid Build Coastguard Worker if (Const1) {
5341*03ce13f7SAndroid Build Coastguard Worker const int32_t MoreOffset =
5342*03ce13f7SAndroid Build Coastguard Worker IsAdd ? Const1->getValue() : -Const1->getValue();
5343*03ce13f7SAndroid Build Coastguard Worker if (Utils::WouldOverflowAdd(*Offset + NewOffset, MoreOffset))
5344*03ce13f7SAndroid Build Coastguard Worker return nullptr;
5345*03ce13f7SAndroid Build Coastguard Worker NewOffset += MoreOffset;
5346*03ce13f7SAndroid Build Coastguard Worker }
5347*03ce13f7SAndroid Build Coastguard Worker if (Utils::WouldOverflowAdd(*Offset, NewOffset << Shift))
5348*03ce13f7SAndroid Build Coastguard Worker return nullptr;
5349*03ce13f7SAndroid Build Coastguard Worker *IndexOrBase = NewIndexOrBase;
5350*03ce13f7SAndroid Build Coastguard Worker *Offset += (NewOffset << Shift);
5351*03ce13f7SAndroid Build Coastguard Worker // Shift is always zero if this is called with the base
5352*03ce13f7SAndroid Build Coastguard Worker *Relocatable = NewRelocatable;
5353*03ce13f7SAndroid Build Coastguard Worker return Definition;
5354*03ce13f7SAndroid Build Coastguard Worker }
5355*03ce13f7SAndroid Build Coastguard Worker return nullptr;
5356*03ce13f7SAndroid Build Coastguard Worker }
5357*03ce13f7SAndroid Build Coastguard Worker
computeAddressOpt(const Inst * Instr,Type MemType,Operand * Addr)5358*03ce13f7SAndroid Build Coastguard Worker X86OperandMem *TargetX8632::computeAddressOpt(const Inst *Instr, Type MemType,
5359*03ce13f7SAndroid Build Coastguard Worker Operand *Addr) {
5360*03ce13f7SAndroid Build Coastguard Worker Func->resetCurrentNode();
5361*03ce13f7SAndroid Build Coastguard Worker if (Func->isVerbose(IceV_AddrOpt)) {
5362*03ce13f7SAndroid Build Coastguard Worker OstreamLocker L(Func->getContext());
5363*03ce13f7SAndroid Build Coastguard Worker Ostream &Str = Func->getContext()->getStrDump();
5364*03ce13f7SAndroid Build Coastguard Worker Str << "\nStarting computeAddressOpt for instruction:\n ";
5365*03ce13f7SAndroid Build Coastguard Worker Instr->dumpDecorated(Func);
5366*03ce13f7SAndroid Build Coastguard Worker }
5367*03ce13f7SAndroid Build Coastguard Worker
5368*03ce13f7SAndroid Build Coastguard Worker OptAddr NewAddr;
5369*03ce13f7SAndroid Build Coastguard Worker NewAddr.Base = llvm::dyn_cast<Variable>(Addr);
5370*03ce13f7SAndroid Build Coastguard Worker if (NewAddr.Base == nullptr)
5371*03ce13f7SAndroid Build Coastguard Worker return nullptr;
5372*03ce13f7SAndroid Build Coastguard Worker
5373*03ce13f7SAndroid Build Coastguard Worker // If the Base has more than one use or is live across multiple blocks, then
5374*03ce13f7SAndroid Build Coastguard Worker // don't go further. Alternatively (?), never consider a transformation that
5375*03ce13f7SAndroid Build Coastguard Worker // would change a variable that is currently *not* live across basic block
5376*03ce13f7SAndroid Build Coastguard Worker // boundaries into one that *is*.
5377*03ce13f7SAndroid Build Coastguard Worker if (!getFlags().getLoopInvariantCodeMotion()) {
5378*03ce13f7SAndroid Build Coastguard Worker // Need multi block address opt when licm is enabled.
5379*03ce13f7SAndroid Build Coastguard Worker // Might make sense to restrict to current node and loop header.
5380*03ce13f7SAndroid Build Coastguard Worker if (Func->getVMetadata()->isMultiBlock(
5381*03ce13f7SAndroid Build Coastguard Worker NewAddr.Base) /* || Base->getUseCount() > 1*/)
5382*03ce13f7SAndroid Build Coastguard Worker return nullptr;
5383*03ce13f7SAndroid Build Coastguard Worker }
5384*03ce13f7SAndroid Build Coastguard Worker AddressOptimizer AddrOpt(Func);
5385*03ce13f7SAndroid Build Coastguard Worker const bool MockBounds = getFlags().getMockBoundsCheck();
5386*03ce13f7SAndroid Build Coastguard Worker const Inst *Reason = nullptr;
5387*03ce13f7SAndroid Build Coastguard Worker bool AddressWasOptimized = false;
5388*03ce13f7SAndroid Build Coastguard Worker // The following unnamed struct identifies the address mode formation steps
5389*03ce13f7SAndroid Build Coastguard Worker // that could potentially create an invalid memory operand (i.e., no free
5390*03ce13f7SAndroid Build Coastguard Worker // slots for RebasePtr.) We add all those variables to this struct so that
5391*03ce13f7SAndroid Build Coastguard Worker // we can use memset() to reset all members to false.
5392*03ce13f7SAndroid Build Coastguard Worker struct {
5393*03ce13f7SAndroid Build Coastguard Worker bool AssignBase = false;
5394*03ce13f7SAndroid Build Coastguard Worker bool AssignIndex = false;
5395*03ce13f7SAndroid Build Coastguard Worker bool OffsetFromBase = false;
5396*03ce13f7SAndroid Build Coastguard Worker bool OffsetFromIndex = false;
5397*03ce13f7SAndroid Build Coastguard Worker bool CombinedBaseIndex = false;
5398*03ce13f7SAndroid Build Coastguard Worker } Skip;
5399*03ce13f7SAndroid Build Coastguard Worker // NewAddrCheckpoint is used to rollback the address being formed in case an
5400*03ce13f7SAndroid Build Coastguard Worker // invalid address is formed.
5401*03ce13f7SAndroid Build Coastguard Worker OptAddr NewAddrCheckpoint;
5402*03ce13f7SAndroid Build Coastguard Worker Reason = Instr;
5403*03ce13f7SAndroid Build Coastguard Worker do {
5404*03ce13f7SAndroid Build Coastguard Worker if (Reason) {
5405*03ce13f7SAndroid Build Coastguard Worker AddrOpt.dumpAddressOpt(NewAddr.Relocatable, NewAddr.Offset, NewAddr.Base,
5406*03ce13f7SAndroid Build Coastguard Worker NewAddr.Index, NewAddr.Shift, Reason);
5407*03ce13f7SAndroid Build Coastguard Worker AddressWasOptimized = true;
5408*03ce13f7SAndroid Build Coastguard Worker Reason = nullptr;
5409*03ce13f7SAndroid Build Coastguard Worker memset(reinterpret_cast<void *>(&Skip), 0, sizeof(Skip));
5410*03ce13f7SAndroid Build Coastguard Worker }
5411*03ce13f7SAndroid Build Coastguard Worker
5412*03ce13f7SAndroid Build Coastguard Worker NewAddrCheckpoint = NewAddr;
5413*03ce13f7SAndroid Build Coastguard Worker
5414*03ce13f7SAndroid Build Coastguard Worker // Update Base and Index to follow through assignments to definitions.
5415*03ce13f7SAndroid Build Coastguard Worker if (!Skip.AssignBase &&
5416*03ce13f7SAndroid Build Coastguard Worker (Reason = AddrOpt.matchAssign(&NewAddr.Base, &NewAddr.Relocatable,
5417*03ce13f7SAndroid Build Coastguard Worker &NewAddr.Offset))) {
5418*03ce13f7SAndroid Build Coastguard Worker // Assignments of Base from a Relocatable or ConstantInt32 can result
5419*03ce13f7SAndroid Build Coastguard Worker // in Base becoming nullptr. To avoid code duplication in this loop we
5420*03ce13f7SAndroid Build Coastguard Worker // prefer that Base be non-nullptr if possible.
5421*03ce13f7SAndroid Build Coastguard Worker if ((NewAddr.Base == nullptr) && (NewAddr.Index != nullptr) &&
5422*03ce13f7SAndroid Build Coastguard Worker NewAddr.Shift == 0) {
5423*03ce13f7SAndroid Build Coastguard Worker std::swap(NewAddr.Base, NewAddr.Index);
5424*03ce13f7SAndroid Build Coastguard Worker }
5425*03ce13f7SAndroid Build Coastguard Worker continue;
5426*03ce13f7SAndroid Build Coastguard Worker }
5427*03ce13f7SAndroid Build Coastguard Worker if (!Skip.AssignBase &&
5428*03ce13f7SAndroid Build Coastguard Worker (Reason = AddrOpt.matchAssign(&NewAddr.Index, &NewAddr.Relocatable,
5429*03ce13f7SAndroid Build Coastguard Worker &NewAddr.Offset))) {
5430*03ce13f7SAndroid Build Coastguard Worker continue;
5431*03ce13f7SAndroid Build Coastguard Worker }
5432*03ce13f7SAndroid Build Coastguard Worker
5433*03ce13f7SAndroid Build Coastguard Worker if (!MockBounds) {
5434*03ce13f7SAndroid Build Coastguard Worker // Transition from:
5435*03ce13f7SAndroid Build Coastguard Worker // <Relocatable + Offset>(Base) to
5436*03ce13f7SAndroid Build Coastguard Worker // <Relocatable + Offset>(Base, Index)
5437*03ce13f7SAndroid Build Coastguard Worker if (!Skip.CombinedBaseIndex &&
5438*03ce13f7SAndroid Build Coastguard Worker (Reason = AddrOpt.matchCombinedBaseIndex(
5439*03ce13f7SAndroid Build Coastguard Worker &NewAddr.Base, &NewAddr.Index, &NewAddr.Shift))) {
5440*03ce13f7SAndroid Build Coastguard Worker continue;
5441*03ce13f7SAndroid Build Coastguard Worker }
5442*03ce13f7SAndroid Build Coastguard Worker
5443*03ce13f7SAndroid Build Coastguard Worker // Recognize multiply/shift and update Shift amount.
5444*03ce13f7SAndroid Build Coastguard Worker // Index becomes Index=Var<<Const && Const+Shift<=3 ==>
5445*03ce13f7SAndroid Build Coastguard Worker // Index=Var, Shift+=Const
5446*03ce13f7SAndroid Build Coastguard Worker // Index becomes Index=Const*Var && log2(Const)+Shift<=3 ==>
5447*03ce13f7SAndroid Build Coastguard Worker // Index=Var, Shift+=log2(Const)
5448*03ce13f7SAndroid Build Coastguard Worker if ((Reason =
5449*03ce13f7SAndroid Build Coastguard Worker AddrOpt.matchShiftedIndex(&NewAddr.Index, &NewAddr.Shift))) {
5450*03ce13f7SAndroid Build Coastguard Worker continue;
5451*03ce13f7SAndroid Build Coastguard Worker }
5452*03ce13f7SAndroid Build Coastguard Worker
5453*03ce13f7SAndroid Build Coastguard Worker // If Shift is zero, the choice of Base and Index was purely arbitrary.
5454*03ce13f7SAndroid Build Coastguard Worker // Recognize multiply/shift and set Shift amount.
5455*03ce13f7SAndroid Build Coastguard Worker // Shift==0 && Base is Base=Var*Const && log2(Const)+Shift<=3 ==>
5456*03ce13f7SAndroid Build Coastguard Worker // swap(Index,Base)
5457*03ce13f7SAndroid Build Coastguard Worker // Similar for Base=Const*Var and Base=Var<<Const
5458*03ce13f7SAndroid Build Coastguard Worker if (NewAddr.Shift == 0 &&
5459*03ce13f7SAndroid Build Coastguard Worker (Reason = AddrOpt.matchShiftedIndex(&NewAddr.Base, &NewAddr.Shift))) {
5460*03ce13f7SAndroid Build Coastguard Worker std::swap(NewAddr.Base, NewAddr.Index);
5461*03ce13f7SAndroid Build Coastguard Worker continue;
5462*03ce13f7SAndroid Build Coastguard Worker }
5463*03ce13f7SAndroid Build Coastguard Worker }
5464*03ce13f7SAndroid Build Coastguard Worker
5465*03ce13f7SAndroid Build Coastguard Worker // Update Offset to reflect additions/subtractions with constants and
5466*03ce13f7SAndroid Build Coastguard Worker // relocatables.
5467*03ce13f7SAndroid Build Coastguard Worker // TODO: consider overflow issues with respect to Offset.
5468*03ce13f7SAndroid Build Coastguard Worker if (!Skip.OffsetFromBase && (Reason = AddrOpt.matchOffsetIndexOrBase(
5469*03ce13f7SAndroid Build Coastguard Worker &NewAddr.Base, /*Shift =*/0,
5470*03ce13f7SAndroid Build Coastguard Worker &NewAddr.Relocatable, &NewAddr.Offset))) {
5471*03ce13f7SAndroid Build Coastguard Worker continue;
5472*03ce13f7SAndroid Build Coastguard Worker }
5473*03ce13f7SAndroid Build Coastguard Worker if (!Skip.OffsetFromIndex && (Reason = AddrOpt.matchOffsetIndexOrBase(
5474*03ce13f7SAndroid Build Coastguard Worker &NewAddr.Index, NewAddr.Shift,
5475*03ce13f7SAndroid Build Coastguard Worker &NewAddr.Relocatable, &NewAddr.Offset))) {
5476*03ce13f7SAndroid Build Coastguard Worker continue;
5477*03ce13f7SAndroid Build Coastguard Worker }
5478*03ce13f7SAndroid Build Coastguard Worker
5479*03ce13f7SAndroid Build Coastguard Worker break;
5480*03ce13f7SAndroid Build Coastguard Worker } while (Reason);
5481*03ce13f7SAndroid Build Coastguard Worker
5482*03ce13f7SAndroid Build Coastguard Worker if (!AddressWasOptimized) {
5483*03ce13f7SAndroid Build Coastguard Worker return nullptr;
5484*03ce13f7SAndroid Build Coastguard Worker }
5485*03ce13f7SAndroid Build Coastguard Worker
5486*03ce13f7SAndroid Build Coastguard Worker // Undo any addition of RebasePtr. It will be added back when the mem
5487*03ce13f7SAndroid Build Coastguard Worker // operand is sandboxed.
5488*03ce13f7SAndroid Build Coastguard Worker if (NewAddr.Base == RebasePtr) {
5489*03ce13f7SAndroid Build Coastguard Worker NewAddr.Base = nullptr;
5490*03ce13f7SAndroid Build Coastguard Worker }
5491*03ce13f7SAndroid Build Coastguard Worker
5492*03ce13f7SAndroid Build Coastguard Worker if (NewAddr.Index == RebasePtr) {
5493*03ce13f7SAndroid Build Coastguard Worker NewAddr.Index = nullptr;
5494*03ce13f7SAndroid Build Coastguard Worker NewAddr.Shift = 0;
5495*03ce13f7SAndroid Build Coastguard Worker }
5496*03ce13f7SAndroid Build Coastguard Worker
5497*03ce13f7SAndroid Build Coastguard Worker Constant *OffsetOp = nullptr;
5498*03ce13f7SAndroid Build Coastguard Worker if (NewAddr.Relocatable == nullptr) {
5499*03ce13f7SAndroid Build Coastguard Worker OffsetOp = Ctx->getConstantInt32(NewAddr.Offset);
5500*03ce13f7SAndroid Build Coastguard Worker } else {
5501*03ce13f7SAndroid Build Coastguard Worker OffsetOp =
5502*03ce13f7SAndroid Build Coastguard Worker Ctx->getConstantSym(NewAddr.Relocatable->getOffset() + NewAddr.Offset,
5503*03ce13f7SAndroid Build Coastguard Worker NewAddr.Relocatable->getName());
5504*03ce13f7SAndroid Build Coastguard Worker }
5505*03ce13f7SAndroid Build Coastguard Worker // Vanilla ICE load instructions should not use the segment registers, and
5506*03ce13f7SAndroid Build Coastguard Worker // computeAddressOpt only works at the level of Variables and Constants, not
5507*03ce13f7SAndroid Build Coastguard Worker // other X86OperandMem, so there should be no mention of segment
5508*03ce13f7SAndroid Build Coastguard Worker // registers there either.
5509*03ce13f7SAndroid Build Coastguard Worker static constexpr auto SegmentReg =
5510*03ce13f7SAndroid Build Coastguard Worker X86OperandMem::SegmentRegisters::DefaultSegment;
5511*03ce13f7SAndroid Build Coastguard Worker
5512*03ce13f7SAndroid Build Coastguard Worker return X86OperandMem::create(Func, MemType, NewAddr.Base, OffsetOp,
5513*03ce13f7SAndroid Build Coastguard Worker NewAddr.Index, NewAddr.Shift, SegmentReg);
5514*03ce13f7SAndroid Build Coastguard Worker }
5515*03ce13f7SAndroid Build Coastguard Worker
5516*03ce13f7SAndroid Build Coastguard Worker /// Add a mock bounds check on the memory address before using it as a load or
5517*03ce13f7SAndroid Build Coastguard Worker /// store operand. The basic idea is that given a memory operand [reg], we
5518*03ce13f7SAndroid Build Coastguard Worker /// would first add bounds-check code something like:
5519*03ce13f7SAndroid Build Coastguard Worker ///
5520*03ce13f7SAndroid Build Coastguard Worker /// cmp reg, <lb>
5521*03ce13f7SAndroid Build Coastguard Worker /// jl out_of_line_error
5522*03ce13f7SAndroid Build Coastguard Worker /// cmp reg, <ub>
5523*03ce13f7SAndroid Build Coastguard Worker /// jg out_of_line_error
5524*03ce13f7SAndroid Build Coastguard Worker ///
5525*03ce13f7SAndroid Build Coastguard Worker /// In reality, the specific code will depend on how <lb> and <ub> are
5526*03ce13f7SAndroid Build Coastguard Worker /// represented, e.g. an immediate, a global, or a function argument.
5527*03ce13f7SAndroid Build Coastguard Worker ///
5528*03ce13f7SAndroid Build Coastguard Worker /// As such, we need to enforce that the memory operand does not have the form
5529*03ce13f7SAndroid Build Coastguard Worker /// [reg1+reg2], because then there is no simple cmp instruction that would
5530*03ce13f7SAndroid Build Coastguard Worker /// suffice. However, we consider [reg+offset] to be OK because the offset is
5531*03ce13f7SAndroid Build Coastguard Worker /// usually small, and so <ub> could have a safety buffer built in and then we
5532*03ce13f7SAndroid Build Coastguard Worker /// could instead branch to a custom out_of_line_error that does the precise
5533*03ce13f7SAndroid Build Coastguard Worker /// check and jumps back if it turns out OK.
5534*03ce13f7SAndroid Build Coastguard Worker ///
5535*03ce13f7SAndroid Build Coastguard Worker /// For the purpose of mocking the bounds check, we'll do something like this:
5536*03ce13f7SAndroid Build Coastguard Worker ///
5537*03ce13f7SAndroid Build Coastguard Worker /// cmp reg, 0
5538*03ce13f7SAndroid Build Coastguard Worker /// je label
5539*03ce13f7SAndroid Build Coastguard Worker /// cmp reg, 1
5540*03ce13f7SAndroid Build Coastguard Worker /// je label
5541*03ce13f7SAndroid Build Coastguard Worker /// label:
5542*03ce13f7SAndroid Build Coastguard Worker ///
5543*03ce13f7SAndroid Build Coastguard Worker /// Also note that we don't need to add a bounds check to a dereference of a
5544*03ce13f7SAndroid Build Coastguard Worker /// simple global variable address.
5545*03ce13f7SAndroid Build Coastguard Worker
doMockBoundsCheck(Operand * Opnd)5546*03ce13f7SAndroid Build Coastguard Worker void TargetX8632::doMockBoundsCheck(Operand *Opnd) {
5547*03ce13f7SAndroid Build Coastguard Worker if (!getFlags().getMockBoundsCheck())
5548*03ce13f7SAndroid Build Coastguard Worker return;
5549*03ce13f7SAndroid Build Coastguard Worker if (auto *Mem = llvm::dyn_cast<X86OperandMem>(Opnd)) {
5550*03ce13f7SAndroid Build Coastguard Worker if (Mem->getIndex()) {
5551*03ce13f7SAndroid Build Coastguard Worker llvm::report_fatal_error("doMockBoundsCheck: Opnd contains index reg");
5552*03ce13f7SAndroid Build Coastguard Worker }
5553*03ce13f7SAndroid Build Coastguard Worker Opnd = Mem->getBase();
5554*03ce13f7SAndroid Build Coastguard Worker }
5555*03ce13f7SAndroid Build Coastguard Worker // At this point Opnd could be nullptr, or Variable, or Constant, or perhaps
5556*03ce13f7SAndroid Build Coastguard Worker // something else. We only care if it is Variable.
5557*03ce13f7SAndroid Build Coastguard Worker auto *Var = llvm::dyn_cast_or_null<Variable>(Opnd);
5558*03ce13f7SAndroid Build Coastguard Worker if (Var == nullptr)
5559*03ce13f7SAndroid Build Coastguard Worker return;
5560*03ce13f7SAndroid Build Coastguard Worker // We use lowerStore() to copy out-args onto the stack. This creates a
5561*03ce13f7SAndroid Build Coastguard Worker // memory operand with the stack pointer as the base register. Don't do
5562*03ce13f7SAndroid Build Coastguard Worker // bounds checks on that.
5563*03ce13f7SAndroid Build Coastguard Worker if (Var->getRegNum() == getStackReg())
5564*03ce13f7SAndroid Build Coastguard Worker return;
5565*03ce13f7SAndroid Build Coastguard Worker
5566*03ce13f7SAndroid Build Coastguard Worker auto *Label = InstX86Label::create(Func, this);
5567*03ce13f7SAndroid Build Coastguard Worker _cmp(Opnd, Ctx->getConstantZero(IceType_i32));
5568*03ce13f7SAndroid Build Coastguard Worker _br(CondX86::Br_e, Label);
5569*03ce13f7SAndroid Build Coastguard Worker _cmp(Opnd, Ctx->getConstantInt32(1));
5570*03ce13f7SAndroid Build Coastguard Worker _br(CondX86::Br_e, Label);
5571*03ce13f7SAndroid Build Coastguard Worker Context.insert(Label);
5572*03ce13f7SAndroid Build Coastguard Worker }
5573*03ce13f7SAndroid Build Coastguard Worker
lowerLoad(const InstLoad * Load)5574*03ce13f7SAndroid Build Coastguard Worker void TargetX8632::lowerLoad(const InstLoad *Load) {
5575*03ce13f7SAndroid Build Coastguard Worker // A Load instruction can be treated the same as an Assign instruction,
5576*03ce13f7SAndroid Build Coastguard Worker // after the source operand is transformed into an X86OperandMem operand.
5577*03ce13f7SAndroid Build Coastguard Worker // Note that the address mode optimization already creates an X86OperandMem
5578*03ce13f7SAndroid Build Coastguard Worker // operand, so it doesn't need another level of transformation.
5579*03ce13f7SAndroid Build Coastguard Worker Variable *DestLoad = Load->getDest();
5580*03ce13f7SAndroid Build Coastguard Worker Type Ty = DestLoad->getType();
5581*03ce13f7SAndroid Build Coastguard Worker Operand *Src0 = formMemoryOperand(Load->getLoadAddress(), Ty);
5582*03ce13f7SAndroid Build Coastguard Worker doMockBoundsCheck(Src0);
5583*03ce13f7SAndroid Build Coastguard Worker auto *Assign = InstAssign::create(Func, DestLoad, Src0);
5584*03ce13f7SAndroid Build Coastguard Worker lowerAssign(Assign);
5585*03ce13f7SAndroid Build Coastguard Worker }
5586*03ce13f7SAndroid Build Coastguard Worker
doAddressOptOther()5587*03ce13f7SAndroid Build Coastguard Worker void TargetX8632::doAddressOptOther() {
5588*03ce13f7SAndroid Build Coastguard Worker // Inverts some Icmp instructions which helps doAddressOptLoad later.
5589*03ce13f7SAndroid Build Coastguard Worker // TODO(manasijm): Refactor to unify the conditions for Var0 and Var1
5590*03ce13f7SAndroid Build Coastguard Worker Inst *Instr = iteratorToInst(Context.getCur());
5591*03ce13f7SAndroid Build Coastguard Worker auto *VMetadata = Func->getVMetadata();
5592*03ce13f7SAndroid Build Coastguard Worker if (auto *Icmp = llvm::dyn_cast<InstIcmp>(Instr)) {
5593*03ce13f7SAndroid Build Coastguard Worker if (llvm::isa<Constant>(Icmp->getSrc(0)) ||
5594*03ce13f7SAndroid Build Coastguard Worker llvm::isa<Constant>(Icmp->getSrc(1)))
5595*03ce13f7SAndroid Build Coastguard Worker return;
5596*03ce13f7SAndroid Build Coastguard Worker auto *Var0 = llvm::dyn_cast<Variable>(Icmp->getSrc(0));
5597*03ce13f7SAndroid Build Coastguard Worker if (Var0 == nullptr)
5598*03ce13f7SAndroid Build Coastguard Worker return;
5599*03ce13f7SAndroid Build Coastguard Worker if (!VMetadata->isTracked(Var0))
5600*03ce13f7SAndroid Build Coastguard Worker return;
5601*03ce13f7SAndroid Build Coastguard Worker auto *Op0Def = VMetadata->getFirstDefinitionSingleBlock(Var0);
5602*03ce13f7SAndroid Build Coastguard Worker if (Op0Def == nullptr || !llvm::isa<InstLoad>(Op0Def))
5603*03ce13f7SAndroid Build Coastguard Worker return;
5604*03ce13f7SAndroid Build Coastguard Worker if (VMetadata->getLocalUseNode(Var0) != Context.getNode())
5605*03ce13f7SAndroid Build Coastguard Worker return;
5606*03ce13f7SAndroid Build Coastguard Worker
5607*03ce13f7SAndroid Build Coastguard Worker auto *Var1 = llvm::dyn_cast<Variable>(Icmp->getSrc(1));
5608*03ce13f7SAndroid Build Coastguard Worker if (Var1 != nullptr && VMetadata->isTracked(Var1)) {
5609*03ce13f7SAndroid Build Coastguard Worker auto *Op1Def = VMetadata->getFirstDefinitionSingleBlock(Var1);
5610*03ce13f7SAndroid Build Coastguard Worker if (Op1Def != nullptr && !VMetadata->isMultiBlock(Var1) &&
5611*03ce13f7SAndroid Build Coastguard Worker llvm::isa<InstLoad>(Op1Def)) {
5612*03ce13f7SAndroid Build Coastguard Worker return; // Both are loads
5613*03ce13f7SAndroid Build Coastguard Worker }
5614*03ce13f7SAndroid Build Coastguard Worker }
5615*03ce13f7SAndroid Build Coastguard Worker Icmp->reverseConditionAndOperands();
5616*03ce13f7SAndroid Build Coastguard Worker }
5617*03ce13f7SAndroid Build Coastguard Worker }
5618*03ce13f7SAndroid Build Coastguard Worker
doAddressOptLoad()5619*03ce13f7SAndroid Build Coastguard Worker void TargetX8632::doAddressOptLoad() {
5620*03ce13f7SAndroid Build Coastguard Worker Inst *Instr = iteratorToInst(Context.getCur());
5621*03ce13f7SAndroid Build Coastguard Worker Operand *Addr = Instr->getSrc(0);
5622*03ce13f7SAndroid Build Coastguard Worker Variable *Dest = Instr->getDest();
5623*03ce13f7SAndroid Build Coastguard Worker if (auto *OptAddr = computeAddressOpt(Instr, Dest->getType(), Addr)) {
5624*03ce13f7SAndroid Build Coastguard Worker Instr->setDeleted();
5625*03ce13f7SAndroid Build Coastguard Worker Context.insert<InstLoad>(Dest, OptAddr);
5626*03ce13f7SAndroid Build Coastguard Worker }
5627*03ce13f7SAndroid Build Coastguard Worker }
5628*03ce13f7SAndroid Build Coastguard Worker
doAddressOptLoadSubVector()5629*03ce13f7SAndroid Build Coastguard Worker void TargetX8632::doAddressOptLoadSubVector() {
5630*03ce13f7SAndroid Build Coastguard Worker auto *Intrinsic = llvm::cast<InstIntrinsic>(Context.getCur());
5631*03ce13f7SAndroid Build Coastguard Worker Operand *Addr = Intrinsic->getArg(0);
5632*03ce13f7SAndroid Build Coastguard Worker Variable *Dest = Intrinsic->getDest();
5633*03ce13f7SAndroid Build Coastguard Worker if (auto *OptAddr = computeAddressOpt(Intrinsic, Dest->getType(), Addr)) {
5634*03ce13f7SAndroid Build Coastguard Worker Intrinsic->setDeleted();
5635*03ce13f7SAndroid Build Coastguard Worker const Ice::Intrinsics::IntrinsicInfo Info = {
5636*03ce13f7SAndroid Build Coastguard Worker Ice::Intrinsics::LoadSubVector, Ice::Intrinsics::SideEffects_F,
5637*03ce13f7SAndroid Build Coastguard Worker Ice::Intrinsics::ReturnsTwice_F, Ice::Intrinsics::MemoryWrite_F};
5638*03ce13f7SAndroid Build Coastguard Worker auto *NewLoad = Context.insert<InstIntrinsic>(2, Dest, Info);
5639*03ce13f7SAndroid Build Coastguard Worker NewLoad->addArg(OptAddr);
5640*03ce13f7SAndroid Build Coastguard Worker NewLoad->addArg(Intrinsic->getArg(1));
5641*03ce13f7SAndroid Build Coastguard Worker }
5642*03ce13f7SAndroid Build Coastguard Worker }
5643*03ce13f7SAndroid Build Coastguard Worker
lowerPhi(const InstPhi *)5644*03ce13f7SAndroid Build Coastguard Worker void TargetX8632::lowerPhi(const InstPhi * /*Instr*/) {
5645*03ce13f7SAndroid Build Coastguard Worker Func->setError("Phi found in regular instruction list");
5646*03ce13f7SAndroid Build Coastguard Worker }
5647*03ce13f7SAndroid Build Coastguard Worker
lowerRet(const InstRet * Instr)5648*03ce13f7SAndroid Build Coastguard Worker void TargetX8632::lowerRet(const InstRet *Instr) {
5649*03ce13f7SAndroid Build Coastguard Worker Variable *Reg = nullptr;
5650*03ce13f7SAndroid Build Coastguard Worker if (Instr->hasRetValue()) {
5651*03ce13f7SAndroid Build Coastguard Worker Operand *RetValue = legalize(Instr->getRetValue());
5652*03ce13f7SAndroid Build Coastguard Worker const Type ReturnType = RetValue->getType();
5653*03ce13f7SAndroid Build Coastguard Worker assert(isVectorType(ReturnType) || isScalarFloatingType(ReturnType) ||
5654*03ce13f7SAndroid Build Coastguard Worker (ReturnType == IceType_i32) || (ReturnType == IceType_i64));
5655*03ce13f7SAndroid Build Coastguard Worker Reg = moveReturnValueToRegister(RetValue, ReturnType);
5656*03ce13f7SAndroid Build Coastguard Worker }
5657*03ce13f7SAndroid Build Coastguard Worker // Add a ret instruction even if sandboxing is enabled, because addEpilog
5658*03ce13f7SAndroid Build Coastguard Worker // explicitly looks for a ret instruction as a marker for where to insert
5659*03ce13f7SAndroid Build Coastguard Worker // the frame removal instructions.
5660*03ce13f7SAndroid Build Coastguard Worker _ret(Reg);
5661*03ce13f7SAndroid Build Coastguard Worker // Add a fake use of esp to make sure esp stays alive for the entire
5662*03ce13f7SAndroid Build Coastguard Worker // function. Otherwise post-call esp adjustments get dead-code eliminated.
5663*03ce13f7SAndroid Build Coastguard Worker keepEspLiveAtExit();
5664*03ce13f7SAndroid Build Coastguard Worker }
5665*03ce13f7SAndroid Build Coastguard Worker
makePshufdMask(SizeT Index0,SizeT Index1,SizeT Index2,SizeT Index3)5666*03ce13f7SAndroid Build Coastguard Worker inline uint32_t makePshufdMask(SizeT Index0, SizeT Index1, SizeT Index2,
5667*03ce13f7SAndroid Build Coastguard Worker SizeT Index3) {
5668*03ce13f7SAndroid Build Coastguard Worker const SizeT Mask = (Index0 & 0x3) | ((Index1 & 0x3) << 2) |
5669*03ce13f7SAndroid Build Coastguard Worker ((Index2 & 0x3) << 4) | ((Index3 & 0x3) << 6);
5670*03ce13f7SAndroid Build Coastguard Worker assert(Mask < 256);
5671*03ce13f7SAndroid Build Coastguard Worker return Mask;
5672*03ce13f7SAndroid Build Coastguard Worker }
5673*03ce13f7SAndroid Build Coastguard Worker
lowerShuffleVector_AllFromSameSrc(Operand * Src,SizeT Index0,SizeT Index1,SizeT Index2,SizeT Index3)5674*03ce13f7SAndroid Build Coastguard Worker Variable *TargetX8632::lowerShuffleVector_AllFromSameSrc(
5675*03ce13f7SAndroid Build Coastguard Worker Operand *Src, SizeT Index0, SizeT Index1, SizeT Index2, SizeT Index3) {
5676*03ce13f7SAndroid Build Coastguard Worker constexpr SizeT SrcBit = 1 << 2;
5677*03ce13f7SAndroid Build Coastguard Worker assert((Index0 & SrcBit) == (Index1 & SrcBit));
5678*03ce13f7SAndroid Build Coastguard Worker assert((Index0 & SrcBit) == (Index2 & SrcBit));
5679*03ce13f7SAndroid Build Coastguard Worker assert((Index0 & SrcBit) == (Index3 & SrcBit));
5680*03ce13f7SAndroid Build Coastguard Worker (void)SrcBit;
5681*03ce13f7SAndroid Build Coastguard Worker
5682*03ce13f7SAndroid Build Coastguard Worker const Type SrcTy = Src->getType();
5683*03ce13f7SAndroid Build Coastguard Worker auto *T = makeReg(SrcTy);
5684*03ce13f7SAndroid Build Coastguard Worker auto *SrcRM = legalize(Src, Legal_Reg | Legal_Mem);
5685*03ce13f7SAndroid Build Coastguard Worker auto *Mask =
5686*03ce13f7SAndroid Build Coastguard Worker Ctx->getConstantInt32(makePshufdMask(Index0, Index1, Index2, Index3));
5687*03ce13f7SAndroid Build Coastguard Worker _pshufd(T, SrcRM, Mask);
5688*03ce13f7SAndroid Build Coastguard Worker return T;
5689*03ce13f7SAndroid Build Coastguard Worker }
5690*03ce13f7SAndroid Build Coastguard Worker
5691*03ce13f7SAndroid Build Coastguard Worker Variable *
lowerShuffleVector_TwoFromSameSrc(Operand * Src0,SizeT Index0,SizeT Index1,Operand * Src1,SizeT Index2,SizeT Index3)5692*03ce13f7SAndroid Build Coastguard Worker TargetX8632::lowerShuffleVector_TwoFromSameSrc(Operand *Src0, SizeT Index0,
5693*03ce13f7SAndroid Build Coastguard Worker SizeT Index1, Operand *Src1,
5694*03ce13f7SAndroid Build Coastguard Worker SizeT Index2, SizeT Index3) {
5695*03ce13f7SAndroid Build Coastguard Worker constexpr SizeT SrcBit = 1 << 2;
5696*03ce13f7SAndroid Build Coastguard Worker assert((Index0 & SrcBit) == (Index1 & SrcBit) || (Index1 == IGNORE_INDEX));
5697*03ce13f7SAndroid Build Coastguard Worker assert((Index2 & SrcBit) == (Index3 & SrcBit) || (Index3 == IGNORE_INDEX));
5698*03ce13f7SAndroid Build Coastguard Worker (void)SrcBit;
5699*03ce13f7SAndroid Build Coastguard Worker
5700*03ce13f7SAndroid Build Coastguard Worker const Type SrcTy = Src0->getType();
5701*03ce13f7SAndroid Build Coastguard Worker assert(Src1->getType() == SrcTy);
5702*03ce13f7SAndroid Build Coastguard Worker auto *T = makeReg(SrcTy);
5703*03ce13f7SAndroid Build Coastguard Worker auto *Src0R = legalizeToReg(Src0);
5704*03ce13f7SAndroid Build Coastguard Worker auto *Src1RM = legalize(Src1, Legal_Reg | Legal_Mem);
5705*03ce13f7SAndroid Build Coastguard Worker auto *Mask =
5706*03ce13f7SAndroid Build Coastguard Worker Ctx->getConstantInt32(makePshufdMask(Index0, Index1, Index2, Index3));
5707*03ce13f7SAndroid Build Coastguard Worker _movp(T, Src0R);
5708*03ce13f7SAndroid Build Coastguard Worker _shufps(T, Src1RM, Mask);
5709*03ce13f7SAndroid Build Coastguard Worker return T;
5710*03ce13f7SAndroid Build Coastguard Worker }
5711*03ce13f7SAndroid Build Coastguard Worker
lowerShuffleVector_UnifyFromDifferentSrcs(Operand * Src0,SizeT Index0,Operand * Src1,SizeT Index1)5712*03ce13f7SAndroid Build Coastguard Worker Variable *TargetX8632::lowerShuffleVector_UnifyFromDifferentSrcs(Operand *Src0,
5713*03ce13f7SAndroid Build Coastguard Worker SizeT Index0,
5714*03ce13f7SAndroid Build Coastguard Worker Operand *Src1,
5715*03ce13f7SAndroid Build Coastguard Worker SizeT Index1) {
5716*03ce13f7SAndroid Build Coastguard Worker return lowerShuffleVector_TwoFromSameSrc(Src0, Index0, IGNORE_INDEX, Src1,
5717*03ce13f7SAndroid Build Coastguard Worker Index1, IGNORE_INDEX);
5718*03ce13f7SAndroid Build Coastguard Worker }
5719*03ce13f7SAndroid Build Coastguard Worker
makeSrcSwitchMask(SizeT Index0,SizeT Index1,SizeT Index2,SizeT Index3)5720*03ce13f7SAndroid Build Coastguard Worker inline SizeT makeSrcSwitchMask(SizeT Index0, SizeT Index1, SizeT Index2,
5721*03ce13f7SAndroid Build Coastguard Worker SizeT Index3) {
5722*03ce13f7SAndroid Build Coastguard Worker constexpr SizeT SrcBit = 1 << 2;
5723*03ce13f7SAndroid Build Coastguard Worker const SizeT Index0Bits = ((Index0 & SrcBit) == 0) ? 0 : (1 << 0);
5724*03ce13f7SAndroid Build Coastguard Worker const SizeT Index1Bits = ((Index1 & SrcBit) == 0) ? 0 : (1 << 1);
5725*03ce13f7SAndroid Build Coastguard Worker const SizeT Index2Bits = ((Index2 & SrcBit) == 0) ? 0 : (1 << 2);
5726*03ce13f7SAndroid Build Coastguard Worker const SizeT Index3Bits = ((Index3 & SrcBit) == 0) ? 0 : (1 << 3);
5727*03ce13f7SAndroid Build Coastguard Worker return Index0Bits | Index1Bits | Index2Bits | Index3Bits;
5728*03ce13f7SAndroid Build Coastguard Worker }
5729*03ce13f7SAndroid Build Coastguard Worker
lowerShuffleVector_NewMaskName()5730*03ce13f7SAndroid Build Coastguard Worker GlobalString TargetX8632::lowerShuffleVector_NewMaskName() {
5731*03ce13f7SAndroid Build Coastguard Worker GlobalString FuncName = Func->getFunctionName();
5732*03ce13f7SAndroid Build Coastguard Worker const SizeT Id = PshufbMaskCount++;
5733*03ce13f7SAndroid Build Coastguard Worker if (!BuildDefs::dump() || !FuncName.hasStdString()) {
5734*03ce13f7SAndroid Build Coastguard Worker return GlobalString::createWithString(
5735*03ce13f7SAndroid Build Coastguard Worker Ctx,
5736*03ce13f7SAndroid Build Coastguard Worker "$PS" + std::to_string(FuncName.getID()) + "_" + std::to_string(Id));
5737*03ce13f7SAndroid Build Coastguard Worker }
5738*03ce13f7SAndroid Build Coastguard Worker return GlobalString::createWithString(
5739*03ce13f7SAndroid Build Coastguard Worker Ctx, "Pshufb$" + Func->getFunctionName() + "$" + std::to_string(Id));
5740*03ce13f7SAndroid Build Coastguard Worker }
5741*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)5742*03ce13f7SAndroid Build Coastguard Worker ConstantRelocatable *TargetX8632::lowerShuffleVector_CreatePshufbMask(
5743*03ce13f7SAndroid Build Coastguard Worker int8_t Idx0, int8_t Idx1, int8_t Idx2, int8_t Idx3, int8_t Idx4,
5744*03ce13f7SAndroid Build Coastguard Worker int8_t Idx5, int8_t Idx6, int8_t Idx7, int8_t Idx8, int8_t Idx9,
5745*03ce13f7SAndroid Build Coastguard Worker int8_t Idx10, int8_t Idx11, int8_t Idx12, int8_t Idx13, int8_t Idx14,
5746*03ce13f7SAndroid Build Coastguard Worker int8_t Idx15) {
5747*03ce13f7SAndroid Build Coastguard Worker static constexpr uint8_t NumElements = 16;
5748*03ce13f7SAndroid Build Coastguard Worker const char Initializer[NumElements] = {
5749*03ce13f7SAndroid Build Coastguard Worker Idx0, Idx1, Idx2, Idx3, Idx4, Idx5, Idx6, Idx7,
5750*03ce13f7SAndroid Build Coastguard Worker Idx8, Idx9, Idx10, Idx11, Idx12, Idx13, Idx14, Idx15,
5751*03ce13f7SAndroid Build Coastguard Worker };
5752*03ce13f7SAndroid Build Coastguard Worker
5753*03ce13f7SAndroid Build Coastguard Worker static constexpr Type V4VectorType = IceType_v4i32;
5754*03ce13f7SAndroid Build Coastguard Worker const uint32_t MaskAlignment = typeWidthInBytesOnStack(V4VectorType);
5755*03ce13f7SAndroid Build Coastguard Worker auto *Mask = VariableDeclaration::create(Func->getGlobalPool());
5756*03ce13f7SAndroid Build Coastguard Worker GlobalString MaskName = lowerShuffleVector_NewMaskName();
5757*03ce13f7SAndroid Build Coastguard Worker Mask->setIsConstant(true);
5758*03ce13f7SAndroid Build Coastguard Worker Mask->addInitializer(VariableDeclaration::DataInitializer::create(
5759*03ce13f7SAndroid Build Coastguard Worker Func->getGlobalPool(), Initializer, NumElements));
5760*03ce13f7SAndroid Build Coastguard Worker Mask->setName(MaskName);
5761*03ce13f7SAndroid Build Coastguard Worker // Mask needs to be 16-byte aligned, or pshufb will seg fault.
5762*03ce13f7SAndroid Build Coastguard Worker Mask->setAlignment(MaskAlignment);
5763*03ce13f7SAndroid Build Coastguard Worker Func->addGlobal(Mask);
5764*03ce13f7SAndroid Build Coastguard Worker
5765*03ce13f7SAndroid Build Coastguard Worker constexpr RelocOffsetT Offset = 0;
5766*03ce13f7SAndroid Build Coastguard Worker return llvm::cast<ConstantRelocatable>(Ctx->getConstantSym(Offset, MaskName));
5767*03ce13f7SAndroid Build Coastguard Worker }
5768*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)5769*03ce13f7SAndroid Build Coastguard Worker void TargetX8632::lowerShuffleVector_UsingPshufb(
5770*03ce13f7SAndroid Build Coastguard Worker Variable *Dest, Operand *Src0, Operand *Src1, int8_t Idx0, int8_t Idx1,
5771*03ce13f7SAndroid Build Coastguard Worker int8_t Idx2, int8_t Idx3, int8_t Idx4, int8_t Idx5, int8_t Idx6,
5772*03ce13f7SAndroid Build Coastguard Worker int8_t Idx7, int8_t Idx8, int8_t Idx9, int8_t Idx10, int8_t Idx11,
5773*03ce13f7SAndroid Build Coastguard Worker int8_t Idx12, int8_t Idx13, int8_t Idx14, int8_t Idx15) {
5774*03ce13f7SAndroid Build Coastguard Worker const Type DestTy = Dest->getType();
5775*03ce13f7SAndroid Build Coastguard Worker static constexpr bool NotRebased = false;
5776*03ce13f7SAndroid Build Coastguard Worker static constexpr Variable *NoBase = nullptr;
5777*03ce13f7SAndroid Build Coastguard Worker // We use void for the memory operand instead of DestTy because using the
5778*03ce13f7SAndroid Build Coastguard Worker // latter causes a validation failure: the X86 Inst layer complains that
5779*03ce13f7SAndroid Build Coastguard Worker // vector mem operands could be under aligned. Thus, using void we avoid the
5780*03ce13f7SAndroid Build Coastguard Worker // validation error. Note that the mask global declaration is aligned, so it
5781*03ce13f7SAndroid Build Coastguard Worker // can be used as an XMM mem operand.
5782*03ce13f7SAndroid Build Coastguard Worker static constexpr Type MaskType = IceType_void;
5783*03ce13f7SAndroid Build Coastguard Worker #define IDX_IN_SRC(N, S) \
5784*03ce13f7SAndroid Build Coastguard Worker ((((N) & (1 << 4)) == (S << 4)) ? ((N)&0xf) : CLEAR_ALL_BITS)
5785*03ce13f7SAndroid Build Coastguard Worker auto *Mask0M = X86OperandMem::create(
5786*03ce13f7SAndroid Build Coastguard Worker Func, MaskType, NoBase,
5787*03ce13f7SAndroid Build Coastguard Worker lowerShuffleVector_CreatePshufbMask(
5788*03ce13f7SAndroid Build Coastguard Worker IDX_IN_SRC(Idx0, 0), IDX_IN_SRC(Idx1, 0), IDX_IN_SRC(Idx2, 0),
5789*03ce13f7SAndroid Build Coastguard Worker IDX_IN_SRC(Idx3, 0), IDX_IN_SRC(Idx4, 0), IDX_IN_SRC(Idx5, 0),
5790*03ce13f7SAndroid Build Coastguard Worker IDX_IN_SRC(Idx6, 0), IDX_IN_SRC(Idx7, 0), IDX_IN_SRC(Idx8, 0),
5791*03ce13f7SAndroid Build Coastguard Worker IDX_IN_SRC(Idx9, 0), IDX_IN_SRC(Idx10, 0), IDX_IN_SRC(Idx11, 0),
5792*03ce13f7SAndroid Build Coastguard Worker IDX_IN_SRC(Idx12, 0), IDX_IN_SRC(Idx13, 0), IDX_IN_SRC(Idx14, 0),
5793*03ce13f7SAndroid Build Coastguard Worker IDX_IN_SRC(Idx15, 0)),
5794*03ce13f7SAndroid Build Coastguard Worker NotRebased);
5795*03ce13f7SAndroid Build Coastguard Worker
5796*03ce13f7SAndroid Build Coastguard Worker auto *T0 = makeReg(DestTy);
5797*03ce13f7SAndroid Build Coastguard Worker auto *Src0RM = legalize(Src0, Legal_Reg | Legal_Mem);
5798*03ce13f7SAndroid Build Coastguard Worker _movp(T0, Src0RM);
5799*03ce13f7SAndroid Build Coastguard Worker
5800*03ce13f7SAndroid Build Coastguard Worker _pshufb(T0, Mask0M);
5801*03ce13f7SAndroid Build Coastguard Worker
5802*03ce13f7SAndroid Build Coastguard Worker if (Idx0 >= 16 || Idx1 >= 16 || Idx2 >= 16 || Idx3 >= 16 || Idx4 >= 16 ||
5803*03ce13f7SAndroid Build Coastguard Worker Idx5 >= 16 || Idx6 >= 16 || Idx7 >= 16 || Idx8 >= 16 || Idx9 >= 16 ||
5804*03ce13f7SAndroid Build Coastguard Worker Idx10 >= 16 || Idx11 >= 16 || Idx12 >= 16 || Idx13 >= 16 || Idx14 >= 16 ||
5805*03ce13f7SAndroid Build Coastguard Worker Idx15 >= 16) {
5806*03ce13f7SAndroid Build Coastguard Worker auto *Mask1M = X86OperandMem::create(
5807*03ce13f7SAndroid Build Coastguard Worker Func, MaskType, NoBase,
5808*03ce13f7SAndroid Build Coastguard Worker lowerShuffleVector_CreatePshufbMask(
5809*03ce13f7SAndroid Build Coastguard Worker IDX_IN_SRC(Idx0, 1), IDX_IN_SRC(Idx1, 1), IDX_IN_SRC(Idx2, 1),
5810*03ce13f7SAndroid Build Coastguard Worker IDX_IN_SRC(Idx3, 1), IDX_IN_SRC(Idx4, 1), IDX_IN_SRC(Idx5, 1),
5811*03ce13f7SAndroid Build Coastguard Worker IDX_IN_SRC(Idx6, 1), IDX_IN_SRC(Idx7, 1), IDX_IN_SRC(Idx8, 1),
5812*03ce13f7SAndroid Build Coastguard Worker IDX_IN_SRC(Idx9, 1), IDX_IN_SRC(Idx10, 1), IDX_IN_SRC(Idx11, 1),
5813*03ce13f7SAndroid Build Coastguard Worker IDX_IN_SRC(Idx12, 1), IDX_IN_SRC(Idx13, 1), IDX_IN_SRC(Idx14, 1),
5814*03ce13f7SAndroid Build Coastguard Worker IDX_IN_SRC(Idx15, 1)),
5815*03ce13f7SAndroid Build Coastguard Worker NotRebased);
5816*03ce13f7SAndroid Build Coastguard Worker #undef IDX_IN_SRC
5817*03ce13f7SAndroid Build Coastguard Worker auto *T1 = makeReg(DestTy);
5818*03ce13f7SAndroid Build Coastguard Worker auto *Src1RM = legalize(Src1, Legal_Reg | Legal_Mem);
5819*03ce13f7SAndroid Build Coastguard Worker _movp(T1, Src1RM);
5820*03ce13f7SAndroid Build Coastguard Worker _pshufb(T1, Mask1M);
5821*03ce13f7SAndroid Build Coastguard Worker _por(T0, T1);
5822*03ce13f7SAndroid Build Coastguard Worker }
5823*03ce13f7SAndroid Build Coastguard Worker
5824*03ce13f7SAndroid Build Coastguard Worker _movp(Dest, T0);
5825*03ce13f7SAndroid Build Coastguard Worker }
5826*03ce13f7SAndroid Build Coastguard Worker
lowerShuffleVector(const InstShuffleVector * Instr)5827*03ce13f7SAndroid Build Coastguard Worker void TargetX8632::lowerShuffleVector(const InstShuffleVector *Instr) {
5828*03ce13f7SAndroid Build Coastguard Worker auto *Dest = Instr->getDest();
5829*03ce13f7SAndroid Build Coastguard Worker const Type DestTy = Dest->getType();
5830*03ce13f7SAndroid Build Coastguard Worker auto *Src0 = Instr->getSrc(0);
5831*03ce13f7SAndroid Build Coastguard Worker auto *Src1 = Instr->getSrc(1);
5832*03ce13f7SAndroid Build Coastguard Worker const SizeT NumElements = typeNumElements(DestTy);
5833*03ce13f7SAndroid Build Coastguard Worker
5834*03ce13f7SAndroid Build Coastguard Worker auto *T = makeReg(DestTy);
5835*03ce13f7SAndroid Build Coastguard Worker
5836*03ce13f7SAndroid Build Coastguard Worker switch (DestTy) {
5837*03ce13f7SAndroid Build Coastguard Worker default:
5838*03ce13f7SAndroid Build Coastguard Worker llvm::report_fatal_error("Unexpected vector type.");
5839*03ce13f7SAndroid Build Coastguard Worker case IceType_v16i1:
5840*03ce13f7SAndroid Build Coastguard Worker case IceType_v16i8: {
5841*03ce13f7SAndroid Build Coastguard Worker static constexpr SizeT ExpectedNumElements = 16;
5842*03ce13f7SAndroid Build Coastguard Worker assert(ExpectedNumElements == Instr->getNumIndexes());
5843*03ce13f7SAndroid Build Coastguard Worker (void)ExpectedNumElements;
5844*03ce13f7SAndroid Build Coastguard Worker
5845*03ce13f7SAndroid Build Coastguard Worker if (Instr->indexesAre(0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7)) {
5846*03ce13f7SAndroid Build Coastguard Worker auto *T = makeReg(DestTy);
5847*03ce13f7SAndroid Build Coastguard Worker auto *Src0RM = legalize(Src0, Legal_Reg | Legal_Mem);
5848*03ce13f7SAndroid Build Coastguard Worker _movp(T, Src0RM);
5849*03ce13f7SAndroid Build Coastguard Worker _punpckl(T, Src0RM);
5850*03ce13f7SAndroid Build Coastguard Worker _movp(Dest, T);
5851*03ce13f7SAndroid Build Coastguard Worker return;
5852*03ce13f7SAndroid Build Coastguard Worker }
5853*03ce13f7SAndroid Build Coastguard Worker
5854*03ce13f7SAndroid Build Coastguard Worker if (Instr->indexesAre(0, 16, 1, 17, 2, 18, 3, 19, 4, 20, 5, 21, 6, 22, 7,
5855*03ce13f7SAndroid Build Coastguard Worker 23)) {
5856*03ce13f7SAndroid Build Coastguard Worker auto *T = makeReg(DestTy);
5857*03ce13f7SAndroid Build Coastguard Worker auto *Src0RM = legalize(Src0, Legal_Reg | Legal_Mem);
5858*03ce13f7SAndroid Build Coastguard Worker auto *Src1RM = legalize(Src1, Legal_Reg | Legal_Mem);
5859*03ce13f7SAndroid Build Coastguard Worker _movp(T, Src0RM);
5860*03ce13f7SAndroid Build Coastguard Worker _punpckl(T, Src1RM);
5861*03ce13f7SAndroid Build Coastguard Worker _movp(Dest, T);
5862*03ce13f7SAndroid Build Coastguard Worker return;
5863*03ce13f7SAndroid Build Coastguard Worker }
5864*03ce13f7SAndroid Build Coastguard Worker
5865*03ce13f7SAndroid Build Coastguard Worker if (Instr->indexesAre(8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14,
5866*03ce13f7SAndroid Build Coastguard Worker 15, 15)) {
5867*03ce13f7SAndroid Build Coastguard Worker auto *T = makeReg(DestTy);
5868*03ce13f7SAndroid Build Coastguard Worker auto *Src0RM = legalize(Src0, Legal_Reg | Legal_Mem);
5869*03ce13f7SAndroid Build Coastguard Worker _movp(T, Src0RM);
5870*03ce13f7SAndroid Build Coastguard Worker _punpckh(T, Src0RM);
5871*03ce13f7SAndroid Build Coastguard Worker _movp(Dest, T);
5872*03ce13f7SAndroid Build Coastguard Worker return;
5873*03ce13f7SAndroid Build Coastguard Worker }
5874*03ce13f7SAndroid Build Coastguard Worker
5875*03ce13f7SAndroid Build Coastguard Worker if (Instr->indexesAre(8, 24, 9, 25, 10, 26, 11, 27, 12, 28, 13, 29, 14, 30,
5876*03ce13f7SAndroid Build Coastguard Worker 15, 31)) {
5877*03ce13f7SAndroid Build Coastguard Worker auto *T = makeReg(DestTy);
5878*03ce13f7SAndroid Build Coastguard Worker auto *Src0RM = legalize(Src0, Legal_Reg | Legal_Mem);
5879*03ce13f7SAndroid Build Coastguard Worker auto *Src1RM = legalize(Src1, Legal_Reg | Legal_Mem);
5880*03ce13f7SAndroid Build Coastguard Worker _movp(T, Src0RM);
5881*03ce13f7SAndroid Build Coastguard Worker _punpckh(T, Src1RM);
5882*03ce13f7SAndroid Build Coastguard Worker _movp(Dest, T);
5883*03ce13f7SAndroid Build Coastguard Worker return;
5884*03ce13f7SAndroid Build Coastguard Worker }
5885*03ce13f7SAndroid Build Coastguard Worker
5886*03ce13f7SAndroid Build Coastguard Worker if (InstructionSet < SSE4_1) {
5887*03ce13f7SAndroid Build Coastguard Worker // TODO(jpp): figure out how to lower with sse2.
5888*03ce13f7SAndroid Build Coastguard Worker break;
5889*03ce13f7SAndroid Build Coastguard Worker }
5890*03ce13f7SAndroid Build Coastguard Worker
5891*03ce13f7SAndroid Build Coastguard Worker const SizeT Index0 = Instr->getIndexValue(0);
5892*03ce13f7SAndroid Build Coastguard Worker const SizeT Index1 = Instr->getIndexValue(1);
5893*03ce13f7SAndroid Build Coastguard Worker const SizeT Index2 = Instr->getIndexValue(2);
5894*03ce13f7SAndroid Build Coastguard Worker const SizeT Index3 = Instr->getIndexValue(3);
5895*03ce13f7SAndroid Build Coastguard Worker const SizeT Index4 = Instr->getIndexValue(4);
5896*03ce13f7SAndroid Build Coastguard Worker const SizeT Index5 = Instr->getIndexValue(5);
5897*03ce13f7SAndroid Build Coastguard Worker const SizeT Index6 = Instr->getIndexValue(6);
5898*03ce13f7SAndroid Build Coastguard Worker const SizeT Index7 = Instr->getIndexValue(7);
5899*03ce13f7SAndroid Build Coastguard Worker const SizeT Index8 = Instr->getIndexValue(8);
5900*03ce13f7SAndroid Build Coastguard Worker const SizeT Index9 = Instr->getIndexValue(9);
5901*03ce13f7SAndroid Build Coastguard Worker const SizeT Index10 = Instr->getIndexValue(10);
5902*03ce13f7SAndroid Build Coastguard Worker const SizeT Index11 = Instr->getIndexValue(11);
5903*03ce13f7SAndroid Build Coastguard Worker const SizeT Index12 = Instr->getIndexValue(12);
5904*03ce13f7SAndroid Build Coastguard Worker const SizeT Index13 = Instr->getIndexValue(13);
5905*03ce13f7SAndroid Build Coastguard Worker const SizeT Index14 = Instr->getIndexValue(14);
5906*03ce13f7SAndroid Build Coastguard Worker const SizeT Index15 = Instr->getIndexValue(15);
5907*03ce13f7SAndroid Build Coastguard Worker
5908*03ce13f7SAndroid Build Coastguard Worker lowerShuffleVector_UsingPshufb(Dest, Src0, Src1, Index0, Index1, Index2,
5909*03ce13f7SAndroid Build Coastguard Worker Index3, Index4, Index5, Index6, Index7,
5910*03ce13f7SAndroid Build Coastguard Worker Index8, Index9, Index10, Index11, Index12,
5911*03ce13f7SAndroid Build Coastguard Worker Index13, Index14, Index15);
5912*03ce13f7SAndroid Build Coastguard Worker return;
5913*03ce13f7SAndroid Build Coastguard Worker }
5914*03ce13f7SAndroid Build Coastguard Worker case IceType_v8i1:
5915*03ce13f7SAndroid Build Coastguard Worker case IceType_v8i16: {
5916*03ce13f7SAndroid Build Coastguard Worker static constexpr SizeT ExpectedNumElements = 8;
5917*03ce13f7SAndroid Build Coastguard Worker assert(ExpectedNumElements == Instr->getNumIndexes());
5918*03ce13f7SAndroid Build Coastguard Worker (void)ExpectedNumElements;
5919*03ce13f7SAndroid Build Coastguard Worker
5920*03ce13f7SAndroid Build Coastguard Worker if (Instr->indexesAre(0, 0, 1, 1, 2, 2, 3, 3)) {
5921*03ce13f7SAndroid Build Coastguard Worker auto *T = makeReg(DestTy);
5922*03ce13f7SAndroid Build Coastguard Worker auto *Src0RM = legalize(Src0, Legal_Reg | Legal_Mem);
5923*03ce13f7SAndroid Build Coastguard Worker _movp(T, Src0RM);
5924*03ce13f7SAndroid Build Coastguard Worker _punpckl(T, Src0RM);
5925*03ce13f7SAndroid Build Coastguard Worker _movp(Dest, T);
5926*03ce13f7SAndroid Build Coastguard Worker return;
5927*03ce13f7SAndroid Build Coastguard Worker }
5928*03ce13f7SAndroid Build Coastguard Worker
5929*03ce13f7SAndroid Build Coastguard Worker if (Instr->indexesAre(0, 8, 1, 9, 2, 10, 3, 11)) {
5930*03ce13f7SAndroid Build Coastguard Worker auto *T = makeReg(DestTy);
5931*03ce13f7SAndroid Build Coastguard Worker auto *Src0RM = legalize(Src0, Legal_Reg | Legal_Mem);
5932*03ce13f7SAndroid Build Coastguard Worker auto *Src1RM = legalize(Src1, Legal_Reg | Legal_Mem);
5933*03ce13f7SAndroid Build Coastguard Worker _movp(T, Src0RM);
5934*03ce13f7SAndroid Build Coastguard Worker _punpckl(T, Src1RM);
5935*03ce13f7SAndroid Build Coastguard Worker _movp(Dest, T);
5936*03ce13f7SAndroid Build Coastguard Worker return;
5937*03ce13f7SAndroid Build Coastguard Worker }
5938*03ce13f7SAndroid Build Coastguard Worker
5939*03ce13f7SAndroid Build Coastguard Worker if (Instr->indexesAre(4, 4, 5, 5, 6, 6, 7, 7)) {
5940*03ce13f7SAndroid Build Coastguard Worker auto *T = makeReg(DestTy);
5941*03ce13f7SAndroid Build Coastguard Worker auto *Src0RM = legalize(Src0, Legal_Reg | Legal_Mem);
5942*03ce13f7SAndroid Build Coastguard Worker _movp(T, Src0RM);
5943*03ce13f7SAndroid Build Coastguard Worker _punpckh(T, Src0RM);
5944*03ce13f7SAndroid Build Coastguard Worker _movp(Dest, T);
5945*03ce13f7SAndroid Build Coastguard Worker return;
5946*03ce13f7SAndroid Build Coastguard Worker }
5947*03ce13f7SAndroid Build Coastguard Worker
5948*03ce13f7SAndroid Build Coastguard Worker if (Instr->indexesAre(4, 12, 5, 13, 6, 14, 7, 15)) {
5949*03ce13f7SAndroid Build Coastguard Worker auto *T = makeReg(DestTy);
5950*03ce13f7SAndroid Build Coastguard Worker auto *Src0RM = legalize(Src0, Legal_Reg | Legal_Mem);
5951*03ce13f7SAndroid Build Coastguard Worker auto *Src1RM = legalize(Src1, Legal_Reg | Legal_Mem);
5952*03ce13f7SAndroid Build Coastguard Worker _movp(T, Src0RM);
5953*03ce13f7SAndroid Build Coastguard Worker _punpckh(T, Src1RM);
5954*03ce13f7SAndroid Build Coastguard Worker _movp(Dest, T);
5955*03ce13f7SAndroid Build Coastguard Worker return;
5956*03ce13f7SAndroid Build Coastguard Worker }
5957*03ce13f7SAndroid Build Coastguard Worker
5958*03ce13f7SAndroid Build Coastguard Worker if (InstructionSet < SSE4_1) {
5959*03ce13f7SAndroid Build Coastguard Worker // TODO(jpp): figure out how to lower with sse2.
5960*03ce13f7SAndroid Build Coastguard Worker break;
5961*03ce13f7SAndroid Build Coastguard Worker }
5962*03ce13f7SAndroid Build Coastguard Worker
5963*03ce13f7SAndroid Build Coastguard Worker const SizeT Index0 = Instr->getIndexValue(0);
5964*03ce13f7SAndroid Build Coastguard Worker const SizeT Index1 = Instr->getIndexValue(1);
5965*03ce13f7SAndroid Build Coastguard Worker const SizeT Index2 = Instr->getIndexValue(2);
5966*03ce13f7SAndroid Build Coastguard Worker const SizeT Index3 = Instr->getIndexValue(3);
5967*03ce13f7SAndroid Build Coastguard Worker const SizeT Index4 = Instr->getIndexValue(4);
5968*03ce13f7SAndroid Build Coastguard Worker const SizeT Index5 = Instr->getIndexValue(5);
5969*03ce13f7SAndroid Build Coastguard Worker const SizeT Index6 = Instr->getIndexValue(6);
5970*03ce13f7SAndroid Build Coastguard Worker const SizeT Index7 = Instr->getIndexValue(7);
5971*03ce13f7SAndroid Build Coastguard Worker
5972*03ce13f7SAndroid Build Coastguard Worker #define TO_BYTE_INDEX(I) ((I) << 1)
5973*03ce13f7SAndroid Build Coastguard Worker lowerShuffleVector_UsingPshufb(
5974*03ce13f7SAndroid Build Coastguard Worker Dest, Src0, Src1, TO_BYTE_INDEX(Index0), TO_BYTE_INDEX(Index0) + 1,
5975*03ce13f7SAndroid Build Coastguard Worker TO_BYTE_INDEX(Index1), TO_BYTE_INDEX(Index1) + 1, TO_BYTE_INDEX(Index2),
5976*03ce13f7SAndroid Build Coastguard Worker TO_BYTE_INDEX(Index2) + 1, TO_BYTE_INDEX(Index3),
5977*03ce13f7SAndroid Build Coastguard Worker TO_BYTE_INDEX(Index3) + 1, TO_BYTE_INDEX(Index4),
5978*03ce13f7SAndroid Build Coastguard Worker TO_BYTE_INDEX(Index4) + 1, TO_BYTE_INDEX(Index5),
5979*03ce13f7SAndroid Build Coastguard Worker TO_BYTE_INDEX(Index5) + 1, TO_BYTE_INDEX(Index6),
5980*03ce13f7SAndroid Build Coastguard Worker TO_BYTE_INDEX(Index6) + 1, TO_BYTE_INDEX(Index7),
5981*03ce13f7SAndroid Build Coastguard Worker TO_BYTE_INDEX(Index7) + 1);
5982*03ce13f7SAndroid Build Coastguard Worker #undef TO_BYTE_INDEX
5983*03ce13f7SAndroid Build Coastguard Worker return;
5984*03ce13f7SAndroid Build Coastguard Worker }
5985*03ce13f7SAndroid Build Coastguard Worker case IceType_v4i1:
5986*03ce13f7SAndroid Build Coastguard Worker case IceType_v4i32:
5987*03ce13f7SAndroid Build Coastguard Worker case IceType_v4f32: {
5988*03ce13f7SAndroid Build Coastguard Worker static constexpr SizeT ExpectedNumElements = 4;
5989*03ce13f7SAndroid Build Coastguard Worker assert(ExpectedNumElements == Instr->getNumIndexes());
5990*03ce13f7SAndroid Build Coastguard Worker const SizeT Index0 = Instr->getIndexValue(0);
5991*03ce13f7SAndroid Build Coastguard Worker const SizeT Index1 = Instr->getIndexValue(1);
5992*03ce13f7SAndroid Build Coastguard Worker const SizeT Index2 = Instr->getIndexValue(2);
5993*03ce13f7SAndroid Build Coastguard Worker const SizeT Index3 = Instr->getIndexValue(3);
5994*03ce13f7SAndroid Build Coastguard Worker Variable *T = nullptr;
5995*03ce13f7SAndroid Build Coastguard Worker switch (makeSrcSwitchMask(Index0, Index1, Index2, Index3)) {
5996*03ce13f7SAndroid Build Coastguard Worker #define CASE_SRCS_IN(S0, S1, S2, S3) \
5997*03ce13f7SAndroid Build Coastguard Worker case (((S0) << 0) | ((S1) << 1) | ((S2) << 2) | ((S3) << 3))
5998*03ce13f7SAndroid Build Coastguard Worker CASE_SRCS_IN(0, 0, 0, 0) : {
5999*03ce13f7SAndroid Build Coastguard Worker T = lowerShuffleVector_AllFromSameSrc(Src0, Index0, Index1, Index2,
6000*03ce13f7SAndroid Build Coastguard Worker Index3);
6001*03ce13f7SAndroid Build Coastguard Worker }
6002*03ce13f7SAndroid Build Coastguard Worker break;
6003*03ce13f7SAndroid Build Coastguard Worker CASE_SRCS_IN(0, 0, 0, 1) : {
6004*03ce13f7SAndroid Build Coastguard Worker auto *Unified = lowerShuffleVector_UnifyFromDifferentSrcs(Src0, Index2,
6005*03ce13f7SAndroid Build Coastguard Worker Src1, Index3);
6006*03ce13f7SAndroid Build Coastguard Worker T = lowerShuffleVector_TwoFromSameSrc(Src0, Index0, Index1, Unified,
6007*03ce13f7SAndroid Build Coastguard Worker UNIFIED_INDEX_0, UNIFIED_INDEX_1);
6008*03ce13f7SAndroid Build Coastguard Worker }
6009*03ce13f7SAndroid Build Coastguard Worker break;
6010*03ce13f7SAndroid Build Coastguard Worker CASE_SRCS_IN(0, 0, 1, 0) : {
6011*03ce13f7SAndroid Build Coastguard Worker auto *Unified = lowerShuffleVector_UnifyFromDifferentSrcs(Src1, Index2,
6012*03ce13f7SAndroid Build Coastguard Worker Src0, Index3);
6013*03ce13f7SAndroid Build Coastguard Worker T = lowerShuffleVector_TwoFromSameSrc(Src0, Index0, Index1, Unified,
6014*03ce13f7SAndroid Build Coastguard Worker UNIFIED_INDEX_0, UNIFIED_INDEX_1);
6015*03ce13f7SAndroid Build Coastguard Worker }
6016*03ce13f7SAndroid Build Coastguard Worker break;
6017*03ce13f7SAndroid Build Coastguard Worker CASE_SRCS_IN(0, 0, 1, 1) : {
6018*03ce13f7SAndroid Build Coastguard Worker T = lowerShuffleVector_TwoFromSameSrc(Src0, Index0, Index1, Src1,
6019*03ce13f7SAndroid Build Coastguard Worker Index2, Index3);
6020*03ce13f7SAndroid Build Coastguard Worker }
6021*03ce13f7SAndroid Build Coastguard Worker break;
6022*03ce13f7SAndroid Build Coastguard Worker CASE_SRCS_IN(0, 1, 0, 0) : {
6023*03ce13f7SAndroid Build Coastguard Worker auto *Unified = lowerShuffleVector_UnifyFromDifferentSrcs(Src0, Index0,
6024*03ce13f7SAndroid Build Coastguard Worker Src1, Index1);
6025*03ce13f7SAndroid Build Coastguard Worker T = lowerShuffleVector_TwoFromSameSrc(
6026*03ce13f7SAndroid Build Coastguard Worker Unified, UNIFIED_INDEX_0, UNIFIED_INDEX_1, Src0, Index2, Index3);
6027*03ce13f7SAndroid Build Coastguard Worker }
6028*03ce13f7SAndroid Build Coastguard Worker break;
6029*03ce13f7SAndroid Build Coastguard Worker CASE_SRCS_IN(0, 1, 0, 1) : {
6030*03ce13f7SAndroid Build Coastguard Worker if (Index0 == 0 && (Index1 - ExpectedNumElements) == 0 && Index2 == 1 &&
6031*03ce13f7SAndroid Build Coastguard Worker (Index3 - ExpectedNumElements) == 1) {
6032*03ce13f7SAndroid Build Coastguard Worker auto *Src1RM = legalize(Src1, Legal_Reg | Legal_Mem);
6033*03ce13f7SAndroid Build Coastguard Worker auto *Src0R = legalizeToReg(Src0);
6034*03ce13f7SAndroid Build Coastguard Worker T = makeReg(DestTy);
6035*03ce13f7SAndroid Build Coastguard Worker _movp(T, Src0R);
6036*03ce13f7SAndroid Build Coastguard Worker _punpckl(T, Src1RM);
6037*03ce13f7SAndroid Build Coastguard Worker } else if (Index0 == Index2 && Index1 == Index3) {
6038*03ce13f7SAndroid Build Coastguard Worker auto *Unified = lowerShuffleVector_UnifyFromDifferentSrcs(
6039*03ce13f7SAndroid Build Coastguard Worker Src0, Index0, Src1, Index1);
6040*03ce13f7SAndroid Build Coastguard Worker T = lowerShuffleVector_AllFromSameSrc(
6041*03ce13f7SAndroid Build Coastguard Worker Unified, UNIFIED_INDEX_0, UNIFIED_INDEX_1, UNIFIED_INDEX_0,
6042*03ce13f7SAndroid Build Coastguard Worker UNIFIED_INDEX_1);
6043*03ce13f7SAndroid Build Coastguard Worker } else {
6044*03ce13f7SAndroid Build Coastguard Worker auto *Unified0 = lowerShuffleVector_UnifyFromDifferentSrcs(
6045*03ce13f7SAndroid Build Coastguard Worker Src0, Index0, Src1, Index1);
6046*03ce13f7SAndroid Build Coastguard Worker auto *Unified1 = lowerShuffleVector_UnifyFromDifferentSrcs(
6047*03ce13f7SAndroid Build Coastguard Worker Src0, Index2, Src1, Index3);
6048*03ce13f7SAndroid Build Coastguard Worker T = lowerShuffleVector_TwoFromSameSrc(
6049*03ce13f7SAndroid Build Coastguard Worker Unified0, UNIFIED_INDEX_0, UNIFIED_INDEX_1, Unified1,
6050*03ce13f7SAndroid Build Coastguard Worker UNIFIED_INDEX_0, UNIFIED_INDEX_1);
6051*03ce13f7SAndroid Build Coastguard Worker }
6052*03ce13f7SAndroid Build Coastguard Worker }
6053*03ce13f7SAndroid Build Coastguard Worker break;
6054*03ce13f7SAndroid Build Coastguard Worker CASE_SRCS_IN(0, 1, 1, 0) : {
6055*03ce13f7SAndroid Build Coastguard Worker if (Index0 == Index3 && Index1 == Index2) {
6056*03ce13f7SAndroid Build Coastguard Worker auto *Unified = lowerShuffleVector_UnifyFromDifferentSrcs(
6057*03ce13f7SAndroid Build Coastguard Worker Src0, Index0, Src1, Index1);
6058*03ce13f7SAndroid Build Coastguard Worker T = lowerShuffleVector_AllFromSameSrc(
6059*03ce13f7SAndroid Build Coastguard Worker Unified, UNIFIED_INDEX_0, UNIFIED_INDEX_1, UNIFIED_INDEX_1,
6060*03ce13f7SAndroid Build Coastguard Worker UNIFIED_INDEX_0);
6061*03ce13f7SAndroid Build Coastguard Worker } else {
6062*03ce13f7SAndroid Build Coastguard Worker auto *Unified0 = lowerShuffleVector_UnifyFromDifferentSrcs(
6063*03ce13f7SAndroid Build Coastguard Worker Src0, Index0, Src1, Index1);
6064*03ce13f7SAndroid Build Coastguard Worker auto *Unified1 = lowerShuffleVector_UnifyFromDifferentSrcs(
6065*03ce13f7SAndroid Build Coastguard Worker Src1, Index2, Src0, Index3);
6066*03ce13f7SAndroid Build Coastguard Worker T = lowerShuffleVector_TwoFromSameSrc(
6067*03ce13f7SAndroid Build Coastguard Worker Unified0, UNIFIED_INDEX_0, UNIFIED_INDEX_1, Unified1,
6068*03ce13f7SAndroid Build Coastguard Worker UNIFIED_INDEX_0, UNIFIED_INDEX_1);
6069*03ce13f7SAndroid Build Coastguard Worker }
6070*03ce13f7SAndroid Build Coastguard Worker }
6071*03ce13f7SAndroid Build Coastguard Worker break;
6072*03ce13f7SAndroid Build Coastguard Worker CASE_SRCS_IN(0, 1, 1, 1) : {
6073*03ce13f7SAndroid Build Coastguard Worker auto *Unified = lowerShuffleVector_UnifyFromDifferentSrcs(Src0, Index0,
6074*03ce13f7SAndroid Build Coastguard Worker Src1, Index1);
6075*03ce13f7SAndroid Build Coastguard Worker T = lowerShuffleVector_TwoFromSameSrc(
6076*03ce13f7SAndroid Build Coastguard Worker Unified, UNIFIED_INDEX_0, UNIFIED_INDEX_1, Src1, Index2, Index3);
6077*03ce13f7SAndroid Build Coastguard Worker }
6078*03ce13f7SAndroid Build Coastguard Worker break;
6079*03ce13f7SAndroid Build Coastguard Worker CASE_SRCS_IN(1, 0, 0, 0) : {
6080*03ce13f7SAndroid Build Coastguard Worker auto *Unified = lowerShuffleVector_UnifyFromDifferentSrcs(Src1, Index0,
6081*03ce13f7SAndroid Build Coastguard Worker Src0, Index1);
6082*03ce13f7SAndroid Build Coastguard Worker T = lowerShuffleVector_TwoFromSameSrc(
6083*03ce13f7SAndroid Build Coastguard Worker Unified, UNIFIED_INDEX_0, UNIFIED_INDEX_1, Src0, Index2, Index3);
6084*03ce13f7SAndroid Build Coastguard Worker }
6085*03ce13f7SAndroid Build Coastguard Worker break;
6086*03ce13f7SAndroid Build Coastguard Worker CASE_SRCS_IN(1, 0, 0, 1) : {
6087*03ce13f7SAndroid Build Coastguard Worker if (Index0 == Index3 && Index1 == Index2) {
6088*03ce13f7SAndroid Build Coastguard Worker auto *Unified = lowerShuffleVector_UnifyFromDifferentSrcs(
6089*03ce13f7SAndroid Build Coastguard Worker Src1, Index0, Src0, Index1);
6090*03ce13f7SAndroid Build Coastguard Worker T = lowerShuffleVector_AllFromSameSrc(
6091*03ce13f7SAndroid Build Coastguard Worker Unified, UNIFIED_INDEX_0, UNIFIED_INDEX_1, UNIFIED_INDEX_1,
6092*03ce13f7SAndroid Build Coastguard Worker UNIFIED_INDEX_0);
6093*03ce13f7SAndroid Build Coastguard Worker } else {
6094*03ce13f7SAndroid Build Coastguard Worker auto *Unified0 = lowerShuffleVector_UnifyFromDifferentSrcs(
6095*03ce13f7SAndroid Build Coastguard Worker Src1, Index0, Src0, Index1);
6096*03ce13f7SAndroid Build Coastguard Worker auto *Unified1 = lowerShuffleVector_UnifyFromDifferentSrcs(
6097*03ce13f7SAndroid Build Coastguard Worker Src0, Index2, Src1, Index3);
6098*03ce13f7SAndroid Build Coastguard Worker T = lowerShuffleVector_TwoFromSameSrc(
6099*03ce13f7SAndroid Build Coastguard Worker Unified0, UNIFIED_INDEX_0, UNIFIED_INDEX_1, Unified1,
6100*03ce13f7SAndroid Build Coastguard Worker UNIFIED_INDEX_0, UNIFIED_INDEX_1);
6101*03ce13f7SAndroid Build Coastguard Worker }
6102*03ce13f7SAndroid Build Coastguard Worker }
6103*03ce13f7SAndroid Build Coastguard Worker break;
6104*03ce13f7SAndroid Build Coastguard Worker CASE_SRCS_IN(1, 0, 1, 0) : {
6105*03ce13f7SAndroid Build Coastguard Worker if ((Index0 - ExpectedNumElements) == 0 && Index1 == 0 &&
6106*03ce13f7SAndroid Build Coastguard Worker (Index2 - ExpectedNumElements) == 1 && Index3 == 1) {
6107*03ce13f7SAndroid Build Coastguard Worker auto *Src1RM = legalize(Src0, Legal_Reg | Legal_Mem);
6108*03ce13f7SAndroid Build Coastguard Worker auto *Src0R = legalizeToReg(Src1);
6109*03ce13f7SAndroid Build Coastguard Worker T = makeReg(DestTy);
6110*03ce13f7SAndroid Build Coastguard Worker _movp(T, Src0R);
6111*03ce13f7SAndroid Build Coastguard Worker _punpckl(T, Src1RM);
6112*03ce13f7SAndroid Build Coastguard Worker } else if (Index0 == Index2 && Index1 == Index3) {
6113*03ce13f7SAndroid Build Coastguard Worker auto *Unified = lowerShuffleVector_UnifyFromDifferentSrcs(
6114*03ce13f7SAndroid Build Coastguard Worker Src1, Index0, Src0, Index1);
6115*03ce13f7SAndroid Build Coastguard Worker T = lowerShuffleVector_AllFromSameSrc(
6116*03ce13f7SAndroid Build Coastguard Worker Unified, UNIFIED_INDEX_0, UNIFIED_INDEX_1, UNIFIED_INDEX_0,
6117*03ce13f7SAndroid Build Coastguard Worker UNIFIED_INDEX_1);
6118*03ce13f7SAndroid Build Coastguard Worker } else {
6119*03ce13f7SAndroid Build Coastguard Worker auto *Unified0 = lowerShuffleVector_UnifyFromDifferentSrcs(
6120*03ce13f7SAndroid Build Coastguard Worker Src1, Index0, Src0, Index1);
6121*03ce13f7SAndroid Build Coastguard Worker auto *Unified1 = lowerShuffleVector_UnifyFromDifferentSrcs(
6122*03ce13f7SAndroid Build Coastguard Worker Src1, Index2, Src0, Index3);
6123*03ce13f7SAndroid Build Coastguard Worker T = lowerShuffleVector_TwoFromSameSrc(
6124*03ce13f7SAndroid Build Coastguard Worker Unified0, UNIFIED_INDEX_0, UNIFIED_INDEX_1, Unified1,
6125*03ce13f7SAndroid Build Coastguard Worker UNIFIED_INDEX_0, UNIFIED_INDEX_1);
6126*03ce13f7SAndroid Build Coastguard Worker }
6127*03ce13f7SAndroid Build Coastguard Worker }
6128*03ce13f7SAndroid Build Coastguard Worker break;
6129*03ce13f7SAndroid Build Coastguard Worker CASE_SRCS_IN(1, 0, 1, 1) : {
6130*03ce13f7SAndroid Build Coastguard Worker auto *Unified = lowerShuffleVector_UnifyFromDifferentSrcs(Src1, Index0,
6131*03ce13f7SAndroid Build Coastguard Worker Src0, Index1);
6132*03ce13f7SAndroid Build Coastguard Worker T = lowerShuffleVector_TwoFromSameSrc(
6133*03ce13f7SAndroid Build Coastguard Worker Unified, UNIFIED_INDEX_0, UNIFIED_INDEX_1, Src1, Index2, Index3);
6134*03ce13f7SAndroid Build Coastguard Worker }
6135*03ce13f7SAndroid Build Coastguard Worker break;
6136*03ce13f7SAndroid Build Coastguard Worker CASE_SRCS_IN(1, 1, 0, 0) : {
6137*03ce13f7SAndroid Build Coastguard Worker T = lowerShuffleVector_TwoFromSameSrc(Src1, Index0, Index1, Src0,
6138*03ce13f7SAndroid Build Coastguard Worker Index2, Index3);
6139*03ce13f7SAndroid Build Coastguard Worker }
6140*03ce13f7SAndroid Build Coastguard Worker break;
6141*03ce13f7SAndroid Build Coastguard Worker CASE_SRCS_IN(1, 1, 0, 1) : {
6142*03ce13f7SAndroid Build Coastguard Worker auto *Unified = lowerShuffleVector_UnifyFromDifferentSrcs(Src0, Index2,
6143*03ce13f7SAndroid Build Coastguard Worker Src1, Index3);
6144*03ce13f7SAndroid Build Coastguard Worker T = lowerShuffleVector_TwoFromSameSrc(Src1, Index0, Index1, Unified,
6145*03ce13f7SAndroid Build Coastguard Worker UNIFIED_INDEX_0, UNIFIED_INDEX_1);
6146*03ce13f7SAndroid Build Coastguard Worker }
6147*03ce13f7SAndroid Build Coastguard Worker break;
6148*03ce13f7SAndroid Build Coastguard Worker CASE_SRCS_IN(1, 1, 1, 0) : {
6149*03ce13f7SAndroid Build Coastguard Worker auto *Unified = lowerShuffleVector_UnifyFromDifferentSrcs(Src1, Index2,
6150*03ce13f7SAndroid Build Coastguard Worker Src0, Index3);
6151*03ce13f7SAndroid Build Coastguard Worker T = lowerShuffleVector_TwoFromSameSrc(Src1, Index0, Index1, Unified,
6152*03ce13f7SAndroid Build Coastguard Worker UNIFIED_INDEX_0, UNIFIED_INDEX_1);
6153*03ce13f7SAndroid Build Coastguard Worker }
6154*03ce13f7SAndroid Build Coastguard Worker break;
6155*03ce13f7SAndroid Build Coastguard Worker CASE_SRCS_IN(1, 1, 1, 1) : {
6156*03ce13f7SAndroid Build Coastguard Worker T = lowerShuffleVector_AllFromSameSrc(Src1, Index0, Index1, Index2,
6157*03ce13f7SAndroid Build Coastguard Worker Index3);
6158*03ce13f7SAndroid Build Coastguard Worker }
6159*03ce13f7SAndroid Build Coastguard Worker break;
6160*03ce13f7SAndroid Build Coastguard Worker #undef CASE_SRCS_IN
6161*03ce13f7SAndroid Build Coastguard Worker }
6162*03ce13f7SAndroid Build Coastguard Worker
6163*03ce13f7SAndroid Build Coastguard Worker assert(T != nullptr);
6164*03ce13f7SAndroid Build Coastguard Worker assert(T->getType() == DestTy);
6165*03ce13f7SAndroid Build Coastguard Worker _movp(Dest, T);
6166*03ce13f7SAndroid Build Coastguard Worker return;
6167*03ce13f7SAndroid Build Coastguard Worker } break;
6168*03ce13f7SAndroid Build Coastguard Worker }
6169*03ce13f7SAndroid Build Coastguard Worker
6170*03ce13f7SAndroid Build Coastguard Worker // Unoptimized shuffle. Perform a series of inserts and extracts.
6171*03ce13f7SAndroid Build Coastguard Worker Context.insert<InstFakeDef>(T);
6172*03ce13f7SAndroid Build Coastguard Worker const Type ElementType = typeElementType(DestTy);
6173*03ce13f7SAndroid Build Coastguard Worker for (SizeT I = 0; I < Instr->getNumIndexes(); ++I) {
6174*03ce13f7SAndroid Build Coastguard Worker auto *Index = Instr->getIndex(I);
6175*03ce13f7SAndroid Build Coastguard Worker const SizeT Elem = Index->getValue();
6176*03ce13f7SAndroid Build Coastguard Worker auto *ExtElmt = makeReg(ElementType);
6177*03ce13f7SAndroid Build Coastguard Worker if (Elem < NumElements) {
6178*03ce13f7SAndroid Build Coastguard Worker lowerExtractElement(
6179*03ce13f7SAndroid Build Coastguard Worker InstExtractElement::create(Func, ExtElmt, Src0, Index));
6180*03ce13f7SAndroid Build Coastguard Worker } else {
6181*03ce13f7SAndroid Build Coastguard Worker lowerExtractElement(InstExtractElement::create(
6182*03ce13f7SAndroid Build Coastguard Worker Func, ExtElmt, Src1, Ctx->getConstantInt32(Elem - NumElements)));
6183*03ce13f7SAndroid Build Coastguard Worker }
6184*03ce13f7SAndroid Build Coastguard Worker auto *NewT = makeReg(DestTy);
6185*03ce13f7SAndroid Build Coastguard Worker lowerInsertElement(InstInsertElement::create(Func, NewT, T, ExtElmt,
6186*03ce13f7SAndroid Build Coastguard Worker Ctx->getConstantInt32(I)));
6187*03ce13f7SAndroid Build Coastguard Worker T = NewT;
6188*03ce13f7SAndroid Build Coastguard Worker }
6189*03ce13f7SAndroid Build Coastguard Worker _movp(Dest, T);
6190*03ce13f7SAndroid Build Coastguard Worker }
6191*03ce13f7SAndroid Build Coastguard Worker
lowerSelect(const InstSelect * Select)6192*03ce13f7SAndroid Build Coastguard Worker void TargetX8632::lowerSelect(const InstSelect *Select) {
6193*03ce13f7SAndroid Build Coastguard Worker Variable *Dest = Select->getDest();
6194*03ce13f7SAndroid Build Coastguard Worker
6195*03ce13f7SAndroid Build Coastguard Worker Operand *Condition = Select->getCondition();
6196*03ce13f7SAndroid Build Coastguard Worker // Handle folding opportunities.
6197*03ce13f7SAndroid Build Coastguard Worker if (const Inst *Producer = FoldingInfo.getProducerFor(Condition)) {
6198*03ce13f7SAndroid Build Coastguard Worker assert(Producer->isDeleted());
6199*03ce13f7SAndroid Build Coastguard Worker switch (BoolFolding::getProducerKind(Producer)) {
6200*03ce13f7SAndroid Build Coastguard Worker default:
6201*03ce13f7SAndroid Build Coastguard Worker break;
6202*03ce13f7SAndroid Build Coastguard Worker case BoolFolding::PK_Icmp32:
6203*03ce13f7SAndroid Build Coastguard Worker case BoolFolding::PK_Icmp64: {
6204*03ce13f7SAndroid Build Coastguard Worker lowerIcmpAndConsumer(llvm::cast<InstIcmp>(Producer), Select);
6205*03ce13f7SAndroid Build Coastguard Worker return;
6206*03ce13f7SAndroid Build Coastguard Worker }
6207*03ce13f7SAndroid Build Coastguard Worker case BoolFolding::PK_Fcmp: {
6208*03ce13f7SAndroid Build Coastguard Worker lowerFcmpAndConsumer(llvm::cast<InstFcmp>(Producer), Select);
6209*03ce13f7SAndroid Build Coastguard Worker return;
6210*03ce13f7SAndroid Build Coastguard Worker }
6211*03ce13f7SAndroid Build Coastguard Worker }
6212*03ce13f7SAndroid Build Coastguard Worker }
6213*03ce13f7SAndroid Build Coastguard Worker
6214*03ce13f7SAndroid Build Coastguard Worker if (isVectorType(Dest->getType())) {
6215*03ce13f7SAndroid Build Coastguard Worker lowerSelectVector(Select);
6216*03ce13f7SAndroid Build Coastguard Worker return;
6217*03ce13f7SAndroid Build Coastguard Worker }
6218*03ce13f7SAndroid Build Coastguard Worker
6219*03ce13f7SAndroid Build Coastguard Worker Operand *CmpResult = legalize(Condition, Legal_Reg | Legal_Mem);
6220*03ce13f7SAndroid Build Coastguard Worker Operand *Zero = Ctx->getConstantZero(IceType_i32);
6221*03ce13f7SAndroid Build Coastguard Worker _cmp(CmpResult, Zero);
6222*03ce13f7SAndroid Build Coastguard Worker Operand *SrcT = Select->getTrueOperand();
6223*03ce13f7SAndroid Build Coastguard Worker Operand *SrcF = Select->getFalseOperand();
6224*03ce13f7SAndroid Build Coastguard Worker const BrCond Cond = CondX86::Br_ne;
6225*03ce13f7SAndroid Build Coastguard Worker lowerSelectMove(Dest, Cond, SrcT, SrcF);
6226*03ce13f7SAndroid Build Coastguard Worker }
6227*03ce13f7SAndroid Build Coastguard Worker
lowerSelectMove(Variable * Dest,BrCond Cond,Operand * SrcT,Operand * SrcF)6228*03ce13f7SAndroid Build Coastguard Worker void TargetX8632::lowerSelectMove(Variable *Dest, BrCond Cond, Operand *SrcT,
6229*03ce13f7SAndroid Build Coastguard Worker Operand *SrcF) {
6230*03ce13f7SAndroid Build Coastguard Worker Type DestTy = Dest->getType();
6231*03ce13f7SAndroid Build Coastguard Worker if (typeWidthInBytes(DestTy) == 1 || isFloatingType(DestTy)) {
6232*03ce13f7SAndroid Build Coastguard Worker // The cmov instruction doesn't allow 8-bit or FP operands, so we need
6233*03ce13f7SAndroid Build Coastguard Worker // explicit control flow.
6234*03ce13f7SAndroid Build Coastguard Worker // d=cmp e,f; a=d?b:c ==> cmp e,f; a=b; jne L1; a=c; L1:
6235*03ce13f7SAndroid Build Coastguard Worker auto *Label = InstX86Label::create(Func, this);
6236*03ce13f7SAndroid Build Coastguard Worker SrcT = legalize(SrcT, Legal_Reg | Legal_Imm);
6237*03ce13f7SAndroid Build Coastguard Worker _mov(Dest, SrcT);
6238*03ce13f7SAndroid Build Coastguard Worker _br(Cond, Label);
6239*03ce13f7SAndroid Build Coastguard Worker SrcF = legalize(SrcF, Legal_Reg | Legal_Imm);
6240*03ce13f7SAndroid Build Coastguard Worker _redefined(_mov(Dest, SrcF));
6241*03ce13f7SAndroid Build Coastguard Worker Context.insert(Label);
6242*03ce13f7SAndroid Build Coastguard Worker return;
6243*03ce13f7SAndroid Build Coastguard Worker }
6244*03ce13f7SAndroid Build Coastguard Worker // mov t, SrcF; cmov_cond t, SrcT; mov dest, t
6245*03ce13f7SAndroid Build Coastguard Worker // But if SrcT is immediate, we might be able to do better, as the cmov
6246*03ce13f7SAndroid Build Coastguard Worker // instruction doesn't allow an immediate operand:
6247*03ce13f7SAndroid Build Coastguard Worker // mov t, SrcT; cmov_!cond t, SrcF; mov dest, t
6248*03ce13f7SAndroid Build Coastguard Worker if (llvm::isa<Constant>(SrcT) && !llvm::isa<Constant>(SrcF)) {
6249*03ce13f7SAndroid Build Coastguard Worker std::swap(SrcT, SrcF);
6250*03ce13f7SAndroid Build Coastguard Worker Cond = InstX86Base::getOppositeCondition(Cond);
6251*03ce13f7SAndroid Build Coastguard Worker }
6252*03ce13f7SAndroid Build Coastguard Worker if (DestTy == IceType_i64) {
6253*03ce13f7SAndroid Build Coastguard Worker SrcT = legalizeUndef(SrcT);
6254*03ce13f7SAndroid Build Coastguard Worker SrcF = legalizeUndef(SrcF);
6255*03ce13f7SAndroid Build Coastguard Worker // Set the low portion.
6256*03ce13f7SAndroid Build Coastguard Worker auto *DestLo = llvm::cast<Variable>(loOperand(Dest));
6257*03ce13f7SAndroid Build Coastguard Worker lowerSelectIntMove(DestLo, Cond, loOperand(SrcT), loOperand(SrcF));
6258*03ce13f7SAndroid Build Coastguard Worker // Set the high portion.
6259*03ce13f7SAndroid Build Coastguard Worker auto *DestHi = llvm::cast<Variable>(hiOperand(Dest));
6260*03ce13f7SAndroid Build Coastguard Worker lowerSelectIntMove(DestHi, Cond, hiOperand(SrcT), hiOperand(SrcF));
6261*03ce13f7SAndroid Build Coastguard Worker return;
6262*03ce13f7SAndroid Build Coastguard Worker }
6263*03ce13f7SAndroid Build Coastguard Worker
6264*03ce13f7SAndroid Build Coastguard Worker assert(DestTy == IceType_i16 || DestTy == IceType_i32);
6265*03ce13f7SAndroid Build Coastguard Worker lowerSelectIntMove(Dest, Cond, SrcT, SrcF);
6266*03ce13f7SAndroid Build Coastguard Worker }
6267*03ce13f7SAndroid Build Coastguard Worker
lowerSelectIntMove(Variable * Dest,BrCond Cond,Operand * SrcT,Operand * SrcF)6268*03ce13f7SAndroid Build Coastguard Worker void TargetX8632::lowerSelectIntMove(Variable *Dest, BrCond Cond, Operand *SrcT,
6269*03ce13f7SAndroid Build Coastguard Worker Operand *SrcF) {
6270*03ce13f7SAndroid Build Coastguard Worker Variable *T = nullptr;
6271*03ce13f7SAndroid Build Coastguard Worker SrcF = legalize(SrcF);
6272*03ce13f7SAndroid Build Coastguard Worker _mov(T, SrcF);
6273*03ce13f7SAndroid Build Coastguard Worker SrcT = legalize(SrcT, Legal_Reg | Legal_Mem);
6274*03ce13f7SAndroid Build Coastguard Worker _cmov(T, SrcT, Cond);
6275*03ce13f7SAndroid Build Coastguard Worker _mov(Dest, T);
6276*03ce13f7SAndroid Build Coastguard Worker }
6277*03ce13f7SAndroid Build Coastguard Worker
lowerMove(Variable * Dest,Operand * Src,bool IsRedefinition)6278*03ce13f7SAndroid Build Coastguard Worker void TargetX8632::lowerMove(Variable *Dest, Operand *Src, bool IsRedefinition) {
6279*03ce13f7SAndroid Build Coastguard Worker assert(Dest->getType() == Src->getType());
6280*03ce13f7SAndroid Build Coastguard Worker assert(!Dest->isRematerializable());
6281*03ce13f7SAndroid Build Coastguard Worker if (Dest->getType() == IceType_i64) {
6282*03ce13f7SAndroid Build Coastguard Worker Src = legalize(Src);
6283*03ce13f7SAndroid Build Coastguard Worker Operand *SrcLo = loOperand(Src);
6284*03ce13f7SAndroid Build Coastguard Worker Operand *SrcHi = hiOperand(Src);
6285*03ce13f7SAndroid Build Coastguard Worker auto *DestLo = llvm::cast<Variable>(loOperand(Dest));
6286*03ce13f7SAndroid Build Coastguard Worker auto *DestHi = llvm::cast<Variable>(hiOperand(Dest));
6287*03ce13f7SAndroid Build Coastguard Worker Variable *T_Lo = nullptr, *T_Hi = nullptr;
6288*03ce13f7SAndroid Build Coastguard Worker _mov(T_Lo, SrcLo);
6289*03ce13f7SAndroid Build Coastguard Worker _redefined(_mov(DestLo, T_Lo), IsRedefinition);
6290*03ce13f7SAndroid Build Coastguard Worker _mov(T_Hi, SrcHi);
6291*03ce13f7SAndroid Build Coastguard Worker _redefined(_mov(DestHi, T_Hi), IsRedefinition);
6292*03ce13f7SAndroid Build Coastguard Worker } else {
6293*03ce13f7SAndroid Build Coastguard Worker Operand *SrcLegal;
6294*03ce13f7SAndroid Build Coastguard Worker if (Dest->hasReg()) {
6295*03ce13f7SAndroid Build Coastguard Worker // If Dest already has a physical register, then only basic legalization
6296*03ce13f7SAndroid Build Coastguard Worker // is needed, as the source operand can be a register, immediate, or
6297*03ce13f7SAndroid Build Coastguard Worker // memory.
6298*03ce13f7SAndroid Build Coastguard Worker SrcLegal = legalize(Src, Legal_Reg, Dest->getRegNum());
6299*03ce13f7SAndroid Build Coastguard Worker } else {
6300*03ce13f7SAndroid Build Coastguard Worker // If Dest could be a stack operand, then RI must be a physical register
6301*03ce13f7SAndroid Build Coastguard Worker // or a scalar integer immediate.
6302*03ce13f7SAndroid Build Coastguard Worker SrcLegal = legalize(Src, Legal_Reg | Legal_Imm);
6303*03ce13f7SAndroid Build Coastguard Worker }
6304*03ce13f7SAndroid Build Coastguard Worker if (isVectorType(Dest->getType())) {
6305*03ce13f7SAndroid Build Coastguard Worker _redefined(_movp(Dest, SrcLegal), IsRedefinition);
6306*03ce13f7SAndroid Build Coastguard Worker } else {
6307*03ce13f7SAndroid Build Coastguard Worker _redefined(_mov(Dest, SrcLegal), IsRedefinition);
6308*03ce13f7SAndroid Build Coastguard Worker }
6309*03ce13f7SAndroid Build Coastguard Worker }
6310*03ce13f7SAndroid Build Coastguard Worker }
6311*03ce13f7SAndroid Build Coastguard Worker
lowerOptimizeFcmpSelect(const InstFcmp * Fcmp,const InstSelect * Select)6312*03ce13f7SAndroid Build Coastguard Worker bool TargetX8632::lowerOptimizeFcmpSelect(const InstFcmp *Fcmp,
6313*03ce13f7SAndroid Build Coastguard Worker const InstSelect *Select) {
6314*03ce13f7SAndroid Build Coastguard Worker Operand *CmpSrc0 = Fcmp->getSrc(0);
6315*03ce13f7SAndroid Build Coastguard Worker Operand *CmpSrc1 = Fcmp->getSrc(1);
6316*03ce13f7SAndroid Build Coastguard Worker Operand *SelectSrcT = Select->getTrueOperand();
6317*03ce13f7SAndroid Build Coastguard Worker Operand *SelectSrcF = Select->getFalseOperand();
6318*03ce13f7SAndroid Build Coastguard Worker Variable *SelectDest = Select->getDest();
6319*03ce13f7SAndroid Build Coastguard Worker
6320*03ce13f7SAndroid Build Coastguard Worker // TODO(capn): also handle swapped compare/select operand order.
6321*03ce13f7SAndroid Build Coastguard Worker if (CmpSrc0 != SelectSrcT || CmpSrc1 != SelectSrcF)
6322*03ce13f7SAndroid Build Coastguard Worker return false;
6323*03ce13f7SAndroid Build Coastguard Worker
6324*03ce13f7SAndroid Build Coastguard Worker // TODO(sehr, stichnot): fcmp/select patterns (e.g., minsd/maxss) go here.
6325*03ce13f7SAndroid Build Coastguard Worker InstFcmp::FCond Condition = Fcmp->getCondition();
6326*03ce13f7SAndroid Build Coastguard Worker switch (Condition) {
6327*03ce13f7SAndroid Build Coastguard Worker default:
6328*03ce13f7SAndroid Build Coastguard Worker return false;
6329*03ce13f7SAndroid Build Coastguard Worker case InstFcmp::True:
6330*03ce13f7SAndroid Build Coastguard Worker break;
6331*03ce13f7SAndroid Build Coastguard Worker case InstFcmp::False:
6332*03ce13f7SAndroid Build Coastguard Worker break;
6333*03ce13f7SAndroid Build Coastguard Worker case InstFcmp::Ogt: {
6334*03ce13f7SAndroid Build Coastguard Worker Variable *T = makeReg(SelectDest->getType());
6335*03ce13f7SAndroid Build Coastguard Worker if (isScalarFloatingType(SelectSrcT->getType())) {
6336*03ce13f7SAndroid Build Coastguard Worker _mov(T, legalize(SelectSrcT, Legal_Reg | Legal_Mem));
6337*03ce13f7SAndroid Build Coastguard Worker _maxss(T, legalize(SelectSrcF, Legal_Reg | Legal_Mem));
6338*03ce13f7SAndroid Build Coastguard Worker _mov(SelectDest, T);
6339*03ce13f7SAndroid Build Coastguard Worker } else {
6340*03ce13f7SAndroid Build Coastguard Worker _movp(T, legalize(SelectSrcT, Legal_Reg | Legal_Mem));
6341*03ce13f7SAndroid Build Coastguard Worker _maxps(T, legalize(SelectSrcF, Legal_Reg | Legal_Mem));
6342*03ce13f7SAndroid Build Coastguard Worker _movp(SelectDest, T);
6343*03ce13f7SAndroid Build Coastguard Worker }
6344*03ce13f7SAndroid Build Coastguard Worker return true;
6345*03ce13f7SAndroid Build Coastguard Worker } break;
6346*03ce13f7SAndroid Build Coastguard Worker case InstFcmp::Olt: {
6347*03ce13f7SAndroid Build Coastguard Worker Variable *T = makeReg(SelectSrcT->getType());
6348*03ce13f7SAndroid Build Coastguard Worker if (isScalarFloatingType(SelectSrcT->getType())) {
6349*03ce13f7SAndroid Build Coastguard Worker _mov(T, legalize(SelectSrcT, Legal_Reg | Legal_Mem));
6350*03ce13f7SAndroid Build Coastguard Worker _minss(T, legalize(SelectSrcF, Legal_Reg | Legal_Mem));
6351*03ce13f7SAndroid Build Coastguard Worker _mov(SelectDest, T);
6352*03ce13f7SAndroid Build Coastguard Worker } else {
6353*03ce13f7SAndroid Build Coastguard Worker _movp(T, legalize(SelectSrcT, Legal_Reg | Legal_Mem));
6354*03ce13f7SAndroid Build Coastguard Worker _minps(T, legalize(SelectSrcF, Legal_Reg | Legal_Mem));
6355*03ce13f7SAndroid Build Coastguard Worker _movp(SelectDest, T);
6356*03ce13f7SAndroid Build Coastguard Worker }
6357*03ce13f7SAndroid Build Coastguard Worker return true;
6358*03ce13f7SAndroid Build Coastguard Worker } break;
6359*03ce13f7SAndroid Build Coastguard Worker }
6360*03ce13f7SAndroid Build Coastguard Worker return false;
6361*03ce13f7SAndroid Build Coastguard Worker }
6362*03ce13f7SAndroid Build Coastguard Worker
lowerIcmp(const InstIcmp * Icmp)6363*03ce13f7SAndroid Build Coastguard Worker void TargetX8632::lowerIcmp(const InstIcmp *Icmp) {
6364*03ce13f7SAndroid Build Coastguard Worker Variable *Dest = Icmp->getDest();
6365*03ce13f7SAndroid Build Coastguard Worker if (isVectorType(Dest->getType())) {
6366*03ce13f7SAndroid Build Coastguard Worker lowerIcmpVector(Icmp);
6367*03ce13f7SAndroid Build Coastguard Worker } else {
6368*03ce13f7SAndroid Build Coastguard Worker constexpr Inst *Consumer = nullptr;
6369*03ce13f7SAndroid Build Coastguard Worker lowerIcmpAndConsumer(Icmp, Consumer);
6370*03ce13f7SAndroid Build Coastguard Worker }
6371*03ce13f7SAndroid Build Coastguard Worker }
6372*03ce13f7SAndroid Build Coastguard Worker
lowerSelectVector(const InstSelect * Instr)6373*03ce13f7SAndroid Build Coastguard Worker void TargetX8632::lowerSelectVector(const InstSelect *Instr) {
6374*03ce13f7SAndroid Build Coastguard Worker Variable *Dest = Instr->getDest();
6375*03ce13f7SAndroid Build Coastguard Worker Type DestTy = Dest->getType();
6376*03ce13f7SAndroid Build Coastguard Worker Operand *SrcT = Instr->getTrueOperand();
6377*03ce13f7SAndroid Build Coastguard Worker Operand *SrcF = Instr->getFalseOperand();
6378*03ce13f7SAndroid Build Coastguard Worker Operand *Condition = Instr->getCondition();
6379*03ce13f7SAndroid Build Coastguard Worker
6380*03ce13f7SAndroid Build Coastguard Worker if (!isVectorType(DestTy))
6381*03ce13f7SAndroid Build Coastguard Worker llvm::report_fatal_error("Expected a vector select");
6382*03ce13f7SAndroid Build Coastguard Worker
6383*03ce13f7SAndroid Build Coastguard Worker Type SrcTy = SrcT->getType();
6384*03ce13f7SAndroid Build Coastguard Worker Variable *T = makeReg(SrcTy);
6385*03ce13f7SAndroid Build Coastguard Worker Operand *SrcTRM = legalize(SrcT, Legal_Reg | Legal_Mem);
6386*03ce13f7SAndroid Build Coastguard Worker Operand *SrcFRM = legalize(SrcF, Legal_Reg | Legal_Mem);
6387*03ce13f7SAndroid Build Coastguard Worker
6388*03ce13f7SAndroid Build Coastguard Worker if (InstructionSet >= SSE4_1) {
6389*03ce13f7SAndroid Build Coastguard Worker // TODO(wala): If the condition operand is a constant, use blendps or
6390*03ce13f7SAndroid Build Coastguard Worker // pblendw.
6391*03ce13f7SAndroid Build Coastguard Worker //
6392*03ce13f7SAndroid Build Coastguard Worker // Use blendvps or pblendvb to implement select.
6393*03ce13f7SAndroid Build Coastguard Worker if (SrcTy == IceType_v4i1 || SrcTy == IceType_v4i32 ||
6394*03ce13f7SAndroid Build Coastguard Worker SrcTy == IceType_v4f32) {
6395*03ce13f7SAndroid Build Coastguard Worker Operand *ConditionRM = legalize(Condition, Legal_Reg | Legal_Mem);
6396*03ce13f7SAndroid Build Coastguard Worker Variable *xmm0 = makeReg(IceType_v4i32, RegX8632::Reg_xmm0);
6397*03ce13f7SAndroid Build Coastguard Worker _movp(xmm0, ConditionRM);
6398*03ce13f7SAndroid Build Coastguard Worker _psll(xmm0, Ctx->getConstantInt8(31));
6399*03ce13f7SAndroid Build Coastguard Worker _movp(T, SrcFRM);
6400*03ce13f7SAndroid Build Coastguard Worker _blendvps(T, SrcTRM, xmm0);
6401*03ce13f7SAndroid Build Coastguard Worker _movp(Dest, T);
6402*03ce13f7SAndroid Build Coastguard Worker } else {
6403*03ce13f7SAndroid Build Coastguard Worker assert(typeNumElements(SrcTy) == 8 || typeNumElements(SrcTy) == 16);
6404*03ce13f7SAndroid Build Coastguard Worker Type SignExtTy =
6405*03ce13f7SAndroid Build Coastguard Worker Condition->getType() == IceType_v8i1 ? IceType_v8i16 : IceType_v16i8;
6406*03ce13f7SAndroid Build Coastguard Worker Variable *xmm0 = makeReg(SignExtTy, RegX8632::Reg_xmm0);
6407*03ce13f7SAndroid Build Coastguard Worker lowerCast(InstCast::create(Func, InstCast::Sext, xmm0, Condition));
6408*03ce13f7SAndroid Build Coastguard Worker _movp(T, SrcFRM);
6409*03ce13f7SAndroid Build Coastguard Worker _pblendvb(T, SrcTRM, xmm0);
6410*03ce13f7SAndroid Build Coastguard Worker _movp(Dest, T);
6411*03ce13f7SAndroid Build Coastguard Worker }
6412*03ce13f7SAndroid Build Coastguard Worker return;
6413*03ce13f7SAndroid Build Coastguard Worker }
6414*03ce13f7SAndroid Build Coastguard Worker // Lower select without SSE4.1:
6415*03ce13f7SAndroid Build Coastguard Worker // a=d?b:c ==>
6416*03ce13f7SAndroid Build Coastguard Worker // if elementtype(d) != i1:
6417*03ce13f7SAndroid Build Coastguard Worker // d=sext(d);
6418*03ce13f7SAndroid Build Coastguard Worker // a=(b&d)|(c&~d);
6419*03ce13f7SAndroid Build Coastguard Worker Variable *T2 = makeReg(SrcTy);
6420*03ce13f7SAndroid Build Coastguard Worker // Sign extend the condition operand if applicable.
6421*03ce13f7SAndroid Build Coastguard Worker if (SrcTy == IceType_v4f32) {
6422*03ce13f7SAndroid Build Coastguard Worker // The sext operation takes only integer arguments.
6423*03ce13f7SAndroid Build Coastguard Worker Variable *T3 = Func->makeVariable(IceType_v4i32);
6424*03ce13f7SAndroid Build Coastguard Worker lowerCast(InstCast::create(Func, InstCast::Sext, T3, Condition));
6425*03ce13f7SAndroid Build Coastguard Worker _movp(T, T3);
6426*03ce13f7SAndroid Build Coastguard Worker } else if (typeElementType(SrcTy) != IceType_i1) {
6427*03ce13f7SAndroid Build Coastguard Worker lowerCast(InstCast::create(Func, InstCast::Sext, T, Condition));
6428*03ce13f7SAndroid Build Coastguard Worker } else {
6429*03ce13f7SAndroid Build Coastguard Worker Operand *ConditionRM = legalize(Condition, Legal_Reg | Legal_Mem);
6430*03ce13f7SAndroid Build Coastguard Worker _movp(T, ConditionRM);
6431*03ce13f7SAndroid Build Coastguard Worker }
6432*03ce13f7SAndroid Build Coastguard Worker _movp(T2, T);
6433*03ce13f7SAndroid Build Coastguard Worker _pand(T, SrcTRM);
6434*03ce13f7SAndroid Build Coastguard Worker _pandn(T2, SrcFRM);
6435*03ce13f7SAndroid Build Coastguard Worker _por(T, T2);
6436*03ce13f7SAndroid Build Coastguard Worker _movp(Dest, T);
6437*03ce13f7SAndroid Build Coastguard Worker
6438*03ce13f7SAndroid Build Coastguard Worker return;
6439*03ce13f7SAndroid Build Coastguard Worker }
6440*03ce13f7SAndroid Build Coastguard Worker
lowerStore(const InstStore * Instr)6441*03ce13f7SAndroid Build Coastguard Worker void TargetX8632::lowerStore(const InstStore *Instr) {
6442*03ce13f7SAndroid Build Coastguard Worker Operand *Value = Instr->getData();
6443*03ce13f7SAndroid Build Coastguard Worker Operand *Addr = Instr->getStoreAddress();
6444*03ce13f7SAndroid Build Coastguard Worker X86OperandMem *NewAddr = formMemoryOperand(Addr, Value->getType());
6445*03ce13f7SAndroid Build Coastguard Worker doMockBoundsCheck(NewAddr);
6446*03ce13f7SAndroid Build Coastguard Worker Type Ty = NewAddr->getType();
6447*03ce13f7SAndroid Build Coastguard Worker
6448*03ce13f7SAndroid Build Coastguard Worker if (Ty == IceType_i64) {
6449*03ce13f7SAndroid Build Coastguard Worker Value = legalizeUndef(Value);
6450*03ce13f7SAndroid Build Coastguard Worker Operand *ValueHi = legalize(hiOperand(Value), Legal_Reg | Legal_Imm);
6451*03ce13f7SAndroid Build Coastguard Worker _store(ValueHi, llvm::cast<X86OperandMem>(hiOperand(NewAddr)));
6452*03ce13f7SAndroid Build Coastguard Worker Operand *ValueLo = legalize(loOperand(Value), Legal_Reg | Legal_Imm);
6453*03ce13f7SAndroid Build Coastguard Worker _store(ValueLo, llvm::cast<X86OperandMem>(loOperand(NewAddr)));
6454*03ce13f7SAndroid Build Coastguard Worker } else if (isVectorType(Ty)) {
6455*03ce13f7SAndroid Build Coastguard Worker _storep(legalizeToReg(Value), NewAddr);
6456*03ce13f7SAndroid Build Coastguard Worker } else {
6457*03ce13f7SAndroid Build Coastguard Worker Value = legalize(Value, Legal_Reg | Legal_Imm);
6458*03ce13f7SAndroid Build Coastguard Worker _store(Value, NewAddr);
6459*03ce13f7SAndroid Build Coastguard Worker }
6460*03ce13f7SAndroid Build Coastguard Worker }
6461*03ce13f7SAndroid Build Coastguard Worker
doAddressOptStore()6462*03ce13f7SAndroid Build Coastguard Worker void TargetX8632::doAddressOptStore() {
6463*03ce13f7SAndroid Build Coastguard Worker auto *Instr = llvm::cast<InstStore>(Context.getCur());
6464*03ce13f7SAndroid Build Coastguard Worker Operand *Addr = Instr->getStoreAddress();
6465*03ce13f7SAndroid Build Coastguard Worker Operand *Data = Instr->getData();
6466*03ce13f7SAndroid Build Coastguard Worker if (auto *OptAddr = computeAddressOpt(Instr, Data->getType(), Addr)) {
6467*03ce13f7SAndroid Build Coastguard Worker Instr->setDeleted();
6468*03ce13f7SAndroid Build Coastguard Worker auto *NewStore = Context.insert<InstStore>(Data, OptAddr);
6469*03ce13f7SAndroid Build Coastguard Worker if (Instr->getDest())
6470*03ce13f7SAndroid Build Coastguard Worker NewStore->setRmwBeacon(Instr->getRmwBeacon());
6471*03ce13f7SAndroid Build Coastguard Worker }
6472*03ce13f7SAndroid Build Coastguard Worker }
6473*03ce13f7SAndroid Build Coastguard Worker
doAddressOptStoreSubVector()6474*03ce13f7SAndroid Build Coastguard Worker void TargetX8632::doAddressOptStoreSubVector() {
6475*03ce13f7SAndroid Build Coastguard Worker auto *Intrinsic = llvm::cast<InstIntrinsic>(Context.getCur());
6476*03ce13f7SAndroid Build Coastguard Worker Operand *Addr = Intrinsic->getArg(1);
6477*03ce13f7SAndroid Build Coastguard Worker Operand *Data = Intrinsic->getArg(0);
6478*03ce13f7SAndroid Build Coastguard Worker if (auto *OptAddr = computeAddressOpt(Intrinsic, Data->getType(), Addr)) {
6479*03ce13f7SAndroid Build Coastguard Worker Intrinsic->setDeleted();
6480*03ce13f7SAndroid Build Coastguard Worker const Ice::Intrinsics::IntrinsicInfo Info = {
6481*03ce13f7SAndroid Build Coastguard Worker Ice::Intrinsics::StoreSubVector, Ice::Intrinsics::SideEffects_T,
6482*03ce13f7SAndroid Build Coastguard Worker Ice::Intrinsics::ReturnsTwice_F, Ice::Intrinsics::MemoryWrite_T};
6483*03ce13f7SAndroid Build Coastguard Worker auto *NewStore = Context.insert<InstIntrinsic>(3, nullptr, Info);
6484*03ce13f7SAndroid Build Coastguard Worker NewStore->addArg(Data);
6485*03ce13f7SAndroid Build Coastguard Worker NewStore->addArg(OptAddr);
6486*03ce13f7SAndroid Build Coastguard Worker NewStore->addArg(Intrinsic->getArg(2));
6487*03ce13f7SAndroid Build Coastguard Worker }
6488*03ce13f7SAndroid Build Coastguard Worker }
6489*03ce13f7SAndroid Build Coastguard Worker
lowerCmpRange(Operand * Comparison,uint64_t Min,uint64_t Max)6490*03ce13f7SAndroid Build Coastguard Worker Operand *TargetX8632::lowerCmpRange(Operand *Comparison, uint64_t Min,
6491*03ce13f7SAndroid Build Coastguard Worker uint64_t Max) {
6492*03ce13f7SAndroid Build Coastguard Worker // TODO(ascull): 64-bit should not reach here but only because it is not
6493*03ce13f7SAndroid Build Coastguard Worker // implemented yet. This should be able to handle the 64-bit case.
6494*03ce13f7SAndroid Build Coastguard Worker assert(Comparison->getType() != IceType_i64);
6495*03ce13f7SAndroid Build Coastguard Worker // Subtracting 0 is a nop so don't do it
6496*03ce13f7SAndroid Build Coastguard Worker if (Min != 0) {
6497*03ce13f7SAndroid Build Coastguard Worker // Avoid clobbering the comparison by copying it
6498*03ce13f7SAndroid Build Coastguard Worker Variable *T = nullptr;
6499*03ce13f7SAndroid Build Coastguard Worker _mov(T, Comparison);
6500*03ce13f7SAndroid Build Coastguard Worker _sub(T, Ctx->getConstantInt32(Min));
6501*03ce13f7SAndroid Build Coastguard Worker Comparison = T;
6502*03ce13f7SAndroid Build Coastguard Worker }
6503*03ce13f7SAndroid Build Coastguard Worker
6504*03ce13f7SAndroid Build Coastguard Worker _cmp(Comparison, Ctx->getConstantInt32(Max - Min));
6505*03ce13f7SAndroid Build Coastguard Worker
6506*03ce13f7SAndroid Build Coastguard Worker return Comparison;
6507*03ce13f7SAndroid Build Coastguard Worker }
6508*03ce13f7SAndroid Build Coastguard Worker
lowerCaseCluster(const CaseCluster & Case,Operand * Comparison,bool DoneCmp,CfgNode * DefaultTarget)6509*03ce13f7SAndroid Build Coastguard Worker void TargetX8632::lowerCaseCluster(const CaseCluster &Case, Operand *Comparison,
6510*03ce13f7SAndroid Build Coastguard Worker bool DoneCmp, CfgNode *DefaultTarget) {
6511*03ce13f7SAndroid Build Coastguard Worker switch (Case.getKind()) {
6512*03ce13f7SAndroid Build Coastguard Worker case CaseCluster::JumpTable: {
6513*03ce13f7SAndroid Build Coastguard Worker InstX86Label *SkipJumpTable;
6514*03ce13f7SAndroid Build Coastguard Worker
6515*03ce13f7SAndroid Build Coastguard Worker Operand *RangeIndex =
6516*03ce13f7SAndroid Build Coastguard Worker lowerCmpRange(Comparison, Case.getLow(), Case.getHigh());
6517*03ce13f7SAndroid Build Coastguard Worker if (DefaultTarget == nullptr) {
6518*03ce13f7SAndroid Build Coastguard Worker // Skip over jump table logic if comparison not in range and no default
6519*03ce13f7SAndroid Build Coastguard Worker SkipJumpTable = InstX86Label::create(Func, this);
6520*03ce13f7SAndroid Build Coastguard Worker _br(CondX86::Br_a, SkipJumpTable);
6521*03ce13f7SAndroid Build Coastguard Worker } else {
6522*03ce13f7SAndroid Build Coastguard Worker _br(CondX86::Br_a, DefaultTarget);
6523*03ce13f7SAndroid Build Coastguard Worker }
6524*03ce13f7SAndroid Build Coastguard Worker
6525*03ce13f7SAndroid Build Coastguard Worker InstJumpTable *JumpTable = Case.getJumpTable();
6526*03ce13f7SAndroid Build Coastguard Worker Context.insert(JumpTable);
6527*03ce13f7SAndroid Build Coastguard Worker
6528*03ce13f7SAndroid Build Coastguard Worker // Make sure the index is a register of the same width as the base
6529*03ce13f7SAndroid Build Coastguard Worker Variable *Index;
6530*03ce13f7SAndroid Build Coastguard Worker const Type PointerType = IceType_i32;
6531*03ce13f7SAndroid Build Coastguard Worker if (RangeIndex->getType() != PointerType) {
6532*03ce13f7SAndroid Build Coastguard Worker Index = makeReg(PointerType);
6533*03ce13f7SAndroid Build Coastguard Worker assert(RangeIndex->getType() != IceType_i64);
6534*03ce13f7SAndroid Build Coastguard Worker Operand *RangeIndexRM = legalize(RangeIndex, Legal_Reg | Legal_Mem);
6535*03ce13f7SAndroid Build Coastguard Worker _movzx(Index, RangeIndexRM);
6536*03ce13f7SAndroid Build Coastguard Worker } else {
6537*03ce13f7SAndroid Build Coastguard Worker Index = legalizeToReg(RangeIndex);
6538*03ce13f7SAndroid Build Coastguard Worker }
6539*03ce13f7SAndroid Build Coastguard Worker
6540*03ce13f7SAndroid Build Coastguard Worker constexpr RelocOffsetT RelocOffset = 0;
6541*03ce13f7SAndroid Build Coastguard Worker constexpr Variable *NoBase = nullptr;
6542*03ce13f7SAndroid Build Coastguard Worker constexpr Constant *NoOffset = nullptr;
6543*03ce13f7SAndroid Build Coastguard Worker auto JTName = GlobalString::createWithString(Ctx, JumpTable->getName());
6544*03ce13f7SAndroid Build Coastguard Worker Constant *Offset = Ctx->getConstantSym(RelocOffset, JTName);
6545*03ce13f7SAndroid Build Coastguard Worker uint16_t Shift = typeWidthInBytesLog2(PointerType);
6546*03ce13f7SAndroid Build Coastguard Worker constexpr auto Segment = X86OperandMem::SegmentRegisters::DefaultSegment;
6547*03ce13f7SAndroid Build Coastguard Worker
6548*03ce13f7SAndroid Build Coastguard Worker Variable *Target = nullptr;
6549*03ce13f7SAndroid Build Coastguard Worker if (PointerType == IceType_i32) {
6550*03ce13f7SAndroid Build Coastguard Worker _mov(Target, X86OperandMem::create(Func, PointerType, NoBase, Offset,
6551*03ce13f7SAndroid Build Coastguard Worker Index, Shift, Segment));
6552*03ce13f7SAndroid Build Coastguard Worker } else {
6553*03ce13f7SAndroid Build Coastguard Worker auto *Base = makeReg(IceType_i64);
6554*03ce13f7SAndroid Build Coastguard Worker _lea(Base, X86OperandMem::create(Func, IceType_void, NoBase, Offset));
6555*03ce13f7SAndroid Build Coastguard Worker _mov(Target, X86OperandMem::create(Func, PointerType, Base, NoOffset,
6556*03ce13f7SAndroid Build Coastguard Worker Index, Shift, Segment));
6557*03ce13f7SAndroid Build Coastguard Worker }
6558*03ce13f7SAndroid Build Coastguard Worker
6559*03ce13f7SAndroid Build Coastguard Worker lowerIndirectJump(Target);
6560*03ce13f7SAndroid Build Coastguard Worker
6561*03ce13f7SAndroid Build Coastguard Worker if (DefaultTarget == nullptr)
6562*03ce13f7SAndroid Build Coastguard Worker Context.insert(SkipJumpTable);
6563*03ce13f7SAndroid Build Coastguard Worker return;
6564*03ce13f7SAndroid Build Coastguard Worker }
6565*03ce13f7SAndroid Build Coastguard Worker case CaseCluster::Range: {
6566*03ce13f7SAndroid Build Coastguard Worker if (Case.isUnitRange()) {
6567*03ce13f7SAndroid Build Coastguard Worker // Single item
6568*03ce13f7SAndroid Build Coastguard Worker if (!DoneCmp) {
6569*03ce13f7SAndroid Build Coastguard Worker Constant *Value = Ctx->getConstantInt32(Case.getLow());
6570*03ce13f7SAndroid Build Coastguard Worker _cmp(Comparison, Value);
6571*03ce13f7SAndroid Build Coastguard Worker }
6572*03ce13f7SAndroid Build Coastguard Worker _br(CondX86::Br_e, Case.getTarget());
6573*03ce13f7SAndroid Build Coastguard Worker } else if (DoneCmp && Case.isPairRange()) {
6574*03ce13f7SAndroid Build Coastguard Worker // Range of two items with first item aleady compared against
6575*03ce13f7SAndroid Build Coastguard Worker _br(CondX86::Br_e, Case.getTarget());
6576*03ce13f7SAndroid Build Coastguard Worker Constant *Value = Ctx->getConstantInt32(Case.getHigh());
6577*03ce13f7SAndroid Build Coastguard Worker _cmp(Comparison, Value);
6578*03ce13f7SAndroid Build Coastguard Worker _br(CondX86::Br_e, Case.getTarget());
6579*03ce13f7SAndroid Build Coastguard Worker } else {
6580*03ce13f7SAndroid Build Coastguard Worker // Range
6581*03ce13f7SAndroid Build Coastguard Worker lowerCmpRange(Comparison, Case.getLow(), Case.getHigh());
6582*03ce13f7SAndroid Build Coastguard Worker _br(CondX86::Br_be, Case.getTarget());
6583*03ce13f7SAndroid Build Coastguard Worker }
6584*03ce13f7SAndroid Build Coastguard Worker if (DefaultTarget != nullptr)
6585*03ce13f7SAndroid Build Coastguard Worker _br(DefaultTarget);
6586*03ce13f7SAndroid Build Coastguard Worker return;
6587*03ce13f7SAndroid Build Coastguard Worker }
6588*03ce13f7SAndroid Build Coastguard Worker }
6589*03ce13f7SAndroid Build Coastguard Worker }
6590*03ce13f7SAndroid Build Coastguard Worker
lowerSwitch(const InstSwitch * Instr)6591*03ce13f7SAndroid Build Coastguard Worker void TargetX8632::lowerSwitch(const InstSwitch *Instr) {
6592*03ce13f7SAndroid Build Coastguard Worker // Group cases together and navigate through them with a binary search
6593*03ce13f7SAndroid Build Coastguard Worker CaseClusterArray CaseClusters = CaseCluster::clusterizeSwitch(Func, Instr);
6594*03ce13f7SAndroid Build Coastguard Worker Operand *Src0 = Instr->getComparison();
6595*03ce13f7SAndroid Build Coastguard Worker CfgNode *DefaultTarget = Instr->getLabelDefault();
6596*03ce13f7SAndroid Build Coastguard Worker
6597*03ce13f7SAndroid Build Coastguard Worker assert(CaseClusters.size() != 0); // Should always be at least one
6598*03ce13f7SAndroid Build Coastguard Worker
6599*03ce13f7SAndroid Build Coastguard Worker if (Src0->getType() == IceType_i64) {
6600*03ce13f7SAndroid Build Coastguard Worker Src0 = legalize(Src0); // get Base/Index into physical registers
6601*03ce13f7SAndroid Build Coastguard Worker Operand *Src0Lo = loOperand(Src0);
6602*03ce13f7SAndroid Build Coastguard Worker Operand *Src0Hi = hiOperand(Src0);
6603*03ce13f7SAndroid Build Coastguard Worker if (CaseClusters.back().getHigh() > UINT32_MAX) {
6604*03ce13f7SAndroid Build Coastguard Worker // TODO(ascull): handle 64-bit case properly (currently naive version)
6605*03ce13f7SAndroid Build Coastguard Worker // This might be handled by a higher level lowering of switches.
6606*03ce13f7SAndroid Build Coastguard Worker SizeT NumCases = Instr->getNumCases();
6607*03ce13f7SAndroid Build Coastguard Worker if (NumCases >= 2) {
6608*03ce13f7SAndroid Build Coastguard Worker Src0Lo = legalizeToReg(Src0Lo);
6609*03ce13f7SAndroid Build Coastguard Worker Src0Hi = legalizeToReg(Src0Hi);
6610*03ce13f7SAndroid Build Coastguard Worker } else {
6611*03ce13f7SAndroid Build Coastguard Worker Src0Lo = legalize(Src0Lo, Legal_Reg | Legal_Mem);
6612*03ce13f7SAndroid Build Coastguard Worker Src0Hi = legalize(Src0Hi, Legal_Reg | Legal_Mem);
6613*03ce13f7SAndroid Build Coastguard Worker }
6614*03ce13f7SAndroid Build Coastguard Worker for (SizeT I = 0; I < NumCases; ++I) {
6615*03ce13f7SAndroid Build Coastguard Worker Constant *ValueLo = Ctx->getConstantInt32(Instr->getValue(I));
6616*03ce13f7SAndroid Build Coastguard Worker Constant *ValueHi = Ctx->getConstantInt32(Instr->getValue(I) >> 32);
6617*03ce13f7SAndroid Build Coastguard Worker InstX86Label *Label = InstX86Label::create(Func, this);
6618*03ce13f7SAndroid Build Coastguard Worker _cmp(Src0Lo, ValueLo);
6619*03ce13f7SAndroid Build Coastguard Worker _br(CondX86::Br_ne, Label);
6620*03ce13f7SAndroid Build Coastguard Worker _cmp(Src0Hi, ValueHi);
6621*03ce13f7SAndroid Build Coastguard Worker _br(CondX86::Br_e, Instr->getLabel(I));
6622*03ce13f7SAndroid Build Coastguard Worker Context.insert(Label);
6623*03ce13f7SAndroid Build Coastguard Worker }
6624*03ce13f7SAndroid Build Coastguard Worker _br(Instr->getLabelDefault());
6625*03ce13f7SAndroid Build Coastguard Worker return;
6626*03ce13f7SAndroid Build Coastguard Worker } else {
6627*03ce13f7SAndroid Build Coastguard Worker // All the values are 32-bit so just check the operand is too and then
6628*03ce13f7SAndroid Build Coastguard Worker // fall through to the 32-bit implementation. This is a common case.
6629*03ce13f7SAndroid Build Coastguard Worker Src0Hi = legalize(Src0Hi, Legal_Reg | Legal_Mem);
6630*03ce13f7SAndroid Build Coastguard Worker Constant *Zero = Ctx->getConstantInt32(0);
6631*03ce13f7SAndroid Build Coastguard Worker _cmp(Src0Hi, Zero);
6632*03ce13f7SAndroid Build Coastguard Worker _br(CondX86::Br_ne, DefaultTarget);
6633*03ce13f7SAndroid Build Coastguard Worker Src0 = Src0Lo;
6634*03ce13f7SAndroid Build Coastguard Worker }
6635*03ce13f7SAndroid Build Coastguard Worker }
6636*03ce13f7SAndroid Build Coastguard Worker
6637*03ce13f7SAndroid Build Coastguard Worker // 32-bit lowering
6638*03ce13f7SAndroid Build Coastguard Worker
6639*03ce13f7SAndroid Build Coastguard Worker if (CaseClusters.size() == 1) {
6640*03ce13f7SAndroid Build Coastguard Worker // Jump straight to default if needed. Currently a common case as jump
6641*03ce13f7SAndroid Build Coastguard Worker // tables occur on their own.
6642*03ce13f7SAndroid Build Coastguard Worker constexpr bool DoneCmp = false;
6643*03ce13f7SAndroid Build Coastguard Worker lowerCaseCluster(CaseClusters.front(), Src0, DoneCmp, DefaultTarget);
6644*03ce13f7SAndroid Build Coastguard Worker return;
6645*03ce13f7SAndroid Build Coastguard Worker }
6646*03ce13f7SAndroid Build Coastguard Worker
6647*03ce13f7SAndroid Build Coastguard Worker // Going to be using multiple times so get it in a register early
6648*03ce13f7SAndroid Build Coastguard Worker Variable *Comparison = legalizeToReg(Src0);
6649*03ce13f7SAndroid Build Coastguard Worker
6650*03ce13f7SAndroid Build Coastguard Worker // A span is over the clusters
6651*03ce13f7SAndroid Build Coastguard Worker struct SearchSpan {
6652*03ce13f7SAndroid Build Coastguard Worker SearchSpan(SizeT Begin, SizeT Size, InstX86Label *Label)
6653*03ce13f7SAndroid Build Coastguard Worker : Begin(Begin), Size(Size), Label(Label) {}
6654*03ce13f7SAndroid Build Coastguard Worker
6655*03ce13f7SAndroid Build Coastguard Worker SizeT Begin;
6656*03ce13f7SAndroid Build Coastguard Worker SizeT Size;
6657*03ce13f7SAndroid Build Coastguard Worker InstX86Label *Label;
6658*03ce13f7SAndroid Build Coastguard Worker };
6659*03ce13f7SAndroid Build Coastguard Worker // The stack will only grow to the height of the tree so 12 should be plenty
6660*03ce13f7SAndroid Build Coastguard Worker std::stack<SearchSpan, llvm::SmallVector<SearchSpan, 12>> SearchSpanStack;
6661*03ce13f7SAndroid Build Coastguard Worker SearchSpanStack.emplace(0, CaseClusters.size(), nullptr);
6662*03ce13f7SAndroid Build Coastguard Worker bool DoneCmp = false;
6663*03ce13f7SAndroid Build Coastguard Worker
6664*03ce13f7SAndroid Build Coastguard Worker while (!SearchSpanStack.empty()) {
6665*03ce13f7SAndroid Build Coastguard Worker SearchSpan Span = SearchSpanStack.top();
6666*03ce13f7SAndroid Build Coastguard Worker SearchSpanStack.pop();
6667*03ce13f7SAndroid Build Coastguard Worker
6668*03ce13f7SAndroid Build Coastguard Worker if (Span.Label != nullptr)
6669*03ce13f7SAndroid Build Coastguard Worker Context.insert(Span.Label);
6670*03ce13f7SAndroid Build Coastguard Worker
6671*03ce13f7SAndroid Build Coastguard Worker switch (Span.Size) {
6672*03ce13f7SAndroid Build Coastguard Worker case 0:
6673*03ce13f7SAndroid Build Coastguard Worker llvm::report_fatal_error("Invalid SearchSpan size");
6674*03ce13f7SAndroid Build Coastguard Worker break;
6675*03ce13f7SAndroid Build Coastguard Worker
6676*03ce13f7SAndroid Build Coastguard Worker case 1:
6677*03ce13f7SAndroid Build Coastguard Worker lowerCaseCluster(CaseClusters[Span.Begin], Comparison, DoneCmp,
6678*03ce13f7SAndroid Build Coastguard Worker SearchSpanStack.empty() ? nullptr : DefaultTarget);
6679*03ce13f7SAndroid Build Coastguard Worker DoneCmp = false;
6680*03ce13f7SAndroid Build Coastguard Worker break;
6681*03ce13f7SAndroid Build Coastguard Worker
6682*03ce13f7SAndroid Build Coastguard Worker case 2: {
6683*03ce13f7SAndroid Build Coastguard Worker const CaseCluster *CaseA = &CaseClusters[Span.Begin];
6684*03ce13f7SAndroid Build Coastguard Worker const CaseCluster *CaseB = &CaseClusters[Span.Begin + 1];
6685*03ce13f7SAndroid Build Coastguard Worker
6686*03ce13f7SAndroid Build Coastguard Worker // Placing a range last may allow register clobbering during the range
6687*03ce13f7SAndroid Build Coastguard Worker // test. That means there is no need to clone the register. If it is a
6688*03ce13f7SAndroid Build Coastguard Worker // unit range the comparison may have already been done in the binary
6689*03ce13f7SAndroid Build Coastguard Worker // search (DoneCmp) and so it should be placed first. If this is a range
6690*03ce13f7SAndroid Build Coastguard Worker // of two items and the comparison with the low value has already been
6691*03ce13f7SAndroid Build Coastguard Worker // done, comparing with the other element is cheaper than a range test.
6692*03ce13f7SAndroid Build Coastguard Worker // If the low end of the range is zero then there is no subtraction and
6693*03ce13f7SAndroid Build Coastguard Worker // nothing to be gained.
6694*03ce13f7SAndroid Build Coastguard Worker if (!CaseA->isUnitRange() &&
6695*03ce13f7SAndroid Build Coastguard Worker !(CaseA->getLow() == 0 || (DoneCmp && CaseA->isPairRange()))) {
6696*03ce13f7SAndroid Build Coastguard Worker std::swap(CaseA, CaseB);
6697*03ce13f7SAndroid Build Coastguard Worker DoneCmp = false;
6698*03ce13f7SAndroid Build Coastguard Worker }
6699*03ce13f7SAndroid Build Coastguard Worker
6700*03ce13f7SAndroid Build Coastguard Worker lowerCaseCluster(*CaseA, Comparison, DoneCmp);
6701*03ce13f7SAndroid Build Coastguard Worker DoneCmp = false;
6702*03ce13f7SAndroid Build Coastguard Worker lowerCaseCluster(*CaseB, Comparison, DoneCmp,
6703*03ce13f7SAndroid Build Coastguard Worker SearchSpanStack.empty() ? nullptr : DefaultTarget);
6704*03ce13f7SAndroid Build Coastguard Worker } break;
6705*03ce13f7SAndroid Build Coastguard Worker
6706*03ce13f7SAndroid Build Coastguard Worker default:
6707*03ce13f7SAndroid Build Coastguard Worker // Pick the middle item and branch b or ae
6708*03ce13f7SAndroid Build Coastguard Worker SizeT PivotIndex = Span.Begin + (Span.Size / 2);
6709*03ce13f7SAndroid Build Coastguard Worker const CaseCluster &Pivot = CaseClusters[PivotIndex];
6710*03ce13f7SAndroid Build Coastguard Worker Constant *Value = Ctx->getConstantInt32(Pivot.getLow());
6711*03ce13f7SAndroid Build Coastguard Worker InstX86Label *Label = InstX86Label::create(Func, this);
6712*03ce13f7SAndroid Build Coastguard Worker _cmp(Comparison, Value);
6713*03ce13f7SAndroid Build Coastguard Worker // TODO(ascull): does it alway have to be far?
6714*03ce13f7SAndroid Build Coastguard Worker _br(CondX86::Br_b, Label, InstX86Br::Far);
6715*03ce13f7SAndroid Build Coastguard Worker // Lower the left and (pivot+right) sides, falling through to the right
6716*03ce13f7SAndroid Build Coastguard Worker SearchSpanStack.emplace(Span.Begin, Span.Size / 2, Label);
6717*03ce13f7SAndroid Build Coastguard Worker SearchSpanStack.emplace(PivotIndex, Span.Size - (Span.Size / 2), nullptr);
6718*03ce13f7SAndroid Build Coastguard Worker DoneCmp = true;
6719*03ce13f7SAndroid Build Coastguard Worker break;
6720*03ce13f7SAndroid Build Coastguard Worker }
6721*03ce13f7SAndroid Build Coastguard Worker }
6722*03ce13f7SAndroid Build Coastguard Worker
6723*03ce13f7SAndroid Build Coastguard Worker _br(DefaultTarget);
6724*03ce13f7SAndroid Build Coastguard Worker }
6725*03ce13f7SAndroid Build Coastguard Worker
6726*03ce13f7SAndroid Build Coastguard Worker /// The following pattern occurs often in lowered C and C++ code:
6727*03ce13f7SAndroid Build Coastguard Worker ///
6728*03ce13f7SAndroid Build Coastguard Worker /// %cmp = fcmp/icmp pred <n x ty> %src0, %src1
6729*03ce13f7SAndroid Build Coastguard Worker /// %cmp.ext = sext <n x i1> %cmp to <n x ty>
6730*03ce13f7SAndroid Build Coastguard Worker ///
6731*03ce13f7SAndroid Build Coastguard Worker /// We can eliminate the sext operation by copying the result of pcmpeqd,
6732*03ce13f7SAndroid Build Coastguard Worker /// pcmpgtd, or cmpps (which produce sign extended results) to the result of
6733*03ce13f7SAndroid Build Coastguard Worker /// the sext operation.
6734*03ce13f7SAndroid Build Coastguard Worker
eliminateNextVectorSextInstruction(Variable * SignExtendedResult)6735*03ce13f7SAndroid Build Coastguard Worker void TargetX8632::eliminateNextVectorSextInstruction(
6736*03ce13f7SAndroid Build Coastguard Worker Variable *SignExtendedResult) {
6737*03ce13f7SAndroid Build Coastguard Worker if (auto *NextCast =
6738*03ce13f7SAndroid Build Coastguard Worker llvm::dyn_cast_or_null<InstCast>(Context.getNextInst())) {
6739*03ce13f7SAndroid Build Coastguard Worker if (NextCast->getCastKind() == InstCast::Sext &&
6740*03ce13f7SAndroid Build Coastguard Worker NextCast->getSrc(0) == SignExtendedResult) {
6741*03ce13f7SAndroid Build Coastguard Worker NextCast->setDeleted();
6742*03ce13f7SAndroid Build Coastguard Worker _movp(NextCast->getDest(), legalizeToReg(SignExtendedResult));
6743*03ce13f7SAndroid Build Coastguard Worker // Skip over the instruction.
6744*03ce13f7SAndroid Build Coastguard Worker Context.advanceNext();
6745*03ce13f7SAndroid Build Coastguard Worker }
6746*03ce13f7SAndroid Build Coastguard Worker }
6747*03ce13f7SAndroid Build Coastguard Worker }
6748*03ce13f7SAndroid Build Coastguard Worker
lowerUnreachable(const InstUnreachable *)6749*03ce13f7SAndroid Build Coastguard Worker void TargetX8632::lowerUnreachable(const InstUnreachable * /*Instr*/) {
6750*03ce13f7SAndroid Build Coastguard Worker _ud2();
6751*03ce13f7SAndroid Build Coastguard Worker // Add a fake use of esp to make sure esp adjustments after the unreachable
6752*03ce13f7SAndroid Build Coastguard Worker // do not get dead-code eliminated.
6753*03ce13f7SAndroid Build Coastguard Worker keepEspLiveAtExit();
6754*03ce13f7SAndroid Build Coastguard Worker }
6755*03ce13f7SAndroid Build Coastguard Worker
lowerBreakpoint(const InstBreakpoint *)6756*03ce13f7SAndroid Build Coastguard Worker void TargetX8632::lowerBreakpoint(const InstBreakpoint * /*Instr*/) { _int3(); }
6757*03ce13f7SAndroid Build Coastguard Worker
lowerRMW(const InstX86FakeRMW * RMW)6758*03ce13f7SAndroid Build Coastguard Worker void TargetX8632::lowerRMW(const InstX86FakeRMW *RMW) {
6759*03ce13f7SAndroid Build Coastguard Worker // If the beacon variable's live range does not end in this instruction,
6760*03ce13f7SAndroid Build Coastguard Worker // then it must end in the modified Store instruction that follows. This
6761*03ce13f7SAndroid Build Coastguard Worker // means that the original Store instruction is still there, either because
6762*03ce13f7SAndroid Build Coastguard Worker // the value being stored is used beyond the Store instruction, or because
6763*03ce13f7SAndroid Build Coastguard Worker // dead code elimination did not happen. In either case, we cancel RMW
6764*03ce13f7SAndroid Build Coastguard Worker // lowering (and the caller deletes the RMW instruction).
6765*03ce13f7SAndroid Build Coastguard Worker if (!RMW->isLastUse(RMW->getBeacon()))
6766*03ce13f7SAndroid Build Coastguard Worker return;
6767*03ce13f7SAndroid Build Coastguard Worker Operand *Src = RMW->getData();
6768*03ce13f7SAndroid Build Coastguard Worker Type Ty = Src->getType();
6769*03ce13f7SAndroid Build Coastguard Worker X86OperandMem *Addr = formMemoryOperand(RMW->getAddr(), Ty);
6770*03ce13f7SAndroid Build Coastguard Worker doMockBoundsCheck(Addr);
6771*03ce13f7SAndroid Build Coastguard Worker if (Ty == IceType_i64) {
6772*03ce13f7SAndroid Build Coastguard Worker Src = legalizeUndef(Src);
6773*03ce13f7SAndroid Build Coastguard Worker Operand *SrcLo = legalize(loOperand(Src), Legal_Reg | Legal_Imm);
6774*03ce13f7SAndroid Build Coastguard Worker Operand *SrcHi = legalize(hiOperand(Src), Legal_Reg | Legal_Imm);
6775*03ce13f7SAndroid Build Coastguard Worker auto *AddrLo = llvm::cast<X86OperandMem>(loOperand(Addr));
6776*03ce13f7SAndroid Build Coastguard Worker auto *AddrHi = llvm::cast<X86OperandMem>(hiOperand(Addr));
6777*03ce13f7SAndroid Build Coastguard Worker switch (RMW->getOp()) {
6778*03ce13f7SAndroid Build Coastguard Worker default:
6779*03ce13f7SAndroid Build Coastguard Worker // TODO(stichnot): Implement other arithmetic operators.
6780*03ce13f7SAndroid Build Coastguard Worker break;
6781*03ce13f7SAndroid Build Coastguard Worker case InstArithmetic::Add:
6782*03ce13f7SAndroid Build Coastguard Worker _add_rmw(AddrLo, SrcLo);
6783*03ce13f7SAndroid Build Coastguard Worker _adc_rmw(AddrHi, SrcHi);
6784*03ce13f7SAndroid Build Coastguard Worker return;
6785*03ce13f7SAndroid Build Coastguard Worker case InstArithmetic::Sub:
6786*03ce13f7SAndroid Build Coastguard Worker _sub_rmw(AddrLo, SrcLo);
6787*03ce13f7SAndroid Build Coastguard Worker _sbb_rmw(AddrHi, SrcHi);
6788*03ce13f7SAndroid Build Coastguard Worker return;
6789*03ce13f7SAndroid Build Coastguard Worker case InstArithmetic::And:
6790*03ce13f7SAndroid Build Coastguard Worker _and_rmw(AddrLo, SrcLo);
6791*03ce13f7SAndroid Build Coastguard Worker _and_rmw(AddrHi, SrcHi);
6792*03ce13f7SAndroid Build Coastguard Worker return;
6793*03ce13f7SAndroid Build Coastguard Worker case InstArithmetic::Or:
6794*03ce13f7SAndroid Build Coastguard Worker _or_rmw(AddrLo, SrcLo);
6795*03ce13f7SAndroid Build Coastguard Worker _or_rmw(AddrHi, SrcHi);
6796*03ce13f7SAndroid Build Coastguard Worker return;
6797*03ce13f7SAndroid Build Coastguard Worker case InstArithmetic::Xor:
6798*03ce13f7SAndroid Build Coastguard Worker _xor_rmw(AddrLo, SrcLo);
6799*03ce13f7SAndroid Build Coastguard Worker _xor_rmw(AddrHi, SrcHi);
6800*03ce13f7SAndroid Build Coastguard Worker return;
6801*03ce13f7SAndroid Build Coastguard Worker }
6802*03ce13f7SAndroid Build Coastguard Worker } else {
6803*03ce13f7SAndroid Build Coastguard Worker // x86-32: i8, i16, i32
6804*03ce13f7SAndroid Build Coastguard Worker // x86-64: i8, i16, i32, i64
6805*03ce13f7SAndroid Build Coastguard Worker switch (RMW->getOp()) {
6806*03ce13f7SAndroid Build Coastguard Worker default:
6807*03ce13f7SAndroid Build Coastguard Worker // TODO(stichnot): Implement other arithmetic operators.
6808*03ce13f7SAndroid Build Coastguard Worker break;
6809*03ce13f7SAndroid Build Coastguard Worker case InstArithmetic::Add:
6810*03ce13f7SAndroid Build Coastguard Worker Src = legalize(Src, Legal_Reg | Legal_Imm);
6811*03ce13f7SAndroid Build Coastguard Worker _add_rmw(Addr, Src);
6812*03ce13f7SAndroid Build Coastguard Worker return;
6813*03ce13f7SAndroid Build Coastguard Worker case InstArithmetic::Sub:
6814*03ce13f7SAndroid Build Coastguard Worker Src = legalize(Src, Legal_Reg | Legal_Imm);
6815*03ce13f7SAndroid Build Coastguard Worker _sub_rmw(Addr, Src);
6816*03ce13f7SAndroid Build Coastguard Worker return;
6817*03ce13f7SAndroid Build Coastguard Worker case InstArithmetic::And:
6818*03ce13f7SAndroid Build Coastguard Worker Src = legalize(Src, Legal_Reg | Legal_Imm);
6819*03ce13f7SAndroid Build Coastguard Worker _and_rmw(Addr, Src);
6820*03ce13f7SAndroid Build Coastguard Worker return;
6821*03ce13f7SAndroid Build Coastguard Worker case InstArithmetic::Or:
6822*03ce13f7SAndroid Build Coastguard Worker Src = legalize(Src, Legal_Reg | Legal_Imm);
6823*03ce13f7SAndroid Build Coastguard Worker _or_rmw(Addr, Src);
6824*03ce13f7SAndroid Build Coastguard Worker return;
6825*03ce13f7SAndroid Build Coastguard Worker case InstArithmetic::Xor:
6826*03ce13f7SAndroid Build Coastguard Worker Src = legalize(Src, Legal_Reg | Legal_Imm);
6827*03ce13f7SAndroid Build Coastguard Worker _xor_rmw(Addr, Src);
6828*03ce13f7SAndroid Build Coastguard Worker return;
6829*03ce13f7SAndroid Build Coastguard Worker }
6830*03ce13f7SAndroid Build Coastguard Worker }
6831*03ce13f7SAndroid Build Coastguard Worker llvm::report_fatal_error("Couldn't lower RMW instruction");
6832*03ce13f7SAndroid Build Coastguard Worker }
6833*03ce13f7SAndroid Build Coastguard Worker
lowerOther(const Inst * Instr)6834*03ce13f7SAndroid Build Coastguard Worker void TargetX8632::lowerOther(const Inst *Instr) {
6835*03ce13f7SAndroid Build Coastguard Worker if (const auto *RMW = llvm::dyn_cast<InstX86FakeRMW>(Instr)) {
6836*03ce13f7SAndroid Build Coastguard Worker lowerRMW(RMW);
6837*03ce13f7SAndroid Build Coastguard Worker } else {
6838*03ce13f7SAndroid Build Coastguard Worker TargetLowering::lowerOther(Instr);
6839*03ce13f7SAndroid Build Coastguard Worker }
6840*03ce13f7SAndroid Build Coastguard Worker }
6841*03ce13f7SAndroid Build Coastguard Worker
6842*03ce13f7SAndroid Build Coastguard Worker /// Turn an i64 Phi instruction into a pair of i32 Phi instructions, to
6843*03ce13f7SAndroid Build Coastguard Worker /// preserve integrity of liveness analysis. Undef values are also turned into
6844*03ce13f7SAndroid Build Coastguard Worker /// zeroes, since loOperand() and hiOperand() don't expect Undef input.
prelowerPhis()6845*03ce13f7SAndroid Build Coastguard Worker void TargetX8632::prelowerPhis() {
6846*03ce13f7SAndroid Build Coastguard Worker PhiLowering::prelowerPhis32Bit<TargetX8632>(this, Context.getNode(), Func);
6847*03ce13f7SAndroid Build Coastguard Worker }
6848*03ce13f7SAndroid Build Coastguard Worker
genTargetHelperCallFor(Inst * Instr)6849*03ce13f7SAndroid Build Coastguard Worker void TargetX8632::genTargetHelperCallFor(Inst *Instr) {
6850*03ce13f7SAndroid Build Coastguard Worker uint32_t StackArgumentsSize = 0;
6851*03ce13f7SAndroid Build Coastguard Worker if (auto *Arith = llvm::dyn_cast<InstArithmetic>(Instr)) {
6852*03ce13f7SAndroid Build Coastguard Worker RuntimeHelper HelperID = RuntimeHelper::H_Num;
6853*03ce13f7SAndroid Build Coastguard Worker Variable *Dest = Arith->getDest();
6854*03ce13f7SAndroid Build Coastguard Worker Type DestTy = Dest->getType();
6855*03ce13f7SAndroid Build Coastguard Worker if (DestTy == IceType_i64) {
6856*03ce13f7SAndroid Build Coastguard Worker switch (Arith->getOp()) {
6857*03ce13f7SAndroid Build Coastguard Worker default:
6858*03ce13f7SAndroid Build Coastguard Worker return;
6859*03ce13f7SAndroid Build Coastguard Worker case InstArithmetic::Udiv:
6860*03ce13f7SAndroid Build Coastguard Worker HelperID = RuntimeHelper::H_udiv_i64;
6861*03ce13f7SAndroid Build Coastguard Worker break;
6862*03ce13f7SAndroid Build Coastguard Worker case InstArithmetic::Sdiv:
6863*03ce13f7SAndroid Build Coastguard Worker HelperID = RuntimeHelper::H_sdiv_i64;
6864*03ce13f7SAndroid Build Coastguard Worker break;
6865*03ce13f7SAndroid Build Coastguard Worker case InstArithmetic::Urem:
6866*03ce13f7SAndroid Build Coastguard Worker HelperID = RuntimeHelper::H_urem_i64;
6867*03ce13f7SAndroid Build Coastguard Worker break;
6868*03ce13f7SAndroid Build Coastguard Worker case InstArithmetic::Srem:
6869*03ce13f7SAndroid Build Coastguard Worker HelperID = RuntimeHelper::H_srem_i64;
6870*03ce13f7SAndroid Build Coastguard Worker break;
6871*03ce13f7SAndroid Build Coastguard Worker }
6872*03ce13f7SAndroid Build Coastguard Worker } else if (isVectorType(DestTy)) {
6873*03ce13f7SAndroid Build Coastguard Worker Variable *Dest = Arith->getDest();
6874*03ce13f7SAndroid Build Coastguard Worker Operand *Src0 = Arith->getSrc(0);
6875*03ce13f7SAndroid Build Coastguard Worker Operand *Src1 = Arith->getSrc(1);
6876*03ce13f7SAndroid Build Coastguard Worker switch (Arith->getOp()) {
6877*03ce13f7SAndroid Build Coastguard Worker default:
6878*03ce13f7SAndroid Build Coastguard Worker return;
6879*03ce13f7SAndroid Build Coastguard Worker case InstArithmetic::Mul:
6880*03ce13f7SAndroid Build Coastguard Worker if (DestTy == IceType_v16i8) {
6881*03ce13f7SAndroid Build Coastguard Worker scalarizeArithmetic(Arith->getOp(), Dest, Src0, Src1);
6882*03ce13f7SAndroid Build Coastguard Worker Arith->setDeleted();
6883*03ce13f7SAndroid Build Coastguard Worker }
6884*03ce13f7SAndroid Build Coastguard Worker return;
6885*03ce13f7SAndroid Build Coastguard Worker case InstArithmetic::Shl:
6886*03ce13f7SAndroid Build Coastguard Worker case InstArithmetic::Lshr:
6887*03ce13f7SAndroid Build Coastguard Worker case InstArithmetic::Ashr:
6888*03ce13f7SAndroid Build Coastguard Worker if (llvm::isa<Constant>(Src1)) {
6889*03ce13f7SAndroid Build Coastguard Worker return;
6890*03ce13f7SAndroid Build Coastguard Worker }
6891*03ce13f7SAndroid Build Coastguard Worker case InstArithmetic::Udiv:
6892*03ce13f7SAndroid Build Coastguard Worker case InstArithmetic::Urem:
6893*03ce13f7SAndroid Build Coastguard Worker case InstArithmetic::Sdiv:
6894*03ce13f7SAndroid Build Coastguard Worker case InstArithmetic::Srem:
6895*03ce13f7SAndroid Build Coastguard Worker case InstArithmetic::Frem:
6896*03ce13f7SAndroid Build Coastguard Worker scalarizeArithmetic(Arith->getOp(), Dest, Src0, Src1);
6897*03ce13f7SAndroid Build Coastguard Worker Arith->setDeleted();
6898*03ce13f7SAndroid Build Coastguard Worker return;
6899*03ce13f7SAndroid Build Coastguard Worker }
6900*03ce13f7SAndroid Build Coastguard Worker } else {
6901*03ce13f7SAndroid Build Coastguard Worker switch (Arith->getOp()) {
6902*03ce13f7SAndroid Build Coastguard Worker default:
6903*03ce13f7SAndroid Build Coastguard Worker return;
6904*03ce13f7SAndroid Build Coastguard Worker case InstArithmetic::Frem:
6905*03ce13f7SAndroid Build Coastguard Worker if (isFloat32Asserting32Or64(DestTy))
6906*03ce13f7SAndroid Build Coastguard Worker HelperID = RuntimeHelper::H_frem_f32;
6907*03ce13f7SAndroid Build Coastguard Worker else
6908*03ce13f7SAndroid Build Coastguard Worker HelperID = RuntimeHelper::H_frem_f64;
6909*03ce13f7SAndroid Build Coastguard Worker }
6910*03ce13f7SAndroid Build Coastguard Worker }
6911*03ce13f7SAndroid Build Coastguard Worker constexpr SizeT MaxSrcs = 2;
6912*03ce13f7SAndroid Build Coastguard Worker InstCall *Call = makeHelperCall(HelperID, Dest, MaxSrcs);
6913*03ce13f7SAndroid Build Coastguard Worker Call->addArg(Arith->getSrc(0));
6914*03ce13f7SAndroid Build Coastguard Worker Call->addArg(Arith->getSrc(1));
6915*03ce13f7SAndroid Build Coastguard Worker StackArgumentsSize = getCallStackArgumentsSizeBytes(Call);
6916*03ce13f7SAndroid Build Coastguard Worker Context.insert(Call);
6917*03ce13f7SAndroid Build Coastguard Worker Arith->setDeleted();
6918*03ce13f7SAndroid Build Coastguard Worker } else if (auto *Cast = llvm::dyn_cast<InstCast>(Instr)) {
6919*03ce13f7SAndroid Build Coastguard Worker InstCast::OpKind CastKind = Cast->getCastKind();
6920*03ce13f7SAndroid Build Coastguard Worker Operand *Src0 = Cast->getSrc(0);
6921*03ce13f7SAndroid Build Coastguard Worker const Type SrcType = Src0->getType();
6922*03ce13f7SAndroid Build Coastguard Worker Variable *Dest = Cast->getDest();
6923*03ce13f7SAndroid Build Coastguard Worker const Type DestTy = Dest->getType();
6924*03ce13f7SAndroid Build Coastguard Worker RuntimeHelper HelperID = RuntimeHelper::H_Num;
6925*03ce13f7SAndroid Build Coastguard Worker Variable *CallDest = Dest;
6926*03ce13f7SAndroid Build Coastguard Worker switch (CastKind) {
6927*03ce13f7SAndroid Build Coastguard Worker default:
6928*03ce13f7SAndroid Build Coastguard Worker return;
6929*03ce13f7SAndroid Build Coastguard Worker case InstCast::Fptosi:
6930*03ce13f7SAndroid Build Coastguard Worker if (DestTy == IceType_i64) {
6931*03ce13f7SAndroid Build Coastguard Worker HelperID = isFloat32Asserting32Or64(SrcType)
6932*03ce13f7SAndroid Build Coastguard Worker ? RuntimeHelper::H_fptosi_f32_i64
6933*03ce13f7SAndroid Build Coastguard Worker : RuntimeHelper::H_fptosi_f64_i64;
6934*03ce13f7SAndroid Build Coastguard Worker } else {
6935*03ce13f7SAndroid Build Coastguard Worker return;
6936*03ce13f7SAndroid Build Coastguard Worker }
6937*03ce13f7SAndroid Build Coastguard Worker break;
6938*03ce13f7SAndroid Build Coastguard Worker case InstCast::Fptoui:
6939*03ce13f7SAndroid Build Coastguard Worker if (isVectorType(DestTy)) {
6940*03ce13f7SAndroid Build Coastguard Worker assert(DestTy == IceType_v4i32);
6941*03ce13f7SAndroid Build Coastguard Worker assert(SrcType == IceType_v4f32);
6942*03ce13f7SAndroid Build Coastguard Worker HelperID = RuntimeHelper::H_fptoui_4xi32_f32;
6943*03ce13f7SAndroid Build Coastguard Worker } else if (DestTy == IceType_i64 || DestTy == IceType_i32) {
6944*03ce13f7SAndroid Build Coastguard Worker if (isInt32Asserting32Or64(DestTy)) {
6945*03ce13f7SAndroid Build Coastguard Worker HelperID = isFloat32Asserting32Or64(SrcType)
6946*03ce13f7SAndroid Build Coastguard Worker ? RuntimeHelper::H_fptoui_f32_i32
6947*03ce13f7SAndroid Build Coastguard Worker : RuntimeHelper::H_fptoui_f64_i32;
6948*03ce13f7SAndroid Build Coastguard Worker } else {
6949*03ce13f7SAndroid Build Coastguard Worker HelperID = isFloat32Asserting32Or64(SrcType)
6950*03ce13f7SAndroid Build Coastguard Worker ? RuntimeHelper::H_fptoui_f32_i64
6951*03ce13f7SAndroid Build Coastguard Worker : RuntimeHelper::H_fptoui_f64_i64;
6952*03ce13f7SAndroid Build Coastguard Worker }
6953*03ce13f7SAndroid Build Coastguard Worker } else {
6954*03ce13f7SAndroid Build Coastguard Worker return;
6955*03ce13f7SAndroid Build Coastguard Worker }
6956*03ce13f7SAndroid Build Coastguard Worker break;
6957*03ce13f7SAndroid Build Coastguard Worker case InstCast::Sitofp:
6958*03ce13f7SAndroid Build Coastguard Worker if (SrcType == IceType_i64) {
6959*03ce13f7SAndroid Build Coastguard Worker HelperID = isFloat32Asserting32Or64(DestTy)
6960*03ce13f7SAndroid Build Coastguard Worker ? RuntimeHelper::H_sitofp_i64_f32
6961*03ce13f7SAndroid Build Coastguard Worker : RuntimeHelper::H_sitofp_i64_f64;
6962*03ce13f7SAndroid Build Coastguard Worker } else {
6963*03ce13f7SAndroid Build Coastguard Worker return;
6964*03ce13f7SAndroid Build Coastguard Worker }
6965*03ce13f7SAndroid Build Coastguard Worker break;
6966*03ce13f7SAndroid Build Coastguard Worker case InstCast::Uitofp:
6967*03ce13f7SAndroid Build Coastguard Worker if (isVectorType(SrcType)) {
6968*03ce13f7SAndroid Build Coastguard Worker assert(DestTy == IceType_v4f32);
6969*03ce13f7SAndroid Build Coastguard Worker assert(SrcType == IceType_v4i32);
6970*03ce13f7SAndroid Build Coastguard Worker HelperID = RuntimeHelper::H_uitofp_4xi32_4xf32;
6971*03ce13f7SAndroid Build Coastguard Worker } else if (SrcType == IceType_i64 || SrcType == IceType_i32) {
6972*03ce13f7SAndroid Build Coastguard Worker if (isInt32Asserting32Or64(SrcType)) {
6973*03ce13f7SAndroid Build Coastguard Worker HelperID = isFloat32Asserting32Or64(DestTy)
6974*03ce13f7SAndroid Build Coastguard Worker ? RuntimeHelper::H_uitofp_i32_f32
6975*03ce13f7SAndroid Build Coastguard Worker : RuntimeHelper::H_uitofp_i32_f64;
6976*03ce13f7SAndroid Build Coastguard Worker } else {
6977*03ce13f7SAndroid Build Coastguard Worker HelperID = isFloat32Asserting32Or64(DestTy)
6978*03ce13f7SAndroid Build Coastguard Worker ? RuntimeHelper::H_uitofp_i64_f32
6979*03ce13f7SAndroid Build Coastguard Worker : RuntimeHelper::H_uitofp_i64_f64;
6980*03ce13f7SAndroid Build Coastguard Worker }
6981*03ce13f7SAndroid Build Coastguard Worker } else {
6982*03ce13f7SAndroid Build Coastguard Worker return;
6983*03ce13f7SAndroid Build Coastguard Worker }
6984*03ce13f7SAndroid Build Coastguard Worker break;
6985*03ce13f7SAndroid Build Coastguard Worker case InstCast::Bitcast: {
6986*03ce13f7SAndroid Build Coastguard Worker if (DestTy == Src0->getType())
6987*03ce13f7SAndroid Build Coastguard Worker return;
6988*03ce13f7SAndroid Build Coastguard Worker switch (DestTy) {
6989*03ce13f7SAndroid Build Coastguard Worker default:
6990*03ce13f7SAndroid Build Coastguard Worker return;
6991*03ce13f7SAndroid Build Coastguard Worker case IceType_i8:
6992*03ce13f7SAndroid Build Coastguard Worker assert(Src0->getType() == IceType_v8i1);
6993*03ce13f7SAndroid Build Coastguard Worker HelperID = RuntimeHelper::H_bitcast_8xi1_i8;
6994*03ce13f7SAndroid Build Coastguard Worker CallDest = Func->makeVariable(IceType_i32);
6995*03ce13f7SAndroid Build Coastguard Worker break;
6996*03ce13f7SAndroid Build Coastguard Worker case IceType_i16:
6997*03ce13f7SAndroid Build Coastguard Worker assert(Src0->getType() == IceType_v16i1);
6998*03ce13f7SAndroid Build Coastguard Worker HelperID = RuntimeHelper::H_bitcast_16xi1_i16;
6999*03ce13f7SAndroid Build Coastguard Worker CallDest = Func->makeVariable(IceType_i32);
7000*03ce13f7SAndroid Build Coastguard Worker break;
7001*03ce13f7SAndroid Build Coastguard Worker case IceType_v8i1: {
7002*03ce13f7SAndroid Build Coastguard Worker assert(Src0->getType() == IceType_i8);
7003*03ce13f7SAndroid Build Coastguard Worker HelperID = RuntimeHelper::H_bitcast_i8_8xi1;
7004*03ce13f7SAndroid Build Coastguard Worker Variable *Src0AsI32 = Func->makeVariable(stackSlotType());
7005*03ce13f7SAndroid Build Coastguard Worker // Arguments to functions are required to be at least 32 bits wide.
7006*03ce13f7SAndroid Build Coastguard Worker Context.insert<InstCast>(InstCast::Zext, Src0AsI32, Src0);
7007*03ce13f7SAndroid Build Coastguard Worker Src0 = Src0AsI32;
7008*03ce13f7SAndroid Build Coastguard Worker } break;
7009*03ce13f7SAndroid Build Coastguard Worker case IceType_v16i1: {
7010*03ce13f7SAndroid Build Coastguard Worker assert(Src0->getType() == IceType_i16);
7011*03ce13f7SAndroid Build Coastguard Worker HelperID = RuntimeHelper::H_bitcast_i16_16xi1;
7012*03ce13f7SAndroid Build Coastguard Worker Variable *Src0AsI32 = Func->makeVariable(stackSlotType());
7013*03ce13f7SAndroid Build Coastguard Worker // Arguments to functions are required to be at least 32 bits wide.
7014*03ce13f7SAndroid Build Coastguard Worker Context.insert<InstCast>(InstCast::Zext, Src0AsI32, Src0);
7015*03ce13f7SAndroid Build Coastguard Worker Src0 = Src0AsI32;
7016*03ce13f7SAndroid Build Coastguard Worker } break;
7017*03ce13f7SAndroid Build Coastguard Worker }
7018*03ce13f7SAndroid Build Coastguard Worker } break;
7019*03ce13f7SAndroid Build Coastguard Worker }
7020*03ce13f7SAndroid Build Coastguard Worker constexpr SizeT MaxSrcs = 1;
7021*03ce13f7SAndroid Build Coastguard Worker InstCall *Call = makeHelperCall(HelperID, CallDest, MaxSrcs);
7022*03ce13f7SAndroid Build Coastguard Worker Call->addArg(Src0);
7023*03ce13f7SAndroid Build Coastguard Worker StackArgumentsSize = getCallStackArgumentsSizeBytes(Call);
7024*03ce13f7SAndroid Build Coastguard Worker Context.insert(Call);
7025*03ce13f7SAndroid Build Coastguard Worker // The PNaCl ABI disallows i8/i16 return types, so truncate the helper
7026*03ce13f7SAndroid Build Coastguard Worker // call result to the appropriate type as necessary.
7027*03ce13f7SAndroid Build Coastguard Worker if (CallDest->getType() != Dest->getType())
7028*03ce13f7SAndroid Build Coastguard Worker Context.insert<InstCast>(InstCast::Trunc, Dest, CallDest);
7029*03ce13f7SAndroid Build Coastguard Worker Cast->setDeleted();
7030*03ce13f7SAndroid Build Coastguard Worker } else if (auto *Intrinsic = llvm::dyn_cast<InstIntrinsic>(Instr)) {
7031*03ce13f7SAndroid Build Coastguard Worker CfgVector<Type> ArgTypes;
7032*03ce13f7SAndroid Build Coastguard Worker Type ReturnType = IceType_void;
7033*03ce13f7SAndroid Build Coastguard Worker switch (Intrinsic->getIntrinsicID()) {
7034*03ce13f7SAndroid Build Coastguard Worker default:
7035*03ce13f7SAndroid Build Coastguard Worker return;
7036*03ce13f7SAndroid Build Coastguard Worker case Intrinsics::Ctpop: {
7037*03ce13f7SAndroid Build Coastguard Worker Operand *Val = Intrinsic->getArg(0);
7038*03ce13f7SAndroid Build Coastguard Worker Type ValTy = Val->getType();
7039*03ce13f7SAndroid Build Coastguard Worker if (ValTy == IceType_i64)
7040*03ce13f7SAndroid Build Coastguard Worker ArgTypes = {IceType_i64};
7041*03ce13f7SAndroid Build Coastguard Worker else
7042*03ce13f7SAndroid Build Coastguard Worker ArgTypes = {IceType_i32};
7043*03ce13f7SAndroid Build Coastguard Worker ReturnType = IceType_i32;
7044*03ce13f7SAndroid Build Coastguard Worker } break;
7045*03ce13f7SAndroid Build Coastguard Worker case Intrinsics::Longjmp:
7046*03ce13f7SAndroid Build Coastguard Worker ArgTypes = {IceType_i32, IceType_i32};
7047*03ce13f7SAndroid Build Coastguard Worker ReturnType = IceType_void;
7048*03ce13f7SAndroid Build Coastguard Worker break;
7049*03ce13f7SAndroid Build Coastguard Worker case Intrinsics::Memcpy:
7050*03ce13f7SAndroid Build Coastguard Worker ArgTypes = {IceType_i32, IceType_i32, IceType_i32};
7051*03ce13f7SAndroid Build Coastguard Worker ReturnType = IceType_void;
7052*03ce13f7SAndroid Build Coastguard Worker break;
7053*03ce13f7SAndroid Build Coastguard Worker case Intrinsics::Memmove:
7054*03ce13f7SAndroid Build Coastguard Worker ArgTypes = {IceType_i32, IceType_i32, IceType_i32};
7055*03ce13f7SAndroid Build Coastguard Worker ReturnType = IceType_void;
7056*03ce13f7SAndroid Build Coastguard Worker break;
7057*03ce13f7SAndroid Build Coastguard Worker case Intrinsics::Memset:
7058*03ce13f7SAndroid Build Coastguard Worker ArgTypes = {IceType_i32, IceType_i32, IceType_i32};
7059*03ce13f7SAndroid Build Coastguard Worker ReturnType = IceType_void;
7060*03ce13f7SAndroid Build Coastguard Worker break;
7061*03ce13f7SAndroid Build Coastguard Worker case Intrinsics::Setjmp:
7062*03ce13f7SAndroid Build Coastguard Worker ArgTypes = {IceType_i32};
7063*03ce13f7SAndroid Build Coastguard Worker ReturnType = IceType_i32;
7064*03ce13f7SAndroid Build Coastguard Worker break;
7065*03ce13f7SAndroid Build Coastguard Worker }
7066*03ce13f7SAndroid Build Coastguard Worker StackArgumentsSize = getCallStackArgumentsSizeBytes(ArgTypes, ReturnType);
7067*03ce13f7SAndroid Build Coastguard Worker } else if (auto *Call = llvm::dyn_cast<InstCall>(Instr)) {
7068*03ce13f7SAndroid Build Coastguard Worker StackArgumentsSize = getCallStackArgumentsSizeBytes(Call);
7069*03ce13f7SAndroid Build Coastguard Worker } else if (auto *Ret = llvm::dyn_cast<InstRet>(Instr)) {
7070*03ce13f7SAndroid Build Coastguard Worker if (!Ret->hasRetValue())
7071*03ce13f7SAndroid Build Coastguard Worker return;
7072*03ce13f7SAndroid Build Coastguard Worker Operand *RetValue = Ret->getRetValue();
7073*03ce13f7SAndroid Build Coastguard Worker Type ReturnType = RetValue->getType();
7074*03ce13f7SAndroid Build Coastguard Worker if (!isScalarFloatingType(ReturnType))
7075*03ce13f7SAndroid Build Coastguard Worker return;
7076*03ce13f7SAndroid Build Coastguard Worker StackArgumentsSize = typeWidthInBytes(ReturnType);
7077*03ce13f7SAndroid Build Coastguard Worker } else {
7078*03ce13f7SAndroid Build Coastguard Worker return;
7079*03ce13f7SAndroid Build Coastguard Worker }
7080*03ce13f7SAndroid Build Coastguard Worker StackArgumentsSize = applyStackAlignment(StackArgumentsSize);
7081*03ce13f7SAndroid Build Coastguard Worker updateMaxOutArgsSizeBytes(StackArgumentsSize);
7082*03ce13f7SAndroid Build Coastguard Worker }
7083*03ce13f7SAndroid Build Coastguard Worker
7084*03ce13f7SAndroid Build Coastguard Worker uint32_t
getCallStackArgumentsSizeBytes(const CfgVector<Type> & ArgTypes,Type ReturnType)7085*03ce13f7SAndroid Build Coastguard Worker TargetX8632::getCallStackArgumentsSizeBytes(const CfgVector<Type> &ArgTypes,
7086*03ce13f7SAndroid Build Coastguard Worker Type ReturnType) {
7087*03ce13f7SAndroid Build Coastguard Worker uint32_t OutArgumentsSizeBytes = 0;
7088*03ce13f7SAndroid Build Coastguard Worker uint32_t XmmArgCount = 0;
7089*03ce13f7SAndroid Build Coastguard Worker uint32_t GprArgCount = 0;
7090*03ce13f7SAndroid Build Coastguard Worker for (SizeT i = 0, NumArgTypes = ArgTypes.size(); i < NumArgTypes; ++i) {
7091*03ce13f7SAndroid Build Coastguard Worker Type Ty = ArgTypes[i];
7092*03ce13f7SAndroid Build Coastguard Worker // The PNaCl ABI requires the width of arguments to be at least 32 bits.
7093*03ce13f7SAndroid Build Coastguard Worker assert(typeWidthInBytes(Ty) >= 4);
7094*03ce13f7SAndroid Build Coastguard Worker if (isVectorType(Ty) &&
7095*03ce13f7SAndroid Build Coastguard Worker RegX8632::getRegisterForXmmArgNum(RegX8632::getArgIndex(i, XmmArgCount))
7096*03ce13f7SAndroid Build Coastguard Worker .hasValue()) {
7097*03ce13f7SAndroid Build Coastguard Worker ++XmmArgCount;
7098*03ce13f7SAndroid Build Coastguard Worker } else if (isScalarIntegerType(Ty) &&
7099*03ce13f7SAndroid Build Coastguard Worker RegX8632::getRegisterForGprArgNum(
7100*03ce13f7SAndroid Build Coastguard Worker Ty, RegX8632::getArgIndex(i, GprArgCount))
7101*03ce13f7SAndroid Build Coastguard Worker .hasValue()) {
7102*03ce13f7SAndroid Build Coastguard Worker // The 64 bit ABI allows some integers to be passed in GPRs.
7103*03ce13f7SAndroid Build Coastguard Worker ++GprArgCount;
7104*03ce13f7SAndroid Build Coastguard Worker } else {
7105*03ce13f7SAndroid Build Coastguard Worker if (isVectorType(Ty)) {
7106*03ce13f7SAndroid Build Coastguard Worker OutArgumentsSizeBytes = applyStackAlignment(OutArgumentsSizeBytes);
7107*03ce13f7SAndroid Build Coastguard Worker }
7108*03ce13f7SAndroid Build Coastguard Worker OutArgumentsSizeBytes += typeWidthInBytesOnStack(Ty);
7109*03ce13f7SAndroid Build Coastguard Worker }
7110*03ce13f7SAndroid Build Coastguard Worker }
7111*03ce13f7SAndroid Build Coastguard Worker // The 32 bit ABI requires floating point values to be returned on the x87
7112*03ce13f7SAndroid Build Coastguard Worker // FP stack. Ensure there is enough space for the fstp/movs for floating
7113*03ce13f7SAndroid Build Coastguard Worker // returns.
7114*03ce13f7SAndroid Build Coastguard Worker if (isScalarFloatingType(ReturnType)) {
7115*03ce13f7SAndroid Build Coastguard Worker OutArgumentsSizeBytes =
7116*03ce13f7SAndroid Build Coastguard Worker std::max(OutArgumentsSizeBytes,
7117*03ce13f7SAndroid Build Coastguard Worker static_cast<uint32_t>(typeWidthInBytesOnStack(ReturnType)));
7118*03ce13f7SAndroid Build Coastguard Worker }
7119*03ce13f7SAndroid Build Coastguard Worker return OutArgumentsSizeBytes;
7120*03ce13f7SAndroid Build Coastguard Worker }
7121*03ce13f7SAndroid Build Coastguard Worker
getCallStackArgumentsSizeBytes(const InstCall * Instr)7122*03ce13f7SAndroid Build Coastguard Worker uint32_t TargetX8632::getCallStackArgumentsSizeBytes(const InstCall *Instr) {
7123*03ce13f7SAndroid Build Coastguard Worker // Build a vector of the arguments' types.
7124*03ce13f7SAndroid Build Coastguard Worker const SizeT NumArgs = Instr->getNumArgs();
7125*03ce13f7SAndroid Build Coastguard Worker CfgVector<Type> ArgTypes;
7126*03ce13f7SAndroid Build Coastguard Worker ArgTypes.reserve(NumArgs);
7127*03ce13f7SAndroid Build Coastguard Worker for (SizeT i = 0; i < NumArgs; ++i) {
7128*03ce13f7SAndroid Build Coastguard Worker Operand *Arg = Instr->getArg(i);
7129*03ce13f7SAndroid Build Coastguard Worker ArgTypes.emplace_back(Arg->getType());
7130*03ce13f7SAndroid Build Coastguard Worker }
7131*03ce13f7SAndroid Build Coastguard Worker // Compute the return type (if any);
7132*03ce13f7SAndroid Build Coastguard Worker Type ReturnType = IceType_void;
7133*03ce13f7SAndroid Build Coastguard Worker Variable *Dest = Instr->getDest();
7134*03ce13f7SAndroid Build Coastguard Worker if (Dest != nullptr)
7135*03ce13f7SAndroid Build Coastguard Worker ReturnType = Dest->getType();
7136*03ce13f7SAndroid Build Coastguard Worker return getCallStackArgumentsSizeBytes(ArgTypes, ReturnType);
7137*03ce13f7SAndroid Build Coastguard Worker }
7138*03ce13f7SAndroid Build Coastguard Worker
makeZeroedRegister(Type Ty,RegNumT RegNum)7139*03ce13f7SAndroid Build Coastguard Worker Variable *TargetX8632::makeZeroedRegister(Type Ty, RegNumT RegNum) {
7140*03ce13f7SAndroid Build Coastguard Worker Variable *Reg = makeReg(Ty, RegNum);
7141*03ce13f7SAndroid Build Coastguard Worker switch (Ty) {
7142*03ce13f7SAndroid Build Coastguard Worker case IceType_i1:
7143*03ce13f7SAndroid Build Coastguard Worker case IceType_i8:
7144*03ce13f7SAndroid Build Coastguard Worker case IceType_i16:
7145*03ce13f7SAndroid Build Coastguard Worker case IceType_i32:
7146*03ce13f7SAndroid Build Coastguard Worker case IceType_i64:
7147*03ce13f7SAndroid Build Coastguard Worker // Conservatively do "mov reg, 0" to avoid modifying FLAGS.
7148*03ce13f7SAndroid Build Coastguard Worker _mov(Reg, Ctx->getConstantZero(Ty));
7149*03ce13f7SAndroid Build Coastguard Worker break;
7150*03ce13f7SAndroid Build Coastguard Worker case IceType_f32:
7151*03ce13f7SAndroid Build Coastguard Worker case IceType_f64:
7152*03ce13f7SAndroid Build Coastguard Worker Context.insert<InstFakeDef>(Reg);
7153*03ce13f7SAndroid Build Coastguard Worker _xorps(Reg, Reg);
7154*03ce13f7SAndroid Build Coastguard Worker break;
7155*03ce13f7SAndroid Build Coastguard Worker default:
7156*03ce13f7SAndroid Build Coastguard Worker // All vector types use the same pxor instruction.
7157*03ce13f7SAndroid Build Coastguard Worker assert(isVectorType(Ty));
7158*03ce13f7SAndroid Build Coastguard Worker Context.insert<InstFakeDef>(Reg);
7159*03ce13f7SAndroid Build Coastguard Worker _pxor(Reg, Reg);
7160*03ce13f7SAndroid Build Coastguard Worker break;
7161*03ce13f7SAndroid Build Coastguard Worker }
7162*03ce13f7SAndroid Build Coastguard Worker return Reg;
7163*03ce13f7SAndroid Build Coastguard Worker }
7164*03ce13f7SAndroid Build Coastguard Worker
7165*03ce13f7SAndroid Build Coastguard Worker // There is no support for loading or emitting vector constants, so the vector
7166*03ce13f7SAndroid Build Coastguard Worker // values returned from makeVectorOfZeros, makeVectorOfOnes, etc. are
7167*03ce13f7SAndroid Build Coastguard Worker // initialized with register operations.
7168*03ce13f7SAndroid Build Coastguard Worker //
7169*03ce13f7SAndroid Build Coastguard Worker // TODO(wala): Add limited support for vector constants so that complex
7170*03ce13f7SAndroid Build Coastguard Worker // initialization in registers is unnecessary.
7171*03ce13f7SAndroid Build Coastguard Worker
makeVectorOfZeros(Type Ty,RegNumT RegNum)7172*03ce13f7SAndroid Build Coastguard Worker Variable *TargetX8632::makeVectorOfZeros(Type Ty, RegNumT RegNum) {
7173*03ce13f7SAndroid Build Coastguard Worker return makeZeroedRegister(Ty, RegNum);
7174*03ce13f7SAndroid Build Coastguard Worker }
7175*03ce13f7SAndroid Build Coastguard Worker
makeVectorOfMinusOnes(Type Ty,RegNumT RegNum)7176*03ce13f7SAndroid Build Coastguard Worker Variable *TargetX8632::makeVectorOfMinusOnes(Type Ty, RegNumT RegNum) {
7177*03ce13f7SAndroid Build Coastguard Worker Variable *MinusOnes = makeReg(Ty, RegNum);
7178*03ce13f7SAndroid Build Coastguard Worker // Insert a FakeDef so the live range of MinusOnes is not overestimated.
7179*03ce13f7SAndroid Build Coastguard Worker Context.insert<InstFakeDef>(MinusOnes);
7180*03ce13f7SAndroid Build Coastguard Worker if (Ty == IceType_f64)
7181*03ce13f7SAndroid Build Coastguard Worker // Making a vector of minus ones of type f64 is currently only used for
7182*03ce13f7SAndroid Build Coastguard Worker // the fabs intrinsic. To use the f64 type to create this mask with
7183*03ce13f7SAndroid Build Coastguard Worker // pcmpeqq requires SSE 4.1. Since we're just creating a mask, pcmpeqd
7184*03ce13f7SAndroid Build Coastguard Worker // does the same job and only requires SSE2.
7185*03ce13f7SAndroid Build Coastguard Worker _pcmpeq(MinusOnes, MinusOnes, IceType_f32);
7186*03ce13f7SAndroid Build Coastguard Worker else
7187*03ce13f7SAndroid Build Coastguard Worker _pcmpeq(MinusOnes, MinusOnes);
7188*03ce13f7SAndroid Build Coastguard Worker return MinusOnes;
7189*03ce13f7SAndroid Build Coastguard Worker }
7190*03ce13f7SAndroid Build Coastguard Worker
makeVectorOfOnes(Type Ty,RegNumT RegNum)7191*03ce13f7SAndroid Build Coastguard Worker Variable *TargetX8632::makeVectorOfOnes(Type Ty, RegNumT RegNum) {
7192*03ce13f7SAndroid Build Coastguard Worker Variable *Dest = makeVectorOfZeros(Ty, RegNum);
7193*03ce13f7SAndroid Build Coastguard Worker Variable *MinusOne = makeVectorOfMinusOnes(Ty);
7194*03ce13f7SAndroid Build Coastguard Worker _psub(Dest, MinusOne);
7195*03ce13f7SAndroid Build Coastguard Worker return Dest;
7196*03ce13f7SAndroid Build Coastguard Worker }
7197*03ce13f7SAndroid Build Coastguard Worker
makeVectorOfHighOrderBits(Type Ty,RegNumT RegNum)7198*03ce13f7SAndroid Build Coastguard Worker Variable *TargetX8632::makeVectorOfHighOrderBits(Type Ty, RegNumT RegNum) {
7199*03ce13f7SAndroid Build Coastguard Worker assert(Ty == IceType_v4i32 || Ty == IceType_v4f32 || Ty == IceType_v8i16 ||
7200*03ce13f7SAndroid Build Coastguard Worker Ty == IceType_v16i8);
7201*03ce13f7SAndroid Build Coastguard Worker if (Ty == IceType_v4f32 || Ty == IceType_v4i32 || Ty == IceType_v8i16) {
7202*03ce13f7SAndroid Build Coastguard Worker Variable *Reg = makeVectorOfOnes(Ty, RegNum);
7203*03ce13f7SAndroid Build Coastguard Worker SizeT Shift = typeWidthInBytes(typeElementType(Ty)) * X86_CHAR_BIT - 1;
7204*03ce13f7SAndroid Build Coastguard Worker _psll(Reg, Ctx->getConstantInt8(Shift));
7205*03ce13f7SAndroid Build Coastguard Worker return Reg;
7206*03ce13f7SAndroid Build Coastguard Worker } else {
7207*03ce13f7SAndroid Build Coastguard Worker // SSE has no left shift operation for vectors of 8 bit integers.
7208*03ce13f7SAndroid Build Coastguard Worker constexpr uint32_t HIGH_ORDER_BITS_MASK = 0x80808080;
7209*03ce13f7SAndroid Build Coastguard Worker Constant *ConstantMask = Ctx->getConstantInt32(HIGH_ORDER_BITS_MASK);
7210*03ce13f7SAndroid Build Coastguard Worker Variable *Reg = makeReg(Ty, RegNum);
7211*03ce13f7SAndroid Build Coastguard Worker _movd(Reg, legalize(ConstantMask, Legal_Reg | Legal_Mem));
7212*03ce13f7SAndroid Build Coastguard Worker _pshufd(Reg, Reg, Ctx->getConstantZero(IceType_i8));
7213*03ce13f7SAndroid Build Coastguard Worker return Reg;
7214*03ce13f7SAndroid Build Coastguard Worker }
7215*03ce13f7SAndroid Build Coastguard Worker }
7216*03ce13f7SAndroid Build Coastguard Worker
7217*03ce13f7SAndroid Build Coastguard Worker /// Construct a mask in a register that can be and'ed with a floating-point
7218*03ce13f7SAndroid Build Coastguard Worker /// value to mask off its sign bit. The value will be <4 x 0x7fffffff> for f32
7219*03ce13f7SAndroid Build Coastguard Worker /// and v4f32, and <2 x 0x7fffffffffffffff> for f64. Construct it as vector of
7220*03ce13f7SAndroid Build Coastguard Worker /// ones logically right shifted one bit.
7221*03ce13f7SAndroid Build Coastguard Worker // TODO(stichnot): Fix the wala
7222*03ce13f7SAndroid Build Coastguard Worker // TODO: above, to represent vector constants in memory.
7223*03ce13f7SAndroid Build Coastguard Worker
makeVectorOfFabsMask(Type Ty,RegNumT RegNum)7224*03ce13f7SAndroid Build Coastguard Worker Variable *TargetX8632::makeVectorOfFabsMask(Type Ty, RegNumT RegNum) {
7225*03ce13f7SAndroid Build Coastguard Worker Variable *Reg = makeVectorOfMinusOnes(Ty, RegNum);
7226*03ce13f7SAndroid Build Coastguard Worker _psrl(Reg, Ctx->getConstantInt8(1));
7227*03ce13f7SAndroid Build Coastguard Worker return Reg;
7228*03ce13f7SAndroid Build Coastguard Worker }
7229*03ce13f7SAndroid Build Coastguard Worker
getMemoryOperandForStackSlot(Type Ty,Variable * Slot,uint32_t Offset)7230*03ce13f7SAndroid Build Coastguard Worker X86OperandMem *TargetX8632::getMemoryOperandForStackSlot(Type Ty,
7231*03ce13f7SAndroid Build Coastguard Worker Variable *Slot,
7232*03ce13f7SAndroid Build Coastguard Worker uint32_t Offset) {
7233*03ce13f7SAndroid Build Coastguard Worker // Ensure that Loc is a stack slot.
7234*03ce13f7SAndroid Build Coastguard Worker assert(Slot->mustNotHaveReg());
7235*03ce13f7SAndroid Build Coastguard Worker assert(Slot->getRegNum().hasNoValue());
7236*03ce13f7SAndroid Build Coastguard Worker // Compute the location of Loc in memory.
7237*03ce13f7SAndroid Build Coastguard Worker // TODO(wala,stichnot): lea should not
7238*03ce13f7SAndroid Build Coastguard Worker // be required. The address of the stack slot is known at compile time
7239*03ce13f7SAndroid Build Coastguard Worker // (although not until after addProlog()).
7240*03ce13f7SAndroid Build Coastguard Worker const Type PointerType = IceType_i32;
7241*03ce13f7SAndroid Build Coastguard Worker Variable *Loc = makeReg(PointerType);
7242*03ce13f7SAndroid Build Coastguard Worker _lea(Loc, Slot);
7243*03ce13f7SAndroid Build Coastguard Worker Constant *ConstantOffset = Ctx->getConstantInt32(Offset);
7244*03ce13f7SAndroid Build Coastguard Worker return X86OperandMem::create(Func, Ty, Loc, ConstantOffset);
7245*03ce13f7SAndroid Build Coastguard Worker }
7246*03ce13f7SAndroid Build Coastguard Worker
7247*03ce13f7SAndroid Build Coastguard Worker /// Lowering helper to copy a scalar integer source operand into some 8-bit
7248*03ce13f7SAndroid Build Coastguard Worker /// GPR. Src is assumed to already be legalized. If the source operand is
7249*03ce13f7SAndroid Build Coastguard Worker /// known to be a memory or immediate operand, a simple mov will suffice. But
7250*03ce13f7SAndroid Build Coastguard Worker /// if the source operand can be a physical register, then it must first be
7251*03ce13f7SAndroid Build Coastguard Worker /// copied into a physical register that is truncable to 8-bit, then truncated
7252*03ce13f7SAndroid Build Coastguard Worker /// into a physical register that can receive a truncation, and finally copied
7253*03ce13f7SAndroid Build Coastguard Worker /// into the result 8-bit register (which in general can be any 8-bit
7254*03ce13f7SAndroid Build Coastguard Worker /// register). For example, moving %ebp into %ah may be accomplished as:
7255*03ce13f7SAndroid Build Coastguard Worker /// movl %ebp, %edx
7256*03ce13f7SAndroid Build Coastguard Worker /// mov_trunc %edx, %dl // this redundant assignment is ultimately elided
7257*03ce13f7SAndroid Build Coastguard Worker /// movb %dl, %ah
7258*03ce13f7SAndroid Build Coastguard Worker /// On the other hand, moving a memory or immediate operand into ah:
7259*03ce13f7SAndroid Build Coastguard Worker /// movb 4(%ebp), %ah
7260*03ce13f7SAndroid Build Coastguard Worker /// movb $my_imm, %ah
7261*03ce13f7SAndroid Build Coastguard Worker ///
7262*03ce13f7SAndroid Build Coastguard Worker /// Note #1. On a 64-bit target, the "movb 4(%ebp), %ah" is likely not
7263*03ce13f7SAndroid Build Coastguard Worker /// encodable, so RegNum=Reg_ah should NOT be given as an argument. Instead,
7264*03ce13f7SAndroid Build Coastguard Worker /// use RegNum=RegNumT() and then let the caller do a separate copy into
7265*03ce13f7SAndroid Build Coastguard Worker /// Reg_ah.
7266*03ce13f7SAndroid Build Coastguard Worker ///
7267*03ce13f7SAndroid Build Coastguard Worker /// Note #2. ConstantRelocatable operands are also put through this process
7268*03ce13f7SAndroid Build Coastguard Worker /// (not truncated directly) because our ELF emitter does R_386_32 relocations
7269*03ce13f7SAndroid Build Coastguard Worker /// but not R_386_8 relocations.
7270*03ce13f7SAndroid Build Coastguard Worker ///
7271*03ce13f7SAndroid Build Coastguard Worker /// Note #3. If Src is a Variable, the result will be an infinite-weight i8
7272*03ce13f7SAndroid Build Coastguard Worker /// Variable with the RCX86_IsTrunc8Rcvr register class. As such, this helper
7273*03ce13f7SAndroid Build Coastguard Worker /// is a convenient way to prevent ah/bh/ch/dh from being an (invalid)
7274*03ce13f7SAndroid Build Coastguard Worker /// argument to the pinsrb instruction.
7275*03ce13f7SAndroid Build Coastguard Worker
copyToReg8(Operand * Src,RegNumT RegNum)7276*03ce13f7SAndroid Build Coastguard Worker Variable *TargetX8632::copyToReg8(Operand *Src, RegNumT RegNum) {
7277*03ce13f7SAndroid Build Coastguard Worker Type Ty = Src->getType();
7278*03ce13f7SAndroid Build Coastguard Worker assert(isScalarIntegerType(Ty));
7279*03ce13f7SAndroid Build Coastguard Worker assert(Ty != IceType_i1);
7280*03ce13f7SAndroid Build Coastguard Worker Variable *Reg = makeReg(IceType_i8, RegNum);
7281*03ce13f7SAndroid Build Coastguard Worker Reg->setRegClass(RCX86_IsTrunc8Rcvr);
7282*03ce13f7SAndroid Build Coastguard Worker if (llvm::isa<Variable>(Src) || llvm::isa<ConstantRelocatable>(Src)) {
7283*03ce13f7SAndroid Build Coastguard Worker Variable *SrcTruncable = makeReg(Ty);
7284*03ce13f7SAndroid Build Coastguard Worker switch (Ty) {
7285*03ce13f7SAndroid Build Coastguard Worker case IceType_i64:
7286*03ce13f7SAndroid Build Coastguard Worker SrcTruncable->setRegClass(RCX86_Is64To8);
7287*03ce13f7SAndroid Build Coastguard Worker break;
7288*03ce13f7SAndroid Build Coastguard Worker case IceType_i32:
7289*03ce13f7SAndroid Build Coastguard Worker SrcTruncable->setRegClass(RCX86_Is32To8);
7290*03ce13f7SAndroid Build Coastguard Worker break;
7291*03ce13f7SAndroid Build Coastguard Worker case IceType_i16:
7292*03ce13f7SAndroid Build Coastguard Worker SrcTruncable->setRegClass(RCX86_Is16To8);
7293*03ce13f7SAndroid Build Coastguard Worker break;
7294*03ce13f7SAndroid Build Coastguard Worker default:
7295*03ce13f7SAndroid Build Coastguard Worker // i8 - just use default register class
7296*03ce13f7SAndroid Build Coastguard Worker break;
7297*03ce13f7SAndroid Build Coastguard Worker }
7298*03ce13f7SAndroid Build Coastguard Worker Variable *SrcRcvr = makeReg(IceType_i8);
7299*03ce13f7SAndroid Build Coastguard Worker SrcRcvr->setRegClass(RCX86_IsTrunc8Rcvr);
7300*03ce13f7SAndroid Build Coastguard Worker _mov(SrcTruncable, Src);
7301*03ce13f7SAndroid Build Coastguard Worker _mov(SrcRcvr, SrcTruncable);
7302*03ce13f7SAndroid Build Coastguard Worker Src = SrcRcvr;
7303*03ce13f7SAndroid Build Coastguard Worker }
7304*03ce13f7SAndroid Build Coastguard Worker _mov(Reg, Src);
7305*03ce13f7SAndroid Build Coastguard Worker return Reg;
7306*03ce13f7SAndroid Build Coastguard Worker }
7307*03ce13f7SAndroid Build Coastguard Worker
7308*03ce13f7SAndroid Build Coastguard Worker /// Helper for legalize() to emit the right code to lower an operand to a
7309*03ce13f7SAndroid Build Coastguard Worker /// register of the appropriate type.
7310*03ce13f7SAndroid Build Coastguard Worker
copyToReg(Operand * Src,RegNumT RegNum)7311*03ce13f7SAndroid Build Coastguard Worker Variable *TargetX8632::copyToReg(Operand *Src, RegNumT RegNum) {
7312*03ce13f7SAndroid Build Coastguard Worker Type Ty = Src->getType();
7313*03ce13f7SAndroid Build Coastguard Worker Variable *Reg = makeReg(Ty, RegNum);
7314*03ce13f7SAndroid Build Coastguard Worker if (isVectorType(Ty)) {
7315*03ce13f7SAndroid Build Coastguard Worker _movp(Reg, Src);
7316*03ce13f7SAndroid Build Coastguard Worker } else {
7317*03ce13f7SAndroid Build Coastguard Worker _mov(Reg, Src);
7318*03ce13f7SAndroid Build Coastguard Worker }
7319*03ce13f7SAndroid Build Coastguard Worker return Reg;
7320*03ce13f7SAndroid Build Coastguard Worker }
7321*03ce13f7SAndroid Build Coastguard Worker
legalize(Operand * From,LegalMask Allowed,RegNumT RegNum)7322*03ce13f7SAndroid Build Coastguard Worker Operand *TargetX8632::legalize(Operand *From, LegalMask Allowed,
7323*03ce13f7SAndroid Build Coastguard Worker RegNumT RegNum) {
7324*03ce13f7SAndroid Build Coastguard Worker const Type Ty = From->getType();
7325*03ce13f7SAndroid Build Coastguard Worker // Assert that a physical register is allowed. To date, all calls to
7326*03ce13f7SAndroid Build Coastguard Worker // legalize() allow a physical register. If a physical register needs to be
7327*03ce13f7SAndroid Build Coastguard Worker // explicitly disallowed, then new code will need to be written to force a
7328*03ce13f7SAndroid Build Coastguard Worker // spill.
7329*03ce13f7SAndroid Build Coastguard Worker assert(Allowed & Legal_Reg);
7330*03ce13f7SAndroid Build Coastguard Worker // If we're asking for a specific physical register, make sure we're not
7331*03ce13f7SAndroid Build Coastguard Worker // allowing any other operand kinds. (This could be future work, e.g. allow
7332*03ce13f7SAndroid Build Coastguard Worker // the shl shift amount to be either an immediate or in ecx.)
7333*03ce13f7SAndroid Build Coastguard Worker assert(RegNum.hasNoValue() || Allowed == Legal_Reg);
7334*03ce13f7SAndroid Build Coastguard Worker
7335*03ce13f7SAndroid Build Coastguard Worker // Substitute with an available infinite-weight variable if possible. Only
7336*03ce13f7SAndroid Build Coastguard Worker // do this when we are not asking for a specific register, and when the
7337*03ce13f7SAndroid Build Coastguard Worker // substitution is not locked to a specific register, and when the types
7338*03ce13f7SAndroid Build Coastguard Worker // match, in order to capture the vast majority of opportunities and avoid
7339*03ce13f7SAndroid Build Coastguard Worker // corner cases in the lowering.
7340*03ce13f7SAndroid Build Coastguard Worker if (RegNum.hasNoValue()) {
7341*03ce13f7SAndroid Build Coastguard Worker if (Variable *Subst = getContext().availabilityGet(From)) {
7342*03ce13f7SAndroid Build Coastguard Worker // At this point we know there is a potential substitution available.
7343*03ce13f7SAndroid Build Coastguard Worker if (Subst->mustHaveReg() && !Subst->hasReg()) {
7344*03ce13f7SAndroid Build Coastguard Worker // At this point we know the substitution will have a register.
7345*03ce13f7SAndroid Build Coastguard Worker if (From->getType() == Subst->getType()) {
7346*03ce13f7SAndroid Build Coastguard Worker // At this point we know the substitution's register is compatible.
7347*03ce13f7SAndroid Build Coastguard Worker return Subst;
7348*03ce13f7SAndroid Build Coastguard Worker }
7349*03ce13f7SAndroid Build Coastguard Worker }
7350*03ce13f7SAndroid Build Coastguard Worker }
7351*03ce13f7SAndroid Build Coastguard Worker }
7352*03ce13f7SAndroid Build Coastguard Worker
7353*03ce13f7SAndroid Build Coastguard Worker if (auto *Mem = llvm::dyn_cast<X86OperandMem>(From)) {
7354*03ce13f7SAndroid Build Coastguard Worker // Before doing anything with a Mem operand, we need to ensure that the
7355*03ce13f7SAndroid Build Coastguard Worker // Base and Index components are in physical registers.
7356*03ce13f7SAndroid Build Coastguard Worker Variable *Base = Mem->getBase();
7357*03ce13f7SAndroid Build Coastguard Worker Variable *Index = Mem->getIndex();
7358*03ce13f7SAndroid Build Coastguard Worker Constant *Offset = Mem->getOffset();
7359*03ce13f7SAndroid Build Coastguard Worker Variable *RegBase = nullptr;
7360*03ce13f7SAndroid Build Coastguard Worker Variable *RegIndex = nullptr;
7361*03ce13f7SAndroid Build Coastguard Worker uint16_t Shift = Mem->getShift();
7362*03ce13f7SAndroid Build Coastguard Worker if (Base) {
7363*03ce13f7SAndroid Build Coastguard Worker RegBase = llvm::cast<Variable>(
7364*03ce13f7SAndroid Build Coastguard Worker legalize(Base, Legal_Reg | Legal_Rematerializable));
7365*03ce13f7SAndroid Build Coastguard Worker }
7366*03ce13f7SAndroid Build Coastguard Worker if (Index) {
7367*03ce13f7SAndroid Build Coastguard Worker // TODO(jpp): perhaps we should only allow Legal_Reg if
7368*03ce13f7SAndroid Build Coastguard Worker // Base->isRematerializable.
7369*03ce13f7SAndroid Build Coastguard Worker RegIndex = llvm::cast<Variable>(
7370*03ce13f7SAndroid Build Coastguard Worker legalize(Index, Legal_Reg | Legal_Rematerializable));
7371*03ce13f7SAndroid Build Coastguard Worker }
7372*03ce13f7SAndroid Build Coastguard Worker
7373*03ce13f7SAndroid Build Coastguard Worker if (Base != RegBase || Index != RegIndex) {
7374*03ce13f7SAndroid Build Coastguard Worker Mem = X86OperandMem::create(Func, Ty, RegBase, Offset, RegIndex, Shift,
7375*03ce13f7SAndroid Build Coastguard Worker Mem->getSegmentRegister());
7376*03ce13f7SAndroid Build Coastguard Worker }
7377*03ce13f7SAndroid Build Coastguard Worker
7378*03ce13f7SAndroid Build Coastguard Worker From = Mem;
7379*03ce13f7SAndroid Build Coastguard Worker
7380*03ce13f7SAndroid Build Coastguard Worker if (!(Allowed & Legal_Mem)) {
7381*03ce13f7SAndroid Build Coastguard Worker From = copyToReg(From, RegNum);
7382*03ce13f7SAndroid Build Coastguard Worker }
7383*03ce13f7SAndroid Build Coastguard Worker return From;
7384*03ce13f7SAndroid Build Coastguard Worker }
7385*03ce13f7SAndroid Build Coastguard Worker
7386*03ce13f7SAndroid Build Coastguard Worker if (auto *Const = llvm::dyn_cast<Constant>(From)) {
7387*03ce13f7SAndroid Build Coastguard Worker if (llvm::isa<ConstantUndef>(Const)) {
7388*03ce13f7SAndroid Build Coastguard Worker From = legalizeUndef(Const, RegNum);
7389*03ce13f7SAndroid Build Coastguard Worker if (isVectorType(Ty))
7390*03ce13f7SAndroid Build Coastguard Worker return From;
7391*03ce13f7SAndroid Build Coastguard Worker Const = llvm::cast<Constant>(From);
7392*03ce13f7SAndroid Build Coastguard Worker }
7393*03ce13f7SAndroid Build Coastguard Worker // There should be no constants of vector type (other than undef).
7394*03ce13f7SAndroid Build Coastguard Worker assert(!isVectorType(Ty));
7395*03ce13f7SAndroid Build Coastguard Worker
7396*03ce13f7SAndroid Build Coastguard Worker if (!llvm::dyn_cast<ConstantRelocatable>(Const)) {
7397*03ce13f7SAndroid Build Coastguard Worker if (isScalarFloatingType(Ty)) {
7398*03ce13f7SAndroid Build Coastguard Worker // Convert a scalar floating point constant into an explicit memory
7399*03ce13f7SAndroid Build Coastguard Worker // operand.
7400*03ce13f7SAndroid Build Coastguard Worker if (auto *ConstFloat = llvm::dyn_cast<ConstantFloat>(Const)) {
7401*03ce13f7SAndroid Build Coastguard Worker if (Utils::isPositiveZero(ConstFloat->getValue()))
7402*03ce13f7SAndroid Build Coastguard Worker return makeZeroedRegister(Ty, RegNum);
7403*03ce13f7SAndroid Build Coastguard Worker } else if (auto *ConstDouble = llvm::dyn_cast<ConstantDouble>(Const)) {
7404*03ce13f7SAndroid Build Coastguard Worker if (Utils::isPositiveZero(ConstDouble->getValue()))
7405*03ce13f7SAndroid Build Coastguard Worker return makeZeroedRegister(Ty, RegNum);
7406*03ce13f7SAndroid Build Coastguard Worker }
7407*03ce13f7SAndroid Build Coastguard Worker
7408*03ce13f7SAndroid Build Coastguard Worker auto *CFrom = llvm::cast<Constant>(From);
7409*03ce13f7SAndroid Build Coastguard Worker assert(CFrom->getShouldBePooled());
7410*03ce13f7SAndroid Build Coastguard Worker Constant *Offset = Ctx->getConstantSym(0, CFrom->getLabelName());
7411*03ce13f7SAndroid Build Coastguard Worker auto *Mem = X86OperandMem::create(Func, Ty, nullptr, Offset);
7412*03ce13f7SAndroid Build Coastguard Worker From = Mem;
7413*03ce13f7SAndroid Build Coastguard Worker }
7414*03ce13f7SAndroid Build Coastguard Worker }
7415*03ce13f7SAndroid Build Coastguard Worker
7416*03ce13f7SAndroid Build Coastguard Worker bool NeedsReg = false;
7417*03ce13f7SAndroid Build Coastguard Worker if (!(Allowed & Legal_Imm) && !isScalarFloatingType(Ty))
7418*03ce13f7SAndroid Build Coastguard Worker // Immediate specifically not allowed.
7419*03ce13f7SAndroid Build Coastguard Worker NeedsReg = true;
7420*03ce13f7SAndroid Build Coastguard Worker if (!(Allowed & Legal_Mem) && isScalarFloatingType(Ty))
7421*03ce13f7SAndroid Build Coastguard Worker // On x86, FP constants are lowered to mem operands.
7422*03ce13f7SAndroid Build Coastguard Worker NeedsReg = true;
7423*03ce13f7SAndroid Build Coastguard Worker if (NeedsReg) {
7424*03ce13f7SAndroid Build Coastguard Worker From = copyToReg(From, RegNum);
7425*03ce13f7SAndroid Build Coastguard Worker }
7426*03ce13f7SAndroid Build Coastguard Worker return From;
7427*03ce13f7SAndroid Build Coastguard Worker }
7428*03ce13f7SAndroid Build Coastguard Worker
7429*03ce13f7SAndroid Build Coastguard Worker if (auto *Var = llvm::dyn_cast<Variable>(From)) {
7430*03ce13f7SAndroid Build Coastguard Worker // Check if the variable is guaranteed a physical register. This can
7431*03ce13f7SAndroid Build Coastguard Worker // happen either when the variable is pre-colored or when it is assigned
7432*03ce13f7SAndroid Build Coastguard Worker // infinite weight.
7433*03ce13f7SAndroid Build Coastguard Worker bool MustHaveRegister = (Var->hasReg() || Var->mustHaveReg());
7434*03ce13f7SAndroid Build Coastguard Worker bool MustRematerialize =
7435*03ce13f7SAndroid Build Coastguard Worker (Var->isRematerializable() && !(Allowed & Legal_Rematerializable));
7436*03ce13f7SAndroid Build Coastguard Worker // We need a new physical register for the operand if:
7437*03ce13f7SAndroid Build Coastguard Worker // - Mem is not allowed and Var isn't guaranteed a physical register, or
7438*03ce13f7SAndroid Build Coastguard Worker // - RegNum is required and Var->getRegNum() doesn't match, or
7439*03ce13f7SAndroid Build Coastguard Worker // - Var is a rematerializable variable and rematerializable pass-through
7440*03ce13f7SAndroid Build Coastguard Worker // is
7441*03ce13f7SAndroid Build Coastguard Worker // not allowed (in which case we need a lea instruction).
7442*03ce13f7SAndroid Build Coastguard Worker if (MustRematerialize) {
7443*03ce13f7SAndroid Build Coastguard Worker Variable *NewVar = makeReg(Ty, RegNum);
7444*03ce13f7SAndroid Build Coastguard Worker // Since Var is rematerializable, the offset will be added when the lea
7445*03ce13f7SAndroid Build Coastguard Worker // is emitted.
7446*03ce13f7SAndroid Build Coastguard Worker constexpr Constant *NoOffset = nullptr;
7447*03ce13f7SAndroid Build Coastguard Worker auto *Mem = X86OperandMem::create(Func, Ty, Var, NoOffset);
7448*03ce13f7SAndroid Build Coastguard Worker _lea(NewVar, Mem);
7449*03ce13f7SAndroid Build Coastguard Worker From = NewVar;
7450*03ce13f7SAndroid Build Coastguard Worker } else if ((!(Allowed & Legal_Mem) && !MustHaveRegister) ||
7451*03ce13f7SAndroid Build Coastguard Worker (RegNum.hasValue() && RegNum != Var->getRegNum())) {
7452*03ce13f7SAndroid Build Coastguard Worker From = copyToReg(From, RegNum);
7453*03ce13f7SAndroid Build Coastguard Worker }
7454*03ce13f7SAndroid Build Coastguard Worker return From;
7455*03ce13f7SAndroid Build Coastguard Worker }
7456*03ce13f7SAndroid Build Coastguard Worker
7457*03ce13f7SAndroid Build Coastguard Worker llvm::report_fatal_error("Unhandled operand kind in legalize()");
7458*03ce13f7SAndroid Build Coastguard Worker return From;
7459*03ce13f7SAndroid Build Coastguard Worker }
7460*03ce13f7SAndroid Build Coastguard Worker
7461*03ce13f7SAndroid Build Coastguard Worker /// Provide a trivial wrapper to legalize() for this common usage.
7462*03ce13f7SAndroid Build Coastguard Worker
legalizeToReg(Operand * From,RegNumT RegNum)7463*03ce13f7SAndroid Build Coastguard Worker Variable *TargetX8632::legalizeToReg(Operand *From, RegNumT RegNum) {
7464*03ce13f7SAndroid Build Coastguard Worker return llvm::cast<Variable>(legalize(From, Legal_Reg, RegNum));
7465*03ce13f7SAndroid Build Coastguard Worker }
7466*03ce13f7SAndroid Build Coastguard Worker
7467*03ce13f7SAndroid Build Coastguard Worker /// Legalize undef values to concrete values.
7468*03ce13f7SAndroid Build Coastguard Worker
legalizeUndef(Operand * From,RegNumT RegNum)7469*03ce13f7SAndroid Build Coastguard Worker Operand *TargetX8632::legalizeUndef(Operand *From, RegNumT RegNum) {
7470*03ce13f7SAndroid Build Coastguard Worker Type Ty = From->getType();
7471*03ce13f7SAndroid Build Coastguard Worker if (llvm::isa<ConstantUndef>(From)) {
7472*03ce13f7SAndroid Build Coastguard Worker // Lower undefs to zero. Another option is to lower undefs to an
7473*03ce13f7SAndroid Build Coastguard Worker // uninitialized register; however, using an uninitialized register
7474*03ce13f7SAndroid Build Coastguard Worker // results in less predictable code.
7475*03ce13f7SAndroid Build Coastguard Worker //
7476*03ce13f7SAndroid Build Coastguard Worker // If in the future the implementation is changed to lower undef values to
7477*03ce13f7SAndroid Build Coastguard Worker // uninitialized registers, a FakeDef will be needed:
7478*03ce13f7SAndroid Build Coastguard Worker // Context.insert<InstFakeDef>(Reg);
7479*03ce13f7SAndroid Build Coastguard Worker // This is in order to ensure that the live range of Reg is not
7480*03ce13f7SAndroid Build Coastguard Worker // overestimated. If the constant being lowered is a 64 bit value, then
7481*03ce13f7SAndroid Build Coastguard Worker // the result should be split and the lo and hi components will need to go
7482*03ce13f7SAndroid Build Coastguard Worker // in uninitialized registers.
7483*03ce13f7SAndroid Build Coastguard Worker if (isVectorType(Ty))
7484*03ce13f7SAndroid Build Coastguard Worker return makeVectorOfZeros(Ty, RegNum);
7485*03ce13f7SAndroid Build Coastguard Worker return Ctx->getConstantZero(Ty);
7486*03ce13f7SAndroid Build Coastguard Worker }
7487*03ce13f7SAndroid Build Coastguard Worker return From;
7488*03ce13f7SAndroid Build Coastguard Worker }
7489*03ce13f7SAndroid Build Coastguard Worker
7490*03ce13f7SAndroid Build Coastguard Worker /// For the cmp instruction, if Src1 is an immediate, or known to be a
7491*03ce13f7SAndroid Build Coastguard Worker /// physical register, we can allow Src0 to be a memory operand. Otherwise,
7492*03ce13f7SAndroid Build Coastguard Worker /// Src0 must be copied into a physical register. (Actually, either Src0 or
7493*03ce13f7SAndroid Build Coastguard Worker /// Src1 can be chosen for the physical register, but unfortunately we have to
7494*03ce13f7SAndroid Build Coastguard Worker /// commit to one or the other before register allocation.)
7495*03ce13f7SAndroid Build Coastguard Worker
legalizeSrc0ForCmp(Operand * Src0,Operand * Src1)7496*03ce13f7SAndroid Build Coastguard Worker Operand *TargetX8632::legalizeSrc0ForCmp(Operand *Src0, Operand *Src1) {
7497*03ce13f7SAndroid Build Coastguard Worker bool IsSrc1ImmOrReg = false;
7498*03ce13f7SAndroid Build Coastguard Worker if (llvm::isa<Constant>(Src1)) {
7499*03ce13f7SAndroid Build Coastguard Worker IsSrc1ImmOrReg = true;
7500*03ce13f7SAndroid Build Coastguard Worker } else if (auto *Var = llvm::dyn_cast<Variable>(Src1)) {
7501*03ce13f7SAndroid Build Coastguard Worker if (Var->hasReg())
7502*03ce13f7SAndroid Build Coastguard Worker IsSrc1ImmOrReg = true;
7503*03ce13f7SAndroid Build Coastguard Worker }
7504*03ce13f7SAndroid Build Coastguard Worker return legalize(Src0, IsSrc1ImmOrReg ? (Legal_Reg | Legal_Mem) : Legal_Reg);
7505*03ce13f7SAndroid Build Coastguard Worker }
7506*03ce13f7SAndroid Build Coastguard Worker
formMemoryOperand(Operand * Opnd,Type Ty,bool DoLegalize)7507*03ce13f7SAndroid Build Coastguard Worker X86OperandMem *TargetX8632::formMemoryOperand(Operand *Opnd, Type Ty,
7508*03ce13f7SAndroid Build Coastguard Worker bool DoLegalize) {
7509*03ce13f7SAndroid Build Coastguard Worker auto *Mem = llvm::dyn_cast<X86OperandMem>(Opnd);
7510*03ce13f7SAndroid Build Coastguard Worker // It may be the case that address mode optimization already creates an
7511*03ce13f7SAndroid Build Coastguard Worker // X86OperandMem, so in that case it wouldn't need another level of
7512*03ce13f7SAndroid Build Coastguard Worker // transformation.
7513*03ce13f7SAndroid Build Coastguard Worker if (!Mem) {
7514*03ce13f7SAndroid Build Coastguard Worker auto *Base = llvm::dyn_cast<Variable>(Opnd);
7515*03ce13f7SAndroid Build Coastguard Worker auto *Offset = llvm::dyn_cast<Constant>(Opnd);
7516*03ce13f7SAndroid Build Coastguard Worker assert(Base || Offset);
7517*03ce13f7SAndroid Build Coastguard Worker if (Offset) {
7518*03ce13f7SAndroid Build Coastguard Worker if (!llvm::isa<ConstantRelocatable>(Offset)) {
7519*03ce13f7SAndroid Build Coastguard Worker if (llvm::isa<ConstantInteger64>(Offset)) {
7520*03ce13f7SAndroid Build Coastguard Worker // Memory operands cannot have 64-bit immediates, so they must be
7521*03ce13f7SAndroid Build Coastguard Worker // legalized into a register only.
7522*03ce13f7SAndroid Build Coastguard Worker Base = llvm::cast<Variable>(legalize(Offset, Legal_Reg));
7523*03ce13f7SAndroid Build Coastguard Worker Offset = nullptr;
7524*03ce13f7SAndroid Build Coastguard Worker } else {
7525*03ce13f7SAndroid Build Coastguard Worker Offset = llvm::cast<Constant>(legalize(Offset));
7526*03ce13f7SAndroid Build Coastguard Worker
7527*03ce13f7SAndroid Build Coastguard Worker assert(llvm::isa<ConstantInteger32>(Offset) ||
7528*03ce13f7SAndroid Build Coastguard Worker llvm::isa<ConstantRelocatable>(Offset));
7529*03ce13f7SAndroid Build Coastguard Worker }
7530*03ce13f7SAndroid Build Coastguard Worker }
7531*03ce13f7SAndroid Build Coastguard Worker }
7532*03ce13f7SAndroid Build Coastguard Worker Mem = X86OperandMem::create(Func, Ty, Base, Offset);
7533*03ce13f7SAndroid Build Coastguard Worker }
7534*03ce13f7SAndroid Build Coastguard Worker return llvm::cast<X86OperandMem>(DoLegalize ? legalize(Mem) : Mem);
7535*03ce13f7SAndroid Build Coastguard Worker }
7536*03ce13f7SAndroid Build Coastguard Worker
makeReg(Type Type,RegNumT RegNum)7537*03ce13f7SAndroid Build Coastguard Worker Variable *TargetX8632::makeReg(Type Type, RegNumT RegNum) {
7538*03ce13f7SAndroid Build Coastguard Worker // There aren't any 64-bit integer registers for x86-32.
7539*03ce13f7SAndroid Build Coastguard Worker assert(Type != IceType_i64);
7540*03ce13f7SAndroid Build Coastguard Worker Variable *Reg = Func->makeVariable(Type);
7541*03ce13f7SAndroid Build Coastguard Worker if (RegNum.hasValue())
7542*03ce13f7SAndroid Build Coastguard Worker Reg->setRegNum(RegNum);
7543*03ce13f7SAndroid Build Coastguard Worker else
7544*03ce13f7SAndroid Build Coastguard Worker Reg->setMustHaveReg();
7545*03ce13f7SAndroid Build Coastguard Worker return Reg;
7546*03ce13f7SAndroid Build Coastguard Worker }
7547*03ce13f7SAndroid Build Coastguard Worker
7548*03ce13f7SAndroid Build Coastguard Worker const Type TypeForSize[] = {IceType_i8, IceType_i16, IceType_i32, IceType_f64,
7549*03ce13f7SAndroid Build Coastguard Worker IceType_v16i8};
7550*03ce13f7SAndroid Build Coastguard Worker
largestTypeInSize(uint32_t Size,uint32_t MaxSize)7551*03ce13f7SAndroid Build Coastguard Worker Type TargetX8632::largestTypeInSize(uint32_t Size, uint32_t MaxSize) {
7552*03ce13f7SAndroid Build Coastguard Worker assert(Size != 0);
7553*03ce13f7SAndroid Build Coastguard Worker uint32_t TyIndex = llvm::findLastSet(Size, llvm::ZB_Undefined);
7554*03ce13f7SAndroid Build Coastguard Worker uint32_t MaxIndex = MaxSize == NoSizeLimit
7555*03ce13f7SAndroid Build Coastguard Worker ? llvm::array_lengthof(TypeForSize) - 1
7556*03ce13f7SAndroid Build Coastguard Worker : llvm::findLastSet(MaxSize, llvm::ZB_Undefined);
7557*03ce13f7SAndroid Build Coastguard Worker return TypeForSize[std::min(TyIndex, MaxIndex)];
7558*03ce13f7SAndroid Build Coastguard Worker }
7559*03ce13f7SAndroid Build Coastguard Worker
firstTypeThatFitsSize(uint32_t Size,uint32_t MaxSize)7560*03ce13f7SAndroid Build Coastguard Worker Type TargetX8632::firstTypeThatFitsSize(uint32_t Size, uint32_t MaxSize) {
7561*03ce13f7SAndroid Build Coastguard Worker assert(Size != 0);
7562*03ce13f7SAndroid Build Coastguard Worker uint32_t TyIndex = llvm::findLastSet(Size, llvm::ZB_Undefined);
7563*03ce13f7SAndroid Build Coastguard Worker if (!llvm::isPowerOf2_32(Size))
7564*03ce13f7SAndroid Build Coastguard Worker ++TyIndex;
7565*03ce13f7SAndroid Build Coastguard Worker uint32_t MaxIndex = MaxSize == NoSizeLimit
7566*03ce13f7SAndroid Build Coastguard Worker ? llvm::array_lengthof(TypeForSize) - 1
7567*03ce13f7SAndroid Build Coastguard Worker : llvm::findLastSet(MaxSize, llvm::ZB_Undefined);
7568*03ce13f7SAndroid Build Coastguard Worker return TypeForSize[std::min(TyIndex, MaxIndex)];
7569*03ce13f7SAndroid Build Coastguard Worker }
7570*03ce13f7SAndroid Build Coastguard Worker
postLower()7571*03ce13f7SAndroid Build Coastguard Worker void TargetX8632::postLower() {
7572*03ce13f7SAndroid Build Coastguard Worker if (Func->getOptLevel() == Opt_m1)
7573*03ce13f7SAndroid Build Coastguard Worker return;
7574*03ce13f7SAndroid Build Coastguard Worker markRedefinitions();
7575*03ce13f7SAndroid Build Coastguard Worker Context.availabilityUpdate();
7576*03ce13f7SAndroid Build Coastguard Worker }
7577*03ce13f7SAndroid Build Coastguard Worker
emit(const ConstantInteger32 * C) const7578*03ce13f7SAndroid Build Coastguard Worker void TargetX8632::emit(const ConstantInteger32 *C) const {
7579*03ce13f7SAndroid Build Coastguard Worker if (!BuildDefs::dump())
7580*03ce13f7SAndroid Build Coastguard Worker return;
7581*03ce13f7SAndroid Build Coastguard Worker Ostream &Str = Ctx->getStrEmit();
7582*03ce13f7SAndroid Build Coastguard Worker Str << "$" << C->getValue();
7583*03ce13f7SAndroid Build Coastguard Worker }
7584*03ce13f7SAndroid Build Coastguard Worker
emit(const ConstantInteger64 * C) const7585*03ce13f7SAndroid Build Coastguard Worker void TargetX8632::emit(const ConstantInteger64 *C) const {
7586*03ce13f7SAndroid Build Coastguard Worker llvm::report_fatal_error("Not expecting to emit 64-bit integers");
7587*03ce13f7SAndroid Build Coastguard Worker }
7588*03ce13f7SAndroid Build Coastguard Worker
emit(const ConstantFloat * C) const7589*03ce13f7SAndroid Build Coastguard Worker void TargetX8632::emit(const ConstantFloat *C) const {
7590*03ce13f7SAndroid Build Coastguard Worker if (!BuildDefs::dump())
7591*03ce13f7SAndroid Build Coastguard Worker return;
7592*03ce13f7SAndroid Build Coastguard Worker Ostream &Str = Ctx->getStrEmit();
7593*03ce13f7SAndroid Build Coastguard Worker Str << C->getLabelName();
7594*03ce13f7SAndroid Build Coastguard Worker }
7595*03ce13f7SAndroid Build Coastguard Worker
emit(const ConstantDouble * C) const7596*03ce13f7SAndroid Build Coastguard Worker void TargetX8632::emit(const ConstantDouble *C) const {
7597*03ce13f7SAndroid Build Coastguard Worker if (!BuildDefs::dump())
7598*03ce13f7SAndroid Build Coastguard Worker return;
7599*03ce13f7SAndroid Build Coastguard Worker Ostream &Str = Ctx->getStrEmit();
7600*03ce13f7SAndroid Build Coastguard Worker Str << C->getLabelName();
7601*03ce13f7SAndroid Build Coastguard Worker }
7602*03ce13f7SAndroid Build Coastguard Worker
emit(const ConstantUndef *) const7603*03ce13f7SAndroid Build Coastguard Worker void TargetX8632::emit(const ConstantUndef *) const {
7604*03ce13f7SAndroid Build Coastguard Worker llvm::report_fatal_error("undef value encountered by emitter.");
7605*03ce13f7SAndroid Build Coastguard Worker }
7606*03ce13f7SAndroid Build Coastguard Worker
emit(const ConstantRelocatable * C) const7607*03ce13f7SAndroid Build Coastguard Worker void TargetX8632::emit(const ConstantRelocatable *C) const {
7608*03ce13f7SAndroid Build Coastguard Worker if (!BuildDefs::dump())
7609*03ce13f7SAndroid Build Coastguard Worker return;
7610*03ce13f7SAndroid Build Coastguard Worker Ostream &Str = Ctx->getStrEmit();
7611*03ce13f7SAndroid Build Coastguard Worker Str << "$";
7612*03ce13f7SAndroid Build Coastguard Worker emitWithoutPrefix(C);
7613*03ce13f7SAndroid Build Coastguard Worker }
7614*03ce13f7SAndroid Build Coastguard Worker
emitJumpTable(const Cfg *,const InstJumpTable * JumpTable) const7615*03ce13f7SAndroid Build Coastguard Worker void TargetX8632::emitJumpTable(const Cfg *,
7616*03ce13f7SAndroid Build Coastguard Worker const InstJumpTable *JumpTable) const {
7617*03ce13f7SAndroid Build Coastguard Worker if (!BuildDefs::dump())
7618*03ce13f7SAndroid Build Coastguard Worker return;
7619*03ce13f7SAndroid Build Coastguard Worker Ostream &Str = Ctx->getStrEmit();
7620*03ce13f7SAndroid Build Coastguard Worker Str << "\t.section\t.rodata." << JumpTable->getSectionName()
7621*03ce13f7SAndroid Build Coastguard Worker << ",\"a\",@progbits\n"
7622*03ce13f7SAndroid Build Coastguard Worker "\t.align\t"
7623*03ce13f7SAndroid Build Coastguard Worker << typeWidthInBytes(IceType_i32) << "\n"
7624*03ce13f7SAndroid Build Coastguard Worker << JumpTable->getName() << ":";
7625*03ce13f7SAndroid Build Coastguard Worker
7626*03ce13f7SAndroid Build Coastguard Worker for (SizeT I = 0; I < JumpTable->getNumTargets(); ++I)
7627*03ce13f7SAndroid Build Coastguard Worker Str << "\n\t.long\t" << JumpTable->getTarget(I)->getAsmName();
7628*03ce13f7SAndroid Build Coastguard Worker Str << "\n";
7629*03ce13f7SAndroid Build Coastguard Worker }
7630*03ce13f7SAndroid Build Coastguard Worker
7631*03ce13f7SAndroid Build Coastguard Worker const TargetX8632::TableFcmpType TargetX8632::TableFcmp[] = {
7632*03ce13f7SAndroid Build Coastguard Worker #define X(val, dflt, swapS, C1, C2, swapV, pred) \
7633*03ce13f7SAndroid Build Coastguard Worker {dflt, swapS, CondX86::C1, CondX86::C2, swapV, CondX86::pred},
7634*03ce13f7SAndroid Build Coastguard Worker FCMPX8632_TABLE
7635*03ce13f7SAndroid Build Coastguard Worker #undef X
7636*03ce13f7SAndroid Build Coastguard Worker };
7637*03ce13f7SAndroid Build Coastguard Worker
7638*03ce13f7SAndroid Build Coastguard Worker const size_t TargetX8632::TableFcmpSize = llvm::array_lengthof(TableFcmp);
7639*03ce13f7SAndroid Build Coastguard Worker
7640*03ce13f7SAndroid Build Coastguard Worker const TargetX8632::TableIcmp32Type TargetX8632::TableIcmp32[] = {
7641*03ce13f7SAndroid Build Coastguard Worker #define X(val, C_32, C1_64, C2_64, C3_64) {CondX86::C_32},
7642*03ce13f7SAndroid Build Coastguard Worker ICMPX8632_TABLE
7643*03ce13f7SAndroid Build Coastguard Worker #undef X
7644*03ce13f7SAndroid Build Coastguard Worker };
7645*03ce13f7SAndroid Build Coastguard Worker
7646*03ce13f7SAndroid Build Coastguard Worker const size_t TargetX8632::TableIcmp32Size = llvm::array_lengthof(TableIcmp32);
7647*03ce13f7SAndroid Build Coastguard Worker
7648*03ce13f7SAndroid Build Coastguard Worker const TargetX8632::TableIcmp64Type TargetX8632::TableIcmp64[] = {
7649*03ce13f7SAndroid Build Coastguard Worker #define X(val, C_32, C1_64, C2_64, C3_64) \
7650*03ce13f7SAndroid Build Coastguard Worker {CondX86::C1_64, CondX86::C2_64, CondX86::C3_64},
7651*03ce13f7SAndroid Build Coastguard Worker ICMPX8632_TABLE
7652*03ce13f7SAndroid Build Coastguard Worker #undef X
7653*03ce13f7SAndroid Build Coastguard Worker };
7654*03ce13f7SAndroid Build Coastguard Worker
7655*03ce13f7SAndroid Build Coastguard Worker const size_t TargetX8632::TableIcmp64Size = llvm::array_lengthof(TableIcmp64);
7656*03ce13f7SAndroid Build Coastguard Worker
7657*03ce13f7SAndroid Build Coastguard Worker std::array<SmallBitVector, RCX86_NUM> TargetX8632::TypeToRegisterSet = {{}};
7658*03ce13f7SAndroid Build Coastguard Worker
7659*03ce13f7SAndroid Build Coastguard Worker std::array<SmallBitVector, RCX86_NUM> TargetX8632::TypeToRegisterSetUnfiltered =
7660*03ce13f7SAndroid Build Coastguard Worker {{}};
7661*03ce13f7SAndroid Build Coastguard Worker
7662*03ce13f7SAndroid Build Coastguard Worker std::array<SmallBitVector, RegisterSet::Reg_NUM> TargetX8632::RegisterAliases =
7663*03ce13f7SAndroid Build Coastguard Worker {{}};
7664*03ce13f7SAndroid Build Coastguard Worker
7665*03ce13f7SAndroid Build Coastguard Worker template <typename T>
emitConstantPool(GlobalContext * Ctx)7666*03ce13f7SAndroid Build Coastguard Worker void TargetDataX8632::emitConstantPool(GlobalContext *Ctx) {
7667*03ce13f7SAndroid Build Coastguard Worker if (!BuildDefs::dump())
7668*03ce13f7SAndroid Build Coastguard Worker return;
7669*03ce13f7SAndroid Build Coastguard Worker Ostream &Str = Ctx->getStrEmit();
7670*03ce13f7SAndroid Build Coastguard Worker Type Ty = T::Ty;
7671*03ce13f7SAndroid Build Coastguard Worker SizeT Align = typeAlignInBytes(Ty);
7672*03ce13f7SAndroid Build Coastguard Worker ConstantList Pool = Ctx->getConstantPool(Ty);
7673*03ce13f7SAndroid Build Coastguard Worker
7674*03ce13f7SAndroid Build Coastguard Worker Str << "\t.section\t.rodata.cst" << Align << ",\"aM\",@progbits," << Align
7675*03ce13f7SAndroid Build Coastguard Worker << "\n";
7676*03ce13f7SAndroid Build Coastguard Worker Str << "\t.align\t" << Align << "\n";
7677*03ce13f7SAndroid Build Coastguard Worker
7678*03ce13f7SAndroid Build Coastguard Worker for (Constant *C : Pool) {
7679*03ce13f7SAndroid Build Coastguard Worker if (!C->getShouldBePooled())
7680*03ce13f7SAndroid Build Coastguard Worker continue;
7681*03ce13f7SAndroid Build Coastguard Worker auto *Const = llvm::cast<typename T::IceType>(C);
7682*03ce13f7SAndroid Build Coastguard Worker typename T::IceType::PrimType Value = Const->getValue();
7683*03ce13f7SAndroid Build Coastguard Worker // Use memcpy() to copy bits from Value into RawValue in a way that avoids
7684*03ce13f7SAndroid Build Coastguard Worker // breaking strict-aliasing rules.
7685*03ce13f7SAndroid Build Coastguard Worker typename T::PrimitiveIntType RawValue;
7686*03ce13f7SAndroid Build Coastguard Worker memcpy(&RawValue, &Value, sizeof(Value));
7687*03ce13f7SAndroid Build Coastguard Worker char buf[30];
7688*03ce13f7SAndroid Build Coastguard Worker int CharsPrinted =
7689*03ce13f7SAndroid Build Coastguard Worker snprintf(buf, llvm::array_lengthof(buf), T::PrintfString, RawValue);
7690*03ce13f7SAndroid Build Coastguard Worker assert(CharsPrinted >= 0);
7691*03ce13f7SAndroid Build Coastguard Worker assert((size_t)CharsPrinted < llvm::array_lengthof(buf));
7692*03ce13f7SAndroid Build Coastguard Worker (void)CharsPrinted; // avoid warnings if asserts are disabled
7693*03ce13f7SAndroid Build Coastguard Worker Str << Const->getLabelName();
7694*03ce13f7SAndroid Build Coastguard Worker Str << ":\n\t" << T::AsmTag << "\t" << buf << "\t/* " << T::TypeName << " "
7695*03ce13f7SAndroid Build Coastguard Worker << Value << " */\n";
7696*03ce13f7SAndroid Build Coastguard Worker }
7697*03ce13f7SAndroid Build Coastguard Worker }
7698*03ce13f7SAndroid Build Coastguard Worker
lowerConstants()7699*03ce13f7SAndroid Build Coastguard Worker void TargetDataX8632::lowerConstants() {
7700*03ce13f7SAndroid Build Coastguard Worker if (getFlags().getDisableTranslation())
7701*03ce13f7SAndroid Build Coastguard Worker return;
7702*03ce13f7SAndroid Build Coastguard Worker switch (getFlags().getOutFileType()) {
7703*03ce13f7SAndroid Build Coastguard Worker case FT_Elf: {
7704*03ce13f7SAndroid Build Coastguard Worker ELFObjectWriter *Writer = Ctx->getObjectWriter();
7705*03ce13f7SAndroid Build Coastguard Worker
7706*03ce13f7SAndroid Build Coastguard Worker Writer->writeConstantPool<ConstantInteger32>(IceType_i8);
7707*03ce13f7SAndroid Build Coastguard Worker Writer->writeConstantPool<ConstantInteger32>(IceType_i16);
7708*03ce13f7SAndroid Build Coastguard Worker Writer->writeConstantPool<ConstantInteger32>(IceType_i32);
7709*03ce13f7SAndroid Build Coastguard Worker
7710*03ce13f7SAndroid Build Coastguard Worker Writer->writeConstantPool<ConstantFloat>(IceType_f32);
7711*03ce13f7SAndroid Build Coastguard Worker Writer->writeConstantPool<ConstantDouble>(IceType_f64);
7712*03ce13f7SAndroid Build Coastguard Worker } break;
7713*03ce13f7SAndroid Build Coastguard Worker case FT_Asm:
7714*03ce13f7SAndroid Build Coastguard Worker case FT_Iasm: {
7715*03ce13f7SAndroid Build Coastguard Worker OstreamLocker L(Ctx);
7716*03ce13f7SAndroid Build Coastguard Worker
7717*03ce13f7SAndroid Build Coastguard Worker emitConstantPool<PoolTypeConverter<uint8_t>>(Ctx);
7718*03ce13f7SAndroid Build Coastguard Worker emitConstantPool<PoolTypeConverter<uint16_t>>(Ctx);
7719*03ce13f7SAndroid Build Coastguard Worker emitConstantPool<PoolTypeConverter<uint32_t>>(Ctx);
7720*03ce13f7SAndroid Build Coastguard Worker
7721*03ce13f7SAndroid Build Coastguard Worker emitConstantPool<PoolTypeConverter<float>>(Ctx);
7722*03ce13f7SAndroid Build Coastguard Worker emitConstantPool<PoolTypeConverter<double>>(Ctx);
7723*03ce13f7SAndroid Build Coastguard Worker } break;
7724*03ce13f7SAndroid Build Coastguard Worker }
7725*03ce13f7SAndroid Build Coastguard Worker }
7726*03ce13f7SAndroid Build Coastguard Worker
lowerJumpTables()7727*03ce13f7SAndroid Build Coastguard Worker void TargetDataX8632::lowerJumpTables() {
7728*03ce13f7SAndroid Build Coastguard Worker const bool IsPIC = false;
7729*03ce13f7SAndroid Build Coastguard Worker switch (getFlags().getOutFileType()) {
7730*03ce13f7SAndroid Build Coastguard Worker case FT_Elf: {
7731*03ce13f7SAndroid Build Coastguard Worker ELFObjectWriter *Writer = Ctx->getObjectWriter();
7732*03ce13f7SAndroid Build Coastguard Worker const FixupKind RelocationKind = FK_Abs;
7733*03ce13f7SAndroid Build Coastguard Worker for (const JumpTableData &JT : Ctx->getJumpTables())
7734*03ce13f7SAndroid Build Coastguard Worker Writer->writeJumpTable(JT, RelocationKind, IsPIC);
7735*03ce13f7SAndroid Build Coastguard Worker } break;
7736*03ce13f7SAndroid Build Coastguard Worker case FT_Asm:
7737*03ce13f7SAndroid Build Coastguard Worker // Already emitted from Cfg
7738*03ce13f7SAndroid Build Coastguard Worker break;
7739*03ce13f7SAndroid Build Coastguard Worker case FT_Iasm: {
7740*03ce13f7SAndroid Build Coastguard Worker if (!BuildDefs::dump())
7741*03ce13f7SAndroid Build Coastguard Worker return;
7742*03ce13f7SAndroid Build Coastguard Worker Ostream &Str = Ctx->getStrEmit();
7743*03ce13f7SAndroid Build Coastguard Worker const char *Prefix = IsPIC ? ".data.rel.ro." : ".rodata.";
7744*03ce13f7SAndroid Build Coastguard Worker for (const JumpTableData &JT : Ctx->getJumpTables()) {
7745*03ce13f7SAndroid Build Coastguard Worker Str << "\t.section\t" << Prefix << JT.getSectionName()
7746*03ce13f7SAndroid Build Coastguard Worker << ",\"a\",@progbits\n"
7747*03ce13f7SAndroid Build Coastguard Worker "\t.align\t"
7748*03ce13f7SAndroid Build Coastguard Worker << typeWidthInBytes(IceType_i32) << "\n"
7749*03ce13f7SAndroid Build Coastguard Worker << JT.getName().toString() << ":";
7750*03ce13f7SAndroid Build Coastguard Worker
7751*03ce13f7SAndroid Build Coastguard Worker // On X8664 ILP32 pointers are 32-bit hence the use of .long
7752*03ce13f7SAndroid Build Coastguard Worker for (intptr_t TargetOffset : JT.getTargetOffsets())
7753*03ce13f7SAndroid Build Coastguard Worker Str << "\n\t.long\t" << JT.getFunctionName() << "+" << TargetOffset;
7754*03ce13f7SAndroid Build Coastguard Worker Str << "\n";
7755*03ce13f7SAndroid Build Coastguard Worker }
7756*03ce13f7SAndroid Build Coastguard Worker } break;
7757*03ce13f7SAndroid Build Coastguard Worker }
7758*03ce13f7SAndroid Build Coastguard Worker }
7759*03ce13f7SAndroid Build Coastguard Worker
lowerGlobals(const VariableDeclarationList & Vars,const std::string & SectionSuffix)7760*03ce13f7SAndroid Build Coastguard Worker void TargetDataX8632::lowerGlobals(const VariableDeclarationList &Vars,
7761*03ce13f7SAndroid Build Coastguard Worker const std::string &SectionSuffix) {
7762*03ce13f7SAndroid Build Coastguard Worker const bool IsPIC = false;
7763*03ce13f7SAndroid Build Coastguard Worker switch (getFlags().getOutFileType()) {
7764*03ce13f7SAndroid Build Coastguard Worker case FT_Elf: {
7765*03ce13f7SAndroid Build Coastguard Worker ELFObjectWriter *Writer = Ctx->getObjectWriter();
7766*03ce13f7SAndroid Build Coastguard Worker Writer->writeDataSection(Vars, FK_Abs, SectionSuffix, IsPIC);
7767*03ce13f7SAndroid Build Coastguard Worker } break;
7768*03ce13f7SAndroid Build Coastguard Worker case FT_Asm:
7769*03ce13f7SAndroid Build Coastguard Worker case FT_Iasm: {
7770*03ce13f7SAndroid Build Coastguard Worker OstreamLocker L(Ctx);
7771*03ce13f7SAndroid Build Coastguard Worker for (const VariableDeclaration *Var : Vars) {
7772*03ce13f7SAndroid Build Coastguard Worker if (getFlags().matchTranslateOnly(Var->getName(), 0)) {
7773*03ce13f7SAndroid Build Coastguard Worker emitGlobal(*Var, SectionSuffix);
7774*03ce13f7SAndroid Build Coastguard Worker }
7775*03ce13f7SAndroid Build Coastguard Worker }
7776*03ce13f7SAndroid Build Coastguard Worker } break;
7777*03ce13f7SAndroid Build Coastguard Worker }
7778*03ce13f7SAndroid Build Coastguard Worker }
7779*03ce13f7SAndroid Build Coastguard Worker
7780*03ce13f7SAndroid Build Coastguard Worker //------------------------------------------------------------------------------
7781*03ce13f7SAndroid Build Coastguard Worker // __ ______ __ __ ______ ______ __ __ __ ______
7782*03ce13f7SAndroid Build Coastguard Worker // /\ \ /\ __ \/\ \ _ \ \/\ ___\/\ == \/\ \/\ "-.\ \/\ ___\
7783*03ce13f7SAndroid Build Coastguard Worker // \ \ \___\ \ \/\ \ \ \/ ".\ \ \ __\\ \ __<\ \ \ \ \-. \ \ \__ \
7784*03ce13f7SAndroid Build Coastguard Worker // \ \_____\ \_____\ \__/".~\_\ \_____\ \_\ \_\ \_\ \_\\"\_\ \_____\
7785*03ce13f7SAndroid Build Coastguard Worker // \/_____/\/_____/\/_/ \/_/\/_____/\/_/ /_/\/_/\/_/ \/_/\/_____/
7786*03ce13f7SAndroid Build Coastguard Worker //
7787*03ce13f7SAndroid Build Coastguard Worker //------------------------------------------------------------------------------
_add_sp(Operand * Adjustment)7788*03ce13f7SAndroid Build Coastguard Worker void TargetX8632::_add_sp(Operand *Adjustment) {
7789*03ce13f7SAndroid Build Coastguard Worker Variable *esp = getPhysicalRegister(RegX8632::Reg_esp);
7790*03ce13f7SAndroid Build Coastguard Worker _add(esp, Adjustment);
7791*03ce13f7SAndroid Build Coastguard Worker }
7792*03ce13f7SAndroid Build Coastguard Worker
_mov_sp(Operand * NewValue)7793*03ce13f7SAndroid Build Coastguard Worker void TargetX8632::_mov_sp(Operand *NewValue) {
7794*03ce13f7SAndroid Build Coastguard Worker Variable *esp = getPhysicalRegister(RegX8632::Reg_esp);
7795*03ce13f7SAndroid Build Coastguard Worker _redefined(_mov(esp, NewValue));
7796*03ce13f7SAndroid Build Coastguard Worker }
7797*03ce13f7SAndroid Build Coastguard Worker
_sub_sp(Operand * Adjustment)7798*03ce13f7SAndroid Build Coastguard Worker void TargetX8632::_sub_sp(Operand *Adjustment) {
7799*03ce13f7SAndroid Build Coastguard Worker Variable *esp = getPhysicalRegister(RegX8632::Reg_esp);
7800*03ce13f7SAndroid Build Coastguard Worker _sub(esp, Adjustment);
7801*03ce13f7SAndroid Build Coastguard Worker // Add a fake use of the stack pointer, to prevent the stack pointer
7802*03ce13f7SAndroid Build Coastguard Worker // adustment from being dead-code eliminated in a function that doesn't
7803*03ce13f7SAndroid Build Coastguard Worker // return.
7804*03ce13f7SAndroid Build Coastguard Worker Context.insert<InstFakeUse>(esp);
7805*03ce13f7SAndroid Build Coastguard Worker }
7806*03ce13f7SAndroid Build Coastguard Worker
_link_bp()7807*03ce13f7SAndroid Build Coastguard Worker void TargetX8632::_link_bp() {
7808*03ce13f7SAndroid Build Coastguard Worker Variable *ebp = getPhysicalRegister(RegX8632::Reg_ebp);
7809*03ce13f7SAndroid Build Coastguard Worker Variable *esp = getPhysicalRegister(RegX8632::Reg_esp);
7810*03ce13f7SAndroid Build Coastguard Worker _push(ebp);
7811*03ce13f7SAndroid Build Coastguard Worker _mov(ebp, esp);
7812*03ce13f7SAndroid Build Coastguard Worker // Keep ebp live for late-stage liveness analysis (e.g. asm-verbose mode).
7813*03ce13f7SAndroid Build Coastguard Worker Context.insert<InstFakeUse>(ebp);
7814*03ce13f7SAndroid Build Coastguard Worker }
7815*03ce13f7SAndroid Build Coastguard Worker
_unlink_bp()7816*03ce13f7SAndroid Build Coastguard Worker void TargetX8632::_unlink_bp() {
7817*03ce13f7SAndroid Build Coastguard Worker Variable *esp = getPhysicalRegister(RegX8632::Reg_esp);
7818*03ce13f7SAndroid Build Coastguard Worker Variable *ebp = getPhysicalRegister(RegX8632::Reg_ebp);
7819*03ce13f7SAndroid Build Coastguard Worker // For late-stage liveness analysis (e.g. asm-verbose mode), adding a fake
7820*03ce13f7SAndroid Build Coastguard Worker // use of esp before the assignment of esp=ebp keeps previous esp
7821*03ce13f7SAndroid Build Coastguard Worker // adjustments from being dead-code eliminated.
7822*03ce13f7SAndroid Build Coastguard Worker Context.insert<InstFakeUse>(esp);
7823*03ce13f7SAndroid Build Coastguard Worker _mov(esp, ebp);
7824*03ce13f7SAndroid Build Coastguard Worker _pop(ebp);
7825*03ce13f7SAndroid Build Coastguard Worker }
7826*03ce13f7SAndroid Build Coastguard Worker
_push_reg(RegNumT RegNum)7827*03ce13f7SAndroid Build Coastguard Worker void TargetX8632::_push_reg(RegNumT RegNum) {
7828*03ce13f7SAndroid Build Coastguard Worker _push(getPhysicalRegister(RegNum, WordType));
7829*03ce13f7SAndroid Build Coastguard Worker }
7830*03ce13f7SAndroid Build Coastguard Worker
_pop_reg(RegNumT RegNum)7831*03ce13f7SAndroid Build Coastguard Worker void TargetX8632::_pop_reg(RegNumT RegNum) {
7832*03ce13f7SAndroid Build Coastguard Worker _pop(getPhysicalRegister(RegNum, WordType));
7833*03ce13f7SAndroid Build Coastguard Worker }
7834*03ce13f7SAndroid Build Coastguard Worker
7835*03ce13f7SAndroid Build Coastguard Worker /// Lower an indirect jump adding sandboxing when needed.
lowerIndirectJump(Variable * JumpTarget)7836*03ce13f7SAndroid Build Coastguard Worker void TargetX8632::lowerIndirectJump(Variable *JumpTarget) { _jmp(JumpTarget); }
7837*03ce13f7SAndroid Build Coastguard Worker
emitCallToTarget(Operand * CallTarget,Variable * ReturnReg,size_t NumVariadicFpArgs)7838*03ce13f7SAndroid Build Coastguard Worker Inst *TargetX8632::emitCallToTarget(Operand *CallTarget, Variable *ReturnReg,
7839*03ce13f7SAndroid Build Coastguard Worker size_t NumVariadicFpArgs) {
7840*03ce13f7SAndroid Build Coastguard Worker (void)NumVariadicFpArgs;
7841*03ce13f7SAndroid Build Coastguard Worker // Note that NumVariadicFpArgs is only used for System V x86-64 variadic
7842*03ce13f7SAndroid Build Coastguard Worker // calls, because floating point arguments are passed via vector registers,
7843*03ce13f7SAndroid Build Coastguard Worker // whereas for x86-32, all args are passed via the stack.
7844*03ce13f7SAndroid Build Coastguard Worker
7845*03ce13f7SAndroid Build Coastguard Worker return Context.insert<Insts::Call>(ReturnReg, CallTarget);
7846*03ce13f7SAndroid Build Coastguard Worker }
7847*03ce13f7SAndroid Build Coastguard Worker
moveReturnValueToRegister(Operand * Value,Type ReturnType)7848*03ce13f7SAndroid Build Coastguard Worker Variable *TargetX8632::moveReturnValueToRegister(Operand *Value,
7849*03ce13f7SAndroid Build Coastguard Worker Type ReturnType) {
7850*03ce13f7SAndroid Build Coastguard Worker if (isVectorType(ReturnType)) {
7851*03ce13f7SAndroid Build Coastguard Worker return legalizeToReg(Value, RegX8632::Reg_xmm0);
7852*03ce13f7SAndroid Build Coastguard Worker } else if (isScalarFloatingType(ReturnType)) {
7853*03ce13f7SAndroid Build Coastguard Worker _fld(Value);
7854*03ce13f7SAndroid Build Coastguard Worker return nullptr;
7855*03ce13f7SAndroid Build Coastguard Worker } else {
7856*03ce13f7SAndroid Build Coastguard Worker assert(ReturnType == IceType_i32 || ReturnType == IceType_i64);
7857*03ce13f7SAndroid Build Coastguard Worker if (ReturnType == IceType_i64) {
7858*03ce13f7SAndroid Build Coastguard Worker Variable *eax = legalizeToReg(loOperand(Value), RegX8632::Reg_eax);
7859*03ce13f7SAndroid Build Coastguard Worker Variable *edx = legalizeToReg(hiOperand(Value), RegX8632::Reg_edx);
7860*03ce13f7SAndroid Build Coastguard Worker Context.insert<InstFakeUse>(edx);
7861*03ce13f7SAndroid Build Coastguard Worker return eax;
7862*03ce13f7SAndroid Build Coastguard Worker } else {
7863*03ce13f7SAndroid Build Coastguard Worker Variable *Reg = nullptr;
7864*03ce13f7SAndroid Build Coastguard Worker _mov(Reg, Value, RegX8632::Reg_eax);
7865*03ce13f7SAndroid Build Coastguard Worker return Reg;
7866*03ce13f7SAndroid Build Coastguard Worker }
7867*03ce13f7SAndroid Build Coastguard Worker }
7868*03ce13f7SAndroid Build Coastguard Worker }
7869*03ce13f7SAndroid Build Coastguard Worker
emitStackProbe(size_t StackSizeBytes)7870*03ce13f7SAndroid Build Coastguard Worker void TargetX8632::emitStackProbe(size_t StackSizeBytes) {
7871*03ce13f7SAndroid Build Coastguard Worker #if defined(_WIN32)
7872*03ce13f7SAndroid Build Coastguard Worker if (StackSizeBytes >= 4096) {
7873*03ce13f7SAndroid Build Coastguard Worker // _chkstk on Win32 is actually __alloca_probe, which adjusts ESP by the
7874*03ce13f7SAndroid Build Coastguard Worker // stack amount specified in EAX, so we save ESP in ECX, and restore them
7875*03ce13f7SAndroid Build Coastguard Worker // both after the call.
7876*03ce13f7SAndroid Build Coastguard Worker
7877*03ce13f7SAndroid Build Coastguard Worker Variable *EAX = makeReg(IceType_i32, RegX8632::Reg_eax);
7878*03ce13f7SAndroid Build Coastguard Worker Variable *ESP = makeReg(IceType_i32, RegX8632::Reg_esp);
7879*03ce13f7SAndroid Build Coastguard Worker Variable *ECX = makeReg(IceType_i32, RegX8632::Reg_ecx);
7880*03ce13f7SAndroid Build Coastguard Worker
7881*03ce13f7SAndroid Build Coastguard Worker _push_reg(ECX->getRegNum());
7882*03ce13f7SAndroid Build Coastguard Worker _mov(ECX, ESP);
7883*03ce13f7SAndroid Build Coastguard Worker
7884*03ce13f7SAndroid Build Coastguard Worker _mov(EAX, Ctx->getConstantInt32(StackSizeBytes));
7885*03ce13f7SAndroid Build Coastguard Worker
7886*03ce13f7SAndroid Build Coastguard Worker auto *CallTarget =
7887*03ce13f7SAndroid Build Coastguard Worker Ctx->getConstantInt32(reinterpret_cast<int32_t>(&_chkstk));
7888*03ce13f7SAndroid Build Coastguard Worker emitCallToTarget(CallTarget, nullptr);
7889*03ce13f7SAndroid Build Coastguard Worker
7890*03ce13f7SAndroid Build Coastguard Worker _mov(ESP, ECX);
7891*03ce13f7SAndroid Build Coastguard Worker _pop_reg(ECX->getRegNum());
7892*03ce13f7SAndroid Build Coastguard Worker }
7893*03ce13f7SAndroid Build Coastguard Worker #endif
7894*03ce13f7SAndroid Build Coastguard Worker }
7895*03ce13f7SAndroid Build Coastguard Worker
7896*03ce13f7SAndroid Build Coastguard Worker // In some cases, there are x-macros tables for both high-level and low-level
7897*03ce13f7SAndroid Build Coastguard Worker // instructions/operands that use the same enum key value. The tables are kept
7898*03ce13f7SAndroid Build Coastguard Worker // separate to maintain a proper separation between abstraction layers. There
7899*03ce13f7SAndroid Build Coastguard Worker // is a risk that the tables could get out of sync if enum values are
7900*03ce13f7SAndroid Build Coastguard Worker // reordered or if entries are added or deleted. The following dummy
7901*03ce13f7SAndroid Build Coastguard Worker // namespaces use static_asserts to ensure everything is kept in sync.
7902*03ce13f7SAndroid Build Coastguard Worker
7903*03ce13f7SAndroid Build Coastguard Worker namespace {
7904*03ce13f7SAndroid Build Coastguard Worker // Validate the enum values in FCMPX8632_TABLE.
7905*03ce13f7SAndroid Build Coastguard Worker namespace dummy1 {
7906*03ce13f7SAndroid Build Coastguard Worker // Define a temporary set of enum values based on low-level table entries.
7907*03ce13f7SAndroid Build Coastguard Worker enum _tmp_enum {
7908*03ce13f7SAndroid Build Coastguard Worker #define X(val, dflt, swapS, C1, C2, swapV, pred) _tmp_##val,
7909*03ce13f7SAndroid Build Coastguard Worker FCMPX8632_TABLE
7910*03ce13f7SAndroid Build Coastguard Worker #undef X
7911*03ce13f7SAndroid Build Coastguard Worker _num
7912*03ce13f7SAndroid Build Coastguard Worker };
7913*03ce13f7SAndroid Build Coastguard Worker // Define a set of constants based on high-level table entries.
7914*03ce13f7SAndroid Build Coastguard Worker #define X(tag, str) static const int _table1_##tag = InstFcmp::tag;
7915*03ce13f7SAndroid Build Coastguard Worker ICEINSTFCMP_TABLE
7916*03ce13f7SAndroid Build Coastguard Worker #undef X
7917*03ce13f7SAndroid Build Coastguard Worker // Define a set of constants based on low-level table entries, and ensure the
7918*03ce13f7SAndroid Build Coastguard Worker // table entry keys are consistent.
7919*03ce13f7SAndroid Build Coastguard Worker #define X(val, dflt, swapS, C1, C2, swapV, pred) \
7920*03ce13f7SAndroid Build Coastguard Worker static const int _table2_##val = _tmp_##val; \
7921*03ce13f7SAndroid Build Coastguard Worker static_assert( \
7922*03ce13f7SAndroid Build Coastguard Worker _table1_##val == _table2_##val, \
7923*03ce13f7SAndroid Build Coastguard Worker "Inconsistency between FCMPX8632_TABLE and ICEINSTFCMP_TABLE");
7924*03ce13f7SAndroid Build Coastguard Worker FCMPX8632_TABLE
7925*03ce13f7SAndroid Build Coastguard Worker #undef X
7926*03ce13f7SAndroid Build Coastguard Worker // Repeat the static asserts with respect to the high-level table entries in
7927*03ce13f7SAndroid Build Coastguard Worker // case the high-level table has extra entries.
7928*03ce13f7SAndroid Build Coastguard Worker #define X(tag, str) \
7929*03ce13f7SAndroid Build Coastguard Worker static_assert( \
7930*03ce13f7SAndroid Build Coastguard Worker _table1_##tag == _table2_##tag, \
7931*03ce13f7SAndroid Build Coastguard Worker "Inconsistency between FCMPX8632_TABLE and ICEINSTFCMP_TABLE");
7932*03ce13f7SAndroid Build Coastguard Worker ICEINSTFCMP_TABLE
7933*03ce13f7SAndroid Build Coastguard Worker #undef X
7934*03ce13f7SAndroid Build Coastguard Worker } // end of namespace dummy1
7935*03ce13f7SAndroid Build Coastguard Worker
7936*03ce13f7SAndroid Build Coastguard Worker // Validate the enum values in ICMPX8632_TABLE.
7937*03ce13f7SAndroid Build Coastguard Worker namespace dummy2 {
7938*03ce13f7SAndroid Build Coastguard Worker // Define a temporary set of enum values based on low-level table entries.
7939*03ce13f7SAndroid Build Coastguard Worker enum _tmp_enum {
7940*03ce13f7SAndroid Build Coastguard Worker #define X(val, C_32, C1_64, C2_64, C3_64) _tmp_##val,
7941*03ce13f7SAndroid Build Coastguard Worker ICMPX8632_TABLE
7942*03ce13f7SAndroid Build Coastguard Worker #undef X
7943*03ce13f7SAndroid Build Coastguard Worker _num
7944*03ce13f7SAndroid Build Coastguard Worker };
7945*03ce13f7SAndroid Build Coastguard Worker // Define a set of constants based on high-level table entries.
7946*03ce13f7SAndroid Build Coastguard Worker #define X(tag, reverse, str) static const int _table1_##tag = InstIcmp::tag;
7947*03ce13f7SAndroid Build Coastguard Worker ICEINSTICMP_TABLE
7948*03ce13f7SAndroid Build Coastguard Worker #undef X
7949*03ce13f7SAndroid Build Coastguard Worker // Define a set of constants based on low-level table entries, and ensure the
7950*03ce13f7SAndroid Build Coastguard Worker // table entry keys are consistent.
7951*03ce13f7SAndroid Build Coastguard Worker #define X(val, C_32, C1_64, C2_64, C3_64) \
7952*03ce13f7SAndroid Build Coastguard Worker static const int _table2_##val = _tmp_##val; \
7953*03ce13f7SAndroid Build Coastguard Worker static_assert( \
7954*03ce13f7SAndroid Build Coastguard Worker _table1_##val == _table2_##val, \
7955*03ce13f7SAndroid Build Coastguard Worker "Inconsistency between ICMPX8632_TABLE and ICEINSTICMP_TABLE");
7956*03ce13f7SAndroid Build Coastguard Worker ICMPX8632_TABLE
7957*03ce13f7SAndroid Build Coastguard Worker #undef X
7958*03ce13f7SAndroid Build Coastguard Worker // Repeat the static asserts with respect to the high-level table entries in
7959*03ce13f7SAndroid Build Coastguard Worker // case the high-level table has extra entries.
7960*03ce13f7SAndroid Build Coastguard Worker #define X(tag, reverse, str) \
7961*03ce13f7SAndroid Build Coastguard Worker static_assert( \
7962*03ce13f7SAndroid Build Coastguard Worker _table1_##tag == _table2_##tag, \
7963*03ce13f7SAndroid Build Coastguard Worker "Inconsistency between ICMPX8632_TABLE and ICEINSTICMP_TABLE");
7964*03ce13f7SAndroid Build Coastguard Worker ICEINSTICMP_TABLE
7965*03ce13f7SAndroid Build Coastguard Worker #undef X
7966*03ce13f7SAndroid Build Coastguard Worker } // end of namespace dummy2
7967*03ce13f7SAndroid Build Coastguard Worker
7968*03ce13f7SAndroid Build Coastguard Worker // Validate the enum values in ICETYPEX86_TABLE.
7969*03ce13f7SAndroid Build Coastguard Worker namespace dummy3 {
7970*03ce13f7SAndroid Build Coastguard Worker // Define a temporary set of enum values based on low-level table entries.
7971*03ce13f7SAndroid Build Coastguard Worker enum _tmp_enum {
7972*03ce13f7SAndroid Build Coastguard Worker #define X(tag, elty, cvt, sdss, pdps, spsd, int_, unpack, pack, width, fld) \
7973*03ce13f7SAndroid Build Coastguard Worker _tmp_##tag,
7974*03ce13f7SAndroid Build Coastguard Worker ICETYPEX86_TABLE
7975*03ce13f7SAndroid Build Coastguard Worker #undef X
7976*03ce13f7SAndroid Build Coastguard Worker _num
7977*03ce13f7SAndroid Build Coastguard Worker };
7978*03ce13f7SAndroid Build Coastguard Worker // Define a set of constants based on high-level table entries.
7979*03ce13f7SAndroid Build Coastguard Worker #define X(tag, sizeLog2, align, elts, elty, str, rcstr) \
7980*03ce13f7SAndroid Build Coastguard Worker static const int _table1_##tag = IceType_##tag;
7981*03ce13f7SAndroid Build Coastguard Worker ICETYPE_TABLE
7982*03ce13f7SAndroid Build Coastguard Worker #undef X
7983*03ce13f7SAndroid Build Coastguard Worker // Define a set of constants based on low-level table entries, and ensure the
7984*03ce13f7SAndroid Build Coastguard Worker // table entry keys are consistent.
7985*03ce13f7SAndroid Build Coastguard Worker #define X(tag, elty, cvt, sdss, pdps, spsd, int_, unpack, pack, width, fld) \
7986*03ce13f7SAndroid Build Coastguard Worker static const int _table2_##tag = _tmp_##tag; \
7987*03ce13f7SAndroid Build Coastguard Worker static_assert(_table1_##tag == _table2_##tag, \
7988*03ce13f7SAndroid Build Coastguard Worker "Inconsistency between ICETYPEX86_TABLE and ICETYPE_TABLE");
7989*03ce13f7SAndroid Build Coastguard Worker ICETYPEX86_TABLE
7990*03ce13f7SAndroid Build Coastguard Worker #undef X
7991*03ce13f7SAndroid Build Coastguard Worker // Repeat the static asserts with respect to the high-level table entries in
7992*03ce13f7SAndroid Build Coastguard Worker // case the high-level table has extra entries.
7993*03ce13f7SAndroid Build Coastguard Worker #define X(tag, sizeLog2, align, elts, elty, str, rcstr) \
7994*03ce13f7SAndroid Build Coastguard Worker static_assert(_table1_##tag == _table2_##tag, \
7995*03ce13f7SAndroid Build Coastguard Worker "Inconsistency between ICETYPEX86_TABLE and ICETYPE_TABLE");
7996*03ce13f7SAndroid Build Coastguard Worker ICETYPE_TABLE
7997*03ce13f7SAndroid Build Coastguard Worker #undef X
7998*03ce13f7SAndroid Build Coastguard Worker
7999*03ce13f7SAndroid Build Coastguard Worker } // end of namespace dummy3
8000*03ce13f7SAndroid Build Coastguard Worker } // end of anonymous namespace
8001*03ce13f7SAndroid Build Coastguard Worker
8002*03ce13f7SAndroid Build Coastguard Worker } // end of namespace X8632
8003*03ce13f7SAndroid Build Coastguard Worker } // end of namespace Ice
8004