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