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