OLD | NEW |
1 //===- subzero/src/IceInstX86BaseImpl.h - Generic X86 instructions -*- C++ -*=// | 1 //===- subzero/src/IceInstX86BaseImpl.h - Generic X86 instructions -*- C++ -*=// |
2 // | 2 // |
3 // The Subzero Code Generator | 3 // The Subzero Code Generator |
4 // | 4 // |
5 // This file is distributed under the University of Illinois Open Source | 5 // This file is distributed under the University of Illinois Open Source |
6 // License. See LICENSE.TXT for details. | 6 // License. See LICENSE.TXT for details. |
7 // | 7 // |
8 //===----------------------------------------------------------------------===// | 8 //===----------------------------------------------------------------------===// |
9 /// | 9 /// |
10 /// \file | 10 /// \file |
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
105 InstX86Br<Machine>::InstX86Br( | 105 InstX86Br<Machine>::InstX86Br( |
106 Cfg *Func, const CfgNode *TargetTrue, const CfgNode *TargetFalse, | 106 Cfg *Func, const CfgNode *TargetTrue, const CfgNode *TargetFalse, |
107 const InstX86Label<Machine> *Label, | 107 const InstX86Label<Machine> *Label, |
108 typename InstX86Base<Machine>::Traits::Cond::BrCond Condition, Mode Kind) | 108 typename InstX86Base<Machine>::Traits::Cond::BrCond Condition, Mode Kind) |
109 : InstX86Base<Machine>(Func, InstX86Base<Machine>::Br, 0, nullptr), | 109 : InstX86Base<Machine>(Func, InstX86Base<Machine>::Br, 0, nullptr), |
110 Condition(Condition), TargetTrue(TargetTrue), TargetFalse(TargetFalse), | 110 Condition(Condition), TargetTrue(TargetTrue), TargetFalse(TargetFalse), |
111 Label(Label), Kind(Kind) {} | 111 Label(Label), Kind(Kind) {} |
112 | 112 |
113 template <class Machine> | 113 template <class Machine> |
114 bool InstX86Br<Machine>::optimizeBranch(const CfgNode *NextNode) { | 114 bool InstX86Br<Machine>::optimizeBranch(const CfgNode *NextNode) { |
115 // If there is no next block, then there can be no fallthrough to | 115 // If there is no next block, then there can be no fallthrough to optimize. |
116 // optimize. | |
117 if (NextNode == nullptr) | 116 if (NextNode == nullptr) |
118 return false; | 117 return false; |
119 // Intra-block conditional branches can't be optimized. | 118 // Intra-block conditional branches can't be optimized. |
120 if (Label) | 119 if (Label) |
121 return false; | 120 return false; |
122 // If there is no fallthrough node, such as a non-default case label | 121 // If there is no fallthrough node, such as a non-default case label for a |
123 // for a switch instruction, then there is no opportunity to | 122 // switch instruction, then there is no opportunity to optimize. |
124 // optimize. | |
125 if (getTargetFalse() == nullptr) | 123 if (getTargetFalse() == nullptr) |
126 return false; | 124 return false; |
127 | 125 |
128 // Unconditional branch to the next node can be removed. | 126 // Unconditional branch to the next node can be removed. |
129 if (Condition == InstX86Base<Machine>::Traits::Cond::Br_None && | 127 if (Condition == InstX86Base<Machine>::Traits::Cond::Br_None && |
130 getTargetFalse() == NextNode) { | 128 getTargetFalse() == NextNode) { |
131 assert(getTargetTrue() == nullptr); | 129 assert(getTargetTrue() == nullptr); |
132 this->setDeleted(); | 130 this->setDeleted(); |
133 return true; | 131 return true; |
134 } | 132 } |
135 // If the fallthrough is to the next node, set fallthrough to nullptr | 133 // If the fallthrough is to the next node, set fallthrough to nullptr to |
136 // to indicate. | 134 // indicate. |
137 if (getTargetFalse() == NextNode) { | 135 if (getTargetFalse() == NextNode) { |
138 TargetFalse = nullptr; | 136 TargetFalse = nullptr; |
139 return true; | 137 return true; |
140 } | 138 } |
141 // If TargetTrue is the next node, and TargetFalse is not nullptr | 139 // If TargetTrue is the next node, and TargetFalse is not nullptr (which was |
142 // (which was already tested above), then invert the branch | 140 // already tested above), then invert the branch condition, swap the targets, |
143 // condition, swap the targets, and set new fallthrough to nullptr. | 141 // and set new fallthrough to nullptr. |
144 if (getTargetTrue() == NextNode) { | 142 if (getTargetTrue() == NextNode) { |
145 assert(Condition != InstX86Base<Machine>::Traits::Cond::Br_None); | 143 assert(Condition != InstX86Base<Machine>::Traits::Cond::Br_None); |
146 Condition = this->getOppositeCondition(Condition); | 144 Condition = this->getOppositeCondition(Condition); |
147 TargetTrue = getTargetFalse(); | 145 TargetTrue = getTargetFalse(); |
148 TargetFalse = nullptr; | 146 TargetFalse = nullptr; |
149 return true; | 147 return true; |
150 } | 148 } |
151 return false; | 149 return false; |
152 } | 150 } |
153 | 151 |
(...skipping 24 matching lines...) Expand all Loading... |
178 this->HasSideEffects = true; | 176 this->HasSideEffects = true; |
179 this->addSource(CallTarget); | 177 this->addSource(CallTarget); |
180 } | 178 } |
181 | 179 |
182 template <class Machine> | 180 template <class Machine> |
183 InstX86Cmov<Machine>::InstX86Cmov( | 181 InstX86Cmov<Machine>::InstX86Cmov( |
184 Cfg *Func, Variable *Dest, Operand *Source, | 182 Cfg *Func, Variable *Dest, Operand *Source, |
185 typename InstX86Base<Machine>::Traits::Cond::BrCond Condition) | 183 typename InstX86Base<Machine>::Traits::Cond::BrCond Condition) |
186 : InstX86Base<Machine>(Func, InstX86Base<Machine>::Cmov, 2, Dest), | 184 : InstX86Base<Machine>(Func, InstX86Base<Machine>::Cmov, 2, Dest), |
187 Condition(Condition) { | 185 Condition(Condition) { |
188 // The final result is either the original Dest, or Source, so mark | 186 // The final result is either the original Dest, or Source, so mark both as |
189 // both as sources. | 187 // sources. |
190 this->addSource(Dest); | 188 this->addSource(Dest); |
191 this->addSource(Source); | 189 this->addSource(Source); |
192 } | 190 } |
193 | 191 |
194 template <class Machine> | 192 template <class Machine> |
195 InstX86Cmpps<Machine>::InstX86Cmpps( | 193 InstX86Cmpps<Machine>::InstX86Cmpps( |
196 Cfg *Func, Variable *Dest, Operand *Source, | 194 Cfg *Func, Variable *Dest, Operand *Source, |
197 typename InstX86Base<Machine>::Traits::Cond::CmppsCond Condition) | 195 typename InstX86Base<Machine>::Traits::Cond::CmppsCond Condition) |
198 : InstX86Base<Machine>(Func, InstX86Base<Machine>::Cmpps, 2, Dest), | 196 : InstX86Base<Machine>(Func, InstX86Base<Machine>::Cmpps, 2, Dest), |
199 Condition(Condition) { | 197 Condition(Condition) { |
(...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
313 this->addSource(Src); | 311 this->addSource(Src); |
314 } | 312 } |
315 | 313 |
316 template <class Machine> | 314 template <class Machine> |
317 InstX86Fstp<Machine>::InstX86Fstp(Cfg *Func, Variable *Dest) | 315 InstX86Fstp<Machine>::InstX86Fstp(Cfg *Func, Variable *Dest) |
318 : InstX86Base<Machine>(Func, InstX86Base<Machine>::Fstp, 0, Dest) {} | 316 : InstX86Base<Machine>(Func, InstX86Base<Machine>::Fstp, 0, Dest) {} |
319 | 317 |
320 template <class Machine> | 318 template <class Machine> |
321 InstX86Pop<Machine>::InstX86Pop(Cfg *Func, Variable *Dest) | 319 InstX86Pop<Machine>::InstX86Pop(Cfg *Func, Variable *Dest) |
322 : InstX86Base<Machine>(Func, InstX86Base<Machine>::Pop, 0, Dest) { | 320 : InstX86Base<Machine>(Func, InstX86Base<Machine>::Pop, 0, Dest) { |
323 // A pop instruction affects the stack pointer and so it should not | 321 // A pop instruction affects the stack pointer and so it should not be |
324 // be allowed to be automatically dead-code eliminated. (The | 322 // allowed to be automatically dead-code eliminated. (The corresponding push |
325 // corresponding push instruction doesn't need this treatment | 323 // instruction doesn't need this treatment because it has no dest variable |
326 // because it has no dest variable and therefore won't be dead-code | 324 // and therefore won't be dead-code eliminated.) This is needed for |
327 // eliminated.) This is needed for late-stage liveness analysis | 325 // late-stage liveness analysis (e.g. asm-verbose mode). |
328 // (e.g. asm-verbose mode). | |
329 this->HasSideEffects = true; | 326 this->HasSideEffects = true; |
330 } | 327 } |
331 | 328 |
332 template <class Machine> | 329 template <class Machine> |
333 InstX86Push<Machine>::InstX86Push(Cfg *Func, Variable *Source) | 330 InstX86Push<Machine>::InstX86Push(Cfg *Func, Variable *Source) |
334 : InstX86Base<Machine>(Func, InstX86Base<Machine>::Push, 1, nullptr) { | 331 : InstX86Base<Machine>(Func, InstX86Base<Machine>::Push, 1, nullptr) { |
335 this->addSource(Source); | 332 this->addSource(Source); |
336 } | 333 } |
337 | 334 |
338 template <class Machine> | 335 template <class Machine> |
(...skipping 183 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
522 void InstX86Jmp<Machine>::emitIAS(const Cfg *Func) const { | 519 void InstX86Jmp<Machine>::emitIAS(const Cfg *Func) const { |
523 // Note: Adapted (mostly copied) from InstX86Call<Machine>::emitIAS(). | 520 // Note: Adapted (mostly copied) from InstX86Call<Machine>::emitIAS(). |
524 typename InstX86Base<Machine>::Traits::Assembler *Asm = | 521 typename InstX86Base<Machine>::Traits::Assembler *Asm = |
525 Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>(); | 522 Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>(); |
526 Operand *Target = getJmpTarget(); | 523 Operand *Target = getJmpTarget(); |
527 if (const auto Var = llvm::dyn_cast<Variable>(Target)) { | 524 if (const auto Var = llvm::dyn_cast<Variable>(Target)) { |
528 if (Var->hasReg()) { | 525 if (Var->hasReg()) { |
529 Asm->jmp(InstX86Base<Machine>::Traits::RegisterSet::getEncodedGPR( | 526 Asm->jmp(InstX86Base<Machine>::Traits::RegisterSet::getEncodedGPR( |
530 Var->getRegNum())); | 527 Var->getRegNum())); |
531 } else { | 528 } else { |
532 // The jmp instruction with a memory operand should be possible | 529 // The jmp instruction with a memory operand should be possible to |
533 // to encode, but it isn't a valid sandboxed instruction, and | 530 // encode, but it isn't a valid sandboxed instruction, and there |
534 // there shouldn't be a register allocation issue to jump | 531 // shouldn't be a register allocation issue to jump through a scratch |
535 // through a scratch register, so we don't really need to bother | 532 // register, so we don't really need to bother implementing it. |
536 // implementing it. | |
537 llvm::report_fatal_error("Assembler can't jmp to memory operand"); | 533 llvm::report_fatal_error("Assembler can't jmp to memory operand"); |
538 } | 534 } |
539 } else if (const auto Mem = llvm::dyn_cast< | 535 } else if (const auto Mem = llvm::dyn_cast< |
540 typename InstX86Base<Machine>::Traits::X86OperandMem>( | 536 typename InstX86Base<Machine>::Traits::X86OperandMem>( |
541 Target)) { | 537 Target)) { |
542 (void)Mem; | 538 (void)Mem; |
543 assert(Mem->getSegmentRegister() == | 539 assert(Mem->getSegmentRegister() == |
544 InstX86Base<Machine>::Traits::X86OperandMem::DefaultSegment); | 540 InstX86Base<Machine>::Traits::X86OperandMem::DefaultSegment); |
545 llvm::report_fatal_error("Assembler can't jmp to memory operand"); | 541 llvm::report_fatal_error("Assembler can't jmp to memory operand"); |
546 } else if (const auto CR = llvm::dyn_cast<ConstantRelocatable>(Target)) { | 542 } else if (const auto CR = llvm::dyn_cast<ConstantRelocatable>(Target)) { |
547 assert(CR->getOffset() == 0 && "We only support jumping to a function"); | 543 assert(CR->getOffset() == 0 && "We only support jumping to a function"); |
548 Asm->jmp(CR); | 544 Asm->jmp(CR); |
549 } else if (const auto Imm = llvm::dyn_cast<ConstantInteger32>(Target)) { | 545 } else if (const auto Imm = llvm::dyn_cast<ConstantInteger32>(Target)) { |
550 // NaCl trampoline calls refer to an address within the sandbox directly. | 546 // NaCl trampoline calls refer to an address within the sandbox directly. |
551 // This is usually only needed for non-IRT builds and otherwise not | 547 // This is usually only needed for non-IRT builds and otherwise not very |
552 // very portable or stable. Usually this is only done for "calls" | 548 // portable or stable. Usually this is only done for "calls" and not jumps. |
553 // and not jumps. | 549 // TODO(jvoung): Support this when there is a lowering that actually |
554 // TODO(jvoung): Support this when there is a lowering that | 550 // triggers this case. |
555 // actually triggers this case. | |
556 (void)Imm; | 551 (void)Imm; |
557 llvm::report_fatal_error("Unexpected jmp to absolute address"); | 552 llvm::report_fatal_error("Unexpected jmp to absolute address"); |
558 } else { | 553 } else { |
559 llvm::report_fatal_error("Unexpected operand type"); | 554 llvm::report_fatal_error("Unexpected operand type"); |
560 } | 555 } |
561 } | 556 } |
562 | 557 |
563 template <class Machine> void InstX86Jmp<Machine>::dump(const Cfg *Func) const { | 558 template <class Machine> void InstX86Jmp<Machine>::dump(const Cfg *Func) const { |
564 if (!BuildDefs::dump()) | 559 if (!BuildDefs::dump()) |
565 return; | 560 return; |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
626 return; | 621 return; |
627 Ostream &Str = Func->getContext()->getStrDump(); | 622 Ostream &Str = Func->getContext()->getStrDump(); |
628 if (this->getDest()) { | 623 if (this->getDest()) { |
629 this->dumpDest(Func); | 624 this->dumpDest(Func); |
630 Str << " = "; | 625 Str << " = "; |
631 } | 626 } |
632 Str << "call "; | 627 Str << "call "; |
633 getCallTarget()->dump(Func); | 628 getCallTarget()->dump(Func); |
634 } | 629 } |
635 | 630 |
636 // The ShiftHack parameter is used to emit "cl" instead of "ecx" for | 631 // The ShiftHack parameter is used to emit "cl" instead of "ecx" for shift |
637 // shift instructions, in order to be syntactically valid. The | 632 // instructions, in order to be syntactically valid. The this->Opcode parameter |
638 // this->Opcode parameter needs to be char* and not IceString because of | 633 // needs to be char* and not IceString because of template issues. |
639 // template issues. | |
640 template <class Machine> | 634 template <class Machine> |
641 void InstX86Base<Machine>::emitTwoAddress(const char *Opcode, const Inst *Inst, | 635 void InstX86Base<Machine>::emitTwoAddress(const char *Opcode, const Inst *Inst, |
642 const Cfg *Func, bool ShiftHack) { | 636 const Cfg *Func, bool ShiftHack) { |
643 if (!BuildDefs::dump()) | 637 if (!BuildDefs::dump()) |
644 return; | 638 return; |
645 Ostream &Str = Func->getContext()->getStrEmit(); | 639 Ostream &Str = Func->getContext()->getStrEmit(); |
646 assert(Inst->getSrcSize() == 2); | 640 assert(Inst->getSrcSize() == 2); |
647 Operand *Dest = Inst->getDest(); | 641 Operand *Dest = Inst->getDest(); |
648 if (Dest == nullptr) | 642 if (Dest == nullptr) |
649 Dest = Inst->getSrc(0); | 643 Dest = Inst->getSrc(0); |
(...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
795 } | 789 } |
796 } | 790 } |
797 | 791 |
798 template <class Machine> | 792 template <class Machine> |
799 void InstX86Base<Machine>::emitIASGPRShift( | 793 void InstX86Base<Machine>::emitIASGPRShift( |
800 const Cfg *Func, Type Ty, const Variable *Var, const Operand *Src, | 794 const Cfg *Func, Type Ty, const Variable *Var, const Operand *Src, |
801 const typename InstX86Base<Machine>::Traits::Assembler::GPREmitterShiftOp | 795 const typename InstX86Base<Machine>::Traits::Assembler::GPREmitterShiftOp |
802 &Emitter) { | 796 &Emitter) { |
803 typename InstX86Base<Machine>::Traits::Assembler *Asm = | 797 typename InstX86Base<Machine>::Traits::Assembler *Asm = |
804 Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>(); | 798 Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>(); |
805 // Technically, the Dest Var can be mem as well, but we only use Reg. | 799 // Technically, the Dest Var can be mem as well, but we only use Reg. We can |
806 // We can extend this to check Dest if we decide to use that form. | 800 // extend this to check Dest if we decide to use that form. |
807 assert(Var->hasReg()); | 801 assert(Var->hasReg()); |
808 // We cheat a little and use GPRRegister even for byte operations. | 802 // We cheat a little and use GPRRegister even for byte operations. |
809 typename InstX86Base<Machine>::Traits::RegisterSet::GPRRegister VarReg = | 803 typename InstX86Base<Machine>::Traits::RegisterSet::GPRRegister VarReg = |
810 InstX86Base<Machine>::Traits::RegisterSet::getEncodedByteRegOrGPR( | 804 InstX86Base<Machine>::Traits::RegisterSet::getEncodedByteRegOrGPR( |
811 Ty, Var->getRegNum()); | 805 Ty, Var->getRegNum()); |
812 // Src must be reg == ECX or an Imm8. | 806 // Src must be reg == ECX or an Imm8. This is asserted by the assembler. |
813 // This is asserted by the assembler. | |
814 if (const auto SrcVar = llvm::dyn_cast<Variable>(Src)) { | 807 if (const auto SrcVar = llvm::dyn_cast<Variable>(Src)) { |
815 assert(SrcVar->hasReg()); | 808 assert(SrcVar->hasReg()); |
816 typename InstX86Base<Machine>::Traits::RegisterSet::GPRRegister SrcReg = | 809 typename InstX86Base<Machine>::Traits::RegisterSet::GPRRegister SrcReg = |
817 InstX86Base<Machine>::Traits::RegisterSet::getEncodedByteRegOrGPR( | 810 InstX86Base<Machine>::Traits::RegisterSet::getEncodedByteRegOrGPR( |
818 Ty, SrcVar->getRegNum()); | 811 Ty, SrcVar->getRegNum()); |
819 (Asm->*(Emitter.GPRGPR))(Ty, VarReg, SrcReg); | 812 (Asm->*(Emitter.GPRGPR))(Ty, VarReg, SrcReg); |
820 } else if (const auto Imm = llvm::dyn_cast<ConstantInteger32>(Src)) { | 813 } else if (const auto Imm = llvm::dyn_cast<ConstantInteger32>(Src)) { |
821 (Asm->*(Emitter.GPRImm))(Ty, VarReg, Immediate(Imm->getValue())); | 814 (Asm->*(Emitter.GPRImm))(Ty, VarReg, Immediate(Imm->getValue())); |
822 } else { | 815 } else { |
823 llvm_unreachable("Unexpected operand type"); | 816 llvm_unreachable("Unexpected operand type"); |
(...skipping 506 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1330 (void)Src0Var; | 1323 (void)Src0Var; |
1331 assert(Src0Var && | 1324 assert(Src0Var && |
1332 Src0Var->getRegNum() == | 1325 Src0Var->getRegNum() == |
1333 InstX86Base<Machine>::Traits::RegisterSet::Reg_eax); | 1326 InstX86Base<Machine>::Traits::RegisterSet::Reg_eax); |
1334 static const typename InstX86Base< | 1327 static const typename InstX86Base< |
1335 Machine>::Traits::Assembler::GPREmitterOneOp Emitter = { | 1328 Machine>::Traits::Assembler::GPREmitterOneOp Emitter = { |
1336 &InstX86Base<Machine>::Traits::Assembler::imul, | 1329 &InstX86Base<Machine>::Traits::Assembler::imul, |
1337 &InstX86Base<Machine>::Traits::Assembler::imul}; | 1330 &InstX86Base<Machine>::Traits::Assembler::imul}; |
1338 emitIASOpTyGPR<Machine>(Func, Ty, this->getSrc(1), Emitter); | 1331 emitIASOpTyGPR<Machine>(Func, Ty, this->getSrc(1), Emitter); |
1339 } else { | 1332 } else { |
1340 // We only use imul as a two-address instruction even though | 1333 // We only use imul as a two-address instruction even though there is a 3 |
1341 // there is a 3 operand version when one of the operands is a constant. | 1334 // operand version when one of the operands is a constant. |
1342 assert(Var == this->getSrc(0)); | 1335 assert(Var == this->getSrc(0)); |
1343 static const typename InstX86Base< | 1336 static const typename InstX86Base< |
1344 Machine>::Traits::Assembler::GPREmitterRegOp Emitter = { | 1337 Machine>::Traits::Assembler::GPREmitterRegOp Emitter = { |
1345 &InstX86Base<Machine>::Traits::Assembler::imul, | 1338 &InstX86Base<Machine>::Traits::Assembler::imul, |
1346 &InstX86Base<Machine>::Traits::Assembler::imul, | 1339 &InstX86Base<Machine>::Traits::Assembler::imul, |
1347 &InstX86Base<Machine>::Traits::Assembler::imul}; | 1340 &InstX86Base<Machine>::Traits::Assembler::imul}; |
1348 emitIASRegOpTyGPR<Machine>(Func, Ty, Var, Src, Emitter); | 1341 emitIASRegOpTyGPR<Machine>(Func, Ty, Var, Src, Emitter); |
1349 } | 1342 } |
1350 } | 1343 } |
1351 | 1344 |
(...skipping 319 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1671 Str << ", "; | 1664 Str << ", "; |
1672 this->getDest()->emit(Func); | 1665 this->getDest()->emit(Func); |
1673 } | 1666 } |
1674 | 1667 |
1675 template <class Machine> | 1668 template <class Machine> |
1676 void InstX86Cmpps<Machine>::emitIAS(const Cfg *Func) const { | 1669 void InstX86Cmpps<Machine>::emitIAS(const Cfg *Func) const { |
1677 typename InstX86Base<Machine>::Traits::Assembler *Asm = | 1670 typename InstX86Base<Machine>::Traits::Assembler *Asm = |
1678 Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>(); | 1671 Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>(); |
1679 assert(this->getSrcSize() == 2); | 1672 assert(this->getSrcSize() == 2); |
1680 assert(Condition < InstX86Base<Machine>::Traits::Cond::Cmpps_Invalid); | 1673 assert(Condition < InstX86Base<Machine>::Traits::Cond::Cmpps_Invalid); |
1681 // Assuming there isn't any load folding for cmpps, and vector constants | 1674 // Assuming there isn't any load folding for cmpps, and vector constants are |
1682 // are not allowed in PNaCl. | 1675 // not allowed in PNaCl. |
1683 assert(llvm::isa<Variable>(this->getSrc(1))); | 1676 assert(llvm::isa<Variable>(this->getSrc(1))); |
1684 const auto SrcVar = llvm::cast<Variable>(this->getSrc(1)); | 1677 const auto SrcVar = llvm::cast<Variable>(this->getSrc(1)); |
1685 if (SrcVar->hasReg()) { | 1678 if (SrcVar->hasReg()) { |
1686 Asm->cmpps(InstX86Base<Machine>::Traits::RegisterSet::getEncodedXmm( | 1679 Asm->cmpps(InstX86Base<Machine>::Traits::RegisterSet::getEncodedXmm( |
1687 this->getDest()->getRegNum()), | 1680 this->getDest()->getRegNum()), |
1688 InstX86Base<Machine>::Traits::RegisterSet::getEncodedXmm( | 1681 InstX86Base<Machine>::Traits::RegisterSet::getEncodedXmm( |
1689 SrcVar->getRegNum()), | 1682 SrcVar->getRegNum()), |
1690 Condition); | 1683 Condition); |
1691 } else { | 1684 } else { |
1692 typename InstX86Base<Machine>::Traits::Address SrcStackAddr = | 1685 typename InstX86Base<Machine>::Traits::Address SrcStackAddr = |
(...skipping 288 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1981 ->getType()] | 1974 ->getType()] |
1982 .SdSsString << "\t"; | 1975 .SdSsString << "\t"; |
1983 this->getSrc(1)->emit(Func); | 1976 this->getSrc(1)->emit(Func); |
1984 Str << ", "; | 1977 Str << ", "; |
1985 this->getSrc(0)->emit(Func); | 1978 this->getSrc(0)->emit(Func); |
1986 } | 1979 } |
1987 | 1980 |
1988 template <class Machine> | 1981 template <class Machine> |
1989 void InstX86Ucomiss<Machine>::emitIAS(const Cfg *Func) const { | 1982 void InstX86Ucomiss<Machine>::emitIAS(const Cfg *Func) const { |
1990 assert(this->getSrcSize() == 2); | 1983 assert(this->getSrcSize() == 2); |
1991 // Currently src0 is always a variable by convention, to avoid having | 1984 // Currently src0 is always a variable by convention, to avoid having two |
1992 // two memory operands. | 1985 // memory operands. |
1993 assert(llvm::isa<Variable>(this->getSrc(0))); | 1986 assert(llvm::isa<Variable>(this->getSrc(0))); |
1994 const auto Src0Var = llvm::cast<Variable>(this->getSrc(0)); | 1987 const auto Src0Var = llvm::cast<Variable>(this->getSrc(0)); |
1995 Type Ty = Src0Var->getType(); | 1988 Type Ty = Src0Var->getType(); |
1996 static const typename InstX86Base<Machine>::Traits::Assembler::XmmEmitterRegOp | 1989 static const typename InstX86Base<Machine>::Traits::Assembler::XmmEmitterRegOp |
1997 Emitter = {&InstX86Base<Machine>::Traits::Assembler::ucomiss, | 1990 Emitter = {&InstX86Base<Machine>::Traits::Assembler::ucomiss, |
1998 &InstX86Base<Machine>::Traits::Assembler::ucomiss}; | 1991 &InstX86Base<Machine>::Traits::Assembler::ucomiss}; |
1999 emitIASRegOpTyXMM<Machine>(Func, Ty, Src0Var, this->getSrc(1), Emitter); | 1992 emitIASRegOpTyXMM<Machine>(Func, Ty, Src0Var, this->getSrc(1), Emitter); |
2000 } | 1993 } |
2001 | 1994 |
2002 template <class Machine> | 1995 template <class Machine> |
(...skipping 281 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2284 if (InstX86Base<Machine>::Traits::Is64Bit && DestTy == IceType_i64 && | 2277 if (InstX86Base<Machine>::Traits::Is64Bit && DestTy == IceType_i64 && |
2285 isIntegerConstant(Src)) { | 2278 isIntegerConstant(Src)) { |
2286 Str << "\tmovabs\t"; | 2279 Str << "\tmovabs\t"; |
2287 } else { | 2280 } else { |
2288 Str << "\tmov" | 2281 Str << "\tmov" |
2289 << (!isScalarFloatingType(DestTy) | 2282 << (!isScalarFloatingType(DestTy) |
2290 ? this->getWidthString(SrcTy) | 2283 ? this->getWidthString(SrcTy) |
2291 : InstX86Base<Machine>::Traits::TypeAttributes[DestTy] | 2284 : InstX86Base<Machine>::Traits::TypeAttributes[DestTy] |
2292 .SdSsString) << "\t"; | 2285 .SdSsString) << "\t"; |
2293 } | 2286 } |
2294 // For an integer truncation operation, src is wider than dest. | 2287 // For an integer truncation operation, src is wider than dest. Ideally, we |
2295 // Ideally, we use a mov instruction whose data width matches the | 2288 // use a mov instruction whose data width matches the narrower dest. This is |
2296 // narrower dest. This is a problem if e.g. src is a register like | 2289 // a problem if e.g. src is a register like esi or si where there is no 8-bit |
2297 // esi or si where there is no 8-bit version of the register. To be | 2290 // version of the register. To be safe, we instead widen the dest to match |
2298 // safe, we instead widen the dest to match src. This works even | 2291 // src. This works even for stack-allocated dest variables because |
2299 // for stack-allocated dest variables because typeWidthOnStack() | 2292 // typeWidthOnStack() pads to a 4-byte boundary even if only a lower portion |
2300 // pads to a 4-byte boundary even if only a lower portion is used. | 2293 // is used. |
2301 // TODO: This assert disallows usages such as copying a floating point | 2294 // TODO: This assert disallows usages such as copying a floating |
2302 // value between a vector and a scalar (which movss is used for). | 2295 // point value between a vector and a scalar (which movss is used for). Clean |
2303 // Clean this up. | 2296 // this up. |
2304 assert(Func->getTarget()->typeWidthInBytesOnStack(DestTy) == | 2297 assert(Func->getTarget()->typeWidthInBytesOnStack(DestTy) == |
2305 Func->getTarget()->typeWidthInBytesOnStack(SrcTy)); | 2298 Func->getTarget()->typeWidthInBytesOnStack(SrcTy)); |
2306 Src->emit(Func); | 2299 Src->emit(Func); |
2307 Str << ", "; | 2300 Str << ", "; |
2308 this->getDest()->asType(SrcTy)->emit(Func); | 2301 this->getDest()->asType(SrcTy)->emit(Func); |
2309 } | 2302 } |
2310 | 2303 |
2311 template <class Machine> | 2304 template <class Machine> |
2312 void InstX86Mov<Machine>::emitIAS(const Cfg *Func) const { | 2305 void InstX86Mov<Machine>::emitIAS(const Cfg *Func) const { |
2313 assert(this->getSrcSize() == 1); | 2306 assert(this->getSrcSize() == 1); |
2314 const Variable *Dest = this->getDest(); | 2307 const Variable *Dest = this->getDest(); |
2315 const Operand *Src = this->getSrc(0); | 2308 const Operand *Src = this->getSrc(0); |
2316 Type DestTy = Dest->getType(); | 2309 Type DestTy = Dest->getType(); |
2317 Type SrcTy = Src->getType(); | 2310 Type SrcTy = Src->getType(); |
2318 // Mov can be used for GPRs or XMM registers. Also, the type does not | 2311 // Mov can be used for GPRs or XMM registers. Also, the type does not |
2319 // necessarily match (Mov can be used for bitcasts). However, when | 2312 // necessarily match (Mov can be used for bitcasts). However, when the type |
2320 // the type does not match, one of the operands must be a register. | 2313 // does not match, one of the operands must be a register. Thus, the strategy |
2321 // Thus, the strategy is to find out if Src or Dest are a register, | 2314 // is to find out if Src or Dest are a register, then use that register's |
2322 // then use that register's type to decide on which emitter set to use. | 2315 // type to decide on which emitter set to use. The emitter set will include |
2323 // The emitter set will include reg-reg movs, but that case should | 2316 // reg-reg movs, but that case should be unused when the types don't match. |
2324 // be unused when the types don't match. | |
2325 static const typename InstX86Base<Machine>::Traits::Assembler::XmmEmitterRegOp | 2317 static const typename InstX86Base<Machine>::Traits::Assembler::XmmEmitterRegOp |
2326 XmmRegEmitter = {&InstX86Base<Machine>::Traits::Assembler::movss, | 2318 XmmRegEmitter = {&InstX86Base<Machine>::Traits::Assembler::movss, |
2327 &InstX86Base<Machine>::Traits::Assembler::movss}; | 2319 &InstX86Base<Machine>::Traits::Assembler::movss}; |
2328 static const typename InstX86Base<Machine>::Traits::Assembler::GPREmitterRegOp | 2320 static const typename InstX86Base<Machine>::Traits::Assembler::GPREmitterRegOp |
2329 GPRRegEmitter = {&InstX86Base<Machine>::Traits::Assembler::mov, | 2321 GPRRegEmitter = {&InstX86Base<Machine>::Traits::Assembler::mov, |
2330 &InstX86Base<Machine>::Traits::Assembler::mov, | 2322 &InstX86Base<Machine>::Traits::Assembler::mov, |
2331 &InstX86Base<Machine>::Traits::Assembler::mov}; | 2323 &InstX86Base<Machine>::Traits::Assembler::mov}; |
2332 static const typename InstX86Base< | 2324 static const typename InstX86Base< |
2333 Machine>::Traits::Assembler::GPREmitterAddrOp GPRAddrEmitter = { | 2325 Machine>::Traits::Assembler::GPREmitterAddrOp GPRAddrEmitter = { |
2334 &InstX86Base<Machine>::Traits::Assembler::mov, | 2326 &InstX86Base<Machine>::Traits::Assembler::mov, |
2335 &InstX86Base<Machine>::Traits::Assembler::mov}; | 2327 &InstX86Base<Machine>::Traits::Assembler::mov}; |
2336 // For an integer truncation operation, src is wider than dest. | 2328 // For an integer truncation operation, src is wider than dest. Ideally, we |
2337 // Ideally, we use a mov instruction whose data width matches the | 2329 // use a mov instruction whose data width matches the narrower dest. This is |
2338 // narrower dest. This is a problem if e.g. src is a register like | 2330 // a problem if e.g. src is a register like esi or si where there is no 8-bit |
2339 // esi or si where there is no 8-bit version of the register. To be | 2331 // version of the register. To be safe, we instead widen the dest to match |
2340 // safe, we instead widen the dest to match src. This works even | 2332 // src. This works even for stack-allocated dest variables because |
2341 // for stack-allocated dest variables because typeWidthOnStack() | 2333 // typeWidthOnStack() pads to a 4-byte boundary even if only a lower portion |
2342 // pads to a 4-byte boundary even if only a lower portion is used. | 2334 // is used. |
2343 // TODO: This assert disallows usages such as copying a floating point | 2335 // TODO: This assert disallows usages such as copying a floating |
2344 // value between a vector and a scalar (which movss is used for). | 2336 // point value between a vector and a scalar (which movss is used for). Clean |
2345 // Clean this up. | 2337 // this up. |
2346 assert( | 2338 assert( |
2347 Func->getTarget()->typeWidthInBytesOnStack(this->getDest()->getType()) == | 2339 Func->getTarget()->typeWidthInBytesOnStack(this->getDest()->getType()) == |
2348 Func->getTarget()->typeWidthInBytesOnStack(Src->getType())); | 2340 Func->getTarget()->typeWidthInBytesOnStack(Src->getType())); |
2349 if (Dest->hasReg()) { | 2341 if (Dest->hasReg()) { |
2350 if (isScalarFloatingType(DestTy)) { | 2342 if (isScalarFloatingType(DestTy)) { |
2351 emitIASRegOpTyXMM<Machine>(Func, DestTy, Dest, Src, XmmRegEmitter); | 2343 emitIASRegOpTyXMM<Machine>(Func, DestTy, Dest, Src, XmmRegEmitter); |
2352 return; | 2344 return; |
2353 } else { | 2345 } else { |
2354 assert(isScalarIntegerType(DestTy)); | 2346 assert(isScalarIntegerType(DestTy)); |
2355 // Widen DestTy for truncation (see above note). We should only do this | 2347 // Widen DestTy for truncation (see above note). We should only do this |
(...skipping 12 matching lines...) Expand all Loading... |
2368 Value); | 2360 Value); |
2369 return; | 2361 return; |
2370 } | 2362 } |
2371 if (isScalarIntegerType(SrcTy)) { | 2363 if (isScalarIntegerType(SrcTy)) { |
2372 DestTy = SrcTy; | 2364 DestTy = SrcTy; |
2373 } | 2365 } |
2374 emitIASRegOpTyGPR<Machine>(Func, DestTy, Dest, Src, GPRRegEmitter); | 2366 emitIASRegOpTyGPR<Machine>(Func, DestTy, Dest, Src, GPRRegEmitter); |
2375 return; | 2367 return; |
2376 } | 2368 } |
2377 } else { | 2369 } else { |
2378 // Dest must be Stack and Src *could* be a register. Use Src's type | 2370 // Dest must be Stack and Src *could* be a register. Use Src's type to |
2379 // to decide on the emitters. | 2371 // decide on the emitters. |
2380 typename InstX86Base<Machine>::Traits::Address StackAddr( | 2372 typename InstX86Base<Machine>::Traits::Address StackAddr( |
2381 static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>( | 2373 static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>( |
2382 Func->getTarget()) | 2374 Func->getTarget()) |
2383 ->stackVarToAsmOperand(Dest)); | 2375 ->stackVarToAsmOperand(Dest)); |
2384 if (isScalarFloatingType(SrcTy)) { | 2376 if (isScalarFloatingType(SrcTy)) { |
2385 // Src must be a register. | 2377 // Src must be a register. |
2386 const auto SrcVar = llvm::cast<Variable>(Src); | 2378 const auto SrcVar = llvm::cast<Variable>(Src); |
2387 assert(SrcVar->hasReg()); | 2379 assert(SrcVar->hasReg()); |
2388 typename InstX86Base<Machine>::Traits::Assembler *Asm = | 2380 typename InstX86Base<Machine>::Traits::Assembler *Asm = |
2389 Func->getAssembler< | 2381 Func->getAssembler< |
(...skipping 12 matching lines...) Expand all Loading... |
2402 } | 2394 } |
2403 } | 2395 } |
2404 | 2396 |
2405 template <class Machine> | 2397 template <class Machine> |
2406 void InstX86Movd<Machine>::emitIAS(const Cfg *Func) const { | 2398 void InstX86Movd<Machine>::emitIAS(const Cfg *Func) const { |
2407 typename InstX86Base<Machine>::Traits::Assembler *Asm = | 2399 typename InstX86Base<Machine>::Traits::Assembler *Asm = |
2408 Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>(); | 2400 Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>(); |
2409 assert(this->getSrcSize() == 1); | 2401 assert(this->getSrcSize() == 1); |
2410 const Variable *Dest = this->getDest(); | 2402 const Variable *Dest = this->getDest(); |
2411 const auto SrcVar = llvm::cast<Variable>(this->getSrc(0)); | 2403 const auto SrcVar = llvm::cast<Variable>(this->getSrc(0)); |
2412 // For insert/extract element (one of Src/Dest is an Xmm vector and | 2404 // For insert/extract element (one of Src/Dest is an Xmm vector and the other |
2413 // the other is an int type). | 2405 // is an int type). |
2414 if (SrcVar->getType() == IceType_i32 || | 2406 if (SrcVar->getType() == IceType_i32 || |
2415 (InstX86Base<Machine>::Traits::Is64Bit && | 2407 (InstX86Base<Machine>::Traits::Is64Bit && |
2416 SrcVar->getType() == IceType_i64)) { | 2408 SrcVar->getType() == IceType_i64)) { |
2417 assert(isVectorType(Dest->getType()) || | 2409 assert(isVectorType(Dest->getType()) || |
2418 (isScalarFloatingType(Dest->getType()) && | 2410 (isScalarFloatingType(Dest->getType()) && |
2419 typeWidthInBytes(SrcVar->getType()) == | 2411 typeWidthInBytes(SrcVar->getType()) == |
2420 typeWidthInBytes(Dest->getType()))); | 2412 typeWidthInBytes(Dest->getType()))); |
2421 assert(Dest->hasReg()); | 2413 assert(Dest->hasReg()); |
2422 typename InstX86Base<Machine>::Traits::RegisterSet::XmmRegister DestReg = | 2414 typename InstX86Base<Machine>::Traits::RegisterSet::XmmRegister DestReg = |
2423 InstX86Base<Machine>::Traits::RegisterSet::getEncodedXmm( | 2415 InstX86Base<Machine>::Traits::RegisterSet::getEncodedXmm( |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2457 ->stackVarToAsmOperand(Dest)); | 2449 ->stackVarToAsmOperand(Dest)); |
2458 Asm->movd(Dest->getType(), StackAddr, SrcReg); | 2450 Asm->movd(Dest->getType(), StackAddr, SrcReg); |
2459 } | 2451 } |
2460 } | 2452 } |
2461 } | 2453 } |
2462 | 2454 |
2463 template <class Machine> | 2455 template <class Machine> |
2464 void InstX86Movp<Machine>::emit(const Cfg *Func) const { | 2456 void InstX86Movp<Machine>::emit(const Cfg *Func) const { |
2465 if (!BuildDefs::dump()) | 2457 if (!BuildDefs::dump()) |
2466 return; | 2458 return; |
2467 // TODO(wala,stichnot): movups works with all vector operands, but | 2459 // TODO(wala,stichnot): movups works with all vector operands, but there |
2468 // there exist other instructions (movaps, movdqa, movdqu) that may | 2460 // exist other instructions (movaps, movdqa, movdqu) that may perform better, |
2469 // perform better, depending on the data type and alignment of the | 2461 // depending on the data type and alignment of the operands. |
2470 // operands. | |
2471 Ostream &Str = Func->getContext()->getStrEmit(); | 2462 Ostream &Str = Func->getContext()->getStrEmit(); |
2472 assert(this->getSrcSize() == 1); | 2463 assert(this->getSrcSize() == 1); |
2473 Str << "\tmovups\t"; | 2464 Str << "\tmovups\t"; |
2474 this->getSrc(0)->emit(Func); | 2465 this->getSrc(0)->emit(Func); |
2475 Str << ", "; | 2466 Str << ", "; |
2476 this->getDest()->emit(Func); | 2467 this->getDest()->emit(Func); |
2477 } | 2468 } |
2478 | 2469 |
2479 template <class Machine> | 2470 template <class Machine> |
2480 void InstX86Movp<Machine>::emitIAS(const Cfg *Func) const { | 2471 void InstX86Movp<Machine>::emitIAS(const Cfg *Func) const { |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2514 static const typename InstX86Base< | 2505 static const typename InstX86Base< |
2515 Machine>::Traits::Assembler::XmmEmitterMovOps Emitter = { | 2506 Machine>::Traits::Assembler::XmmEmitterMovOps Emitter = { |
2516 &InstX86Base<Machine>::Traits::Assembler::movq, | 2507 &InstX86Base<Machine>::Traits::Assembler::movq, |
2517 &InstX86Base<Machine>::Traits::Assembler::movq, | 2508 &InstX86Base<Machine>::Traits::Assembler::movq, |
2518 &InstX86Base<Machine>::Traits::Assembler::movq}; | 2509 &InstX86Base<Machine>::Traits::Assembler::movq}; |
2519 emitIASMovlikeXMM<Machine>(Func, Dest, Src, Emitter); | 2510 emitIASMovlikeXMM<Machine>(Func, Dest, Src, Emitter); |
2520 } | 2511 } |
2521 | 2512 |
2522 template <class Machine> | 2513 template <class Machine> |
2523 void InstX86MovssRegs<Machine>::emitIAS(const Cfg *Func) const { | 2514 void InstX86MovssRegs<Machine>::emitIAS(const Cfg *Func) const { |
2524 // This is Binop variant is only intended to be used for reg-reg moves | 2515 // This is Binop variant is only intended to be used for reg-reg moves where |
2525 // where part of the Dest register is untouched. | 2516 // part of the Dest register is untouched. |
2526 assert(this->getSrcSize() == 2); | 2517 assert(this->getSrcSize() == 2); |
2527 const Variable *Dest = this->getDest(); | 2518 const Variable *Dest = this->getDest(); |
2528 assert(Dest == this->getSrc(0)); | 2519 assert(Dest == this->getSrc(0)); |
2529 const auto SrcVar = llvm::cast<Variable>(this->getSrc(1)); | 2520 const auto SrcVar = llvm::cast<Variable>(this->getSrc(1)); |
2530 assert(Dest->hasReg() && SrcVar->hasReg()); | 2521 assert(Dest->hasReg() && SrcVar->hasReg()); |
2531 typename InstX86Base<Machine>::Traits::Assembler *Asm = | 2522 typename InstX86Base<Machine>::Traits::Assembler *Asm = |
2532 Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>(); | 2523 Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>(); |
2533 Asm->movss(IceType_f32, | 2524 Asm->movss(IceType_f32, |
2534 InstX86Base<Machine>::Traits::RegisterSet::getEncodedXmm( | 2525 InstX86Base<Machine>::Traits::RegisterSet::getEncodedXmm( |
2535 Dest->getRegNum()), | 2526 Dest->getRegNum()), |
2536 InstX86Base<Machine>::Traits::RegisterSet::getEncodedXmm( | 2527 InstX86Base<Machine>::Traits::RegisterSet::getEncodedXmm( |
2537 SrcVar->getRegNum())); | 2528 SrcVar->getRegNum())); |
2538 } | 2529 } |
2539 | 2530 |
2540 template <class Machine> | 2531 template <class Machine> |
2541 void InstX86Movsx<Machine>::emitIAS(const Cfg *Func) const { | 2532 void InstX86Movsx<Machine>::emitIAS(const Cfg *Func) const { |
2542 assert(this->getSrcSize() == 1); | 2533 assert(this->getSrcSize() == 1); |
2543 const Variable *Dest = this->getDest(); | 2534 const Variable *Dest = this->getDest(); |
2544 const Operand *Src = this->getSrc(0); | 2535 const Operand *Src = this->getSrc(0); |
2545 // Dest must be a > 8-bit register, but Src can be 8-bit. In practice | 2536 // Dest must be a > 8-bit register, but Src can be 8-bit. In practice we just |
2546 // we just use the full register for Dest to avoid having an | 2537 // use the full register for Dest to avoid having an OperandSizeOverride |
2547 // OperandSizeOverride prefix. It also allows us to only dispatch on SrcTy. | 2538 // prefix. It also allows us to only dispatch on SrcTy. |
2548 Type SrcTy = Src->getType(); | 2539 Type SrcTy = Src->getType(); |
2549 assert(typeWidthInBytes(Dest->getType()) > 1); | 2540 assert(typeWidthInBytes(Dest->getType()) > 1); |
2550 assert(typeWidthInBytes(Dest->getType()) > typeWidthInBytes(SrcTy)); | 2541 assert(typeWidthInBytes(Dest->getType()) > typeWidthInBytes(SrcTy)); |
2551 emitIASRegOpTyGPR<Machine, false, true>(Func, SrcTy, Dest, Src, | 2542 emitIASRegOpTyGPR<Machine, false, true>(Func, SrcTy, Dest, Src, |
2552 this->Emitter); | 2543 this->Emitter); |
2553 } | 2544 } |
2554 | 2545 |
2555 template <class Machine> | 2546 template <class Machine> |
2556 void InstX86Movzx<Machine>::emitIAS(const Cfg *Func) const { | 2547 void InstX86Movzx<Machine>::emitIAS(const Cfg *Func) const { |
2557 assert(this->getSrcSize() == 1); | 2548 assert(this->getSrcSize() == 1); |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2589 | 2580 |
2590 template <class Machine> void InstX86Fld<Machine>::emit(const Cfg *Func) const { | 2581 template <class Machine> void InstX86Fld<Machine>::emit(const Cfg *Func) const { |
2591 if (!BuildDefs::dump()) | 2582 if (!BuildDefs::dump()) |
2592 return; | 2583 return; |
2593 Ostream &Str = Func->getContext()->getStrEmit(); | 2584 Ostream &Str = Func->getContext()->getStrEmit(); |
2594 assert(this->getSrcSize() == 1); | 2585 assert(this->getSrcSize() == 1); |
2595 Type Ty = this->getSrc(0)->getType(); | 2586 Type Ty = this->getSrc(0)->getType(); |
2596 SizeT Width = typeWidthInBytes(Ty); | 2587 SizeT Width = typeWidthInBytes(Ty); |
2597 const auto Var = llvm::dyn_cast<Variable>(this->getSrc(0)); | 2588 const auto Var = llvm::dyn_cast<Variable>(this->getSrc(0)); |
2598 if (Var && Var->hasReg()) { | 2589 if (Var && Var->hasReg()) { |
2599 // This is a physical xmm register, so we need to spill it to a | 2590 // This is a physical xmm register, so we need to spill it to a temporary |
2600 // temporary stack slot. | 2591 // stack slot. |
2601 Str << "\tsubl\t$" << Width << ", %esp" | 2592 Str << "\tsubl\t$" << Width << ", %esp" |
2602 << "\n"; | 2593 << "\n"; |
2603 Str << "\tmov" | 2594 Str << "\tmov" |
2604 << InstX86Base<Machine>::Traits::TypeAttributes[Ty].SdSsString << "\t"; | 2595 << InstX86Base<Machine>::Traits::TypeAttributes[Ty].SdSsString << "\t"; |
2605 Var->emit(Func); | 2596 Var->emit(Func); |
2606 Str << ", (%esp)\n"; | 2597 Str << ", (%esp)\n"; |
2607 Str << "\tfld" << this->getFldString(Ty) << "\t" | 2598 Str << "\tfld" << this->getFldString(Ty) << "\t" |
2608 << "(%esp)\n"; | 2599 << "(%esp)\n"; |
2609 Str << "\taddl\t$" << Width << ", %esp"; | 2600 Str << "\taddl\t$" << Width << ", %esp"; |
2610 return; | 2601 return; |
2611 } | 2602 } |
2612 Str << "\tfld" << this->getFldString(Ty) << "\t"; | 2603 Str << "\tfld" << this->getFldString(Ty) << "\t"; |
2613 this->getSrc(0)->emit(Func); | 2604 this->getSrc(0)->emit(Func); |
2614 } | 2605 } |
2615 | 2606 |
2616 template <class Machine> | 2607 template <class Machine> |
2617 void InstX86Fld<Machine>::emitIAS(const Cfg *Func) const { | 2608 void InstX86Fld<Machine>::emitIAS(const Cfg *Func) const { |
2618 typename InstX86Base<Machine>::Traits::Assembler *Asm = | 2609 typename InstX86Base<Machine>::Traits::Assembler *Asm = |
2619 Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>(); | 2610 Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>(); |
2620 assert(this->getSrcSize() == 1); | 2611 assert(this->getSrcSize() == 1); |
2621 const Operand *Src = this->getSrc(0); | 2612 const Operand *Src = this->getSrc(0); |
2622 Type Ty = Src->getType(); | 2613 Type Ty = Src->getType(); |
2623 if (const auto Var = llvm::dyn_cast<Variable>(Src)) { | 2614 if (const auto Var = llvm::dyn_cast<Variable>(Src)) { |
2624 if (Var->hasReg()) { | 2615 if (Var->hasReg()) { |
2625 // This is a physical xmm register, so we need to spill it to a | 2616 // This is a physical xmm register, so we need to spill it to a temporary |
2626 // temporary stack slot. | 2617 // stack slot. |
2627 Immediate Width(typeWidthInBytes(Ty)); | 2618 Immediate Width(typeWidthInBytes(Ty)); |
2628 Asm->sub(IceType_i32, | 2619 Asm->sub(IceType_i32, |
2629 InstX86Base<Machine>::Traits::RegisterSet::Encoded_Reg_esp, | 2620 InstX86Base<Machine>::Traits::RegisterSet::Encoded_Reg_esp, |
2630 Width); | 2621 Width); |
2631 typename InstX86Base<Machine>::Traits::Address StackSlot = | 2622 typename InstX86Base<Machine>::Traits::Address StackSlot = |
2632 typename InstX86Base<Machine>::Traits::Address( | 2623 typename InstX86Base<Machine>::Traits::Address( |
2633 InstX86Base<Machine>::Traits::RegisterSet::Encoded_Reg_esp, 0); | 2624 InstX86Base<Machine>::Traits::RegisterSet::Encoded_Reg_esp, 0); |
2634 Asm->movss(Ty, StackSlot, | 2625 Asm->movss(Ty, StackSlot, |
2635 InstX86Base<Machine>::Traits::RegisterSet::getEncodedXmm( | 2626 InstX86Base<Machine>::Traits::RegisterSet::getEncodedXmm( |
2636 Var->getRegNum())); | 2627 Var->getRegNum())); |
(...skipping 28 matching lines...) Expand all Loading... |
2665 this->dumpSources(Func); | 2656 this->dumpSources(Func); |
2666 } | 2657 } |
2667 | 2658 |
2668 template <class Machine> | 2659 template <class Machine> |
2669 void InstX86Fstp<Machine>::emit(const Cfg *Func) const { | 2660 void InstX86Fstp<Machine>::emit(const Cfg *Func) const { |
2670 if (!BuildDefs::dump()) | 2661 if (!BuildDefs::dump()) |
2671 return; | 2662 return; |
2672 Ostream &Str = Func->getContext()->getStrEmit(); | 2663 Ostream &Str = Func->getContext()->getStrEmit(); |
2673 assert(this->getSrcSize() == 0); | 2664 assert(this->getSrcSize() == 0); |
2674 // TODO(jvoung,stichnot): Utilize this by setting Dest to nullptr to | 2665 // TODO(jvoung,stichnot): Utilize this by setting Dest to nullptr to |
2675 // "partially" delete the fstp if the Dest is unused. | 2666 // "partially" delete the fstp if the Dest is unused. Even if Dest is unused, |
2676 // Even if Dest is unused, the fstp should be kept for the SideEffects | 2667 // the fstp should be kept for the SideEffects of popping the stack. |
2677 // of popping the stack. | |
2678 if (!this->getDest()) { | 2668 if (!this->getDest()) { |
2679 Str << "\tfstp\tst(0)"; | 2669 Str << "\tfstp\tst(0)"; |
2680 return; | 2670 return; |
2681 } | 2671 } |
2682 Type Ty = this->getDest()->getType(); | 2672 Type Ty = this->getDest()->getType(); |
2683 size_t Width = typeWidthInBytes(Ty); | 2673 size_t Width = typeWidthInBytes(Ty); |
2684 if (!this->getDest()->hasReg()) { | 2674 if (!this->getDest()->hasReg()) { |
2685 Str << "\tfstp" << this->getFldString(Ty) << "\t"; | 2675 Str << "\tfstp" << this->getFldString(Ty) << "\t"; |
2686 this->getDest()->emit(Func); | 2676 this->getDest()->emit(Func); |
2687 return; | 2677 return; |
2688 } | 2678 } |
2689 // Dest is a physical (xmm) register, so st(0) needs to go through | 2679 // Dest is a physical (xmm) register, so st(0) needs to go through memory. |
2690 // memory. Hack this by creating a temporary stack slot, spilling | 2680 // Hack this by creating a temporary stack slot, spilling st(0) there, |
2691 // st(0) there, loading it into the xmm register, and deallocating | 2681 // loading it into the xmm register, and deallocating the stack slot. |
2692 // the stack slot. | |
2693 Str << "\tsubl\t$" << Width << ", %esp\n"; | 2682 Str << "\tsubl\t$" << Width << ", %esp\n"; |
2694 Str << "\tfstp" << this->getFldString(Ty) << "\t" | 2683 Str << "\tfstp" << this->getFldString(Ty) << "\t" |
2695 << "(%esp)\n"; | 2684 << "(%esp)\n"; |
2696 Str << "\tmov" << InstX86Base<Machine>::Traits::TypeAttributes[Ty].SdSsString | 2685 Str << "\tmov" << InstX86Base<Machine>::Traits::TypeAttributes[Ty].SdSsString |
2697 << "\t" | 2686 << "\t" |
2698 << "(%esp), "; | 2687 << "(%esp), "; |
2699 this->getDest()->emit(Func); | 2688 this->getDest()->emit(Func); |
2700 Str << "\n"; | 2689 Str << "\n"; |
2701 Str << "\taddl\t$" << Width << ", %esp"; | 2690 Str << "\taddl\t$" << Width << ", %esp"; |
2702 } | 2691 } |
2703 | 2692 |
2704 template <class Machine> | 2693 template <class Machine> |
2705 void InstX86Fstp<Machine>::emitIAS(const Cfg *Func) const { | 2694 void InstX86Fstp<Machine>::emitIAS(const Cfg *Func) const { |
2706 typename InstX86Base<Machine>::Traits::Assembler *Asm = | 2695 typename InstX86Base<Machine>::Traits::Assembler *Asm = |
2707 Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>(); | 2696 Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>(); |
2708 assert(this->getSrcSize() == 0); | 2697 assert(this->getSrcSize() == 0); |
2709 const Variable *Dest = this->getDest(); | 2698 const Variable *Dest = this->getDest(); |
2710 // TODO(jvoung,stichnot): Utilize this by setting Dest to nullptr to | 2699 // TODO(jvoung,stichnot): Utilize this by setting Dest to nullptr to |
2711 // "partially" delete the fstp if the Dest is unused. | 2700 // "partially" delete the fstp if the Dest is unused. Even if Dest is unused, |
2712 // Even if Dest is unused, the fstp should be kept for the SideEffects | 2701 // the fstp should be kept for the SideEffects of popping the stack. |
2713 // of popping the stack. | |
2714 if (!Dest) { | 2702 if (!Dest) { |
2715 Asm->fstp(InstX86Base<Machine>::Traits::RegisterSet::getEncodedSTReg(0)); | 2703 Asm->fstp(InstX86Base<Machine>::Traits::RegisterSet::getEncodedSTReg(0)); |
2716 return; | 2704 return; |
2717 } | 2705 } |
2718 Type Ty = Dest->getType(); | 2706 Type Ty = Dest->getType(); |
2719 if (!Dest->hasReg()) { | 2707 if (!Dest->hasReg()) { |
2720 typename InstX86Base<Machine>::Traits::Address StackAddr( | 2708 typename InstX86Base<Machine>::Traits::Address StackAddr( |
2721 static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>( | 2709 static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>( |
2722 Func->getTarget()) | 2710 Func->getTarget()) |
2723 ->stackVarToAsmOperand(Dest)); | 2711 ->stackVarToAsmOperand(Dest)); |
2724 Asm->fstp(Ty, StackAddr); | 2712 Asm->fstp(Ty, StackAddr); |
2725 } else { | 2713 } else { |
2726 // Dest is a physical (xmm) register, so st(0) needs to go through | 2714 // Dest is a physical (xmm) register, so st(0) needs to go through memory. |
2727 // memory. Hack this by creating a temporary stack slot, spilling | 2715 // Hack this by creating a temporary stack slot, spilling st(0) there, |
2728 // st(0) there, loading it into the xmm register, and deallocating | 2716 // loading it into the xmm register, and deallocating the stack slot. |
2729 // the stack slot. | |
2730 Immediate Width(typeWidthInBytes(Ty)); | 2717 Immediate Width(typeWidthInBytes(Ty)); |
2731 Asm->sub(IceType_i32, | 2718 Asm->sub(IceType_i32, |
2732 InstX86Base<Machine>::Traits::RegisterSet::Encoded_Reg_esp, Width); | 2719 InstX86Base<Machine>::Traits::RegisterSet::Encoded_Reg_esp, Width); |
2733 typename InstX86Base<Machine>::Traits::Address StackSlot = | 2720 typename InstX86Base<Machine>::Traits::Address StackSlot = |
2734 typename InstX86Base<Machine>::Traits::Address( | 2721 typename InstX86Base<Machine>::Traits::Address( |
2735 InstX86Base<Machine>::Traits::RegisterSet::Encoded_Reg_esp, 0); | 2722 InstX86Base<Machine>::Traits::RegisterSet::Encoded_Reg_esp, 0); |
2736 Asm->fstp(Ty, StackSlot); | 2723 Asm->fstp(Ty, StackSlot); |
2737 Asm->movss(Ty, InstX86Base<Machine>::Traits::RegisterSet::getEncodedXmm( | 2724 Asm->movss(Ty, InstX86Base<Machine>::Traits::RegisterSet::getEncodedXmm( |
2738 Dest->getRegNum()), | 2725 Dest->getRegNum()), |
2739 StackSlot); | 2726 StackSlot); |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2789 ->getInstructionSet() >= InstX86Base<Machine>::Traits::SSE4_1); | 2776 ->getInstructionSet() >= InstX86Base<Machine>::Traits::SSE4_1); |
2790 Str << "\t" << this->Opcode | 2777 Str << "\t" << this->Opcode |
2791 << InstX86Base<Machine>::Traits::TypeAttributes[this->getSrc(0) | 2778 << InstX86Base<Machine>::Traits::TypeAttributes[this->getSrc(0) |
2792 ->getType()] | 2779 ->getType()] |
2793 .PackString << "\t"; | 2780 .PackString << "\t"; |
2794 this->getSrc(1)->emit(Func); | 2781 this->getSrc(1)->emit(Func); |
2795 Str << ", "; | 2782 Str << ", "; |
2796 this->getSrc(0)->emit(Func); | 2783 this->getSrc(0)->emit(Func); |
2797 Str << ", "; | 2784 Str << ", "; |
2798 Variable *Dest = this->getDest(); | 2785 Variable *Dest = this->getDest(); |
2799 // pextrw must take a register dest. There is an SSE4.1 version that takes | 2786 // pextrw must take a register dest. There is an SSE4.1 version that takes a |
2800 // a memory dest, but we aren't using it. For uniformity, just restrict | 2787 // memory dest, but we aren't using it. For uniformity, just restrict them |
2801 // them all to have a register dest for now. | 2788 // all to have a register dest for now. |
2802 assert(Dest->hasReg()); | 2789 assert(Dest->hasReg()); |
2803 Dest->asType(IceType_i32)->emit(Func); | 2790 Dest->asType(IceType_i32)->emit(Func); |
2804 } | 2791 } |
2805 | 2792 |
2806 template <class Machine> | 2793 template <class Machine> |
2807 void InstX86Pextr<Machine>::emitIAS(const Cfg *Func) const { | 2794 void InstX86Pextr<Machine>::emitIAS(const Cfg *Func) const { |
2808 assert(this->getSrcSize() == 2); | 2795 assert(this->getSrcSize() == 2); |
2809 // pextrb and pextrd are SSE4.1 instructions. | 2796 // pextrb and pextrd are SSE4.1 instructions. |
2810 const Variable *Dest = this->getDest(); | 2797 const Variable *Dest = this->getDest(); |
2811 Type DispatchTy = Dest->getType(); | 2798 Type DispatchTy = Dest->getType(); |
2812 assert(DispatchTy == IceType_i16 || | 2799 assert(DispatchTy == IceType_i16 || |
2813 static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>( | 2800 static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>( |
2814 Func->getTarget()) | 2801 Func->getTarget()) |
2815 ->getInstructionSet() >= InstX86Base<Machine>::Traits::SSE4_1); | 2802 ->getInstructionSet() >= InstX86Base<Machine>::Traits::SSE4_1); |
2816 // pextrw must take a register dest. There is an SSE4.1 version that takes | 2803 // pextrw must take a register dest. There is an SSE4.1 version that takes a |
2817 // a memory dest, but we aren't using it. For uniformity, just restrict | 2804 // memory dest, but we aren't using it. For uniformity, just restrict them |
2818 // them all to have a register dest for now. | 2805 // all to have a register dest for now. |
2819 assert(Dest->hasReg()); | 2806 assert(Dest->hasReg()); |
2820 // pextrw's Src(0) must be a register (both SSE4.1 and SSE2). | 2807 // pextrw's Src(0) must be a register (both SSE4.1 and SSE2). |
2821 assert(llvm::cast<Variable>(this->getSrc(0))->hasReg()); | 2808 assert(llvm::cast<Variable>(this->getSrc(0))->hasReg()); |
2822 static const typename InstX86Base<Machine>::Traits::Assembler:: | 2809 static const typename InstX86Base<Machine>::Traits::Assembler:: |
2823 template ThreeOpImmEmitter< | 2810 template ThreeOpImmEmitter< |
2824 typename InstX86Base<Machine>::Traits::RegisterSet::GPRRegister, | 2811 typename InstX86Base<Machine>::Traits::RegisterSet::GPRRegister, |
2825 typename InstX86Base<Machine>::Traits::RegisterSet::XmmRegister> | 2812 typename InstX86Base<Machine>::Traits::RegisterSet::XmmRegister> |
2826 Emitter = {&InstX86Base<Machine>::Traits::Assembler::pextr, nullptr}; | 2813 Emitter = {&InstX86Base<Machine>::Traits::Assembler::pextr, nullptr}; |
2827 emitIASThreeOpImmOps< | 2814 emitIASThreeOpImmOps< |
2828 Machine, typename InstX86Base<Machine>::Traits::RegisterSet::GPRRegister, | 2815 Machine, typename InstX86Base<Machine>::Traits::RegisterSet::GPRRegister, |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2869 void InstX86Pinsr<Machine>::emitIAS(const Cfg *Func) const { | 2856 void InstX86Pinsr<Machine>::emitIAS(const Cfg *Func) const { |
2870 assert(this->getSrcSize() == 3); | 2857 assert(this->getSrcSize() == 3); |
2871 assert(this->getDest() == this->getSrc(0)); | 2858 assert(this->getDest() == this->getSrc(0)); |
2872 // pinsrb and pinsrd are SSE4.1 instructions. | 2859 // pinsrb and pinsrd are SSE4.1 instructions. |
2873 const Operand *Src0 = this->getSrc(1); | 2860 const Operand *Src0 = this->getSrc(1); |
2874 Type DispatchTy = Src0->getType(); | 2861 Type DispatchTy = Src0->getType(); |
2875 assert(DispatchTy == IceType_i16 || | 2862 assert(DispatchTy == IceType_i16 || |
2876 static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>( | 2863 static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>( |
2877 Func->getTarget()) | 2864 Func->getTarget()) |
2878 ->getInstructionSet() >= InstX86Base<Machine>::Traits::SSE4_1); | 2865 ->getInstructionSet() >= InstX86Base<Machine>::Traits::SSE4_1); |
2879 // If src1 is a register, it should always be r32 (this should fall out | 2866 // If src1 is a register, it should always be r32 (this should fall out from |
2880 // from the encodings for ByteRegs overlapping the encodings for r32), | 2867 // the encodings for ByteRegs overlapping the encodings for r32), but we have |
2881 // but we have to trust the regalloc to not choose "ah", where it | 2868 // to trust the regalloc to not choose "ah", where it doesn't overlap. |
2882 // doesn't overlap. | |
2883 static const typename InstX86Base<Machine>::Traits::Assembler:: | 2869 static const typename InstX86Base<Machine>::Traits::Assembler:: |
2884 template ThreeOpImmEmitter< | 2870 template ThreeOpImmEmitter< |
2885 typename InstX86Base<Machine>::Traits::RegisterSet::XmmRegister, | 2871 typename InstX86Base<Machine>::Traits::RegisterSet::XmmRegister, |
2886 typename InstX86Base<Machine>::Traits::RegisterSet::GPRRegister> | 2872 typename InstX86Base<Machine>::Traits::RegisterSet::GPRRegister> |
2887 Emitter = {&InstX86Base<Machine>::Traits::Assembler::pinsr, | 2873 Emitter = {&InstX86Base<Machine>::Traits::Assembler::pinsr, |
2888 &InstX86Base<Machine>::Traits::Assembler::pinsr}; | 2874 &InstX86Base<Machine>::Traits::Assembler::pinsr}; |
2889 emitIASThreeOpImmOps< | 2875 emitIASThreeOpImmOps< |
2890 Machine, typename InstX86Base<Machine>::Traits::RegisterSet::XmmRegister, | 2876 Machine, typename InstX86Base<Machine>::Traits::RegisterSet::XmmRegister, |
2891 typename InstX86Base<Machine>::Traits::RegisterSet::GPRRegister, | 2877 typename InstX86Base<Machine>::Traits::RegisterSet::GPRRegister, |
2892 InstX86Base<Machine>::Traits::RegisterSet::getEncodedXmm, | 2878 InstX86Base<Machine>::Traits::RegisterSet::getEncodedXmm, |
(...skipping 394 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3287 return; | 3273 return; |
3288 Ostream &Str = Func->getContext()->getStrDump(); | 3274 Ostream &Str = Func->getContext()->getStrDump(); |
3289 Str << "IACA_END"; | 3275 Str << "IACA_END"; |
3290 } | 3276 } |
3291 | 3277 |
3292 } // end of namespace X86Internal | 3278 } // end of namespace X86Internal |
3293 | 3279 |
3294 } // end of namespace Ice | 3280 } // end of namespace Ice |
3295 | 3281 |
3296 #endif // SUBZERO_SRC_ICEINSTX86BASEIMPL_H | 3282 #endif // SUBZERO_SRC_ICEINSTX86BASEIMPL_H |
OLD | NEW |