• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
dump(const Cfg *,Ostream & Str) const61 void TargetX8664Traits::X86Operand::dump(const Cfg *, Ostream &Str) const {
62   if (BuildDefs::dump())
63     Str << "<OperandX8664>";
64 }
65 
X86OperandMem(Cfg * Func,Type Ty,Variable * Base,Constant * Offset,Variable * Index,uint16_t Shift,bool IsRebased)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 {
getRematerializableOffset(Variable * Var,const::Ice::X8664::TargetX8664 * Target)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 
emit(const Cfg * Func) const105 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 
dump(const Cfg * Func,Ostream & Str) const188 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 
toAsmAddress(TargetX8664Traits::Assembler * Asm,const Ice::TargetLowering * TargetLowering,bool IsLeaAddr) const248 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
toAsmAddress(const Cfg * Func) const317 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 
emit(const Cfg * Func) const325 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 
dump(const Cfg * Func,Ostream & Str) const339 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