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