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