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