| //===- subzero/src/IceInstX8632.cpp - X86-32 instruction implementation ---===// | 
 | // | 
 | //                        The Subzero Code Generator | 
 | // | 
 | // This file is distributed under the University of Illinois Open Source | 
 | // License. See LICENSE.TXT for details. | 
 | // | 
 | //===----------------------------------------------------------------------===// | 
 | /// | 
 | /// \file | 
 | /// \brief Defines X8632 specific data related to X8632 Instructions and | 
 | /// Instruction traits. | 
 | /// | 
 | /// These are declared in the IceTargetLoweringX8632Traits.h header file. This | 
 | /// file also defines X8632 operand specific methods (dump and emit.) | 
 | /// | 
 | //===----------------------------------------------------------------------===// | 
 | #include "IceInstX8632.h" | 
 |  | 
 | #include "IceAssemblerX8632.h" | 
 | #include "IceCfg.h" | 
 | #include "IceCfgNode.h" | 
 | #include "IceConditionCodesX8632.h" | 
 | #include "IceInst.h" | 
 | #include "IceRegistersX8632.h" | 
 | #include "IceTargetLoweringX8632.h" | 
 | #include "IceOperand.h" | 
 |  | 
 | namespace Ice { | 
 |  | 
 | namespace X8632 { | 
 |  | 
 | const TargetX8632Traits::InstBrAttributesType | 
 |     TargetX8632Traits::InstBrAttributes[] = { | 
 | #define X(val, encode, opp, dump, emit)                                        \ | 
 |   { X8632::Traits::Cond::opp, dump, emit }                                     \ | 
 |   , | 
 |         ICEINSTX8632BR_TABLE | 
 | #undef X | 
 | }; | 
 |  | 
 | const TargetX8632Traits::InstCmppsAttributesType | 
 |     TargetX8632Traits::InstCmppsAttributes[] = { | 
 | #define X(val, emit)                                                           \ | 
 |   { emit }                                                                     \ | 
 |   , | 
 |         ICEINSTX8632CMPPS_TABLE | 
 | #undef X | 
 | }; | 
 |  | 
 | const TargetX8632Traits::TypeAttributesType | 
 |     TargetX8632Traits::TypeAttributes[] = { | 
 | #define X(tag, elty, cvt, sdss, pdps, spsd, int_, unpack, pack, width, fld)    \ | 
 |   { cvt, sdss, pdps, spsd, int_, unpack, pack, width, fld }                    \ | 
 |   , | 
 |         ICETYPEX8632_TABLE | 
 | #undef X | 
 | }; | 
 |  | 
 | const char *TargetX8632Traits::InstSegmentRegNames[] = { | 
 | #define X(val, name, prefix) name, | 
 |     SEG_REGX8632_TABLE | 
 | #undef X | 
 | }; | 
 |  | 
 | uint8_t TargetX8632Traits::InstSegmentPrefixes[] = { | 
 | #define X(val, name, prefix) prefix, | 
 |     SEG_REGX8632_TABLE | 
 | #undef X | 
 | }; | 
 |  | 
 | void TargetX8632Traits::X86Operand::dump(const Cfg *, Ostream &Str) const { | 
 |   if (BuildDefs::dump()) | 
 |     Str << "<OperandX8632>"; | 
 | } | 
 |  | 
 | TargetX8632Traits::X86OperandMem::X86OperandMem( | 
 |     Cfg *Func, Type Ty, Variable *Base, Constant *Offset, Variable *Index, | 
 |     uint16_t Shift, SegmentRegisters SegmentReg, bool IsRebased) | 
 |     : X86Operand(kMem, Ty), Base(Base), Offset(Offset), Index(Index), | 
 |       Shift(Shift), SegmentReg(SegmentReg), IsRebased(IsRebased) { | 
 |   assert(Shift <= 3); | 
 |   Vars = nullptr; | 
 |   NumVars = 0; | 
 |   if (Base) | 
 |     ++NumVars; | 
 |   if (Index) | 
 |     ++NumVars; | 
 |   if (NumVars) { | 
 |     Vars = Func->allocateArrayOf<Variable *>(NumVars); | 
 |     SizeT I = 0; | 
 |     if (Base) | 
 |       Vars[I++] = Base; | 
 |     if (Index) | 
 |       Vars[I++] = Index; | 
 |     assert(I == NumVars); | 
 |   } | 
 | } | 
 |  | 
 | namespace { | 
 |  | 
 | int32_t getRematerializableOffset(Variable *Var, | 
 |                                   const Ice::X8632::TargetX8632 *Target) { | 
 |   int32_t Disp = Var->getStackOffset(); | 
 |   const auto RegNum = Var->getRegNum(); | 
 |   if (RegNum == Target->getFrameReg()) { | 
 |     Disp += Target->getFrameFixedAllocaOffset(); | 
 |   } else if (RegNum != Target->getStackReg()) { | 
 |     llvm::report_fatal_error("Unexpected rematerializable register type"); | 
 |   } | 
 |   return Disp; | 
 | } | 
 |  | 
 | void validateMemOperandPIC(const TargetX8632Traits::X86OperandMem *Mem, | 
 |                            bool UseNonsfi) { | 
 |   if (!BuildDefs::asserts()) | 
 |     return; | 
 |   const bool HasCR = | 
 |       Mem->getOffset() && llvm::isa<ConstantRelocatable>(Mem->getOffset()); | 
 |   (void)HasCR; | 
 |   const bool IsRebased = Mem->getIsRebased(); | 
 |   (void)IsRebased; | 
 |   if (UseNonsfi) | 
 |     assert(HasCR == IsRebased); | 
 |   else | 
 |     assert(!IsRebased); | 
 | } | 
 |  | 
 | } // end of anonymous namespace | 
 |  | 
 | void TargetX8632Traits::X86OperandMem::emit(const Cfg *Func) const { | 
 |   if (!BuildDefs::dump()) | 
 |     return; | 
 |   const bool UseNonsfi = getFlags().getUseNonsfi(); | 
 |   validateMemOperandPIC(this, UseNonsfi); | 
 |   const auto *Target = | 
 |       static_cast<const ::Ice::X8632::TargetX8632 *>(Func->getTarget()); | 
 |   // If the base is rematerializable, we need to replace it with the correct | 
 |   // physical register (esp or ebp), and update the Offset. | 
 |   int32_t Disp = 0; | 
 |   if (getBase() && getBase()->isRematerializable()) { | 
 |     Disp += getRematerializableOffset(getBase(), Target); | 
 |   } | 
 |   // The index should never be rematerializable.  But if we ever allow it, then | 
 |   // we should make sure the rematerialization offset is shifted by the Shift | 
 |   // value. | 
 |   if (getIndex()) | 
 |     assert(!getIndex()->isRematerializable()); | 
 |   Ostream &Str = Func->getContext()->getStrEmit(); | 
 |   if (SegmentReg != DefaultSegment) { | 
 |     assert(SegmentReg >= 0 && SegmentReg < SegReg_NUM); | 
 |     Str << "%" << X8632::Traits::InstSegmentRegNames[SegmentReg] << ":"; | 
 |   } | 
 |   // Emit as Offset(Base,Index,1<<Shift). Offset is emitted without the leading | 
 |   // '$'. Omit the (Base,Index,1<<Shift) part if Base==nullptr. | 
 |   if (getOffset() == nullptr && Disp == 0) { | 
 |     // No offset, emit nothing. | 
 |   } else if (getOffset() == nullptr && Disp != 0) { | 
 |     Str << Disp; | 
 |   } else if (const auto *CI = llvm::dyn_cast<ConstantInteger32>(getOffset())) { | 
 |     if (getBase() == nullptr || CI->getValue() || Disp != 0) | 
 |       // Emit a non-zero offset without a leading '$'. | 
 |       Str << CI->getValue() + Disp; | 
 |   } else if (const auto *CR = | 
 |                  llvm::dyn_cast<ConstantRelocatable>(getOffset())) { | 
 |     // TODO(sehr): ConstantRelocatable still needs updating for | 
 |     // rematerializable base/index and Disp. | 
 |     assert(Disp == 0); | 
 |     CR->emitWithoutPrefix(Target, UseNonsfi ? "@GOTOFF" : ""); | 
 |   } else { | 
 |     llvm_unreachable("Invalid offset type for x86 mem operand"); | 
 |   } | 
 |  | 
 |   if (getBase() || getIndex()) { | 
 |     Str << "("; | 
 |     if (getBase()) | 
 |       getBase()->emit(Func); | 
 |     if (getIndex()) { | 
 |       Str << ","; | 
 |       getIndex()->emit(Func); | 
 |       if (getShift()) | 
 |         Str << "," << (1u << getShift()); | 
 |     } | 
 |     Str << ")"; | 
 |   } | 
 | } | 
 |  | 
 | void TargetX8632Traits::X86OperandMem::dump(const Cfg *Func, | 
 |                                             Ostream &Str) const { | 
 |   if (!BuildDefs::dump()) | 
 |     return; | 
 |   if (SegmentReg != DefaultSegment) { | 
 |     assert(SegmentReg >= 0 && SegmentReg < SegReg_NUM); | 
 |     Str << X8632::Traits::InstSegmentRegNames[SegmentReg] << ":"; | 
 |   } | 
 |   bool Dumped = false; | 
 |   Str << "["; | 
 |   int32_t Disp = 0; | 
 |   const auto *Target = | 
 |       static_cast<const ::Ice::X8632::TargetX8632 *>(Func->getTarget()); | 
 |   if (getBase() && getBase()->isRematerializable()) { | 
 |     Disp += getRematerializableOffset(getBase(), Target); | 
 |   } | 
 |   if (getBase()) { | 
 |     if (Func) | 
 |       getBase()->dump(Func); | 
 |     else | 
 |       getBase()->dump(Str); | 
 |     Dumped = true; | 
 |   } | 
 |   if (getIndex()) { | 
 |     assert(!getIndex()->isRematerializable()); | 
 |     if (getBase()) | 
 |       Str << "+"; | 
 |     if (getShift() > 0) | 
 |       Str << (1u << getShift()) << "*"; | 
 |     if (Func) | 
 |       getIndex()->dump(Func); | 
 |     else | 
 |       getIndex()->dump(Str); | 
 |     Dumped = true; | 
 |   } | 
 |   if (Disp) { | 
 |     if (Disp > 0) | 
 |       Str << "+"; | 
 |     Str << Disp; | 
 |     Dumped = true; | 
 |   } | 
 |   // Pretty-print the Offset. | 
 |   bool OffsetIsZero = false; | 
 |   bool OffsetIsNegative = false; | 
 |   if (getOffset() == nullptr) { | 
 |     OffsetIsZero = true; | 
 |   } else if (const auto *CI = llvm::dyn_cast<ConstantInteger32>(getOffset())) { | 
 |     OffsetIsZero = (CI->getValue() == 0); | 
 |     OffsetIsNegative = (static_cast<int32_t>(CI->getValue()) < 0); | 
 |   } else { | 
 |     assert(llvm::isa<ConstantRelocatable>(getOffset())); | 
 |   } | 
 |   if (Dumped) { | 
 |     if (!OffsetIsZero) {     // Suppress if Offset is known to be 0 | 
 |       if (!OffsetIsNegative) // Suppress if Offset is known to be negative | 
 |         Str << "+"; | 
 |       getOffset()->dump(Func, Str); | 
 |     } | 
 |   } else { | 
 |     // There is only the offset. | 
 |     getOffset()->dump(Func, Str); | 
 |   } | 
 |   Str << "]"; | 
 | } | 
 |  | 
 | void TargetX8632Traits::X86OperandMem::emitSegmentOverride( | 
 |     TargetX8632Traits::Assembler *Asm) const { | 
 |   if (SegmentReg != DefaultSegment) { | 
 |     assert(SegmentReg >= 0 && SegmentReg < SegReg_NUM); | 
 |     Asm->emitSegmentOverride(X8632::Traits::InstSegmentPrefixes[SegmentReg]); | 
 |   } | 
 | } | 
 |  | 
 | TargetX8632Traits::Address TargetX8632Traits::X86OperandMem::toAsmAddress( | 
 |     TargetX8632Traits::Assembler *Asm, | 
 |     const Ice::TargetLowering *TargetLowering, bool /*IsLeaAddr*/) const { | 
 |   const auto *Target = | 
 |       static_cast<const ::Ice::X8632::TargetX8632 *>(TargetLowering); | 
 |   const bool UseNonsfi = getFlags().getUseNonsfi(); | 
 |   validateMemOperandPIC(this, UseNonsfi); | 
 |   int32_t Disp = 0; | 
 |   if (getBase() && getBase()->isRematerializable()) { | 
 |     Disp += getRematerializableOffset(getBase(), Target); | 
 |   } | 
 |   // The index should never be rematerializable.  But if we ever allow it, then | 
 |   // we should make sure the rematerialization offset is shifted by the Shift | 
 |   // value. | 
 |   if (getIndex()) | 
 |     assert(!getIndex()->isRematerializable()); | 
 |   AssemblerFixup *Fixup = nullptr; | 
 |   // Determine the offset (is it relocatable?) | 
 |   if (getOffset()) { | 
 |     if (const auto *CI = llvm::dyn_cast<ConstantInteger32>(getOffset())) { | 
 |       Disp += static_cast<int32_t>(CI->getValue()); | 
 |     } else if (const auto CR = | 
 |                    llvm::dyn_cast<ConstantRelocatable>(getOffset())) { | 
 |       Disp += CR->getOffset(); | 
 |       Fixup = Asm->createFixup(Target->getAbsFixup(), CR); | 
 |     } else { | 
 |       llvm_unreachable("Unexpected offset type"); | 
 |     } | 
 |   } | 
 |  | 
 |   // Now convert to the various possible forms. | 
 |   if (getBase() && getIndex()) { | 
 |     return X8632::Traits::Address(getEncodedGPR(getBase()->getRegNum()), | 
 |                                   getEncodedGPR(getIndex()->getRegNum()), | 
 |                                   X8632::Traits::ScaleFactor(getShift()), Disp, | 
 |                                   Fixup); | 
 |   } else if (getBase()) { | 
 |     return X8632::Traits::Address(getEncodedGPR(getBase()->getRegNum()), Disp, | 
 |                                   Fixup); | 
 |   } else if (getIndex()) { | 
 |     return X8632::Traits::Address(getEncodedGPR(getIndex()->getRegNum()), | 
 |                                   X8632::Traits::ScaleFactor(getShift()), Disp, | 
 |                                   Fixup); | 
 |   } else { | 
 |     return X8632::Traits::Address(Disp, Fixup); | 
 |   } | 
 | } | 
 |  | 
 | TargetX8632Traits::Address | 
 | TargetX8632Traits::VariableSplit::toAsmAddress(const Cfg *Func) const { | 
 |   assert(!Var->hasReg()); | 
 |   const ::Ice::TargetLowering *Target = Func->getTarget(); | 
 |   int32_t Offset = Var->getStackOffset() + getOffset(); | 
 |   return X8632::Traits::Address(getEncodedGPR(Target->getFrameOrStackReg()), | 
 |                                 Offset, AssemblerFixup::NoFixup); | 
 | } | 
 |  | 
 | void TargetX8632Traits::VariableSplit::emit(const Cfg *Func) const { | 
 |   if (!BuildDefs::dump()) | 
 |     return; | 
 |   Ostream &Str = Func->getContext()->getStrEmit(); | 
 |   assert(!Var->hasReg()); | 
 |   // The following is copied/adapted from TargetX8632::emitVariable(). | 
 |   const ::Ice::TargetLowering *Target = Func->getTarget(); | 
 |   constexpr Type Ty = IceType_i32; | 
 |   int32_t Offset = Var->getStackOffset() + getOffset(); | 
 |   if (Offset) | 
 |     Str << Offset; | 
 |   Str << "(%" << Target->getRegName(Target->getFrameOrStackReg(), Ty) << ")"; | 
 | } | 
 |  | 
 | void TargetX8632Traits::VariableSplit::dump(const Cfg *Func, | 
 |                                             Ostream &Str) const { | 
 |   if (!BuildDefs::dump()) | 
 |     return; | 
 |   switch (Part) { | 
 |   case Low: | 
 |     Str << "low"; | 
 |     break; | 
 |   case High: | 
 |     Str << "high"; | 
 |     break; | 
 |   } | 
 |   Str << "("; | 
 |   if (Func) | 
 |     Var->dump(Func); | 
 |   else | 
 |     Var->dump(Str); | 
 |   Str << ")"; | 
 | } | 
 |  | 
 | } // namespace X8632 | 
 | } // end of namespace Ice | 
 |  | 
 | X86INSTS_DEFINE_STATIC_DATA(X8632, X8632::Traits) |