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