OLD | NEW |
1 //===- subzero/src/IceInstX8632.h - x86-32 machine instructions -*- C++ -*-===// | 1 //===- subzero/src/IceInstX8632.h - x86-32 machine instructions -*- C++ -*-===// |
2 // | 2 // |
3 // The Subzero Code Generator | 3 // The Subzero Code Generator |
4 // | 4 // |
5 // This file is distributed under the University of Illinois Open Source | 5 // This file is distributed under the University of Illinois Open Source |
6 // License. See LICENSE.TXT for details. | 6 // License. See LICENSE.TXT for details. |
7 // | 7 // |
8 //===----------------------------------------------------------------------===// | 8 //===----------------------------------------------------------------------===// |
9 /// | 9 /// |
10 /// \file | 10 /// \file |
11 /// This file declares the InstX8632 and OperandX8632 classes and | 11 /// This file used to house all the X8632 instructions. Subzero has been |
12 /// their subclasses. This represents the machine instructions and | 12 /// modified to use templates for X86 instructions, so all those definitions are |
13 /// operands used for x86-32 code selection. | 13 /// are in IceInstX86Base.h |
| 14 /// |
| 15 /// When interacting with the X8632 target (which should only happen in the |
| 16 /// X8632 TargetLowering) clients have should use the Ice::X8632::Traits::Insts |
| 17 /// traits, which hides all the template verboseness behind a type alias. |
| 18 /// |
| 19 /// For example, to create an X8632 MOV Instruction, clients should do |
| 20 /// |
| 21 /// ::Ice::X8632::Traits::Insts::Mov::create |
| 22 /// |
| 23 /// In the future, this file might be used to declare X8632 specific |
| 24 /// instructions (e.g., FLD, and FSTP.) |
14 /// | 25 /// |
15 //===----------------------------------------------------------------------===// | 26 //===----------------------------------------------------------------------===// |
16 | 27 |
17 #ifndef SUBZERO_SRC_ICEINSTX8632_H | 28 #ifndef SUBZERO_SRC_ICEINSTX8632_H |
18 #define SUBZERO_SRC_ICEINSTX8632_H | 29 #define SUBZERO_SRC_ICEINSTX8632_H |
19 | 30 |
20 #include "IceAssemblerX8632.h" | |
21 #include "IceConditionCodesX8632.h" | |
22 #include "IceDefs.h" | 31 #include "IceDefs.h" |
23 #include "IceInst.h" | 32 #include "IceInst.h" |
24 #include "IceInstX8632.def" | 33 #include "IceInstX86Base.h" |
25 #include "IceOperand.h" | 34 #include "IceOperand.h" |
26 #include "IceTargetLoweringX8632Traits.h" | 35 #include "IceTargetLoweringX8632Traits.h" |
27 | 36 |
28 namespace Ice { | |
29 | |
30 class TargetX8632; | |
31 | |
32 /// OperandX8632 extends the Operand hierarchy. Its subclasses are | |
33 /// OperandX8632Mem and VariableSplit. | |
34 class OperandX8632 : public Operand { | |
35 OperandX8632() = delete; | |
36 OperandX8632(const OperandX8632 &) = delete; | |
37 OperandX8632 &operator=(const OperandX8632 &) = delete; | |
38 | |
39 public: | |
40 enum OperandKindX8632 { k__Start = Operand::kTarget, kMem, kSplit }; | |
41 using Operand::dump; | |
42 void dump(const Cfg *, Ostream &Str) const override { | |
43 if (BuildDefs::dump()) | |
44 Str << "<OperandX8632>"; | |
45 } | |
46 | |
47 protected: | |
48 OperandX8632(OperandKindX8632 Kind, Type Ty) | |
49 : Operand(static_cast<OperandKind>(Kind), Ty) {} | |
50 }; | |
51 | |
52 /// OperandX8632Mem represents the m32 addressing mode, with optional | |
53 /// base and index registers, a constant offset, and a fixed shift | |
54 /// value for the index register. | |
55 class OperandX8632Mem : public OperandX8632 { | |
56 OperandX8632Mem() = delete; | |
57 OperandX8632Mem(const OperandX8632Mem &) = delete; | |
58 OperandX8632Mem &operator=(const OperandX8632Mem &) = delete; | |
59 | |
60 public: | |
61 enum SegmentRegisters { | |
62 DefaultSegment = -1, | |
63 #define X(val, name, prefix) val, | |
64 SEG_REGX8632_TABLE | |
65 #undef X | |
66 SegReg_NUM | |
67 }; | |
68 static OperandX8632Mem *create(Cfg *Func, Type Ty, Variable *Base, | |
69 Constant *Offset, Variable *Index = nullptr, | |
70 uint16_t Shift = 0, | |
71 SegmentRegisters SegmentReg = DefaultSegment) { | |
72 return new (Func->allocate<OperandX8632Mem>()) | |
73 OperandX8632Mem(Func, Ty, Base, Offset, Index, Shift, SegmentReg); | |
74 } | |
75 Variable *getBase() const { return Base; } | |
76 Constant *getOffset() const { return Offset; } | |
77 Variable *getIndex() const { return Index; } | |
78 uint16_t getShift() const { return Shift; } | |
79 SegmentRegisters getSegmentRegister() const { return SegmentReg; } | |
80 void emitSegmentOverride(X8632::AssemblerX8632 *Asm) const; | |
81 X8632::Traits::Address toAsmAddress(Assembler *Asm) const; | |
82 void emit(const Cfg *Func) const override; | |
83 using OperandX8632::dump; | |
84 void dump(const Cfg *Func, Ostream &Str) const override; | |
85 | |
86 static bool classof(const Operand *Operand) { | |
87 return Operand->getKind() == static_cast<OperandKind>(kMem); | |
88 } | |
89 | |
90 void setRandomized(bool R) { Randomized = R; } | |
91 | |
92 bool getRandomized() const { return Randomized; } | |
93 | |
94 private: | |
95 OperandX8632Mem(Cfg *Func, Type Ty, Variable *Base, Constant *Offset, | |
96 Variable *Index, uint16_t Shift, SegmentRegisters SegmentReg); | |
97 | |
98 Variable *Base; | |
99 Constant *Offset; | |
100 Variable *Index; | |
101 uint16_t Shift; | |
102 SegmentRegisters SegmentReg : 16; | |
103 /// A flag to show if this memory operand is a randomized one. | |
104 /// Randomized memory operands are generated in | |
105 /// TargetX8632::randomizeOrPoolImmediate() | |
106 bool Randomized; | |
107 }; | |
108 | |
109 /// VariableSplit is a way to treat an f64 memory location as a pair | |
110 /// of i32 locations (Low and High). This is needed for some cases | |
111 /// of the Bitcast instruction. Since it's not possible for integer | |
112 /// registers to access the XMM registers and vice versa, the | |
113 /// lowering forces the f64 to be spilled to the stack and then | |
114 /// accesses through the VariableSplit. | |
115 class VariableSplit : public OperandX8632 { | |
116 VariableSplit() = delete; | |
117 VariableSplit(const VariableSplit &) = delete; | |
118 VariableSplit &operator=(const VariableSplit &) = delete; | |
119 | |
120 public: | |
121 enum Portion { Low, High }; | |
122 static VariableSplit *create(Cfg *Func, Variable *Var, Portion Part) { | |
123 return new (Func->allocate<VariableSplit>()) VariableSplit(Func, Var, Part); | |
124 } | |
125 int32_t getOffset() const { return Part == High ? 4 : 0; } | |
126 | |
127 X8632::Traits::Address toAsmAddress(const Cfg *Func) const; | |
128 void emit(const Cfg *Func) const override; | |
129 using OperandX8632::dump; | |
130 void dump(const Cfg *Func, Ostream &Str) const override; | |
131 | |
132 static bool classof(const Operand *Operand) { | |
133 return Operand->getKind() == static_cast<OperandKind>(kSplit); | |
134 } | |
135 | |
136 private: | |
137 VariableSplit(Cfg *Func, Variable *Var, Portion Part) | |
138 : OperandX8632(kSplit, IceType_i32), Var(Var), Part(Part) { | |
139 assert(Var->getType() == IceType_f64); | |
140 Vars = Func->allocateArrayOf<Variable *>(1); | |
141 Vars[0] = Var; | |
142 NumVars = 1; | |
143 } | |
144 | |
145 Variable *Var; | |
146 Portion Part; | |
147 }; | |
148 | |
149 /// SpillVariable decorates a Variable by linking it to another | |
150 /// Variable. When stack frame offsets are computed, the SpillVariable | |
151 /// is given a distinct stack slot only if its linked Variable has a | |
152 /// register. If the linked Variable has a stack slot, then the | |
153 /// Variable and SpillVariable share that slot. | |
154 class SpillVariable : public Variable { | |
155 SpillVariable() = delete; | |
156 SpillVariable(const SpillVariable &) = delete; | |
157 SpillVariable &operator=(const SpillVariable &) = delete; | |
158 | |
159 public: | |
160 static SpillVariable *create(Cfg *Func, Type Ty, SizeT Index) { | |
161 return new (Func->allocate<SpillVariable>()) SpillVariable(Ty, Index); | |
162 } | |
163 const static OperandKind SpillVariableKind = | |
164 static_cast<OperandKind>(kVariable_Target); | |
165 static bool classof(const Operand *Operand) { | |
166 return Operand->getKind() == SpillVariableKind; | |
167 } | |
168 void setLinkedTo(Variable *Var) { LinkedTo = Var; } | |
169 Variable *getLinkedTo() const { return LinkedTo; } | |
170 // Inherit dump() and emit() from Variable. | |
171 private: | |
172 SpillVariable(Type Ty, SizeT Index) | |
173 : Variable(SpillVariableKind, Ty, Index), LinkedTo(nullptr) {} | |
174 Variable *LinkedTo; | |
175 }; | |
176 | |
177 class InstX8632 : public InstTarget { | |
178 InstX8632() = delete; | |
179 InstX8632(const InstX8632 &) = delete; | |
180 InstX8632 &operator=(const InstX8632 &) = delete; | |
181 | |
182 public: | |
183 enum InstKindX8632 { | |
184 k__Start = Inst::Target, | |
185 Adc, | |
186 AdcRMW, | |
187 Add, | |
188 AddRMW, | |
189 Addps, | |
190 Addss, | |
191 Adjuststack, | |
192 And, | |
193 AndRMW, | |
194 Blendvps, | |
195 Br, | |
196 Bsf, | |
197 Bsr, | |
198 Bswap, | |
199 Call, | |
200 Cbwdq, | |
201 Cmov, | |
202 Cmpps, | |
203 Cmpxchg, | |
204 Cmpxchg8b, | |
205 Cvt, | |
206 Div, | |
207 Divps, | |
208 Divss, | |
209 FakeRMW, | |
210 Fld, | |
211 Fstp, | |
212 Icmp, | |
213 Idiv, | |
214 Imul, | |
215 Insertps, | |
216 Jmp, | |
217 Label, | |
218 Lea, | |
219 Load, | |
220 Mfence, | |
221 Mov, | |
222 Movd, | |
223 Movp, | |
224 Movq, | |
225 MovssRegs, | |
226 Movsx, | |
227 Movzx, | |
228 Mul, | |
229 Mulps, | |
230 Mulss, | |
231 Neg, | |
232 Nop, | |
233 Or, | |
234 OrRMW, | |
235 Padd, | |
236 Pand, | |
237 Pandn, | |
238 Pblendvb, | |
239 Pcmpeq, | |
240 Pcmpgt, | |
241 Pextr, | |
242 Pinsr, | |
243 Pmull, | |
244 Pmuludq, | |
245 Pop, | |
246 Por, | |
247 Pshufd, | |
248 Psll, | |
249 Psra, | |
250 Psrl, | |
251 Psub, | |
252 Push, | |
253 Pxor, | |
254 Ret, | |
255 Rol, | |
256 Sar, | |
257 Sbb, | |
258 SbbRMW, | |
259 Setcc, | |
260 Shl, | |
261 Shld, | |
262 Shr, | |
263 Shrd, | |
264 Shufps, | |
265 Sqrtss, | |
266 Store, | |
267 StoreP, | |
268 StoreQ, | |
269 Sub, | |
270 SubRMW, | |
271 Subps, | |
272 Subss, | |
273 Test, | |
274 Ucomiss, | |
275 UD2, | |
276 Xadd, | |
277 Xchg, | |
278 Xor, | |
279 XorRMW | |
280 }; | |
281 | |
282 static const char *getWidthString(Type Ty); | |
283 static const char *getFldString(Type Ty); | |
284 static X8632::Traits::Cond::BrCond | |
285 getOppositeCondition(X8632::Traits::Cond::BrCond Cond); | |
286 void dump(const Cfg *Func) const override; | |
287 | |
288 /// Shared emit routines for common forms of instructions. | |
289 /// See the definition of emitTwoAddress() for a description of | |
290 /// ShiftHack. | |
291 static void emitTwoAddress(const char *Opcode, const Inst *Inst, | |
292 const Cfg *Func, bool ShiftHack = false); | |
293 | |
294 static void | |
295 emitIASGPRShift(const Cfg *Func, Type Ty, const Variable *Var, | |
296 const Operand *Src, | |
297 const X8632::AssemblerX8632::GPREmitterShiftOp &Emitter); | |
298 | |
299 protected: | |
300 InstX8632(Cfg *Func, InstKindX8632 Kind, SizeT Maxsrcs, Variable *Dest) | |
301 : InstTarget(Func, static_cast<InstKind>(Kind), Maxsrcs, Dest) {} | |
302 | |
303 static bool isClassof(const Inst *Inst, InstKindX8632 MyKind) { | |
304 return Inst->getKind() == static_cast<InstKind>(MyKind); | |
305 } | |
306 /// Most instructions that operate on vector arguments require vector | |
307 /// memory operands to be fully aligned (16-byte alignment for PNaCl | |
308 /// vector types). The stack frame layout and call ABI ensure proper | |
309 /// alignment for stack operands, but memory operands (originating | |
310 /// from load/store bitcode instructions) only have element-size | |
311 /// alignment guarantees. This function validates that none of the | |
312 /// operands is a memory operand of vector type, calling | |
313 /// report_fatal_error() if one is found. This function should be | |
314 /// called during emission, and maybe also in the ctor (as long as | |
315 /// that fits the lowering style). | |
316 void validateVectorAddrMode() const { | |
317 if (getDest()) | |
318 validateVectorAddrModeOpnd(getDest()); | |
319 for (SizeT i = 0; i < getSrcSize(); ++i) { | |
320 validateVectorAddrModeOpnd(getSrc(i)); | |
321 } | |
322 } | |
323 | |
324 private: | |
325 static void validateVectorAddrModeOpnd(const Operand *Opnd) { | |
326 if (llvm::isa<OperandX8632Mem>(Opnd) && isVectorType(Opnd->getType())) { | |
327 llvm::report_fatal_error("Possible misaligned vector memory operation"); | |
328 } | |
329 } | |
330 }; | |
331 | |
332 /// InstX8632FakeRMW represents a non-atomic read-modify-write operation on a | |
333 /// memory location. An InstX8632FakeRMW is a "fake" instruction in that it | |
334 /// still needs to be lowered to some actual RMW instruction. | |
335 /// | |
336 /// If A is some memory address, D is some data value to apply, and OP is an | |
337 /// arithmetic operator, the instruction operates as: (*A) = (*A) OP D | |
338 class InstX8632FakeRMW : public InstX8632 { | |
339 InstX8632FakeRMW() = delete; | |
340 InstX8632FakeRMW(const InstX8632FakeRMW &) = delete; | |
341 InstX8632FakeRMW &operator=(const InstX8632FakeRMW &) = delete; | |
342 | |
343 public: | |
344 static InstX8632FakeRMW *create(Cfg *Func, Operand *Data, Operand *Addr, | |
345 Variable *Beacon, InstArithmetic::OpKind Op, | |
346 uint32_t Align = 1) { | |
347 // TODO(stichnot): Stop ignoring alignment specification. | |
348 (void)Align; | |
349 return new (Func->allocate<InstX8632FakeRMW>()) | |
350 InstX8632FakeRMW(Func, Data, Addr, Op, Beacon); | |
351 } | |
352 Operand *getAddr() const { return getSrc(1); } | |
353 Operand *getData() const { return getSrc(0); } | |
354 InstArithmetic::OpKind getOp() const { return Op; } | |
355 Variable *getBeacon() const { return llvm::cast<Variable>(getSrc(2)); } | |
356 void dump(const Cfg *Func) const override; | |
357 static bool classof(const Inst *Inst) { return isClassof(Inst, FakeRMW); } | |
358 | |
359 private: | |
360 InstArithmetic::OpKind Op; | |
361 InstX8632FakeRMW(Cfg *Func, Operand *Data, Operand *Addr, | |
362 InstArithmetic::OpKind Op, Variable *Beacon); | |
363 }; | |
364 | |
365 /// InstX8632Label represents an intra-block label that is the target | |
366 /// of an intra-block branch. The offset between the label and the | |
367 /// branch must be fit into one byte (considered "near"). These are | |
368 /// used for lowering i1 calculations, Select instructions, and 64-bit | |
369 /// compares on a 32-bit architecture, without basic block splitting. | |
370 /// Basic block splitting is not so desirable for several reasons, one | |
371 /// of which is the impact on decisions based on whether a variable's | |
372 /// live range spans multiple basic blocks. | |
373 /// | |
374 /// Intra-block control flow must be used with caution. Consider the | |
375 /// sequence for "c = (a >= b ? x : y)". | |
376 /// cmp a, b | |
377 /// br lt, L1 | |
378 /// mov c, x | |
379 /// jmp L2 | |
380 /// L1: | |
381 /// mov c, y | |
382 /// L2: | |
383 /// | |
384 /// Labels L1 and L2 are intra-block labels. Without knowledge of the | |
385 /// intra-block control flow, liveness analysis will determine the "mov | |
386 /// c, x" instruction to be dead. One way to prevent this is to insert | |
387 /// a "FakeUse(c)" instruction anywhere between the two "mov c, ..." | |
388 /// instructions, e.g.: | |
389 /// | |
390 /// cmp a, b | |
391 /// br lt, L1 | |
392 /// mov c, x | |
393 /// jmp L2 | |
394 /// FakeUse(c) | |
395 /// L1: | |
396 /// mov c, y | |
397 /// L2: | |
398 /// | |
399 /// The down-side is that "mov c, x" can never be dead-code eliminated | |
400 /// even if there are no uses of c. As unlikely as this situation is, | |
401 /// it may be prevented by running dead code elimination before | |
402 /// lowering. | |
403 class InstX8632Label : public InstX8632 { | |
404 InstX8632Label() = delete; | |
405 InstX8632Label(const InstX8632Label &) = delete; | |
406 InstX8632Label &operator=(const InstX8632Label &) = delete; | |
407 | |
408 public: | |
409 static InstX8632Label *create(Cfg *Func, TargetX8632 *Target) { | |
410 return new (Func->allocate<InstX8632Label>()) InstX8632Label(Func, Target); | |
411 } | |
412 uint32_t getEmitInstCount() const override { return 0; } | |
413 IceString getName(const Cfg *Func) const; | |
414 SizeT getNumber() const { return Number; } | |
415 void emit(const Cfg *Func) const override; | |
416 void emitIAS(const Cfg *Func) const override; | |
417 void dump(const Cfg *Func) const override; | |
418 | |
419 private: | |
420 InstX8632Label(Cfg *Func, TargetX8632 *Target); | |
421 | |
422 SizeT Number; /// used for unique label generation. | |
423 }; | |
424 | |
425 /// Conditional and unconditional branch instruction. | |
426 class InstX8632Br : public InstX8632 { | |
427 InstX8632Br() = delete; | |
428 InstX8632Br(const InstX8632Br &) = delete; | |
429 InstX8632Br &operator=(const InstX8632Br &) = delete; | |
430 | |
431 public: | |
432 /// Create a conditional branch to a node. | |
433 static InstX8632Br *create(Cfg *Func, CfgNode *TargetTrue, | |
434 CfgNode *TargetFalse, | |
435 X8632::Traits::Cond::BrCond Condition) { | |
436 assert(Condition != X8632::Traits::Cond::Br_None); | |
437 const InstX8632Label *NoLabel = nullptr; | |
438 return new (Func->allocate<InstX8632Br>()) | |
439 InstX8632Br(Func, TargetTrue, TargetFalse, NoLabel, Condition); | |
440 } | |
441 /// Create an unconditional branch to a node. | |
442 static InstX8632Br *create(Cfg *Func, CfgNode *Target) { | |
443 const CfgNode *NoCondTarget = nullptr; | |
444 const InstX8632Label *NoLabel = nullptr; | |
445 return new (Func->allocate<InstX8632Br>()) InstX8632Br( | |
446 Func, NoCondTarget, Target, NoLabel, X8632::Traits::Cond::Br_None); | |
447 } | |
448 /// Create a non-terminator conditional branch to a node, with a | |
449 /// fallthrough to the next instruction in the current node. This is | |
450 /// used for switch lowering. | |
451 static InstX8632Br *create(Cfg *Func, CfgNode *Target, | |
452 X8632::Traits::Cond::BrCond Condition) { | |
453 assert(Condition != X8632::Traits::Cond::Br_None); | |
454 const CfgNode *NoUncondTarget = nullptr; | |
455 const InstX8632Label *NoLabel = nullptr; | |
456 return new (Func->allocate<InstX8632Br>()) | |
457 InstX8632Br(Func, Target, NoUncondTarget, NoLabel, Condition); | |
458 } | |
459 /// Create a conditional intra-block branch (or unconditional, if | |
460 /// Condition==Br_None) to a label in the current block. | |
461 static InstX8632Br *create(Cfg *Func, InstX8632Label *Label, | |
462 X8632::Traits::Cond::BrCond Condition) { | |
463 const CfgNode *NoCondTarget = nullptr; | |
464 const CfgNode *NoUncondTarget = nullptr; | |
465 return new (Func->allocate<InstX8632Br>()) | |
466 InstX8632Br(Func, NoCondTarget, NoUncondTarget, Label, Condition); | |
467 } | |
468 const CfgNode *getTargetTrue() const { return TargetTrue; } | |
469 const CfgNode *getTargetFalse() const { return TargetFalse; } | |
470 bool optimizeBranch(const CfgNode *NextNode); | |
471 uint32_t getEmitInstCount() const override { | |
472 uint32_t Sum = 0; | |
473 if (Label) | |
474 ++Sum; | |
475 if (getTargetTrue()) | |
476 ++Sum; | |
477 if (getTargetFalse()) | |
478 ++Sum; | |
479 return Sum; | |
480 } | |
481 bool isUnconditionalBranch() const override { | |
482 return !Label && Condition == X8632::Traits::Cond::Br_None; | |
483 } | |
484 bool repointEdge(CfgNode *OldNode, CfgNode *NewNode) override; | |
485 void emit(const Cfg *Func) const override; | |
486 void emitIAS(const Cfg *Func) const override; | |
487 void dump(const Cfg *Func) const override; | |
488 static bool classof(const Inst *Inst) { return isClassof(Inst, Br); } | |
489 | |
490 private: | |
491 InstX8632Br(Cfg *Func, const CfgNode *TargetTrue, const CfgNode *TargetFalse, | |
492 const InstX8632Label *Label, | |
493 X8632::Traits::Cond::BrCond Condition); | |
494 | |
495 X8632::Traits::Cond::BrCond Condition; | |
496 const CfgNode *TargetTrue; | |
497 const CfgNode *TargetFalse; | |
498 const InstX8632Label *Label; /// Intra-block branch target | |
499 }; | |
500 | |
501 /// Jump to a target outside this function, such as tailcall, nacljump, | |
502 /// naclret, unreachable. This is different from a Branch instruction | |
503 /// in that there is no intra-function control flow to represent. | |
504 class InstX8632Jmp : public InstX8632 { | |
505 InstX8632Jmp() = delete; | |
506 InstX8632Jmp(const InstX8632Jmp &) = delete; | |
507 InstX8632Jmp &operator=(const InstX8632Jmp &) = delete; | |
508 | |
509 public: | |
510 static InstX8632Jmp *create(Cfg *Func, Operand *Target) { | |
511 return new (Func->allocate<InstX8632Jmp>()) InstX8632Jmp(Func, Target); | |
512 } | |
513 Operand *getJmpTarget() const { return getSrc(0); } | |
514 void emit(const Cfg *Func) const override; | |
515 void emitIAS(const Cfg *Func) const override; | |
516 void dump(const Cfg *Func) const override; | |
517 static bool classof(const Inst *Inst) { return isClassof(Inst, Jmp); } | |
518 | |
519 private: | |
520 InstX8632Jmp(Cfg *Func, Operand *Target); | |
521 }; | |
522 | |
523 /// AdjustStack instruction - subtracts esp by the given amount and | |
524 /// updates the stack offset during code emission. | |
525 class InstX8632AdjustStack : public InstX8632 { | |
526 InstX8632AdjustStack() = delete; | |
527 InstX8632AdjustStack(const InstX8632AdjustStack &) = delete; | |
528 InstX8632AdjustStack &operator=(const InstX8632AdjustStack &) = delete; | |
529 | |
530 public: | |
531 static InstX8632AdjustStack *create(Cfg *Func, SizeT Amount, Variable *Esp) { | |
532 return new (Func->allocate<InstX8632AdjustStack>()) | |
533 InstX8632AdjustStack(Func, Amount, Esp); | |
534 } | |
535 void emit(const Cfg *Func) const override; | |
536 void emitIAS(const Cfg *Func) const override; | |
537 void dump(const Cfg *Func) const override; | |
538 static bool classof(const Inst *Inst) { return isClassof(Inst, Adjuststack); } | |
539 | |
540 private: | |
541 InstX8632AdjustStack(Cfg *Func, SizeT Amount, Variable *Esp); | |
542 SizeT Amount; | |
543 }; | |
544 | |
545 /// Call instruction. Arguments should have already been pushed. | |
546 class InstX8632Call : public InstX8632 { | |
547 InstX8632Call() = delete; | |
548 InstX8632Call(const InstX8632Call &) = delete; | |
549 InstX8632Call &operator=(const InstX8632Call &) = delete; | |
550 | |
551 public: | |
552 static InstX8632Call *create(Cfg *Func, Variable *Dest, Operand *CallTarget) { | |
553 return new (Func->allocate<InstX8632Call>()) | |
554 InstX8632Call(Func, Dest, CallTarget); | |
555 } | |
556 Operand *getCallTarget() const { return getSrc(0); } | |
557 void emit(const Cfg *Func) const override; | |
558 void emitIAS(const Cfg *Func) const override; | |
559 void dump(const Cfg *Func) const override; | |
560 static bool classof(const Inst *Inst) { return isClassof(Inst, Call); } | |
561 | |
562 private: | |
563 InstX8632Call(Cfg *Func, Variable *Dest, Operand *CallTarget); | |
564 }; | |
565 | |
566 /// Emit a one-operand (GPR) instruction. | |
567 void emitIASOpTyGPR(const Cfg *Func, Type Ty, const Operand *Var, | |
568 const X8632::AssemblerX8632::GPREmitterOneOp &Emitter); | |
569 void emitIASAsAddrOpTyGPR( | |
570 const Cfg *Func, Type Ty, const Operand *Op0, const Operand *Op1, | |
571 const X8632::AssemblerX8632::GPREmitterAddrOp &Emitter); | |
572 | |
573 /// Instructions of the form x := op(x). | |
574 template <InstX8632::InstKindX8632 K> | |
575 class InstX8632InplaceopGPR : public InstX8632 { | |
576 InstX8632InplaceopGPR() = delete; | |
577 InstX8632InplaceopGPR(const InstX8632InplaceopGPR &) = delete; | |
578 InstX8632InplaceopGPR &operator=(const InstX8632InplaceopGPR &) = delete; | |
579 | |
580 public: | |
581 static InstX8632InplaceopGPR *create(Cfg *Func, Operand *SrcDest) { | |
582 return new (Func->allocate<InstX8632InplaceopGPR>()) | |
583 InstX8632InplaceopGPR(Func, SrcDest); | |
584 } | |
585 void emit(const Cfg *Func) const override { | |
586 if (!BuildDefs::dump()) | |
587 return; | |
588 Ostream &Str = Func->getContext()->getStrEmit(); | |
589 assert(getSrcSize() == 1); | |
590 Str << "\t" << Opcode << "\t"; | |
591 getSrc(0)->emit(Func); | |
592 } | |
593 void emitIAS(const Cfg *Func) const override { | |
594 assert(getSrcSize() == 1); | |
595 const Variable *Var = getDest(); | |
596 Type Ty = Var->getType(); | |
597 emitIASOpTyGPR(Func, Ty, Var, Emitter); | |
598 } | |
599 void dump(const Cfg *Func) const override { | |
600 if (!BuildDefs::dump()) | |
601 return; | |
602 Ostream &Str = Func->getContext()->getStrDump(); | |
603 dumpDest(Func); | |
604 Str << " = " << Opcode << "." << getDest()->getType() << " "; | |
605 dumpSources(Func); | |
606 } | |
607 static bool classof(const Inst *Inst) { return isClassof(Inst, K); } | |
608 | |
609 private: | |
610 InstX8632InplaceopGPR(Cfg *Func, Operand *SrcDest) | |
611 : InstX8632(Func, K, 1, llvm::dyn_cast<Variable>(SrcDest)) { | |
612 addSource(SrcDest); | |
613 } | |
614 | |
615 static const char *Opcode; | |
616 static const X8632::AssemblerX8632::GPREmitterOneOp Emitter; | |
617 }; | |
618 | |
619 /// Emit a two-operand (GPR) instruction, where the dest operand is a | |
620 /// Variable that's guaranteed to be a register. | |
621 template <bool VarCanBeByte = true, bool SrcCanBeByte = true> | |
622 void emitIASRegOpTyGPR(const Cfg *Func, Type Ty, const Variable *Dst, | |
623 const Operand *Src, | |
624 const X8632::AssemblerX8632::GPREmitterRegOp &Emitter); | |
625 | |
626 /// Instructions of the form x := op(y). | |
627 template <InstX8632::InstKindX8632 K> | |
628 class InstX8632UnaryopGPR : public InstX8632 { | |
629 InstX8632UnaryopGPR() = delete; | |
630 InstX8632UnaryopGPR(const InstX8632UnaryopGPR &) = delete; | |
631 InstX8632UnaryopGPR &operator=(const InstX8632UnaryopGPR &) = delete; | |
632 | |
633 public: | |
634 static InstX8632UnaryopGPR *create(Cfg *Func, Variable *Dest, Operand *Src) { | |
635 return new (Func->allocate<InstX8632UnaryopGPR>()) | |
636 InstX8632UnaryopGPR(Func, Dest, Src); | |
637 } | |
638 void emit(const Cfg *Func) const override { | |
639 if (!BuildDefs::dump()) | |
640 return; | |
641 Ostream &Str = Func->getContext()->getStrEmit(); | |
642 assert(getSrcSize() == 1); | |
643 Type SrcTy = getSrc(0)->getType(); | |
644 Type DestTy = getDest()->getType(); | |
645 Str << "\t" << Opcode << getWidthString(SrcTy); | |
646 // Movsx and movzx need both the source and dest type width letter | |
647 // to define the operation. The other unary operations have the | |
648 // same source and dest type and as a result need only one letter. | |
649 if (SrcTy != DestTy) | |
650 Str << getWidthString(DestTy); | |
651 Str << "\t"; | |
652 getSrc(0)->emit(Func); | |
653 Str << ", "; | |
654 getDest()->emit(Func); | |
655 } | |
656 void emitIAS(const Cfg *Func) const override { | |
657 assert(getSrcSize() == 1); | |
658 const Variable *Var = getDest(); | |
659 Type Ty = Var->getType(); | |
660 const Operand *Src = getSrc(0); | |
661 emitIASRegOpTyGPR(Func, Ty, Var, Src, Emitter); | |
662 } | |
663 void dump(const Cfg *Func) const override { | |
664 if (!BuildDefs::dump()) | |
665 return; | |
666 Ostream &Str = Func->getContext()->getStrDump(); | |
667 dumpDest(Func); | |
668 Str << " = " << Opcode << "." << getSrc(0)->getType() << " "; | |
669 dumpSources(Func); | |
670 } | |
671 static bool classof(const Inst *Inst) { return isClassof(Inst, K); } | |
672 | |
673 private: | |
674 InstX8632UnaryopGPR(Cfg *Func, Variable *Dest, Operand *Src) | |
675 : InstX8632(Func, K, 1, Dest) { | |
676 addSource(Src); | |
677 } | |
678 | |
679 static const char *Opcode; | |
680 static const X8632::AssemblerX8632::GPREmitterRegOp Emitter; | |
681 }; | |
682 | |
683 void emitIASRegOpTyXMM(const Cfg *Func, Type Ty, const Variable *Var, | |
684 const Operand *Src, | |
685 const X8632::AssemblerX8632::XmmEmitterRegOp &Emitter); | |
686 | |
687 template <InstX8632::InstKindX8632 K> | |
688 class InstX8632UnaryopXmm : public InstX8632 { | |
689 InstX8632UnaryopXmm() = delete; | |
690 InstX8632UnaryopXmm(const InstX8632UnaryopXmm &) = delete; | |
691 InstX8632UnaryopXmm &operator=(const InstX8632UnaryopXmm &) = delete; | |
692 | |
693 public: | |
694 static InstX8632UnaryopXmm *create(Cfg *Func, Variable *Dest, Operand *Src) { | |
695 return new (Func->allocate<InstX8632UnaryopXmm>()) | |
696 InstX8632UnaryopXmm(Func, Dest, Src); | |
697 } | |
698 void emit(const Cfg *Func) const override { | |
699 if (!BuildDefs::dump()) | |
700 return; | |
701 Ostream &Str = Func->getContext()->getStrEmit(); | |
702 assert(getSrcSize() == 1); | |
703 Str << "\t" << Opcode << "\t"; | |
704 getSrc(0)->emit(Func); | |
705 Str << ", "; | |
706 getDest()->emit(Func); | |
707 } | |
708 void emitIAS(const Cfg *Func) const override { | |
709 Type Ty = getDest()->getType(); | |
710 assert(getSrcSize() == 1); | |
711 emitIASRegOpTyXMM(Func, Ty, getDest(), getSrc(0), Emitter); | |
712 } | |
713 void dump(const Cfg *Func) const override { | |
714 if (!BuildDefs::dump()) | |
715 return; | |
716 Ostream &Str = Func->getContext()->getStrDump(); | |
717 dumpDest(Func); | |
718 Str << " = " << Opcode << "." << getDest()->getType() << " "; | |
719 dumpSources(Func); | |
720 } | |
721 static bool classof(const Inst *Inst) { return isClassof(Inst, K); } | |
722 | |
723 private: | |
724 InstX8632UnaryopXmm(Cfg *Func, Variable *Dest, Operand *Src) | |
725 : InstX8632(Func, K, 1, Dest) { | |
726 addSource(Src); | |
727 } | |
728 | |
729 static const char *Opcode; | |
730 static const X8632::AssemblerX8632::XmmEmitterRegOp Emitter; | |
731 }; | |
732 | |
733 template <InstX8632::InstKindX8632 K> | |
734 class InstX8632BinopGPRShift : public InstX8632 { | |
735 InstX8632BinopGPRShift() = delete; | |
736 InstX8632BinopGPRShift(const InstX8632BinopGPRShift &) = delete; | |
737 InstX8632BinopGPRShift &operator=(const InstX8632BinopGPRShift &) = delete; | |
738 | |
739 public: | |
740 /// Create a binary-op GPR shift instruction. | |
741 static InstX8632BinopGPRShift *create(Cfg *Func, Variable *Dest, | |
742 Operand *Source) { | |
743 return new (Func->allocate<InstX8632BinopGPRShift>()) | |
744 InstX8632BinopGPRShift(Func, Dest, Source); | |
745 } | |
746 void emit(const Cfg *Func) const override { | |
747 if (!BuildDefs::dump()) | |
748 return; | |
749 const bool ShiftHack = true; | |
750 emitTwoAddress(Opcode, this, Func, ShiftHack); | |
751 } | |
752 void emitIAS(const Cfg *Func) const override { | |
753 Type Ty = getDest()->getType(); | |
754 assert(getSrcSize() == 2); | |
755 emitIASGPRShift(Func, Ty, getDest(), getSrc(1), Emitter); | |
756 } | |
757 void dump(const Cfg *Func) const override { | |
758 if (!BuildDefs::dump()) | |
759 return; | |
760 Ostream &Str = Func->getContext()->getStrDump(); | |
761 dumpDest(Func); | |
762 Str << " = " << Opcode << "." << getDest()->getType() << " "; | |
763 dumpSources(Func); | |
764 } | |
765 static bool classof(const Inst *Inst) { return isClassof(Inst, K); } | |
766 | |
767 private: | |
768 InstX8632BinopGPRShift(Cfg *Func, Variable *Dest, Operand *Source) | |
769 : InstX8632(Func, K, 2, Dest) { | |
770 addSource(Dest); | |
771 addSource(Source); | |
772 } | |
773 | |
774 static const char *Opcode; | |
775 static const X8632::AssemblerX8632::GPREmitterShiftOp Emitter; | |
776 }; | |
777 | |
778 template <InstX8632::InstKindX8632 K> | |
779 class InstX8632BinopGPR : public InstX8632 { | |
780 InstX8632BinopGPR() = delete; | |
781 InstX8632BinopGPR(const InstX8632BinopGPR &) = delete; | |
782 InstX8632BinopGPR &operator=(const InstX8632BinopGPR &) = delete; | |
783 | |
784 public: | |
785 /// Create an ordinary binary-op instruction like add or sub. | |
786 static InstX8632BinopGPR *create(Cfg *Func, Variable *Dest, Operand *Source) { | |
787 return new (Func->allocate<InstX8632BinopGPR>()) | |
788 InstX8632BinopGPR(Func, Dest, Source); | |
789 } | |
790 void emit(const Cfg *Func) const override { | |
791 if (!BuildDefs::dump()) | |
792 return; | |
793 const bool ShiftHack = false; | |
794 emitTwoAddress(Opcode, this, Func, ShiftHack); | |
795 } | |
796 void emitIAS(const Cfg *Func) const override { | |
797 Type Ty = getDest()->getType(); | |
798 assert(getSrcSize() == 2); | |
799 emitIASRegOpTyGPR(Func, Ty, getDest(), getSrc(1), Emitter); | |
800 } | |
801 void dump(const Cfg *Func) const override { | |
802 if (!BuildDefs::dump()) | |
803 return; | |
804 Ostream &Str = Func->getContext()->getStrDump(); | |
805 dumpDest(Func); | |
806 Str << " = " << Opcode << "." << getDest()->getType() << " "; | |
807 dumpSources(Func); | |
808 } | |
809 static bool classof(const Inst *Inst) { return isClassof(Inst, K); } | |
810 | |
811 private: | |
812 InstX8632BinopGPR(Cfg *Func, Variable *Dest, Operand *Source) | |
813 : InstX8632(Func, K, 2, Dest) { | |
814 addSource(Dest); | |
815 addSource(Source); | |
816 } | |
817 | |
818 static const char *Opcode; | |
819 static const X8632::AssemblerX8632::GPREmitterRegOp Emitter; | |
820 }; | |
821 | |
822 template <InstX8632::InstKindX8632 K> | |
823 class InstX8632BinopRMW : public InstX8632 { | |
824 InstX8632BinopRMW() = delete; | |
825 InstX8632BinopRMW(const InstX8632BinopRMW &) = delete; | |
826 InstX8632BinopRMW &operator=(const InstX8632BinopRMW &) = delete; | |
827 | |
828 public: | |
829 /// Create an ordinary binary-op instruction like add or sub. | |
830 static InstX8632BinopRMW *create(Cfg *Func, OperandX8632Mem *DestSrc0, | |
831 Operand *Src1) { | |
832 return new (Func->allocate<InstX8632BinopRMW>()) | |
833 InstX8632BinopRMW(Func, DestSrc0, Src1); | |
834 } | |
835 void emit(const Cfg *Func) const override { | |
836 if (!BuildDefs::dump()) | |
837 return; | |
838 const bool ShiftHack = false; | |
839 emitTwoAddress(Opcode, this, Func, ShiftHack); | |
840 } | |
841 void emitIAS(const Cfg *Func) const override { | |
842 Type Ty = getSrc(0)->getType(); | |
843 assert(getSrcSize() == 2); | |
844 emitIASAsAddrOpTyGPR(Func, Ty, getSrc(0), getSrc(1), Emitter); | |
845 } | |
846 void dump(const Cfg *Func) const override { | |
847 if (!BuildDefs::dump()) | |
848 return; | |
849 Ostream &Str = Func->getContext()->getStrDump(); | |
850 Str << Opcode << "." << getSrc(0)->getType() << " "; | |
851 dumpSources(Func); | |
852 } | |
853 static bool classof(const Inst *Inst) { return isClassof(Inst, K); } | |
854 | |
855 private: | |
856 InstX8632BinopRMW(Cfg *Func, OperandX8632Mem *DestSrc0, Operand *Src1) | |
857 : InstX8632(Func, K, 2, nullptr) { | |
858 addSource(DestSrc0); | |
859 addSource(Src1); | |
860 } | |
861 static const char *Opcode; | |
862 static const X8632::AssemblerX8632::GPREmitterAddrOp Emitter; | |
863 }; | |
864 | |
865 template <InstX8632::InstKindX8632 K, bool NeedsElementType> | |
866 class InstX8632BinopXmm : public InstX8632 { | |
867 InstX8632BinopXmm() = delete; | |
868 InstX8632BinopXmm(const InstX8632BinopXmm &) = delete; | |
869 InstX8632BinopXmm &operator=(const InstX8632BinopXmm &) = delete; | |
870 | |
871 public: | |
872 /// Create an XMM binary-op instruction like addss or addps. | |
873 static InstX8632BinopXmm *create(Cfg *Func, Variable *Dest, Operand *Source) { | |
874 return new (Func->allocate<InstX8632BinopXmm>()) | |
875 InstX8632BinopXmm(Func, Dest, Source); | |
876 } | |
877 void emit(const Cfg *Func) const override { | |
878 if (!BuildDefs::dump()) | |
879 return; | |
880 validateVectorAddrMode(); | |
881 const bool ShiftHack = false; | |
882 emitTwoAddress(Opcode, this, Func, ShiftHack); | |
883 } | |
884 void emitIAS(const Cfg *Func) const override { | |
885 validateVectorAddrMode(); | |
886 Type Ty = getDest()->getType(); | |
887 if (NeedsElementType) | |
888 Ty = typeElementType(Ty); | |
889 assert(getSrcSize() == 2); | |
890 emitIASRegOpTyXMM(Func, Ty, getDest(), getSrc(1), Emitter); | |
891 } | |
892 void dump(const Cfg *Func) const override { | |
893 if (!BuildDefs::dump()) | |
894 return; | |
895 Ostream &Str = Func->getContext()->getStrDump(); | |
896 dumpDest(Func); | |
897 Str << " = " << Opcode << "." << getDest()->getType() << " "; | |
898 dumpSources(Func); | |
899 } | |
900 static bool classof(const Inst *Inst) { return isClassof(Inst, K); } | |
901 | |
902 private: | |
903 InstX8632BinopXmm(Cfg *Func, Variable *Dest, Operand *Source) | |
904 : InstX8632(Func, K, 2, Dest) { | |
905 addSource(Dest); | |
906 addSource(Source); | |
907 } | |
908 | |
909 static const char *Opcode; | |
910 static const X8632::AssemblerX8632::XmmEmitterRegOp Emitter; | |
911 }; | |
912 | |
913 void emitIASXmmShift(const Cfg *Func, Type Ty, const Variable *Var, | |
914 const Operand *Src, | |
915 const X8632::AssemblerX8632::XmmEmitterShiftOp &Emitter); | |
916 | |
917 template <InstX8632::InstKindX8632 K, bool AllowAllTypes = false> | |
918 class InstX8632BinopXmmShift : public InstX8632 { | |
919 InstX8632BinopXmmShift() = delete; | |
920 InstX8632BinopXmmShift(const InstX8632BinopXmmShift &) = delete; | |
921 InstX8632BinopXmmShift &operator=(const InstX8632BinopXmmShift &) = delete; | |
922 | |
923 public: | |
924 /// Create an XMM binary-op shift operation. | |
925 static InstX8632BinopXmmShift *create(Cfg *Func, Variable *Dest, | |
926 Operand *Source) { | |
927 return new (Func->allocate<InstX8632BinopXmmShift>()) | |
928 InstX8632BinopXmmShift(Func, Dest, Source); | |
929 } | |
930 void emit(const Cfg *Func) const override { | |
931 if (!BuildDefs::dump()) | |
932 return; | |
933 validateVectorAddrMode(); | |
934 const bool ShiftHack = false; | |
935 emitTwoAddress(Opcode, this, Func, ShiftHack); | |
936 } | |
937 void emitIAS(const Cfg *Func) const override { | |
938 validateVectorAddrMode(); | |
939 Type Ty = getDest()->getType(); | |
940 assert(AllowAllTypes || isVectorType(Ty)); | |
941 Type ElementTy = typeElementType(Ty); | |
942 assert(getSrcSize() == 2); | |
943 emitIASXmmShift(Func, ElementTy, getDest(), getSrc(1), Emitter); | |
944 } | |
945 void dump(const Cfg *Func) const override { | |
946 if (!BuildDefs::dump()) | |
947 return; | |
948 Ostream &Str = Func->getContext()->getStrDump(); | |
949 dumpDest(Func); | |
950 Str << " = " << Opcode << "." << getDest()->getType() << " "; | |
951 dumpSources(Func); | |
952 } | |
953 static bool classof(const Inst *Inst) { return isClassof(Inst, K); } | |
954 | |
955 private: | |
956 InstX8632BinopXmmShift(Cfg *Func, Variable *Dest, Operand *Source) | |
957 : InstX8632(Func, K, 2, Dest) { | |
958 addSource(Dest); | |
959 addSource(Source); | |
960 } | |
961 | |
962 static const char *Opcode; | |
963 static const X8632::AssemblerX8632::XmmEmitterShiftOp Emitter; | |
964 }; | |
965 | |
966 template <InstX8632::InstKindX8632 K> class InstX8632Ternop : public InstX8632 { | |
967 InstX8632Ternop() = delete; | |
968 InstX8632Ternop(const InstX8632Ternop &) = delete; | |
969 InstX8632Ternop &operator=(const InstX8632Ternop &) = delete; | |
970 | |
971 public: | |
972 /// Create a ternary-op instruction like div or idiv. | |
973 static InstX8632Ternop *create(Cfg *Func, Variable *Dest, Operand *Source1, | |
974 Operand *Source2) { | |
975 return new (Func->allocate<InstX8632Ternop>()) | |
976 InstX8632Ternop(Func, Dest, Source1, Source2); | |
977 } | |
978 void emit(const Cfg *Func) const override { | |
979 if (!BuildDefs::dump()) | |
980 return; | |
981 Ostream &Str = Func->getContext()->getStrEmit(); | |
982 assert(getSrcSize() == 3); | |
983 Str << "\t" << Opcode << "\t"; | |
984 getSrc(2)->emit(Func); | |
985 Str << ", "; | |
986 getSrc(1)->emit(Func); | |
987 Str << ", "; | |
988 getDest()->emit(Func); | |
989 } | |
990 void emitIAS(const Cfg *Func) const override; | |
991 void dump(const Cfg *Func) const override { | |
992 if (!BuildDefs::dump()) | |
993 return; | |
994 Ostream &Str = Func->getContext()->getStrDump(); | |
995 dumpDest(Func); | |
996 Str << " = " << Opcode << "." << getDest()->getType() << " "; | |
997 dumpSources(Func); | |
998 } | |
999 static bool classof(const Inst *Inst) { return isClassof(Inst, K); } | |
1000 | |
1001 private: | |
1002 InstX8632Ternop(Cfg *Func, Variable *Dest, Operand *Source1, Operand *Source2) | |
1003 : InstX8632(Func, K, 3, Dest) { | |
1004 addSource(Dest); | |
1005 addSource(Source1); | |
1006 addSource(Source2); | |
1007 } | |
1008 | |
1009 static const char *Opcode; | |
1010 }; | |
1011 | |
1012 /// Instructions of the form x := y op z | |
1013 template <InstX8632::InstKindX8632 K> | |
1014 class InstX8632ThreeAddressop : public InstX8632 { | |
1015 InstX8632ThreeAddressop() = delete; | |
1016 InstX8632ThreeAddressop(const InstX8632ThreeAddressop &) = delete; | |
1017 InstX8632ThreeAddressop &operator=(const InstX8632ThreeAddressop &) = delete; | |
1018 | |
1019 public: | |
1020 static InstX8632ThreeAddressop *create(Cfg *Func, Variable *Dest, | |
1021 Operand *Source0, Operand *Source1) { | |
1022 return new (Func->allocate<InstX8632ThreeAddressop>()) | |
1023 InstX8632ThreeAddressop(Func, Dest, Source0, Source1); | |
1024 } | |
1025 void emit(const Cfg *Func) const override { | |
1026 if (!BuildDefs::dump()) | |
1027 return; | |
1028 Ostream &Str = Func->getContext()->getStrEmit(); | |
1029 assert(getSrcSize() == 2); | |
1030 Str << "\t" << Opcode << "\t"; | |
1031 getSrc(1)->emit(Func); | |
1032 Str << ", "; | |
1033 getSrc(0)->emit(Func); | |
1034 Str << ", "; | |
1035 getDest()->emit(Func); | |
1036 } | |
1037 void emitIAS(const Cfg *Func) const override; | |
1038 void dump(const Cfg *Func) const override { | |
1039 if (!BuildDefs::dump()) | |
1040 return; | |
1041 Ostream &Str = Func->getContext()->getStrDump(); | |
1042 dumpDest(Func); | |
1043 Str << " = " << Opcode << "." << getDest()->getType() << " "; | |
1044 dumpSources(Func); | |
1045 } | |
1046 static bool classof(const Inst *Inst) { return isClassof(Inst, K); } | |
1047 | |
1048 private: | |
1049 InstX8632ThreeAddressop(Cfg *Func, Variable *Dest, Operand *Source0, | |
1050 Operand *Source1) | |
1051 : InstX8632(Func, K, 2, Dest) { | |
1052 addSource(Source0); | |
1053 addSource(Source1); | |
1054 } | |
1055 | |
1056 static const char *Opcode; | |
1057 }; | |
1058 | |
1059 /// Base class for assignment instructions | |
1060 template <InstX8632::InstKindX8632 K> | |
1061 class InstX8632Movlike : public InstX8632 { | |
1062 InstX8632Movlike() = delete; | |
1063 InstX8632Movlike(const InstX8632Movlike &) = delete; | |
1064 InstX8632Movlike &operator=(const InstX8632Movlike &) = delete; | |
1065 | |
1066 public: | |
1067 static InstX8632Movlike *create(Cfg *Func, Variable *Dest, Operand *Source) { | |
1068 return new (Func->allocate<InstX8632Movlike>()) | |
1069 InstX8632Movlike(Func, Dest, Source); | |
1070 } | |
1071 bool isRedundantAssign() const override { | |
1072 return checkForRedundantAssign(getDest(), getSrc(0)); | |
1073 } | |
1074 bool isSimpleAssign() const override { return true; } | |
1075 void emit(const Cfg *Func) const override; | |
1076 void emitIAS(const Cfg *Func) const override; | |
1077 void dump(const Cfg *Func) const override { | |
1078 if (!BuildDefs::dump()) | |
1079 return; | |
1080 Ostream &Str = Func->getContext()->getStrDump(); | |
1081 Str << Opcode << "." << getDest()->getType() << " "; | |
1082 dumpDest(Func); | |
1083 Str << ", "; | |
1084 dumpSources(Func); | |
1085 } | |
1086 static bool classof(const Inst *Inst) { return isClassof(Inst, K); } | |
1087 | |
1088 private: | |
1089 InstX8632Movlike(Cfg *Func, Variable *Dest, Operand *Source) | |
1090 : InstX8632(Func, K, 1, Dest) { | |
1091 addSource(Source); | |
1092 } | |
1093 | |
1094 static const char *Opcode; | |
1095 }; | |
1096 | |
1097 typedef InstX8632InplaceopGPR<InstX8632::Bswap> InstX8632Bswap; | |
1098 typedef InstX8632InplaceopGPR<InstX8632::Neg> InstX8632Neg; | |
1099 typedef InstX8632UnaryopGPR<InstX8632::Bsf> InstX8632Bsf; | |
1100 typedef InstX8632UnaryopGPR<InstX8632::Bsr> InstX8632Bsr; | |
1101 typedef InstX8632UnaryopGPR<InstX8632::Lea> InstX8632Lea; | |
1102 /// Cbwdq instruction - wrapper for cbw, cwd, and cdq | |
1103 typedef InstX8632UnaryopGPR<InstX8632::Cbwdq> InstX8632Cbwdq; | |
1104 typedef InstX8632UnaryopGPR<InstX8632::Movsx> InstX8632Movsx; | |
1105 typedef InstX8632UnaryopGPR<InstX8632::Movzx> InstX8632Movzx; | |
1106 typedef InstX8632UnaryopXmm<InstX8632::Movd> InstX8632Movd; | |
1107 typedef InstX8632UnaryopXmm<InstX8632::Sqrtss> InstX8632Sqrtss; | |
1108 /// Move/assignment instruction - wrapper for mov/movss/movsd. | |
1109 typedef InstX8632Movlike<InstX8632::Mov> InstX8632Mov; | |
1110 /// Move packed - copy 128 bit values between XMM registers, or mem128 | |
1111 /// and XMM registers. | |
1112 typedef InstX8632Movlike<InstX8632::Movp> InstX8632Movp; | |
1113 /// Movq - copy between XMM registers, or mem64 and XMM registers. | |
1114 typedef InstX8632Movlike<InstX8632::Movq> InstX8632Movq; | |
1115 typedef InstX8632BinopGPR<InstX8632::Add> InstX8632Add; | |
1116 typedef InstX8632BinopRMW<InstX8632::AddRMW> InstX8632AddRMW; | |
1117 typedef InstX8632BinopXmm<InstX8632::Addps, true> InstX8632Addps; | |
1118 typedef InstX8632BinopGPR<InstX8632::Adc> InstX8632Adc; | |
1119 typedef InstX8632BinopRMW<InstX8632::AdcRMW> InstX8632AdcRMW; | |
1120 typedef InstX8632BinopXmm<InstX8632::Addss, false> InstX8632Addss; | |
1121 typedef InstX8632BinopXmm<InstX8632::Padd, true> InstX8632Padd; | |
1122 typedef InstX8632BinopGPR<InstX8632::Sub> InstX8632Sub; | |
1123 typedef InstX8632BinopRMW<InstX8632::SubRMW> InstX8632SubRMW; | |
1124 typedef InstX8632BinopXmm<InstX8632::Subps, true> InstX8632Subps; | |
1125 typedef InstX8632BinopXmm<InstX8632::Subss, false> InstX8632Subss; | |
1126 typedef InstX8632BinopGPR<InstX8632::Sbb> InstX8632Sbb; | |
1127 typedef InstX8632BinopRMW<InstX8632::SbbRMW> InstX8632SbbRMW; | |
1128 typedef InstX8632BinopXmm<InstX8632::Psub, true> InstX8632Psub; | |
1129 typedef InstX8632BinopGPR<InstX8632::And> InstX8632And; | |
1130 typedef InstX8632BinopRMW<InstX8632::AndRMW> InstX8632AndRMW; | |
1131 typedef InstX8632BinopXmm<InstX8632::Pand, false> InstX8632Pand; | |
1132 typedef InstX8632BinopXmm<InstX8632::Pandn, false> InstX8632Pandn; | |
1133 typedef InstX8632BinopGPR<InstX8632::Or> InstX8632Or; | |
1134 typedef InstX8632BinopRMW<InstX8632::OrRMW> InstX8632OrRMW; | |
1135 typedef InstX8632BinopXmm<InstX8632::Por, false> InstX8632Por; | |
1136 typedef InstX8632BinopGPR<InstX8632::Xor> InstX8632Xor; | |
1137 typedef InstX8632BinopRMW<InstX8632::XorRMW> InstX8632XorRMW; | |
1138 typedef InstX8632BinopXmm<InstX8632::Pxor, false> InstX8632Pxor; | |
1139 typedef InstX8632BinopGPR<InstX8632::Imul> InstX8632Imul; | |
1140 typedef InstX8632BinopXmm<InstX8632::Mulps, true> InstX8632Mulps; | |
1141 typedef InstX8632BinopXmm<InstX8632::Mulss, false> InstX8632Mulss; | |
1142 typedef InstX8632BinopXmm<InstX8632::Pmull, true> InstX8632Pmull; | |
1143 typedef InstX8632BinopXmm<InstX8632::Pmuludq, false> InstX8632Pmuludq; | |
1144 typedef InstX8632BinopXmm<InstX8632::Divps, true> InstX8632Divps; | |
1145 typedef InstX8632BinopXmm<InstX8632::Divss, false> InstX8632Divss; | |
1146 typedef InstX8632BinopGPRShift<InstX8632::Rol> InstX8632Rol; | |
1147 typedef InstX8632BinopGPRShift<InstX8632::Shl> InstX8632Shl; | |
1148 typedef InstX8632BinopXmmShift<InstX8632::Psll> InstX8632Psll; | |
1149 typedef InstX8632BinopXmmShift<InstX8632::Psrl, true> InstX8632Psrl; | |
1150 typedef InstX8632BinopGPRShift<InstX8632::Shr> InstX8632Shr; | |
1151 typedef InstX8632BinopGPRShift<InstX8632::Sar> InstX8632Sar; | |
1152 typedef InstX8632BinopXmmShift<InstX8632::Psra> InstX8632Psra; | |
1153 typedef InstX8632BinopXmm<InstX8632::Pcmpeq, true> InstX8632Pcmpeq; | |
1154 typedef InstX8632BinopXmm<InstX8632::Pcmpgt, true> InstX8632Pcmpgt; | |
1155 /// movss is only a binary operation when the source and dest | |
1156 /// operands are both registers (the high bits of dest are left untouched). | |
1157 /// In other cases, it behaves like a copy (mov-like) operation (and the | |
1158 /// high bits of dest are cleared). | |
1159 /// InstX8632Movss will assert that both its source and dest operands are | |
1160 /// registers, so the lowering code should use _mov instead of _movss | |
1161 /// in cases where a copy operation is intended. | |
1162 typedef InstX8632BinopXmm<InstX8632::MovssRegs, false> InstX8632MovssRegs; | |
1163 typedef InstX8632Ternop<InstX8632::Idiv> InstX8632Idiv; | |
1164 typedef InstX8632Ternop<InstX8632::Div> InstX8632Div; | |
1165 typedef InstX8632Ternop<InstX8632::Insertps> InstX8632Insertps; | |
1166 typedef InstX8632Ternop<InstX8632::Pinsr> InstX8632Pinsr; | |
1167 typedef InstX8632Ternop<InstX8632::Shufps> InstX8632Shufps; | |
1168 typedef InstX8632Ternop<InstX8632::Blendvps> InstX8632Blendvps; | |
1169 typedef InstX8632Ternop<InstX8632::Pblendvb> InstX8632Pblendvb; | |
1170 typedef InstX8632ThreeAddressop<InstX8632::Pextr> InstX8632Pextr; | |
1171 typedef InstX8632ThreeAddressop<InstX8632::Pshufd> InstX8632Pshufd; | |
1172 | |
1173 /// Base class for a lockable x86-32 instruction (emits a locked prefix). | |
1174 class InstX8632Lockable : public InstX8632 { | |
1175 InstX8632Lockable() = delete; | |
1176 InstX8632Lockable(const InstX8632Lockable &) = delete; | |
1177 InstX8632Lockable &operator=(const InstX8632Lockable &) = delete; | |
1178 | |
1179 protected: | |
1180 bool Locked; | |
1181 | |
1182 InstX8632Lockable(Cfg *Func, InstKindX8632 Kind, SizeT Maxsrcs, | |
1183 Variable *Dest, bool Locked) | |
1184 : InstX8632(Func, Kind, Maxsrcs, Dest), Locked(Locked) { | |
1185 // Assume that such instructions are used for Atomics and be careful | |
1186 // with optimizations. | |
1187 HasSideEffects = Locked; | |
1188 } | |
1189 }; | |
1190 | |
1191 /// Mul instruction - unsigned multiply. | |
1192 class InstX8632Mul : public InstX8632 { | |
1193 InstX8632Mul() = delete; | |
1194 InstX8632Mul(const InstX8632Mul &) = delete; | |
1195 InstX8632Mul &operator=(const InstX8632Mul &) = delete; | |
1196 | |
1197 public: | |
1198 static InstX8632Mul *create(Cfg *Func, Variable *Dest, Variable *Source1, | |
1199 Operand *Source2) { | |
1200 return new (Func->allocate<InstX8632Mul>()) | |
1201 InstX8632Mul(Func, Dest, Source1, Source2); | |
1202 } | |
1203 void emit(const Cfg *Func) const override; | |
1204 void emitIAS(const Cfg *Func) const override; | |
1205 void dump(const Cfg *Func) const override; | |
1206 static bool classof(const Inst *Inst) { return isClassof(Inst, Mul); } | |
1207 | |
1208 private: | |
1209 InstX8632Mul(Cfg *Func, Variable *Dest, Variable *Source1, Operand *Source2); | |
1210 }; | |
1211 | |
1212 /// Shld instruction - shift across a pair of operands. | |
1213 class InstX8632Shld : public InstX8632 { | |
1214 InstX8632Shld() = delete; | |
1215 InstX8632Shld(const InstX8632Shld &) = delete; | |
1216 InstX8632Shld &operator=(const InstX8632Shld &) = delete; | |
1217 | |
1218 public: | |
1219 static InstX8632Shld *create(Cfg *Func, Variable *Dest, Variable *Source1, | |
1220 Variable *Source2) { | |
1221 return new (Func->allocate<InstX8632Shld>()) | |
1222 InstX8632Shld(Func, Dest, Source1, Source2); | |
1223 } | |
1224 void emit(const Cfg *Func) const override; | |
1225 void emitIAS(const Cfg *Func) const override; | |
1226 void dump(const Cfg *Func) const override; | |
1227 static bool classof(const Inst *Inst) { return isClassof(Inst, Shld); } | |
1228 | |
1229 private: | |
1230 InstX8632Shld(Cfg *Func, Variable *Dest, Variable *Source1, | |
1231 Variable *Source2); | |
1232 }; | |
1233 | |
1234 /// Shrd instruction - shift across a pair of operands. | |
1235 class InstX8632Shrd : public InstX8632 { | |
1236 InstX8632Shrd() = delete; | |
1237 InstX8632Shrd(const InstX8632Shrd &) = delete; | |
1238 InstX8632Shrd &operator=(const InstX8632Shrd &) = delete; | |
1239 | |
1240 public: | |
1241 static InstX8632Shrd *create(Cfg *Func, Variable *Dest, Variable *Source1, | |
1242 Variable *Source2) { | |
1243 return new (Func->allocate<InstX8632Shrd>()) | |
1244 InstX8632Shrd(Func, Dest, Source1, Source2); | |
1245 } | |
1246 void emit(const Cfg *Func) const override; | |
1247 void emitIAS(const Cfg *Func) const override; | |
1248 void dump(const Cfg *Func) const override; | |
1249 static bool classof(const Inst *Inst) { return isClassof(Inst, Shrd); } | |
1250 | |
1251 private: | |
1252 InstX8632Shrd(Cfg *Func, Variable *Dest, Variable *Source1, | |
1253 Variable *Source2); | |
1254 }; | |
1255 | |
1256 /// Conditional move instruction. | |
1257 class InstX8632Cmov : public InstX8632 { | |
1258 InstX8632Cmov() = delete; | |
1259 InstX8632Cmov(const InstX8632Cmov &) = delete; | |
1260 InstX8632Cmov &operator=(const InstX8632Cmov &) = delete; | |
1261 | |
1262 public: | |
1263 static InstX8632Cmov *create(Cfg *Func, Variable *Dest, Operand *Source, | |
1264 X8632::Traits::Cond::BrCond Cond) { | |
1265 return new (Func->allocate<InstX8632Cmov>()) | |
1266 InstX8632Cmov(Func, Dest, Source, Cond); | |
1267 } | |
1268 void emit(const Cfg *Func) const override; | |
1269 void emitIAS(const Cfg *Func) const override; | |
1270 void dump(const Cfg *Func) const override; | |
1271 static bool classof(const Inst *Inst) { return isClassof(Inst, Cmov); } | |
1272 | |
1273 private: | |
1274 InstX8632Cmov(Cfg *Func, Variable *Dest, Operand *Source, | |
1275 X8632::Traits::Cond::BrCond Cond); | |
1276 | |
1277 X8632::Traits::Cond::BrCond Condition; | |
1278 }; | |
1279 | |
1280 /// Cmpps instruction - compare packed singled-precision floating point | |
1281 /// values | |
1282 class InstX8632Cmpps : public InstX8632 { | |
1283 InstX8632Cmpps() = delete; | |
1284 InstX8632Cmpps(const InstX8632Cmpps &) = delete; | |
1285 InstX8632Cmpps &operator=(const InstX8632Cmpps &) = delete; | |
1286 | |
1287 public: | |
1288 static InstX8632Cmpps *create(Cfg *Func, Variable *Dest, Operand *Source, | |
1289 X8632::Traits::Cond::CmppsCond Condition) { | |
1290 return new (Func->allocate<InstX8632Cmpps>()) | |
1291 InstX8632Cmpps(Func, Dest, Source, Condition); | |
1292 } | |
1293 void emit(const Cfg *Func) const override; | |
1294 void emitIAS(const Cfg *Func) const override; | |
1295 void dump(const Cfg *Func) const override; | |
1296 static bool classof(const Inst *Inst) { return isClassof(Inst, Cmpps); } | |
1297 | |
1298 private: | |
1299 InstX8632Cmpps(Cfg *Func, Variable *Dest, Operand *Source, | |
1300 X8632::Traits::Cond::CmppsCond Cond); | |
1301 | |
1302 X8632::Traits::Cond::CmppsCond Condition; | |
1303 }; | |
1304 | |
1305 /// Cmpxchg instruction - cmpxchg <dest>, <desired> will compare if <dest> | |
1306 /// equals eax. If so, the ZF is set and <desired> is stored in <dest>. | |
1307 /// If not, ZF is cleared and <dest> is copied to eax (or subregister). | |
1308 /// <dest> can be a register or memory, while <desired> must be a register. | |
1309 /// It is the user's responsiblity to mark eax with a FakeDef. | |
1310 class InstX8632Cmpxchg : public InstX8632Lockable { | |
1311 InstX8632Cmpxchg() = delete; | |
1312 InstX8632Cmpxchg(const InstX8632Cmpxchg &) = delete; | |
1313 InstX8632Cmpxchg &operator=(const InstX8632Cmpxchg &) = delete; | |
1314 | |
1315 public: | |
1316 static InstX8632Cmpxchg *create(Cfg *Func, Operand *DestOrAddr, Variable *Eax, | |
1317 Variable *Desired, bool Locked) { | |
1318 return new (Func->allocate<InstX8632Cmpxchg>()) | |
1319 InstX8632Cmpxchg(Func, DestOrAddr, Eax, Desired, Locked); | |
1320 } | |
1321 void emit(const Cfg *Func) const override; | |
1322 void emitIAS(const Cfg *Func) const override; | |
1323 void dump(const Cfg *Func) const override; | |
1324 static bool classof(const Inst *Inst) { return isClassof(Inst, Cmpxchg); } | |
1325 | |
1326 private: | |
1327 InstX8632Cmpxchg(Cfg *Func, Operand *DestOrAddr, Variable *Eax, | |
1328 Variable *Desired, bool Locked); | |
1329 }; | |
1330 | |
1331 /// Cmpxchg8b instruction - cmpxchg8b <m64> will compare if <m64> | |
1332 /// equals edx:eax. If so, the ZF is set and ecx:ebx is stored in <m64>. | |
1333 /// If not, ZF is cleared and <m64> is copied to edx:eax. | |
1334 /// The caller is responsible for inserting FakeDefs to mark edx | |
1335 /// and eax as modified. | |
1336 /// <m64> must be a memory operand. | |
1337 class InstX8632Cmpxchg8b : public InstX8632Lockable { | |
1338 InstX8632Cmpxchg8b() = delete; | |
1339 InstX8632Cmpxchg8b(const InstX8632Cmpxchg8b &) = delete; | |
1340 InstX8632Cmpxchg8b &operator=(const InstX8632Cmpxchg8b &) = delete; | |
1341 | |
1342 public: | |
1343 static InstX8632Cmpxchg8b *create(Cfg *Func, OperandX8632Mem *Dest, | |
1344 Variable *Edx, Variable *Eax, Variable *Ecx, | |
1345 Variable *Ebx, bool Locked) { | |
1346 return new (Func->allocate<InstX8632Cmpxchg8b>()) | |
1347 InstX8632Cmpxchg8b(Func, Dest, Edx, Eax, Ecx, Ebx, Locked); | |
1348 } | |
1349 void emit(const Cfg *Func) const override; | |
1350 void emitIAS(const Cfg *Func) const override; | |
1351 void dump(const Cfg *Func) const override; | |
1352 static bool classof(const Inst *Inst) { return isClassof(Inst, Cmpxchg8b); } | |
1353 | |
1354 private: | |
1355 InstX8632Cmpxchg8b(Cfg *Func, OperandX8632Mem *Dest, Variable *Edx, | |
1356 Variable *Eax, Variable *Ecx, Variable *Ebx, bool Locked); | |
1357 }; | |
1358 | |
1359 /// Cvt instruction - wrapper for cvtsX2sY where X and Y are in {s,d,i} | |
1360 /// as appropriate. s=float, d=double, i=int. X and Y are determined | |
1361 /// from dest/src types. Sign and zero extension on the integer | |
1362 /// operand needs to be done separately. | |
1363 class InstX8632Cvt : public InstX8632 { | |
1364 InstX8632Cvt() = delete; | |
1365 InstX8632Cvt(const InstX8632Cvt &) = delete; | |
1366 InstX8632Cvt &operator=(const InstX8632Cvt &) = delete; | |
1367 | |
1368 public: | |
1369 enum CvtVariant { Si2ss, Tss2si, Float2float, Dq2ps, Tps2dq }; | |
1370 static InstX8632Cvt *create(Cfg *Func, Variable *Dest, Operand *Source, | |
1371 CvtVariant Variant) { | |
1372 return new (Func->allocate<InstX8632Cvt>()) | |
1373 InstX8632Cvt(Func, Dest, Source, Variant); | |
1374 } | |
1375 void emit(const Cfg *Func) const override; | |
1376 void emitIAS(const Cfg *Func) const override; | |
1377 void dump(const Cfg *Func) const override; | |
1378 static bool classof(const Inst *Inst) { return isClassof(Inst, Cvt); } | |
1379 bool isTruncating() const { return Variant == Tss2si || Variant == Tps2dq; } | |
1380 | |
1381 private: | |
1382 CvtVariant Variant; | |
1383 InstX8632Cvt(Cfg *Func, Variable *Dest, Operand *Source, CvtVariant Variant); | |
1384 }; | |
1385 | |
1386 /// cmp - Integer compare instruction. | |
1387 class InstX8632Icmp : public InstX8632 { | |
1388 InstX8632Icmp() = delete; | |
1389 InstX8632Icmp(const InstX8632Icmp &) = delete; | |
1390 InstX8632Icmp &operator=(const InstX8632Icmp &) = delete; | |
1391 | |
1392 public: | |
1393 static InstX8632Icmp *create(Cfg *Func, Operand *Src1, Operand *Src2) { | |
1394 return new (Func->allocate<InstX8632Icmp>()) | |
1395 InstX8632Icmp(Func, Src1, Src2); | |
1396 } | |
1397 void emit(const Cfg *Func) const override; | |
1398 void emitIAS(const Cfg *Func) const override; | |
1399 void dump(const Cfg *Func) const override; | |
1400 static bool classof(const Inst *Inst) { return isClassof(Inst, Icmp); } | |
1401 | |
1402 private: | |
1403 InstX8632Icmp(Cfg *Func, Operand *Src1, Operand *Src2); | |
1404 }; | |
1405 | |
1406 /// ucomiss/ucomisd - floating-point compare instruction. | |
1407 class InstX8632Ucomiss : public InstX8632 { | |
1408 InstX8632Ucomiss() = delete; | |
1409 InstX8632Ucomiss(const InstX8632Ucomiss &) = delete; | |
1410 InstX8632Ucomiss &operator=(const InstX8632Ucomiss &) = delete; | |
1411 | |
1412 public: | |
1413 static InstX8632Ucomiss *create(Cfg *Func, Operand *Src1, Operand *Src2) { | |
1414 return new (Func->allocate<InstX8632Ucomiss>()) | |
1415 InstX8632Ucomiss(Func, Src1, Src2); | |
1416 } | |
1417 void emit(const Cfg *Func) const override; | |
1418 void emitIAS(const Cfg *Func) const override; | |
1419 void dump(const Cfg *Func) const override; | |
1420 static bool classof(const Inst *Inst) { return isClassof(Inst, Ucomiss); } | |
1421 | |
1422 private: | |
1423 InstX8632Ucomiss(Cfg *Func, Operand *Src1, Operand *Src2); | |
1424 }; | |
1425 | |
1426 /// UD2 instruction. | |
1427 class InstX8632UD2 : public InstX8632 { | |
1428 InstX8632UD2() = delete; | |
1429 InstX8632UD2(const InstX8632UD2 &) = delete; | |
1430 InstX8632UD2 &operator=(const InstX8632UD2 &) = delete; | |
1431 | |
1432 public: | |
1433 static InstX8632UD2 *create(Cfg *Func) { | |
1434 return new (Func->allocate<InstX8632UD2>()) InstX8632UD2(Func); | |
1435 } | |
1436 void emit(const Cfg *Func) const override; | |
1437 void emitIAS(const Cfg *Func) const override; | |
1438 void dump(const Cfg *Func) const override; | |
1439 static bool classof(const Inst *Inst) { return isClassof(Inst, UD2); } | |
1440 | |
1441 private: | |
1442 explicit InstX8632UD2(Cfg *Func); | |
1443 }; | |
1444 | |
1445 /// Test instruction. | |
1446 class InstX8632Test : public InstX8632 { | |
1447 InstX8632Test() = delete; | |
1448 InstX8632Test(const InstX8632Test &) = delete; | |
1449 InstX8632Test &operator=(const InstX8632Test &) = delete; | |
1450 | |
1451 public: | |
1452 static InstX8632Test *create(Cfg *Func, Operand *Source1, Operand *Source2) { | |
1453 return new (Func->allocate<InstX8632Test>()) | |
1454 InstX8632Test(Func, Source1, Source2); | |
1455 } | |
1456 void emit(const Cfg *Func) const override; | |
1457 void emitIAS(const Cfg *Func) const override; | |
1458 void dump(const Cfg *Func) const override; | |
1459 static bool classof(const Inst *Inst) { return isClassof(Inst, Test); } | |
1460 | |
1461 private: | |
1462 InstX8632Test(Cfg *Func, Operand *Source1, Operand *Source2); | |
1463 }; | |
1464 | |
1465 /// Mfence instruction. | |
1466 class InstX8632Mfence : public InstX8632 { | |
1467 InstX8632Mfence() = delete; | |
1468 InstX8632Mfence(const InstX8632Mfence &) = delete; | |
1469 InstX8632Mfence &operator=(const InstX8632Mfence &) = delete; | |
1470 | |
1471 public: | |
1472 static InstX8632Mfence *create(Cfg *Func) { | |
1473 return new (Func->allocate<InstX8632Mfence>()) InstX8632Mfence(Func); | |
1474 } | |
1475 void emit(const Cfg *Func) const override; | |
1476 void emitIAS(const Cfg *Func) const override; | |
1477 void dump(const Cfg *Func) const override; | |
1478 static bool classof(const Inst *Inst) { return isClassof(Inst, Mfence); } | |
1479 | |
1480 private: | |
1481 explicit InstX8632Mfence(Cfg *Func); | |
1482 }; | |
1483 | |
1484 /// This is essentially a "mov" instruction with an OperandX8632Mem | |
1485 /// operand instead of Variable as the destination. It's important | |
1486 /// for liveness that there is no Dest operand. | |
1487 class InstX8632Store : public InstX8632 { | |
1488 InstX8632Store() = delete; | |
1489 InstX8632Store(const InstX8632Store &) = delete; | |
1490 InstX8632Store &operator=(const InstX8632Store &) = delete; | |
1491 | |
1492 public: | |
1493 static InstX8632Store *create(Cfg *Func, Operand *Value, OperandX8632 *Mem) { | |
1494 return new (Func->allocate<InstX8632Store>()) | |
1495 InstX8632Store(Func, Value, Mem); | |
1496 } | |
1497 void emit(const Cfg *Func) const override; | |
1498 void emitIAS(const Cfg *Func) const override; | |
1499 void dump(const Cfg *Func) const override; | |
1500 static bool classof(const Inst *Inst) { return isClassof(Inst, Store); } | |
1501 | |
1502 private: | |
1503 InstX8632Store(Cfg *Func, Operand *Value, OperandX8632 *Mem); | |
1504 }; | |
1505 | |
1506 /// This is essentially a vector "mov" instruction with an OperandX8632Mem | |
1507 /// operand instead of Variable as the destination. It's important | |
1508 /// for liveness that there is no Dest operand. The source must be an | |
1509 /// Xmm register, since Dest is mem. | |
1510 class InstX8632StoreP : public InstX8632 { | |
1511 InstX8632StoreP() = delete; | |
1512 InstX8632StoreP(const InstX8632StoreP &) = delete; | |
1513 InstX8632StoreP &operator=(const InstX8632StoreP &) = delete; | |
1514 | |
1515 public: | |
1516 static InstX8632StoreP *create(Cfg *Func, Variable *Value, | |
1517 OperandX8632Mem *Mem) { | |
1518 return new (Func->allocate<InstX8632StoreP>()) | |
1519 InstX8632StoreP(Func, Value, Mem); | |
1520 } | |
1521 void emit(const Cfg *Func) const override; | |
1522 void emitIAS(const Cfg *Func) const override; | |
1523 void dump(const Cfg *Func) const override; | |
1524 static bool classof(const Inst *Inst) { return isClassof(Inst, StoreP); } | |
1525 | |
1526 private: | |
1527 InstX8632StoreP(Cfg *Func, Variable *Value, OperandX8632Mem *Mem); | |
1528 }; | |
1529 | |
1530 class InstX8632StoreQ : public InstX8632 { | |
1531 InstX8632StoreQ() = delete; | |
1532 InstX8632StoreQ(const InstX8632StoreQ &) = delete; | |
1533 InstX8632StoreQ &operator=(const InstX8632StoreQ &) = delete; | |
1534 | |
1535 public: | |
1536 static InstX8632StoreQ *create(Cfg *Func, Variable *Value, | |
1537 OperandX8632Mem *Mem) { | |
1538 return new (Func->allocate<InstX8632StoreQ>()) | |
1539 InstX8632StoreQ(Func, Value, Mem); | |
1540 } | |
1541 void emit(const Cfg *Func) const override; | |
1542 void emitIAS(const Cfg *Func) const override; | |
1543 void dump(const Cfg *Func) const override; | |
1544 static bool classof(const Inst *Inst) { return isClassof(Inst, StoreQ); } | |
1545 | |
1546 private: | |
1547 InstX8632StoreQ(Cfg *Func, Variable *Value, OperandX8632Mem *Mem); | |
1548 }; | |
1549 | |
1550 /// Nop instructions of varying length | |
1551 class InstX8632Nop : public InstX8632 { | |
1552 InstX8632Nop() = delete; | |
1553 InstX8632Nop(const InstX8632Nop &) = delete; | |
1554 InstX8632Nop &operator=(const InstX8632Nop &) = delete; | |
1555 | |
1556 public: | |
1557 // TODO: Replace with enum. | |
1558 typedef unsigned NopVariant; | |
1559 | |
1560 static InstX8632Nop *create(Cfg *Func, NopVariant Variant) { | |
1561 return new (Func->allocate<InstX8632Nop>()) InstX8632Nop(Func, Variant); | |
1562 } | |
1563 void emit(const Cfg *Func) const override; | |
1564 void emitIAS(const Cfg *Func) const override; | |
1565 void dump(const Cfg *Func) const override; | |
1566 static bool classof(const Inst *Inst) { return isClassof(Inst, Nop); } | |
1567 | |
1568 private: | |
1569 InstX8632Nop(Cfg *Func, SizeT Length); | |
1570 | |
1571 NopVariant Variant; | |
1572 }; | |
1573 | |
1574 /// Fld - load a value onto the x87 FP stack. | |
1575 class InstX8632Fld : public InstX8632 { | |
1576 InstX8632Fld() = delete; | |
1577 InstX8632Fld(const InstX8632Fld &) = delete; | |
1578 InstX8632Fld &operator=(const InstX8632Fld &) = delete; | |
1579 | |
1580 public: | |
1581 static InstX8632Fld *create(Cfg *Func, Operand *Src) { | |
1582 return new (Func->allocate<InstX8632Fld>()) InstX8632Fld(Func, Src); | |
1583 } | |
1584 void emit(const Cfg *Func) const override; | |
1585 void emitIAS(const Cfg *Func) const override; | |
1586 void dump(const Cfg *Func) const override; | |
1587 static bool classof(const Inst *Inst) { return isClassof(Inst, Fld); } | |
1588 | |
1589 private: | |
1590 InstX8632Fld(Cfg *Func, Operand *Src); | |
1591 }; | |
1592 | |
1593 /// Fstp - store x87 st(0) into memory and pop st(0). | |
1594 class InstX8632Fstp : public InstX8632 { | |
1595 InstX8632Fstp() = delete; | |
1596 InstX8632Fstp(const InstX8632Fstp &) = delete; | |
1597 InstX8632Fstp &operator=(const InstX8632Fstp &) = delete; | |
1598 | |
1599 public: | |
1600 static InstX8632Fstp *create(Cfg *Func, Variable *Dest) { | |
1601 return new (Func->allocate<InstX8632Fstp>()) InstX8632Fstp(Func, Dest); | |
1602 } | |
1603 void emit(const Cfg *Func) const override; | |
1604 void emitIAS(const Cfg *Func) const override; | |
1605 void dump(const Cfg *Func) const override; | |
1606 static bool classof(const Inst *Inst) { return isClassof(Inst, Fstp); } | |
1607 | |
1608 private: | |
1609 InstX8632Fstp(Cfg *Func, Variable *Dest); | |
1610 }; | |
1611 | |
1612 class InstX8632Pop : public InstX8632 { | |
1613 InstX8632Pop() = delete; | |
1614 InstX8632Pop(const InstX8632Pop &) = delete; | |
1615 InstX8632Pop &operator=(const InstX8632Pop &) = delete; | |
1616 | |
1617 public: | |
1618 static InstX8632Pop *create(Cfg *Func, Variable *Dest) { | |
1619 return new (Func->allocate<InstX8632Pop>()) InstX8632Pop(Func, Dest); | |
1620 } | |
1621 void emit(const Cfg *Func) const override; | |
1622 void emitIAS(const Cfg *Func) const override; | |
1623 void dump(const Cfg *Func) const override; | |
1624 static bool classof(const Inst *Inst) { return isClassof(Inst, Pop); } | |
1625 | |
1626 private: | |
1627 InstX8632Pop(Cfg *Func, Variable *Dest); | |
1628 }; | |
1629 | |
1630 class InstX8632Push : public InstX8632 { | |
1631 InstX8632Push() = delete; | |
1632 InstX8632Push(const InstX8632Push &) = delete; | |
1633 InstX8632Push &operator=(const InstX8632Push &) = delete; | |
1634 | |
1635 public: | |
1636 static InstX8632Push *create(Cfg *Func, Variable *Source) { | |
1637 return new (Func->allocate<InstX8632Push>()) InstX8632Push(Func, Source); | |
1638 } | |
1639 void emit(const Cfg *Func) const override; | |
1640 void emitIAS(const Cfg *Func) const override; | |
1641 void dump(const Cfg *Func) const override; | |
1642 static bool classof(const Inst *Inst) { return isClassof(Inst, Push); } | |
1643 | |
1644 private: | |
1645 InstX8632Push(Cfg *Func, Variable *Source); | |
1646 }; | |
1647 | |
1648 /// Ret instruction. Currently only supports the "ret" version that | |
1649 /// does not pop arguments. This instruction takes a Source operand | |
1650 /// (for non-void returning functions) for liveness analysis, though | |
1651 /// a FakeUse before the ret would do just as well. | |
1652 class InstX8632Ret : public InstX8632 { | |
1653 InstX8632Ret() = delete; | |
1654 InstX8632Ret(const InstX8632Ret &) = delete; | |
1655 InstX8632Ret &operator=(const InstX8632Ret &) = delete; | |
1656 | |
1657 public: | |
1658 static InstX8632Ret *create(Cfg *Func, Variable *Source = nullptr) { | |
1659 return new (Func->allocate<InstX8632Ret>()) InstX8632Ret(Func, Source); | |
1660 } | |
1661 void emit(const Cfg *Func) const override; | |
1662 void emitIAS(const Cfg *Func) const override; | |
1663 void dump(const Cfg *Func) const override; | |
1664 static bool classof(const Inst *Inst) { return isClassof(Inst, Ret); } | |
1665 | |
1666 private: | |
1667 InstX8632Ret(Cfg *Func, Variable *Source); | |
1668 }; | |
1669 | |
1670 /// Conditional set-byte instruction. | |
1671 class InstX8632Setcc : public InstX8632 { | |
1672 InstX8632Setcc() = delete; | |
1673 InstX8632Setcc(const InstX8632Cmov &) = delete; | |
1674 InstX8632Setcc &operator=(const InstX8632Setcc &) = delete; | |
1675 | |
1676 public: | |
1677 static InstX8632Setcc *create(Cfg *Func, Variable *Dest, | |
1678 X8632::Traits::Cond::BrCond Cond) { | |
1679 return new (Func->allocate<InstX8632Setcc>()) | |
1680 InstX8632Setcc(Func, Dest, Cond); | |
1681 } | |
1682 void emit(const Cfg *Func) const override; | |
1683 void emitIAS(const Cfg *Func) const override; | |
1684 void dump(const Cfg *Func) const override; | |
1685 static bool classof(const Inst *Inst) { return isClassof(Inst, Setcc); } | |
1686 | |
1687 private: | |
1688 InstX8632Setcc(Cfg *Func, Variable *Dest, X8632::Traits::Cond::BrCond Cond); | |
1689 | |
1690 const X8632::Traits::Cond::BrCond Condition; | |
1691 }; | |
1692 | |
1693 /// Exchanging Add instruction. Exchanges the first operand (destination | |
1694 /// operand) with the second operand (source operand), then loads the sum | |
1695 /// of the two values into the destination operand. The destination may be | |
1696 /// a register or memory, while the source must be a register. | |
1697 /// | |
1698 /// Both the dest and source are updated. The caller should then insert a | |
1699 /// FakeDef to reflect the second udpate. | |
1700 class InstX8632Xadd : public InstX8632Lockable { | |
1701 InstX8632Xadd() = delete; | |
1702 InstX8632Xadd(const InstX8632Xadd &) = delete; | |
1703 InstX8632Xadd &operator=(const InstX8632Xadd &) = delete; | |
1704 | |
1705 public: | |
1706 static InstX8632Xadd *create(Cfg *Func, Operand *Dest, Variable *Source, | |
1707 bool Locked) { | |
1708 return new (Func->allocate<InstX8632Xadd>()) | |
1709 InstX8632Xadd(Func, Dest, Source, Locked); | |
1710 } | |
1711 void emit(const Cfg *Func) const override; | |
1712 void emitIAS(const Cfg *Func) const override; | |
1713 void dump(const Cfg *Func) const override; | |
1714 static bool classof(const Inst *Inst) { return isClassof(Inst, Xadd); } | |
1715 | |
1716 private: | |
1717 InstX8632Xadd(Cfg *Func, Operand *Dest, Variable *Source, bool Locked); | |
1718 }; | |
1719 | |
1720 /// Exchange instruction. Exchanges the first operand (destination | |
1721 /// operand) with the second operand (source operand). At least one of | |
1722 /// the operands must be a register (and the other can be reg or mem). | |
1723 /// Both the Dest and Source are updated. If there is a memory operand, | |
1724 /// then the instruction is automatically "locked" without the need for | |
1725 /// a lock prefix. | |
1726 class InstX8632Xchg : public InstX8632 { | |
1727 InstX8632Xchg() = delete; | |
1728 InstX8632Xchg(const InstX8632Xchg &) = delete; | |
1729 InstX8632Xchg &operator=(const InstX8632Xchg &) = delete; | |
1730 | |
1731 public: | |
1732 static InstX8632Xchg *create(Cfg *Func, Operand *Dest, Variable *Source) { | |
1733 return new (Func->allocate<InstX8632Xchg>()) | |
1734 InstX8632Xchg(Func, Dest, Source); | |
1735 } | |
1736 void emit(const Cfg *Func) const override; | |
1737 void emitIAS(const Cfg *Func) const override; | |
1738 void dump(const Cfg *Func) const override; | |
1739 static bool classof(const Inst *Inst) { return isClassof(Inst, Xchg); } | |
1740 | |
1741 private: | |
1742 InstX8632Xchg(Cfg *Func, Operand *Dest, Variable *Source); | |
1743 }; | |
1744 | |
1745 /// Declare partial template specializations of emit() methods that | |
1746 /// already have default implementations. Without this, there is the | |
1747 /// possibility of ODR violations and link errors. | |
1748 template <> void InstX8632Addss::emit(const Cfg *Func) const; | |
1749 template <> void InstX8632Blendvps::emit(const Cfg *Func) const; | |
1750 template <> void InstX8632Cbwdq::emit(const Cfg *Func) const; | |
1751 template <> void InstX8632Div::emit(const Cfg *Func) const; | |
1752 template <> void InstX8632Divss::emit(const Cfg *Func) const; | |
1753 template <> void InstX8632Idiv::emit(const Cfg *Func) const; | |
1754 template <> void InstX8632Imul::emit(const Cfg *Func) const; | |
1755 template <> void InstX8632Lea::emit(const Cfg *Func) const; | |
1756 template <> void InstX8632Mulss::emit(const Cfg *Func) const; | |
1757 template <> void InstX8632Padd::emit(const Cfg *Func) const; | |
1758 template <> void InstX8632Pblendvb::emit(const Cfg *Func) const; | |
1759 template <> void InstX8632Pcmpeq::emit(const Cfg *Func) const; | |
1760 template <> void InstX8632Pcmpgt::emit(const Cfg *Func) const; | |
1761 template <> void InstX8632Pextr::emit(const Cfg *Func) const; | |
1762 template <> void InstX8632Pinsr::emit(const Cfg *Func) const; | |
1763 template <> void InstX8632Pmull::emit(const Cfg *Func) const; | |
1764 template <> void InstX8632Pmuludq::emit(const Cfg *Func) const; | |
1765 template <> void InstX8632Psll::emit(const Cfg *Func) const; | |
1766 template <> void InstX8632Psra::emit(const Cfg *Func) const; | |
1767 template <> void InstX8632Psrl::emit(const Cfg *Func) const; | |
1768 template <> void InstX8632Psub::emit(const Cfg *Func) const; | |
1769 template <> void InstX8632Sqrtss::emit(const Cfg *Func) const; | |
1770 template <> void InstX8632Subss::emit(const Cfg *Func) const; | |
1771 | |
1772 template <> void InstX8632Blendvps::emitIAS(const Cfg *Func) const; | |
1773 template <> void InstX8632Cbwdq::emitIAS(const Cfg *Func) const; | |
1774 template <> void InstX8632Div::emitIAS(const Cfg *Func) const; | |
1775 template <> void InstX8632Idiv::emitIAS(const Cfg *Func) const; | |
1776 template <> void InstX8632Imul::emitIAS(const Cfg *Func) const; | |
1777 template <> void InstX8632Insertps::emitIAS(const Cfg *Func) const; | |
1778 template <> void InstX8632Movd::emitIAS(const Cfg *Func) const; | |
1779 template <> void InstX8632MovssRegs::emitIAS(const Cfg *Func) const; | |
1780 template <> void InstX8632Pblendvb::emitIAS(const Cfg *Func) const; | |
1781 template <> void InstX8632Pextr::emitIAS(const Cfg *Func) const; | |
1782 template <> void InstX8632Pinsr::emitIAS(const Cfg *Func) const; | |
1783 template <> void InstX8632Movsx::emitIAS(const Cfg *Func) const; | |
1784 template <> void InstX8632Movzx::emitIAS(const Cfg *Func) const; | |
1785 template <> void InstX8632Pmull::emitIAS(const Cfg *Func) const; | |
1786 template <> void InstX8632Pshufd::emitIAS(const Cfg *Func) const; | |
1787 template <> void InstX8632Shufps::emitIAS(const Cfg *Func) const; | |
1788 | |
1789 } // end of namespace Ice | |
1790 | |
1791 #endif // SUBZERO_SRC_ICEINSTX8632_H | 37 #endif // SUBZERO_SRC_ICEINSTX8632_H |
OLD | NEW |