Home | History | Annotate | Download | only in src
      1 //===- subzero/src/IceInstX8664.cpp - X86-64 instruction implementation ---===//
      2 //
      3 //                        The Subzero Code Generator
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 ///
     10 /// \file
     11 /// \brief This file defines X8664 specific data related to X8664 Instructions
     12 /// and Instruction traits.
     13 ///
     14 /// These are declared in the IceTargetLoweringX8664Traits.h header file.
     15 ///
     16 /// This file also defines X8664 operand specific methods (dump and emit.)
     17 ///
     18 //===----------------------------------------------------------------------===//
     19 #include "IceInstX8664.h"
     20 
     21 #include "IceAssemblerX8664.h"
     22 #include "IceCfg.h"
     23 #include "IceCfgNode.h"
     24 #include "IceConditionCodesX8664.h"
     25 #include "IceInst.h"
     26 #include "IceRegistersX8664.h"
     27 #include "IceTargetLoweringX8664.h"
     28 #include "IceOperand.h"
     29 
     30 namespace Ice {
     31 
     32 namespace X8664 {
     33 
     34 const TargetX8664Traits::InstBrAttributesType
     35     TargetX8664Traits::InstBrAttributes[] = {
     36 #define X(val, encode, opp, dump, emit)                                        \
     37   { X8664::Traits::Cond::opp, dump, emit }                                     \
     38   ,
     39         ICEINSTX8664BR_TABLE
     40 #undef X
     41 };
     42 
     43 const TargetX8664Traits::InstCmppsAttributesType
     44     TargetX8664Traits::InstCmppsAttributes[] = {
     45 #define X(val, emit)                                                           \
     46   { emit }                                                                     \
     47   ,
     48         ICEINSTX8664CMPPS_TABLE
     49 #undef X
     50 };
     51 
     52 const TargetX8664Traits::TypeAttributesType
     53     TargetX8664Traits::TypeAttributes[] = {
     54 #define X(tag, elty, cvt, sdss, pdps, spsd, int_, unpack, pack, width, fld)    \
     55   { cvt, sdss, pdps, spsd, int_, unpack, pack, width, fld }                    \
     56   ,
     57         ICETYPEX8664_TABLE
     58 #undef X
     59 };
     60 
     61 void TargetX8664Traits::X86Operand::dump(const Cfg *, Ostream &Str) const {
     62   if (BuildDefs::dump())
     63     Str << "<OperandX8664>";
     64 }
     65 
     66 TargetX8664Traits::X86OperandMem::X86OperandMem(Cfg *Func, Type Ty,
     67                                                 Variable *Base,
     68                                                 Constant *Offset,
     69                                                 Variable *Index, uint16_t Shift,
     70                                                 bool IsRebased)
     71     : X86Operand(kMem, Ty), Base(Base), Offset(Offset), Index(Index),
     72       Shift(Shift), IsRebased(IsRebased) {
     73   assert(Shift <= 3);
     74   Vars = nullptr;
     75   NumVars = 0;
     76   if (Base)
     77     ++NumVars;
     78   if (Index)
     79     ++NumVars;
     80   if (NumVars) {
     81     Vars = Func->allocateArrayOf<Variable *>(NumVars);
     82     SizeT I = 0;
     83     if (Base)
     84       Vars[I++] = Base;
     85     if (Index)
     86       Vars[I++] = Index;
     87     assert(I == NumVars);
     88   }
     89 }
     90 
     91 namespace {
     92 int32_t getRematerializableOffset(Variable *Var,
     93                                   const ::Ice::X8664::TargetX8664 *Target) {
     94   int32_t Disp = Var->getStackOffset();
     95   const auto RegNum = Var->getRegNum();
     96   if (RegNum == Target->getFrameReg()) {
     97     Disp += Target->getFrameFixedAllocaOffset();
     98   } else if (RegNum != Target->getStackReg()) {
     99     llvm::report_fatal_error("Unexpected rematerializable register type");
    100   }
    101   return Disp;
    102 }
    103 } // end of anonymous namespace
    104 
    105 void TargetX8664Traits::X86OperandMem::emit(const Cfg *Func) const {
    106   if (!BuildDefs::dump())
    107     return;
    108   const auto *Target =
    109       static_cast<const ::Ice::X8664::TargetX8664 *>(Func->getTarget());
    110   // If the base is rematerializable, we need to replace it with the correct
    111   // physical register (stack or base pointer), and update the Offset.
    112   const bool NeedSandboxing = Target->needSandboxing();
    113   int32_t Disp = 0;
    114   if (getBase() && getBase()->isRematerializable()) {
    115     Disp += getRematerializableOffset(getBase(), Target);
    116   }
    117   // The index should never be rematerializable.  But if we ever allow it, then
    118   // we should make sure the rematerialization offset is shifted by the Shift
    119   // value.
    120   if (getIndex())
    121     assert(!getIndex()->isRematerializable());
    122   Ostream &Str = Func->getContext()->getStrEmit();
    123   // Emit as Offset(Base,Index,1<<Shift). Offset is emitted without the leading
    124   // '$'. Omit the (Base,Index,1<<Shift) part if Base==nullptr.
    125   if (getOffset() == nullptr && Disp == 0) {
    126     // No offset, emit nothing.
    127   } else if (getOffset() == nullptr && Disp != 0) {
    128     Str << Disp;
    129   } else if (const auto *CI = llvm::dyn_cast<ConstantInteger32>(Offset)) {
    130     if (Base == nullptr || CI->getValue() || Disp != 0)
    131       // Emit a non-zero offset without a leading '$'.
    132       Str << CI->getValue() + Disp;
    133   } else if (const auto *CR = llvm::dyn_cast<ConstantRelocatable>(Offset)) {
    134     // TODO(sehr): ConstantRelocatable still needs updating for
    135     // rematerializable base/index and Disp.
    136     assert(Disp == 0);
    137     const bool UseNonsfi = getFlags().getUseNonsfi();
    138     CR->emitWithoutPrefix(Target, UseNonsfi ? "@GOTOFF" : "");
    139     assert(!UseNonsfi);
    140     if (Base == nullptr && Index == nullptr) {
    141       // rip-relative addressing.
    142       if (NeedSandboxing) {
    143         Str << "(%rip)";
    144       } else {
    145         Str << "(%eip)";
    146       }
    147     }
    148   } else {
    149     llvm_unreachable("Invalid offset type for x86 mem operand");
    150   }
    151 
    152   if (Base == nullptr && Index == nullptr) {
    153     return;
    154   }
    155 
    156   Str << "(";
    157   if (Base != nullptr) {
    158     const Variable *B = Base;
    159     if (!NeedSandboxing) {
    160       // TODO(jpp): stop abusing the operand's type to identify LEAs.
    161       const Type MemType = getType();
    162       if (Base->getType() != IceType_i32 && MemType != IceType_void) {
    163         // X86-64 is ILP32, but %rsp and %rbp are accessed as 64-bit registers.
    164         // For filetype=asm, they need to be emitted as their 32-bit siblings.
    165         assert(Base->getType() == IceType_i64);
    166         assert(getEncodedGPR(Base->getRegNum()) == RegX8664::Encoded_Reg_rsp ||
    167                getEncodedGPR(Base->getRegNum()) == RegX8664::Encoded_Reg_rbp ||
    168                getType() == IceType_void);
    169         B = B->asType(Func, IceType_i32, X8664::Traits::getGprForType(
    170                                              IceType_i32, Base->getRegNum()));
    171       }
    172     }
    173 
    174     B->emit(Func);
    175   }
    176 
    177   if (Index != nullptr) {
    178     Variable *I = Index;
    179     Str << ",";
    180     I->emit(Func);
    181     if (Shift)
    182       Str << "," << (1u << Shift);
    183   }
    184 
    185   Str << ")";
    186 }
    187 
    188 void TargetX8664Traits::X86OperandMem::dump(const Cfg *Func,
    189                                             Ostream &Str) const {
    190   if (!BuildDefs::dump())
    191     return;
    192   bool Dumped = false;
    193   Str << "[";
    194   int32_t Disp = 0;
    195   const auto *Target =
    196       static_cast<const ::Ice::X8664::TargetX8664 *>(Func->getTarget());
    197   if (getBase() && getBase()->isRematerializable()) {
    198     Disp += getRematerializableOffset(getBase(), Target);
    199   }
    200   if (Base) {
    201     if (Func)
    202       Base->dump(Func);
    203     else
    204       Base->dump(Str);
    205     Dumped = true;
    206   }
    207   if (Index) {
    208     if (Base)
    209       Str << "+";
    210     if (Shift > 0)
    211       Str << (1u << Shift) << "*";
    212     if (Func)
    213       Index->dump(Func);
    214     else
    215       Index->dump(Str);
    216     Dumped = true;
    217   }
    218   if (Disp) {
    219     if (Disp > 0)
    220       Str << "+";
    221     Str << Disp;
    222     Dumped = true;
    223   }
    224   // Pretty-print the Offset.
    225   bool OffsetIsZero = false;
    226   bool OffsetIsNegative = false;
    227   if (!Offset) {
    228     OffsetIsZero = true;
    229   } else if (const auto *CI = llvm::dyn_cast<ConstantInteger32>(Offset)) {
    230     OffsetIsZero = (CI->getValue() == 0);
    231     OffsetIsNegative = (static_cast<int32_t>(CI->getValue()) < 0);
    232   } else {
    233     assert(llvm::isa<ConstantRelocatable>(Offset));
    234   }
    235   if (Dumped) {
    236     if (!OffsetIsZero) {     // Suppress if Offset is known to be 0
    237       if (!OffsetIsNegative) // Suppress if Offset is known to be negative
    238         Str << "+";
    239       Offset->dump(Func, Str);
    240     }
    241   } else {
    242     // There is only the offset.
    243     Offset->dump(Func, Str);
    244   }
    245   Str << "]";
    246 }
    247 
    248 TargetX8664Traits::Address TargetX8664Traits::X86OperandMem::toAsmAddress(
    249     TargetX8664Traits::Assembler *Asm,
    250     const Ice::TargetLowering *TargetLowering, bool IsLeaAddr) const {
    251   (void)IsLeaAddr;
    252   const auto *Target =
    253       static_cast<const ::Ice::X8664::TargetX8664 *>(TargetLowering);
    254   int32_t Disp = 0;
    255   if (getBase() && getBase()->isRematerializable()) {
    256     Disp += getRematerializableOffset(getBase(), Target);
    257   }
    258   if (getIndex() != nullptr) {
    259     assert(!getIndex()->isRematerializable());
    260   }
    261 
    262   AssemblerFixup *Fixup = nullptr;
    263   // Determine the offset (is it relocatable?)
    264   if (getOffset() != nullptr) {
    265     if (const auto *CI = llvm::dyn_cast<ConstantInteger32>(getOffset())) {
    266       Disp += static_cast<int32_t>(CI->getValue());
    267     } else if (const auto *CR =
    268                    llvm::dyn_cast<ConstantRelocatable>(getOffset())) {
    269       const auto FixupKind =
    270           (getBase() != nullptr || getIndex() != nullptr) ? FK_Abs : FK_PcRel;
    271       const RelocOffsetT DispAdjustment = FixupKind == FK_PcRel ? 4 : 0;
    272       Fixup = Asm->createFixup(FixupKind, CR);
    273       Fixup->set_addend(-DispAdjustment);
    274       Disp = CR->getOffset();
    275     } else {
    276       llvm_unreachable("Unexpected offset type");
    277     }
    278   }
    279 
    280   // Now convert to the various possible forms.
    281   if (getBase() && getIndex()) {
    282     const bool NeedSandboxing = Target->needSandboxing();
    283     (void)NeedSandboxing;
    284     assert(!NeedSandboxing || IsLeaAddr ||
    285            (getBase()->getRegNum() == Traits::RegisterSet::Reg_r15) ||
    286            (getBase()->getRegNum() == Traits::RegisterSet::Reg_rsp) ||
    287            (getBase()->getRegNum() == Traits::RegisterSet::Reg_rbp));
    288     return X8664::Traits::Address(getEncodedGPR(getBase()->getRegNum()),
    289                                   getEncodedGPR(getIndex()->getRegNum()),
    290                                   X8664::Traits::ScaleFactor(getShift()), Disp,
    291                                   Fixup);
    292   }
    293 
    294   if (getBase()) {
    295     return X8664::Traits::Address(getEncodedGPR(getBase()->getRegNum()), Disp,
    296                                   Fixup);
    297   }
    298 
    299   if (getIndex()) {
    300     return X8664::Traits::Address(getEncodedGPR(getIndex()->getRegNum()),
    301                                   X8664::Traits::ScaleFactor(getShift()), Disp,
    302                                   Fixup);
    303   }
    304 
    305   if (Fixup == nullptr) {
    306     // Absolute addresses are not allowed in Nexes -- they must be rebased
    307     // w.r.t. %r15.
    308     // Exception: LEAs are fine because they do not touch memory.
    309     assert(!Target->needSandboxing() || IsLeaAddr);
    310     return X8664::Traits::Address::Absolute(Disp);
    311   }
    312 
    313   return X8664::Traits::Address::RipRelative(Disp, Fixup);
    314 }
    315 
    316 TargetX8664Traits::Address
    317 TargetX8664Traits::VariableSplit::toAsmAddress(const Cfg *Func) const {
    318   assert(!Var->hasReg());
    319   const ::Ice::TargetLowering *Target = Func->getTarget();
    320   int32_t Offset = Var->getStackOffset() + getOffset();
    321   return X8664::Traits::Address(getEncodedGPR(Target->getFrameOrStackReg()),
    322                                 Offset, AssemblerFixup::NoFixup);
    323 }
    324 
    325 void TargetX8664Traits::VariableSplit::emit(const Cfg *Func) const {
    326   if (!BuildDefs::dump())
    327     return;
    328   Ostream &Str = Func->getContext()->getStrEmit();
    329   assert(!Var->hasReg());
    330   // The following is copied/adapted from TargetX8664::emitVariable().
    331   const ::Ice::TargetLowering *Target = Func->getTarget();
    332   constexpr Type Ty = IceType_i32;
    333   int32_t Offset = Var->getStackOffset() + getOffset();
    334   if (Offset)
    335     Str << Offset;
    336   Str << "(%" << Target->getRegName(Target->getFrameOrStackReg(), Ty) << ")";
    337 }
    338 
    339 void TargetX8664Traits::VariableSplit::dump(const Cfg *Func,
    340                                             Ostream &Str) const {
    341   if (!BuildDefs::dump())
    342     return;
    343   switch (Part) {
    344   case Low:
    345     Str << "low";
    346     break;
    347   case High:
    348     Str << "high";
    349     break;
    350   }
    351   Str << "(";
    352   if (Func)
    353     Var->dump(Func);
    354   else
    355     Var->dump(Str);
    356   Str << ")";
    357 }
    358 
    359 } // namespace X8664
    360 } // end of namespace Ice
    361 
    362 X86INSTS_DEFINE_STATIC_DATA(X8664, X8664::Traits)
    363