blob: d44f35dc59e4a84cf39460d00f25d0657e1a29f0 [file] [log] [blame]
John Porto453660f2015-07-31 14:52:52 -07001//===- 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
Jim Stichnoth92a6e5b2015-12-02 16:52:44 -080011/// \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.
John Porto453660f2015-07-31 14:52:52 -070015///
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 "IceRegistersX8664.h"
27#include "IceTargetLoweringX8664.h"
28#include "IceOperand.h"
29
30namespace Ice {
31
John Porto4a566862016-01-04 09:33:41 -080032namespace X8664 {
John Porto453660f2015-07-31 14:52:52 -070033
John Porto4a566862016-01-04 09:33:41 -080034const TargetX8664Traits::InstBrAttributesType
35 TargetX8664Traits::InstBrAttributes[] = {
Jim Stichnoth5bff61c2015-10-28 09:26:00 -070036#define X(val, encode, opp, dump, emit) \
John Porto453660f2015-07-31 14:52:52 -070037 { X8664::Traits::Cond::opp, dump, emit } \
38 ,
39 ICEINSTX8664BR_TABLE
40#undef X
41};
42
John Porto4a566862016-01-04 09:33:41 -080043const TargetX8664Traits::InstCmppsAttributesType
44 TargetX8664Traits::InstCmppsAttributes[] = {
Jim Stichnoth5bff61c2015-10-28 09:26:00 -070045#define X(val, emit) \
John Porto453660f2015-07-31 14:52:52 -070046 { emit } \
47 ,
48 ICEINSTX8664CMPPS_TABLE
49#undef X
50};
51
John Porto4a566862016-01-04 09:33:41 -080052const TargetX8664Traits::TypeAttributesType
53 TargetX8664Traits::TypeAttributes[] = {
Nicolas Capens7638e272016-10-06 11:33:55 -040054#define X(tag, elty, cvt, sdss, pdps, spsd, int_, unpack, pack, width, fld) \
55 { cvt, sdss, pdps, spsd, int_, unpack, pack, width, fld } \
John Porto453660f2015-07-31 14:52:52 -070056 ,
57 ICETYPEX8664_TABLE
58#undef X
59};
60
John Porto4a566862016-01-04 09:33:41 -080061void TargetX8664Traits::X86Operand::dump(const Cfg *, Ostream &Str) const {
John Porto453660f2015-07-31 14:52:52 -070062 if (BuildDefs::dump())
63 Str << "<OperandX8664>";
64}
65
John Porto4a566862016-01-04 09:33:41 -080066TargetX8664Traits::X86OperandMem::X86OperandMem(Cfg *Func, Type Ty,
67 Variable *Base,
68 Constant *Offset,
Jim Stichnoth8ff4b282016-01-04 15:39:06 -080069 Variable *Index, uint16_t Shift,
John Porto56958cb2016-01-14 09:18:18 -080070 bool IsRebased)
John Porto453660f2015-07-31 14:52:52 -070071 : X86Operand(kMem, Ty), Base(Base), Offset(Offset), Index(Index),
John Porto56958cb2016-01-14 09:18:18 -080072 Shift(Shift), IsRebased(IsRebased) {
John Porto453660f2015-07-31 14:52:52 -070073 assert(Shift <= 3);
74 Vars = nullptr;
75 NumVars = 0;
76 if (Base)
77 ++NumVars;
78 if (Index)
79 ++NumVars;
80 if (NumVars) {
81 Vars = Func->allocateArrayOf<Variable *>(NumVars);
82 SizeT I = 0;
83 if (Base)
84 Vars[I++] = Base;
85 if (Index)
86 Vars[I++] = Index;
87 assert(I == NumVars);
88 }
89}
90
John Porto3c275ce2015-12-22 08:14:00 -080091namespace {
Jim Stichnoth8aa39662016-02-10 11:20:30 -080092int32_t getRematerializableOffset(Variable *Var,
93 const ::Ice::X8664::TargetX8664 *Target) {
John Porto3c275ce2015-12-22 08:14:00 -080094 int32_t Disp = Var->getStackOffset();
Jim Stichnoth8aa39662016-02-10 11:20:30 -080095 const auto RegNum = Var->getRegNum();
John Porto3c275ce2015-12-22 08:14:00 -080096 if (RegNum == Target->getFrameReg()) {
97 Disp += Target->getFrameFixedAllocaOffset();
98 } else if (RegNum != Target->getStackReg()) {
99 llvm::report_fatal_error("Unexpected rematerializable register type");
100 }
101 return Disp;
102}
103} // end of anonymous namespace
104
John Porto4a566862016-01-04 09:33:41 -0800105void TargetX8664Traits::X86OperandMem::emit(const Cfg *Func) const {
John Porto453660f2015-07-31 14:52:52 -0700106 if (!BuildDefs::dump())
107 return;
John Porto4a566862016-01-04 09:33:41 -0800108 const auto *Target =
109 static_cast<const ::Ice::X8664::TargetX8664 *>(Func->getTarget());
John Porto3c275ce2015-12-22 08:14:00 -0800110 // If the base is rematerializable, we need to replace it with the correct
111 // physical register (stack or base pointer), and update the Offset.
John Porto56958cb2016-01-14 09:18:18 -0800112 const bool NeedSandboxing = Target->needSandboxing();
John Porto3c275ce2015-12-22 08:14:00 -0800113 int32_t Disp = 0;
114 if (getBase() && getBase()->isRematerializable()) {
115 Disp += getRematerializableOffset(getBase(), Target);
116 }
117 // The index should never be rematerializable. But if we ever allow it, then
118 // we should make sure the rematerialization offset is shifted by the Shift
119 // value.
120 if (getIndex())
121 assert(!getIndex()->isRematerializable());
John Porto453660f2015-07-31 14:52:52 -0700122 Ostream &Str = Func->getContext()->getStrEmit();
Andrew Scull57e12682015-09-16 11:30:19 -0700123 // Emit as Offset(Base,Index,1<<Shift). Offset is emitted without the leading
124 // '$'. Omit the (Base,Index,1<<Shift) part if Base==nullptr.
John Porto3c275ce2015-12-22 08:14:00 -0800125 if (getOffset() == nullptr && Disp == 0) {
John Porto453660f2015-07-31 14:52:52 -0700126 // No offset, emit nothing.
John Porto3c275ce2015-12-22 08:14:00 -0800127 } else if (getOffset() == nullptr && Disp != 0) {
128 Str << Disp;
Jim Stichnoth5bff61c2015-10-28 09:26:00 -0700129 } else if (const auto *CI = llvm::dyn_cast<ConstantInteger32>(Offset)) {
John Porto3c275ce2015-12-22 08:14:00 -0800130 if (Base == nullptr || CI->getValue() || Disp != 0)
John Porto453660f2015-07-31 14:52:52 -0700131 // Emit a non-zero offset without a leading '$'.
John Porto3c275ce2015-12-22 08:14:00 -0800132 Str << CI->getValue() + Disp;
Jim Stichnoth5bff61c2015-10-28 09:26:00 -0700133 } else if (const auto *CR = llvm::dyn_cast<ConstantRelocatable>(Offset)) {
John Porto3c275ce2015-12-22 08:14:00 -0800134 // TODO(sehr): ConstantRelocatable still needs updating for
135 // rematerializable base/index and Disp.
136 assert(Disp == 0);
Karl Schimpfd4699942016-04-02 09:55:31 -0700137 const bool UseNonsfi = getFlags().getUseNonsfi();
John Portod1bd1d32016-01-26 11:44:01 -0800138 CR->emitWithoutPrefix(Target, UseNonsfi ? "@GOTOFF" : "");
139 assert(!UseNonsfi);
140 if (Base == nullptr && Index == nullptr) {
Jim Stichnoth467ffe52016-03-29 15:01:06 -0700141 // rip-relative addressing.
142 if (NeedSandboxing) {
143 Str << "(%rip)";
144 } else {
145 Str << "(%eip)";
John Portod1bd1d32016-01-26 11:44:01 -0800146 }
147 }
John Porto453660f2015-07-31 14:52:52 -0700148 } else {
149 llvm_unreachable("Invalid offset type for x86 mem operand");
150 }
151
John Porto56958cb2016-01-14 09:18:18 -0800152 if (Base == nullptr && Index == nullptr) {
153 return;
154 }
155
156 Str << "(";
157 if (Base != nullptr) {
158 const Variable *B = Base;
159 if (!NeedSandboxing) {
160 // TODO(jpp): stop abusing the operand's type to identify LEAs.
161 const Type MemType = getType();
162 if (Base->getType() != IceType_i32 && MemType != IceType_void) {
John Porto008f4ce2015-12-24 13:22:18 -0800163 // X86-64 is ILP32, but %rsp and %rbp are accessed as 64-bit registers.
Manasij Mukherjeefe2caab2016-06-27 15:42:12 -0700164 // For filetype=asm, they need to be emitted as their 32-bit siblings.
John Porto008f4ce2015-12-24 13:22:18 -0800165 assert(Base->getType() == IceType_i64);
Manasij Mukherjeefe2caab2016-06-27 15:42:12 -0700166 assert(getEncodedGPR(Base->getRegNum()) == RegX8664::Encoded_Reg_rsp ||
167 getEncodedGPR(Base->getRegNum()) == RegX8664::Encoded_Reg_rbp ||
John Porto56958cb2016-01-14 09:18:18 -0800168 getType() == IceType_void);
Jim Stichnoth467ffe52016-03-29 15:01:06 -0700169 B = B->asType(Func, IceType_i32, X8664::Traits::getGprForType(
170 IceType_i32, Base->getRegNum()));
John Porto008f4ce2015-12-24 13:22:18 -0800171 }
John Porto008f4ce2015-12-24 13:22:18 -0800172 }
John Porto56958cb2016-01-14 09:18:18 -0800173
174 B->emit(Func);
John Porto453660f2015-07-31 14:52:52 -0700175 }
John Porto56958cb2016-01-14 09:18:18 -0800176
177 if (Index != nullptr) {
178 Variable *I = Index;
179 Str << ",";
180 I->emit(Func);
181 if (Shift)
182 Str << "," << (1u << Shift);
183 }
184
185 Str << ")";
John Porto453660f2015-07-31 14:52:52 -0700186}
187
John Porto4a566862016-01-04 09:33:41 -0800188void TargetX8664Traits::X86OperandMem::dump(const Cfg *Func,
189 Ostream &Str) const {
John Porto453660f2015-07-31 14:52:52 -0700190 if (!BuildDefs::dump())
191 return;
192 bool Dumped = false;
193 Str << "[";
John Porto3c275ce2015-12-22 08:14:00 -0800194 int32_t Disp = 0;
John Porto4a566862016-01-04 09:33:41 -0800195 const auto *Target =
196 static_cast<const ::Ice::X8664::TargetX8664 *>(Func->getTarget());
John Porto3c275ce2015-12-22 08:14:00 -0800197 if (getBase() && getBase()->isRematerializable()) {
198 Disp += getRematerializableOffset(getBase(), Target);
199 }
John Porto453660f2015-07-31 14:52:52 -0700200 if (Base) {
201 if (Func)
202 Base->dump(Func);
203 else
204 Base->dump(Str);
205 Dumped = true;
206 }
207 if (Index) {
David Sehraa0b1a12015-10-27 16:55:40 -0700208 if (Base)
209 Str << "+";
John Porto453660f2015-07-31 14:52:52 -0700210 if (Shift > 0)
211 Str << (1u << Shift) << "*";
212 if (Func)
213 Index->dump(Func);
214 else
215 Index->dump(Str);
216 Dumped = true;
217 }
John Porto3c275ce2015-12-22 08:14:00 -0800218 if (Disp) {
219 if (Disp > 0)
220 Str << "+";
221 Str << Disp;
222 Dumped = true;
223 }
John Porto453660f2015-07-31 14:52:52 -0700224 // Pretty-print the Offset.
225 bool OffsetIsZero = false;
226 bool OffsetIsNegative = false;
227 if (!Offset) {
228 OffsetIsZero = true;
Jim Stichnoth5bff61c2015-10-28 09:26:00 -0700229 } else if (const auto *CI = llvm::dyn_cast<ConstantInteger32>(Offset)) {
John Porto453660f2015-07-31 14:52:52 -0700230 OffsetIsZero = (CI->getValue() == 0);
231 OffsetIsNegative = (static_cast<int32_t>(CI->getValue()) < 0);
232 } else {
233 assert(llvm::isa<ConstantRelocatable>(Offset));
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 Offset->dump(Func, Str);
240 }
241 } else {
242 // There is only the offset.
243 Offset->dump(Func, Str);
244 }
245 Str << "]";
246}
247
John Porto4a566862016-01-04 09:33:41 -0800248TargetX8664Traits::Address TargetX8664Traits::X86OperandMem::toAsmAddress(
249 TargetX8664Traits::Assembler *Asm,
John Porto56958cb2016-01-14 09:18:18 -0800250 const Ice::TargetLowering *TargetLowering, bool IsLeaAddr) const {
251 (void)IsLeaAddr;
John Porto4a566862016-01-04 09:33:41 -0800252 const auto *Target =
253 static_cast<const ::Ice::X8664::TargetX8664 *>(TargetLowering);
John Porto3c275ce2015-12-22 08:14:00 -0800254 int32_t Disp = 0;
255 if (getBase() && getBase()->isRematerializable()) {
256 Disp += getRematerializableOffset(getBase(), Target);
257 }
John Porto56958cb2016-01-14 09:18:18 -0800258 if (getIndex() != nullptr) {
David Sehr4318a412015-11-11 15:01:55 -0800259 assert(!getIndex()->isRematerializable());
John Porto56958cb2016-01-14 09:18:18 -0800260 }
261
John Porto453660f2015-07-31 14:52:52 -0700262 AssemblerFixup *Fixup = nullptr;
263 // Determine the offset (is it relocatable?)
John Porto3c275ce2015-12-22 08:14:00 -0800264 if (getOffset() != nullptr) {
Jim Stichnoth5bff61c2015-10-28 09:26:00 -0700265 if (const auto *CI = llvm::dyn_cast<ConstantInteger32>(getOffset())) {
John Porto3c275ce2015-12-22 08:14:00 -0800266 Disp += static_cast<int32_t>(CI->getValue());
John Portod1bd1d32016-01-26 11:44:01 -0800267 } else if (const auto *CR =
John Porto453660f2015-07-31 14:52:52 -0700268 llvm::dyn_cast<ConstantRelocatable>(getOffset())) {
Jim Stichnoth467ffe52016-03-29 15:01:06 -0700269 const auto FixupKind =
270 (getBase() != nullptr || getIndex() != nullptr) ? FK_Abs : FK_PcRel;
271 const RelocOffsetT DispAdjustment = FixupKind == FK_PcRel ? 4 : 0;
272 Fixup = Asm->createFixup(FixupKind, CR);
273 Fixup->set_addend(-DispAdjustment);
John Porto6e8d3fa2016-02-04 10:35:20 -0800274 Disp = CR->getOffset();
John Porto453660f2015-07-31 14:52:52 -0700275 } else {
276 llvm_unreachable("Unexpected offset type");
277 }
278 }
279
280 // Now convert to the various possible forms.
281 if (getBase() && getIndex()) {
John Porto56958cb2016-01-14 09:18:18 -0800282 const bool NeedSandboxing = Target->needSandboxing();
283 (void)NeedSandboxing;
284 assert(!NeedSandboxing || IsLeaAddr ||
John Portoac2388c2016-01-22 07:10:56 -0800285 (getBase()->getRegNum() == Traits::RegisterSet::Reg_r15) ||
286 (getBase()->getRegNum() == Traits::RegisterSet::Reg_rsp) ||
287 (getBase()->getRegNum() == Traits::RegisterSet::Reg_rbp));
Jim Stichnoth5bff61c2015-10-28 09:26:00 -0700288 return X8664::Traits::Address(getEncodedGPR(getBase()->getRegNum()),
289 getEncodedGPR(getIndex()->getRegNum()),
290 X8664::Traits::ScaleFactor(getShift()), Disp,
291 Fixup);
John Porto56958cb2016-01-14 09:18:18 -0800292 }
293
294 if (getBase()) {
Jim Stichnoth5bff61c2015-10-28 09:26:00 -0700295 return X8664::Traits::Address(getEncodedGPR(getBase()->getRegNum()), Disp,
296 Fixup);
John Porto56958cb2016-01-14 09:18:18 -0800297 }
298
299 if (getIndex()) {
Jim Stichnoth5bff61c2015-10-28 09:26:00 -0700300 return X8664::Traits::Address(getEncodedGPR(getIndex()->getRegNum()),
301 X8664::Traits::ScaleFactor(getShift()), Disp,
302 Fixup);
John Porto453660f2015-07-31 14:52:52 -0700303 }
John Porto56958cb2016-01-14 09:18:18 -0800304
John Portod1bd1d32016-01-26 11:44:01 -0800305 if (Fixup == nullptr) {
306 // Absolute addresses are not allowed in Nexes -- they must be rebased
307 // w.r.t. %r15.
308 // Exception: LEAs are fine because they do not touch memory.
309 assert(!Target->needSandboxing() || IsLeaAddr);
310 return X8664::Traits::Address::Absolute(Disp);
311 }
312
313 return X8664::Traits::Address::RipRelative(Disp, Fixup);
John Porto453660f2015-07-31 14:52:52 -0700314}
315
John Porto4a566862016-01-04 09:33:41 -0800316TargetX8664Traits::Address
317TargetX8664Traits::VariableSplit::toAsmAddress(const Cfg *Func) const {
John Porto453660f2015-07-31 14:52:52 -0700318 assert(!Var->hasReg());
319 const ::Ice::TargetLowering *Target = Func->getTarget();
David Sehr26217e32015-11-26 13:03:50 -0800320 int32_t Offset = Var->getStackOffset() + getOffset();
Jim Stichnoth5bff61c2015-10-28 09:26:00 -0700321 return X8664::Traits::Address(getEncodedGPR(Target->getFrameOrStackReg()),
322 Offset, AssemblerFixup::NoFixup);
John Porto453660f2015-07-31 14:52:52 -0700323}
324
John Porto4a566862016-01-04 09:33:41 -0800325void TargetX8664Traits::VariableSplit::emit(const Cfg *Func) const {
John Porto453660f2015-07-31 14:52:52 -0700326 if (!BuildDefs::dump())
327 return;
328 Ostream &Str = Func->getContext()->getStrEmit();
329 assert(!Var->hasReg());
330 // The following is copied/adapted from TargetX8664::emitVariable().
331 const ::Ice::TargetLowering *Target = Func->getTarget();
Jim Stichnoth5bff61c2015-10-28 09:26:00 -0700332 constexpr Type Ty = IceType_i32;
David Sehr26217e32015-11-26 13:03:50 -0800333 int32_t Offset = Var->getStackOffset() + getOffset();
John Porto453660f2015-07-31 14:52:52 -0700334 if (Offset)
335 Str << Offset;
336 Str << "(%" << Target->getRegName(Target->getFrameOrStackReg(), Ty) << ")";
337}
338
John Porto4a566862016-01-04 09:33:41 -0800339void TargetX8664Traits::VariableSplit::dump(const Cfg *Func,
340 Ostream &Str) const {
John Porto453660f2015-07-31 14:52:52 -0700341 if (!BuildDefs::dump())
342 return;
343 switch (Part) {
344 case Low:
345 Str << "low";
346 break;
347 case High:
348 Str << "high";
349 break;
350 }
351 Str << "(";
352 if (Func)
353 Var->dump(Func);
354 else
355 Var->dump(Str);
356 Str << ")";
357}
358
John Porto4a566862016-01-04 09:33:41 -0800359} // namespace X8664
John Porto453660f2015-07-31 14:52:52 -0700360} // end of namespace Ice
361
John Porto4a566862016-01-04 09:33:41 -0800362X86INSTS_DEFINE_STATIC_DATA(X8664, X8664::Traits)