OLD | NEW |
1 //===- subzero/src/IceTargetLoweringX86Base.h - x86 lowering ----*- C++ -*-===// | 1 //===- subzero/src/IceTargetLoweringX86Base.h - x86 lowering ----*- 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 TargetLoweringX86 template class, which | 11 /// This file declares the TargetLoweringX86 template class, which implements |
12 /// implements the TargetLowering base interface for the x86 | 12 /// the TargetLowering base interface for the x86 architecture. |
13 /// architecture. | |
14 /// | 13 /// |
15 //===----------------------------------------------------------------------===// | 14 //===----------------------------------------------------------------------===// |
16 | 15 |
17 #ifndef SUBZERO_SRC_ICETARGETLOWERINGX86BASE_H | 16 #ifndef SUBZERO_SRC_ICETARGETLOWERINGX86BASE_H |
18 #define SUBZERO_SRC_ICETARGETLOWERINGX86BASE_H | 17 #define SUBZERO_SRC_ICETARGETLOWERINGX86BASE_H |
19 | 18 |
20 #include "IceDefs.h" | 19 #include "IceDefs.h" |
21 #include "IceInst.h" | 20 #include "IceInst.h" |
22 #include "IceSwitchLowering.h" | 21 #include "IceSwitchLowering.h" |
23 #include "IceTargetLowering.h" | 22 #include "IceTargetLowering.h" |
(...skipping 13 matching lines...) Expand all Loading... |
37 /// TargetX86Base is a template for all X86 Targets, and it relies on the CRT | 36 /// TargetX86Base is a template for all X86 Targets, and it relies on the CRT |
38 /// pattern for generating code, delegating to actual backends target-specific | 37 /// pattern for generating code, delegating to actual backends target-specific |
39 /// lowerings (e.g., call, ret, and intrinsics.) Backends are expected to | 38 /// lowerings (e.g., call, ret, and intrinsics.) Backends are expected to |
40 /// implement the following methods (which should be accessible from | 39 /// implement the following methods (which should be accessible from |
41 /// TargetX86Base): | 40 /// TargetX86Base): |
42 /// | 41 /// |
43 /// Operand *createNaClReadTPSrcOperand() | 42 /// Operand *createNaClReadTPSrcOperand() |
44 /// | 43 /// |
45 /// Note: Ideally, we should be able to | 44 /// Note: Ideally, we should be able to |
46 /// | 45 /// |
47 /// static_assert(std::is_base_of<TargetX86Base<Machine>, Machine>::value); | 46 /// static_assert(std::is_base_of<TargetX86Base<Machine>, Machine>::value); |
48 /// | 47 /// |
49 /// but that does not work: the compiler does not know that Machine inherits | 48 /// but that does not work: the compiler does not know that Machine inherits |
50 /// from TargetX86Base at this point in translation. | 49 /// from TargetX86Base at this point in translation. |
51 template <class Machine> class TargetX86Base : public TargetLowering { | 50 template <class Machine> class TargetX86Base : public TargetLowering { |
52 TargetX86Base() = delete; | 51 TargetX86Base() = delete; |
53 TargetX86Base(const TargetX86Base &) = delete; | 52 TargetX86Base(const TargetX86Base &) = delete; |
54 TargetX86Base &operator=(const TargetX86Base &) = delete; | 53 TargetX86Base &operator=(const TargetX86Base &) = delete; |
55 | 54 |
56 public: | 55 public: |
57 using Traits = MachineTraits<Machine>; | 56 using Traits = MachineTraits<Machine>; |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
99 | 98 |
100 const char *getConstantPrefix() const final { return "$"; } | 99 const char *getConstantPrefix() const final { return "$"; } |
101 void emit(const ConstantUndef *C) const final; | 100 void emit(const ConstantUndef *C) const final; |
102 void emit(const ConstantInteger32 *C) const final; | 101 void emit(const ConstantInteger32 *C) const final; |
103 void emit(const ConstantInteger64 *C) const final; | 102 void emit(const ConstantInteger64 *C) const final; |
104 void emit(const ConstantFloat *C) const final; | 103 void emit(const ConstantFloat *C) const final; |
105 void emit(const ConstantDouble *C) const final; | 104 void emit(const ConstantDouble *C) const final; |
106 | 105 |
107 void initNodeForLowering(CfgNode *Node) override; | 106 void initNodeForLowering(CfgNode *Node) override; |
108 /// x86-32: Ensure that a 64-bit Variable has been split into 2 32-bit | 107 /// x86-32: Ensure that a 64-bit Variable has been split into 2 32-bit |
109 /// Variables, creating them if necessary. This is needed for all | 108 /// Variables, creating them if necessary. This is needed for all I64 |
110 /// I64 operations, and it is needed for pushing F64 arguments for | 109 /// operations, and it is needed for pushing F64 arguments for function calls |
111 /// function calls using the 32-bit push instruction (though the | 110 /// using the 32-bit push instruction (though the latter could be done by |
112 /// latter could be done by directly writing to the stack). | 111 /// directly writing to the stack). |
113 /// | 112 /// |
114 /// x86-64: Complains loudly if invoked because the cpu can handle | 113 /// x86-64: Complains loudly if invoked because the cpu can handle 64-bit |
115 /// 64-bit types natively. | 114 /// types natively. |
116 template <typename T = Traits> | 115 template <typename T = Traits> |
117 typename std::enable_if<!T::Is64Bit, void>::type split64(Variable *Var); | 116 typename std::enable_if<!T::Is64Bit, void>::type split64(Variable *Var); |
118 template <typename T = Traits> | 117 template <typename T = Traits> |
119 typename std::enable_if<T::Is64Bit, void>::type split64(Variable *) { | 118 typename std::enable_if<T::Is64Bit, void>::type split64(Variable *) { |
120 llvm::report_fatal_error( | 119 llvm::report_fatal_error( |
121 "Hey, yo! This is x86-64. Watcha doin'? (split64)"); | 120 "Hey, yo! This is x86-64. Watcha doin'? (split64)"); |
122 } | 121 } |
123 | 122 |
124 template <typename T = Traits> | 123 template <typename T = Traits> |
125 typename std::enable_if<!T::Is64Bit, Operand>::type * | 124 typename std::enable_if<!T::Is64Bit, Operand>::type * |
(...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
232 | 231 |
233 using LowerBinOp = void (TargetX86Base::*)(Variable *, Operand *); | 232 using LowerBinOp = void (TargetX86Base::*)(Variable *, Operand *); |
234 void expandAtomicRMWAsCmpxchg(LowerBinOp op_lo, LowerBinOp op_hi, | 233 void expandAtomicRMWAsCmpxchg(LowerBinOp op_lo, LowerBinOp op_hi, |
235 Variable *Dest, Operand *Ptr, Operand *Val); | 234 Variable *Dest, Operand *Ptr, Operand *Val); |
236 | 235 |
237 void eliminateNextVectorSextInstruction(Variable *SignExtendedResult); | 236 void eliminateNextVectorSextInstruction(Variable *SignExtendedResult); |
238 | 237 |
239 void scalarizeArithmetic(InstArithmetic::OpKind K, Variable *Dest, | 238 void scalarizeArithmetic(InstArithmetic::OpKind K, Variable *Dest, |
240 Operand *Src0, Operand *Src1); | 239 Operand *Src0, Operand *Src1); |
241 | 240 |
242 /// Operand legalization helpers. To deal with address mode | 241 /// Operand legalization helpers. To deal with address mode constraints, the |
243 /// constraints, the helpers will create a new Operand and emit | 242 /// helpers will create a new Operand and emit instructions that guarantee |
244 /// instructions that guarantee that the Operand kind is one of those | 243 /// that the Operand kind is one of those indicated by the LegalMask (a |
245 /// indicated by the LegalMask (a bitmask of allowed kinds). If the | 244 /// bitmask of allowed kinds). If the input Operand is known to already meet |
246 /// input Operand is known to already meet the constraints, it may be | 245 /// the constraints, it may be simply returned as the result, without creating |
247 /// simply returned as the result, without creating any new | 246 /// any new instructions or operands. |
248 /// instructions or operands. | |
249 enum OperandLegalization { | 247 enum OperandLegalization { |
250 Legal_None = 0, | 248 Legal_None = 0, |
251 Legal_Reg = 1 << 0, // physical register, not stack location | 249 Legal_Reg = 1 << 0, // physical register, not stack location |
252 Legal_Imm = 1 << 1, | 250 Legal_Imm = 1 << 1, |
253 Legal_Mem = 1 << 2, // includes [eax+4*ecx] as well as [esp+12] | 251 Legal_Mem = 1 << 2, // includes [eax+4*ecx] as well as [esp+12] |
254 Legal_All = ~Legal_None | 252 Legal_All = ~Legal_None |
255 }; | 253 }; |
256 using LegalMask = uint32_t; | 254 using LegalMask = uint32_t; |
257 Operand *legalize(Operand *From, LegalMask Allowed = Legal_All, | 255 Operand *legalize(Operand *From, LegalMask Allowed = Legal_All, |
258 int32_t RegNum = Variable::NoRegister); | 256 int32_t RegNum = Variable::NoRegister); |
259 Variable *legalizeToReg(Operand *From, int32_t RegNum = Variable::NoRegister); | 257 Variable *legalizeToReg(Operand *From, int32_t RegNum = Variable::NoRegister); |
260 /// Legalize the first source operand for use in the cmp instruction. | 258 /// Legalize the first source operand for use in the cmp instruction. |
261 Operand *legalizeSrc0ForCmp(Operand *Src0, Operand *Src1); | 259 Operand *legalizeSrc0ForCmp(Operand *Src0, Operand *Src1); |
262 /// Turn a pointer operand into a memory operand that can be | 260 /// Turn a pointer operand into a memory operand that can be used by a real |
263 /// used by a real load/store operation. Legalizes the operand as well. | 261 /// load/store operation. Legalizes the operand as well. This is a nop if the |
264 /// This is a nop if the operand is already a legal memory operand. | 262 /// operand is already a legal memory operand. |
265 typename Traits::X86OperandMem *formMemoryOperand(Operand *Ptr, Type Ty, | 263 typename Traits::X86OperandMem *formMemoryOperand(Operand *Ptr, Type Ty, |
266 bool DoLegalize = true); | 264 bool DoLegalize = true); |
267 | 265 |
268 Variable *makeReg(Type Ty, int32_t RegNum = Variable::NoRegister); | 266 Variable *makeReg(Type Ty, int32_t RegNum = Variable::NoRegister); |
269 static Type stackSlotType(); | 267 static Type stackSlotType(); |
270 | 268 |
271 static constexpr uint32_t NoSizeLimit = 0; | 269 static constexpr uint32_t NoSizeLimit = 0; |
272 static const Type TypeForSize[]; | 270 static const Type TypeForSize[]; |
273 /// Returns the largest type which is equal to or larger than Size bytes. The | 271 /// Returns the largest type which is equal to or larger than Size bytes. The |
274 /// type is suitable for copying memory i.e. a load and store will be a | 272 /// type is suitable for copying memory i.e. a load and store will be a single |
275 /// single instruction (for example x86 will get f64 not i64). | 273 /// instruction (for example x86 will get f64 not i64). |
276 static Type largestTypeInSize(uint32_t Size, uint32_t MaxSize = NoSizeLimit); | 274 static Type largestTypeInSize(uint32_t Size, uint32_t MaxSize = NoSizeLimit); |
277 /// Returns the smallest type which is equal to or larger than Size bytes. If | 275 /// Returns the smallest type which is equal to or larger than Size bytes. If |
278 /// one doesn't exist then the largest type smaller than Size bytes is | 276 /// one doesn't exist then the largest type smaller than Size bytes is |
279 /// returned. The type is suitable for memory copies as described at | 277 /// returned. The type is suitable for memory copies as described at |
280 /// largestTypeInSize. | 278 /// largestTypeInSize. |
281 static Type firstTypeThatFitsSize(uint32_t Size, | 279 static Type firstTypeThatFitsSize(uint32_t Size, |
282 uint32_t MaxSize = NoSizeLimit); | 280 uint32_t MaxSize = NoSizeLimit); |
283 | 281 |
284 Variable *copyToReg(Operand *Src, int32_t RegNum = Variable::NoRegister); | 282 Variable *copyToReg(Operand *Src, int32_t RegNum = Variable::NoRegister); |
285 | 283 |
(...skipping 11 matching lines...) Expand all Loading... |
297 | 295 |
298 /// Return a memory operand corresponding to a stack allocated Variable. | 296 /// Return a memory operand corresponding to a stack allocated Variable. |
299 typename Traits::X86OperandMem * | 297 typename Traits::X86OperandMem * |
300 getMemoryOperandForStackSlot(Type Ty, Variable *Slot, uint32_t Offset = 0); | 298 getMemoryOperandForStackSlot(Type Ty, Variable *Slot, uint32_t Offset = 0); |
301 | 299 |
302 void | 300 void |
303 makeRandomRegisterPermutation(llvm::SmallVectorImpl<int32_t> &Permutation, | 301 makeRandomRegisterPermutation(llvm::SmallVectorImpl<int32_t> &Permutation, |
304 const llvm::SmallBitVector &ExcludeRegisters, | 302 const llvm::SmallBitVector &ExcludeRegisters, |
305 uint64_t Salt) const override; | 303 uint64_t Salt) const override; |
306 | 304 |
307 /// The following are helpers that insert lowered x86 instructions | 305 /// The following are helpers that insert lowered x86 instructions with |
308 /// with minimal syntactic overhead, so that the lowering code can | 306 /// minimal syntactic overhead, so that the lowering code can look as close to |
309 /// look as close to assembly as practical. | 307 /// assembly as practical. |
310 void _adc(Variable *Dest, Operand *Src0) { | 308 void _adc(Variable *Dest, Operand *Src0) { |
311 Context.insert(Traits::Insts::Adc::create(Func, Dest, Src0)); | 309 Context.insert(Traits::Insts::Adc::create(Func, Dest, Src0)); |
312 } | 310 } |
313 void _adc_rmw(typename Traits::X86OperandMem *DestSrc0, Operand *Src1) { | 311 void _adc_rmw(typename Traits::X86OperandMem *DestSrc0, Operand *Src1) { |
314 Context.insert(Traits::Insts::AdcRMW::create(Func, DestSrc0, Src1)); | 312 Context.insert(Traits::Insts::AdcRMW::create(Func, DestSrc0, Src1)); |
315 } | 313 } |
316 void _add(Variable *Dest, Operand *Src0) { | 314 void _add(Variable *Dest, Operand *Src0) { |
317 Context.insert(Traits::Insts::Add::create(Func, Dest, Src0)); | 315 Context.insert(Traits::Insts::Add::create(Func, Dest, Src0)); |
318 } | 316 } |
319 void _add_rmw(typename Traits::X86OperandMem *DestSrc0, Operand *Src1) { | 317 void _add_rmw(typename Traits::X86OperandMem *DestSrc0, Operand *Src1) { |
(...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
443 void _insertps(Variable *Dest, Operand *Src0, Operand *Src1) { | 441 void _insertps(Variable *Dest, Operand *Src0, Operand *Src1) { |
444 Context.insert(Traits::Insts::Insertps::create(Func, Dest, Src0, Src1)); | 442 Context.insert(Traits::Insts::Insertps::create(Func, Dest, Src0, Src1)); |
445 } | 443 } |
446 void _jmp(Operand *Target) { | 444 void _jmp(Operand *Target) { |
447 Context.insert(Traits::Insts::Jmp::create(Func, Target)); | 445 Context.insert(Traits::Insts::Jmp::create(Func, Target)); |
448 } | 446 } |
449 void _lea(Variable *Dest, Operand *Src0) { | 447 void _lea(Variable *Dest, Operand *Src0) { |
450 Context.insert(Traits::Insts::Lea::create(Func, Dest, Src0)); | 448 Context.insert(Traits::Insts::Lea::create(Func, Dest, Src0)); |
451 } | 449 } |
452 void _mfence() { Context.insert(Traits::Insts::Mfence::create(Func)); } | 450 void _mfence() { Context.insert(Traits::Insts::Mfence::create(Func)); } |
453 /// If Dest=nullptr is passed in, then a new variable is created, | 451 /// If Dest=nullptr is passed in, then a new variable is created, marked as |
454 /// marked as infinite register allocation weight, and returned | 452 /// infinite register allocation weight, and returned through the in/out Dest |
455 /// through the in/out Dest argument. | 453 /// argument. |
456 void _mov(Variable *&Dest, Operand *Src0, | 454 void _mov(Variable *&Dest, Operand *Src0, |
457 int32_t RegNum = Variable::NoRegister) { | 455 int32_t RegNum = Variable::NoRegister) { |
458 if (Dest == nullptr) | 456 if (Dest == nullptr) |
459 Dest = makeReg(Src0->getType(), RegNum); | 457 Dest = makeReg(Src0->getType(), RegNum); |
460 Context.insert(Traits::Insts::Mov::create(Func, Dest, Src0)); | 458 Context.insert(Traits::Insts::Mov::create(Func, Dest, Src0)); |
461 } | 459 } |
462 void _mov_nonkillable(Variable *Dest, Operand *Src0) { | 460 void _mov_nonkillable(Variable *Dest, Operand *Src0) { |
463 Inst *NewInst = Traits::Insts::Mov::create(Func, Dest, Src0); | 461 Inst *NewInst = Traits::Insts::Mov::create(Func, Dest, Src0); |
464 NewInst->setDestNonKillable(); | 462 NewInst->setDestNonKillable(); |
465 Context.insert(NewInst); | 463 Context.insert(NewInst); |
(...skipping 153 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
619 } | 617 } |
620 void _test(Operand *Src0, Operand *Src1) { | 618 void _test(Operand *Src0, Operand *Src1) { |
621 Context.insert(Traits::Insts::Test::create(Func, Src0, Src1)); | 619 Context.insert(Traits::Insts::Test::create(Func, Src0, Src1)); |
622 } | 620 } |
623 void _ucomiss(Operand *Src0, Operand *Src1) { | 621 void _ucomiss(Operand *Src0, Operand *Src1) { |
624 Context.insert(Traits::Insts::Ucomiss::create(Func, Src0, Src1)); | 622 Context.insert(Traits::Insts::Ucomiss::create(Func, Src0, Src1)); |
625 } | 623 } |
626 void _ud2() { Context.insert(Traits::Insts::UD2::create(Func)); } | 624 void _ud2() { Context.insert(Traits::Insts::UD2::create(Func)); } |
627 void _xadd(Operand *Dest, Variable *Src, bool Locked) { | 625 void _xadd(Operand *Dest, Variable *Src, bool Locked) { |
628 Context.insert(Traits::Insts::Xadd::create(Func, Dest, Src, Locked)); | 626 Context.insert(Traits::Insts::Xadd::create(Func, Dest, Src, Locked)); |
629 // The xadd exchanges Dest and Src (modifying Src). | 627 // The xadd exchanges Dest and Src (modifying Src). Model that update with |
630 // Model that update with a FakeDef followed by a FakeUse. | 628 // a FakeDef followed by a FakeUse. |
631 Context.insert( | 629 Context.insert( |
632 InstFakeDef::create(Func, Src, llvm::dyn_cast<Variable>(Dest))); | 630 InstFakeDef::create(Func, Src, llvm::dyn_cast<Variable>(Dest))); |
633 _set_dest_nonkillable(); | 631 _set_dest_nonkillable(); |
634 Context.insert(InstFakeUse::create(Func, Src)); | 632 Context.insert(InstFakeUse::create(Func, Src)); |
635 } | 633 } |
636 void _xchg(Operand *Dest, Variable *Src) { | 634 void _xchg(Operand *Dest, Variable *Src) { |
637 Context.insert(Traits::Insts::Xchg::create(Func, Dest, Src)); | 635 Context.insert(Traits::Insts::Xchg::create(Func, Dest, Src)); |
638 // The xchg modifies Dest and Src -- model that update with a | 636 // The xchg modifies Dest and Src -- model that update with a |
639 // FakeDef/FakeUse. | 637 // FakeDef/FakeUse. |
640 Context.insert( | 638 Context.insert( |
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
727 } | 725 } |
728 | 726 |
729 BoolFolding FoldingInfo; | 727 BoolFolding FoldingInfo; |
730 }; | 728 }; |
731 } // end of namespace X86Internal | 729 } // end of namespace X86Internal |
732 } // end of namespace Ice | 730 } // end of namespace Ice |
733 | 731 |
734 #include "IceTargetLoweringX86BaseImpl.h" | 732 #include "IceTargetLoweringX86BaseImpl.h" |
735 | 733 |
736 #endif // SUBZERO_SRC_ICETARGETLOWERINGX86BASE_H | 734 #endif // SUBZERO_SRC_ICETARGETLOWERINGX86BASE_H |
OLD | NEW |