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