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 
dump(const Cfg *,Ostream & Str) const72 void TargetX8632Traits::X86Operand::dump(const Cfg *, Ostream &Str) const {
73   if (BuildDefs::dump())
74     Str << "<OperandX8632>";
75 }
76 
X86OperandMem(Cfg * Func,Type Ty,Variable * Base,Constant * Offset,Variable * Index,uint16_t Shift,SegmentRegisters SegmentReg,bool IsRebased)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 
getRematerializableOffset(Variable * Var,const Ice::X8632::TargetX8632 * Target)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 
validateMemOperandPIC(const TargetX8632Traits::X86OperandMem * Mem,bool UseNonsfi)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 
emit(const Cfg * Func) const131 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 
dump(const Cfg * Func,Ostream & Str) const188 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 
emitSegmentOverride(TargetX8632Traits::Assembler * Asm) const253 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 
toAsmAddress(TargetX8632Traits::Assembler * Asm,const Ice::TargetLowering * TargetLowering,bool) const261 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
toAsmAddress(const Cfg * Func) const310 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 
emit(const Cfg * Func) const318 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 
dump(const Cfg * Func,Ostream & Str) const332 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