| //===- 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, elementty, cvt, sdss, pdps, spsd, pack, unpack, width, fld) \ |
| { cvt, sdss, pdps, spsd, pack, unpack, 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) |