• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //===- subzero/src/IceInstX86BaseImpl.h - Generic X86 instructions -*- C++ -*=//
2 //
3 //                        The Subzero Code Generator
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 ///
10 /// \file
11 /// \brief Implements the InstX86Base class and its descendants.
12 ///
13 //===----------------------------------------------------------------------===//
14 
15 #ifndef SUBZERO_SRC_ICEINSTX86BASEIMPL_H
16 #define SUBZERO_SRC_ICEINSTX86BASEIMPL_H
17 
18 #include "IceInstX86Base.h"
19 
20 #include "IceAssemblerX86Base.h"
21 #include "IceCfg.h"
22 #include "IceCfgNode.h"
23 #include "IceDefs.h"
24 #include "IceInst.h"
25 #include "IceOperand.h"
26 #include "IceTargetLowering.h"
27 #include "IceTargetLoweringX86Base.h"
28 
29 namespace Ice {
30 
31 namespace X86NAMESPACE {
32 
33 template <typename TraitsType>
getWidthString(Type Ty)34 const char *InstImpl<TraitsType>::InstX86Base::getWidthString(Type Ty) {
35   return Traits::TypeAttributes[Ty].WidthString;
36 }
37 
38 template <typename TraitsType>
getFldString(Type Ty)39 const char *InstImpl<TraitsType>::InstX86Base::getFldString(Type Ty) {
40   return Traits::TypeAttributes[Ty].FldString;
41 }
42 
43 template <typename TraitsType>
44 typename InstImpl<TraitsType>::Cond::BrCond
getOppositeCondition(BrCond Cond)45 InstImpl<TraitsType>::InstX86Base::getOppositeCondition(BrCond Cond) {
46   return Traits::InstBrAttributes[Cond].Opposite;
47 }
48 
49 template <typename TraitsType>
InstX86FakeRMW(Cfg * Func,Operand * Data,Operand * Addr,InstArithmetic::OpKind Op,Variable * Beacon)50 InstImpl<TraitsType>::InstX86FakeRMW::InstX86FakeRMW(Cfg *Func, Operand *Data,
51                                                      Operand *Addr,
52                                                      InstArithmetic::OpKind Op,
53                                                      Variable *Beacon)
54     : InstX86Base(Func, InstX86Base::FakeRMW, 3, nullptr), Op(Op) {
55   this->addSource(Data);
56   this->addSource(Addr);
57   this->addSource(Beacon);
58 }
59 
60 template <typename TraitsType>
InstX86GetIP(Cfg * Func,Variable * Dest)61 InstImpl<TraitsType>::InstX86GetIP::InstX86GetIP(Cfg *Func, Variable *Dest)
62     : InstX86Base(Func, InstX86Base::GetIP, 0, Dest) {}
63 
64 template <typename TraitsType>
InstX86Mul(Cfg * Func,Variable * Dest,Variable * Source1,Operand * Source2)65 InstImpl<TraitsType>::InstX86Mul::InstX86Mul(Cfg *Func, Variable *Dest,
66                                              Variable *Source1,
67                                              Operand *Source2)
68     : InstX86Base(Func, InstX86Base::Mul, 2, Dest) {
69   this->addSource(Source1);
70   this->addSource(Source2);
71 }
72 
73 template <typename TraitsType>
InstX86Shld(Cfg * Func,Variable * Dest,Variable * Source1,Operand * Source2)74 InstImpl<TraitsType>::InstX86Shld::InstX86Shld(Cfg *Func, Variable *Dest,
75                                                Variable *Source1,
76                                                Operand *Source2)
77     : InstX86Base(Func, InstX86Base::Shld, 3, Dest) {
78   this->addSource(Dest);
79   this->addSource(Source1);
80   this->addSource(Source2);
81 }
82 
83 template <typename TraitsType>
InstX86Shrd(Cfg * Func,Variable * Dest,Variable * Source1,Operand * Source2)84 InstImpl<TraitsType>::InstX86Shrd::InstX86Shrd(Cfg *Func, Variable *Dest,
85                                                Variable *Source1,
86                                                Operand *Source2)
87     : InstX86Base(Func, InstX86Base::Shrd, 3, Dest) {
88   this->addSource(Dest);
89   this->addSource(Source1);
90   this->addSource(Source2);
91 }
92 
93 template <typename TraitsType>
InstX86Label(Cfg * Func,TargetLowering * Target)94 InstImpl<TraitsType>::InstX86Label::InstX86Label(Cfg *Func,
95                                                  TargetLowering *Target)
96     : InstX86Base(Func, InstX86Base::Label, 0, nullptr),
97       LabelNumber(Target->makeNextLabelNumber()) {
98   if (BuildDefs::dump()) {
99     Name = GlobalString::createWithString(
100         Func->getContext(), ".L" + Func->getFunctionName() + "$local$__" +
101                                 std::to_string(LabelNumber));
102   } else {
103     Name = GlobalString::createWithoutString(Func->getContext());
104   }
105 }
106 
107 template <typename TraitsType>
InstX86Br(Cfg * Func,const CfgNode * TargetTrue,const CfgNode * TargetFalse,const InstX86Label * Label,BrCond Condition,Mode Kind)108 InstImpl<TraitsType>::InstX86Br::InstX86Br(Cfg *Func, const CfgNode *TargetTrue,
109                                            const CfgNode *TargetFalse,
110                                            const InstX86Label *Label,
111                                            BrCond Condition, Mode Kind)
112     : InstX86Base(Func, InstX86Base::Br, 0, nullptr), Condition(Condition),
113       TargetTrue(TargetTrue), TargetFalse(TargetFalse), Label(Label),
114       Kind(Kind) {}
115 
116 template <typename TraitsType>
optimizeBranch(const CfgNode * NextNode)117 bool InstImpl<TraitsType>::InstX86Br::optimizeBranch(const CfgNode *NextNode) {
118   // If there is no next block, then there can be no fallthrough to optimize.
119   if (NextNode == nullptr)
120     return false;
121   // Intra-block conditional branches can't be optimized.
122   if (Label)
123     return false;
124   // If there is no fallthrough node, such as a non-default case label for a
125   // switch instruction, then there is no opportunity to optimize.
126   if (getTargetFalse() == nullptr)
127     return false;
128 
129   // Unconditional branch to the next node can be removed.
130   if (Condition == Cond::Br_None && getTargetFalse() == NextNode) {
131     assert(getTargetTrue() == nullptr);
132     this->setDeleted();
133     return true;
134   }
135   // If the fallthrough is to the next node, set fallthrough to nullptr to
136   // indicate.
137   if (getTargetFalse() == NextNode) {
138     TargetFalse = nullptr;
139     return true;
140   }
141   // If TargetTrue is the next node, and TargetFalse is not nullptr (which was
142   // already tested above), then invert the branch condition, swap the targets,
143   // and set new fallthrough to nullptr.
144   if (getTargetTrue() == NextNode) {
145     assert(Condition != Cond::Br_None);
146     Condition = this->getOppositeCondition(Condition);
147     TargetTrue = getTargetFalse();
148     TargetFalse = nullptr;
149     return true;
150   }
151   return false;
152 }
153 
154 template <typename TraitsType>
repointEdges(CfgNode * OldNode,CfgNode * NewNode)155 bool InstImpl<TraitsType>::InstX86Br::repointEdges(CfgNode *OldNode,
156                                                    CfgNode *NewNode) {
157   bool Found = false;
158   if (TargetFalse == OldNode) {
159     TargetFalse = NewNode;
160     Found = true;
161   }
162   if (TargetTrue == OldNode) {
163     TargetTrue = NewNode;
164     Found = true;
165   }
166   return Found;
167 }
168 
169 template <typename TraitsType>
InstX86Jmp(Cfg * Func,Operand * Target)170 InstImpl<TraitsType>::InstX86Jmp::InstX86Jmp(Cfg *Func, Operand *Target)
171     : InstX86Base(Func, InstX86Base::Jmp, 1, nullptr) {
172   this->addSource(Target);
173 }
174 
175 template <typename TraitsType>
InstX86Call(Cfg * Func,Variable * Dest,Operand * CallTarget)176 InstImpl<TraitsType>::InstX86Call::InstX86Call(Cfg *Func, Variable *Dest,
177                                                Operand *CallTarget)
178     : InstX86Base(Func, InstX86Base::Call, 1, Dest) {
179   this->HasSideEffects = true;
180   this->addSource(CallTarget);
181 }
182 
183 template <typename TraitsType>
InstX86Movmsk(Cfg * Func,Variable * Dest,Operand * Source)184 InstImpl<TraitsType>::InstX86Movmsk::InstX86Movmsk(Cfg *Func, Variable *Dest,
185                                                    Operand *Source)
186     : InstX86Base(Func, InstX86Base::Movmsk, 1, Dest) {
187   this->addSource(Source);
188 }
189 
190 template <typename TraitsType>
InstX86Cmov(Cfg * Func,Variable * Dest,Operand * Source,BrCond Condition)191 InstImpl<TraitsType>::InstX86Cmov::InstX86Cmov(Cfg *Func, Variable *Dest,
192                                                Operand *Source,
193                                                BrCond Condition)
194     : InstX86Base(Func, InstX86Base::Cmov, 2, Dest), Condition(Condition) {
195   // The final result is either the original Dest, or Source, so mark both as
196   // sources.
197   this->addSource(Dest);
198   this->addSource(Source);
199 }
200 
201 template <typename TraitsType>
InstX86Cmpps(Cfg * Func,Variable * Dest,Operand * Source,CmppsCond Condition)202 InstImpl<TraitsType>::InstX86Cmpps::InstX86Cmpps(Cfg *Func, Variable *Dest,
203                                                  Operand *Source,
204                                                  CmppsCond Condition)
205     : InstX86Base(Func, InstX86Base::Cmpps, 2, Dest), Condition(Condition) {
206   this->addSource(Dest);
207   this->addSource(Source);
208 }
209 
210 template <typename TraitsType>
InstX86Cmpxchg(Cfg * Func,Operand * DestOrAddr,Variable * Eax,Variable * Desired,bool Locked)211 InstImpl<TraitsType>::InstX86Cmpxchg::InstX86Cmpxchg(Cfg *Func,
212                                                      Operand *DestOrAddr,
213                                                      Variable *Eax,
214                                                      Variable *Desired,
215                                                      bool Locked)
216     : InstImpl<TraitsType>::InstX86BaseLockable(
217           Func, InstX86Base::Cmpxchg, 3, llvm::dyn_cast<Variable>(DestOrAddr),
218           Locked) {
219   constexpr uint16_t Encoded_rAX = 0;
220   (void)Encoded_rAX;
221   assert(Traits::getEncodedGPR(Eax->getRegNum()) == Encoded_rAX);
222   this->addSource(DestOrAddr);
223   this->addSource(Eax);
224   this->addSource(Desired);
225 }
226 
227 template <typename TraitsType>
InstX86Cmpxchg8b(Cfg * Func,X86OperandMem * Addr,Variable * Edx,Variable * Eax,Variable * Ecx,Variable * Ebx,bool Locked)228 InstImpl<TraitsType>::InstX86Cmpxchg8b::InstX86Cmpxchg8b(
229     Cfg *Func, X86OperandMem *Addr, Variable *Edx, Variable *Eax, Variable *Ecx,
230     Variable *Ebx, bool Locked)
231     : InstImpl<TraitsType>::InstX86BaseLockable(Func, InstX86Base::Cmpxchg, 5,
232                                                 nullptr, Locked) {
233   assert(Edx->getRegNum() == RegisterSet::Reg_edx);
234   assert(Eax->getRegNum() == RegisterSet::Reg_eax);
235   assert(Ecx->getRegNum() == RegisterSet::Reg_ecx);
236   assert(Ebx->getRegNum() == RegisterSet::Reg_ebx);
237   this->addSource(Addr);
238   this->addSource(Edx);
239   this->addSource(Eax);
240   this->addSource(Ecx);
241   this->addSource(Ebx);
242 }
243 
244 template <typename TraitsType>
InstX86Cvt(Cfg * Func,Variable * Dest,Operand * Source,CvtVariant Variant)245 InstImpl<TraitsType>::InstX86Cvt::InstX86Cvt(Cfg *Func, Variable *Dest,
246                                              Operand *Source,
247                                              CvtVariant Variant)
248     : InstX86Base(Func, InstX86Base::Cvt, 1, Dest), Variant(Variant) {
249   this->addSource(Source);
250 }
251 
252 template <typename TraitsType>
InstX86Icmp(Cfg * Func,Operand * Src0,Operand * Src1)253 InstImpl<TraitsType>::InstX86Icmp::InstX86Icmp(Cfg *Func, Operand *Src0,
254                                                Operand *Src1)
255     : InstX86Base(Func, InstX86Base::Icmp, 2, nullptr) {
256   this->addSource(Src0);
257   this->addSource(Src1);
258 }
259 
260 template <typename TraitsType>
InstX86Ucomiss(Cfg * Func,Operand * Src0,Operand * Src1)261 InstImpl<TraitsType>::InstX86Ucomiss::InstX86Ucomiss(Cfg *Func, Operand *Src0,
262                                                      Operand *Src1)
263     : InstX86Base(Func, InstX86Base::Ucomiss, 2, nullptr) {
264   this->addSource(Src0);
265   this->addSource(Src1);
266 }
267 
268 template <typename TraitsType>
InstX86UD2(Cfg * Func)269 InstImpl<TraitsType>::InstX86UD2::InstX86UD2(Cfg *Func)
270     : InstX86Base(Func, InstX86Base::UD2, 0, nullptr) {}
271 
272 template <typename TraitsType>
InstX86Int3(Cfg * Func)273 InstImpl<TraitsType>::InstX86Int3::InstX86Int3(Cfg *Func)
274     : InstX86Base(Func, InstX86Base::Int3, 0, nullptr) {}
275 
276 template <typename TraitsType>
InstX86Test(Cfg * Func,Operand * Src1,Operand * Src2)277 InstImpl<TraitsType>::InstX86Test::InstX86Test(Cfg *Func, Operand *Src1,
278                                                Operand *Src2)
279     : InstX86Base(Func, InstX86Base::Test, 2, nullptr) {
280   this->addSource(Src1);
281   this->addSource(Src2);
282 }
283 
284 template <typename TraitsType>
InstX86Mfence(Cfg * Func)285 InstImpl<TraitsType>::InstX86Mfence::InstX86Mfence(Cfg *Func)
286     : InstX86Base(Func, InstX86Base::Mfence, 0, nullptr) {
287   this->HasSideEffects = true;
288 }
289 
290 template <typename TraitsType>
InstX86Store(Cfg * Func,Operand * Value,X86Operand * Mem)291 InstImpl<TraitsType>::InstX86Store::InstX86Store(Cfg *Func, Operand *Value,
292                                                  X86Operand *Mem)
293     : InstX86Base(Func, InstX86Base::Store, 2, nullptr) {
294   this->addSource(Value);
295   this->addSource(Mem);
296 }
297 
298 template <typename TraitsType>
InstX86StoreP(Cfg * Func,Variable * Value,X86OperandMem * Mem)299 InstImpl<TraitsType>::InstX86StoreP::InstX86StoreP(Cfg *Func, Variable *Value,
300                                                    X86OperandMem *Mem)
301     : InstX86Base(Func, InstX86Base::StoreP, 2, nullptr) {
302   this->addSource(Value);
303   this->addSource(Mem);
304 }
305 
306 template <typename TraitsType>
InstX86StoreQ(Cfg * Func,Operand * Value,X86OperandMem * Mem)307 InstImpl<TraitsType>::InstX86StoreQ::InstX86StoreQ(Cfg *Func, Operand *Value,
308                                                    X86OperandMem *Mem)
309     : InstX86Base(Func, InstX86Base::StoreQ, 2, nullptr) {
310   this->addSource(Value);
311   this->addSource(Mem);
312 }
313 
314 template <typename TraitsType>
InstX86StoreD(Cfg * Func,Operand * Value,X86OperandMem * Mem)315 InstImpl<TraitsType>::InstX86StoreD::InstX86StoreD(Cfg *Func, Operand *Value,
316                                                    X86OperandMem *Mem)
317     : InstX86Base(Func, InstX86Base::StoreD, 2, nullptr) {
318   this->addSource(Value);
319   this->addSource(Mem);
320 }
321 
322 template <typename TraitsType>
InstX86Nop(Cfg * Func,NopVariant Variant)323 InstImpl<TraitsType>::InstX86Nop::InstX86Nop(Cfg *Func, NopVariant Variant)
324     : InstX86Base(Func, InstX86Base::Nop, 0, nullptr), Variant(Variant) {}
325 
326 template <typename TraitsType>
InstX86Fld(Cfg * Func,Operand * Src)327 InstImpl<TraitsType>::InstX86Fld::InstX86Fld(Cfg *Func, Operand *Src)
328     : InstX86Base(Func, InstX86Base::Fld, 1, nullptr) {
329   this->addSource(Src);
330 }
331 
332 template <typename TraitsType>
InstX86Fstp(Cfg * Func,Variable * Dest)333 InstImpl<TraitsType>::InstX86Fstp::InstX86Fstp(Cfg *Func, Variable *Dest)
334     : InstX86Base(Func, InstX86Base::Fstp, 0, Dest) {}
335 
336 template <typename TraitsType>
InstX86Pop(Cfg * Func,Variable * Dest)337 InstImpl<TraitsType>::InstX86Pop::InstX86Pop(Cfg *Func, Variable *Dest)
338     : InstX86Base(Func, InstX86Base::Pop, 0, Dest) {
339   // A pop instruction affects the stack pointer and so it should not be
340   // allowed to be automatically dead-code eliminated. (The corresponding push
341   // instruction doesn't need this treatment because it has no dest variable
342   // and therefore won't be dead-code eliminated.) This is needed for
343   // late-stage liveness analysis (e.g. asm-verbose mode).
344   this->HasSideEffects = true;
345 }
346 
347 template <typename TraitsType>
InstX86Push(Cfg * Func,Operand * Source)348 InstImpl<TraitsType>::InstX86Push::InstX86Push(Cfg *Func, Operand *Source)
349     : InstX86Base(Func, InstX86Base::Push, 1, nullptr) {
350   this->addSource(Source);
351 }
352 
353 template <typename TraitsType>
InstX86Push(Cfg * Func,InstX86Label * L)354 InstImpl<TraitsType>::InstX86Push::InstX86Push(Cfg *Func, InstX86Label *L)
355     : InstX86Base(Func, InstX86Base::Push, 0, nullptr), Label(L) {}
356 
357 template <typename TraitsType>
InstX86Ret(Cfg * Func,Variable * Source)358 InstImpl<TraitsType>::InstX86Ret::InstX86Ret(Cfg *Func, Variable *Source)
359     : InstX86Base(Func, InstX86Base::Ret, Source ? 1 : 0, nullptr) {
360   if (Source)
361     this->addSource(Source);
362 }
363 
364 template <typename TraitsType>
InstX86Setcc(Cfg * Func,Variable * Dest,BrCond Cond)365 InstImpl<TraitsType>::InstX86Setcc::InstX86Setcc(Cfg *Func, Variable *Dest,
366                                                  BrCond Cond)
367     : InstX86Base(Func, InstX86Base::Setcc, 0, Dest), Condition(Cond) {}
368 
369 template <typename TraitsType>
InstX86Xadd(Cfg * Func,Operand * Dest,Variable * Source,bool Locked)370 InstImpl<TraitsType>::InstX86Xadd::InstX86Xadd(Cfg *Func, Operand *Dest,
371                                                Variable *Source, bool Locked)
372     : InstImpl<TraitsType>::InstX86BaseLockable(
373           Func, InstX86Base::Xadd, 2, llvm::dyn_cast<Variable>(Dest), Locked) {
374   this->addSource(Dest);
375   this->addSource(Source);
376 }
377 
378 template <typename TraitsType>
InstX86Xchg(Cfg * Func,Operand * Dest,Variable * Source)379 InstImpl<TraitsType>::InstX86Xchg::InstX86Xchg(Cfg *Func, Operand *Dest,
380                                                Variable *Source)
381     : InstX86Base(Func, InstX86Base::Xchg, 2, llvm::dyn_cast<Variable>(Dest)) {
382   this->addSource(Dest);
383   this->addSource(Source);
384 }
385 
386 template <typename TraitsType>
InstX86IacaStart(Cfg * Func)387 InstImpl<TraitsType>::InstX86IacaStart::InstX86IacaStart(Cfg *Func)
388     : InstX86Base(Func, InstX86Base::IacaStart, 0, nullptr) {
389   assert(getFlags().getAllowIacaMarks());
390 }
391 
392 template <typename TraitsType>
InstX86IacaEnd(Cfg * Func)393 InstImpl<TraitsType>::InstX86IacaEnd::InstX86IacaEnd(Cfg *Func)
394     : InstX86Base(Func, InstX86Base::IacaEnd, 0, nullptr) {
395   assert(getFlags().getAllowIacaMarks());
396 }
397 
398 // ======================== Dump routines ======================== //
399 
400 template <typename TraitsType>
dump(const Cfg * Func)401 void InstImpl<TraitsType>::InstX86Base::dump(const Cfg *Func) const {
402   if (!BuildDefs::dump())
403     return;
404   Ostream &Str = Func->getContext()->getStrDump();
405   Str << "[" << Traits::TargetName << "] ";
406   Inst::dump(Func);
407 }
408 
409 template <typename TraitsType>
dump(const Cfg * Func)410 void InstImpl<TraitsType>::InstX86FakeRMW::dump(const Cfg *Func) const {
411   if (!BuildDefs::dump())
412     return;
413   Ostream &Str = Func->getContext()->getStrDump();
414   Type Ty = getData()->getType();
415   Str << "rmw " << InstArithmetic::getOpName(getOp()) << " " << Ty << " *";
416   getAddr()->dump(Func);
417   Str << ", ";
418   getData()->dump(Func);
419   Str << ", beacon=";
420   getBeacon()->dump(Func);
421 }
422 
423 template <typename TraitsType>
emit(const Cfg * Func)424 void InstImpl<TraitsType>::InstX86GetIP::emit(const Cfg *Func) const {
425   if (!BuildDefs::dump())
426     return;
427   const auto *Dest = this->getDest();
428   assert(Dest->hasReg());
429   Ostream &Str = Func->getContext()->getStrEmit();
430   Str << "\t"
431          "call"
432          "\t";
433   auto *Target = static_cast<TargetLowering *>(Func->getTarget());
434   Target->emitWithoutPrefix(Target->createGetIPForRegister(Dest));
435 }
436 
437 template <typename TraitsType>
emitIAS(const Cfg * Func)438 void InstImpl<TraitsType>::InstX86GetIP::emitIAS(const Cfg *Func) const {
439   const auto *Dest = this->getDest();
440   Assembler *Asm = Func->getAssembler<Assembler>();
441   assert(Dest->hasReg());
442   Asm->call(static_cast<TargetLowering *>(Func->getTarget())
443                 ->createGetIPForRegister(Dest));
444 }
445 
446 template <typename TraitsType>
dump(const Cfg * Func)447 void InstImpl<TraitsType>::InstX86GetIP::dump(const Cfg *Func) const {
448   if (!BuildDefs::dump())
449     return;
450   Ostream &Str = Func->getContext()->getStrDump();
451   this->getDest()->dump(Func);
452   Str << " = call getIP";
453 }
454 
455 template <typename TraitsType>
emit(const Cfg * Func)456 void InstImpl<TraitsType>::InstX86Label::emit(const Cfg *Func) const {
457   if (!BuildDefs::dump())
458     return;
459   Ostream &Str = Func->getContext()->getStrEmit();
460   Str << getLabelName() << ":";
461 }
462 
463 template <typename TraitsType>
emitIAS(const Cfg * Func)464 void InstImpl<TraitsType>::InstX86Label::emitIAS(const Cfg *Func) const {
465   Assembler *Asm = Func->getAssembler<Assembler>();
466   Asm->bindLocalLabel(LabelNumber);
467   if (OffsetReloc != nullptr) {
468     Asm->bindRelocOffset(OffsetReloc);
469   }
470 }
471 
472 template <typename TraitsType>
dump(const Cfg * Func)473 void InstImpl<TraitsType>::InstX86Label::dump(const Cfg *Func) const {
474   if (!BuildDefs::dump())
475     return;
476   Ostream &Str = Func->getContext()->getStrDump();
477   Str << getLabelName() << ":";
478 }
479 
480 template <typename TraitsType>
emit(const Cfg * Func)481 void InstImpl<TraitsType>::InstX86Br::emit(const Cfg *Func) const {
482   if (!BuildDefs::dump())
483     return;
484   Ostream &Str = Func->getContext()->getStrEmit();
485   Str << "\t";
486 
487   if (Condition == Cond::Br_None) {
488     Str << "jmp";
489   } else {
490     Str << Traits::InstBrAttributes[Condition].EmitString;
491   }
492 
493   if (Label) {
494     Str << "\t" << Label->getLabelName();
495   } else {
496     if (Condition == Cond::Br_None) {
497       Str << "\t" << getTargetFalse()->getAsmName();
498     } else {
499       Str << "\t" << getTargetTrue()->getAsmName();
500       if (getTargetFalse()) {
501         Str << "\n\t"
502                "jmp\t" << getTargetFalse()->getAsmName();
503       }
504     }
505   }
506 }
507 
508 template <typename TraitsType>
emitIAS(const Cfg * Func)509 void InstImpl<TraitsType>::InstX86Br::emitIAS(const Cfg *Func) const {
510   Assembler *Asm = Func->getAssembler<Assembler>();
511   if (Label) {
512     auto *L = Asm->getOrCreateLocalLabel(Label->getLabelNumber());
513     if (Condition == Cond::Br_None) {
514       Asm->jmp(L, isNear());
515     } else {
516       Asm->j(Condition, L, isNear());
517     }
518   } else {
519     if (Condition == Cond::Br_None) {
520       auto *L = Asm->getOrCreateCfgNodeLabel(getTargetFalse()->getIndex());
521       assert(!getTargetTrue());
522       Asm->jmp(L, isNear());
523     } else {
524       auto *L = Asm->getOrCreateCfgNodeLabel(getTargetTrue()->getIndex());
525       Asm->j(Condition, L, isNear());
526       if (getTargetFalse()) {
527         auto *L2 = Asm->getOrCreateCfgNodeLabel(getTargetFalse()->getIndex());
528         Asm->jmp(L2, isNear());
529       }
530     }
531   }
532 }
533 
534 template <typename TraitsType>
dump(const Cfg * Func)535 void InstImpl<TraitsType>::InstX86Br::dump(const Cfg *Func) const {
536   if (!BuildDefs::dump())
537     return;
538   Ostream &Str = Func->getContext()->getStrDump();
539   Str << "br ";
540 
541   if (Condition == Cond::Br_None) {
542     if (Label) {
543       Str << "label %" << Label->getLabelName();
544     } else {
545       Str << "label %" << getTargetFalse()->getName();
546     }
547     return;
548   }
549 
550   Str << Traits::InstBrAttributes[Condition].DisplayString;
551   if (Label) {
552     Str << ", label %" << Label->getLabelName();
553   } else {
554     Str << ", label %" << getTargetTrue()->getName();
555     if (getTargetFalse()) {
556       Str << ", label %" << getTargetFalse()->getName();
557     }
558   }
559 
560   Str << " // (" << (isNear() ? "near" : "far") << " jump)";
561 }
562 
563 template <typename TraitsType>
emit(const Cfg * Func)564 void InstImpl<TraitsType>::InstX86Jmp::emit(const Cfg *Func) const {
565   if (!BuildDefs::dump())
566     return;
567   Ostream &Str = Func->getContext()->getStrEmit();
568   assert(this->getSrcSize() == 1);
569   const Operand *Src = this->getSrc(0);
570   if (Traits::Is64Bit) {
571     if (const auto *CR = llvm::dyn_cast<ConstantRelocatable>(Src)) {
572       Str << "\t"
573              "jmp"
574              "\t" << CR->getName();
575       return;
576     }
577   }
578   Str << "\t"
579          "jmp"
580          "\t*";
581   getJmpTarget()->emit(Func);
582 }
583 
584 template <typename TraitsType>
emitIAS(const Cfg * Func)585 void InstImpl<TraitsType>::InstX86Jmp::emitIAS(const Cfg *Func) const {
586   // Note: Adapted (mostly copied) from
587   // InstImpl<TraitsType>::InstX86Call::emitIAS().
588   Assembler *Asm = Func->getAssembler<Assembler>();
589   Operand *Target = getJmpTarget();
590   if (const auto *Var = llvm::dyn_cast<Variable>(Target)) {
591     if (Var->hasReg()) {
592       Asm->jmp(Traits::getEncodedGPR(Var->getRegNum()));
593     } else {
594       // The jmp instruction with a memory operand should be possible to
595       // encode, but it isn't a valid sandboxed instruction, and there
596       // shouldn't be a register allocation issue to jump through a scratch
597       // register, so we don't really need to bother implementing it.
598       llvm::report_fatal_error("Assembler can't jmp to memory operand");
599     }
600   } else if (const auto *Mem = llvm::dyn_cast<X86OperandMem>(Target)) {
601     (void)Mem;
602     assert(Mem->getSegmentRegister() == X86OperandMem::DefaultSegment);
603     llvm::report_fatal_error("Assembler can't jmp to memory operand");
604   } else if (const auto *CR = llvm::dyn_cast<ConstantRelocatable>(Target)) {
605     Asm->jmp(CR);
606   } else if (const auto *Imm = llvm::dyn_cast<ConstantInteger32>(Target)) {
607     // NaCl trampoline calls refer to an address within the sandbox directly.
608     // This is usually only needed for non-IRT builds and otherwise not very
609     // portable or stable. Usually this is only done for "calls" and not jumps.
610     Asm->jmp(AssemblerImmediate(Imm->getValue()));
611   } else {
612     llvm::report_fatal_error("Unexpected operand type");
613   }
614 }
615 
616 template <typename TraitsType>
dump(const Cfg * Func)617 void InstImpl<TraitsType>::InstX86Jmp::dump(const Cfg *Func) const {
618   if (!BuildDefs::dump())
619     return;
620   Ostream &Str = Func->getContext()->getStrDump();
621   Str << "jmp ";
622   getJmpTarget()->dump(Func);
623 }
624 
625 template <typename TraitsType>
emit(const Cfg * Func)626 void InstImpl<TraitsType>::InstX86Call::emit(const Cfg *Func) const {
627   if (!BuildDefs::dump())
628     return;
629   Ostream &Str = Func->getContext()->getStrEmit();
630   assert(this->getSrcSize() == 1);
631   Str << "\t"
632          "call\t";
633   Operand *CallTarget = getCallTarget();
634   auto *Target = InstX86Base::getTarget(Func);
635   if (const auto *CI = llvm::dyn_cast<ConstantInteger32>(CallTarget)) {
636     // Emit without a leading '$'.
637     Str << CI->getValue();
638   } else if (const auto DirectCallTarget =
639                  llvm::dyn_cast<ConstantRelocatable>(CallTarget)) {
640     DirectCallTarget->emitWithoutPrefix(Target);
641   } else {
642     Str << "*";
643     CallTarget->emit(Func);
644   }
645 }
646 
647 template <typename TraitsType>
emitIAS(const Cfg * Func)648 void InstImpl<TraitsType>::InstX86Call::emitIAS(const Cfg *Func) const {
649   Assembler *Asm = Func->getAssembler<Assembler>();
650   Operand *CallTarget = getCallTarget();
651   auto *Target = InstX86Base::getTarget(Func);
652   if (const auto *Var = llvm::dyn_cast<Variable>(CallTarget)) {
653     if (Var->hasReg()) {
654       Asm->call(Traits::getEncodedGPR(Var->getRegNum()));
655     } else {
656       Asm->call(Target->stackVarToAsmOperand(Var));
657     }
658   } else if (const auto *Mem = llvm::dyn_cast<X86OperandMem>(CallTarget)) {
659     assert(Mem->getSegmentRegister() == X86OperandMem::DefaultSegment);
660     Asm->call(Mem->toAsmAddress(Asm, Target));
661   } else if (const auto *CR = llvm::dyn_cast<ConstantRelocatable>(CallTarget)) {
662     Asm->call(CR);
663   } else if (const auto *Imm = llvm::dyn_cast<ConstantInteger32>(CallTarget)) {
664     Asm->call(AssemblerImmediate(Imm->getValue()));
665   } else {
666     llvm_unreachable("Unexpected operand type");
667   }
668 }
669 
670 template <typename TraitsType>
dump(const Cfg * Func)671 void InstImpl<TraitsType>::InstX86Call::dump(const Cfg *Func) const {
672   if (!BuildDefs::dump())
673     return;
674   Ostream &Str = Func->getContext()->getStrDump();
675   if (this->getDest()) {
676     this->dumpDest(Func);
677     Str << " = ";
678   }
679   Str << "call ";
680   getCallTarget()->dump(Func);
681 }
682 
683 // The this->Opcode parameter needs to be char* and not std::string because of
684 // template issues.
685 template <typename TraitsType>
emitTwoAddress(const Cfg * Func,const char * Opcode,const char * Suffix)686 void InstImpl<TraitsType>::InstX86Base::emitTwoAddress(
687     const Cfg *Func, const char *Opcode, const char *Suffix) const {
688   if (!BuildDefs::dump())
689     return;
690   Ostream &Str = Func->getContext()->getStrEmit();
691   assert(getSrcSize() == 2);
692   Operand *Dest = getDest();
693   if (Dest == nullptr)
694     Dest = getSrc(0);
695   assert(Dest == getSrc(0));
696   Operand *Src1 = getSrc(1);
697   Str << "\t" << Opcode << Suffix
698       << InstX86Base::getWidthString(Dest->getType()) << "\t";
699   Src1->emit(Func);
700   Str << ", ";
701   Dest->emit(Func);
702 }
703 
704 template <typename TraitsType>
emitIASOpTyGPR(const Cfg * Func,Type Ty,const Operand * Op,const GPREmitterOneOp & Emitter)705 void InstImpl<TraitsType>::emitIASOpTyGPR(const Cfg *Func, Type Ty,
706                                           const Operand *Op,
707                                           const GPREmitterOneOp &Emitter) {
708   auto *Target = InstX86Base::getTarget(Func);
709   Assembler *Asm = Func->getAssembler<Assembler>();
710   if (const auto *Var = llvm::dyn_cast<Variable>(Op)) {
711     if (Var->hasReg()) {
712       // We cheat a little and use GPRRegister even for byte operations.
713       GPRRegister VarReg = Traits::getEncodedGPR(Var->getRegNum());
714       (Asm->*(Emitter.Reg))(Ty, VarReg);
715     } else {
716       Address StackAddr(Target->stackVarToAsmOperand(Var));
717       (Asm->*(Emitter.Addr))(Ty, StackAddr);
718     }
719   } else if (const auto *Mem = llvm::dyn_cast<X86OperandMem>(Op)) {
720     Mem->emitSegmentOverride(Asm);
721     (Asm->*(Emitter.Addr))(Ty, Mem->toAsmAddress(Asm, Target));
722   } else {
723     llvm_unreachable("Unexpected operand type");
724   }
725 }
726 
727 template <typename TraitsType>
728 template <bool VarCanBeByte, bool SrcCanBeByte>
emitIASRegOpTyGPR(const Cfg * Func,bool IsLea,Type Ty,const Variable * Var,const Operand * Src,const GPREmitterRegOp & Emitter)729 void InstImpl<TraitsType>::emitIASRegOpTyGPR(const Cfg *Func, bool IsLea,
730                                              Type Ty, const Variable *Var,
731                                              const Operand *Src,
732                                              const GPREmitterRegOp &Emitter) {
733   auto *Target = InstX86Base::getTarget(Func);
734   Assembler *Asm = Func->getAssembler<Assembler>();
735   assert(Var->hasReg());
736   // We cheat a little and use GPRRegister even for byte operations.
737   GPRRegister VarReg = VarCanBeByte ? Traits::getEncodedGPR(Var->getRegNum())
738                                     : Traits::getEncodedGPR(Var->getRegNum());
739   if (const auto *SrcVar = llvm::dyn_cast<Variable>(Src)) {
740     if (SrcVar->hasReg()) {
741       GPRRegister SrcReg = SrcCanBeByte
742                                ? Traits::getEncodedGPR(SrcVar->getRegNum())
743                                : Traits::getEncodedGPR(SrcVar->getRegNum());
744       (Asm->*(Emitter.GPRGPR))(Ty, VarReg, SrcReg);
745     } else {
746       Address SrcStackAddr = Target->stackVarToAsmOperand(SrcVar);
747       (Asm->*(Emitter.GPRAddr))(Ty, VarReg, SrcStackAddr);
748     }
749   } else if (const auto *Mem = llvm::dyn_cast<X86OperandMem>(Src)) {
750     Mem->emitSegmentOverride(Asm);
751     (Asm->*(Emitter.GPRAddr))(Ty, VarReg,
752                               Mem->toAsmAddress(Asm, Target, IsLea));
753   } else if (const auto *Imm = llvm::dyn_cast<ConstantInteger32>(Src)) {
754     (Asm->*(Emitter.GPRImm))(Ty, VarReg, AssemblerImmediate(Imm->getValue()));
755   } else if (const auto *Imm = llvm::dyn_cast<ConstantInteger64>(Src)) {
756     assert(Traits::Is64Bit);
757     assert(Utils::IsInt(32, Imm->getValue()));
758     (Asm->*(Emitter.GPRImm))(Ty, VarReg, AssemblerImmediate(Imm->getValue()));
759   } else if (const auto *Reloc = llvm::dyn_cast<ConstantRelocatable>(Src)) {
760     const auto FixupKind = (Reloc->getName().hasStdString() &&
761                             Reloc->getName().toString() == GlobalOffsetTable)
762                                ? Traits::FK_GotPC
763                                : Traits::TargetLowering::getAbsFixup();
764     AssemblerFixup *Fixup = Asm->createFixup(FixupKind, Reloc);
765     (Asm->*(Emitter.GPRImm))(Ty, VarReg, AssemblerImmediate(Fixup));
766   } else if (const auto *Split = llvm::dyn_cast<VariableSplit>(Src)) {
767     (Asm->*(Emitter.GPRAddr))(Ty, VarReg, Split->toAsmAddress(Func));
768   } else {
769     llvm_unreachable("Unexpected operand type");
770   }
771 }
772 
773 template <typename TraitsType>
emitIASAddrOpTyGPR(const Cfg * Func,Type Ty,const Address & Addr,const Operand * Src,const GPREmitterAddrOp & Emitter)774 void InstImpl<TraitsType>::emitIASAddrOpTyGPR(const Cfg *Func, Type Ty,
775                                               const Address &Addr,
776                                               const Operand *Src,
777                                               const GPREmitterAddrOp &Emitter) {
778   Assembler *Asm = Func->getAssembler<Assembler>();
779   // Src can only be Reg or AssemblerImmediate.
780   if (const auto *SrcVar = llvm::dyn_cast<Variable>(Src)) {
781     assert(SrcVar->hasReg());
782     GPRRegister SrcReg = Traits::getEncodedGPR(SrcVar->getRegNum());
783     (Asm->*(Emitter.AddrGPR))(Ty, Addr, SrcReg);
784   } else if (const auto *Imm = llvm::dyn_cast<ConstantInteger32>(Src)) {
785     (Asm->*(Emitter.AddrImm))(Ty, Addr, AssemblerImmediate(Imm->getValue()));
786   } else if (const auto *Imm = llvm::dyn_cast<ConstantInteger64>(Src)) {
787     assert(Traits::Is64Bit);
788     assert(Utils::IsInt(32, Imm->getValue()));
789     (Asm->*(Emitter.AddrImm))(Ty, Addr, AssemblerImmediate(Imm->getValue()));
790   } else if (const auto *Reloc = llvm::dyn_cast<ConstantRelocatable>(Src)) {
791     const auto FixupKind = (Reloc->getName().hasStdString() &&
792                             Reloc->getName().toString() == GlobalOffsetTable)
793                                ? Traits::FK_GotPC
794                                : Traits::TargetLowering::getAbsFixup();
795     AssemblerFixup *Fixup = Asm->createFixup(FixupKind, Reloc);
796     (Asm->*(Emitter.AddrImm))(Ty, Addr, AssemblerImmediate(Fixup));
797   } else {
798     llvm_unreachable("Unexpected operand type");
799   }
800 }
801 
802 template <typename TraitsType>
emitIASAsAddrOpTyGPR(const Cfg * Func,Type Ty,const Operand * Op0,const Operand * Op1,const GPREmitterAddrOp & Emitter)803 void InstImpl<TraitsType>::emitIASAsAddrOpTyGPR(
804     const Cfg *Func, Type Ty, const Operand *Op0, const Operand *Op1,
805     const GPREmitterAddrOp &Emitter) {
806   auto *Target = InstX86Base::getTarget(Func);
807   if (const auto *Op0Var = llvm::dyn_cast<Variable>(Op0)) {
808     assert(!Op0Var->hasReg());
809     Address StackAddr(Target->stackVarToAsmOperand(Op0Var));
810     emitIASAddrOpTyGPR(Func, Ty, StackAddr, Op1, Emitter);
811   } else if (const auto *Op0Mem = llvm::dyn_cast<X86OperandMem>(Op0)) {
812     Assembler *Asm = Func->getAssembler<Assembler>();
813     Op0Mem->emitSegmentOverride(Asm);
814     emitIASAddrOpTyGPR(Func, Ty, Op0Mem->toAsmAddress(Asm, Target), Op1,
815                        Emitter);
816   } else if (const auto *Split = llvm::dyn_cast<VariableSplit>(Op0)) {
817     emitIASAddrOpTyGPR(Func, Ty, Split->toAsmAddress(Func), Op1, Emitter);
818   } else {
819     llvm_unreachable("Unexpected operand type");
820   }
821 }
822 
823 template <typename TraitsType>
emitIASGPRShift(const Cfg * Func,Type Ty,const Variable * Var,const Operand * Src,const GPREmitterShiftOp & Emitter)824 void InstImpl<TraitsType>::emitIASGPRShift(const Cfg *Func, Type Ty,
825                                            const Variable *Var,
826                                            const Operand *Src,
827                                            const GPREmitterShiftOp &Emitter) {
828   Assembler *Asm = Func->getAssembler<Assembler>();
829   // Technically, the Dest Var can be mem as well, but we only use Reg. We can
830   // extend this to check Dest if we decide to use that form.
831   assert(Var->hasReg());
832   // We cheat a little and use GPRRegister even for byte operations.
833   GPRRegister VarReg = Traits::getEncodedGPR(Var->getRegNum());
834   // Src must be reg == ECX or an Imm8. This is asserted by the assembler.
835   if (const auto *SrcVar = llvm::dyn_cast<Variable>(Src)) {
836     assert(SrcVar->hasReg());
837     GPRRegister SrcReg = Traits::getEncodedGPR(SrcVar->getRegNum());
838     (Asm->*(Emitter.GPRGPR))(Ty, VarReg, SrcReg);
839   } else if (const auto *Imm = llvm::dyn_cast<ConstantInteger32>(Src)) {
840     (Asm->*(Emitter.GPRImm))(Ty, VarReg, AssemblerImmediate(Imm->getValue()));
841   } else if (const auto *Imm = llvm::dyn_cast<ConstantInteger64>(Src)) {
842     assert(Traits::Is64Bit);
843     assert(Utils::IsInt(32, Imm->getValue()));
844     (Asm->*(Emitter.GPRImm))(Ty, VarReg, AssemblerImmediate(Imm->getValue()));
845   } else {
846     llvm_unreachable("Unexpected operand type");
847   }
848 }
849 
850 template <typename TraitsType>
emitIASGPRShiftDouble(const Cfg * Func,const Variable * Dest,const Operand * Src1Op,const Operand * Src2Op,const GPREmitterShiftD & Emitter)851 void InstImpl<TraitsType>::emitIASGPRShiftDouble(
852     const Cfg *Func, const Variable *Dest, const Operand *Src1Op,
853     const Operand *Src2Op, const GPREmitterShiftD &Emitter) {
854   Assembler *Asm = Func->getAssembler<Assembler>();
855   // Dest can be reg or mem, but we only use the reg variant.
856   assert(Dest->hasReg());
857   GPRRegister DestReg = Traits::getEncodedGPR(Dest->getRegNum());
858   // SrcVar1 must be reg.
859   const auto *SrcVar1 = llvm::cast<Variable>(Src1Op);
860   assert(SrcVar1->hasReg());
861   GPRRegister SrcReg = Traits::getEncodedGPR(SrcVar1->getRegNum());
862   Type Ty = SrcVar1->getType();
863   // Src2 can be the implicit CL register or an immediate.
864   if (const auto *Imm = llvm::dyn_cast<ConstantInteger32>(Src2Op)) {
865     (Asm->*(Emitter.GPRGPRImm))(Ty, DestReg, SrcReg,
866                                 AssemblerImmediate(Imm->getValue()));
867   } else {
868     assert(llvm::cast<Variable>(Src2Op)->getRegNum() == RegisterSet::Reg_cl);
869     (Asm->*(Emitter.GPRGPR))(Ty, DestReg, SrcReg);
870   }
871 }
872 
873 template <typename TraitsType>
emitIASXmmShift(const Cfg * Func,Type Ty,const Variable * Var,const Operand * Src,const XmmEmitterShiftOp & Emitter)874 void InstImpl<TraitsType>::emitIASXmmShift(const Cfg *Func, Type Ty,
875                                            const Variable *Var,
876                                            const Operand *Src,
877                                            const XmmEmitterShiftOp &Emitter) {
878   auto *Target = InstX86Base::getTarget(Func);
879   Assembler *Asm = Func->getAssembler<Assembler>();
880   assert(Var->hasReg());
881   XmmRegister VarReg = Traits::getEncodedXmm(Var->getRegNum());
882   if (const auto *SrcVar = llvm::dyn_cast<Variable>(Src)) {
883     if (SrcVar->hasReg()) {
884       XmmRegister SrcReg = Traits::getEncodedXmm(SrcVar->getRegNum());
885       (Asm->*(Emitter.XmmXmm))(Ty, VarReg, SrcReg);
886     } else {
887       Address SrcStackAddr = Target->stackVarToAsmOperand(SrcVar);
888       (Asm->*(Emitter.XmmAddr))(Ty, VarReg, SrcStackAddr);
889     }
890   } else if (const auto *Mem = llvm::dyn_cast<X86OperandMem>(Src)) {
891     assert(Mem->getSegmentRegister() == X86OperandMem::DefaultSegment);
892     (Asm->*(Emitter.XmmAddr))(Ty, VarReg, Mem->toAsmAddress(Asm, Target));
893   } else if (const auto *Imm = llvm::dyn_cast<ConstantInteger32>(Src)) {
894     (Asm->*(Emitter.XmmImm))(Ty, VarReg, AssemblerImmediate(Imm->getValue()));
895   } else {
896     llvm_unreachable("Unexpected operand type");
897   }
898 }
899 
900 template <typename TraitsType>
emitIASRegOpTyXMM(const Cfg * Func,Type Ty,const Variable * Var,const Operand * Src,const XmmEmitterRegOp & Emitter)901 void InstImpl<TraitsType>::emitIASRegOpTyXMM(const Cfg *Func, Type Ty,
902                                              const Variable *Var,
903                                              const Operand *Src,
904                                              const XmmEmitterRegOp &Emitter) {
905   auto *Target = InstX86Base::getTarget(Func);
906   Assembler *Asm = Func->getAssembler<Assembler>();
907   assert(Var->hasReg());
908   XmmRegister VarReg = Traits::getEncodedXmm(Var->getRegNum());
909   if (const auto *SrcVar = llvm::dyn_cast<Variable>(Src)) {
910     if (SrcVar->hasReg()) {
911       XmmRegister SrcReg = Traits::getEncodedXmm(SrcVar->getRegNum());
912       (Asm->*(Emitter.XmmXmm))(Ty, VarReg, SrcReg);
913     } else {
914       Address SrcStackAddr = Target->stackVarToAsmOperand(SrcVar);
915       (Asm->*(Emitter.XmmAddr))(Ty, VarReg, SrcStackAddr);
916     }
917   } else if (const auto *Mem = llvm::dyn_cast<X86OperandMem>(Src)) {
918     assert(Mem->getSegmentRegister() == X86OperandMem::DefaultSegment);
919     (Asm->*(Emitter.XmmAddr))(Ty, VarReg, Mem->toAsmAddress(Asm, Target));
920   } else if (const auto *Imm = llvm::dyn_cast<Constant>(Src)) {
921     (Asm->*(Emitter.XmmAddr))(Ty, VarReg,
922                               Traits::Address::ofConstPool(Asm, Imm));
923   } else {
924     llvm_unreachable("Unexpected operand type");
925   }
926 }
927 
928 template <typename TraitsType>
929 template <typename DReg_t, typename SReg_t, DReg_t (*destEnc)(RegNumT),
930           SReg_t (*srcEnc)(RegNumT)>
emitIASCastRegOp(const Cfg * Func,Type DestTy,const Variable * Dest,Type SrcTy,const Operand * Src,const CastEmitterRegOp<DReg_t,SReg_t> & Emitter)931 void InstImpl<TraitsType>::emitIASCastRegOp(
932     const Cfg *Func, Type DestTy, const Variable *Dest, Type SrcTy,
933     const Operand *Src, const CastEmitterRegOp<DReg_t, SReg_t> &Emitter) {
934   auto *Target = InstX86Base::getTarget(Func);
935   Assembler *Asm = Func->getAssembler<Assembler>();
936   assert(Dest->hasReg());
937   DReg_t DestReg = destEnc(Dest->getRegNum());
938   if (const auto *SrcVar = llvm::dyn_cast<Variable>(Src)) {
939     if (SrcVar->hasReg()) {
940       SReg_t SrcReg = srcEnc(SrcVar->getRegNum());
941       (Asm->*(Emitter.RegReg))(DestTy, DestReg, SrcTy, SrcReg);
942     } else {
943       Address SrcStackAddr = Target->stackVarToAsmOperand(SrcVar);
944       (Asm->*(Emitter.RegAddr))(DestTy, DestReg, SrcTy, SrcStackAddr);
945     }
946   } else if (const auto *Mem = llvm::dyn_cast<X86OperandMem>(Src)) {
947     Mem->emitSegmentOverride(Asm);
948     (Asm->*(Emitter.RegAddr))(DestTy, DestReg, SrcTy,
949                               Mem->toAsmAddress(Asm, Target));
950   } else {
951     llvm_unreachable("Unexpected operand type");
952   }
953 }
954 
955 template <typename TraitsType>
956 template <typename DReg_t, typename SReg_t, DReg_t (*destEnc)(RegNumT),
957           SReg_t (*srcEnc)(RegNumT)>
emitIASThreeOpImmOps(const Cfg * Func,Type DispatchTy,const Variable * Dest,const Operand * Src0,const Operand * Src1,const ThreeOpImmEmitter<DReg_t,SReg_t> Emitter)958 void InstImpl<TraitsType>::emitIASThreeOpImmOps(
959     const Cfg *Func, Type DispatchTy, const Variable *Dest, const Operand *Src0,
960     const Operand *Src1, const ThreeOpImmEmitter<DReg_t, SReg_t> Emitter) {
961   auto *Target = InstX86Base::getTarget(Func);
962   Assembler *Asm = Func->getAssembler<Assembler>();
963   // This only handles Dest being a register, and Src1 being an immediate.
964   assert(Dest->hasReg());
965   DReg_t DestReg = destEnc(Dest->getRegNum());
966   AssemblerImmediate Imm(llvm::cast<ConstantInteger32>(Src1)->getValue());
967   if (const auto *SrcVar = llvm::dyn_cast<Variable>(Src0)) {
968     if (SrcVar->hasReg()) {
969       SReg_t SrcReg = srcEnc(SrcVar->getRegNum());
970       (Asm->*(Emitter.RegRegImm))(DispatchTy, DestReg, SrcReg, Imm);
971     } else {
972       Address SrcStackAddr = Target->stackVarToAsmOperand(SrcVar);
973       (Asm->*(Emitter.RegAddrImm))(DispatchTy, DestReg, SrcStackAddr, Imm);
974     }
975   } else if (const auto *Mem = llvm::dyn_cast<X86OperandMem>(Src0)) {
976     Mem->emitSegmentOverride(Asm);
977     (Asm->*(Emitter.RegAddrImm))(DispatchTy, DestReg,
978                                  Mem->toAsmAddress(Asm, Target), Imm);
979   } else {
980     llvm_unreachable("Unexpected operand type");
981   }
982 }
983 
984 template <typename TraitsType>
emitIASMovlikeXMM(const Cfg * Func,const Variable * Dest,const Operand * Src,const XmmEmitterMovOps Emitter)985 void InstImpl<TraitsType>::emitIASMovlikeXMM(const Cfg *Func,
986                                              const Variable *Dest,
987                                              const Operand *Src,
988                                              const XmmEmitterMovOps Emitter) {
989   auto *Target = InstX86Base::getTarget(Func);
990   Assembler *Asm = Func->getAssembler<Assembler>();
991   if (Dest->hasReg()) {
992     XmmRegister DestReg = Traits::getEncodedXmm(Dest->getRegNum());
993     if (const auto *SrcVar = llvm::dyn_cast<Variable>(Src)) {
994       if (SrcVar->hasReg()) {
995         (Asm->*(Emitter.XmmXmm))(DestReg,
996                                  Traits::getEncodedXmm(SrcVar->getRegNum()));
997       } else {
998         Address StackAddr(Target->stackVarToAsmOperand(SrcVar));
999         (Asm->*(Emitter.XmmAddr))(DestReg, StackAddr);
1000       }
1001     } else if (const auto *SrcMem = llvm::dyn_cast<X86OperandMem>(Src)) {
1002       assert(SrcMem->getSegmentRegister() == X86OperandMem::DefaultSegment);
1003       (Asm->*(Emitter.XmmAddr))(DestReg, SrcMem->toAsmAddress(Asm, Target));
1004     } else {
1005       llvm_unreachable("Unexpected operand type");
1006     }
1007   } else {
1008     Address StackAddr(Target->stackVarToAsmOperand(Dest));
1009     // Src must be a register in this case.
1010     const auto *SrcVar = llvm::cast<Variable>(Src);
1011     assert(SrcVar->hasReg());
1012     (Asm->*(Emitter.AddrXmm))(StackAddr,
1013                               Traits::getEncodedXmm(SrcVar->getRegNum()));
1014   }
1015 }
1016 
1017 template <typename TraitsType>
dump(const Cfg * Func)1018 void InstImpl<TraitsType>::InstX86Movmsk::dump(const Cfg *Func) const {
1019   if (!BuildDefs::dump())
1020     return;
1021   Ostream &Str = Func->getContext()->getStrDump();
1022   this->dumpDest(Func);
1023   Str << " = movmsk." << this->getSrc(0)->getType() << " ";
1024   this->dumpSources(Func);
1025 }
1026 
1027 template <typename TraitsType>
emit(const Cfg * Func)1028 void InstImpl<TraitsType>::InstX86Movmsk::emit(const Cfg *Func) const {
1029   if (!BuildDefs::dump())
1030     return;
1031   Ostream &Str = Func->getContext()->getStrEmit();
1032   assert(this->getSrcSize() == 1);
1033   Type SrcTy = this->getSrc(0)->getType();
1034   assert(isVectorType(SrcTy));
1035   switch (SrcTy) {
1036   case IceType_v16i8:
1037     Str << "\t"
1038            "pmovmskb"
1039            "\t";
1040     break;
1041   case IceType_v4i32:
1042   case IceType_v4f32:
1043     Str << "\t"
1044            "movmskps"
1045            "\t";
1046     break;
1047   default:
1048     llvm_unreachable("Unexpected operand type");
1049   }
1050   this->getSrc(0)->emit(Func);
1051   Str << ", ";
1052   this->getDest()->emit(Func);
1053 }
1054 
1055 template <typename TraitsType>
emitIAS(const Cfg * Func)1056 void InstImpl<TraitsType>::InstX86Movmsk::emitIAS(const Cfg *Func) const {
1057   assert(this->getSrcSize() == 1);
1058   Assembler *Asm = Func->getAssembler<Assembler>();
1059   const Variable *Dest = this->getDest();
1060   const Variable *Src = llvm::cast<Variable>(this->getSrc(0));
1061   const Type DestTy = Dest->getType();
1062   (void)DestTy;
1063   const Type SrcTy = Src->getType();
1064   assert(isVectorType(SrcTy));
1065   assert(isScalarIntegerType(DestTy));
1066   if (Traits::Is64Bit) {
1067     assert(DestTy == IceType_i32 || DestTy == IceType_i64);
1068   } else {
1069     assert(typeWidthInBytes(DestTy) <= 4);
1070   }
1071   XmmRegister SrcReg = Traits::getEncodedXmm(Src->getRegNum());
1072   GPRRegister DestReg = Traits::getEncodedGPR(Dest->getRegNum());
1073   Asm->movmsk(SrcTy, DestReg, SrcReg);
1074 }
1075 
1076 template <typename TraitsType>
emit(const Cfg * Func)1077 void InstImpl<TraitsType>::InstX86Sqrt::emit(const Cfg *Func) const {
1078   if (!BuildDefs::dump())
1079     return;
1080   Ostream &Str = Func->getContext()->getStrEmit();
1081   assert(this->getSrcSize() == 1);
1082   Type Ty = this->getSrc(0)->getType();
1083   assert(isScalarFloatingType(Ty));
1084   Str << "\t"
1085          "sqrt" << Traits::TypeAttributes[Ty].SpSdString << "\t";
1086   this->getSrc(0)->emit(Func);
1087   Str << ", ";
1088   this->getDest()->emit(Func);
1089 }
1090 
1091 template <typename TraitsType>
emit(const Cfg * Func)1092 void InstImpl<TraitsType>::InstX86Div::emit(const Cfg *Func) const {
1093   if (!BuildDefs::dump())
1094     return;
1095   Ostream &Str = Func->getContext()->getStrEmit();
1096   assert(this->getSrcSize() == 3);
1097   Operand *Src1 = this->getSrc(1);
1098   Str << "\t" << this->Opcode << this->getWidthString(Src1->getType()) << "\t";
1099   Src1->emit(Func);
1100 }
1101 
1102 template <typename TraitsType>
emitIAS(const Cfg * Func)1103 void InstImpl<TraitsType>::InstX86Div::emitIAS(const Cfg *Func) const {
1104   assert(this->getSrcSize() == 3);
1105   const Operand *Src = this->getSrc(1);
1106   Type Ty = Src->getType();
1107   static GPREmitterOneOp Emitter = {&Assembler::div, &Assembler::div};
1108   emitIASOpTyGPR(Func, Ty, Src, Emitter);
1109 }
1110 
1111 template <typename TraitsType>
emit(const Cfg * Func)1112 void InstImpl<TraitsType>::InstX86Idiv::emit(const Cfg *Func) const {
1113   if (!BuildDefs::dump())
1114     return;
1115   Ostream &Str = Func->getContext()->getStrEmit();
1116   assert(this->getSrcSize() == 3);
1117   Operand *Src1 = this->getSrc(1);
1118   Str << "\t" << this->Opcode << this->getWidthString(Src1->getType()) << "\t";
1119   Src1->emit(Func);
1120 }
1121 
1122 template <typename TraitsType>
emitIAS(const Cfg * Func)1123 void InstImpl<TraitsType>::InstX86Idiv::emitIAS(const Cfg *Func) const {
1124   assert(this->getSrcSize() == 3);
1125   const Operand *Src = this->getSrc(1);
1126   Type Ty = Src->getType();
1127   static const GPREmitterOneOp Emitter = {&Assembler::idiv, &Assembler::idiv};
1128   emitIASOpTyGPR(Func, Ty, Src, Emitter);
1129 }
1130 
1131 // pblendvb and blendvps take xmm0 as a final implicit argument.
1132 template <typename TraitsType>
emitVariableBlendInst(const char * Opcode,const Inst * Instr,const Cfg * Func)1133 void InstImpl<TraitsType>::emitVariableBlendInst(const char *Opcode,
1134                                                  const Inst *Instr,
1135                                                  const Cfg *Func) {
1136   if (!BuildDefs::dump())
1137     return;
1138   Ostream &Str = Func->getContext()->getStrEmit();
1139   assert(Instr->getSrcSize() == 3);
1140   assert(llvm::cast<Variable>(Instr->getSrc(2))->getRegNum() ==
1141          RegisterSet::Reg_xmm0);
1142   Str << "\t" << Opcode << "\t";
1143   Instr->getSrc(1)->emit(Func);
1144   Str << ", ";
1145   Instr->getDest()->emit(Func);
1146 }
1147 
1148 template <typename TraitsType>
emitIASVariableBlendInst(const Inst * Instr,const Cfg * Func,const XmmEmitterRegOp & Emitter)1149 void InstImpl<TraitsType>::emitIASVariableBlendInst(
1150     const Inst *Instr, const Cfg *Func, const XmmEmitterRegOp &Emitter) {
1151   assert(Instr->getSrcSize() == 3);
1152   assert(llvm::cast<Variable>(Instr->getSrc(2))->getRegNum() ==
1153          RegisterSet::Reg_xmm0);
1154   const Variable *Dest = Instr->getDest();
1155   const Operand *Src = Instr->getSrc(1);
1156   emitIASRegOpTyXMM(Func, Dest->getType(), Dest, Src, Emitter);
1157 }
1158 
1159 template <typename TraitsType>
emit(const Cfg * Func)1160 void InstImpl<TraitsType>::InstX86Blendvps::emit(const Cfg *Func) const {
1161   if (!BuildDefs::dump())
1162     return;
1163   emitVariableBlendInst(this->Opcode, this, Func);
1164 }
1165 
1166 template <typename TraitsType>
emitIAS(const Cfg * Func)1167 void InstImpl<TraitsType>::InstX86Blendvps::emitIAS(const Cfg *Func) const {
1168   static const XmmEmitterRegOp Emitter = {&Assembler::blendvps,
1169                                           &Assembler::blendvps};
1170   emitIASVariableBlendInst(this, Func, Emitter);
1171 }
1172 
1173 template <typename TraitsType>
emit(const Cfg * Func)1174 void InstImpl<TraitsType>::InstX86Pblendvb::emit(const Cfg *Func) const {
1175   if (!BuildDefs::dump())
1176     return;
1177   emitVariableBlendInst(this->Opcode, this, Func);
1178 }
1179 
1180 template <typename TraitsType>
emitIAS(const Cfg * Func)1181 void InstImpl<TraitsType>::InstX86Pblendvb::emitIAS(const Cfg *Func) const {
1182   static const XmmEmitterRegOp Emitter = {&Assembler::pblendvb,
1183                                           &Assembler::pblendvb};
1184   emitIASVariableBlendInst(this, Func, Emitter);
1185 }
1186 
1187 template <typename TraitsType>
emit(const Cfg * Func)1188 void InstImpl<TraitsType>::InstX86Imul::emit(const Cfg *Func) const {
1189   if (!BuildDefs::dump())
1190     return;
1191   Ostream &Str = Func->getContext()->getStrEmit();
1192   assert(this->getSrcSize() == 2);
1193   Variable *Dest = this->getDest();
1194   if (isByteSizedArithType(Dest->getType())) {
1195     // The 8-bit version of imul only allows the form "imul r/m8".
1196     const auto *Src0Var = llvm::dyn_cast<Variable>(this->getSrc(0));
1197     (void)Src0Var;
1198     assert(Src0Var->getRegNum() == RegisterSet::Reg_al);
1199     Str << "\t"
1200            "imulb\t";
1201     this->getSrc(1)->emit(Func);
1202   } else if (llvm::isa<Constant>(this->getSrc(1))) {
1203     Str << "\t"
1204            "imul" << this->getWidthString(Dest->getType()) << "\t";
1205     this->getSrc(1)->emit(Func);
1206     Str << ", ";
1207     this->getSrc(0)->emit(Func);
1208     Str << ", ";
1209     Dest->emit(Func);
1210   } else {
1211     this->emitTwoAddress(Func, this->Opcode);
1212   }
1213 }
1214 
1215 template <typename TraitsType>
emitIAS(const Cfg * Func)1216 void InstImpl<TraitsType>::InstX86Imul::emitIAS(const Cfg *Func) const {
1217   assert(this->getSrcSize() == 2);
1218   const Variable *Var = this->getDest();
1219   Type Ty = Var->getType();
1220   const Operand *Src = this->getSrc(1);
1221   if (isByteSizedArithType(Ty)) {
1222     // The 8-bit version of imul only allows the form "imul r/m8".
1223     const auto *Src0Var = llvm::dyn_cast<Variable>(this->getSrc(0));
1224     (void)Src0Var;
1225     assert(Src0Var->getRegNum() == RegisterSet::Reg_al);
1226     static const GPREmitterOneOp Emitter = {&Assembler::imul, &Assembler::imul};
1227     emitIASOpTyGPR(Func, Ty, this->getSrc(1), Emitter);
1228   } else {
1229     // The two-address version is used when multiplying by a non-constant
1230     // or doing an 8-bit multiply.
1231     assert(Var == this->getSrc(0));
1232     static const GPREmitterRegOp Emitter = {&Assembler::imul, &Assembler::imul,
1233                                             &Assembler::imul};
1234     constexpr bool NotLea = false;
1235     emitIASRegOpTyGPR(Func, NotLea, Ty, Var, Src, Emitter);
1236   }
1237 }
1238 
1239 template <typename TraitsType>
emit(const Cfg * Func)1240 void InstImpl<TraitsType>::InstX86ImulImm::emit(const Cfg *Func) const {
1241   if (!BuildDefs::dump())
1242     return;
1243   Ostream &Str = Func->getContext()->getStrEmit();
1244   assert(this->getSrcSize() == 2);
1245   Variable *Dest = this->getDest();
1246   assert(Dest->getType() == IceType_i16 || Dest->getType() == IceType_i32);
1247   assert(llvm::isa<Constant>(this->getSrc(1)));
1248   Str << "\t"
1249          "imul" << this->getWidthString(Dest->getType()) << "\t";
1250   this->getSrc(1)->emit(Func);
1251   Str << ", ";
1252   this->getSrc(0)->emit(Func);
1253   Str << ", ";
1254   Dest->emit(Func);
1255 }
1256 
1257 template <typename TraitsType>
emitIAS(const Cfg * Func)1258 void InstImpl<TraitsType>::InstX86ImulImm::emitIAS(const Cfg *Func) const {
1259   assert(this->getSrcSize() == 2);
1260   const Variable *Dest = this->getDest();
1261   Type Ty = Dest->getType();
1262   assert(llvm::isa<Constant>(this->getSrc(1)));
1263   static const ThreeOpImmEmitter<GPRRegister, GPRRegister> Emitter = {
1264       &Assembler::imul, &Assembler::imul};
1265   emitIASThreeOpImmOps<GPRRegister, GPRRegister, Traits::getEncodedGPR,
1266                        Traits::getEncodedGPR>(Func, Ty, Dest, this->getSrc(0),
1267                                               this->getSrc(1), Emitter);
1268 }
1269 
1270 template <typename TraitsType>
emitIAS(const Cfg * Func)1271 void InstImpl<TraitsType>::InstX86Insertps::emitIAS(const Cfg *Func) const {
1272   assert(this->getSrcSize() == 3);
1273   assert(InstX86Base::getTarget(Func)->getInstructionSet() >= Traits::SSE4_1);
1274   const Variable *Dest = this->getDest();
1275   assert(Dest == this->getSrc(0));
1276   Type Ty = Dest->getType();
1277   static const ThreeOpImmEmitter<XmmRegister, XmmRegister> Emitter = {
1278       &Assembler::insertps, &Assembler::insertps};
1279   emitIASThreeOpImmOps<XmmRegister, XmmRegister, Traits::getEncodedXmm,
1280                        Traits::getEncodedXmm>(Func, Ty, Dest, this->getSrc(1),
1281                                               this->getSrc(2), Emitter);
1282 }
1283 
1284 template <typename TraitsType>
emit(const Cfg * Func)1285 void InstImpl<TraitsType>::InstX86Cbwdq::emit(const Cfg *Func) const {
1286   if (!BuildDefs::dump())
1287     return;
1288   Ostream &Str = Func->getContext()->getStrEmit();
1289   assert(this->getSrcSize() == 1);
1290   Operand *Src0 = this->getSrc(0);
1291   const auto DestReg = this->getDest()->getRegNum();
1292   const auto SrcReg = llvm::cast<Variable>(Src0)->getRegNum();
1293   (void)DestReg;
1294   (void)SrcReg;
1295   switch (Src0->getType()) {
1296   default:
1297     llvm_unreachable("unexpected source type!");
1298     break;
1299   case IceType_i8:
1300     assert(SrcReg == RegisterSet::Reg_al);
1301     assert(DestReg == RegisterSet::Reg_ax || DestReg == RegisterSet::Reg_ah);
1302     Str << "\t"
1303            "cbtw";
1304     break;
1305   case IceType_i16:
1306     assert(SrcReg == RegisterSet::Reg_ax);
1307     assert(DestReg == RegisterSet::Reg_dx);
1308     Str << "\t"
1309            "cwtd";
1310     break;
1311   case IceType_i32:
1312     assert(SrcReg == RegisterSet::Reg_eax);
1313     assert(DestReg == RegisterSet::Reg_edx);
1314     Str << "\t"
1315            "cltd";
1316     break;
1317   case IceType_i64:
1318     assert(Traits::Is64Bit);
1319     assert(SrcReg == Traits::getRaxOrDie());
1320     assert(DestReg == Traits::getRdxOrDie());
1321     Str << "\t"
1322            "cqo";
1323     break;
1324   }
1325 }
1326 
1327 template <typename TraitsType>
emitIAS(const Cfg * Func)1328 void InstImpl<TraitsType>::InstX86Cbwdq::emitIAS(const Cfg *Func) const {
1329   Assembler *Asm = Func->getAssembler<Assembler>();
1330   assert(this->getSrcSize() == 1);
1331   Operand *Src0 = this->getSrc(0);
1332   const auto DestReg = this->getDest()->getRegNum();
1333   const auto SrcReg = llvm::cast<Variable>(Src0)->getRegNum();
1334   (void)DestReg;
1335   (void)SrcReg;
1336   switch (Src0->getType()) {
1337   default:
1338     llvm_unreachable("unexpected source type!");
1339     break;
1340   case IceType_i8:
1341     assert(SrcReg == RegisterSet::Reg_al);
1342     assert(DestReg == RegisterSet::Reg_ax || DestReg == RegisterSet::Reg_ah);
1343     Asm->cbw();
1344     break;
1345   case IceType_i16:
1346     assert(SrcReg == RegisterSet::Reg_ax);
1347     assert(DestReg == RegisterSet::Reg_dx);
1348     Asm->cwd();
1349     break;
1350   case IceType_i32:
1351     assert(SrcReg == RegisterSet::Reg_eax);
1352     assert(DestReg == RegisterSet::Reg_edx);
1353     Asm->cdq();
1354     break;
1355   case IceType_i64:
1356     assert(Traits::Is64Bit);
1357     assert(SrcReg == Traits::getRaxOrDie());
1358     assert(DestReg == Traits::getRdxOrDie());
1359     Asm->cqo();
1360     break;
1361   }
1362 }
1363 
1364 template <typename TraitsType>
emit(const Cfg * Func)1365 void InstImpl<TraitsType>::InstX86Mul::emit(const Cfg *Func) const {
1366   if (!BuildDefs::dump())
1367     return;
1368   Ostream &Str = Func->getContext()->getStrEmit();
1369   assert(this->getSrcSize() == 2);
1370   assert(llvm::isa<Variable>(this->getSrc(0)));
1371   assert(llvm::cast<Variable>(this->getSrc(0))->getRegNum() ==
1372          RegisterSet::Reg_eax);
1373   assert(this->getDest()->getRegNum() == RegisterSet::Reg_eax); // TODO:
1374                                                                 // allow
1375                                                                 // edx?
1376   Str << "\t"
1377          "mul" << this->getWidthString(this->getDest()->getType()) << "\t";
1378   this->getSrc(1)->emit(Func);
1379 }
1380 
1381 template <typename TraitsType>
emitIAS(const Cfg * Func)1382 void InstImpl<TraitsType>::InstX86Mul::emitIAS(const Cfg *Func) const {
1383   assert(this->getSrcSize() == 2);
1384   assert(llvm::isa<Variable>(this->getSrc(0)));
1385   assert(llvm::cast<Variable>(this->getSrc(0))->getRegNum() ==
1386          RegisterSet::Reg_eax);
1387   assert(this->getDest()->getRegNum() == RegisterSet::Reg_eax); // TODO:
1388                                                                 // allow
1389                                                                 // edx?
1390   const Operand *Src = this->getSrc(1);
1391   Type Ty = Src->getType();
1392   static const GPREmitterOneOp Emitter = {&Assembler::mul, &Assembler::mul};
1393   emitIASOpTyGPR(Func, Ty, Src, Emitter);
1394 }
1395 
1396 template <typename TraitsType>
dump(const Cfg * Func)1397 void InstImpl<TraitsType>::InstX86Mul::dump(const Cfg *Func) const {
1398   if (!BuildDefs::dump())
1399     return;
1400   Ostream &Str = Func->getContext()->getStrDump();
1401   this->dumpDest(Func);
1402   Str << " = mul." << this->getDest()->getType() << " ";
1403   this->dumpSources(Func);
1404 }
1405 
1406 template <typename TraitsType>
emit(const Cfg * Func)1407 void InstImpl<TraitsType>::InstX86Shld::emit(const Cfg *Func) const {
1408   if (!BuildDefs::dump())
1409     return;
1410   Ostream &Str = Func->getContext()->getStrEmit();
1411   Variable *Dest = this->getDest();
1412   assert(this->getSrcSize() == 3);
1413   assert(Dest == this->getSrc(0));
1414   Str << "\t"
1415          "shld" << this->getWidthString(Dest->getType()) << "\t";
1416   this->getSrc(2)->emit(Func);
1417   Str << ", ";
1418   this->getSrc(1)->emit(Func);
1419   Str << ", ";
1420   Dest->emit(Func);
1421 }
1422 
1423 template <typename TraitsType>
emitIAS(const Cfg * Func)1424 void InstImpl<TraitsType>::InstX86Shld::emitIAS(const Cfg *Func) const {
1425   assert(this->getSrcSize() == 3);
1426   assert(this->getDest() == this->getSrc(0));
1427   const Variable *Dest = this->getDest();
1428   const Operand *Src1 = this->getSrc(1);
1429   const Operand *Src2 = this->getSrc(2);
1430   static const GPREmitterShiftD Emitter = {&Assembler::shld, &Assembler::shld};
1431   emitIASGPRShiftDouble(Func, Dest, Src1, Src2, Emitter);
1432 }
1433 
1434 template <typename TraitsType>
dump(const Cfg * Func)1435 void InstImpl<TraitsType>::InstX86Shld::dump(const Cfg *Func) const {
1436   if (!BuildDefs::dump())
1437     return;
1438   Ostream &Str = Func->getContext()->getStrDump();
1439   this->dumpDest(Func);
1440   Str << " = shld." << this->getDest()->getType() << " ";
1441   this->dumpSources(Func);
1442 }
1443 
1444 template <typename TraitsType>
emit(const Cfg * Func)1445 void InstImpl<TraitsType>::InstX86Shrd::emit(const Cfg *Func) const {
1446   if (!BuildDefs::dump())
1447     return;
1448   Ostream &Str = Func->getContext()->getStrEmit();
1449   Variable *Dest = this->getDest();
1450   assert(this->getSrcSize() == 3);
1451   assert(Dest == this->getSrc(0));
1452   Str << "\t"
1453          "shrd" << this->getWidthString(Dest->getType()) << "\t";
1454   this->getSrc(2)->emit(Func);
1455   Str << ", ";
1456   this->getSrc(1)->emit(Func);
1457   Str << ", ";
1458   Dest->emit(Func);
1459 }
1460 
1461 template <typename TraitsType>
emitIAS(const Cfg * Func)1462 void InstImpl<TraitsType>::InstX86Shrd::emitIAS(const Cfg *Func) const {
1463   assert(this->getSrcSize() == 3);
1464   assert(this->getDest() == this->getSrc(0));
1465   const Variable *Dest = this->getDest();
1466   const Operand *Src1 = this->getSrc(1);
1467   const Operand *Src2 = this->getSrc(2);
1468   static const GPREmitterShiftD Emitter = {&Assembler::shrd, &Assembler::shrd};
1469   emitIASGPRShiftDouble(Func, Dest, Src1, Src2, Emitter);
1470 }
1471 
1472 template <typename TraitsType>
dump(const Cfg * Func)1473 void InstImpl<TraitsType>::InstX86Shrd::dump(const Cfg *Func) const {
1474   if (!BuildDefs::dump())
1475     return;
1476   Ostream &Str = Func->getContext()->getStrDump();
1477   this->dumpDest(Func);
1478   Str << " = shrd." << this->getDest()->getType() << " ";
1479   this->dumpSources(Func);
1480 }
1481 
1482 template <typename TraitsType>
emit(const Cfg * Func)1483 void InstImpl<TraitsType>::InstX86Cmov::emit(const Cfg *Func) const {
1484   if (!BuildDefs::dump())
1485     return;
1486   Ostream &Str = Func->getContext()->getStrEmit();
1487   Variable *Dest = this->getDest();
1488   Str << "\t";
1489   assert(Condition != Cond::Br_None);
1490   assert(this->getDest()->hasReg());
1491   Str << "cmov" << Traits::InstBrAttributes[Condition].DisplayString
1492       << this->getWidthString(Dest->getType()) << "\t";
1493   this->getSrc(1)->emit(Func);
1494   Str << ", ";
1495   Dest->emit(Func);
1496 }
1497 
1498 template <typename TraitsType>
emitIAS(const Cfg * Func)1499 void InstImpl<TraitsType>::InstX86Cmov::emitIAS(const Cfg *Func) const {
1500   assert(Condition != Cond::Br_None);
1501   assert(this->getDest()->hasReg());
1502   assert(this->getSrcSize() == 2);
1503   Operand *Src = this->getSrc(1);
1504   Type SrcTy = Src->getType();
1505   assert(SrcTy == IceType_i16 || SrcTy == IceType_i32 || (Traits::Is64Bit));
1506   Assembler *Asm = Func->getAssembler<Assembler>();
1507   auto *Target = InstX86Base::getTarget(Func);
1508   if (const auto *SrcVar = llvm::dyn_cast<Variable>(Src)) {
1509     if (SrcVar->hasReg()) {
1510       Asm->cmov(SrcTy, Condition,
1511                 Traits::getEncodedGPR(this->getDest()->getRegNum()),
1512                 Traits::getEncodedGPR(SrcVar->getRegNum()));
1513     } else {
1514       Asm->cmov(SrcTy, Condition,
1515                 Traits::getEncodedGPR(this->getDest()->getRegNum()),
1516                 Target->stackVarToAsmOperand(SrcVar));
1517     }
1518   } else if (const auto *Mem = llvm::dyn_cast<X86OperandMem>(Src)) {
1519     assert(Mem->getSegmentRegister() == X86OperandMem::DefaultSegment);
1520     Asm->cmov(SrcTy, Condition,
1521               Traits::getEncodedGPR(this->getDest()->getRegNum()),
1522               Mem->toAsmAddress(Asm, Target));
1523   } else {
1524     llvm_unreachable("Unexpected operand type");
1525   }
1526 }
1527 
1528 template <typename TraitsType>
dump(const Cfg * Func)1529 void InstImpl<TraitsType>::InstX86Cmov::dump(const Cfg *Func) const {
1530   if (!BuildDefs::dump())
1531     return;
1532   Ostream &Str = Func->getContext()->getStrDump();
1533   Str << "cmov" << Traits::InstBrAttributes[Condition].DisplayString << ".";
1534   Str << this->getDest()->getType() << " ";
1535   this->dumpDest(Func);
1536   Str << ", ";
1537   this->dumpSources(Func);
1538 }
1539 
1540 template <typename TraitsType>
emit(const Cfg * Func)1541 void InstImpl<TraitsType>::InstX86Cmpps::emit(const Cfg *Func) const {
1542   if (!BuildDefs::dump())
1543     return;
1544   Ostream &Str = Func->getContext()->getStrEmit();
1545   assert(this->getSrcSize() == 2);
1546   assert(Condition < Cond::Cmpps_Invalid);
1547   Type DestTy = this->Dest->getType();
1548   Str << "\t"
1549          "cmp" << Traits::InstCmppsAttributes[Condition].EmitString
1550       << Traits::TypeAttributes[DestTy].PdPsString << "\t";
1551   this->getSrc(1)->emit(Func);
1552   Str << ", ";
1553   this->getDest()->emit(Func);
1554 }
1555 
1556 template <typename TraitsType>
emitIAS(const Cfg * Func)1557 void InstImpl<TraitsType>::InstX86Cmpps::emitIAS(const Cfg *Func) const {
1558   Assembler *Asm = Func->getAssembler<Assembler>();
1559   assert(this->getSrcSize() == 2);
1560   assert(Condition < Cond::Cmpps_Invalid);
1561   // Assuming there isn't any load folding for cmpps, and vector constants are
1562   // not allowed in PNaCl.
1563   assert(llvm::isa<Variable>(this->getSrc(1)));
1564   auto *Target = InstX86Base::getTarget(Func);
1565   const auto *SrcVar = llvm::cast<Variable>(this->getSrc(1));
1566   if (SrcVar->hasReg()) {
1567     Asm->cmpps(this->getDest()->getType(),
1568                Traits::getEncodedXmm(this->getDest()->getRegNum()),
1569                Traits::getEncodedXmm(SrcVar->getRegNum()), Condition);
1570   } else {
1571     Address SrcStackAddr = Target->stackVarToAsmOperand(SrcVar);
1572     Asm->cmpps(this->getDest()->getType(),
1573                Traits::getEncodedXmm(this->getDest()->getRegNum()),
1574                SrcStackAddr, Condition);
1575   }
1576 }
1577 
1578 template <typename TraitsType>
dump(const Cfg * Func)1579 void InstImpl<TraitsType>::InstX86Cmpps::dump(const Cfg *Func) const {
1580   if (!BuildDefs::dump())
1581     return;
1582   Ostream &Str = Func->getContext()->getStrDump();
1583   assert(Condition < Cond::Cmpps_Invalid);
1584   this->dumpDest(Func);
1585   Str << " = cmp" << Traits::InstCmppsAttributes[Condition].EmitString << "ps"
1586                                                                           "\t";
1587   this->dumpSources(Func);
1588 }
1589 
1590 template <typename TraitsType>
emit(const Cfg * Func)1591 void InstImpl<TraitsType>::InstX86Cmpxchg::emit(const Cfg *Func) const {
1592   if (!BuildDefs::dump())
1593     return;
1594   Ostream &Str = Func->getContext()->getStrEmit();
1595   assert(this->getSrcSize() == 3);
1596   if (this->Locked) {
1597     Str << "\t"
1598            "lock";
1599   }
1600   Str << "\t"
1601          "cmpxchg" << this->getWidthString(this->getSrc(0)->getType()) << "\t";
1602   this->getSrc(2)->emit(Func);
1603   Str << ", ";
1604   this->getSrc(0)->emit(Func);
1605 }
1606 
1607 template <typename TraitsType>
emitIAS(const Cfg * Func)1608 void InstImpl<TraitsType>::InstX86Cmpxchg::emitIAS(const Cfg *Func) const {
1609   assert(this->getSrcSize() == 3);
1610   Assembler *Asm = Func->getAssembler<Assembler>();
1611   Type Ty = this->getSrc(0)->getType();
1612   auto *Target = InstX86Base::getTarget(Func);
1613   const auto Mem = llvm::cast<X86OperandMem>(this->getSrc(0));
1614   assert(Mem->getSegmentRegister() == X86OperandMem::DefaultSegment);
1615   const Address Addr = Mem->toAsmAddress(Asm, Target);
1616   const auto *VarReg = llvm::cast<Variable>(this->getSrc(2));
1617   assert(VarReg->hasReg());
1618   const GPRRegister Reg = Traits::getEncodedGPR(VarReg->getRegNum());
1619   Asm->cmpxchg(Ty, Addr, Reg, this->Locked);
1620 }
1621 
1622 template <typename TraitsType>
dump(const Cfg * Func)1623 void InstImpl<TraitsType>::InstX86Cmpxchg::dump(const Cfg *Func) const {
1624   if (!BuildDefs::dump())
1625     return;
1626   Ostream &Str = Func->getContext()->getStrDump();
1627   if (this->Locked) {
1628     Str << "lock ";
1629   }
1630   Str << "cmpxchg." << this->getSrc(0)->getType() << " ";
1631   this->dumpSources(Func);
1632 }
1633 
1634 template <typename TraitsType>
emit(const Cfg * Func)1635 void InstImpl<TraitsType>::InstX86Cmpxchg8b::emit(const Cfg *Func) const {
1636   if (!BuildDefs::dump())
1637     return;
1638   Ostream &Str = Func->getContext()->getStrEmit();
1639   assert(this->getSrcSize() == 5);
1640   if (this->Locked) {
1641     Str << "\t"
1642            "lock";
1643   }
1644   Str << "\t"
1645          "cmpxchg8b\t";
1646   this->getSrc(0)->emit(Func);
1647 }
1648 
1649 template <typename TraitsType>
emitIAS(const Cfg * Func)1650 void InstImpl<TraitsType>::InstX86Cmpxchg8b::emitIAS(const Cfg *Func) const {
1651   assert(this->getSrcSize() == 5);
1652   Assembler *Asm = Func->getAssembler<Assembler>();
1653   const auto Mem = llvm::cast<X86OperandMem>(this->getSrc(0));
1654   assert(Mem->getSegmentRegister() == X86OperandMem::DefaultSegment);
1655   auto *Target = InstX86Base::getTarget(Func);
1656   const Address Addr = Mem->toAsmAddress(Asm, Target);
1657   Asm->cmpxchg8b(Addr, this->Locked);
1658 }
1659 
1660 template <typename TraitsType>
dump(const Cfg * Func)1661 void InstImpl<TraitsType>::InstX86Cmpxchg8b::dump(const Cfg *Func) const {
1662   if (!BuildDefs::dump())
1663     return;
1664   Ostream &Str = Func->getContext()->getStrDump();
1665   if (this->Locked) {
1666     Str << "lock ";
1667   }
1668   Str << "cmpxchg8b ";
1669   this->dumpSources(Func);
1670 }
1671 
1672 template <typename TraitsType>
emit(const Cfg * Func)1673 void InstImpl<TraitsType>::InstX86Cvt::emit(const Cfg *Func) const {
1674   if (!BuildDefs::dump())
1675     return;
1676   Ostream &Str = Func->getContext()->getStrEmit();
1677   assert(this->getSrcSize() == 1);
1678   Str << "\t"
1679          "cvt";
1680   if (isTruncating())
1681     Str << "t";
1682   Str << Traits::TypeAttributes[this->getSrc(0)->getType()].CvtString << "2"
1683       << Traits::TypeAttributes[this->getDest()->getType()].CvtString << "\t";
1684   this->getSrc(0)->emit(Func);
1685   Str << ", ";
1686   this->getDest()->emit(Func);
1687 }
1688 
1689 template <typename TraitsType>
emitIAS(const Cfg * Func)1690 void InstImpl<TraitsType>::InstX86Cvt::emitIAS(const Cfg *Func) const {
1691   assert(this->getSrcSize() == 1);
1692   const Variable *Dest = this->getDest();
1693   const Operand *Src = this->getSrc(0);
1694   Type DestTy = Dest->getType();
1695   Type SrcTy = Src->getType();
1696   switch (Variant) {
1697   case Si2ss: {
1698     assert(isScalarIntegerType(SrcTy));
1699     if (!Traits::Is64Bit) {
1700       assert(typeWidthInBytes(SrcTy) <= 4);
1701     } else {
1702       assert(SrcTy == IceType_i32 || SrcTy == IceType_i64);
1703     }
1704     assert(isScalarFloatingType(DestTy));
1705     static const CastEmitterRegOp<XmmRegister, GPRRegister> Emitter = {
1706         &Assembler::cvtsi2ss, &Assembler::cvtsi2ss};
1707     emitIASCastRegOp<XmmRegister, GPRRegister, Traits::getEncodedXmm,
1708                      Traits::getEncodedGPR>(Func, DestTy, Dest, SrcTy, Src,
1709                                             Emitter);
1710     return;
1711   }
1712   case Tss2si: {
1713     assert(isScalarFloatingType(SrcTy));
1714     assert(isScalarIntegerType(DestTy));
1715     if (Traits::Is64Bit) {
1716       assert(DestTy == IceType_i32 || DestTy == IceType_i64);
1717     } else {
1718       assert(typeWidthInBytes(DestTy) <= 4);
1719     }
1720     static const CastEmitterRegOp<GPRRegister, XmmRegister> Emitter = {
1721         &Assembler::cvttss2si, &Assembler::cvttss2si};
1722     emitIASCastRegOp<GPRRegister, XmmRegister, Traits::getEncodedGPR,
1723                      Traits::getEncodedXmm>(Func, DestTy, Dest, SrcTy, Src,
1724                                             Emitter);
1725     return;
1726   }
1727   case Ss2si: {
1728     assert(isScalarFloatingType(SrcTy));
1729     assert(isScalarIntegerType(DestTy));
1730     if (Traits::Is64Bit) {
1731       assert(DestTy == IceType_i32 || DestTy == IceType_i64);
1732     } else {
1733       assert(typeWidthInBytes(DestTy) <= 4);
1734     }
1735     static const CastEmitterRegOp<GPRRegister, XmmRegister> Emitter = {
1736         &Assembler::cvtss2si, &Assembler::cvtss2si};
1737     emitIASCastRegOp<GPRRegister, XmmRegister, Traits::getEncodedGPR,
1738                      Traits::getEncodedXmm>(Func, DestTy, Dest, SrcTy, Src,
1739                                             Emitter);
1740     return;
1741   }
1742   case Float2float: {
1743     assert(isScalarFloatingType(SrcTy));
1744     assert(isScalarFloatingType(DestTy));
1745     assert(DestTy != SrcTy);
1746     static const XmmEmitterRegOp Emitter = {&Assembler::cvtfloat2float,
1747                                             &Assembler::cvtfloat2float};
1748     emitIASRegOpTyXMM(Func, SrcTy, Dest, Src, Emitter);
1749     return;
1750   }
1751   case Dq2ps: {
1752     assert(isVectorIntegerType(SrcTy));
1753     assert(isVectorFloatingType(DestTy));
1754     static const XmmEmitterRegOp Emitter = {&Assembler::cvtdq2ps,
1755                                             &Assembler::cvtdq2ps};
1756     emitIASRegOpTyXMM(Func, DestTy, Dest, Src, Emitter);
1757     return;
1758   }
1759   case Tps2dq: {
1760     assert(isVectorFloatingType(SrcTy));
1761     assert(isVectorIntegerType(DestTy));
1762     static const XmmEmitterRegOp Emitter = {&Assembler::cvttps2dq,
1763                                             &Assembler::cvttps2dq};
1764     emitIASRegOpTyXMM(Func, DestTy, Dest, Src, Emitter);
1765     return;
1766   }
1767   case Ps2dq: {
1768     assert(isVectorFloatingType(SrcTy));
1769     assert(isVectorIntegerType(DestTy));
1770     static const XmmEmitterRegOp Emitter = {&Assembler::cvtps2dq,
1771                                             &Assembler::cvtps2dq};
1772     emitIASRegOpTyXMM(Func, DestTy, Dest, Src, Emitter);
1773     return;
1774   }
1775   }
1776 }
1777 
1778 template <typename TraitsType>
dump(const Cfg * Func)1779 void InstImpl<TraitsType>::InstX86Cvt::dump(const Cfg *Func) const {
1780   if (!BuildDefs::dump())
1781     return;
1782   Ostream &Str = Func->getContext()->getStrDump();
1783   this->dumpDest(Func);
1784   Str << " = cvt";
1785   if (isTruncating())
1786     Str << "t";
1787   Str << Traits::TypeAttributes[this->getSrc(0)->getType()].CvtString << "2"
1788       << Traits::TypeAttributes[this->getDest()->getType()].CvtString << " ";
1789   this->dumpSources(Func);
1790 }
1791 
1792 template <typename TraitsType>
emit(const Cfg * Func)1793 void InstImpl<TraitsType>::InstX86Round::emit(const Cfg *Func) const {
1794   if (!BuildDefs::dump())
1795     return;
1796   Ostream &Str = Func->getContext()->getStrEmit();
1797   assert(this->getSrcSize() == 3);
1798   Str << "\t" << this->Opcode
1799       << Traits::TypeAttributes[this->getDest()->getType()].SpSdString << "\t";
1800   this->getSrc(1)->emit(Func);
1801   Str << ", ";
1802   this->getSrc(0)->emit(Func);
1803   Str << ", ";
1804   this->getDest()->emit(Func);
1805 }
1806 
1807 template <typename TraitsType>
emitIAS(const Cfg * Func)1808 void InstImpl<TraitsType>::InstX86Round::emitIAS(const Cfg *Func) const {
1809   assert(this->getSrcSize() == 2);
1810   assert(InstX86Base::getTarget(Func)->getInstructionSet() >= Traits::SSE4_1);
1811   const Variable *Dest = this->getDest();
1812   Type Ty = Dest->getType();
1813   static const ThreeOpImmEmitter<XmmRegister, XmmRegister> Emitter = {
1814       &Assembler::round, &Assembler::round};
1815   emitIASThreeOpImmOps<XmmRegister, XmmRegister, Traits::getEncodedXmm,
1816                        Traits::getEncodedXmm>(Func, Ty, Dest, this->getSrc(0),
1817                                               this->getSrc(1), Emitter);
1818 }
1819 
1820 template <typename TraitsType>
emit(const Cfg * Func)1821 void InstImpl<TraitsType>::InstX86Icmp::emit(const Cfg *Func) const {
1822   if (!BuildDefs::dump())
1823     return;
1824   Ostream &Str = Func->getContext()->getStrEmit();
1825   assert(this->getSrcSize() == 2);
1826   Str << "\t"
1827          "cmp" << this->getWidthString(this->getSrc(0)->getType()) << "\t";
1828   this->getSrc(1)->emit(Func);
1829   Str << ", ";
1830   this->getSrc(0)->emit(Func);
1831 }
1832 
1833 template <typename TraitsType>
emitIAS(const Cfg * Func)1834 void InstImpl<TraitsType>::InstX86Icmp::emitIAS(const Cfg *Func) const {
1835   assert(this->getSrcSize() == 2);
1836   const Operand *Src0 = this->getSrc(0);
1837   const Operand *Src1 = this->getSrc(1);
1838   Type Ty = Src0->getType();
1839   static const GPREmitterRegOp RegEmitter = {&Assembler::cmp, &Assembler::cmp,
1840                                              &Assembler::cmp};
1841   static const GPREmitterAddrOp AddrEmitter = {&Assembler::cmp,
1842                                                &Assembler::cmp};
1843   if (const auto *SrcVar0 = llvm::dyn_cast<Variable>(Src0)) {
1844     if (SrcVar0->hasReg()) {
1845       constexpr bool NotLea = false;
1846       emitIASRegOpTyGPR(Func, NotLea, Ty, SrcVar0, Src1, RegEmitter);
1847       return;
1848     }
1849   }
1850   emitIASAsAddrOpTyGPR(Func, Ty, Src0, Src1, AddrEmitter);
1851 }
1852 
1853 template <typename TraitsType>
dump(const Cfg * Func)1854 void InstImpl<TraitsType>::InstX86Icmp::dump(const Cfg *Func) const {
1855   if (!BuildDefs::dump())
1856     return;
1857   Ostream &Str = Func->getContext()->getStrDump();
1858   Str << "cmp." << this->getSrc(0)->getType() << " ";
1859   this->dumpSources(Func);
1860 }
1861 
1862 template <typename TraitsType>
emit(const Cfg * Func)1863 void InstImpl<TraitsType>::InstX86Ucomiss::emit(const Cfg *Func) const {
1864   if (!BuildDefs::dump())
1865     return;
1866   Ostream &Str = Func->getContext()->getStrEmit();
1867   assert(this->getSrcSize() == 2);
1868   Str << "\t"
1869          "ucomi"
1870       << Traits::TypeAttributes[this->getSrc(0)->getType()].SdSsString << "\t";
1871   this->getSrc(1)->emit(Func);
1872   Str << ", ";
1873   this->getSrc(0)->emit(Func);
1874 }
1875 
1876 template <typename TraitsType>
emitIAS(const Cfg * Func)1877 void InstImpl<TraitsType>::InstX86Ucomiss::emitIAS(const Cfg *Func) const {
1878   assert(this->getSrcSize() == 2);
1879   // Currently src0 is always a variable by convention, to avoid having two
1880   // memory operands.
1881   assert(llvm::isa<Variable>(this->getSrc(0)));
1882   const auto *Src0Var = llvm::cast<Variable>(this->getSrc(0));
1883   Type Ty = Src0Var->getType();
1884   static const XmmEmitterRegOp Emitter = {&Assembler::ucomiss,
1885                                           &Assembler::ucomiss};
1886   emitIASRegOpTyXMM(Func, Ty, Src0Var, this->getSrc(1), Emitter);
1887 }
1888 
1889 template <typename TraitsType>
dump(const Cfg * Func)1890 void InstImpl<TraitsType>::InstX86Ucomiss::dump(const Cfg *Func) const {
1891   if (!BuildDefs::dump())
1892     return;
1893   Ostream &Str = Func->getContext()->getStrDump();
1894   Str << "ucomiss." << this->getSrc(0)->getType() << " ";
1895   this->dumpSources(Func);
1896 }
1897 
1898 template <typename TraitsType>
emit(const Cfg * Func)1899 void InstImpl<TraitsType>::InstX86UD2::emit(const Cfg *Func) const {
1900   if (!BuildDefs::dump())
1901     return;
1902   Ostream &Str = Func->getContext()->getStrEmit();
1903   assert(this->getSrcSize() == 0);
1904   Str << "\t"
1905          "ud2";
1906 }
1907 
1908 template <typename TraitsType>
emitIAS(const Cfg * Func)1909 void InstImpl<TraitsType>::InstX86UD2::emitIAS(const Cfg *Func) const {
1910   Assembler *Asm = Func->getAssembler<Assembler>();
1911   Asm->ud2();
1912 }
1913 
1914 template <typename TraitsType>
dump(const Cfg * Func)1915 void InstImpl<TraitsType>::InstX86UD2::dump(const Cfg *Func) const {
1916   if (!BuildDefs::dump())
1917     return;
1918   Ostream &Str = Func->getContext()->getStrDump();
1919   Str << "ud2";
1920 }
1921 
1922 template <typename TraitsType>
emit(const Cfg * Func)1923 void InstImpl<TraitsType>::InstX86Int3::emit(const Cfg *Func) const {
1924   if (!BuildDefs::dump())
1925     return;
1926   Ostream &Str = Func->getContext()->getStrEmit();
1927   assert(this->getSrcSize() == 0);
1928   Str << "\t"
1929          "int 3";
1930 }
1931 
1932 template <typename TraitsType>
emitIAS(const Cfg * Func)1933 void InstImpl<TraitsType>::InstX86Int3::emitIAS(const Cfg *Func) const {
1934   Assembler *Asm = Func->getAssembler<Assembler>();
1935   Asm->int3();
1936 }
1937 
1938 template <typename TraitsType>
dump(const Cfg * Func)1939 void InstImpl<TraitsType>::InstX86Int3::dump(const Cfg *Func) const {
1940   if (!BuildDefs::dump())
1941     return;
1942   Ostream &Str = Func->getContext()->getStrDump();
1943   Str << "int 3";
1944 }
1945 
1946 template <typename TraitsType>
emit(const Cfg * Func)1947 void InstImpl<TraitsType>::InstX86Test::emit(const Cfg *Func) const {
1948   if (!BuildDefs::dump())
1949     return;
1950   Ostream &Str = Func->getContext()->getStrEmit();
1951   assert(this->getSrcSize() == 2);
1952   Str << "\t"
1953          "test" << this->getWidthString(this->getSrc(0)->getType()) << "\t";
1954   this->getSrc(1)->emit(Func);
1955   Str << ", ";
1956   this->getSrc(0)->emit(Func);
1957 }
1958 
1959 template <typename TraitsType>
emitIAS(const Cfg * Func)1960 void InstImpl<TraitsType>::InstX86Test::emitIAS(const Cfg *Func) const {
1961   assert(this->getSrcSize() == 2);
1962   const Operand *Src0 = this->getSrc(0);
1963   const Operand *Src1 = this->getSrc(1);
1964   Type Ty = Src0->getType();
1965   // The Reg/Addr form of test is not encodeable.
1966   static const GPREmitterRegOp RegEmitter = {&Assembler::test, nullptr,
1967                                              &Assembler::test};
1968   static const GPREmitterAddrOp AddrEmitter = {&Assembler::test,
1969                                                &Assembler::test};
1970   if (const auto *SrcVar0 = llvm::dyn_cast<Variable>(Src0)) {
1971     if (SrcVar0->hasReg()) {
1972       constexpr bool NotLea = false;
1973       emitIASRegOpTyGPR(Func, NotLea, Ty, SrcVar0, Src1, RegEmitter);
1974       return;
1975     }
1976   }
1977   emitIASAsAddrOpTyGPR(Func, Ty, Src0, Src1, AddrEmitter);
1978 }
1979 
1980 template <typename TraitsType>
dump(const Cfg * Func)1981 void InstImpl<TraitsType>::InstX86Test::dump(const Cfg *Func) const {
1982   if (!BuildDefs::dump())
1983     return;
1984   Ostream &Str = Func->getContext()->getStrDump();
1985   Str << "test." << this->getSrc(0)->getType() << " ";
1986   this->dumpSources(Func);
1987 }
1988 
1989 template <typename TraitsType>
emit(const Cfg * Func)1990 void InstImpl<TraitsType>::InstX86Mfence::emit(const Cfg *Func) const {
1991   if (!BuildDefs::dump())
1992     return;
1993   Ostream &Str = Func->getContext()->getStrEmit();
1994   assert(this->getSrcSize() == 0);
1995   Str << "\t"
1996          "mfence";
1997 }
1998 
1999 template <typename TraitsType>
emitIAS(const Cfg * Func)2000 void InstImpl<TraitsType>::InstX86Mfence::emitIAS(const Cfg *Func) const {
2001   Assembler *Asm = Func->getAssembler<Assembler>();
2002   Asm->mfence();
2003 }
2004 
2005 template <typename TraitsType>
dump(const Cfg * Func)2006 void InstImpl<TraitsType>::InstX86Mfence::dump(const Cfg *Func) const {
2007   if (!BuildDefs::dump())
2008     return;
2009   Ostream &Str = Func->getContext()->getStrDump();
2010   Str << "mfence";
2011 }
2012 
2013 template <typename TraitsType>
emit(const Cfg * Func)2014 void InstImpl<TraitsType>::InstX86Store::emit(const Cfg *Func) const {
2015   if (!BuildDefs::dump())
2016     return;
2017   Ostream &Str = Func->getContext()->getStrEmit();
2018   assert(this->getSrcSize() == 2);
2019   Type Ty = this->getSrc(0)->getType();
2020   Str << "\t"
2021          "mov" << this->getWidthString(Ty)
2022       << Traits::TypeAttributes[Ty].SdSsString << "\t";
2023   this->getSrc(0)->emit(Func);
2024   Str << ", ";
2025   this->getSrc(1)->emit(Func);
2026 }
2027 
2028 template <typename TraitsType>
emitIAS(const Cfg * Func)2029 void InstImpl<TraitsType>::InstX86Store::emitIAS(const Cfg *Func) const {
2030   assert(this->getSrcSize() == 2);
2031   const Operand *Dest = this->getSrc(1);
2032   const Operand *Src = this->getSrc(0);
2033   Type DestTy = Dest->getType();
2034   if (isScalarFloatingType(DestTy)) {
2035     // Src must be a register, since Dest is a Mem operand of some kind.
2036     const auto *SrcVar = llvm::cast<Variable>(Src);
2037     assert(SrcVar->hasReg());
2038     XmmRegister SrcReg = Traits::getEncodedXmm(SrcVar->getRegNum());
2039     Assembler *Asm = Func->getAssembler<Assembler>();
2040     auto *Target = InstX86Base::getTarget(Func);
2041     if (const auto *DestVar = llvm::dyn_cast<Variable>(Dest)) {
2042       assert(!DestVar->hasReg());
2043       Address StackAddr(Target->stackVarToAsmOperand(DestVar));
2044       Asm->movss(DestTy, StackAddr, SrcReg);
2045     } else {
2046       const auto DestMem = llvm::cast<X86OperandMem>(Dest);
2047       assert(DestMem->getSegmentRegister() == X86OperandMem::DefaultSegment);
2048       Asm->movss(DestTy, DestMem->toAsmAddress(Asm, Target), SrcReg);
2049     }
2050     return;
2051   } else {
2052     assert(isScalarIntegerType(DestTy));
2053     static const GPREmitterAddrOp GPRAddrEmitter = {&Assembler::mov,
2054                                                     &Assembler::mov};
2055     emitIASAsAddrOpTyGPR(Func, DestTy, Dest, Src, GPRAddrEmitter);
2056   }
2057 }
2058 
2059 template <typename TraitsType>
dump(const Cfg * Func)2060 void InstImpl<TraitsType>::InstX86Store::dump(const Cfg *Func) const {
2061   if (!BuildDefs::dump())
2062     return;
2063   Ostream &Str = Func->getContext()->getStrDump();
2064   Str << "mov." << this->getSrc(0)->getType() << " ";
2065   this->getSrc(1)->dump(Func);
2066   Str << ", ";
2067   this->getSrc(0)->dump(Func);
2068 }
2069 
2070 template <typename TraitsType>
emit(const Cfg * Func)2071 void InstImpl<TraitsType>::InstX86StoreP::emit(const Cfg *Func) const {
2072   if (!BuildDefs::dump())
2073     return;
2074   Ostream &Str = Func->getContext()->getStrEmit();
2075   assert(this->getSrcSize() == 2);
2076   assert(isVectorType(this->getSrc(1)->getType()));
2077   Str << "\t"
2078          "movups\t";
2079   this->getSrc(0)->emit(Func);
2080   Str << ", ";
2081   this->getSrc(1)->emit(Func);
2082 }
2083 
2084 template <typename TraitsType>
emitIAS(const Cfg * Func)2085 void InstImpl<TraitsType>::InstX86StoreP::emitIAS(const Cfg *Func) const {
2086   Assembler *Asm = Func->getAssembler<Assembler>();
2087   assert(this->getSrcSize() == 2);
2088   const auto *SrcVar = llvm::cast<Variable>(this->getSrc(0));
2089   const auto DestMem = llvm::cast<X86OperandMem>(this->getSrc(1));
2090   assert(DestMem->getSegmentRegister() == X86OperandMem::DefaultSegment);
2091   assert(SrcVar->hasReg());
2092   auto *Target = InstX86Base::getTarget(Func);
2093   Asm->movups(DestMem->toAsmAddress(Asm, Target),
2094               Traits::getEncodedXmm(SrcVar->getRegNum()));
2095 }
2096 
2097 template <typename TraitsType>
dump(const Cfg * Func)2098 void InstImpl<TraitsType>::InstX86StoreP::dump(const Cfg *Func) const {
2099   if (!BuildDefs::dump())
2100     return;
2101   Ostream &Str = Func->getContext()->getStrDump();
2102   Str << "storep." << this->getSrc(0)->getType() << " ";
2103   this->getSrc(1)->dump(Func);
2104   Str << ", ";
2105   this->getSrc(0)->dump(Func);
2106 }
2107 
2108 template <typename TraitsType>
emit(const Cfg * Func)2109 void InstImpl<TraitsType>::InstX86StoreQ::emit(const Cfg *Func) const {
2110   if (!BuildDefs::dump())
2111     return;
2112   Ostream &Str = Func->getContext()->getStrEmit();
2113   assert(this->getSrcSize() == 2);
2114   assert(this->getSrc(1)->getType() == IceType_i64 ||
2115          this->getSrc(1)->getType() == IceType_f64 ||
2116          isVectorType(this->getSrc(1)->getType()));
2117   Str << "\t"
2118          "movq\t";
2119   this->getSrc(0)->emit(Func);
2120   Str << ", ";
2121   this->getSrc(1)->emit(Func);
2122 }
2123 
2124 template <typename TraitsType>
emitIAS(const Cfg * Func)2125 void InstImpl<TraitsType>::InstX86StoreQ::emitIAS(const Cfg *Func) const {
2126   Assembler *Asm = Func->getAssembler<Assembler>();
2127   assert(this->getSrcSize() == 2);
2128   const auto *SrcVar = llvm::cast<Variable>(this->getSrc(0));
2129   const auto DestMem = llvm::cast<X86OperandMem>(this->getSrc(1));
2130   assert(DestMem->getSegmentRegister() == X86OperandMem::DefaultSegment);
2131   assert(SrcVar->hasReg());
2132   auto *Target = InstX86Base::getTarget(Func);
2133   Asm->movq(DestMem->toAsmAddress(Asm, Target),
2134             Traits::getEncodedXmm(SrcVar->getRegNum()));
2135 }
2136 
2137 template <typename TraitsType>
dump(const Cfg * Func)2138 void InstImpl<TraitsType>::InstX86StoreQ::dump(const Cfg *Func) const {
2139   if (!BuildDefs::dump())
2140     return;
2141   Ostream &Str = Func->getContext()->getStrDump();
2142   Str << "storeq." << this->getSrc(0)->getType() << " ";
2143   this->getSrc(1)->dump(Func);
2144   Str << ", ";
2145   this->getSrc(0)->dump(Func);
2146 }
2147 
2148 template <typename TraitsType>
emit(const Cfg * Func)2149 void InstImpl<TraitsType>::InstX86StoreD::emit(const Cfg *Func) const {
2150   if (!BuildDefs::dump())
2151     return;
2152   Ostream &Str = Func->getContext()->getStrEmit();
2153   assert(this->getSrcSize() == 2);
2154   assert(this->getSrc(1)->getType() == IceType_i64 ||
2155          this->getSrc(1)->getType() == IceType_f64 ||
2156          isVectorType(this->getSrc(1)->getType()));
2157   Str << "\t"
2158          "movd\t";
2159   this->getSrc(0)->emit(Func);
2160   Str << ", ";
2161   this->getSrc(1)->emit(Func);
2162 }
2163 
2164 template <typename TraitsType>
emitIAS(const Cfg * Func)2165 void InstImpl<TraitsType>::InstX86StoreD::emitIAS(const Cfg *Func) const {
2166   Assembler *Asm = Func->getAssembler<Assembler>();
2167   assert(this->getSrcSize() == 2);
2168   const auto *SrcVar = llvm::cast<Variable>(this->getSrc(0));
2169   const auto DestMem = llvm::cast<X86OperandMem>(this->getSrc(1));
2170   assert(DestMem->getSegmentRegister() == X86OperandMem::DefaultSegment);
2171   assert(SrcVar->hasReg());
2172   auto *Target = InstX86Base::getTarget(Func);
2173   Asm->movd(SrcVar->getType(), DestMem->toAsmAddress(Asm, Target),
2174             Traits::getEncodedXmm(SrcVar->getRegNum()));
2175 }
2176 
2177 template <typename TraitsType>
dump(const Cfg * Func)2178 void InstImpl<TraitsType>::InstX86StoreD::dump(const Cfg *Func) const {
2179   if (!BuildDefs::dump())
2180     return;
2181   Ostream &Str = Func->getContext()->getStrDump();
2182   Str << "stored." << this->getSrc(0)->getType() << " ";
2183   this->getSrc(1)->dump(Func);
2184   Str << ", ";
2185   this->getSrc(0)->dump(Func);
2186 }
2187 
2188 template <typename TraitsType>
emit(const Cfg * Func)2189 void InstImpl<TraitsType>::InstX86Lea::emit(const Cfg *Func) const {
2190   if (!BuildDefs::dump())
2191     return;
2192   if (auto *Add = this->deoptLeaToAddOrNull(Func)) {
2193     Add->emit(Func);
2194     return;
2195   }
2196 
2197   Ostream &Str = Func->getContext()->getStrEmit();
2198   assert(this->getSrcSize() == 1);
2199   assert(this->getDest()->hasReg());
2200   Str << "\t"
2201          "lea" << this->getWidthString(this->getDest()->getType()) << "\t";
2202   Operand *Src0 = this->getSrc(0);
2203   if (const auto *Src0Var = llvm::dyn_cast<Variable>(Src0)) {
2204     Type Ty = Src0Var->getType();
2205     // lea on x86-32 doesn't accept mem128 operands, so cast VSrc0 to an
2206     // acceptable type.
2207     Src0Var->asType(Func, isVectorType(Ty) ? IceType_i32 : Ty, RegNumT())
2208         ->emit(Func);
2209   } else {
2210     Src0->emit(Func);
2211   }
2212   Str << ", ";
2213   this->getDest()->emit(Func);
2214 }
2215 
2216 template <typename TraitsType>
emit(const Cfg * Func)2217 void InstImpl<TraitsType>::InstX86Mov::emit(const Cfg *Func) const {
2218   if (!BuildDefs::dump())
2219     return;
2220   Ostream &Str = Func->getContext()->getStrEmit();
2221   assert(this->getSrcSize() == 1);
2222   Operand *Src = this->getSrc(0);
2223   Type SrcTy = Src->getType();
2224   Type DestTy = this->getDest()->getType();
2225   if (Traits::Is64Bit && DestTy == IceType_i64 &&
2226       llvm::isa<ConstantInteger64>(Src) &&
2227       !Utils::IsInt(32, llvm::cast<ConstantInteger64>(Src)->getValue())) {
2228     Str << "\t"
2229            "movabs"
2230            "\t";
2231   } else {
2232     Str << "\t"
2233            "mov" << (!isScalarFloatingType(DestTy)
2234                          ? this->getWidthString(DestTy)
2235                          : Traits::TypeAttributes[DestTy].SdSsString) << "\t";
2236   }
2237   // For an integer truncation operation, src is wider than dest. In this case,
2238   // we use a mov instruction whose data width matches the narrower dest.
2239   // TODO: This assert disallows usages such as copying a floating
2240   // point value between a vector and a scalar (which movss is used for). Clean
2241   // this up.
2242   assert(InstX86Base::getTarget(Func)->typeWidthInBytesOnStack(DestTy) ==
2243          InstX86Base::getTarget(Func)->typeWidthInBytesOnStack(SrcTy));
2244   const Operand *NewSrc = Src;
2245   if (auto *SrcVar = llvm::dyn_cast<Variable>(Src)) {
2246     RegNumT NewRegNum;
2247     if (SrcVar->hasReg())
2248       NewRegNum = Traits::getGprForType(DestTy, SrcVar->getRegNum());
2249     if (SrcTy != DestTy)
2250       NewSrc = SrcVar->asType(Func, DestTy, NewRegNum);
2251   }
2252   NewSrc->emit(Func);
2253   Str << ", ";
2254   this->getDest()->emit(Func);
2255 }
2256 
2257 template <typename TraitsType>
emitIAS(const Cfg * Func)2258 void InstImpl<TraitsType>::InstX86Mov::emitIAS(const Cfg *Func) const {
2259   assert(this->getSrcSize() == 1);
2260   const Variable *Dest = this->getDest();
2261   const Operand *Src = this->getSrc(0);
2262   Type DestTy = Dest->getType();
2263   Type SrcTy = Src->getType();
2264   // Mov can be used for GPRs or XMM registers. Also, the type does not
2265   // necessarily match (Mov can be used for bitcasts). However, when the type
2266   // does not match, one of the operands must be a register. Thus, the strategy
2267   // is to find out if Src or Dest are a register, then use that register's
2268   // type to decide on which emitter set to use. The emitter set will include
2269   // reg-reg movs, but that case should be unused when the types don't match.
2270   static const XmmEmitterRegOp XmmRegEmitter = {&Assembler::movss,
2271                                                 &Assembler::movss};
2272   static const GPREmitterRegOp GPRRegEmitter = {
2273       &Assembler::mov, &Assembler::mov, &Assembler::mov};
2274   static const GPREmitterAddrOp GPRAddrEmitter = {&Assembler::mov,
2275                                                   &Assembler::mov};
2276   // For an integer truncation operation, src is wider than dest. In this case,
2277   // we use a mov instruction whose data width matches the narrower dest.
2278   // TODO: This assert disallows usages such as copying a floating
2279   // point value between a vector and a scalar (which movss is used for). Clean
2280   // this up.
2281   auto *Target = InstX86Base::getTarget(Func);
2282   assert(Target->typeWidthInBytesOnStack(this->getDest()->getType()) ==
2283          Target->typeWidthInBytesOnStack(Src->getType()));
2284   if (Dest->hasReg()) {
2285     if (isScalarFloatingType(DestTy)) {
2286       emitIASRegOpTyXMM(Func, DestTy, Dest, Src, XmmRegEmitter);
2287       return;
2288     } else {
2289       assert(isScalarIntegerType(DestTy));
2290       // Widen DestTy for truncation (see above note). We should only do this
2291       // when both Src and Dest are integer types.
2292       if (Traits::Is64Bit && DestTy == IceType_i64) {
2293         if (const auto *C64 = llvm::dyn_cast<ConstantInteger64>(Src)) {
2294           Func->getAssembler<Assembler>()->movabs(
2295               Traits::getEncodedGPR(Dest->getRegNum()), C64->getValue());
2296           return;
2297         }
2298       }
2299       if (isScalarIntegerType(SrcTy)) {
2300         SrcTy = DestTy;
2301       }
2302       constexpr bool NotLea = false;
2303       emitIASRegOpTyGPR(Func, NotLea, DestTy, Dest, Src, GPRRegEmitter);
2304       return;
2305     }
2306   } else {
2307     // Dest must be Stack and Src *could* be a register. Use Src's type to
2308     // decide on the emitters.
2309     Address StackAddr(Target->stackVarToAsmOperand(Dest));
2310     if (isScalarFloatingType(SrcTy)) {
2311       // Src must be a register.
2312       const auto *SrcVar = llvm::cast<Variable>(Src);
2313       assert(SrcVar->hasReg());
2314       Assembler *Asm = Func->getAssembler<Assembler>();
2315       Asm->movss(SrcTy, StackAddr, Traits::getEncodedXmm(SrcVar->getRegNum()));
2316       return;
2317     } else {
2318       // Src can be a register or immediate.
2319       assert(isScalarIntegerType(SrcTy));
2320       emitIASAddrOpTyGPR(Func, SrcTy, StackAddr, Src, GPRAddrEmitter);
2321       return;
2322     }
2323     return;
2324   }
2325 }
2326 
2327 template <typename TraitsType>
emit(const Cfg * Func)2328 void InstImpl<TraitsType>::InstX86Movd::emit(const Cfg *Func) const {
2329   if (!BuildDefs::dump())
2330     return;
2331   assert(this->getSrcSize() == 1);
2332   Variable *Dest = this->getDest();
2333   Operand *Src = this->getSrc(0);
2334 
2335   if (Dest->getType() == IceType_i64 || Src->getType() == IceType_i64) {
2336     assert(Dest->getType() == IceType_f64 || Src->getType() == IceType_f64);
2337     assert(Dest->getType() != Src->getType());
2338     Ostream &Str = Func->getContext()->getStrEmit();
2339     Str << "\t"
2340            "movq"
2341            "\t";
2342     Src->emit(Func);
2343     Str << ", ";
2344     Dest->emit(Func);
2345     return;
2346   }
2347 
2348   InstX86BaseUnaryopXmm<InstX86Base::Movd>::emit(Func);
2349 }
2350 
2351 template <typename TraitsType>
emitIAS(const Cfg * Func)2352 void InstImpl<TraitsType>::InstX86Movd::emitIAS(const Cfg *Func) const {
2353   Assembler *Asm = Func->getAssembler<Assembler>();
2354   assert(this->getSrcSize() == 1);
2355   const Variable *Dest = this->getDest();
2356   auto *Target = InstX86Base::getTarget(Func);
2357   // For insert/extract element (one of Src/Dest is an Xmm vector and the other
2358   // is an int type).
2359   if (const auto *SrcVar = llvm::dyn_cast<Variable>(this->getSrc(0))) {
2360     if (SrcVar->getType() == IceType_i32 ||
2361         (Traits::Is64Bit && SrcVar->getType() == IceType_i64)) {
2362       assert(isVectorType(Dest->getType()) ||
2363              (isScalarFloatingType(Dest->getType()) &&
2364               typeWidthInBytes(SrcVar->getType()) ==
2365                   typeWidthInBytes(Dest->getType())));
2366       assert(Dest->hasReg());
2367       XmmRegister DestReg = Traits::getEncodedXmm(Dest->getRegNum());
2368       if (SrcVar->hasReg()) {
2369         Asm->movd(SrcVar->getType(), DestReg,
2370                   Traits::getEncodedGPR(SrcVar->getRegNum()));
2371       } else {
2372         Address StackAddr(Target->stackVarToAsmOperand(SrcVar));
2373         Asm->movd(SrcVar->getType(), DestReg, StackAddr);
2374       }
2375     } else {
2376       assert(isVectorType(SrcVar->getType()) ||
2377              (isScalarFloatingType(SrcVar->getType()) &&
2378               typeWidthInBytes(SrcVar->getType()) ==
2379                   typeWidthInBytes(Dest->getType())));
2380       assert(SrcVar->hasReg());
2381       assert(Dest->getType() == IceType_i32 ||
2382              (Traits::Is64Bit && Dest->getType() == IceType_i64));
2383       XmmRegister SrcReg = Traits::getEncodedXmm(SrcVar->getRegNum());
2384       if (Dest->hasReg()) {
2385         Asm->movd(Dest->getType(), Traits::getEncodedGPR(Dest->getRegNum()),
2386                   SrcReg);
2387       } else {
2388         Address StackAddr(Target->stackVarToAsmOperand(Dest));
2389         Asm->movd(Dest->getType(), StackAddr, SrcReg);
2390       }
2391     }
2392   } else {
2393     assert(Dest->hasReg());
2394     XmmRegister DestReg = Traits::getEncodedXmm(Dest->getRegNum());
2395     auto *Mem = llvm::cast<X86OperandMem>(this->getSrc(0));
2396     Asm->movd(Mem->getType(), DestReg, Mem->toAsmAddress(Asm, Target));
2397   }
2398 }
2399 
2400 template <typename TraitsType>
emit(const Cfg * Func)2401 void InstImpl<TraitsType>::InstX86Movp::emit(const Cfg *Func) const {
2402   if (!BuildDefs::dump())
2403     return;
2404   // TODO(wala,stichnot): movups works with all vector operands, but there
2405   // exist other instructions (movaps, movdqa, movdqu) that may perform better,
2406   // depending on the data type and alignment of the operands.
2407   Ostream &Str = Func->getContext()->getStrEmit();
2408   assert(this->getSrcSize() == 1);
2409   Str << "\t"
2410          "movups\t";
2411   this->getSrc(0)->emit(Func);
2412   Str << ", ";
2413   this->getDest()->emit(Func);
2414 }
2415 
2416 template <typename TraitsType>
emitIAS(const Cfg * Func)2417 void InstImpl<TraitsType>::InstX86Movp::emitIAS(const Cfg *Func) const {
2418   assert(this->getSrcSize() == 1);
2419   assert(isVectorType(this->getDest()->getType()));
2420   const Variable *Dest = this->getDest();
2421   const Operand *Src = this->getSrc(0);
2422   static const XmmEmitterMovOps Emitter = {
2423       &Assembler::movups, &Assembler::movups, &Assembler::movups};
2424   emitIASMovlikeXMM(Func, Dest, Src, Emitter);
2425 }
2426 
2427 template <typename TraitsType>
emit(const Cfg * Func)2428 void InstImpl<TraitsType>::InstX86Movq::emit(const Cfg *Func) const {
2429   if (!BuildDefs::dump())
2430     return;
2431   Ostream &Str = Func->getContext()->getStrEmit();
2432   assert(this->getSrcSize() == 1);
2433   assert(this->getDest()->getType() == IceType_i64 ||
2434          this->getDest()->getType() == IceType_f64);
2435   Str << "\t"
2436          "movq"
2437          "\t";
2438   this->getSrc(0)->emit(Func);
2439   Str << ", ";
2440   this->getDest()->emit(Func);
2441 }
2442 
2443 template <typename TraitsType>
emitIAS(const Cfg * Func)2444 void InstImpl<TraitsType>::InstX86Movq::emitIAS(const Cfg *Func) const {
2445   assert(this->getSrcSize() == 1);
2446   assert(this->getDest()->getType() == IceType_i64 ||
2447          this->getDest()->getType() == IceType_f64 ||
2448          isVectorType(this->getDest()->getType()));
2449   const Variable *Dest = this->getDest();
2450   const Operand *Src = this->getSrc(0);
2451   static const XmmEmitterMovOps Emitter = {&Assembler::movq, &Assembler::movq,
2452                                            &Assembler::movq};
2453   emitIASMovlikeXMM(Func, Dest, Src, Emitter);
2454 }
2455 
2456 template <typename TraitsType>
emitIAS(const Cfg * Func)2457 void InstImpl<TraitsType>::InstX86MovssRegs::emitIAS(const Cfg *Func) const {
2458   // This is Binop variant is only intended to be used for reg-reg moves where
2459   // part of the Dest register is untouched.
2460   assert(this->getSrcSize() == 2);
2461   const Variable *Dest = this->getDest();
2462   assert(Dest == this->getSrc(0));
2463   const auto *SrcVar = llvm::cast<Variable>(this->getSrc(1));
2464   assert(Dest->hasReg() && SrcVar->hasReg());
2465   Assembler *Asm = Func->getAssembler<Assembler>();
2466   Asm->movss(IceType_f32, Traits::getEncodedXmm(Dest->getRegNum()),
2467              Traits::getEncodedXmm(SrcVar->getRegNum()));
2468 }
2469 
2470 template <typename TraitsType>
emitIAS(const Cfg * Func)2471 void InstImpl<TraitsType>::InstX86Movsx::emitIAS(const Cfg *Func) const {
2472   assert(this->getSrcSize() == 1);
2473   const Variable *Dest = this->getDest();
2474   const Operand *Src = this->getSrc(0);
2475   // Dest must be a > 8-bit register, but Src can be 8-bit. In practice we just
2476   // use the full register for Dest to avoid having an OperandSizeOverride
2477   // prefix. It also allows us to only dispatch on SrcTy.
2478   Type SrcTy = Src->getType();
2479   assert(typeWidthInBytes(Dest->getType()) > 1);
2480   assert(typeWidthInBytes(Dest->getType()) > typeWidthInBytes(SrcTy));
2481   constexpr bool NotLea = false;
2482   emitIASRegOpTyGPR<false, true>(Func, NotLea, SrcTy, Dest, Src, this->Emitter);
2483 }
2484 
2485 template <typename TraitsType>
mayBeElided(const Variable * Dest,const Operand * SrcOpnd)2486 bool InstImpl<TraitsType>::InstX86Movzx::mayBeElided(
2487     const Variable *Dest, const Operand *SrcOpnd) const {
2488   assert(Traits::Is64Bit);
2489   const auto *Src = llvm::dyn_cast<Variable>(SrcOpnd);
2490 
2491   // Src is not a Variable, so it does not have a register. Movzx can't be
2492   // elided.
2493   if (Src == nullptr)
2494     return false;
2495 
2496   // Movzx to/from memory can't be elided.
2497   if (!Src->hasReg() || !Dest->hasReg())
2498     return false;
2499 
2500   // Reg/reg move with different source and dest can't be elided.
2501   if (Traits::getEncodedGPR(Src->getRegNum()) !=
2502       Traits::getEncodedGPR(Dest->getRegNum()))
2503     return false;
2504 
2505   // A must-keep movzx 32- to 64-bit is sometimes needed in x86-64 sandboxing.
2506   return !MustKeep;
2507 }
2508 
2509 template <typename TraitsType>
emit(const Cfg * Func)2510 void InstImpl<TraitsType>::InstX86Movzx::emit(const Cfg *Func) const {
2511   if (!BuildDefs::dump())
2512     return;
2513   if (Traits::Is64Bit) {
2514     // There's no movzx %eXX, %rXX. To zero extend 32- to 64-bits, we emit a
2515     // mov %eXX, %eXX. The processor will still do a movzx[bw]q.
2516     assert(this->getSrcSize() == 1);
2517     const Operand *Src = this->getSrc(0);
2518     const Variable *Dest = this->Dest;
2519     if (Src->getType() == IceType_i32 && Dest->getType() == IceType_i64) {
2520       Ostream &Str = Func->getContext()->getStrEmit();
2521       if (mayBeElided(Dest, Src)) {
2522         Str << "\t/* elided movzx */";
2523       } else {
2524         Str << "\t"
2525                "mov"
2526                "\t";
2527         Src->emit(Func);
2528         Str << ", ";
2529         Dest->asType(Func, IceType_i32,
2530                      Traits::getGprForType(IceType_i32, Dest->getRegNum()))
2531             ->emit(Func);
2532         Str << " /* movzx */";
2533       }
2534       return;
2535     }
2536   }
2537   InstX86BaseUnaryopGPR<InstX86Base::Movzx>::emit(Func);
2538 }
2539 
2540 template <typename TraitsType>
emitIAS(const Cfg * Func)2541 void InstImpl<TraitsType>::InstX86Movzx::emitIAS(const Cfg *Func) const {
2542   assert(this->getSrcSize() == 1);
2543   const Variable *Dest = this->getDest();
2544   const Operand *Src = this->getSrc(0);
2545   Type SrcTy = Src->getType();
2546   assert(typeWidthInBytes(Dest->getType()) > 1);
2547   assert(typeWidthInBytes(Dest->getType()) > typeWidthInBytes(SrcTy));
2548   if (Traits::Is64Bit) {
2549     if (Src->getType() == IceType_i32 && Dest->getType() == IceType_i64 &&
2550         mayBeElided(Dest, Src)) {
2551       return;
2552     }
2553   }
2554   constexpr bool NotLea = false;
2555   emitIASRegOpTyGPR<false, true>(Func, NotLea, SrcTy, Dest, Src, this->Emitter);
2556 }
2557 
2558 template <typename TraitsType>
emit(const Cfg * Func)2559 void InstImpl<TraitsType>::InstX86Nop::emit(const Cfg *Func) const {
2560   if (!BuildDefs::dump())
2561     return;
2562   Ostream &Str = Func->getContext()->getStrEmit();
2563   // TODO: Emit the right code for each variant.
2564   Str << "\t"
2565          "nop\t/* variant = " << Variant << " */";
2566 }
2567 
2568 template <typename TraitsType>
emitIAS(const Cfg * Func)2569 void InstImpl<TraitsType>::InstX86Nop::emitIAS(const Cfg *Func) const {
2570   Assembler *Asm = Func->getAssembler<Assembler>();
2571   // TODO: Emit the right code for the variant.
2572   Asm->nop();
2573 }
2574 
2575 template <typename TraitsType>
dump(const Cfg * Func)2576 void InstImpl<TraitsType>::InstX86Nop::dump(const Cfg *Func) const {
2577   if (!BuildDefs::dump())
2578     return;
2579   Ostream &Str = Func->getContext()->getStrDump();
2580   Str << "nop (variant = " << Variant << ")";
2581 }
2582 
2583 template <typename TraitsType>
emit(const Cfg * Func)2584 void InstImpl<TraitsType>::InstX86Fld::emit(const Cfg *Func) const {
2585   if (!BuildDefs::dump())
2586     return;
2587   Ostream &Str = Func->getContext()->getStrEmit();
2588   assert(this->getSrcSize() == 1);
2589   Type Ty = this->getSrc(0)->getType();
2590   const auto *Var = llvm::dyn_cast<Variable>(this->getSrc(0));
2591   if (Var && Var->hasReg()) {
2592     // This is a physical xmm register, so we need to spill it to a temporary
2593     // stack slot.  Function prolog emission guarantees that there is sufficient
2594     // space to do this.
2595     Str << "\t"
2596            "mov" << Traits::TypeAttributes[Ty].SdSsString << "\t";
2597     Var->emit(Func);
2598     Str << ", (%esp)\n"
2599            "\t"
2600            "fld" << this->getFldString(Ty) << "\t"
2601                                               "(%esp)";
2602     return;
2603   }
2604   Str << "\t"
2605          "fld" << this->getFldString(Ty) << "\t";
2606   this->getSrc(0)->emit(Func);
2607 }
2608 
2609 template <typename TraitsType>
emitIAS(const Cfg * Func)2610 void InstImpl<TraitsType>::InstX86Fld::emitIAS(const Cfg *Func) const {
2611   Assembler *Asm = Func->getAssembler<Assembler>();
2612   assert(this->getSrcSize() == 1);
2613   const Operand *Src = this->getSrc(0);
2614   auto *Target = InstX86Base::getTarget(Func);
2615   Type Ty = Src->getType();
2616   if (const auto *Var = llvm::dyn_cast<Variable>(Src)) {
2617     if (Var->hasReg()) {
2618       // This is a physical xmm register, so we need to spill it to a temporary
2619       // stack slot.  Function prolog emission guarantees that there is
2620       // sufficient space to do this.
2621       Address StackSlot =
2622           Address(RegisterSet::Encoded_Reg_esp, 0, AssemblerFixup::NoFixup);
2623       Asm->movss(Ty, StackSlot, Traits::getEncodedXmm(Var->getRegNum()));
2624       Asm->fld(Ty, StackSlot);
2625     } else {
2626       Address StackAddr(Target->stackVarToAsmOperand(Var));
2627       Asm->fld(Ty, StackAddr);
2628     }
2629   } else if (const auto *Mem = llvm::dyn_cast<X86OperandMem>(Src)) {
2630     assert(Mem->getSegmentRegister() == X86OperandMem::DefaultSegment);
2631     Asm->fld(Ty, Mem->toAsmAddress(Asm, Target));
2632   } else if (const auto *Imm = llvm::dyn_cast<Constant>(Src)) {
2633     Asm->fld(Ty, Traits::Address::ofConstPool(Asm, Imm));
2634   } else {
2635     llvm_unreachable("Unexpected operand type");
2636   }
2637 }
2638 
2639 template <typename TraitsType>
dump(const Cfg * Func)2640 void InstImpl<TraitsType>::InstX86Fld::dump(const Cfg *Func) const {
2641   if (!BuildDefs::dump())
2642     return;
2643   Ostream &Str = Func->getContext()->getStrDump();
2644   Str << "fld." << this->getSrc(0)->getType() << " ";
2645   this->dumpSources(Func);
2646 }
2647 
2648 template <typename TraitsType>
emit(const Cfg * Func)2649 void InstImpl<TraitsType>::InstX86Fstp::emit(const Cfg *Func) const {
2650   if (!BuildDefs::dump())
2651     return;
2652   Ostream &Str = Func->getContext()->getStrEmit();
2653   assert(this->getSrcSize() == 0);
2654   // TODO(jvoung,stichnot): Utilize this by setting Dest to nullptr to
2655   // "partially" delete the fstp if the Dest is unused. Even if Dest is unused,
2656   // the fstp should be kept for the SideEffects of popping the stack.
2657   if (!this->getDest()) {
2658     Str << "\t"
2659            "fstp\t"
2660            "st(0)";
2661     return;
2662   }
2663   Type Ty = this->getDest()->getType();
2664   if (!this->getDest()->hasReg()) {
2665     Str << "\t"
2666            "fstp" << this->getFldString(Ty) << "\t";
2667     this->getDest()->emit(Func);
2668     return;
2669   }
2670   // Dest is a physical (xmm) register, so st(0) needs to go through memory.
2671   // Hack this by using caller-reserved memory at the top of stack, spilling
2672   // st(0) there, and loading it into the xmm register.
2673   Str << "\t"
2674          "fstp" << this->getFldString(Ty) << "\t"
2675                                              "(%esp)\n";
2676   Str << "\t"
2677          "mov" << Traits::TypeAttributes[Ty].SdSsString << "\t"
2678                                                            "(%esp), ";
2679   this->getDest()->emit(Func);
2680 }
2681 
2682 template <typename TraitsType>
emitIAS(const Cfg * Func)2683 void InstImpl<TraitsType>::InstX86Fstp::emitIAS(const Cfg *Func) const {
2684   Assembler *Asm = Func->getAssembler<Assembler>();
2685   assert(this->getSrcSize() == 0);
2686   const Variable *Dest = this->getDest();
2687   // TODO(jvoung,stichnot): Utilize this by setting Dest to nullptr to
2688   // "partially" delete the fstp if the Dest is unused. Even if Dest is unused,
2689   // the fstp should be kept for the SideEffects of popping the stack.
2690   if (!Dest) {
2691     Asm->fstp(RegisterSet::getEncodedSTReg(0));
2692     return;
2693   }
2694   auto *Target = InstX86Base::getTarget(Func);
2695   Type Ty = Dest->getType();
2696   if (!Dest->hasReg()) {
2697     Address StackAddr(Target->stackVarToAsmOperand(Dest));
2698     Asm->fstp(Ty, StackAddr);
2699   } else {
2700     // Dest is a physical (xmm) register, so st(0) needs to go through memory.
2701     // Hack this by using caller-reserved memory at the top of stack, spilling
2702     // st(0) there, and loading it into the xmm register.
2703     Address StackSlot =
2704         Address(RegisterSet::Encoded_Reg_esp, 0, AssemblerFixup::NoFixup);
2705     Asm->fstp(Ty, StackSlot);
2706     Asm->movss(Ty, Traits::getEncodedXmm(Dest->getRegNum()), StackSlot);
2707   }
2708 }
2709 
2710 template <typename TraitsType>
dump(const Cfg * Func)2711 void InstImpl<TraitsType>::InstX86Fstp::dump(const Cfg *Func) const {
2712   if (!BuildDefs::dump())
2713     return;
2714   Ostream &Str = Func->getContext()->getStrDump();
2715   this->dumpDest(Func);
2716   Str << " = fstp." << this->getDest()->getType() << ", st(0)";
2717 }
2718 
2719 template <typename TraitsType>
emit(const Cfg * Func)2720 void InstImpl<TraitsType>::InstX86Pextr::emit(const Cfg *Func) const {
2721   if (!BuildDefs::dump())
2722     return;
2723   Ostream &Str = Func->getContext()->getStrEmit();
2724   assert(this->getSrcSize() == 2);
2725   // pextrb and pextrd are SSE4.1 instructions.
2726   Str << "\t" << this->Opcode
2727       << Traits::TypeAttributes[this->getSrc(0)->getType()].IntegralString
2728       << "\t";
2729   this->getSrc(1)->emit(Func);
2730   Str << ", ";
2731   this->getSrc(0)->emit(Func);
2732   Str << ", ";
2733   Variable *Dest = this->getDest();
2734   // pextrw must take a register dest. There is an SSE4.1 version that takes a
2735   // memory dest, but we aren't using it. For uniformity, just restrict them
2736   // all to have a register dest for now.
2737   assert(Dest->hasReg());
2738   Dest->asType(Func, IceType_i32, Dest->getRegNum())->emit(Func);
2739 }
2740 
2741 template <typename TraitsType>
emitIAS(const Cfg * Func)2742 void InstImpl<TraitsType>::InstX86Pextr::emitIAS(const Cfg *Func) const {
2743   assert(this->getSrcSize() == 2);
2744   // pextrb and pextrd are SSE4.1 instructions.
2745   const Variable *Dest = this->getDest();
2746   Type DispatchTy = Traits::getInVectorElementType(this->getSrc(0)->getType());
2747   // pextrw must take a register dest. There is an SSE4.1 version that takes a
2748   // memory dest, but we aren't using it. For uniformity, just restrict them
2749   // all to have a register dest for now.
2750   assert(Dest->hasReg());
2751   // pextrw's Src(0) must be a register (both SSE4.1 and SSE2).
2752   assert(llvm::cast<Variable>(this->getSrc(0))->hasReg());
2753   static const ThreeOpImmEmitter<GPRRegister, XmmRegister> Emitter = {
2754       &Assembler::pextr, nullptr};
2755   emitIASThreeOpImmOps<GPRRegister, XmmRegister, Traits::getEncodedGPR,
2756                        Traits::getEncodedXmm>(
2757       Func, DispatchTy, Dest, this->getSrc(0), this->getSrc(1), Emitter);
2758 }
2759 
2760 template <typename TraitsType>
emit(const Cfg * Func)2761 void InstImpl<TraitsType>::InstX86Pinsr::emit(const Cfg *Func) const {
2762   if (!BuildDefs::dump())
2763     return;
2764   Ostream &Str = Func->getContext()->getStrEmit();
2765   assert(this->getSrcSize() == 3);
2766   Str << "\t" << this->Opcode
2767       << Traits::TypeAttributes[this->getDest()->getType()].IntegralString
2768       << "\t";
2769   this->getSrc(2)->emit(Func);
2770   Str << ", ";
2771   Operand *Src1 = this->getSrc(1);
2772   if (const auto *Src1Var = llvm::dyn_cast<Variable>(Src1)) {
2773     // If src1 is a register, it should always be r32.
2774     if (Src1Var->hasReg()) {
2775       const auto NewRegNum = Traits::getBaseReg(Src1Var->getRegNum());
2776       const Variable *NewSrc = Src1Var->asType(Func, IceType_i32, NewRegNum);
2777       NewSrc->emit(Func);
2778     } else {
2779       Src1Var->emit(Func);
2780     }
2781   } else {
2782     Src1->emit(Func);
2783   }
2784   Str << ", ";
2785   this->getDest()->emit(Func);
2786 }
2787 
2788 template <typename TraitsType>
emitIAS(const Cfg * Func)2789 void InstImpl<TraitsType>::InstX86Pinsr::emitIAS(const Cfg *Func) const {
2790   assert(this->getSrcSize() == 3);
2791   assert(this->getDest() == this->getSrc(0));
2792   // pinsrb and pinsrd are SSE4.1 instructions.
2793   const Operand *Src0 = this->getSrc(1);
2794   Type DispatchTy = Src0->getType();
2795   // If src1 is a register, it should always be r32 (this should fall out from
2796   // the encodings for ByteRegs overlapping the encodings for r32), but we have
2797   // to make sure the register allocator didn't choose an 8-bit high register
2798   // like "ah".
2799   if (BuildDefs::asserts()) {
2800     if (auto *Src0Var = llvm::dyn_cast<Variable>(Src0)) {
2801       if (Src0Var->hasReg()) {
2802         const auto RegNum = Src0Var->getRegNum();
2803         const auto BaseRegNum = Traits::getBaseReg(RegNum);
2804         (void)BaseRegNum;
2805         assert(Traits::getEncodedGPR(RegNum) ==
2806                Traits::getEncodedGPR(BaseRegNum));
2807       }
2808     }
2809   }
2810   static const ThreeOpImmEmitter<XmmRegister, GPRRegister> Emitter = {
2811       &Assembler::pinsr, &Assembler::pinsr};
2812   emitIASThreeOpImmOps<XmmRegister, GPRRegister, Traits::getEncodedXmm,
2813                        Traits::getEncodedGPR>(Func, DispatchTy, this->getDest(),
2814                                               Src0, this->getSrc(2), Emitter);
2815 }
2816 
2817 template <typename TraitsType>
emitIAS(const Cfg * Func)2818 void InstImpl<TraitsType>::InstX86Pshufd::emitIAS(const Cfg *Func) const {
2819   assert(this->getSrcSize() == 2);
2820   const Variable *Dest = this->getDest();
2821   Type Ty = Dest->getType();
2822   static const ThreeOpImmEmitter<XmmRegister, XmmRegister> Emitter = {
2823       &Assembler::pshufd, &Assembler::pshufd};
2824   emitIASThreeOpImmOps<XmmRegister, XmmRegister, Traits::getEncodedXmm,
2825                        Traits::getEncodedXmm>(Func, Ty, Dest, this->getSrc(0),
2826                                               this->getSrc(1), Emitter);
2827 }
2828 
2829 template <typename TraitsType>
emitIAS(const Cfg * Func)2830 void InstImpl<TraitsType>::InstX86Shufps::emitIAS(const Cfg *Func) const {
2831   assert(this->getSrcSize() == 3);
2832   const Variable *Dest = this->getDest();
2833   assert(Dest == this->getSrc(0));
2834   Type Ty = Dest->getType();
2835   static const ThreeOpImmEmitter<XmmRegister, XmmRegister> Emitter = {
2836       &Assembler::shufps, &Assembler::shufps};
2837   emitIASThreeOpImmOps<XmmRegister, XmmRegister, Traits::getEncodedXmm,
2838                        Traits::getEncodedXmm>(Func, Ty, Dest, this->getSrc(1),
2839                                               this->getSrc(2), Emitter);
2840 }
2841 
2842 template <typename TraitsType>
emit(const Cfg * Func)2843 void InstImpl<TraitsType>::InstX86Pop::emit(const Cfg *Func) const {
2844   if (!BuildDefs::dump())
2845     return;
2846   Ostream &Str = Func->getContext()->getStrEmit();
2847   assert(this->getSrcSize() == 0);
2848   Str << "\t"
2849          "pop\t";
2850   this->getDest()->emit(Func);
2851 }
2852 
2853 template <typename TraitsType>
emitIAS(const Cfg * Func)2854 void InstImpl<TraitsType>::InstX86Pop::emitIAS(const Cfg *Func) const {
2855   assert(this->getSrcSize() == 0);
2856   Assembler *Asm = Func->getAssembler<Assembler>();
2857   if (this->getDest()->hasReg()) {
2858     Asm->popl(Traits::getEncodedGPR(this->getDest()->getRegNum()));
2859   } else {
2860     auto *Target = InstX86Base::getTarget(Func);
2861     Asm->popl(Target->stackVarToAsmOperand(this->getDest()));
2862   }
2863 }
2864 
2865 template <typename TraitsType>
dump(const Cfg * Func)2866 void InstImpl<TraitsType>::InstX86Pop::dump(const Cfg *Func) const {
2867   if (!BuildDefs::dump())
2868     return;
2869   Ostream &Str = Func->getContext()->getStrDump();
2870   this->dumpDest(Func);
2871   Str << " = pop." << this->getDest()->getType() << " ";
2872 }
2873 
2874 template <typename TraitsType>
emit(const Cfg * Func)2875 void InstImpl<TraitsType>::InstX86Push::emit(const Cfg *Func) const {
2876   if (!BuildDefs::dump())
2877     return;
2878   Ostream &Str = Func->getContext()->getStrEmit();
2879   Str << "\t"
2880          "push"
2881          "\t";
2882   assert(this->getSrcSize() == 1);
2883   const Operand *Src = this->getSrc(0);
2884   Src->emit(Func);
2885 }
2886 
2887 template <typename TraitsType>
emitIAS(const Cfg * Func)2888 void InstImpl<TraitsType>::InstX86Push::emitIAS(const Cfg *Func) const {
2889   Assembler *Asm = Func->getAssembler<Assembler>();
2890 
2891   assert(this->getSrcSize() == 1);
2892   const Operand *Src = this->getSrc(0);
2893 
2894   if (const auto *Var = llvm::dyn_cast<Variable>(Src)) {
2895     Asm->pushl(Traits::getEncodedGPR(Var->getRegNum()));
2896   } else if (const auto *Const32 = llvm::dyn_cast<ConstantInteger32>(Src)) {
2897     Asm->pushl(AssemblerImmediate(Const32->getValue()));
2898   } else if (auto *CR = llvm::dyn_cast<ConstantRelocatable>(Src)) {
2899     Asm->pushl(CR);
2900   } else {
2901     llvm_unreachable("Unexpected operand type");
2902   }
2903 }
2904 
2905 template <typename TraitsType>
dump(const Cfg * Func)2906 void InstImpl<TraitsType>::InstX86Push::dump(const Cfg *Func) const {
2907   if (!BuildDefs::dump())
2908     return;
2909   Ostream &Str = Func->getContext()->getStrDump();
2910   Str << "push." << this->getSrc(0)->getType() << " ";
2911   this->dumpSources(Func);
2912 }
2913 
2914 template <typename TraitsType>
emit(const Cfg * Func)2915 void InstImpl<TraitsType>::InstX86Ret::emit(const Cfg *Func) const {
2916   if (!BuildDefs::dump())
2917     return;
2918   Ostream &Str = Func->getContext()->getStrEmit();
2919   Str << "\t"
2920          "ret";
2921 }
2922 
2923 template <typename TraitsType>
emitIAS(const Cfg * Func)2924 void InstImpl<TraitsType>::InstX86Ret::emitIAS(const Cfg *Func) const {
2925   Assembler *Asm = Func->getAssembler<Assembler>();
2926   Asm->ret();
2927 }
2928 
2929 template <typename TraitsType>
dump(const Cfg * Func)2930 void InstImpl<TraitsType>::InstX86Ret::dump(const Cfg *Func) const {
2931   if (!BuildDefs::dump())
2932     return;
2933   Ostream &Str = Func->getContext()->getStrDump();
2934   Type Ty =
2935       (this->getSrcSize() == 0 ? IceType_void : this->getSrc(0)->getType());
2936   Str << "ret." << Ty << " ";
2937   this->dumpSources(Func);
2938 }
2939 
2940 template <typename TraitsType>
emit(const Cfg * Func)2941 void InstImpl<TraitsType>::InstX86Setcc::emit(const Cfg *Func) const {
2942   if (!BuildDefs::dump())
2943     return;
2944   Ostream &Str = Func->getContext()->getStrEmit();
2945   Str << "\t"
2946          "set" << Traits::InstBrAttributes[Condition].DisplayString << "\t";
2947   this->Dest->emit(Func);
2948 }
2949 
2950 template <typename TraitsType>
emitIAS(const Cfg * Func)2951 void InstImpl<TraitsType>::InstX86Setcc::emitIAS(const Cfg *Func) const {
2952   assert(Condition != Cond::Br_None);
2953   assert(this->getDest()->getType() == IceType_i1);
2954   assert(this->getSrcSize() == 0);
2955   Assembler *Asm = Func->getAssembler<Assembler>();
2956   auto *Target = InstX86Base::getTarget(Func);
2957   if (this->getDest()->hasReg())
2958     Asm->setcc(Condition,
2959                Traits::getEncodedByteReg(this->getDest()->getRegNum()));
2960   else
2961     Asm->setcc(Condition, Target->stackVarToAsmOperand(this->getDest()));
2962   return;
2963 }
2964 
2965 template <typename TraitsType>
dump(const Cfg * Func)2966 void InstImpl<TraitsType>::InstX86Setcc::dump(const Cfg *Func) const {
2967   if (!BuildDefs::dump())
2968     return;
2969   Ostream &Str = Func->getContext()->getStrDump();
2970   Str << "setcc." << Traits::InstBrAttributes[Condition].DisplayString << " ";
2971   this->dumpDest(Func);
2972 }
2973 
2974 template <typename TraitsType>
emit(const Cfg * Func)2975 void InstImpl<TraitsType>::InstX86Xadd::emit(const Cfg *Func) const {
2976   if (!BuildDefs::dump())
2977     return;
2978   Ostream &Str = Func->getContext()->getStrEmit();
2979   if (this->Locked) {
2980     Str << "\t"
2981            "lock";
2982   }
2983   Str << "\t"
2984          "xadd" << this->getWidthString(this->getSrc(0)->getType()) << "\t";
2985   this->getSrc(1)->emit(Func);
2986   Str << ", ";
2987   this->getSrc(0)->emit(Func);
2988 }
2989 
2990 template <typename TraitsType>
emitIAS(const Cfg * Func)2991 void InstImpl<TraitsType>::InstX86Xadd::emitIAS(const Cfg *Func) const {
2992   assert(this->getSrcSize() == 2);
2993   Assembler *Asm = Func->getAssembler<Assembler>();
2994   Type Ty = this->getSrc(0)->getType();
2995   const auto Mem = llvm::cast<X86OperandMem>(this->getSrc(0));
2996   assert(Mem->getSegmentRegister() == X86OperandMem::DefaultSegment);
2997   auto *Target = InstX86Base::getTarget(Func);
2998   const Address Addr = Mem->toAsmAddress(Asm, Target);
2999   const auto *VarReg = llvm::cast<Variable>(this->getSrc(1));
3000   assert(VarReg->hasReg());
3001   const GPRRegister Reg = Traits::getEncodedGPR(VarReg->getRegNum());
3002   Asm->xadd(Ty, Addr, Reg, this->Locked);
3003 }
3004 
3005 template <typename TraitsType>
dump(const Cfg * Func)3006 void InstImpl<TraitsType>::InstX86Xadd::dump(const Cfg *Func) const {
3007   if (!BuildDefs::dump())
3008     return;
3009   Ostream &Str = Func->getContext()->getStrDump();
3010   if (this->Locked) {
3011     Str << "lock ";
3012   }
3013   Type Ty = this->getSrc(0)->getType();
3014   Str << "xadd." << Ty << " ";
3015   this->dumpSources(Func);
3016 }
3017 
3018 template <typename TraitsType>
emit(const Cfg * Func)3019 void InstImpl<TraitsType>::InstX86Xchg::emit(const Cfg *Func) const {
3020   if (!BuildDefs::dump())
3021     return;
3022   Ostream &Str = Func->getContext()->getStrEmit();
3023   Str << "\t"
3024          "xchg" << this->getWidthString(this->getSrc(0)->getType()) << "\t";
3025   this->getSrc(1)->emit(Func);
3026   Str << ", ";
3027   this->getSrc(0)->emit(Func);
3028 }
3029 
3030 template <typename TraitsType>
emitIAS(const Cfg * Func)3031 void InstImpl<TraitsType>::InstX86Xchg::emitIAS(const Cfg *Func) const {
3032   assert(this->getSrcSize() == 2);
3033   Assembler *Asm = Func->getAssembler<Assembler>();
3034   Type Ty = this->getSrc(0)->getType();
3035   const auto *VarReg1 = llvm::cast<Variable>(this->getSrc(1));
3036   assert(VarReg1->hasReg());
3037   const GPRRegister Reg1 = Traits::getEncodedGPR(VarReg1->getRegNum());
3038 
3039   if (const auto *VarReg0 = llvm::dyn_cast<Variable>(this->getSrc(0))) {
3040     assert(VarReg0->hasReg());
3041     const GPRRegister Reg0 = Traits::getEncodedGPR(VarReg0->getRegNum());
3042     Asm->xchg(Ty, Reg0, Reg1);
3043     return;
3044   }
3045 
3046   const auto *Mem = llvm::cast<X86OperandMem>(this->getSrc(0));
3047   assert(Mem->getSegmentRegister() == X86OperandMem::DefaultSegment);
3048   auto *Target = InstX86Base::getTarget(Func);
3049   const Address Addr = Mem->toAsmAddress(Asm, Target);
3050   Asm->xchg(Ty, Addr, Reg1);
3051 }
3052 
3053 template <typename TraitsType>
dump(const Cfg * Func)3054 void InstImpl<TraitsType>::InstX86Xchg::dump(const Cfg *Func) const {
3055   if (!BuildDefs::dump())
3056     return;
3057   Ostream &Str = Func->getContext()->getStrDump();
3058   Type Ty = this->getSrc(0)->getType();
3059   Str << "xchg." << Ty << " ";
3060   this->dumpSources(Func);
3061 }
3062 
3063 template <typename TraitsType>
emit(const Cfg * Func)3064 void InstImpl<TraitsType>::InstX86IacaStart::emit(const Cfg *Func) const {
3065   if (!BuildDefs::dump())
3066     return;
3067   Ostream &Str = Func->getContext()->getStrEmit();
3068   Str << "\t# IACA_START\n"
3069          "\t.byte 0x0F, 0x0B\n"
3070          "\t"
3071          "movl\t$111, %ebx\n"
3072          "\t.byte 0x64, 0x67, 0x90";
3073 }
3074 
3075 template <typename TraitsType>
emitIAS(const Cfg * Func)3076 void InstImpl<TraitsType>::InstX86IacaStart::emitIAS(const Cfg *Func) const {
3077   Assembler *Asm = Func->getAssembler<Assembler>();
3078   Asm->iaca_start();
3079 }
3080 
3081 template <typename TraitsType>
dump(const Cfg * Func)3082 void InstImpl<TraitsType>::InstX86IacaStart::dump(const Cfg *Func) const {
3083   if (!BuildDefs::dump())
3084     return;
3085   Ostream &Str = Func->getContext()->getStrDump();
3086   Str << "IACA_START";
3087 }
3088 
3089 template <typename TraitsType>
emit(const Cfg * Func)3090 void InstImpl<TraitsType>::InstX86IacaEnd::emit(const Cfg *Func) const {
3091   if (!BuildDefs::dump())
3092     return;
3093   Ostream &Str = Func->getContext()->getStrEmit();
3094   Str << "\t# IACA_END\n"
3095          "\t"
3096          "movl\t$222, %ebx\n"
3097          "\t.byte 0x64, 0x67, 0x90\n"
3098          "\t.byte 0x0F, 0x0B";
3099 }
3100 
3101 template <typename TraitsType>
emitIAS(const Cfg * Func)3102 void InstImpl<TraitsType>::InstX86IacaEnd::emitIAS(const Cfg *Func) const {
3103   Assembler *Asm = Func->getAssembler<Assembler>();
3104   Asm->iaca_end();
3105 }
3106 
3107 template <typename TraitsType>
dump(const Cfg * Func)3108 void InstImpl<TraitsType>::InstX86IacaEnd::dump(const Cfg *Func) const {
3109   if (!BuildDefs::dump())
3110     return;
3111   Ostream &Str = Func->getContext()->getStrDump();
3112   Str << "IACA_END";
3113 }
3114 
3115 } // end of namespace X86NAMESPACE
3116 
3117 } // end of namespace Ice
3118 
3119 #endif // SUBZERO_SRC_ICEINSTX86BASEIMPL_H
3120