1 //===- subzero/src/IceInstX86BaseImpl.h - Generic X86 instructions -*- C++ -*=//
3 // The Subzero Code Generator
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
11 /// This file implements the InstX86Base class and its descendants.
13 //===----------------------------------------------------------------------===//
15 #ifndef SUBZERO_SRC_ICEINSTX86BASEIMPL_H
16 #define SUBZERO_SRC_ICEINSTX86BASEIMPL_H
18 #include "IceInstX86Base.h"
20 #include "IceAssemblerX86Base.h"
22 #include "IceCfgNode.h"
25 #include "IceOperand.h"
26 #include "IceTargetLowering.h"
30 namespace X86Internal {
32 template <class Machine>
33 const char *InstX86Base<Machine>::getWidthString(Type Ty) {
34 return Traits::TypeAttributes[Ty].WidthString;
37 template <class Machine>
38 const char *InstX86Base<Machine>::getFldString(Type Ty) {
39 return Traits::TypeAttributes[Ty].FldString;
42 template <class Machine>
43 typename InstX86Base<Machine>::Traits::Cond::BrCond
44 InstX86Base<Machine>::getOppositeCondition(typename Traits::Cond::BrCond Cond) {
45 return Traits::InstBrAttributes[Cond].Opposite;
48 template <class Machine>
49 InstX86FakeRMW<Machine>::InstX86FakeRMW(Cfg *Func, Operand *Data, Operand *Addr,
50 InstArithmetic::OpKind Op,
52 : InstX86Base<Machine>(Func, InstX86Base<Machine>::FakeRMW, 3, nullptr),
54 this->addSource(Data);
55 this->addSource(Addr);
56 this->addSource(Beacon);
59 template <class Machine>
60 InstX86AdjustStack<Machine>::InstX86AdjustStack(Cfg *Func, SizeT Amount,
62 : InstX86Base<Machine>(Func, InstX86Base<Machine>::Adjuststack, 1, Esp),
67 template <class Machine>
68 InstX86Mul<Machine>::InstX86Mul(Cfg *Func, Variable *Dest, Variable *Source1,
70 : InstX86Base<Machine>(Func, InstX86Base<Machine>::Mul, 2, Dest) {
71 this->addSource(Source1);
72 this->addSource(Source2);
75 template <class Machine>
76 InstX86Shld<Machine>::InstX86Shld(Cfg *Func, Variable *Dest, Variable *Source1,
78 : InstX86Base<Machine>(Func, InstX86Base<Machine>::Shld, 3, Dest) {
79 this->addSource(Dest);
80 this->addSource(Source1);
81 this->addSource(Source2);
84 template <class Machine>
85 InstX86Shrd<Machine>::InstX86Shrd(Cfg *Func, Variable *Dest, Variable *Source1,
87 : InstX86Base<Machine>(Func, InstX86Base<Machine>::Shrd, 3, Dest) {
88 this->addSource(Dest);
89 this->addSource(Source1);
90 this->addSource(Source2);
93 template <class Machine>
94 InstX86Label<Machine>::InstX86Label(
95 Cfg *Func, typename InstX86Base<Machine>::Traits::TargetLowering *Target)
96 : InstX86Base<Machine>(Func, InstX86Base<Machine>::Label, 0, nullptr),
97 Number(Target->makeNextLabelNumber()) {}
99 template <class Machine>
100 IceString InstX86Label<Machine>::getName(const Cfg *Func) const {
101 return ".L" + Func->getFunctionName() + "$local$__" + std::to_string(Number);
104 template <class Machine>
105 InstX86Br<Machine>::InstX86Br(
106 Cfg *Func, const CfgNode *TargetTrue, const CfgNode *TargetFalse,
107 const InstX86Label<Machine> *Label,
108 typename InstX86Base<Machine>::Traits::Cond::BrCond Condition, Mode Kind)
109 : InstX86Base<Machine>(Func, InstX86Base<Machine>::Br, 0, nullptr),
110 Condition(Condition), TargetTrue(TargetTrue), TargetFalse(TargetFalse),
111 Label(Label), Kind(Kind) {}
113 template <class Machine>
114 bool InstX86Br<Machine>::optimizeBranch(const CfgNode *NextNode) {
115 // If there is no next block, then there can be no fallthrough to optimize.
116 if (NextNode == nullptr)
118 // Intra-block conditional branches can't be optimized.
121 // If there is no fallthrough node, such as a non-default case label for a
122 // switch instruction, then there is no opportunity to optimize.
123 if (getTargetFalse() == nullptr)
126 // Unconditional branch to the next node can be removed.
127 if (Condition == InstX86Base<Machine>::Traits::Cond::Br_None &&
128 getTargetFalse() == NextNode) {
129 assert(getTargetTrue() == nullptr);
133 // If the fallthrough is to the next node, set fallthrough to nullptr to
135 if (getTargetFalse() == NextNode) {
136 TargetFalse = nullptr;
139 // If TargetTrue is the next node, and TargetFalse is not nullptr (which was
140 // already tested above), then invert the branch condition, swap the targets,
141 // and set new fallthrough to nullptr.
142 if (getTargetTrue() == NextNode) {
143 assert(Condition != InstX86Base<Machine>::Traits::Cond::Br_None);
144 Condition = this->getOppositeCondition(Condition);
145 TargetTrue = getTargetFalse();
146 TargetFalse = nullptr;
152 template <class Machine>
153 bool InstX86Br<Machine>::repointEdges(CfgNode *OldNode, CfgNode *NewNode) {
155 if (TargetFalse == OldNode) {
156 TargetFalse = NewNode;
159 if (TargetTrue == OldNode) {
160 TargetTrue = NewNode;
166 template <class Machine>
167 InstX86Jmp<Machine>::InstX86Jmp(Cfg *Func, Operand *Target)
168 : InstX86Base<Machine>(Func, InstX86Base<Machine>::Jmp, 1, nullptr) {
169 this->addSource(Target);
172 template <class Machine>
173 InstX86Call<Machine>::InstX86Call(Cfg *Func, Variable *Dest,
175 : InstX86Base<Machine>(Func, InstX86Base<Machine>::Call, 1, Dest) {
176 this->HasSideEffects = true;
177 this->addSource(CallTarget);
180 template <class Machine>
181 InstX86Cmov<Machine>::InstX86Cmov(
182 Cfg *Func, Variable *Dest, Operand *Source,
183 typename InstX86Base<Machine>::Traits::Cond::BrCond Condition)
184 : InstX86Base<Machine>(Func, InstX86Base<Machine>::Cmov, 2, Dest),
185 Condition(Condition) {
186 // The final result is either the original Dest, or Source, so mark both as
188 this->addSource(Dest);
189 this->addSource(Source);
192 template <class Machine>
193 InstX86Cmpps<Machine>::InstX86Cmpps(
194 Cfg *Func, Variable *Dest, Operand *Source,
195 typename InstX86Base<Machine>::Traits::Cond::CmppsCond Condition)
196 : InstX86Base<Machine>(Func, InstX86Base<Machine>::Cmpps, 2, Dest),
197 Condition(Condition) {
198 this->addSource(Dest);
199 this->addSource(Source);
202 template <class Machine>
203 InstX86Cmpxchg<Machine>::InstX86Cmpxchg(Cfg *Func, Operand *DestOrAddr,
204 Variable *Eax, Variable *Desired,
206 : InstX86BaseLockable<Machine>(Func, InstX86Base<Machine>::Cmpxchg, 3,
207 llvm::dyn_cast<Variable>(DestOrAddr),
209 assert(Eax->getRegNum() ==
210 InstX86Base<Machine>::Traits::RegisterSet::Reg_eax);
211 this->addSource(DestOrAddr);
212 this->addSource(Eax);
213 this->addSource(Desired);
216 template <class Machine>
217 InstX86Cmpxchg8b<Machine>::InstX86Cmpxchg8b(
218 Cfg *Func, typename InstX86Base<Machine>::Traits::X86OperandMem *Addr,
219 Variable *Edx, Variable *Eax, Variable *Ecx, Variable *Ebx, bool Locked)
220 : InstX86BaseLockable<Machine>(Func, InstX86Base<Machine>::Cmpxchg, 5,
222 assert(Edx->getRegNum() ==
223 InstX86Base<Machine>::Traits::RegisterSet::Reg_edx);
224 assert(Eax->getRegNum() ==
225 InstX86Base<Machine>::Traits::RegisterSet::Reg_eax);
226 assert(Ecx->getRegNum() ==
227 InstX86Base<Machine>::Traits::RegisterSet::Reg_ecx);
228 assert(Ebx->getRegNum() ==
229 InstX86Base<Machine>::Traits::RegisterSet::Reg_ebx);
230 this->addSource(Addr);
231 this->addSource(Edx);
232 this->addSource(Eax);
233 this->addSource(Ecx);
234 this->addSource(Ebx);
237 template <class Machine>
238 InstX86Cvt<Machine>::InstX86Cvt(Cfg *Func, Variable *Dest, Operand *Source,
240 : InstX86Base<Machine>(Func, InstX86Base<Machine>::Cvt, 1, Dest),
242 this->addSource(Source);
245 template <class Machine>
246 InstX86Icmp<Machine>::InstX86Icmp(Cfg *Func, Operand *Src0, Operand *Src1)
247 : InstX86Base<Machine>(Func, InstX86Base<Machine>::Icmp, 2, nullptr) {
248 this->addSource(Src0);
249 this->addSource(Src1);
252 template <class Machine>
253 InstX86Ucomiss<Machine>::InstX86Ucomiss(Cfg *Func, Operand *Src0, Operand *Src1)
254 : InstX86Base<Machine>(Func, InstX86Base<Machine>::Ucomiss, 2, nullptr) {
255 this->addSource(Src0);
256 this->addSource(Src1);
259 template <class Machine>
260 InstX86UD2<Machine>::InstX86UD2(Cfg *Func)
261 : InstX86Base<Machine>(Func, InstX86Base<Machine>::UD2, 0, nullptr) {}
263 template <class Machine>
264 InstX86Test<Machine>::InstX86Test(Cfg *Func, Operand *Src1, Operand *Src2)
265 : InstX86Base<Machine>(Func, InstX86Base<Machine>::Test, 2, nullptr) {
266 this->addSource(Src1);
267 this->addSource(Src2);
270 template <class Machine>
271 InstX86Mfence<Machine>::InstX86Mfence(Cfg *Func)
272 : InstX86Base<Machine>(Func, InstX86Base<Machine>::Mfence, 0, nullptr) {
273 this->HasSideEffects = true;
276 template <class Machine>
277 InstX86Store<Machine>::InstX86Store(
278 Cfg *Func, Operand *Value,
279 typename InstX86Base<Machine>::Traits::X86Operand *Mem)
280 : InstX86Base<Machine>(Func, InstX86Base<Machine>::Store, 2, nullptr) {
281 this->addSource(Value);
282 this->addSource(Mem);
285 template <class Machine>
286 InstX86StoreP<Machine>::InstX86StoreP(
287 Cfg *Func, Variable *Value,
288 typename InstX86Base<Machine>::Traits::X86OperandMem *Mem)
289 : InstX86Base<Machine>(Func, InstX86Base<Machine>::StoreP, 2, nullptr) {
290 this->addSource(Value);
291 this->addSource(Mem);
294 template <class Machine>
295 InstX86StoreQ<Machine>::InstX86StoreQ(
296 Cfg *Func, Variable *Value,
297 typename InstX86Base<Machine>::Traits::X86OperandMem *Mem)
298 : InstX86Base<Machine>(Func, InstX86Base<Machine>::StoreQ, 2, nullptr) {
299 this->addSource(Value);
300 this->addSource(Mem);
303 template <class Machine>
304 InstX86Nop<Machine>::InstX86Nop(Cfg *Func, InstX86Nop::NopVariant Variant)
305 : InstX86Base<Machine>(Func, InstX86Base<Machine>::Nop, 0, nullptr),
308 template <class Machine>
309 InstX86Fld<Machine>::InstX86Fld(Cfg *Func, Operand *Src)
310 : InstX86Base<Machine>(Func, InstX86Base<Machine>::Fld, 1, nullptr) {
311 this->addSource(Src);
314 template <class Machine>
315 InstX86Fstp<Machine>::InstX86Fstp(Cfg *Func, Variable *Dest)
316 : InstX86Base<Machine>(Func, InstX86Base<Machine>::Fstp, 0, Dest) {}
318 template <class Machine>
319 InstX86Pop<Machine>::InstX86Pop(Cfg *Func, Variable *Dest)
320 : InstX86Base<Machine>(Func, InstX86Base<Machine>::Pop, 0, Dest) {
321 // A pop instruction affects the stack pointer and so it should not be
322 // allowed to be automatically dead-code eliminated. (The corresponding push
323 // instruction doesn't need this treatment because it has no dest variable
324 // and therefore won't be dead-code eliminated.) This is needed for
325 // late-stage liveness analysis (e.g. asm-verbose mode).
326 this->HasSideEffects = true;
329 template <class Machine>
330 InstX86Push<Machine>::InstX86Push(Cfg *Func, Variable *Source)
331 : InstX86Base<Machine>(Func, InstX86Base<Machine>::Push, 1, nullptr) {
332 this->addSource(Source);
335 template <class Machine>
336 InstX86Ret<Machine>::InstX86Ret(Cfg *Func, Variable *Source)
337 : InstX86Base<Machine>(Func, InstX86Base<Machine>::Ret, Source ? 1 : 0,
340 this->addSource(Source);
343 template <class Machine>
344 InstX86Setcc<Machine>::InstX86Setcc(
345 Cfg *Func, Variable *Dest,
346 typename InstX86Base<Machine>::Traits::Cond::BrCond Cond)
347 : InstX86Base<Machine>(Func, InstX86Base<Machine>::Setcc, 0, Dest),
350 template <class Machine>
351 InstX86Xadd<Machine>::InstX86Xadd(Cfg *Func, Operand *Dest, Variable *Source,
353 : InstX86BaseLockable<Machine>(Func, InstX86Base<Machine>::Xadd, 2,
354 llvm::dyn_cast<Variable>(Dest), Locked) {
355 this->addSource(Dest);
356 this->addSource(Source);
359 template <class Machine>
360 InstX86Xchg<Machine>::InstX86Xchg(Cfg *Func, Operand *Dest, Variable *Source)
361 : InstX86Base<Machine>(Func, InstX86Base<Machine>::Xchg, 2,
362 llvm::dyn_cast<Variable>(Dest)) {
363 this->addSource(Dest);
364 this->addSource(Source);
367 template <class Machine>
368 InstX86IacaStart<Machine>::InstX86IacaStart(Cfg *Func)
369 : InstX86Base<Machine>(Func, InstX86Base<Machine>::IacaStart, 0, nullptr) {
370 assert(Func->getContext()->getFlags().getAllowIacaMarks());
373 template <class Machine>
374 InstX86IacaEnd<Machine>::InstX86IacaEnd(Cfg *Func)
375 : InstX86Base<Machine>(Func, InstX86Base<Machine>::IacaEnd, 0, nullptr) {
376 assert(Func->getContext()->getFlags().getAllowIacaMarks());
379 // ======================== Dump routines ======================== //
381 template <class Machine>
382 void InstX86Base<Machine>::dump(const Cfg *Func) const {
383 if (!BuildDefs::dump())
385 Ostream &Str = Func->getContext()->getStrDump();
386 Str << "[" << Traits::TargetName << "] ";
390 template <class Machine>
391 void InstX86FakeRMW<Machine>::dump(const Cfg *Func) const {
392 if (!BuildDefs::dump())
394 Ostream &Str = Func->getContext()->getStrDump();
395 Type Ty = getData()->getType();
396 Str << "rmw " << InstArithmetic::getOpName(getOp()) << " " << Ty << " *";
397 getAddr()->dump(Func);
399 getData()->dump(Func);
401 getBeacon()->dump(Func);
404 template <class Machine>
405 void InstX86Label<Machine>::emit(const Cfg *Func) const {
406 if (!BuildDefs::dump())
408 Ostream &Str = Func->getContext()->getStrEmit();
409 Str << getName(Func) << ":";
412 template <class Machine>
413 void InstX86Label<Machine>::emitIAS(const Cfg *Func) const {
414 typename InstX86Base<Machine>::Traits::Assembler *Asm =
415 Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>();
416 Asm->bindLocalLabel(Number);
419 template <class Machine>
420 void InstX86Label<Machine>::dump(const Cfg *Func) const {
421 if (!BuildDefs::dump())
423 Ostream &Str = Func->getContext()->getStrDump();
424 Str << getName(Func) << ":";
427 template <class Machine> void InstX86Br<Machine>::emit(const Cfg *Func) const {
428 if (!BuildDefs::dump())
430 Ostream &Str = Func->getContext()->getStrEmit();
433 if (Condition == InstX86Base<Machine>::Traits::Cond::Br_None) {
436 Str << InstX86Base<Machine>::Traits::InstBrAttributes[Condition].EmitString;
440 Str << "\t" << Label->getName(Func);
442 if (Condition == InstX86Base<Machine>::Traits::Cond::Br_None) {
443 Str << "\t" << getTargetFalse()->getAsmName();
445 Str << "\t" << getTargetTrue()->getAsmName();
446 if (getTargetFalse()) {
447 Str << "\n\tjmp\t" << getTargetFalse()->getAsmName();
453 template <class Machine>
454 void InstX86Br<Machine>::emitIAS(const Cfg *Func) const {
455 typename InstX86Base<Machine>::Traits::Assembler *Asm =
456 Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>();
458 class Label *L = Asm->getOrCreateLocalLabel(Label->getNumber());
459 if (Condition == InstX86Base<Machine>::Traits::Cond::Br_None) {
460 Asm->jmp(L, isNear());
462 Asm->j(Condition, L, isNear());
465 if (Condition == InstX86Base<Machine>::Traits::Cond::Br_None) {
467 Asm->getOrCreateCfgNodeLabel(getTargetFalse()->getIndex());
468 assert(!getTargetTrue());
469 Asm->jmp(L, isNear());
472 Asm->getOrCreateCfgNodeLabel(getTargetTrue()->getIndex());
473 Asm->j(Condition, L, isNear());
474 if (getTargetFalse()) {
476 Asm->getOrCreateCfgNodeLabel(getTargetFalse()->getIndex());
477 Asm->jmp(L2, isNear());
483 template <class Machine> void InstX86Br<Machine>::dump(const Cfg *Func) const {
484 if (!BuildDefs::dump())
486 Ostream &Str = Func->getContext()->getStrDump();
489 if (Condition == InstX86Base<Machine>::Traits::Cond::Br_None) {
491 << (Label ? Label->getName(Func) : getTargetFalse()->getName());
495 Str << InstX86Base<Machine>::Traits::InstBrAttributes[Condition]
498 Str << ", label %" << Label->getName(Func);
500 Str << ", label %" << getTargetTrue()->getName();
501 if (getTargetFalse()) {
502 Str << ", label %" << getTargetFalse()->getName();
506 Str << " // (" << (isNear() ? "near" : "far") << " jump)";
509 template <class Machine> void InstX86Jmp<Machine>::emit(const Cfg *Func) const {
510 if (!BuildDefs::dump())
512 Ostream &Str = Func->getContext()->getStrEmit();
513 assert(this->getSrcSize() == 1);
515 getJmpTarget()->emit(Func);
518 template <class Machine>
519 void InstX86Jmp<Machine>::emitIAS(const Cfg *Func) const {
520 // Note: Adapted (mostly copied) from InstX86Call<Machine>::emitIAS().
521 typename InstX86Base<Machine>::Traits::Assembler *Asm =
522 Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>();
523 Operand *Target = getJmpTarget();
524 if (const auto Var = llvm::dyn_cast<Variable>(Target)) {
526 Asm->jmp(InstX86Base<Machine>::Traits::RegisterSet::getEncodedGPR(
529 // The jmp instruction with a memory operand should be possible to
530 // encode, but it isn't a valid sandboxed instruction, and there
531 // shouldn't be a register allocation issue to jump through a scratch
532 // register, so we don't really need to bother implementing it.
533 llvm::report_fatal_error("Assembler can't jmp to memory operand");
535 } else if (const auto Mem = llvm::dyn_cast<
536 typename InstX86Base<Machine>::Traits::X86OperandMem>(
539 assert(Mem->getSegmentRegister() ==
540 InstX86Base<Machine>::Traits::X86OperandMem::DefaultSegment);
541 llvm::report_fatal_error("Assembler can't jmp to memory operand");
542 } else if (const auto CR = llvm::dyn_cast<ConstantRelocatable>(Target)) {
543 assert(CR->getOffset() == 0 && "We only support jumping to a function");
545 } else if (const auto Imm = llvm::dyn_cast<ConstantInteger32>(Target)) {
546 // NaCl trampoline calls refer to an address within the sandbox directly.
547 // This is usually only needed for non-IRT builds and otherwise not very
548 // portable or stable. Usually this is only done for "calls" and not jumps.
549 // TODO(jvoung): Support this when there is a lowering that actually
550 // triggers this case.
552 llvm::report_fatal_error("Unexpected jmp to absolute address");
554 llvm::report_fatal_error("Unexpected operand type");
558 template <class Machine> void InstX86Jmp<Machine>::dump(const Cfg *Func) const {
559 if (!BuildDefs::dump())
561 Ostream &Str = Func->getContext()->getStrDump();
563 getJmpTarget()->dump(Func);
566 template <class Machine>
567 void InstX86Call<Machine>::emit(const Cfg *Func) const {
568 if (!BuildDefs::dump())
570 Ostream &Str = Func->getContext()->getStrEmit();
571 assert(this->getSrcSize() == 1);
573 if (const auto CI = llvm::dyn_cast<ConstantInteger32>(getCallTarget())) {
574 // Emit without a leading '$'.
575 Str << CI->getValue();
576 } else if (const auto CallTarget =
577 llvm::dyn_cast<ConstantRelocatable>(getCallTarget())) {
578 CallTarget->emitWithoutPrefix(Func->getTarget());
581 getCallTarget()->emit(Func);
583 Func->getTarget()->resetStackAdjustment();
586 template <class Machine>
587 void InstX86Call<Machine>::emitIAS(const Cfg *Func) const {
588 typename InstX86Base<Machine>::Traits::Assembler *Asm =
589 Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>();
590 Operand *Target = getCallTarget();
591 if (const auto Var = llvm::dyn_cast<Variable>(Target)) {
593 Asm->call(InstX86Base<Machine>::Traits::RegisterSet::getEncodedGPR(
597 static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>(
599 ->stackVarToAsmOperand(Var));
601 } else if (const auto Mem = llvm::dyn_cast<
602 typename InstX86Base<Machine>::Traits::X86OperandMem>(
604 assert(Mem->getSegmentRegister() ==
605 InstX86Base<Machine>::Traits::X86OperandMem::DefaultSegment);
606 Asm->call(Mem->toAsmAddress(Asm));
607 } else if (const auto CR = llvm::dyn_cast<ConstantRelocatable>(Target)) {
608 assert(CR->getOffset() == 0 && "We only support calling a function");
610 } else if (const auto Imm = llvm::dyn_cast<ConstantInteger32>(Target)) {
611 Asm->call(Immediate(Imm->getValue()));
613 llvm_unreachable("Unexpected operand type");
615 Func->getTarget()->resetStackAdjustment();
618 template <class Machine>
619 void InstX86Call<Machine>::dump(const Cfg *Func) const {
620 if (!BuildDefs::dump())
622 Ostream &Str = Func->getContext()->getStrDump();
623 if (this->getDest()) {
624 this->dumpDest(Func);
628 getCallTarget()->dump(Func);
631 // The ShiftHack parameter is used to emit "cl" instead of "ecx" for shift
632 // instructions, in order to be syntactically valid. The this->Opcode parameter
633 // needs to be char* and not IceString because of template issues.
634 template <class Machine>
635 void InstX86Base<Machine>::emitTwoAddress(const char *Opcode, const Inst *Inst,
636 const Cfg *Func, bool ShiftHack) {
637 if (!BuildDefs::dump())
639 Ostream &Str = Func->getContext()->getStrEmit();
640 assert(Inst->getSrcSize() == 2);
641 Operand *Dest = Inst->getDest();
643 Dest = Inst->getSrc(0);
644 assert(Dest == Inst->getSrc(0));
645 Operand *Src1 = Inst->getSrc(1);
646 Str << "\t" << Opcode << InstX86Base<Machine>::getWidthString(Dest->getType())
648 const auto ShiftReg = llvm::dyn_cast<Variable>(Src1);
649 if (ShiftHack && ShiftReg &&
650 ShiftReg->getRegNum() ==
651 InstX86Base<Machine>::Traits::RegisterSet::Reg_ecx)
659 template <class Machine>
660 void emitIASOpTyGPR(const Cfg *Func, Type Ty, const Operand *Op,
661 const typename InstX86Base<
662 Machine>::Traits::Assembler::GPREmitterOneOp &Emitter) {
663 typename InstX86Base<Machine>::Traits::Assembler *Asm =
664 Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>();
665 if (const auto Var = llvm::dyn_cast<Variable>(Op)) {
667 // We cheat a little and use GPRRegister even for byte operations.
668 typename InstX86Base<Machine>::Traits::RegisterSet::GPRRegister VarReg =
669 InstX86Base<Machine>::Traits::RegisterSet::getEncodedByteRegOrGPR(
670 Ty, Var->getRegNum());
671 (Asm->*(Emitter.Reg))(Ty, VarReg);
673 typename InstX86Base<Machine>::Traits::Address StackAddr(
674 static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>(
676 ->stackVarToAsmOperand(Var));
677 (Asm->*(Emitter.Addr))(Ty, StackAddr);
679 } else if (const auto Mem = llvm::dyn_cast<
680 typename InstX86Base<Machine>::Traits::X86OperandMem>(Op)) {
681 Mem->emitSegmentOverride(Asm);
682 (Asm->*(Emitter.Addr))(Ty, Mem->toAsmAddress(Asm));
684 llvm_unreachable("Unexpected operand type");
688 template <class Machine, bool VarCanBeByte, bool SrcCanBeByte>
689 void emitIASRegOpTyGPR(
690 const Cfg *Func, Type Ty, const Variable *Var, const Operand *Src,
691 const typename InstX86Base<Machine>::Traits::Assembler::GPREmitterRegOp
693 typename InstX86Base<Machine>::Traits::Assembler *Asm =
694 Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>();
695 assert(Var->hasReg());
696 // We cheat a little and use GPRRegister even for byte operations.
697 typename InstX86Base<Machine>::Traits::RegisterSet::GPRRegister VarReg =
699 ? InstX86Base<Machine>::Traits::RegisterSet::getEncodedByteRegOrGPR(
700 Ty, Var->getRegNum())
701 : InstX86Base<Machine>::Traits::RegisterSet::getEncodedGPR(
703 if (const auto SrcVar = llvm::dyn_cast<Variable>(Src)) {
704 if (SrcVar->hasReg()) {
705 typename InstX86Base<Machine>::Traits::RegisterSet::GPRRegister SrcReg =
707 ? InstX86Base<Machine>::Traits::RegisterSet::
708 getEncodedByteRegOrGPR(Ty, SrcVar->getRegNum())
709 : InstX86Base<Machine>::Traits::RegisterSet::getEncodedGPR(
710 SrcVar->getRegNum());
711 (Asm->*(Emitter.GPRGPR))(Ty, VarReg, SrcReg);
713 typename InstX86Base<Machine>::Traits::Address SrcStackAddr =
714 static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>(
716 ->stackVarToAsmOperand(SrcVar);
717 (Asm->*(Emitter.GPRAddr))(Ty, VarReg, SrcStackAddr);
719 } else if (const auto Mem = llvm::dyn_cast<
720 typename InstX86Base<Machine>::Traits::X86OperandMem>(Src)) {
721 Mem->emitSegmentOverride(Asm);
722 (Asm->*(Emitter.GPRAddr))(Ty, VarReg, Mem->toAsmAddress(Asm));
723 } else if (const auto Imm = llvm::dyn_cast<ConstantInteger32>(Src)) {
724 (Asm->*(Emitter.GPRImm))(Ty, VarReg, Immediate(Imm->getValue()));
725 } else if (const auto Reloc = llvm::dyn_cast<ConstantRelocatable>(Src)) {
726 AssemblerFixup *Fixup =
727 Asm->createFixup(InstX86Base<Machine>::Traits::RelFixup, Reloc);
728 (Asm->*(Emitter.GPRImm))(Ty, VarReg, Immediate(Reloc->getOffset(), Fixup));
729 } else if (const auto Split = llvm::dyn_cast<
730 typename InstX86Base<Machine>::Traits::VariableSplit>(Src)) {
731 (Asm->*(Emitter.GPRAddr))(Ty, VarReg, Split->toAsmAddress(Func));
733 llvm_unreachable("Unexpected operand type");
737 template <class Machine>
738 void emitIASAddrOpTyGPR(
739 const Cfg *Func, Type Ty,
740 const typename InstX86Base<Machine>::Traits::Address &Addr,
742 const typename InstX86Base<Machine>::Traits::Assembler::GPREmitterAddrOp
744 typename InstX86Base<Machine>::Traits::Assembler *Asm =
745 Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>();
746 // Src can only be Reg or Immediate.
747 if (const auto SrcVar = llvm::dyn_cast<Variable>(Src)) {
748 assert(SrcVar->hasReg());
749 typename InstX86Base<Machine>::Traits::RegisterSet::GPRRegister SrcReg =
750 InstX86Base<Machine>::Traits::RegisterSet::getEncodedByteRegOrGPR(
751 Ty, SrcVar->getRegNum());
752 (Asm->*(Emitter.AddrGPR))(Ty, Addr, SrcReg);
753 } else if (const auto Imm = llvm::dyn_cast<ConstantInteger32>(Src)) {
754 (Asm->*(Emitter.AddrImm))(Ty, Addr, Immediate(Imm->getValue()));
755 } else if (const auto Reloc = llvm::dyn_cast<ConstantRelocatable>(Src)) {
756 AssemblerFixup *Fixup =
757 Asm->createFixup(InstX86Base<Machine>::Traits::RelFixup, Reloc);
758 (Asm->*(Emitter.AddrImm))(Ty, Addr, Immediate(Reloc->getOffset(), Fixup));
760 llvm_unreachable("Unexpected operand type");
764 template <class Machine>
765 void emitIASAsAddrOpTyGPR(
766 const Cfg *Func, Type Ty, const Operand *Op0, const Operand *Op1,
767 const typename InstX86Base<Machine>::Traits::Assembler::GPREmitterAddrOp
769 if (const auto Op0Var = llvm::dyn_cast<Variable>(Op0)) {
770 assert(!Op0Var->hasReg());
771 typename InstX86Base<Machine>::Traits::Address StackAddr(
772 static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>(
774 ->stackVarToAsmOperand(Op0Var));
775 emitIASAddrOpTyGPR<Machine>(Func, Ty, StackAddr, Op1, Emitter);
776 } else if (const auto Op0Mem = llvm::dyn_cast<
777 typename InstX86Base<Machine>::Traits::X86OperandMem>(Op0)) {
778 typename InstX86Base<Machine>::Traits::Assembler *Asm =
779 Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>();
780 Op0Mem->emitSegmentOverride(Asm);
781 emitIASAddrOpTyGPR<Machine>(Func, Ty, Op0Mem->toAsmAddress(Asm), Op1,
783 } else if (const auto Split = llvm::dyn_cast<
784 typename InstX86Base<Machine>::Traits::VariableSplit>(Op0)) {
785 emitIASAddrOpTyGPR<Machine>(Func, Ty, Split->toAsmAddress(Func), Op1,
788 llvm_unreachable("Unexpected operand type");
792 template <class Machine>
793 void InstX86Base<Machine>::emitIASGPRShift(
794 const Cfg *Func, Type Ty, const Variable *Var, const Operand *Src,
795 const typename InstX86Base<Machine>::Traits::Assembler::GPREmitterShiftOp
797 typename InstX86Base<Machine>::Traits::Assembler *Asm =
798 Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>();
799 // Technically, the Dest Var can be mem as well, but we only use Reg. We can
800 // extend this to check Dest if we decide to use that form.
801 assert(Var->hasReg());
802 // We cheat a little and use GPRRegister even for byte operations.
803 typename InstX86Base<Machine>::Traits::RegisterSet::GPRRegister VarReg =
804 InstX86Base<Machine>::Traits::RegisterSet::getEncodedByteRegOrGPR(
805 Ty, Var->getRegNum());
806 // Src must be reg == ECX or an Imm8. This is asserted by the assembler.
807 if (const auto SrcVar = llvm::dyn_cast<Variable>(Src)) {
808 assert(SrcVar->hasReg());
809 typename InstX86Base<Machine>::Traits::RegisterSet::GPRRegister SrcReg =
810 InstX86Base<Machine>::Traits::RegisterSet::getEncodedByteRegOrGPR(
811 Ty, SrcVar->getRegNum());
812 (Asm->*(Emitter.GPRGPR))(Ty, VarReg, SrcReg);
813 } else if (const auto Imm = llvm::dyn_cast<ConstantInteger32>(Src)) {
814 (Asm->*(Emitter.GPRImm))(Ty, VarReg, Immediate(Imm->getValue()));
816 llvm_unreachable("Unexpected operand type");
820 template <class Machine>
821 void emitIASGPRShiftDouble(
822 const Cfg *Func, const Variable *Dest, const Operand *Src1Op,
823 const Operand *Src2Op,
824 const typename InstX86Base<Machine>::Traits::Assembler::GPREmitterShiftD
826 typename InstX86Base<Machine>::Traits::Assembler *Asm =
827 Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>();
828 // Dest can be reg or mem, but we only use the reg variant.
829 assert(Dest->hasReg());
830 typename InstX86Base<Machine>::Traits::RegisterSet::GPRRegister DestReg =
831 InstX86Base<Machine>::Traits::RegisterSet::getEncodedGPR(
833 // SrcVar1 must be reg.
834 const auto SrcVar1 = llvm::cast<Variable>(Src1Op);
835 assert(SrcVar1->hasReg());
836 typename InstX86Base<Machine>::Traits::RegisterSet::GPRRegister SrcReg =
837 InstX86Base<Machine>::Traits::RegisterSet::getEncodedGPR(
838 SrcVar1->getRegNum());
839 Type Ty = SrcVar1->getType();
840 // Src2 can be the implicit CL register or an immediate.
841 if (const auto Imm = llvm::dyn_cast<ConstantInteger32>(Src2Op)) {
842 (Asm->*(Emitter.GPRGPRImm))(Ty, DestReg, SrcReg,
843 Immediate(Imm->getValue()));
845 assert(llvm::cast<Variable>(Src2Op)->getRegNum() ==
846 InstX86Base<Machine>::Traits::RegisterSet::Reg_ecx);
847 (Asm->*(Emitter.GPRGPR))(Ty, DestReg, SrcReg);
851 template <class Machine>
852 void emitIASXmmShift(
853 const Cfg *Func, Type Ty, const Variable *Var, const Operand *Src,
854 const typename InstX86Base<Machine>::Traits::Assembler::XmmEmitterShiftOp
856 typename InstX86Base<Machine>::Traits::Assembler *Asm =
857 Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>();
858 assert(Var->hasReg());
859 typename InstX86Base<Machine>::Traits::RegisterSet::XmmRegister VarReg =
860 InstX86Base<Machine>::Traits::RegisterSet::getEncodedXmm(
862 if (const auto SrcVar = llvm::dyn_cast<Variable>(Src)) {
863 if (SrcVar->hasReg()) {
864 typename InstX86Base<Machine>::Traits::RegisterSet::XmmRegister SrcReg =
865 InstX86Base<Machine>::Traits::RegisterSet::getEncodedXmm(
866 SrcVar->getRegNum());
867 (Asm->*(Emitter.XmmXmm))(Ty, VarReg, SrcReg);
869 typename InstX86Base<Machine>::Traits::Address SrcStackAddr =
870 static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>(
872 ->stackVarToAsmOperand(SrcVar);
873 (Asm->*(Emitter.XmmAddr))(Ty, VarReg, SrcStackAddr);
875 } else if (const auto Mem = llvm::dyn_cast<
876 typename InstX86Base<Machine>::Traits::X86OperandMem>(Src)) {
877 assert(Mem->getSegmentRegister() ==
878 InstX86Base<Machine>::Traits::X86OperandMem::DefaultSegment);
879 (Asm->*(Emitter.XmmAddr))(Ty, VarReg, Mem->toAsmAddress(Asm));
880 } else if (const auto Imm = llvm::dyn_cast<ConstantInteger32>(Src)) {
881 (Asm->*(Emitter.XmmImm))(Ty, VarReg, Immediate(Imm->getValue()));
883 llvm_unreachable("Unexpected operand type");
887 template <class Machine>
888 void emitIASRegOpTyXMM(
889 const Cfg *Func, Type Ty, const Variable *Var, const Operand *Src,
890 const typename InstX86Base<Machine>::Traits::Assembler::XmmEmitterRegOp
892 typename InstX86Base<Machine>::Traits::Assembler *Asm =
893 Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>();
894 assert(Var->hasReg());
895 typename InstX86Base<Machine>::Traits::RegisterSet::XmmRegister VarReg =
896 InstX86Base<Machine>::Traits::RegisterSet::getEncodedXmm(
898 if (const auto SrcVar = llvm::dyn_cast<Variable>(Src)) {
899 if (SrcVar->hasReg()) {
900 typename InstX86Base<Machine>::Traits::RegisterSet::XmmRegister SrcReg =
901 InstX86Base<Machine>::Traits::RegisterSet::getEncodedXmm(
902 SrcVar->getRegNum());
903 (Asm->*(Emitter.XmmXmm))(Ty, VarReg, SrcReg);
905 typename InstX86Base<Machine>::Traits::Address SrcStackAddr =
906 static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>(
908 ->stackVarToAsmOperand(SrcVar);
909 (Asm->*(Emitter.XmmAddr))(Ty, VarReg, SrcStackAddr);
911 } else if (const auto Mem = llvm::dyn_cast<
912 typename InstX86Base<Machine>::Traits::X86OperandMem>(Src)) {
913 assert(Mem->getSegmentRegister() ==
914 InstX86Base<Machine>::Traits::X86OperandMem::DefaultSegment);
915 (Asm->*(Emitter.XmmAddr))(Ty, VarReg, Mem->toAsmAddress(Asm));
916 } else if (const auto Imm = llvm::dyn_cast<Constant>(Src)) {
917 (Asm->*(Emitter.XmmAddr))(
919 InstX86Base<Machine>::Traits::Address::ofConstPool(Asm, Imm));
921 llvm_unreachable("Unexpected operand type");
925 template <class Machine, typename DReg_t, typename SReg_t,
926 DReg_t (*destEnc)(int32_t), SReg_t (*srcEnc)(int32_t)>
927 void emitIASCastRegOp(const Cfg *Func, Type DestTy, const Variable *Dest,
928 Type SrcTy, const Operand *Src,
929 const typename InstX86Base<Machine>::Traits::Assembler::
930 template CastEmitterRegOp<DReg_t, SReg_t> &Emitter) {
931 typename InstX86Base<Machine>::Traits::Assembler *Asm =
932 Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>();
933 assert(Dest->hasReg());
934 DReg_t DestReg = destEnc(Dest->getRegNum());
935 if (const auto SrcVar = llvm::dyn_cast<Variable>(Src)) {
936 if (SrcVar->hasReg()) {
937 SReg_t SrcReg = srcEnc(SrcVar->getRegNum());
938 (Asm->*(Emitter.RegReg))(DestTy, DestReg, SrcTy, SrcReg);
940 typename InstX86Base<Machine>::Traits::Address SrcStackAddr =
941 static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>(
943 ->stackVarToAsmOperand(SrcVar);
944 (Asm->*(Emitter.RegAddr))(DestTy, DestReg, SrcTy, SrcStackAddr);
946 } else if (const auto Mem = llvm::dyn_cast<
947 typename InstX86Base<Machine>::Traits::X86OperandMem>(Src)) {
948 Mem->emitSegmentOverride(Asm);
949 (Asm->*(Emitter.RegAddr))(DestTy, DestReg, SrcTy, Mem->toAsmAddress(Asm));
951 llvm_unreachable("Unexpected operand type");
955 template <class Machine, typename DReg_t, typename SReg_t,
956 DReg_t (*destEnc)(int32_t), SReg_t (*srcEnc)(int32_t)>
957 void emitIASThreeOpImmOps(
958 const Cfg *Func, Type DispatchTy, const Variable *Dest, const Operand *Src0,
960 const typename InstX86Base<Machine>::Traits::Assembler::
961 template ThreeOpImmEmitter<DReg_t, SReg_t> Emitter) {
962 typename InstX86Base<Machine>::Traits::Assembler *Asm =
963 Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>();
964 // This only handles Dest being a register, and Src1 being an immediate.
965 assert(Dest->hasReg());
966 DReg_t DestReg = destEnc(Dest->getRegNum());
967 Immediate Imm(llvm::cast<ConstantInteger32>(Src1)->getValue());
968 if (const auto SrcVar = llvm::dyn_cast<Variable>(Src0)) {
969 if (SrcVar->hasReg()) {
970 SReg_t SrcReg = srcEnc(SrcVar->getRegNum());
971 (Asm->*(Emitter.RegRegImm))(DispatchTy, DestReg, SrcReg, Imm);
973 typename InstX86Base<Machine>::Traits::Address SrcStackAddr =
974 static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>(
976 ->stackVarToAsmOperand(SrcVar);
977 (Asm->*(Emitter.RegAddrImm))(DispatchTy, DestReg, SrcStackAddr, Imm);
979 } else if (const auto Mem = llvm::dyn_cast<
980 typename InstX86Base<Machine>::Traits::X86OperandMem>(Src0)) {
981 Mem->emitSegmentOverride(Asm);
982 (Asm->*(Emitter.RegAddrImm))(DispatchTy, DestReg, Mem->toAsmAddress(Asm),
985 llvm_unreachable("Unexpected operand type");
989 template <class Machine>
990 void emitIASMovlikeXMM(
991 const Cfg *Func, const Variable *Dest, const Operand *Src,
992 const typename InstX86Base<Machine>::Traits::Assembler::XmmEmitterMovOps
994 typename InstX86Base<Machine>::Traits::Assembler *Asm =
995 Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>();
996 if (Dest->hasReg()) {
997 typename InstX86Base<Machine>::Traits::RegisterSet::XmmRegister DestReg =
998 InstX86Base<Machine>::Traits::RegisterSet::getEncodedXmm(
1000 if (const auto SrcVar = llvm::dyn_cast<Variable>(Src)) {
1001 if (SrcVar->hasReg()) {
1002 (Asm->*(Emitter.XmmXmm))(
1003 DestReg, InstX86Base<Machine>::Traits::RegisterSet::getEncodedXmm(
1004 SrcVar->getRegNum()));
1006 typename InstX86Base<Machine>::Traits::Address StackAddr(
1007 static_cast<typename InstX86Base<Machine>::Traits::TargetLowering
1008 *>(Func->getTarget())
1009 ->stackVarToAsmOperand(SrcVar));
1010 (Asm->*(Emitter.XmmAddr))(DestReg, StackAddr);
1012 } else if (const auto SrcMem = llvm::dyn_cast<
1013 typename InstX86Base<Machine>::Traits::X86OperandMem>(Src)) {
1014 assert(SrcMem->getSegmentRegister() ==
1015 InstX86Base<Machine>::Traits::X86OperandMem::DefaultSegment);
1016 (Asm->*(Emitter.XmmAddr))(DestReg, SrcMem->toAsmAddress(Asm));
1018 llvm_unreachable("Unexpected operand type");
1021 typename InstX86Base<Machine>::Traits::Address StackAddr(
1022 static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>(
1024 ->stackVarToAsmOperand(Dest));
1025 // Src must be a register in this case.
1026 const auto SrcVar = llvm::cast<Variable>(Src);
1027 assert(SrcVar->hasReg());
1028 (Asm->*(Emitter.AddrXmm))(
1029 StackAddr, InstX86Base<Machine>::Traits::RegisterSet::getEncodedXmm(
1030 SrcVar->getRegNum()));
1034 template <class Machine>
1035 void InstX86Sqrtss<Machine>::emit(const Cfg *Func) const {
1036 if (!BuildDefs::dump())
1038 Ostream &Str = Func->getContext()->getStrEmit();
1039 assert(this->getSrcSize() == 1);
1040 Type Ty = this->getSrc(0)->getType();
1041 assert(isScalarFloatingType(Ty));
1042 Str << "\tsqrt" << InstX86Base<Machine>::Traits::TypeAttributes[Ty].SdSsString
1044 this->getSrc(0)->emit(Func);
1046 this->getDest()->emit(Func);
1049 template <class Machine>
1050 void InstX86Addss<Machine>::emit(const Cfg *Func) const {
1051 if (!BuildDefs::dump())
1055 buf, llvm::array_lengthof(buf), "add%s",
1056 InstX86Base<Machine>::Traits::TypeAttributes[this->getDest()->getType()]
1058 this->emitTwoAddress(buf, this, Func);
1061 template <class Machine>
1062 void InstX86Padd<Machine>::emit(const Cfg *Func) const {
1063 if (!BuildDefs::dump())
1067 buf, llvm::array_lengthof(buf), "padd%s",
1068 InstX86Base<Machine>::Traits::TypeAttributes[this->getDest()->getType()]
1070 this->emitTwoAddress(buf, this, Func);
1073 template <class Machine>
1074 void InstX86Pmull<Machine>::emit(const Cfg *Func) const {
1075 if (!BuildDefs::dump())
1078 bool TypesAreValid = this->getDest()->getType() == IceType_v4i32 ||
1079 this->getDest()->getType() == IceType_v8i16;
1080 bool InstructionSetIsValid =
1081 this->getDest()->getType() == IceType_v8i16 ||
1082 static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>(
1084 ->getInstructionSet() >= InstX86Base<Machine>::Traits::SSE4_1;
1085 (void)TypesAreValid;
1086 (void)InstructionSetIsValid;
1087 assert(TypesAreValid);
1088 assert(InstructionSetIsValid);
1090 buf, llvm::array_lengthof(buf), "pmull%s",
1091 InstX86Base<Machine>::Traits::TypeAttributes[this->getDest()->getType()]
1093 this->emitTwoAddress(buf, this, Func);
1096 template <class Machine>
1097 void InstX86Pmull<Machine>::emitIAS(const Cfg *Func) const {
1098 Type Ty = this->getDest()->getType();
1099 bool TypesAreValid = Ty == IceType_v4i32 || Ty == IceType_v8i16;
1100 bool InstructionSetIsValid =
1101 Ty == IceType_v8i16 ||
1102 static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>(
1104 ->getInstructionSet() >= InstX86Base<Machine>::Traits::SSE4_1;
1105 (void)TypesAreValid;
1106 (void)InstructionSetIsValid;
1107 assert(TypesAreValid);
1108 assert(InstructionSetIsValid);
1109 assert(this->getSrcSize() == 2);
1110 Type ElementTy = typeElementType(Ty);
1111 emitIASRegOpTyXMM<Machine>(Func, ElementTy, this->getDest(), this->getSrc(1),
1115 template <class Machine>
1116 void InstX86Subss<Machine>::emit(const Cfg *Func) const {
1117 if (!BuildDefs::dump())
1121 buf, llvm::array_lengthof(buf), "sub%s",
1122 InstX86Base<Machine>::Traits::TypeAttributes[this->getDest()->getType()]
1124 this->emitTwoAddress(buf, this, Func);
1127 template <class Machine>
1128 void InstX86Psub<Machine>::emit(const Cfg *Func) const {
1129 if (!BuildDefs::dump())
1133 buf, llvm::array_lengthof(buf), "psub%s",
1134 InstX86Base<Machine>::Traits::TypeAttributes[this->getDest()->getType()]
1136 this->emitTwoAddress(buf, this, Func);
1139 template <class Machine>
1140 void InstX86Mulss<Machine>::emit(const Cfg *Func) const {
1141 if (!BuildDefs::dump())
1145 buf, llvm::array_lengthof(buf), "mul%s",
1146 InstX86Base<Machine>::Traits::TypeAttributes[this->getDest()->getType()]
1148 this->emitTwoAddress(buf, this, Func);
1151 template <class Machine>
1152 void InstX86Pmuludq<Machine>::emit(const Cfg *Func) const {
1153 if (!BuildDefs::dump())
1155 assert(this->getSrc(0)->getType() == IceType_v4i32 &&
1156 this->getSrc(1)->getType() == IceType_v4i32);
1157 this->emitTwoAddress(this->Opcode, this, Func);
1160 template <class Machine>
1161 void InstX86Divss<Machine>::emit(const Cfg *Func) const {
1162 if (!BuildDefs::dump())
1166 buf, llvm::array_lengthof(buf), "div%s",
1167 InstX86Base<Machine>::Traits::TypeAttributes[this->getDest()->getType()]
1169 this->emitTwoAddress(buf, this, Func);
1172 template <class Machine> void InstX86Div<Machine>::emit(const Cfg *Func) const {
1173 if (!BuildDefs::dump())
1175 Ostream &Str = Func->getContext()->getStrEmit();
1176 assert(this->getSrcSize() == 3);
1177 Operand *Src1 = this->getSrc(1);
1178 Str << "\t" << this->Opcode << this->getWidthString(Src1->getType()) << "\t";
1182 template <class Machine>
1183 void InstX86Div<Machine>::emitIAS(const Cfg *Func) const {
1184 assert(this->getSrcSize() == 3);
1185 const Operand *Src = this->getSrc(1);
1186 Type Ty = Src->getType();
1187 static const typename InstX86Base<Machine>::Traits::Assembler::GPREmitterOneOp
1188 Emitter = {&InstX86Base<Machine>::Traits::Assembler::div,
1189 &InstX86Base<Machine>::Traits::Assembler::div};
1190 emitIASOpTyGPR<Machine>(Func, Ty, Src, Emitter);
1193 template <class Machine>
1194 void InstX86Idiv<Machine>::emit(const Cfg *Func) const {
1195 if (!BuildDefs::dump())
1197 Ostream &Str = Func->getContext()->getStrEmit();
1198 assert(this->getSrcSize() == 3);
1199 Operand *Src1 = this->getSrc(1);
1200 Str << "\t" << this->Opcode << this->getWidthString(Src1->getType()) << "\t";
1204 template <class Machine>
1205 void InstX86Idiv<Machine>::emitIAS(const Cfg *Func) const {
1206 assert(this->getSrcSize() == 3);
1207 const Operand *Src = this->getSrc(1);
1208 Type Ty = Src->getType();
1209 static const typename InstX86Base<Machine>::Traits::Assembler::GPREmitterOneOp
1210 Emitter = {&InstX86Base<Machine>::Traits::Assembler::idiv,
1211 &InstX86Base<Machine>::Traits::Assembler::idiv};
1212 emitIASOpTyGPR<Machine>(Func, Ty, Src, Emitter);
1215 // pblendvb and blendvps take xmm0 as a final implicit argument.
1216 template <class Machine>
1217 void emitVariableBlendInst(const char *Opcode, const Inst *Inst,
1219 if (!BuildDefs::dump())
1221 Ostream &Str = Func->getContext()->getStrEmit();
1222 assert(Inst->getSrcSize() == 3);
1223 assert(llvm::cast<Variable>(Inst->getSrc(2))->getRegNum() ==
1224 InstX86Base<Machine>::Traits::RegisterSet::Reg_xmm0);
1225 Str << "\t" << Opcode << "\t";
1226 Inst->getSrc(1)->emit(Func);
1228 Inst->getDest()->emit(Func);
1231 template <class Machine>
1232 void emitIASVariableBlendInst(
1233 const Inst *Inst, const Cfg *Func,
1234 const typename InstX86Base<Machine>::Traits::Assembler::XmmEmitterRegOp
1236 assert(Inst->getSrcSize() == 3);
1237 assert(llvm::cast<Variable>(Inst->getSrc(2))->getRegNum() ==
1238 InstX86Base<Machine>::Traits::RegisterSet::Reg_xmm0);
1239 const Variable *Dest = Inst->getDest();
1240 const Operand *Src = Inst->getSrc(1);
1241 emitIASRegOpTyXMM<Machine>(Func, Dest->getType(), Dest, Src, Emitter);
1244 template <class Machine>
1245 void InstX86Blendvps<Machine>::emit(const Cfg *Func) const {
1246 if (!BuildDefs::dump())
1248 assert(static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>(
1250 ->getInstructionSet() >= InstX86Base<Machine>::Traits::SSE4_1);
1251 emitVariableBlendInst<Machine>(this->Opcode, this, Func);
1254 template <class Machine>
1255 void InstX86Blendvps<Machine>::emitIAS(const Cfg *Func) const {
1256 assert(static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>(
1258 ->getInstructionSet() >= InstX86Base<Machine>::Traits::SSE4_1);
1259 static const typename InstX86Base<Machine>::Traits::Assembler::XmmEmitterRegOp
1260 Emitter = {&InstX86Base<Machine>::Traits::Assembler::blendvps,
1261 &InstX86Base<Machine>::Traits::Assembler::blendvps};
1262 emitIASVariableBlendInst<Machine>(this, Func, Emitter);
1265 template <class Machine>
1266 void InstX86Pblendvb<Machine>::emit(const Cfg *Func) const {
1267 if (!BuildDefs::dump())
1269 assert(static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>(
1271 ->getInstructionSet() >= InstX86Base<Machine>::Traits::SSE4_1);
1272 emitVariableBlendInst<Machine>(this->Opcode, this, Func);
1275 template <class Machine>
1276 void InstX86Pblendvb<Machine>::emitIAS(const Cfg *Func) const {
1277 assert(static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>(
1279 ->getInstructionSet() >= InstX86Base<Machine>::Traits::SSE4_1);
1280 static const typename InstX86Base<Machine>::Traits::Assembler::XmmEmitterRegOp
1281 Emitter = {&InstX86Base<Machine>::Traits::Assembler::pblendvb,
1282 &InstX86Base<Machine>::Traits::Assembler::pblendvb};
1283 emitIASVariableBlendInst<Machine>(this, Func, Emitter);
1286 template <class Machine>
1287 void InstX86Imul<Machine>::emit(const Cfg *Func) const {
1288 if (!BuildDefs::dump())
1290 Ostream &Str = Func->getContext()->getStrEmit();
1291 assert(this->getSrcSize() == 2);
1292 Variable *Dest = this->getDest();
1293 if (isByteSizedArithType(Dest->getType())) {
1294 // The 8-bit version of imul only allows the form "imul r/m8".
1295 const auto Src0Var = llvm::dyn_cast<Variable>(this->getSrc(0));
1298 Src0Var->getRegNum() ==
1299 InstX86Base<Machine>::Traits::RegisterSet::Reg_eax);
1301 this->getSrc(1)->emit(Func);
1302 } else if (llvm::isa<Constant>(this->getSrc(1))) {
1303 Str << "\timul" << this->getWidthString(Dest->getType()) << "\t";
1304 this->getSrc(1)->emit(Func);
1306 this->getSrc(0)->emit(Func);
1310 this->emitTwoAddress("imul", this, Func);
1314 template <class Machine>
1315 void InstX86Imul<Machine>::emitIAS(const Cfg *Func) const {
1316 assert(this->getSrcSize() == 2);
1317 const Variable *Var = this->getDest();
1318 Type Ty = Var->getType();
1319 const Operand *Src = this->getSrc(1);
1320 if (isByteSizedArithType(Ty)) {
1321 // The 8-bit version of imul only allows the form "imul r/m8".
1322 const auto Src0Var = llvm::dyn_cast<Variable>(this->getSrc(0));
1325 Src0Var->getRegNum() ==
1326 InstX86Base<Machine>::Traits::RegisterSet::Reg_eax);
1327 static const typename InstX86Base<
1328 Machine>::Traits::Assembler::GPREmitterOneOp Emitter = {
1329 &InstX86Base<Machine>::Traits::Assembler::imul,
1330 &InstX86Base<Machine>::Traits::Assembler::imul};
1331 emitIASOpTyGPR<Machine>(Func, Ty, this->getSrc(1), Emitter);
1333 // We only use imul as a two-address instruction even though there is a 3
1334 // operand version when one of the operands is a constant.
1335 assert(Var == this->getSrc(0));
1336 static const typename InstX86Base<
1337 Machine>::Traits::Assembler::GPREmitterRegOp Emitter = {
1338 &InstX86Base<Machine>::Traits::Assembler::imul,
1339 &InstX86Base<Machine>::Traits::Assembler::imul,
1340 &InstX86Base<Machine>::Traits::Assembler::imul};
1341 emitIASRegOpTyGPR<Machine>(Func, Ty, Var, Src, Emitter);
1345 template <class Machine>
1346 void InstX86Insertps<Machine>::emitIAS(const Cfg *Func) const {
1347 assert(this->getSrcSize() == 3);
1348 assert(static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>(
1350 ->getInstructionSet() >= InstX86Base<Machine>::Traits::SSE4_1);
1351 const Variable *Dest = this->getDest();
1352 assert(Dest == this->getSrc(0));
1353 Type Ty = Dest->getType();
1354 static const typename InstX86Base<Machine>::Traits::Assembler::
1355 template ThreeOpImmEmitter<
1356 typename InstX86Base<Machine>::Traits::RegisterSet::XmmRegister,
1357 typename InstX86Base<Machine>::Traits::RegisterSet::XmmRegister>
1358 Emitter = {&InstX86Base<Machine>::Traits::Assembler::insertps,
1359 &InstX86Base<Machine>::Traits::Assembler::insertps};
1360 emitIASThreeOpImmOps<
1361 Machine, typename InstX86Base<Machine>::Traits::RegisterSet::XmmRegister,
1362 typename InstX86Base<Machine>::Traits::RegisterSet::XmmRegister,
1363 InstX86Base<Machine>::Traits::RegisterSet::getEncodedXmm,
1364 InstX86Base<Machine>::Traits::RegisterSet::getEncodedXmm>(
1365 Func, Ty, Dest, this->getSrc(1), this->getSrc(2), Emitter);
1368 template <class Machine>
1369 void InstX86Cbwdq<Machine>::emit(const Cfg *Func) const {
1370 if (!BuildDefs::dump())
1372 Ostream &Str = Func->getContext()->getStrEmit();
1373 assert(this->getSrcSize() == 1);
1374 Operand *Src0 = this->getSrc(0);
1375 assert(llvm::isa<Variable>(Src0));
1376 assert(llvm::cast<Variable>(Src0)->getRegNum() ==
1377 InstX86Base<Machine>::Traits::RegisterSet::Reg_eax);
1378 switch (Src0->getType()) {
1380 llvm_unreachable("unexpected source type!");
1383 assert(this->getDest()->getRegNum() ==
1384 InstX86Base<Machine>::Traits::RegisterSet::Reg_eax);
1389 assert(this->getDest()->getRegNum() ==
1390 InstX86Base<Machine>::Traits::RegisterSet::Reg_edx);
1395 assert(this->getDest()->getRegNum() ==
1396 InstX86Base<Machine>::Traits::RegisterSet::Reg_edx);
1401 assert(this->getDest()->getRegNum() ==
1402 InstX86Base<Machine>::Traits::RegisterSet::Reg_edx);
1409 template <class Machine>
1410 void InstX86Cbwdq<Machine>::emitIAS(const Cfg *Func) const {
1411 typename InstX86Base<Machine>::Traits::Assembler *Asm =
1412 Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>();
1413 assert(this->getSrcSize() == 1);
1414 Operand *Src0 = this->getSrc(0);
1415 assert(llvm::isa<Variable>(Src0));
1416 assert(llvm::cast<Variable>(Src0)->getRegNum() ==
1417 InstX86Base<Machine>::Traits::RegisterSet::Reg_eax);
1418 switch (Src0->getType()) {
1420 llvm_unreachable("unexpected source type!");
1423 assert(this->getDest()->getRegNum() ==
1424 InstX86Base<Machine>::Traits::RegisterSet::Reg_eax);
1428 assert(this->getDest()->getRegNum() ==
1429 InstX86Base<Machine>::Traits::RegisterSet::Reg_edx);
1433 assert(this->getDest()->getRegNum() ==
1434 InstX86Base<Machine>::Traits::RegisterSet::Reg_edx);
1438 assert(this->getDest()->getRegNum() ==
1439 InstX86Base<Machine>::Traits::RegisterSet::Reg_edx);
1445 template <class Machine> void InstX86Mul<Machine>::emit(const Cfg *Func) const {
1446 if (!BuildDefs::dump())
1448 Ostream &Str = Func->getContext()->getStrEmit();
1449 assert(this->getSrcSize() == 2);
1450 assert(llvm::isa<Variable>(this->getSrc(0)));
1451 assert(llvm::cast<Variable>(this->getSrc(0))->getRegNum() ==
1452 InstX86Base<Machine>::Traits::RegisterSet::Reg_eax);
1454 this->getDest()->getRegNum() ==
1455 InstX86Base<Machine>::Traits::RegisterSet::Reg_eax); // TODO: allow edx?
1456 Str << "\tmul" << this->getWidthString(this->getDest()->getType()) << "\t";
1457 this->getSrc(1)->emit(Func);
1460 template <class Machine>
1461 void InstX86Mul<Machine>::emitIAS(const Cfg *Func) const {
1462 assert(this->getSrcSize() == 2);
1463 assert(llvm::isa<Variable>(this->getSrc(0)));
1464 assert(llvm::cast<Variable>(this->getSrc(0))->getRegNum() ==
1465 InstX86Base<Machine>::Traits::RegisterSet::Reg_eax);
1467 this->getDest()->getRegNum() ==
1468 InstX86Base<Machine>::Traits::RegisterSet::Reg_eax); // TODO: allow edx?
1469 const Operand *Src = this->getSrc(1);
1470 Type Ty = Src->getType();
1471 static const typename InstX86Base<Machine>::Traits::Assembler::GPREmitterOneOp
1472 Emitter = {&InstX86Base<Machine>::Traits::Assembler::mul,
1473 &InstX86Base<Machine>::Traits::Assembler::mul};
1474 emitIASOpTyGPR<Machine>(Func, Ty, Src, Emitter);
1477 template <class Machine> void InstX86Mul<Machine>::dump(const Cfg *Func) const {
1478 if (!BuildDefs::dump())
1480 Ostream &Str = Func->getContext()->getStrDump();
1481 this->dumpDest(Func);
1482 Str << " = mul." << this->getDest()->getType() << " ";
1483 this->dumpSources(Func);
1486 template <class Machine>
1487 void InstX86Shld<Machine>::emit(const Cfg *Func) const {
1488 if (!BuildDefs::dump())
1490 Ostream &Str = Func->getContext()->getStrEmit();
1491 Variable *Dest = this->getDest();
1492 assert(this->getSrcSize() == 3);
1493 assert(Dest == this->getSrc(0));
1494 Str << "\tshld" << this->getWidthString(Dest->getType()) << "\t";
1495 if (const auto ShiftReg = llvm::dyn_cast<Variable>(this->getSrc(2))) {
1497 assert(ShiftReg->getRegNum() ==
1498 InstX86Base<Machine>::Traits::RegisterSet::Reg_ecx);
1501 this->getSrc(2)->emit(Func);
1504 this->getSrc(1)->emit(Func);
1509 template <class Machine>
1510 void InstX86Shld<Machine>::emitIAS(const Cfg *Func) const {
1511 assert(this->getSrcSize() == 3);
1512 assert(this->getDest() == this->getSrc(0));
1513 const Variable *Dest = this->getDest();
1514 const Operand *Src1 = this->getSrc(1);
1515 const Operand *Src2 = this->getSrc(2);
1516 static const typename InstX86Base<
1517 Machine>::Traits::Assembler::GPREmitterShiftD Emitter = {
1518 &InstX86Base<Machine>::Traits::Assembler::shld,
1519 &InstX86Base<Machine>::Traits::Assembler::shld};
1520 emitIASGPRShiftDouble<Machine>(Func, Dest, Src1, Src2, Emitter);
1523 template <class Machine>
1524 void InstX86Shld<Machine>::dump(const Cfg *Func) const {
1525 if (!BuildDefs::dump())
1527 Ostream &Str = Func->getContext()->getStrDump();
1528 this->dumpDest(Func);
1529 Str << " = shld." << this->getDest()->getType() << " ";
1530 this->dumpSources(Func);
1533 template <class Machine>
1534 void InstX86Shrd<Machine>::emit(const Cfg *Func) const {
1535 if (!BuildDefs::dump())
1537 Ostream &Str = Func->getContext()->getStrEmit();
1538 Variable *Dest = this->getDest();
1539 assert(this->getSrcSize() == 3);
1540 assert(Dest == this->getSrc(0));
1541 Str << "\tshrd" << this->getWidthString(Dest->getType()) << "\t";
1542 if (const auto ShiftReg = llvm::dyn_cast<Variable>(this->getSrc(2))) {
1544 assert(ShiftReg->getRegNum() ==
1545 InstX86Base<Machine>::Traits::RegisterSet::Reg_ecx);
1548 this->getSrc(2)->emit(Func);
1551 this->getSrc(1)->emit(Func);
1556 template <class Machine>
1557 void InstX86Shrd<Machine>::emitIAS(const Cfg *Func) const {
1558 assert(this->getSrcSize() == 3);
1559 assert(this->getDest() == this->getSrc(0));
1560 const Variable *Dest = this->getDest();
1561 const Operand *Src1 = this->getSrc(1);
1562 const Operand *Src2 = this->getSrc(2);
1563 static const typename InstX86Base<
1564 Machine>::Traits::Assembler::GPREmitterShiftD Emitter = {
1565 &InstX86Base<Machine>::Traits::Assembler::shrd,
1566 &InstX86Base<Machine>::Traits::Assembler::shrd};
1567 emitIASGPRShiftDouble<Machine>(Func, Dest, Src1, Src2, Emitter);
1570 template <class Machine>
1571 void InstX86Shrd<Machine>::dump(const Cfg *Func) const {
1572 if (!BuildDefs::dump())
1574 Ostream &Str = Func->getContext()->getStrDump();
1575 this->dumpDest(Func);
1576 Str << " = shrd." << this->getDest()->getType() << " ";
1577 this->dumpSources(Func);
1580 template <class Machine>
1581 void InstX86Cmov<Machine>::emit(const Cfg *Func) const {
1582 if (!BuildDefs::dump())
1584 Ostream &Str = Func->getContext()->getStrEmit();
1585 Variable *Dest = this->getDest();
1587 assert(Condition != InstX86Base<Machine>::Traits::Cond::Br_None);
1588 assert(this->getDest()->hasReg());
1590 << InstX86Base<Machine>::Traits::InstBrAttributes[Condition].DisplayString
1591 << this->getWidthString(Dest->getType()) << "\t";
1592 this->getSrc(1)->emit(Func);
1597 template <class Machine>
1598 void InstX86Cmov<Machine>::emitIAS(const Cfg *Func) const {
1599 assert(Condition != InstX86Base<Machine>::Traits::Cond::Br_None);
1600 assert(this->getDest()->hasReg());
1601 assert(this->getSrcSize() == 2);
1602 Operand *Src = this->getSrc(1);
1603 Type SrcTy = Src->getType();
1604 assert(SrcTy == IceType_i16 || SrcTy == IceType_i32 ||
1605 (InstX86Base<Machine>::Traits::Is64Bit));
1606 typename InstX86Base<Machine>::Traits::Assembler *Asm =
1607 Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>();
1608 if (const auto *SrcVar = llvm::dyn_cast<Variable>(Src)) {
1609 if (SrcVar->hasReg()) {
1610 Asm->cmov(SrcTy, Condition,
1611 InstX86Base<Machine>::Traits::RegisterSet::getEncodedGPR(
1612 this->getDest()->getRegNum()),
1613 InstX86Base<Machine>::Traits::RegisterSet::getEncodedGPR(
1614 SrcVar->getRegNum()));
1618 InstX86Base<Machine>::Traits::RegisterSet::getEncodedGPR(
1619 this->getDest()->getRegNum()),
1620 static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>(
1622 ->stackVarToAsmOperand(SrcVar));
1624 } else if (const auto Mem = llvm::dyn_cast<
1625 typename InstX86Base<Machine>::Traits::X86OperandMem>(Src)) {
1626 assert(Mem->getSegmentRegister() ==
1627 InstX86Base<Machine>::Traits::X86OperandMem::DefaultSegment);
1628 Asm->cmov(SrcTy, Condition,
1629 InstX86Base<Machine>::Traits::RegisterSet::getEncodedGPR(
1630 this->getDest()->getRegNum()),
1631 Mem->toAsmAddress(Asm));
1633 llvm_unreachable("Unexpected operand type");
1637 template <class Machine>
1638 void InstX86Cmov<Machine>::dump(const Cfg *Func) const {
1639 if (!BuildDefs::dump())
1641 Ostream &Str = Func->getContext()->getStrDump();
1643 << InstX86Base<Machine>::Traits::InstBrAttributes[Condition].DisplayString
1645 Str << this->getDest()->getType() << " ";
1646 this->dumpDest(Func);
1648 this->dumpSources(Func);
1651 template <class Machine>
1652 void InstX86Cmpps<Machine>::emit(const Cfg *Func) const {
1653 if (!BuildDefs::dump())
1655 Ostream &Str = Func->getContext()->getStrEmit();
1656 assert(this->getSrcSize() == 2);
1657 assert(Condition < InstX86Base<Machine>::Traits::Cond::Cmpps_Invalid);
1660 << InstX86Base<Machine>::Traits::InstCmppsAttributes[Condition].EmitString
1663 this->getSrc(1)->emit(Func);
1665 this->getDest()->emit(Func);
1668 template <class Machine>
1669 void InstX86Cmpps<Machine>::emitIAS(const Cfg *Func) const {
1670 typename InstX86Base<Machine>::Traits::Assembler *Asm =
1671 Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>();
1672 assert(this->getSrcSize() == 2);
1673 assert(Condition < InstX86Base<Machine>::Traits::Cond::Cmpps_Invalid);
1674 // Assuming there isn't any load folding for cmpps, and vector constants are
1675 // not allowed in PNaCl.
1676 assert(llvm::isa<Variable>(this->getSrc(1)));
1677 const auto SrcVar = llvm::cast<Variable>(this->getSrc(1));
1678 if (SrcVar->hasReg()) {
1679 Asm->cmpps(InstX86Base<Machine>::Traits::RegisterSet::getEncodedXmm(
1680 this->getDest()->getRegNum()),
1681 InstX86Base<Machine>::Traits::RegisterSet::getEncodedXmm(
1682 SrcVar->getRegNum()),
1685 typename InstX86Base<Machine>::Traits::Address SrcStackAddr =
1686 static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>(
1688 ->stackVarToAsmOperand(SrcVar);
1689 Asm->cmpps(InstX86Base<Machine>::Traits::RegisterSet::getEncodedXmm(
1690 this->getDest()->getRegNum()),
1691 SrcStackAddr, Condition);
1695 template <class Machine>
1696 void InstX86Cmpps<Machine>::dump(const Cfg *Func) const {
1697 if (!BuildDefs::dump())
1699 Ostream &Str = Func->getContext()->getStrDump();
1700 assert(Condition < InstX86Base<Machine>::Traits::Cond::Cmpps_Invalid);
1701 this->dumpDest(Func);
1703 << InstX86Base<Machine>::Traits::InstCmppsAttributes[Condition].EmitString
1706 this->dumpSources(Func);
1709 template <class Machine>
1710 void InstX86Cmpxchg<Machine>::emit(const Cfg *Func) const {
1711 if (!BuildDefs::dump())
1713 Ostream &Str = Func->getContext()->getStrEmit();
1714 assert(this->getSrcSize() == 3);
1718 Str << "\tcmpxchg" << this->getWidthString(this->getSrc(0)->getType())
1720 this->getSrc(2)->emit(Func);
1722 this->getSrc(0)->emit(Func);
1725 template <class Machine>
1726 void InstX86Cmpxchg<Machine>::emitIAS(const Cfg *Func) const {
1727 assert(this->getSrcSize() == 3);
1728 typename InstX86Base<Machine>::Traits::Assembler *Asm =
1729 Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>();
1730 Type Ty = this->getSrc(0)->getType();
1732 llvm::cast<typename InstX86Base<Machine>::Traits::X86OperandMem>(
1734 assert(Mem->getSegmentRegister() ==
1735 InstX86Base<Machine>::Traits::X86OperandMem::DefaultSegment);
1736 const typename InstX86Base<Machine>::Traits::Address Addr =
1737 Mem->toAsmAddress(Asm);
1738 const auto VarReg = llvm::cast<Variable>(this->getSrc(2));
1739 assert(VarReg->hasReg());
1740 const typename InstX86Base<Machine>::Traits::RegisterSet::GPRRegister Reg =
1741 InstX86Base<Machine>::Traits::RegisterSet::getEncodedGPR(
1742 VarReg->getRegNum());
1743 Asm->cmpxchg(Ty, Addr, Reg, this->Locked);
1746 template <class Machine>
1747 void InstX86Cmpxchg<Machine>::dump(const Cfg *Func) const {
1748 if (!BuildDefs::dump())
1750 Ostream &Str = Func->getContext()->getStrDump();
1754 Str << "cmpxchg." << this->getSrc(0)->getType() << " ";
1755 this->dumpSources(Func);
1758 template <class Machine>
1759 void InstX86Cmpxchg8b<Machine>::emit(const Cfg *Func) const {
1760 if (!BuildDefs::dump())
1762 Ostream &Str = Func->getContext()->getStrEmit();
1763 assert(this->getSrcSize() == 5);
1767 Str << "\tcmpxchg8b\t";
1768 this->getSrc(0)->emit(Func);
1771 template <class Machine>
1772 void InstX86Cmpxchg8b<Machine>::emitIAS(const Cfg *Func) const {
1773 assert(this->getSrcSize() == 5);
1774 typename InstX86Base<Machine>::Traits::Assembler *Asm =
1775 Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>();
1777 llvm::cast<typename InstX86Base<Machine>::Traits::X86OperandMem>(
1779 assert(Mem->getSegmentRegister() ==
1780 InstX86Base<Machine>::Traits::X86OperandMem::DefaultSegment);
1781 const typename InstX86Base<Machine>::Traits::Address Addr =
1782 Mem->toAsmAddress(Asm);
1783 Asm->cmpxchg8b(Addr, this->Locked);
1786 template <class Machine>
1787 void InstX86Cmpxchg8b<Machine>::dump(const Cfg *Func) const {
1788 if (!BuildDefs::dump())
1790 Ostream &Str = Func->getContext()->getStrDump();
1794 Str << "cmpxchg8b ";
1795 this->dumpSources(Func);
1798 template <class Machine> void InstX86Cvt<Machine>::emit(const Cfg *Func) const {
1799 if (!BuildDefs::dump())
1801 Ostream &Str = Func->getContext()->getStrEmit();
1802 assert(this->getSrcSize() == 1);
1806 Str << InstX86Base<Machine>::Traits::TypeAttributes[this->getSrc(0)
1810 Machine>::Traits::TypeAttributes[this->getDest()->getType()]
1812 this->getSrc(0)->emit(Func);
1814 this->getDest()->emit(Func);
1817 template <class Machine>
1818 void InstX86Cvt<Machine>::emitIAS(const Cfg *Func) const {
1819 assert(this->getSrcSize() == 1);
1820 const Variable *Dest = this->getDest();
1821 const Operand *Src = this->getSrc(0);
1822 Type DestTy = Dest->getType();
1823 Type SrcTy = Src->getType();
1826 assert(isScalarIntegerType(SrcTy));
1827 if (!InstX86Base<Machine>::Traits::Is64Bit) {
1828 assert(typeWidthInBytes(SrcTy) <= 4);
1830 assert(SrcTy == IceType_i32 || SrcTy == IceType_i64);
1832 assert(isScalarFloatingType(DestTy));
1833 static const typename InstX86Base<Machine>::Traits::Assembler::
1834 template CastEmitterRegOp<
1835 typename InstX86Base<Machine>::Traits::RegisterSet::XmmRegister,
1836 typename InstX86Base<Machine>::Traits::RegisterSet::GPRRegister>
1837 Emitter = {&InstX86Base<Machine>::Traits::Assembler::cvtsi2ss,
1838 &InstX86Base<Machine>::Traits::Assembler::cvtsi2ss};
1841 typename InstX86Base<Machine>::Traits::RegisterSet::XmmRegister,
1842 typename InstX86Base<Machine>::Traits::RegisterSet::GPRRegister,
1843 InstX86Base<Machine>::Traits::RegisterSet::getEncodedXmm,
1844 InstX86Base<Machine>::Traits::RegisterSet::getEncodedGPR>(
1845 Func, DestTy, Dest, SrcTy, Src, Emitter);
1849 assert(isScalarFloatingType(SrcTy));
1850 assert(isScalarIntegerType(DestTy));
1851 if (!InstX86Base<Machine>::Traits::Is64Bit) {
1852 assert(typeWidthInBytes(DestTy) <= 4);
1854 assert(DestTy == IceType_i32 || DestTy == IceType_i64);
1856 static const typename InstX86Base<Machine>::Traits::Assembler::
1857 template CastEmitterRegOp<
1858 typename InstX86Base<Machine>::Traits::RegisterSet::GPRRegister,
1859 typename InstX86Base<Machine>::Traits::RegisterSet::XmmRegister>
1860 Emitter = {&InstX86Base<Machine>::Traits::Assembler::cvttss2si,
1861 &InstX86Base<Machine>::Traits::Assembler::cvttss2si};
1864 typename InstX86Base<Machine>::Traits::RegisterSet::GPRRegister,
1865 typename InstX86Base<Machine>::Traits::RegisterSet::XmmRegister,
1866 InstX86Base<Machine>::Traits::RegisterSet::getEncodedGPR,
1867 InstX86Base<Machine>::Traits::RegisterSet::getEncodedXmm>(
1868 Func, DestTy, Dest, SrcTy, Src, Emitter);
1872 assert(isScalarFloatingType(SrcTy));
1873 assert(isScalarFloatingType(DestTy));
1874 assert(DestTy != SrcTy);
1875 static const typename InstX86Base<
1876 Machine>::Traits::Assembler::XmmEmitterRegOp Emitter = {
1877 &InstX86Base<Machine>::Traits::Assembler::cvtfloat2float,
1878 &InstX86Base<Machine>::Traits::Assembler::cvtfloat2float};
1879 emitIASRegOpTyXMM<Machine>(Func, SrcTy, Dest, Src, Emitter);
1883 assert(isVectorIntegerType(SrcTy));
1884 assert(isVectorFloatingType(DestTy));
1885 static const typename InstX86Base<
1886 Machine>::Traits::Assembler::XmmEmitterRegOp Emitter = {
1887 &InstX86Base<Machine>::Traits::Assembler::cvtdq2ps,
1888 &InstX86Base<Machine>::Traits::Assembler::cvtdq2ps};
1889 emitIASRegOpTyXMM<Machine>(Func, DestTy, Dest, Src, Emitter);
1893 assert(isVectorFloatingType(SrcTy));
1894 assert(isVectorIntegerType(DestTy));
1895 static const typename InstX86Base<
1896 Machine>::Traits::Assembler::XmmEmitterRegOp Emitter = {
1897 &InstX86Base<Machine>::Traits::Assembler::cvttps2dq,
1898 &InstX86Base<Machine>::Traits::Assembler::cvttps2dq};
1899 emitIASRegOpTyXMM<Machine>(Func, DestTy, Dest, Src, Emitter);
1905 template <class Machine> void InstX86Cvt<Machine>::dump(const Cfg *Func) const {
1906 if (!BuildDefs::dump())
1908 Ostream &Str = Func->getContext()->getStrDump();
1909 this->dumpDest(Func);
1913 Str << InstX86Base<Machine>::Traits::TypeAttributes[this->getSrc(0)
1917 Machine>::Traits::TypeAttributes[this->getDest()->getType()]
1919 this->dumpSources(Func);
1922 template <class Machine>
1923 void InstX86Icmp<Machine>::emit(const Cfg *Func) const {
1924 if (!BuildDefs::dump())
1926 Ostream &Str = Func->getContext()->getStrEmit();
1927 assert(this->getSrcSize() == 2);
1928 Str << "\tcmp" << this->getWidthString(this->getSrc(0)->getType()) << "\t";
1929 this->getSrc(1)->emit(Func);
1931 this->getSrc(0)->emit(Func);
1934 template <class Machine>
1935 void InstX86Icmp<Machine>::emitIAS(const Cfg *Func) const {
1936 assert(this->getSrcSize() == 2);
1937 const Operand *Src0 = this->getSrc(0);
1938 const Operand *Src1 = this->getSrc(1);
1939 Type Ty = Src0->getType();
1940 static const typename InstX86Base<Machine>::Traits::Assembler::GPREmitterRegOp
1941 RegEmitter = {&InstX86Base<Machine>::Traits::Assembler::cmp,
1942 &InstX86Base<Machine>::Traits::Assembler::cmp,
1943 &InstX86Base<Machine>::Traits::Assembler::cmp};
1944 static const typename InstX86Base<
1945 Machine>::Traits::Assembler::GPREmitterAddrOp AddrEmitter = {
1946 &InstX86Base<Machine>::Traits::Assembler::cmp,
1947 &InstX86Base<Machine>::Traits::Assembler::cmp};
1948 if (const auto SrcVar0 = llvm::dyn_cast<Variable>(Src0)) {
1949 if (SrcVar0->hasReg()) {
1950 emitIASRegOpTyGPR<Machine>(Func, Ty, SrcVar0, Src1, RegEmitter);
1954 emitIASAsAddrOpTyGPR<Machine>(Func, Ty, Src0, Src1, AddrEmitter);
1957 template <class Machine>
1958 void InstX86Icmp<Machine>::dump(const Cfg *Func) const {
1959 if (!BuildDefs::dump())
1961 Ostream &Str = Func->getContext()->getStrDump();
1962 Str << "cmp." << this->getSrc(0)->getType() << " ";
1963 this->dumpSources(Func);
1966 template <class Machine>
1967 void InstX86Ucomiss<Machine>::emit(const Cfg *Func) const {
1968 if (!BuildDefs::dump())
1970 Ostream &Str = Func->getContext()->getStrEmit();
1971 assert(this->getSrcSize() == 2);
1973 << InstX86Base<Machine>::Traits::TypeAttributes[this->getSrc(0)
1975 .SdSsString << "\t";
1976 this->getSrc(1)->emit(Func);
1978 this->getSrc(0)->emit(Func);
1981 template <class Machine>
1982 void InstX86Ucomiss<Machine>::emitIAS(const Cfg *Func) const {
1983 assert(this->getSrcSize() == 2);
1984 // Currently src0 is always a variable by convention, to avoid having two
1986 assert(llvm::isa<Variable>(this->getSrc(0)));
1987 const auto Src0Var = llvm::cast<Variable>(this->getSrc(0));
1988 Type Ty = Src0Var->getType();
1989 static const typename InstX86Base<Machine>::Traits::Assembler::XmmEmitterRegOp
1990 Emitter = {&InstX86Base<Machine>::Traits::Assembler::ucomiss,
1991 &InstX86Base<Machine>::Traits::Assembler::ucomiss};
1992 emitIASRegOpTyXMM<Machine>(Func, Ty, Src0Var, this->getSrc(1), Emitter);
1995 template <class Machine>
1996 void InstX86Ucomiss<Machine>::dump(const Cfg *Func) const {
1997 if (!BuildDefs::dump())
1999 Ostream &Str = Func->getContext()->getStrDump();
2000 Str << "ucomiss." << this->getSrc(0)->getType() << " ";
2001 this->dumpSources(Func);
2004 template <class Machine> void InstX86UD2<Machine>::emit(const Cfg *Func) const {
2005 if (!BuildDefs::dump())
2007 Ostream &Str = Func->getContext()->getStrEmit();
2008 assert(this->getSrcSize() == 0);
2012 template <class Machine>
2013 void InstX86UD2<Machine>::emitIAS(const Cfg *Func) const {
2014 typename InstX86Base<Machine>::Traits::Assembler *Asm =
2015 Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>();
2019 template <class Machine> void InstX86UD2<Machine>::dump(const Cfg *Func) const {
2020 if (!BuildDefs::dump())
2022 Ostream &Str = Func->getContext()->getStrDump();
2026 template <class Machine>
2027 void InstX86Test<Machine>::emit(const Cfg *Func) const {
2028 if (!BuildDefs::dump())
2030 Ostream &Str = Func->getContext()->getStrEmit();
2031 assert(this->getSrcSize() == 2);
2032 Str << "\ttest" << this->getWidthString(this->getSrc(0)->getType()) << "\t";
2033 this->getSrc(1)->emit(Func);
2035 this->getSrc(0)->emit(Func);
2038 template <class Machine>
2039 void InstX86Test<Machine>::emitIAS(const Cfg *Func) const {
2040 assert(this->getSrcSize() == 2);
2041 const Operand *Src0 = this->getSrc(0);
2042 const Operand *Src1 = this->getSrc(1);
2043 Type Ty = Src0->getType();
2044 // The Reg/Addr form of test is not encodeable.
2045 static const typename InstX86Base<Machine>::Traits::Assembler::GPREmitterRegOp
2046 RegEmitter = {&InstX86Base<Machine>::Traits::Assembler::test, nullptr,
2047 &InstX86Base<Machine>::Traits::Assembler::test};
2048 static const typename InstX86Base<
2049 Machine>::Traits::Assembler::GPREmitterAddrOp AddrEmitter = {
2050 &InstX86Base<Machine>::Traits::Assembler::test,
2051 &InstX86Base<Machine>::Traits::Assembler::test};
2052 if (const auto SrcVar0 = llvm::dyn_cast<Variable>(Src0)) {
2053 if (SrcVar0->hasReg()) {
2054 emitIASRegOpTyGPR<Machine>(Func, Ty, SrcVar0, Src1, RegEmitter);
2058 llvm_unreachable("Nothing actually generates this so it's untested");
2059 emitIASAsAddrOpTyGPR<Machine>(Func, Ty, Src0, Src1, AddrEmitter);
2062 template <class Machine>
2063 void InstX86Test<Machine>::dump(const Cfg *Func) const {
2064 if (!BuildDefs::dump())
2066 Ostream &Str = Func->getContext()->getStrDump();
2067 Str << "test." << this->getSrc(0)->getType() << " ";
2068 this->dumpSources(Func);
2071 template <class Machine>
2072 void InstX86Mfence<Machine>::emit(const Cfg *Func) const {
2073 if (!BuildDefs::dump())
2075 Ostream &Str = Func->getContext()->getStrEmit();
2076 assert(this->getSrcSize() == 0);
2080 template <class Machine>
2081 void InstX86Mfence<Machine>::emitIAS(const Cfg *Func) const {
2082 typename InstX86Base<Machine>::Traits::Assembler *Asm =
2083 Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>();
2087 template <class Machine>
2088 void InstX86Mfence<Machine>::dump(const Cfg *Func) const {
2089 if (!BuildDefs::dump())
2091 Ostream &Str = Func->getContext()->getStrDump();
2095 template <class Machine>
2096 void InstX86Store<Machine>::emit(const Cfg *Func) const {
2097 if (!BuildDefs::dump())
2099 Ostream &Str = Func->getContext()->getStrEmit();
2100 assert(this->getSrcSize() == 2);
2101 Type Ty = this->getSrc(0)->getType();
2102 Str << "\tmov" << this->getWidthString(Ty)
2103 << InstX86Base<Machine>::Traits::TypeAttributes[Ty].SdSsString << "\t";
2104 this->getSrc(0)->emit(Func);
2106 this->getSrc(1)->emit(Func);
2109 template <class Machine>
2110 void InstX86Store<Machine>::emitIAS(const Cfg *Func) const {
2111 assert(this->getSrcSize() == 2);
2112 const Operand *Dest = this->getSrc(1);
2113 const Operand *Src = this->getSrc(0);
2114 Type DestTy = Dest->getType();
2115 if (isScalarFloatingType(DestTy)) {
2116 // Src must be a register, since Dest is a Mem operand of some kind.
2117 const auto SrcVar = llvm::cast<Variable>(Src);
2118 assert(SrcVar->hasReg());
2119 typename InstX86Base<Machine>::Traits::RegisterSet::XmmRegister SrcReg =
2120 InstX86Base<Machine>::Traits::RegisterSet::getEncodedXmm(
2121 SrcVar->getRegNum());
2122 typename InstX86Base<Machine>::Traits::Assembler *Asm =
2123 Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>();
2124 if (const auto DestVar = llvm::dyn_cast<Variable>(Dest)) {
2125 assert(!DestVar->hasReg());
2126 typename InstX86Base<Machine>::Traits::Address StackAddr(
2127 static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>(
2129 ->stackVarToAsmOperand(DestVar));
2130 Asm->movss(DestTy, StackAddr, SrcReg);
2132 const auto DestMem =
2133 llvm::cast<typename InstX86Base<Machine>::Traits::X86OperandMem>(
2135 assert(DestMem->getSegmentRegister() ==
2136 InstX86Base<Machine>::Traits::X86OperandMem::DefaultSegment);
2137 Asm->movss(DestTy, DestMem->toAsmAddress(Asm), SrcReg);
2141 assert(isScalarIntegerType(DestTy));
2142 static const typename InstX86Base<
2143 Machine>::Traits::Assembler::GPREmitterAddrOp GPRAddrEmitter = {
2144 &InstX86Base<Machine>::Traits::Assembler::mov,
2145 &InstX86Base<Machine>::Traits::Assembler::mov};
2146 emitIASAsAddrOpTyGPR<Machine>(Func, DestTy, Dest, Src, GPRAddrEmitter);
2150 template <class Machine>
2151 void InstX86Store<Machine>::dump(const Cfg *Func) const {
2152 if (!BuildDefs::dump())
2154 Ostream &Str = Func->getContext()->getStrDump();
2155 Str << "mov." << this->getSrc(0)->getType() << " ";
2156 this->getSrc(1)->dump(Func);
2158 this->getSrc(0)->dump(Func);
2161 template <class Machine>
2162 void InstX86StoreP<Machine>::emit(const Cfg *Func) const {
2163 if (!BuildDefs::dump())
2165 Ostream &Str = Func->getContext()->getStrEmit();
2166 assert(this->getSrcSize() == 2);
2167 assert(isVectorType(this->getSrc(1)->getType()));
2168 Str << "\tmovups\t";
2169 this->getSrc(0)->emit(Func);
2171 this->getSrc(1)->emit(Func);
2174 template <class Machine>
2175 void InstX86StoreP<Machine>::emitIAS(const Cfg *Func) const {
2176 typename InstX86Base<Machine>::Traits::Assembler *Asm =
2177 Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>();
2178 assert(this->getSrcSize() == 2);
2179 const auto SrcVar = llvm::cast<Variable>(this->getSrc(0));
2180 const auto DestMem =
2181 llvm::cast<typename InstX86Base<Machine>::Traits::X86OperandMem>(
2183 assert(DestMem->getSegmentRegister() ==
2184 InstX86Base<Machine>::Traits::X86OperandMem::DefaultSegment);
2185 assert(SrcVar->hasReg());
2186 Asm->movups(DestMem->toAsmAddress(Asm),
2187 InstX86Base<Machine>::Traits::RegisterSet::getEncodedXmm(
2188 SrcVar->getRegNum()));
2191 template <class Machine>
2192 void InstX86StoreP<Machine>::dump(const Cfg *Func) const {
2193 if (!BuildDefs::dump())
2195 Ostream &Str = Func->getContext()->getStrDump();
2196 Str << "storep." << this->getSrc(0)->getType() << " ";
2197 this->getSrc(1)->dump(Func);
2199 this->getSrc(0)->dump(Func);
2202 template <class Machine>
2203 void InstX86StoreQ<Machine>::emit(const Cfg *Func) const {
2204 if (!BuildDefs::dump())
2206 Ostream &Str = Func->getContext()->getStrEmit();
2207 assert(this->getSrcSize() == 2);
2208 assert(this->getSrc(1)->getType() == IceType_i64 ||
2209 this->getSrc(1)->getType() == IceType_f64 ||
2210 isVectorType(this->getSrc(1)->getType()));
2212 this->getSrc(0)->emit(Func);
2214 this->getSrc(1)->emit(Func);
2217 template <class Machine>
2218 void InstX86StoreQ<Machine>::emitIAS(const Cfg *Func) const {
2219 typename InstX86Base<Machine>::Traits::Assembler *Asm =
2220 Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>();
2221 assert(this->getSrcSize() == 2);
2222 const auto SrcVar = llvm::cast<Variable>(this->getSrc(0));
2223 const auto DestMem =
2224 llvm::cast<typename InstX86Base<Machine>::Traits::X86OperandMem>(
2226 assert(DestMem->getSegmentRegister() ==
2227 InstX86Base<Machine>::Traits::X86OperandMem::DefaultSegment);
2228 assert(SrcVar->hasReg());
2229 Asm->movq(DestMem->toAsmAddress(Asm),
2230 InstX86Base<Machine>::Traits::RegisterSet::getEncodedXmm(
2231 SrcVar->getRegNum()));
2234 template <class Machine>
2235 void InstX86StoreQ<Machine>::dump(const Cfg *Func) const {
2236 if (!BuildDefs::dump())
2238 Ostream &Str = Func->getContext()->getStrDump();
2239 Str << "storeq." << this->getSrc(0)->getType() << " ";
2240 this->getSrc(1)->dump(Func);
2242 this->getSrc(0)->dump(Func);
2245 template <class Machine> void InstX86Lea<Machine>::emit(const Cfg *Func) const {
2246 if (!BuildDefs::dump())
2248 Ostream &Str = Func->getContext()->getStrEmit();
2249 assert(this->getSrcSize() == 1);
2250 assert(this->getDest()->hasReg());
2252 Operand *Src0 = this->getSrc(0);
2253 if (const auto Src0Var = llvm::dyn_cast<Variable>(Src0)) {
2254 Type Ty = Src0Var->getType();
2255 // lea on x86-32 doesn't accept mem128 operands, so cast VSrc0 to an
2257 Src0Var->asType(isVectorType(Ty) ? IceType_i32 : Ty)->emit(Func);
2262 this->getDest()->emit(Func);
2265 inline bool isIntegerConstant(const Operand *Op) {
2266 return llvm::isa<ConstantInteger32>(Op) || llvm::isa<ConstantInteger64>(Op);
2269 template <class Machine> void InstX86Mov<Machine>::emit(const Cfg *Func) const {
2270 if (!BuildDefs::dump())
2272 Ostream &Str = Func->getContext()->getStrEmit();
2273 assert(this->getSrcSize() == 1);
2274 Operand *Src = this->getSrc(0);
2275 Type SrcTy = Src->getType();
2276 Type DestTy = this->getDest()->getType();
2277 if (InstX86Base<Machine>::Traits::Is64Bit && DestTy == IceType_i64 &&
2278 isIntegerConstant(Src)) {
2279 Str << "\tmovabs\t";
2282 << (!isScalarFloatingType(DestTy)
2283 ? this->getWidthString(SrcTy)
2284 : InstX86Base<Machine>::Traits::TypeAttributes[DestTy]
2285 .SdSsString) << "\t";
2287 // For an integer truncation operation, src is wider than dest. Ideally, we
2288 // use a mov instruction whose data width matches the narrower dest. This is
2289 // a problem if e.g. src is a register like esi or si where there is no 8-bit
2290 // version of the register. To be safe, we instead widen the dest to match
2291 // src. This works even for stack-allocated dest variables because
2292 // typeWidthOnStack() pads to a 4-byte boundary even if only a lower portion
2294 // TODO: This assert disallows usages such as copying a floating
2295 // point value between a vector and a scalar (which movss is used for). Clean
2297 assert(Func->getTarget()->typeWidthInBytesOnStack(DestTy) ==
2298 Func->getTarget()->typeWidthInBytesOnStack(SrcTy));
2301 this->getDest()->asType(SrcTy)->emit(Func);
2304 template <class Machine>
2305 void InstX86Mov<Machine>::emitIAS(const Cfg *Func) const {
2306 assert(this->getSrcSize() == 1);
2307 const Variable *Dest = this->getDest();
2308 const Operand *Src = this->getSrc(0);
2309 Type DestTy = Dest->getType();
2310 Type SrcTy = Src->getType();
2311 // Mov can be used for GPRs or XMM registers. Also, the type does not
2312 // necessarily match (Mov can be used for bitcasts). However, when the type
2313 // does not match, one of the operands must be a register. Thus, the strategy
2314 // is to find out if Src or Dest are a register, then use that register's
2315 // type to decide on which emitter set to use. The emitter set will include
2316 // reg-reg movs, but that case should be unused when the types don't match.
2317 static const typename InstX86Base<Machine>::Traits::Assembler::XmmEmitterRegOp
2318 XmmRegEmitter = {&InstX86Base<Machine>::Traits::Assembler::movss,
2319 &InstX86Base<Machine>::Traits::Assembler::movss};
2320 static const typename InstX86Base<Machine>::Traits::Assembler::GPREmitterRegOp
2321 GPRRegEmitter = {&InstX86Base<Machine>::Traits::Assembler::mov,
2322 &InstX86Base<Machine>::Traits::Assembler::mov,
2323 &InstX86Base<Machine>::Traits::Assembler::mov};
2324 static const typename InstX86Base<
2325 Machine>::Traits::Assembler::GPREmitterAddrOp GPRAddrEmitter = {
2326 &InstX86Base<Machine>::Traits::Assembler::mov,
2327 &InstX86Base<Machine>::Traits::Assembler::mov};
2328 // For an integer truncation operation, src is wider than dest. Ideally, we
2329 // use a mov instruction whose data width matches the narrower dest. This is
2330 // a problem if e.g. src is a register like esi or si where there is no 8-bit
2331 // version of the register. To be safe, we instead widen the dest to match
2332 // src. This works even for stack-allocated dest variables because
2333 // typeWidthOnStack() pads to a 4-byte boundary even if only a lower portion
2335 // TODO: This assert disallows usages such as copying a floating
2336 // point value between a vector and a scalar (which movss is used for). Clean
2339 Func->getTarget()->typeWidthInBytesOnStack(this->getDest()->getType()) ==
2340 Func->getTarget()->typeWidthInBytesOnStack(Src->getType()));
2341 if (Dest->hasReg()) {
2342 if (isScalarFloatingType(DestTy)) {
2343 emitIASRegOpTyXMM<Machine>(Func, DestTy, Dest, Src, XmmRegEmitter);
2346 assert(isScalarIntegerType(DestTy));
2347 // Widen DestTy for truncation (see above note). We should only do this
2348 // when both Src and Dest are integer types.
2349 if (InstX86Base<Machine>::Traits::Is64Bit && DestTy == IceType_i64 &&
2350 isIntegerConstant(Src)) {
2351 uint64_t Value = -1;
2352 if (const auto *C64 = llvm::dyn_cast<ConstantInteger64>(Src)) {
2353 Value = C64->getValue();
2355 Value = llvm::cast<ConstantInteger32>(Src)->getValue();
2357 Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>()
2358 ->movabs(InstX86Base<Machine>::Traits::RegisterSet::getEncodedGPR(
2363 if (isScalarIntegerType(SrcTy)) {
2366 emitIASRegOpTyGPR<Machine>(Func, DestTy, Dest, Src, GPRRegEmitter);
2370 // Dest must be Stack and Src *could* be a register. Use Src's type to
2371 // decide on the emitters.
2372 typename InstX86Base<Machine>::Traits::Address StackAddr(
2373 static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>(
2375 ->stackVarToAsmOperand(Dest));
2376 if (isScalarFloatingType(SrcTy)) {
2377 // Src must be a register.
2378 const auto SrcVar = llvm::cast<Variable>(Src);
2379 assert(SrcVar->hasReg());
2380 typename InstX86Base<Machine>::Traits::Assembler *Asm =
2382 typename InstX86Base<Machine>::Traits::Assembler>();
2383 Asm->movss(SrcTy, StackAddr,
2384 InstX86Base<Machine>::Traits::RegisterSet::getEncodedXmm(
2385 SrcVar->getRegNum()));
2388 // Src can be a register or immediate.
2389 assert(isScalarIntegerType(SrcTy));
2390 emitIASAddrOpTyGPR<Machine>(Func, SrcTy, StackAddr, Src, GPRAddrEmitter);
2397 template <class Machine>
2398 void InstX86Movd<Machine>::emitIAS(const Cfg *Func) const {
2399 typename InstX86Base<Machine>::Traits::Assembler *Asm =
2400 Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>();
2401 assert(this->getSrcSize() == 1);
2402 const Variable *Dest = this->getDest();
2403 const auto SrcVar = llvm::cast<Variable>(this->getSrc(0));
2404 // For insert/extract element (one of Src/Dest is an Xmm vector and the other
2406 if (SrcVar->getType() == IceType_i32 ||
2407 (InstX86Base<Machine>::Traits::Is64Bit &&
2408 SrcVar->getType() == IceType_i64)) {
2409 assert(isVectorType(Dest->getType()) ||
2410 (isScalarFloatingType(Dest->getType()) &&
2411 typeWidthInBytes(SrcVar->getType()) ==
2412 typeWidthInBytes(Dest->getType())));
2413 assert(Dest->hasReg());
2414 typename InstX86Base<Machine>::Traits::RegisterSet::XmmRegister DestReg =
2415 InstX86Base<Machine>::Traits::RegisterSet::getEncodedXmm(
2417 if (SrcVar->hasReg()) {
2418 Asm->movd(SrcVar->getType(), DestReg,
2419 InstX86Base<Machine>::Traits::RegisterSet::getEncodedGPR(
2420 SrcVar->getRegNum()));
2422 typename InstX86Base<Machine>::Traits::Address StackAddr(
2423 static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>(
2425 ->stackVarToAsmOperand(SrcVar));
2426 Asm->movd(SrcVar->getType(), DestReg, StackAddr);
2429 assert(isVectorType(SrcVar->getType()) ||
2430 (isScalarFloatingType(SrcVar->getType()) &&
2431 typeWidthInBytes(SrcVar->getType()) ==
2432 typeWidthInBytes(Dest->getType())));
2433 assert(SrcVar->hasReg());
2434 assert(Dest->getType() == IceType_i32 ||
2435 (InstX86Base<Machine>::Traits::Is64Bit &&
2436 Dest->getType() == IceType_i64));
2437 typename InstX86Base<Machine>::Traits::RegisterSet::XmmRegister SrcReg =
2438 InstX86Base<Machine>::Traits::RegisterSet::getEncodedXmm(
2439 SrcVar->getRegNum());
2440 if (Dest->hasReg()) {
2441 Asm->movd(Dest->getType(),
2442 InstX86Base<Machine>::Traits::RegisterSet::getEncodedGPR(
2446 typename InstX86Base<Machine>::Traits::Address StackAddr(
2447 static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>(
2449 ->stackVarToAsmOperand(Dest));
2450 Asm->movd(Dest->getType(), StackAddr, SrcReg);
2455 template <class Machine>
2456 void InstX86Movp<Machine>::emit(const Cfg *Func) const {
2457 if (!BuildDefs::dump())
2459 // TODO(wala,stichnot): movups works with all vector operands, but there
2460 // exist other instructions (movaps, movdqa, movdqu) that may perform better,
2461 // depending on the data type and alignment of the operands.
2462 Ostream &Str = Func->getContext()->getStrEmit();
2463 assert(this->getSrcSize() == 1);
2464 Str << "\tmovups\t";
2465 this->getSrc(0)->emit(Func);
2467 this->getDest()->emit(Func);
2470 template <class Machine>
2471 void InstX86Movp<Machine>::emitIAS(const Cfg *Func) const {
2472 assert(this->getSrcSize() == 1);
2473 assert(isVectorType(this->getDest()->getType()));
2474 const Variable *Dest = this->getDest();
2475 const Operand *Src = this->getSrc(0);
2476 static const typename InstX86Base<
2477 Machine>::Traits::Assembler::XmmEmitterMovOps Emitter = {
2478 &InstX86Base<Machine>::Traits::Assembler::movups,
2479 &InstX86Base<Machine>::Traits::Assembler::movups,
2480 &InstX86Base<Machine>::Traits::Assembler::movups};
2481 emitIASMovlikeXMM<Machine>(Func, Dest, Src, Emitter);
2484 template <class Machine>
2485 void InstX86Movq<Machine>::emit(const Cfg *Func) const {
2486 if (!BuildDefs::dump())
2488 Ostream &Str = Func->getContext()->getStrEmit();
2489 assert(this->getSrcSize() == 1);
2490 assert(this->getDest()->getType() == IceType_i64 ||
2491 this->getDest()->getType() == IceType_f64);
2493 this->getSrc(0)->emit(Func);
2495 this->getDest()->emit(Func);
2498 template <class Machine>
2499 void InstX86Movq<Machine>::emitIAS(const Cfg *Func) const {
2500 assert(this->getSrcSize() == 1);
2501 assert(this->getDest()->getType() == IceType_i64 ||
2502 this->getDest()->getType() == IceType_f64);
2503 const Variable *Dest = this->getDest();
2504 const Operand *Src = this->getSrc(0);
2505 static const typename InstX86Base<
2506 Machine>::Traits::Assembler::XmmEmitterMovOps Emitter = {
2507 &InstX86Base<Machine>::Traits::Assembler::movq,
2508 &InstX86Base<Machine>::Traits::Assembler::movq,
2509 &InstX86Base<Machine>::Traits::Assembler::movq};
2510 emitIASMovlikeXMM<Machine>(Func, Dest, Src, Emitter);
2513 template <class Machine>
2514 void InstX86MovssRegs<Machine>::emitIAS(const Cfg *Func) const {
2515 // This is Binop variant is only intended to be used for reg-reg moves where
2516 // part of the Dest register is untouched.
2517 assert(this->getSrcSize() == 2);
2518 const Variable *Dest = this->getDest();
2519 assert(Dest == this->getSrc(0));
2520 const auto SrcVar = llvm::cast<Variable>(this->getSrc(1));
2521 assert(Dest->hasReg() && SrcVar->hasReg());
2522 typename InstX86Base<Machine>::Traits::Assembler *Asm =
2523 Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>();
2524 Asm->movss(IceType_f32,
2525 InstX86Base<Machine>::Traits::RegisterSet::getEncodedXmm(
2527 InstX86Base<Machine>::Traits::RegisterSet::getEncodedXmm(
2528 SrcVar->getRegNum()));
2531 template <class Machine>
2532 void InstX86Movsx<Machine>::emitIAS(const Cfg *Func) const {
2533 assert(this->getSrcSize() == 1);
2534 const Variable *Dest = this->getDest();
2535 const Operand *Src = this->getSrc(0);
2536 // Dest must be a > 8-bit register, but Src can be 8-bit. In practice we just
2537 // use the full register for Dest to avoid having an OperandSizeOverride
2538 // prefix. It also allows us to only dispatch on SrcTy.
2539 Type SrcTy = Src->getType();
2540 assert(typeWidthInBytes(Dest->getType()) > 1);
2541 assert(typeWidthInBytes(Dest->getType()) > typeWidthInBytes(SrcTy));
2542 emitIASRegOpTyGPR<Machine, false, true>(Func, SrcTy, Dest, Src,
2546 template <class Machine>
2547 void InstX86Movzx<Machine>::emitIAS(const Cfg *Func) const {
2548 assert(this->getSrcSize() == 1);
2549 const Variable *Dest = this->getDest();
2550 const Operand *Src = this->getSrc(0);
2551 Type SrcTy = Src->getType();
2552 assert(typeWidthInBytes(Dest->getType()) > 1);
2553 assert(typeWidthInBytes(Dest->getType()) > typeWidthInBytes(SrcTy));
2554 emitIASRegOpTyGPR<Machine, false, true>(Func, SrcTy, Dest, Src,
2558 template <class Machine> void InstX86Nop<Machine>::emit(const Cfg *Func) const {
2559 if (!BuildDefs::dump())
2561 Ostream &Str = Func->getContext()->getStrEmit();
2562 // TODO: Emit the right code for each variant.
2563 Str << "\tnop\t# variant = " << Variant;
2566 template <class Machine>
2567 void InstX86Nop<Machine>::emitIAS(const Cfg *Func) const {
2568 typename InstX86Base<Machine>::Traits::Assembler *Asm =
2569 Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>();
2570 // TODO: Emit the right code for the variant.
2574 template <class Machine> void InstX86Nop<Machine>::dump(const Cfg *Func) const {
2575 if (!BuildDefs::dump())
2577 Ostream &Str = Func->getContext()->getStrDump();
2578 Str << "nop (variant = " << Variant << ")";
2581 template <class Machine> void InstX86Fld<Machine>::emit(const Cfg *Func) const {
2582 if (!BuildDefs::dump())
2584 Ostream &Str = Func->getContext()->getStrEmit();
2585 assert(this->getSrcSize() == 1);
2586 Type Ty = this->getSrc(0)->getType();
2587 SizeT Width = typeWidthInBytes(Ty);
2588 const auto Var = llvm::dyn_cast<Variable>(this->getSrc(0));
2589 if (Var && Var->hasReg()) {
2590 // This is a physical xmm register, so we need to spill it to a temporary
2592 Str << "\tsubl\t$" << Width << ", %esp"
2595 << InstX86Base<Machine>::Traits::TypeAttributes[Ty].SdSsString << "\t";
2597 Str << ", (%esp)\n";
2598 Str << "\tfld" << this->getFldString(Ty) << "\t"
2600 Str << "\taddl\t$" << Width << ", %esp";
2603 Str << "\tfld" << this->getFldString(Ty) << "\t";
2604 this->getSrc(0)->emit(Func);
2607 template <class Machine>
2608 void InstX86Fld<Machine>::emitIAS(const Cfg *Func) const {
2609 typename InstX86Base<Machine>::Traits::Assembler *Asm =
2610 Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>();
2611 assert(this->getSrcSize() == 1);
2612 const Operand *Src = this->getSrc(0);
2613 Type Ty = Src->getType();
2614 if (const auto Var = llvm::dyn_cast<Variable>(Src)) {
2615 if (Var->hasReg()) {
2616 // This is a physical xmm register, so we need to spill it to a temporary
2618 Immediate Width(typeWidthInBytes(Ty));
2619 Asm->sub(IceType_i32,
2620 InstX86Base<Machine>::Traits::RegisterSet::Encoded_Reg_esp,
2622 typename InstX86Base<Machine>::Traits::Address StackSlot =
2623 typename InstX86Base<Machine>::Traits::Address(
2624 InstX86Base<Machine>::Traits::RegisterSet::Encoded_Reg_esp, 0);
2625 Asm->movss(Ty, StackSlot,
2626 InstX86Base<Machine>::Traits::RegisterSet::getEncodedXmm(
2628 Asm->fld(Ty, StackSlot);
2629 Asm->add(IceType_i32,
2630 InstX86Base<Machine>::Traits::RegisterSet::Encoded_Reg_esp,
2633 typename InstX86Base<Machine>::Traits::Address StackAddr(
2634 static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>(
2636 ->stackVarToAsmOperand(Var));
2637 Asm->fld(Ty, StackAddr);
2639 } else if (const auto Mem = llvm::dyn_cast<
2640 typename InstX86Base<Machine>::Traits::X86OperandMem>(Src)) {
2641 assert(Mem->getSegmentRegister() ==
2642 InstX86Base<Machine>::Traits::X86OperandMem::DefaultSegment);
2643 Asm->fld(Ty, Mem->toAsmAddress(Asm));
2644 } else if (const auto Imm = llvm::dyn_cast<Constant>(Src)) {
2645 Asm->fld(Ty, InstX86Base<Machine>::Traits::Address::ofConstPool(Asm, Imm));
2647 llvm_unreachable("Unexpected operand type");
2651 template <class Machine> void InstX86Fld<Machine>::dump(const Cfg *Func) const {
2652 if (!BuildDefs::dump())
2654 Ostream &Str = Func->getContext()->getStrDump();
2655 Str << "fld." << this->getSrc(0)->getType() << " ";
2656 this->dumpSources(Func);
2659 template <class Machine>
2660 void InstX86Fstp<Machine>::emit(const Cfg *Func) const {
2661 if (!BuildDefs::dump())
2663 Ostream &Str = Func->getContext()->getStrEmit();
2664 assert(this->getSrcSize() == 0);
2665 // TODO(jvoung,stichnot): Utilize this by setting Dest to nullptr to
2666 // "partially" delete the fstp if the Dest is unused. Even if Dest is unused,
2667 // the fstp should be kept for the SideEffects of popping the stack.
2668 if (!this->getDest()) {
2669 Str << "\tfstp\tst(0)";
2672 Type Ty = this->getDest()->getType();
2673 size_t Width = typeWidthInBytes(Ty);
2674 if (!this->getDest()->hasReg()) {
2675 Str << "\tfstp" << this->getFldString(Ty) << "\t";
2676 this->getDest()->emit(Func);
2679 // Dest is a physical (xmm) register, so st(0) needs to go through memory.
2680 // Hack this by creating a temporary stack slot, spilling st(0) there,
2681 // loading it into the xmm register, and deallocating the stack slot.
2682 Str << "\tsubl\t$" << Width << ", %esp\n";
2683 Str << "\tfstp" << this->getFldString(Ty) << "\t"
2685 Str << "\tmov" << InstX86Base<Machine>::Traits::TypeAttributes[Ty].SdSsString
2688 this->getDest()->emit(Func);
2690 Str << "\taddl\t$" << Width << ", %esp";
2693 template <class Machine>
2694 void InstX86Fstp<Machine>::emitIAS(const Cfg *Func) const {
2695 typename InstX86Base<Machine>::Traits::Assembler *Asm =
2696 Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>();
2697 assert(this->getSrcSize() == 0);
2698 const Variable *Dest = this->getDest();
2699 // TODO(jvoung,stichnot): Utilize this by setting Dest to nullptr to
2700 // "partially" delete the fstp if the Dest is unused. Even if Dest is unused,
2701 // the fstp should be kept for the SideEffects of popping the stack.
2703 Asm->fstp(InstX86Base<Machine>::Traits::RegisterSet::getEncodedSTReg(0));
2706 Type Ty = Dest->getType();
2707 if (!Dest->hasReg()) {
2708 typename InstX86Base<Machine>::Traits::Address StackAddr(
2709 static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>(
2711 ->stackVarToAsmOperand(Dest));
2712 Asm->fstp(Ty, StackAddr);
2714 // Dest is a physical (xmm) register, so st(0) needs to go through memory.
2715 // Hack this by creating a temporary stack slot, spilling st(0) there,
2716 // loading it into the xmm register, and deallocating the stack slot.
2717 Immediate Width(typeWidthInBytes(Ty));
2718 Asm->sub(IceType_i32,
2719 InstX86Base<Machine>::Traits::RegisterSet::Encoded_Reg_esp, Width);
2720 typename InstX86Base<Machine>::Traits::Address StackSlot =
2721 typename InstX86Base<Machine>::Traits::Address(
2722 InstX86Base<Machine>::Traits::RegisterSet::Encoded_Reg_esp, 0);
2723 Asm->fstp(Ty, StackSlot);
2724 Asm->movss(Ty, InstX86Base<Machine>::Traits::RegisterSet::getEncodedXmm(
2727 Asm->add(IceType_i32,
2728 InstX86Base<Machine>::Traits::RegisterSet::Encoded_Reg_esp, Width);
2732 template <class Machine>
2733 void InstX86Fstp<Machine>::dump(const Cfg *Func) const {
2734 if (!BuildDefs::dump())
2736 Ostream &Str = Func->getContext()->getStrDump();
2737 this->dumpDest(Func);
2738 Str << " = fstp." << this->getDest()->getType() << ", st(0)";
2741 template <class Machine>
2742 void InstX86Pcmpeq<Machine>::emit(const Cfg *Func) const {
2743 if (!BuildDefs::dump())
2747 buf, llvm::array_lengthof(buf), "pcmpeq%s",
2748 InstX86Base<Machine>::Traits::TypeAttributes[this->getDest()->getType()]
2750 this->emitTwoAddress(buf, this, Func);
2753 template <class Machine>
2754 void InstX86Pcmpgt<Machine>::emit(const Cfg *Func) const {
2755 if (!BuildDefs::dump())
2759 buf, llvm::array_lengthof(buf), "pcmpgt%s",
2760 InstX86Base<Machine>::Traits::TypeAttributes[this->getDest()->getType()]
2762 this->emitTwoAddress(buf, this, Func);
2765 template <class Machine>
2766 void InstX86Pextr<Machine>::emit(const Cfg *Func) const {
2767 if (!BuildDefs::dump())
2769 Ostream &Str = Func->getContext()->getStrEmit();
2770 assert(this->getSrcSize() == 2);
2771 // pextrb and pextrd are SSE4.1 instructions.
2772 assert(this->getSrc(0)->getType() == IceType_v8i16 ||
2773 this->getSrc(0)->getType() == IceType_v8i1 ||
2774 static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>(
2776 ->getInstructionSet() >= InstX86Base<Machine>::Traits::SSE4_1);
2777 Str << "\t" << this->Opcode
2778 << InstX86Base<Machine>::Traits::TypeAttributes[this->getSrc(0)
2780 .PackString << "\t";
2781 this->getSrc(1)->emit(Func);
2783 this->getSrc(0)->emit(Func);
2785 Variable *Dest = this->getDest();
2786 // pextrw must take a register dest. There is an SSE4.1 version that takes a
2787 // memory dest, but we aren't using it. For uniformity, just restrict them
2788 // all to have a register dest for now.
2789 assert(Dest->hasReg());
2790 Dest->asType(IceType_i32)->emit(Func);
2793 template <class Machine>
2794 void InstX86Pextr<Machine>::emitIAS(const Cfg *Func) const {
2795 assert(this->getSrcSize() == 2);
2796 // pextrb and pextrd are SSE4.1 instructions.
2797 const Variable *Dest = this->getDest();
2798 Type DispatchTy = Dest->getType();
2799 assert(DispatchTy == IceType_i16 ||
2800 static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>(
2802 ->getInstructionSet() >= InstX86Base<Machine>::Traits::SSE4_1);
2803 // pextrw must take a register dest. There is an SSE4.1 version that takes a
2804 // memory dest, but we aren't using it. For uniformity, just restrict them
2805 // all to have a register dest for now.
2806 assert(Dest->hasReg());
2807 // pextrw's Src(0) must be a register (both SSE4.1 and SSE2).
2808 assert(llvm::cast<Variable>(this->getSrc(0))->hasReg());
2809 static const typename InstX86Base<Machine>::Traits::Assembler::
2810 template ThreeOpImmEmitter<
2811 typename InstX86Base<Machine>::Traits::RegisterSet::GPRRegister,
2812 typename InstX86Base<Machine>::Traits::RegisterSet::XmmRegister>
2813 Emitter = {&InstX86Base<Machine>::Traits::Assembler::pextr, nullptr};
2814 emitIASThreeOpImmOps<
2815 Machine, typename InstX86Base<Machine>::Traits::RegisterSet::GPRRegister,
2816 typename InstX86Base<Machine>::Traits::RegisterSet::XmmRegister,
2817 InstX86Base<Machine>::Traits::RegisterSet::getEncodedGPR,
2818 InstX86Base<Machine>::Traits::RegisterSet::getEncodedXmm>(
2819 Func, DispatchTy, Dest, this->getSrc(0), this->getSrc(1), Emitter);
2822 template <class Machine>
2823 void InstX86Pinsr<Machine>::emit(const Cfg *Func) const {
2824 if (!BuildDefs::dump())
2826 Ostream &Str = Func->getContext()->getStrEmit();
2827 assert(this->getSrcSize() == 3);
2828 // pinsrb and pinsrd are SSE4.1 instructions.
2829 assert(this->getDest()->getType() == IceType_v8i16 ||
2830 this->getDest()->getType() == IceType_v8i1 ||
2831 static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>(
2833 ->getInstructionSet() >= InstX86Base<Machine>::Traits::SSE4_1);
2834 Str << "\t" << this->Opcode
2836 Machine>::Traits::TypeAttributes[this->getDest()->getType()]
2837 .PackString << "\t";
2838 this->getSrc(2)->emit(Func);
2840 Operand *Src1 = this->getSrc(1);
2841 if (const auto Src1Var = llvm::dyn_cast<Variable>(Src1)) {
2842 // If src1 is a register, it should always be r32.
2843 if (Src1Var->hasReg()) {
2844 Src1Var->asType(IceType_i32)->emit(Func);
2846 Src1Var->emit(Func);
2852 this->getDest()->emit(Func);
2855 template <class Machine>
2856 void InstX86Pinsr<Machine>::emitIAS(const Cfg *Func) const {
2857 assert(this->getSrcSize() == 3);
2858 assert(this->getDest() == this->getSrc(0));
2859 // pinsrb and pinsrd are SSE4.1 instructions.
2860 const Operand *Src0 = this->getSrc(1);
2861 Type DispatchTy = Src0->getType();
2862 assert(DispatchTy == IceType_i16 ||
2863 static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>(
2865 ->getInstructionSet() >= InstX86Base<Machine>::Traits::SSE4_1);
2866 // If src1 is a register, it should always be r32 (this should fall out from
2867 // the encodings for ByteRegs overlapping the encodings for r32), but we have
2868 // to trust the regalloc to not choose "ah", where it doesn't overlap.
2869 static const typename InstX86Base<Machine>::Traits::Assembler::
2870 template ThreeOpImmEmitter<
2871 typename InstX86Base<Machine>::Traits::RegisterSet::XmmRegister,
2872 typename InstX86Base<Machine>::Traits::RegisterSet::GPRRegister>
2873 Emitter = {&InstX86Base<Machine>::Traits::Assembler::pinsr,
2874 &InstX86Base<Machine>::Traits::Assembler::pinsr};
2875 emitIASThreeOpImmOps<
2876 Machine, typename InstX86Base<Machine>::Traits::RegisterSet::XmmRegister,
2877 typename InstX86Base<Machine>::Traits::RegisterSet::GPRRegister,
2878 InstX86Base<Machine>::Traits::RegisterSet::getEncodedXmm,
2879 InstX86Base<Machine>::Traits::RegisterSet::getEncodedGPR>(
2880 Func, DispatchTy, this->getDest(), Src0, this->getSrc(2), Emitter);
2883 template <class Machine>
2884 void InstX86Pshufd<Machine>::emitIAS(const Cfg *Func) const {
2885 assert(this->getSrcSize() == 2);
2886 const Variable *Dest = this->getDest();
2887 Type Ty = Dest->getType();
2888 static const typename InstX86Base<Machine>::Traits::Assembler::
2889 template ThreeOpImmEmitter<
2890 typename InstX86Base<Machine>::Traits::RegisterSet::XmmRegister,
2891 typename InstX86Base<Machine>::Traits::RegisterSet::XmmRegister>
2892 Emitter = {&InstX86Base<Machine>::Traits::Assembler::pshufd,
2893 &InstX86Base<Machine>::Traits::Assembler::pshufd};
2894 emitIASThreeOpImmOps<
2895 Machine, typename InstX86Base<Machine>::Traits::RegisterSet::XmmRegister,
2896 typename InstX86Base<Machine>::Traits::RegisterSet::XmmRegister,
2897 InstX86Base<Machine>::Traits::RegisterSet::getEncodedXmm,
2898 InstX86Base<Machine>::Traits::RegisterSet::getEncodedXmm>(
2899 Func, Ty, Dest, this->getSrc(0), this->getSrc(1), Emitter);
2902 template <class Machine>
2903 void InstX86Shufps<Machine>::emitIAS(const Cfg *Func) const {
2904 assert(this->getSrcSize() == 3);
2905 const Variable *Dest = this->getDest();
2906 assert(Dest == this->getSrc(0));
2907 Type Ty = Dest->getType();
2908 static const typename InstX86Base<Machine>::Traits::Assembler::
2909 template ThreeOpImmEmitter<
2910 typename InstX86Base<Machine>::Traits::RegisterSet::XmmRegister,
2911 typename InstX86Base<Machine>::Traits::RegisterSet::XmmRegister>
2912 Emitter = {&InstX86Base<Machine>::Traits::Assembler::shufps,
2913 &InstX86Base<Machine>::Traits::Assembler::shufps};
2914 emitIASThreeOpImmOps<
2915 Machine, typename InstX86Base<Machine>::Traits::RegisterSet::XmmRegister,
2916 typename InstX86Base<Machine>::Traits::RegisterSet::XmmRegister,
2917 InstX86Base<Machine>::Traits::RegisterSet::getEncodedXmm,
2918 InstX86Base<Machine>::Traits::RegisterSet::getEncodedXmm>(
2919 Func, Ty, Dest, this->getSrc(1), this->getSrc(2), Emitter);
2922 template <class Machine> void InstX86Pop<Machine>::emit(const Cfg *Func) const {
2923 if (!BuildDefs::dump())
2925 Ostream &Str = Func->getContext()->getStrEmit();
2926 assert(this->getSrcSize() == 0);
2928 this->getDest()->emit(Func);
2931 template <class Machine>
2932 void InstX86Pop<Machine>::emitIAS(const Cfg *Func) const {
2933 assert(this->getSrcSize() == 0);
2934 typename InstX86Base<Machine>::Traits::Assembler *Asm =
2935 Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>();
2936 if (this->getDest()->hasReg()) {
2937 Asm->popl(InstX86Base<Machine>::Traits::RegisterSet::getEncodedGPR(
2938 this->getDest()->getRegNum()));
2941 static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>(
2943 ->stackVarToAsmOperand(this->getDest()));
2947 template <class Machine> void InstX86Pop<Machine>::dump(const Cfg *Func) const {
2948 if (!BuildDefs::dump())
2950 Ostream &Str = Func->getContext()->getStrDump();
2951 this->dumpDest(Func);
2952 Str << " = pop." << this->getDest()->getType() << " ";
2955 template <class Machine>
2956 void InstX86AdjustStack<Machine>::emit(const Cfg *Func) const {
2957 if (!BuildDefs::dump())
2959 Ostream &Str = Func->getContext()->getStrEmit();
2960 Str << "\tsubl\t$" << Amount << ", %esp";
2961 Func->getTarget()->updateStackAdjustment(Amount);
2964 template <class Machine>
2965 void InstX86AdjustStack<Machine>::emitIAS(const Cfg *Func) const {
2966 typename InstX86Base<Machine>::Traits::Assembler *Asm =
2967 Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>();
2968 Asm->sub(IceType_i32,
2969 InstX86Base<Machine>::Traits::RegisterSet::Encoded_Reg_esp,
2971 Func->getTarget()->updateStackAdjustment(Amount);
2974 template <class Machine>
2975 void InstX86AdjustStack<Machine>::dump(const Cfg *Func) const {
2976 if (!BuildDefs::dump())
2978 Ostream &Str = Func->getContext()->getStrDump();
2979 Str << "esp = sub.i32 esp, " << Amount;
2982 template <class Machine>
2983 void InstX86Push<Machine>::emit(const Cfg *Func) const {
2984 if (!BuildDefs::dump())
2986 Ostream &Str = Func->getContext()->getStrEmit();
2987 assert(this->getSrcSize() == 1);
2988 // Push is currently only used for saving GPRs.
2989 const auto Var = llvm::cast<Variable>(this->getSrc(0));
2990 assert(Var->hasReg());
2995 template <class Machine>
2996 void InstX86Push<Machine>::emitIAS(const Cfg *Func) const {
2997 assert(this->getSrcSize() == 1);
2998 // Push is currently only used for saving GPRs.
2999 const auto Var = llvm::cast<Variable>(this->getSrc(0));
3000 assert(Var->hasReg());
3001 typename InstX86Base<Machine>::Traits::Assembler *Asm =
3002 Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>();
3003 Asm->pushl(InstX86Base<Machine>::Traits::RegisterSet::getEncodedGPR(
3007 template <class Machine>
3008 void InstX86Push<Machine>::dump(const Cfg *Func) const {
3009 if (!BuildDefs::dump())
3011 Ostream &Str = Func->getContext()->getStrDump();
3012 Str << "push." << this->getSrc(0)->getType() << " ";
3013 this->dumpSources(Func);
3016 template <class Machine>
3017 void InstX86Psll<Machine>::emit(const Cfg *Func) const {
3018 if (!BuildDefs::dump())
3020 assert(this->getDest()->getType() == IceType_v8i16 ||
3021 this->getDest()->getType() == IceType_v8i1 ||
3022 this->getDest()->getType() == IceType_v4i32 ||
3023 this->getDest()->getType() == IceType_v4i1);
3026 buf, llvm::array_lengthof(buf), "psll%s",
3027 InstX86Base<Machine>::Traits::TypeAttributes[this->getDest()->getType()]
3029 this->emitTwoAddress(buf, this, Func);
3032 template <class Machine>
3033 void InstX86Psra<Machine>::emit(const Cfg *Func) const {
3034 if (!BuildDefs::dump())
3036 assert(this->getDest()->getType() == IceType_v8i16 ||
3037 this->getDest()->getType() == IceType_v8i1 ||
3038 this->getDest()->getType() == IceType_v4i32 ||
3039 this->getDest()->getType() == IceType_v4i1);
3042 buf, llvm::array_lengthof(buf), "psra%s",
3043 InstX86Base<Machine>::Traits::TypeAttributes[this->getDest()->getType()]
3045 this->emitTwoAddress(buf, this, Func);
3048 template <class Machine>
3049 void InstX86Psrl<Machine>::emit(const Cfg *Func) const {
3050 if (!BuildDefs::dump())
3054 buf, llvm::array_lengthof(buf), "psrl%s",
3055 InstX86Base<Machine>::Traits::TypeAttributes[this->getDest()->getType()]
3057 this->emitTwoAddress(buf, this, Func);
3060 template <class Machine> void InstX86Ret<Machine>::emit(const Cfg *Func) const {
3061 if (!BuildDefs::dump())
3063 Ostream &Str = Func->getContext()->getStrEmit();
3067 template <class Machine>
3068 void InstX86Ret<Machine>::emitIAS(const Cfg *Func) const {
3069 typename InstX86Base<Machine>::Traits::Assembler *Asm =
3070 Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>();
3074 template <class Machine> void InstX86Ret<Machine>::dump(const Cfg *Func) const {
3075 if (!BuildDefs::dump())
3077 Ostream &Str = Func->getContext()->getStrDump();
3079 (this->getSrcSize() == 0 ? IceType_void : this->getSrc(0)->getType());
3080 Str << "ret." << Ty << " ";
3081 this->dumpSources(Func);
3084 template <class Machine>
3085 void InstX86Setcc<Machine>::emit(const Cfg *Func) const {
3086 if (!BuildDefs::dump())
3088 Ostream &Str = Func->getContext()->getStrEmit();
3090 << InstX86Base<Machine>::Traits::InstBrAttributes[Condition].DisplayString
3092 this->Dest->emit(Func);
3095 template <class Machine>
3096 void InstX86Setcc<Machine>::emitIAS(const Cfg *Func) const {
3097 assert(Condition != InstX86Base<Machine>::Traits::Cond::Br_None);
3098 assert(this->getDest()->getType() == IceType_i1);
3099 assert(this->getSrcSize() == 0);
3100 typename InstX86Base<Machine>::Traits::Assembler *Asm =
3101 Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>();
3102 if (this->getDest()->hasReg())
3103 Asm->setcc(Condition,
3104 InstX86Base<Machine>::Traits::RegisterSet::getEncodedByteReg(
3105 this->getDest()->getRegNum()));
3109 static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>(
3111 ->stackVarToAsmOperand(this->getDest()));
3115 template <class Machine>
3116 void InstX86Setcc<Machine>::dump(const Cfg *Func) const {
3117 if (!BuildDefs::dump())
3119 Ostream &Str = Func->getContext()->getStrDump();
3121 << InstX86Base<Machine>::Traits::InstBrAttributes[Condition].DisplayString
3123 this->dumpDest(Func);
3126 template <class Machine>
3127 void InstX86Xadd<Machine>::emit(const Cfg *Func) const {
3128 if (!BuildDefs::dump())
3130 Ostream &Str = Func->getContext()->getStrEmit();
3134 Str << "\txadd" << this->getWidthString(this->getSrc(0)->getType()) << "\t";
3135 this->getSrc(1)->emit(Func);
3137 this->getSrc(0)->emit(Func);
3140 template <class Machine>
3141 void InstX86Xadd<Machine>::emitIAS(const Cfg *Func) const {
3142 assert(this->getSrcSize() == 2);
3143 typename InstX86Base<Machine>::Traits::Assembler *Asm =
3144 Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>();
3145 Type Ty = this->getSrc(0)->getType();
3147 llvm::cast<typename InstX86Base<Machine>::Traits::X86OperandMem>(
3149 assert(Mem->getSegmentRegister() ==
3150 InstX86Base<Machine>::Traits::X86OperandMem::DefaultSegment);
3151 const typename InstX86Base<Machine>::Traits::Address Addr =
3152 Mem->toAsmAddress(Asm);
3153 const auto VarReg = llvm::cast<Variable>(this->getSrc(1));
3154 assert(VarReg->hasReg());
3155 const typename InstX86Base<Machine>::Traits::RegisterSet::GPRRegister Reg =
3156 InstX86Base<Machine>::Traits::RegisterSet::getEncodedGPR(
3157 VarReg->getRegNum());
3158 Asm->xadd(Ty, Addr, Reg, this->Locked);
3161 template <class Machine>
3162 void InstX86Xadd<Machine>::dump(const Cfg *Func) const {
3163 if (!BuildDefs::dump())
3165 Ostream &Str = Func->getContext()->getStrDump();
3169 Type Ty = this->getSrc(0)->getType();
3170 Str << "xadd." << Ty << " ";
3171 this->dumpSources(Func);
3174 template <class Machine>
3175 void InstX86Xchg<Machine>::emit(const Cfg *Func) const {
3176 if (!BuildDefs::dump())
3178 Ostream &Str = Func->getContext()->getStrEmit();
3179 Str << "\txchg" << this->getWidthString(this->getSrc(0)->getType()) << "\t";
3180 this->getSrc(1)->emit(Func);
3182 this->getSrc(0)->emit(Func);
3185 template <class Machine>
3186 void InstX86Xchg<Machine>::emitIAS(const Cfg *Func) const {
3187 assert(this->getSrcSize() == 2);
3188 typename InstX86Base<Machine>::Traits::Assembler *Asm =
3189 Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>();
3190 Type Ty = this->getSrc(0)->getType();
3191 const auto *VarReg1 = llvm::cast<Variable>(this->getSrc(1));
3192 assert(VarReg1->hasReg());
3193 const typename InstX86Base<Machine>::Traits::RegisterSet::GPRRegister Reg1 =
3194 InstX86Base<Machine>::Traits::RegisterSet::getEncodedGPR(
3195 VarReg1->getRegNum());
3197 if (const auto *VarReg0 = llvm::dyn_cast<Variable>(this->getSrc(0))) {
3198 assert(VarReg0->hasReg());
3199 const typename InstX86Base<Machine>::Traits::RegisterSet::GPRRegister Reg0 =
3200 InstX86Base<Machine>::Traits::RegisterSet::getEncodedGPR(
3201 VarReg0->getRegNum());
3202 Asm->xchg(Ty, Reg0, Reg1);
3207 llvm::cast<typename InstX86Base<Machine>::Traits::X86OperandMem>(
3209 assert(Mem->getSegmentRegister() ==
3210 InstX86Base<Machine>::Traits::X86OperandMem::DefaultSegment);
3211 const typename InstX86Base<Machine>::Traits::Address Addr =
3212 Mem->toAsmAddress(Asm);
3213 Asm->xchg(Ty, Addr, Reg1);
3216 template <class Machine>
3217 void InstX86Xchg<Machine>::dump(const Cfg *Func) const {
3218 if (!BuildDefs::dump())
3220 Ostream &Str = Func->getContext()->getStrDump();
3221 Type Ty = this->getSrc(0)->getType();
3222 Str << "xchg." << Ty << " ";
3223 this->dumpSources(Func);
3226 template <class Machine>
3227 void InstX86IacaStart<Machine>::emit(const Cfg *Func) const {
3228 if (!BuildDefs::dump())
3230 Ostream &Str = Func->getContext()->getStrEmit();
3231 Str << "\t# IACA_START\n"
3232 << "\t.byte 0x0F, 0x0B\n"
3233 << "\tmovl\t$111, %ebx\n"
3234 << "\t.byte 0x64, 0x67, 0x90";
3237 template <class Machine>
3238 void InstX86IacaStart<Machine>::emitIAS(const Cfg *Func) const {
3239 typename InstX86Base<Machine>::Traits::Assembler *Asm =
3240 Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>();
3244 template <class Machine>
3245 void InstX86IacaStart<Machine>::dump(const Cfg *Func) const {
3246 if (!BuildDefs::dump())
3248 Ostream &Str = Func->getContext()->getStrDump();
3249 Str << "IACA_START";
3252 template <class Machine>
3253 void InstX86IacaEnd<Machine>::emit(const Cfg *Func) const {
3254 if (!BuildDefs::dump())
3256 Ostream &Str = Func->getContext()->getStrEmit();
3257 Str << "\t# IACA_END\n"
3258 << "\tmovl\t$222, %ebx\n"
3259 << "\t.byte 0x64, 0x67, 0x90\n"
3260 << "\t.byte 0x0F, 0x0B";
3263 template <class Machine>
3264 void InstX86IacaEnd<Machine>::emitIAS(const Cfg *Func) const {
3265 typename InstX86Base<Machine>::Traits::Assembler *Asm =
3266 Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>();
3270 template <class Machine>
3271 void InstX86IacaEnd<Machine>::dump(const Cfg *Func) const {
3272 if (!BuildDefs::dump())
3274 Ostream &Str = Func->getContext()->getStrDump();
3278 } // end of namespace X86Internal
3280 } // end of namespace Ice
3282 #endif // SUBZERO_SRC_ICEINSTX86BASEIMPL_H