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