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 306 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
317 : InstX86Base(Func, InstX86Base::Pop, 0, Dest) { | 317 : InstX86Base(Func, InstX86Base::Pop, 0, Dest) { |
318 // A pop instruction affects the stack pointer and so it should not be | 318 // A pop instruction affects the stack pointer and so it should not be |
319 // allowed to be automatically dead-code eliminated. (The corresponding push | 319 // allowed to be automatically dead-code eliminated. (The corresponding push |
320 // instruction doesn't need this treatment because it has no dest variable | 320 // instruction doesn't need this treatment because it has no dest variable |
321 // and therefore won't be dead-code eliminated.) This is needed for | 321 // and therefore won't be dead-code eliminated.) This is needed for |
322 // late-stage liveness analysis (e.g. asm-verbose mode). | 322 // late-stage liveness analysis (e.g. asm-verbose mode). |
323 this->HasSideEffects = true; | 323 this->HasSideEffects = true; |
324 } | 324 } |
325 | 325 |
326 template <typename TraitsType> | 326 template <typename TraitsType> |
327 InstImpl<TraitsType>::InstX86Push::InstX86Push(Cfg *Func, Variable *Source) | 327 InstImpl<TraitsType>::InstX86Push::InstX86Push(Cfg *Func, Operand *Source) |
328 : InstX86Base(Func, InstX86Base::Push, 1, nullptr) { | 328 : InstX86Base(Func, InstX86Base::Push, 1, nullptr) { |
329 this->addSource(Source); | 329 this->addSource(Source); |
330 } | 330 } |
331 | 331 |
332 template <typename TraitsType> | 332 template <typename TraitsType> |
333 InstImpl<TraitsType>::InstX86Push::InstX86Push(Cfg *Func, InstX86Label *L) | |
334 : InstX86Base(Func, InstX86Base::Push, 0, nullptr), Label(L) {} | |
335 | |
336 template <typename TraitsType> | |
333 InstImpl<TraitsType>::InstX86Ret::InstX86Ret(Cfg *Func, Variable *Source) | 337 InstImpl<TraitsType>::InstX86Ret::InstX86Ret(Cfg *Func, Variable *Source) |
334 : InstX86Base(Func, InstX86Base::Ret, Source ? 1 : 0, nullptr) { | 338 : InstX86Base(Func, InstX86Base::Ret, Source ? 1 : 0, nullptr) { |
335 if (Source) | 339 if (Source) |
336 this->addSource(Source); | 340 this->addSource(Source); |
337 } | 341 } |
338 | 342 |
339 template <typename TraitsType> | 343 template <typename TraitsType> |
340 InstImpl<TraitsType>::InstX86Setcc::InstX86Setcc(Cfg *Func, Variable *Dest, | 344 InstImpl<TraitsType>::InstX86Setcc::InstX86Setcc(Cfg *Func, Variable *Dest, |
341 BrCond Cond) | 345 BrCond Cond) |
342 : InstX86Base(Func, InstX86Base::Setcc, 0, Dest), Condition(Cond) {} | 346 : InstX86Base(Func, InstX86Base::Setcc, 0, Dest), Condition(Cond) {} |
(...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
448 void InstImpl<TraitsType>::InstX86Label::emit(const Cfg *Func) const { | 452 void InstImpl<TraitsType>::InstX86Label::emit(const Cfg *Func) const { |
449 if (!BuildDefs::dump()) | 453 if (!BuildDefs::dump()) |
450 return; | 454 return; |
451 Ostream &Str = Func->getContext()->getStrEmit(); | 455 Ostream &Str = Func->getContext()->getStrEmit(); |
452 Str << getName(Func) << ":"; | 456 Str << getName(Func) << ":"; |
453 } | 457 } |
454 | 458 |
455 template <typename TraitsType> | 459 template <typename TraitsType> |
456 void InstImpl<TraitsType>::InstX86Label::emitIAS(const Cfg *Func) const { | 460 void InstImpl<TraitsType>::InstX86Label::emitIAS(const Cfg *Func) const { |
457 Assembler *Asm = Func->getAssembler<Assembler>(); | 461 Assembler *Asm = Func->getAssembler<Assembler>(); |
462 if (IsReturnLocation) { | |
463 Asm->addRelocationAtCurrentPosition(getName(Func)); | |
464 } | |
458 Asm->bindLocalLabel(Number); | 465 Asm->bindLocalLabel(Number); |
459 } | 466 } |
460 | 467 |
461 template <typename TraitsType> | 468 template <typename TraitsType> |
462 void InstImpl<TraitsType>::InstX86Label::dump(const Cfg *Func) const { | 469 void InstImpl<TraitsType>::InstX86Label::dump(const Cfg *Func) const { |
463 if (!BuildDefs::dump()) | 470 if (!BuildDefs::dump()) |
464 return; | 471 return; |
465 Ostream &Str = Func->getContext()->getStrDump(); | 472 Ostream &Str = Func->getContext()->getStrDump(); |
466 Str << getName(Func) << ":"; | 473 Str << getName(Func) << ":"; |
467 } | 474 } |
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
545 | 552 |
546 Str << " // (" << (isNear() ? "near" : "far") << " jump)"; | 553 Str << " // (" << (isNear() ? "near" : "far") << " jump)"; |
547 } | 554 } |
548 | 555 |
549 template <typename TraitsType> | 556 template <typename TraitsType> |
550 void InstImpl<TraitsType>::InstX86Jmp::emit(const Cfg *Func) const { | 557 void InstImpl<TraitsType>::InstX86Jmp::emit(const Cfg *Func) const { |
551 if (!BuildDefs::dump()) | 558 if (!BuildDefs::dump()) |
552 return; | 559 return; |
553 Ostream &Str = Func->getContext()->getStrEmit(); | 560 Ostream &Str = Func->getContext()->getStrEmit(); |
554 assert(this->getSrcSize() == 1); | 561 assert(this->getSrcSize() == 1); |
562 const Operand *Src = this->getSrc(0); | |
563 if (Traits::Is64Bit) { | |
564 if (const auto *CR = llvm::dyn_cast<ConstantRelocatable>(Src)) { | |
565 Str << "\t" | |
566 "jmp" | |
567 "\t" << CR->getName(); | |
568 return; | |
569 } | |
570 } | |
555 Str << "\t" | 571 Str << "\t" |
556 "jmp\t*"; | 572 "jmp" |
573 "\t*"; | |
557 getJmpTarget()->emit(Func); | 574 getJmpTarget()->emit(Func); |
558 } | 575 } |
559 | 576 |
560 template <typename TraitsType> | 577 template <typename TraitsType> |
561 void InstImpl<TraitsType>::InstX86Jmp::emitIAS(const Cfg *Func) const { | 578 void InstImpl<TraitsType>::InstX86Jmp::emitIAS(const Cfg *Func) const { |
562 // Note: Adapted (mostly copied) from | 579 // Note: Adapted (mostly copied) from |
563 // InstImpl<TraitsType>::InstX86Call::emitIAS(). | 580 // InstImpl<TraitsType>::InstX86Call::emitIAS(). |
564 Assembler *Asm = Func->getAssembler<Assembler>(); | 581 Assembler *Asm = Func->getAssembler<Assembler>(); |
565 Operand *Target = getJmpTarget(); | 582 Operand *Target = getJmpTarget(); |
566 if (const auto *Var = llvm::dyn_cast<Variable>(Target)) { | 583 if (const auto *Var = llvm::dyn_cast<Variable>(Target)) { |
(...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
700 } else if (const auto *Mem = llvm::dyn_cast<X86OperandMem>(Op)) { | 717 } else if (const auto *Mem = llvm::dyn_cast<X86OperandMem>(Op)) { |
701 Mem->emitSegmentOverride(Asm); | 718 Mem->emitSegmentOverride(Asm); |
702 (Asm->*(Emitter.Addr))(Ty, Mem->toAsmAddress(Asm, Target)); | 719 (Asm->*(Emitter.Addr))(Ty, Mem->toAsmAddress(Asm, Target)); |
703 } else { | 720 } else { |
704 llvm_unreachable("Unexpected operand type"); | 721 llvm_unreachable("Unexpected operand type"); |
705 } | 722 } |
706 } | 723 } |
707 | 724 |
708 template <typename TraitsType> | 725 template <typename TraitsType> |
709 template <bool VarCanBeByte, bool SrcCanBeByte> | 726 template <bool VarCanBeByte, bool SrcCanBeByte> |
710 void InstImpl<TraitsType>::emitIASRegOpTyGPR(const Cfg *Func, Type Ty, | 727 void InstImpl<TraitsType>::emitIASRegOpTyGPR(const Cfg *Func, bool IsLea, |
711 const Variable *Var, | 728 Type Ty, const Variable *Var, |
712 const Operand *Src, | 729 const Operand *Src, |
713 const GPREmitterRegOp &Emitter) { | 730 const GPREmitterRegOp &Emitter) { |
714 auto *Target = InstX86Base::getTarget(Func); | 731 auto *Target = InstX86Base::getTarget(Func); |
715 Assembler *Asm = Func->getAssembler<Assembler>(); | 732 Assembler *Asm = Func->getAssembler<Assembler>(); |
716 assert(Var->hasReg()); | 733 assert(Var->hasReg()); |
717 // We cheat a little and use GPRRegister even for byte operations. | 734 // We cheat a little and use GPRRegister even for byte operations. |
718 GPRRegister VarReg = VarCanBeByte ? Traits::getEncodedGPR(Var->getRegNum()) | 735 GPRRegister VarReg = VarCanBeByte ? Traits::getEncodedGPR(Var->getRegNum()) |
719 : Traits::getEncodedGPR(Var->getRegNum()); | 736 : Traits::getEncodedGPR(Var->getRegNum()); |
720 if (const auto *SrcVar = llvm::dyn_cast<Variable>(Src)) { | 737 if (const auto *SrcVar = llvm::dyn_cast<Variable>(Src)) { |
721 if (SrcVar->hasReg()) { | 738 if (SrcVar->hasReg()) { |
722 GPRRegister SrcReg = SrcCanBeByte | 739 GPRRegister SrcReg = SrcCanBeByte |
723 ? Traits::getEncodedGPR(SrcVar->getRegNum()) | 740 ? Traits::getEncodedGPR(SrcVar->getRegNum()) |
724 : Traits::getEncodedGPR(SrcVar->getRegNum()); | 741 : Traits::getEncodedGPR(SrcVar->getRegNum()); |
725 (Asm->*(Emitter.GPRGPR))(Ty, VarReg, SrcReg); | 742 (Asm->*(Emitter.GPRGPR))(Ty, VarReg, SrcReg); |
726 } else { | 743 } else { |
727 Address SrcStackAddr = Target->stackVarToAsmOperand(SrcVar); | 744 Address SrcStackAddr = Target->stackVarToAsmOperand(SrcVar); |
728 (Asm->*(Emitter.GPRAddr))(Ty, VarReg, SrcStackAddr); | 745 (Asm->*(Emitter.GPRAddr))(Ty, VarReg, SrcStackAddr); |
729 } | 746 } |
730 } else if (const auto *Mem = llvm::dyn_cast<X86OperandMem>(Src)) { | 747 } else if (const auto *Mem = llvm::dyn_cast<X86OperandMem>(Src)) { |
731 Mem->emitSegmentOverride(Asm); | 748 Mem->emitSegmentOverride(Asm); |
732 (Asm->*(Emitter.GPRAddr))(Ty, VarReg, Mem->toAsmAddress(Asm, Target)); | 749 (Asm->*(Emitter.GPRAddr))(Ty, VarReg, |
750 Mem->toAsmAddress(Asm, Target, IsLea)); | |
733 } else if (const auto *Imm = llvm::dyn_cast<ConstantInteger32>(Src)) { | 751 } else if (const auto *Imm = llvm::dyn_cast<ConstantInteger32>(Src)) { |
734 (Asm->*(Emitter.GPRImm))(Ty, VarReg, AssemblerImmediate(Imm->getValue())); | 752 (Asm->*(Emitter.GPRImm))(Ty, VarReg, AssemblerImmediate(Imm->getValue())); |
735 } else if (const auto *Reloc = llvm::dyn_cast<ConstantRelocatable>(Src)) { | 753 } else if (const auto *Reloc = llvm::dyn_cast<ConstantRelocatable>(Src)) { |
736 AssemblerFixup *Fixup = | 754 AssemblerFixup *Fixup = |
737 Asm->createFixup(Traits::TargetLowering::getAbsFixup(), Reloc); | 755 Asm->createFixup(Traits::TargetLowering::getAbsFixup(), Reloc); |
738 (Asm->*(Emitter.GPRImm))(Ty, VarReg, | 756 (Asm->*(Emitter.GPRImm))(Ty, VarReg, |
739 AssemblerImmediate(Reloc->getOffset(), Fixup)); | 757 AssemblerImmediate(Reloc->getOffset(), Fixup)); |
740 } else if (const auto *Split = llvm::dyn_cast<VariableSplit>(Src)) { | 758 } else if (const auto *Split = llvm::dyn_cast<VariableSplit>(Src)) { |
741 (Asm->*(Emitter.GPRAddr))(Ty, VarReg, Split->toAsmAddress(Func)); | 759 (Asm->*(Emitter.GPRAddr))(Ty, VarReg, Split->toAsmAddress(Func)); |
742 } else { | 760 } else { |
(...skipping 386 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1129 (void)Src0Var; | 1147 (void)Src0Var; |
1130 assert(Src0Var->getRegNum() == RegisterSet::Reg_al); | 1148 assert(Src0Var->getRegNum() == RegisterSet::Reg_al); |
1131 static const GPREmitterOneOp Emitter = {&Assembler::imul, &Assembler::imul}; | 1149 static const GPREmitterOneOp Emitter = {&Assembler::imul, &Assembler::imul}; |
1132 emitIASOpTyGPR(Func, Ty, this->getSrc(1), Emitter); | 1150 emitIASOpTyGPR(Func, Ty, this->getSrc(1), Emitter); |
1133 } else { | 1151 } else { |
1134 // The two-address version is used when multiplying by a non-constant | 1152 // The two-address version is used when multiplying by a non-constant |
1135 // or doing an 8-bit multiply. | 1153 // or doing an 8-bit multiply. |
1136 assert(Var == this->getSrc(0)); | 1154 assert(Var == this->getSrc(0)); |
1137 static const GPREmitterRegOp Emitter = {&Assembler::imul, &Assembler::imul, | 1155 static const GPREmitterRegOp Emitter = {&Assembler::imul, &Assembler::imul, |
1138 &Assembler::imul}; | 1156 &Assembler::imul}; |
1139 emitIASRegOpTyGPR(Func, Ty, Var, Src, Emitter); | 1157 constexpr bool NotLea = false; |
1158 emitIASRegOpTyGPR(Func, NotLea, Ty, Var, Src, Emitter); | |
1140 } | 1159 } |
1141 } | 1160 } |
1142 | 1161 |
1143 template <typename TraitsType> | 1162 template <typename TraitsType> |
1144 void InstImpl<TraitsType>::InstX86ImulImm::emit(const Cfg *Func) const { | 1163 void InstImpl<TraitsType>::InstX86ImulImm::emit(const Cfg *Func) const { |
1145 if (!BuildDefs::dump()) | 1164 if (!BuildDefs::dump()) |
1146 return; | 1165 return; |
1147 Ostream &Str = Func->getContext()->getStrEmit(); | 1166 Ostream &Str = Func->getContext()->getStrEmit(); |
1148 assert(this->getSrcSize() == 2); | 1167 assert(this->getSrcSize() == 2); |
1149 Variable *Dest = this->getDest(); | 1168 Variable *Dest = this->getDest(); |
(...skipping 538 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1688 assert(this->getSrcSize() == 2); | 1707 assert(this->getSrcSize() == 2); |
1689 const Operand *Src0 = this->getSrc(0); | 1708 const Operand *Src0 = this->getSrc(0); |
1690 const Operand *Src1 = this->getSrc(1); | 1709 const Operand *Src1 = this->getSrc(1); |
1691 Type Ty = Src0->getType(); | 1710 Type Ty = Src0->getType(); |
1692 static const GPREmitterRegOp RegEmitter = {&Assembler::cmp, &Assembler::cmp, | 1711 static const GPREmitterRegOp RegEmitter = {&Assembler::cmp, &Assembler::cmp, |
1693 &Assembler::cmp}; | 1712 &Assembler::cmp}; |
1694 static const GPREmitterAddrOp AddrEmitter = {&Assembler::cmp, | 1713 static const GPREmitterAddrOp AddrEmitter = {&Assembler::cmp, |
1695 &Assembler::cmp}; | 1714 &Assembler::cmp}; |
1696 if (const auto *SrcVar0 = llvm::dyn_cast<Variable>(Src0)) { | 1715 if (const auto *SrcVar0 = llvm::dyn_cast<Variable>(Src0)) { |
1697 if (SrcVar0->hasReg()) { | 1716 if (SrcVar0->hasReg()) { |
1698 emitIASRegOpTyGPR(Func, Ty, SrcVar0, Src1, RegEmitter); | 1717 constexpr bool NotLea = false; |
1718 emitIASRegOpTyGPR(Func, NotLea, Ty, SrcVar0, Src1, RegEmitter); | |
1699 return; | 1719 return; |
1700 } | 1720 } |
1701 } | 1721 } |
1702 emitIASAsAddrOpTyGPR(Func, Ty, Src0, Src1, AddrEmitter); | 1722 emitIASAsAddrOpTyGPR(Func, Ty, Src0, Src1, AddrEmitter); |
1703 } | 1723 } |
1704 | 1724 |
1705 template <typename TraitsType> | 1725 template <typename TraitsType> |
1706 void InstImpl<TraitsType>::InstX86Icmp::dump(const Cfg *Func) const { | 1726 void InstImpl<TraitsType>::InstX86Icmp::dump(const Cfg *Func) const { |
1707 if (!BuildDefs::dump()) | 1727 if (!BuildDefs::dump()) |
1708 return; | 1728 return; |
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1790 const Operand *Src0 = this->getSrc(0); | 1810 const Operand *Src0 = this->getSrc(0); |
1791 const Operand *Src1 = this->getSrc(1); | 1811 const Operand *Src1 = this->getSrc(1); |
1792 Type Ty = Src0->getType(); | 1812 Type Ty = Src0->getType(); |
1793 // The Reg/Addr form of test is not encodeable. | 1813 // The Reg/Addr form of test is not encodeable. |
1794 static const GPREmitterRegOp RegEmitter = {&Assembler::test, nullptr, | 1814 static const GPREmitterRegOp RegEmitter = {&Assembler::test, nullptr, |
1795 &Assembler::test}; | 1815 &Assembler::test}; |
1796 static const GPREmitterAddrOp AddrEmitter = {&Assembler::test, | 1816 static const GPREmitterAddrOp AddrEmitter = {&Assembler::test, |
1797 &Assembler::test}; | 1817 &Assembler::test}; |
1798 if (const auto *SrcVar0 = llvm::dyn_cast<Variable>(Src0)) { | 1818 if (const auto *SrcVar0 = llvm::dyn_cast<Variable>(Src0)) { |
1799 if (SrcVar0->hasReg()) { | 1819 if (SrcVar0->hasReg()) { |
1800 emitIASRegOpTyGPR(Func, Ty, SrcVar0, Src1, RegEmitter); | 1820 constexpr bool NotLea = false; |
1821 emitIASRegOpTyGPR(Func, NotLea, Ty, SrcVar0, Src1, RegEmitter); | |
1801 return; | 1822 return; |
1802 } | 1823 } |
1803 } | 1824 } |
1804 emitIASAsAddrOpTyGPR(Func, Ty, Src0, Src1, AddrEmitter); | 1825 emitIASAsAddrOpTyGPR(Func, Ty, Src0, Src1, AddrEmitter); |
1805 } | 1826 } |
1806 | 1827 |
1807 template <typename TraitsType> | 1828 template <typename TraitsType> |
1808 void InstImpl<TraitsType>::InstX86Test::dump(const Cfg *Func) const { | 1829 void InstImpl<TraitsType>::InstX86Test::dump(const Cfg *Func) const { |
1809 if (!BuildDefs::dump()) | 1830 if (!BuildDefs::dump()) |
1810 return; | 1831 return; |
(...skipping 162 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1973 } | 1994 } |
1974 | 1995 |
1975 template <typename TraitsType> | 1996 template <typename TraitsType> |
1976 void InstImpl<TraitsType>::InstX86Lea::emit(const Cfg *Func) const { | 1997 void InstImpl<TraitsType>::InstX86Lea::emit(const Cfg *Func) const { |
1977 if (!BuildDefs::dump()) | 1998 if (!BuildDefs::dump()) |
1978 return; | 1999 return; |
1979 Ostream &Str = Func->getContext()->getStrEmit(); | 2000 Ostream &Str = Func->getContext()->getStrEmit(); |
1980 assert(this->getSrcSize() == 1); | 2001 assert(this->getSrcSize() == 1); |
1981 assert(this->getDest()->hasReg()); | 2002 assert(this->getDest()->hasReg()); |
1982 Str << "\t" | 2003 Str << "\t" |
1983 "leal\t"; | 2004 "lea" << this->getWidthString(this->getDest()->getType()) << "\t"; |
1984 Operand *Src0 = this->getSrc(0); | 2005 Operand *Src0 = this->getSrc(0); |
1985 if (const auto *Src0Var = llvm::dyn_cast<Variable>(Src0)) { | 2006 if (const auto *Src0Var = llvm::dyn_cast<Variable>(Src0)) { |
1986 Type Ty = Src0Var->getType(); | 2007 Type Ty = Src0Var->getType(); |
1987 // lea on x86-32 doesn't accept mem128 operands, so cast VSrc0 to an | 2008 // lea on x86-32 doesn't accept mem128 operands, so cast VSrc0 to an |
1988 // acceptable type. | 2009 // acceptable type. |
1989 Src0Var->asType(isVectorType(Ty) ? IceType_i32 : Ty, Variable::NoRegister) | 2010 Src0Var->asType(isVectorType(Ty) ? IceType_i32 : Ty, Variable::NoRegister) |
1990 ->emit(Func); | 2011 ->emit(Func); |
1991 } else { | 2012 } else { |
1992 Src0->emit(Func); | 2013 Src0->emit(Func); |
1993 } | 2014 } |
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2073 if (Traits::Is64Bit && DestTy == IceType_i64) { | 2094 if (Traits::Is64Bit && DestTy == IceType_i64) { |
2074 if (const auto *C64 = llvm::dyn_cast<ConstantInteger64>(Src)) { | 2095 if (const auto *C64 = llvm::dyn_cast<ConstantInteger64>(Src)) { |
2075 Func->getAssembler<Assembler>()->movabs( | 2096 Func->getAssembler<Assembler>()->movabs( |
2076 Traits::getEncodedGPR(Dest->getRegNum()), C64->getValue()); | 2097 Traits::getEncodedGPR(Dest->getRegNum()), C64->getValue()); |
2077 return; | 2098 return; |
2078 } | 2099 } |
2079 } | 2100 } |
2080 if (isScalarIntegerType(SrcTy)) { | 2101 if (isScalarIntegerType(SrcTy)) { |
2081 SrcTy = DestTy; | 2102 SrcTy = DestTy; |
2082 } | 2103 } |
2083 emitIASRegOpTyGPR(Func, DestTy, Dest, Src, GPRRegEmitter); | 2104 constexpr bool NotLea = false; |
2105 emitIASRegOpTyGPR(Func, NotLea, DestTy, Dest, Src, GPRRegEmitter); | |
2084 return; | 2106 return; |
2085 } | 2107 } |
2086 } else { | 2108 } else { |
2087 // Dest must be Stack and Src *could* be a register. Use Src's type to | 2109 // Dest must be Stack and Src *could* be a register. Use Src's type to |
2088 // decide on the emitters. | 2110 // decide on the emitters. |
2089 Address StackAddr(Target->stackVarToAsmOperand(Dest)); | 2111 Address StackAddr(Target->stackVarToAsmOperand(Dest)); |
2090 if (isScalarFloatingType(SrcTy)) { | 2112 if (isScalarFloatingType(SrcTy)) { |
2091 // Src must be a register. | 2113 // Src must be a register. |
2092 const auto *SrcVar = llvm::cast<Variable>(Src); | 2114 const auto *SrcVar = llvm::cast<Variable>(Src); |
2093 assert(SrcVar->hasReg()); | 2115 assert(SrcVar->hasReg()); |
(...skipping 156 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2250 void InstImpl<TraitsType>::InstX86Movsx::emitIAS(const Cfg *Func) const { | 2272 void InstImpl<TraitsType>::InstX86Movsx::emitIAS(const Cfg *Func) const { |
2251 assert(this->getSrcSize() == 1); | 2273 assert(this->getSrcSize() == 1); |
2252 const Variable *Dest = this->getDest(); | 2274 const Variable *Dest = this->getDest(); |
2253 const Operand *Src = this->getSrc(0); | 2275 const Operand *Src = this->getSrc(0); |
2254 // Dest must be a > 8-bit register, but Src can be 8-bit. In practice we just | 2276 // Dest must be a > 8-bit register, but Src can be 8-bit. In practice we just |
2255 // use the full register for Dest to avoid having an OperandSizeOverride | 2277 // use the full register for Dest to avoid having an OperandSizeOverride |
2256 // prefix. It also allows us to only dispatch on SrcTy. | 2278 // prefix. It also allows us to only dispatch on SrcTy. |
2257 Type SrcTy = Src->getType(); | 2279 Type SrcTy = Src->getType(); |
2258 assert(typeWidthInBytes(Dest->getType()) > 1); | 2280 assert(typeWidthInBytes(Dest->getType()) > 1); |
2259 assert(typeWidthInBytes(Dest->getType()) > typeWidthInBytes(SrcTy)); | 2281 assert(typeWidthInBytes(Dest->getType()) > typeWidthInBytes(SrcTy)); |
2260 emitIASRegOpTyGPR<false, true>(Func, SrcTy, Dest, Src, this->Emitter); | 2282 constexpr bool NotLea = false; |
2283 emitIASRegOpTyGPR<false, true>(Func, NotLea, SrcTy, Dest, Src, this->Emitter); | |
2261 } | 2284 } |
2262 | 2285 |
2263 template <typename TraitsType> | 2286 template <typename TraitsType> |
2287 bool InstImpl<TraitsType>::InstX86Movzx::mayBeElided( | |
2288 const Variable *Dest, const Operand *SrcOpnd) const { | |
2289 assert(Traits::Is64Bit); | |
2290 const auto *Src = llvm::dyn_cast<Variable>(SrcOpnd); | |
2291 | |
2292 // Src is not a Variable, so it does not have a register. Movzx can't be | |
2293 // elided. | |
2294 if (Src == nullptr) | |
2295 return false; | |
2296 | |
2297 // Movzx to/from memory can't be elided. | |
2298 if (!Src->hasReg() || !Dest->hasReg()) | |
2299 return false; | |
2300 | |
2301 // Reg/reg move with different source and dest can't be elided. | |
2302 if (Traits::getEncodedGPR(Src->getRegNum()) != | |
2303 Traits::getEncodedGPR(Dest->getRegNum())) | |
2304 return false; | |
2305 | |
2306 // A must-keep movzx 32- to 64-bit is sometimes needed in x86-64 sandboxing. | |
2307 return !MustKeep; | |
2308 } | |
2309 | |
2310 template <typename TraitsType> | |
2264 void InstImpl<TraitsType>::InstX86Movzx::emit(const Cfg *Func) const { | 2311 void InstImpl<TraitsType>::InstX86Movzx::emit(const Cfg *Func) const { |
2265 if (!BuildDefs::dump()) | 2312 if (!BuildDefs::dump()) |
2266 return; | 2313 return; |
2267 if (Traits::Is64Bit) { | 2314 if (Traits::Is64Bit) { |
2268 // There's no movzx %eXX, %rXX. To zero extend 32- to 64-bits, we emit a | 2315 // There's no movzx %eXX, %rXX. To zero extend 32- to 64-bits, we emit a |
2269 // mov %eXX, %eXX. The processor will still do a movzx[bw]q. | 2316 // mov %eXX, %eXX. The processor will still do a movzx[bw]q. |
2270 assert(this->getSrcSize() == 1); | 2317 assert(this->getSrcSize() == 1); |
2271 const Operand *Src = this->getSrc(0); | 2318 const Operand *Src = this->getSrc(0); |
2272 const Variable *Dest = this->Dest; | 2319 const Variable *Dest = this->Dest; |
2273 if (Src->getType() == IceType_i32 && Dest->getType() == IceType_i64) { | 2320 if (Src->getType() == IceType_i32 && Dest->getType() == IceType_i64) { |
2274 Ostream &Str = Func->getContext()->getStrEmit(); | 2321 Ostream &Str = Func->getContext()->getStrEmit(); |
2275 Str << "\t" | 2322 if (mayBeElided(Dest, Src)) { |
2276 "mov" | 2323 Str << "\t/* elided movzx */"; |
2277 "\t"; | 2324 } else { |
2278 Src->emit(Func); | 2325 Str << "\t" |
2279 Str << ", "; | 2326 "mov" |
2280 Dest->asType(IceType_i32, | 2327 "\t"; |
2281 Traits::getGprForType(IceType_i32, Dest->getRegNum())) | 2328 Src->emit(Func); |
2282 ->emit(Func); | 2329 Str << ", "; |
2283 Str << " /* movzx */"; | 2330 Dest->asType(IceType_i32, |
2331 Traits::getGprForType(IceType_i32, Dest->getRegNum())) | |
2332 ->emit(Func); | |
2333 Str << " /* movzx */"; | |
2334 } | |
2284 return; | 2335 return; |
2285 } | 2336 } |
2286 } | 2337 } |
2287 InstX86BaseUnaryopGPR<InstX86Base::Movzx>::emit(Func); | 2338 InstX86BaseUnaryopGPR<InstX86Base::Movzx>::emit(Func); |
2288 } | 2339 } |
2289 | 2340 |
2290 template <typename TraitsType> | 2341 template <typename TraitsType> |
2291 void InstImpl<TraitsType>::InstX86Movzx::emitIAS(const Cfg *Func) const { | 2342 void InstImpl<TraitsType>::InstX86Movzx::emitIAS(const Cfg *Func) const { |
2292 assert(this->getSrcSize() == 1); | 2343 assert(this->getSrcSize() == 1); |
2293 const Variable *Dest = this->getDest(); | 2344 const Variable *Dest = this->getDest(); |
2294 const Operand *Src = this->getSrc(0); | 2345 const Operand *Src = this->getSrc(0); |
2295 Type SrcTy = Src->getType(); | 2346 Type SrcTy = Src->getType(); |
2296 assert(typeWidthInBytes(Dest->getType()) > 1); | 2347 assert(typeWidthInBytes(Dest->getType()) > 1); |
2297 assert(typeWidthInBytes(Dest->getType()) > typeWidthInBytes(SrcTy)); | 2348 assert(typeWidthInBytes(Dest->getType()) > typeWidthInBytes(SrcTy)); |
2298 emitIASRegOpTyGPR<false, true>(Func, SrcTy, Dest, Src, this->Emitter); | 2349 if (Traits::Is64Bit) { |
Jim Stichnoth
2016/01/14 00:09:52
I would just add this to the && conjunction below
John
2016/01/14 23:18:25
I thought about this, but I decided to go with thi
| |
2350 if (Src->getType() == IceType_i32 && Dest->getType() == IceType_i64 && | |
2351 mayBeElided(Dest, Src)) { | |
2352 return; | |
2353 } | |
2354 } | |
2355 constexpr bool NotLea = false; | |
2356 emitIASRegOpTyGPR<false, true>(Func, NotLea, SrcTy, Dest, Src, this->Emitter); | |
2299 } | 2357 } |
2300 | 2358 |
2301 template <typename TraitsType> | 2359 template <typename TraitsType> |
2302 void InstImpl<TraitsType>::InstX86Nop::emit(const Cfg *Func) const { | 2360 void InstImpl<TraitsType>::InstX86Nop::emit(const Cfg *Func) const { |
2303 if (!BuildDefs::dump()) | 2361 if (!BuildDefs::dump()) |
2304 return; | 2362 return; |
2305 Ostream &Str = Func->getContext()->getStrEmit(); | 2363 Ostream &Str = Func->getContext()->getStrEmit(); |
2306 // TODO: Emit the right code for each variant. | 2364 // TODO: Emit the right code for each variant. |
2307 Str << "\t" | 2365 Str << "\t" |
2308 "nop\t/* variant = " << Variant << " */"; | 2366 "nop\t/* variant = " << Variant << " */"; |
(...skipping 301 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2610 Ostream &Str = Func->getContext()->getStrDump(); | 2668 Ostream &Str = Func->getContext()->getStrDump(); |
2611 this->dumpDest(Func); | 2669 this->dumpDest(Func); |
2612 Str << " = pop." << this->getDest()->getType() << " "; | 2670 Str << " = pop." << this->getDest()->getType() << " "; |
2613 } | 2671 } |
2614 | 2672 |
2615 template <typename TraitsType> | 2673 template <typename TraitsType> |
2616 void InstImpl<TraitsType>::InstX86Push::emit(const Cfg *Func) const { | 2674 void InstImpl<TraitsType>::InstX86Push::emit(const Cfg *Func) const { |
2617 if (!BuildDefs::dump()) | 2675 if (!BuildDefs::dump()) |
2618 return; | 2676 return; |
2619 Ostream &Str = Func->getContext()->getStrEmit(); | 2677 Ostream &Str = Func->getContext()->getStrEmit(); |
2678 Str << "\t" | |
2679 "push" | |
2680 "\t"; | |
2620 assert(this->getSrcSize() == 1); | 2681 assert(this->getSrcSize() == 1); |
2621 // Push is currently only used for saving GPRs. | 2682 const Operand *Src = this->getSrc(0); |
2622 const auto *Var = llvm::cast<Variable>(this->getSrc(0)); | 2683 Src->emit(Func); |
2623 assert(Var->hasReg()); | |
2624 Str << "\t" | |
2625 "push\t"; | |
2626 Var->emit(Func); | |
2627 } | 2684 } |
2628 | 2685 |
2629 template <typename TraitsType> | 2686 template <typename TraitsType> |
2630 void InstImpl<TraitsType>::InstX86Push::emitIAS(const Cfg *Func) const { | 2687 void InstImpl<TraitsType>::InstX86Push::emitIAS(const Cfg *Func) const { |
2688 Assembler *Asm = Func->getAssembler<Assembler>(); | |
2689 | |
2631 assert(this->getSrcSize() == 1); | 2690 assert(this->getSrcSize() == 1); |
2632 // Push is currently only used for saving GPRs. | 2691 const Operand *Src = this->getSrc(0); |
2633 const auto *Var = llvm::cast<Variable>(this->getSrc(0)); | 2692 |
2634 assert(Var->hasReg()); | 2693 if (const auto *Var = llvm::dyn_cast<Variable>(Src)) { |
2635 Assembler *Asm = Func->getAssembler<Assembler>(); | 2694 Asm->pushl(Traits::getEncodedGPR(Var->getRegNum())); |
2636 Asm->pushl(Traits::getEncodedGPR(Var->getRegNum())); | 2695 } else if (const auto *Const32 = llvm::dyn_cast<ConstantInteger32>(Src)) { |
2696 Asm->pushl(AssemblerImmediate(Const32->getValue())); | |
2697 } else if (auto *CR = llvm::dyn_cast<ConstantRelocatable>(Src)) { | |
2698 Asm->pushl(CR); | |
2699 } else { | |
2700 llvm_unreachable("Unexpected operand type"); | |
2701 } | |
2637 } | 2702 } |
2638 | 2703 |
2639 template <typename TraitsType> | 2704 template <typename TraitsType> |
2640 void InstImpl<TraitsType>::InstX86Push::dump(const Cfg *Func) const { | 2705 void InstImpl<TraitsType>::InstX86Push::dump(const Cfg *Func) const { |
2641 if (!BuildDefs::dump()) | 2706 if (!BuildDefs::dump()) |
2642 return; | 2707 return; |
2643 Ostream &Str = Func->getContext()->getStrDump(); | 2708 Ostream &Str = Func->getContext()->getStrDump(); |
2644 Str << "push." << this->getSrc(0)->getType() << " "; | 2709 Str << "push." << this->getSrc(0)->getType() << " "; |
2645 this->dumpSources(Func); | 2710 this->dumpSources(Func); |
2646 } | 2711 } |
(...skipping 197 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2844 return; | 2909 return; |
2845 Ostream &Str = Func->getContext()->getStrDump(); | 2910 Ostream &Str = Func->getContext()->getStrDump(); |
2846 Str << "IACA_END"; | 2911 Str << "IACA_END"; |
2847 } | 2912 } |
2848 | 2913 |
2849 } // end of namespace X86NAMESPACE | 2914 } // end of namespace X86NAMESPACE |
2850 | 2915 |
2851 } // end of namespace Ice | 2916 } // end of namespace Ice |
2852 | 2917 |
2853 #endif // SUBZERO_SRC_ICEINSTX86BASEIMPL_H | 2918 #endif // SUBZERO_SRC_ICEINSTX86BASEIMPL_H |
OLD | NEW |