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...) 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...) 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 105 matching lines...) Loading... |
231 | 230 |
232 using LowerBinOp = void (TargetX86Base::*)(Variable *, Operand *); | 231 using LowerBinOp = void (TargetX86Base::*)(Variable *, Operand *); |
233 void expandAtomicRMWAsCmpxchg(LowerBinOp op_lo, LowerBinOp op_hi, | 232 void expandAtomicRMWAsCmpxchg(LowerBinOp op_lo, LowerBinOp op_hi, |
234 Variable *Dest, Operand *Ptr, Operand *Val); | 233 Variable *Dest, Operand *Ptr, Operand *Val); |
235 | 234 |
236 void eliminateNextVectorSextInstruction(Variable *SignExtendedResult); | 235 void eliminateNextVectorSextInstruction(Variable *SignExtendedResult); |
237 | 236 |
238 void scalarizeArithmetic(InstArithmetic::OpKind K, Variable *Dest, | 237 void scalarizeArithmetic(InstArithmetic::OpKind K, Variable *Dest, |
239 Operand *Src0, Operand *Src1); | 238 Operand *Src0, Operand *Src1); |
240 | 239 |
241 /// Operand legalization helpers. To deal with address mode | 240 /// Operand legalization helpers. To deal with address mode constraints, the |
242 /// constraints, the helpers will create a new Operand and emit | 241 /// helpers will create a new Operand and emit instructions that guarantee |
243 /// instructions that guarantee that the Operand kind is one of those | 242 /// that the Operand kind is one of those indicated by the LegalMask (a |
244 /// indicated by the LegalMask (a bitmask of allowed kinds). If the | 243 /// bitmask of allowed kinds). If the input Operand is known to already meet |
245 /// input Operand is known to already meet the constraints, it may be | 244 /// the constraints, it may be simply returned as the result, without creating |
246 /// simply returned as the result, without creating any new | 245 /// any new instructions or operands. |
247 /// instructions or operands. | |
248 enum OperandLegalization { | 246 enum OperandLegalization { |
249 Legal_None = 0, | 247 Legal_None = 0, |
250 Legal_Reg = 1 << 0, // physical register, not stack location | 248 Legal_Reg = 1 << 0, // physical register, not stack location |
251 Legal_Imm = 1 << 1, | 249 Legal_Imm = 1 << 1, |
252 Legal_Mem = 1 << 2, // includes [eax+4*ecx] as well as [esp+12] | 250 Legal_Mem = 1 << 2, // includes [eax+4*ecx] as well as [esp+12] |
253 Legal_All = ~Legal_None | 251 Legal_All = ~Legal_None |
254 }; | 252 }; |
255 using LegalMask = uint32_t; | 253 using LegalMask = uint32_t; |
256 Operand *legalize(Operand *From, LegalMask Allowed = Legal_All, | 254 Operand *legalize(Operand *From, LegalMask Allowed = Legal_All, |
257 int32_t RegNum = Variable::NoRegister); | 255 int32_t RegNum = Variable::NoRegister); |
258 Variable *legalizeToReg(Operand *From, int32_t RegNum = Variable::NoRegister); | 256 Variable *legalizeToReg(Operand *From, int32_t RegNum = Variable::NoRegister); |
259 /// Legalize the first source operand for use in the cmp instruction. | 257 /// Legalize the first source operand for use in the cmp instruction. |
260 Operand *legalizeSrc0ForCmp(Operand *Src0, Operand *Src1); | 258 Operand *legalizeSrc0ForCmp(Operand *Src0, Operand *Src1); |
261 /// Turn a pointer operand into a memory operand that can be | 259 /// Turn a pointer operand into a memory operand that can be used by a real |
262 /// used by a real load/store operation. Legalizes the operand as well. | 260 /// load/store operation. Legalizes the operand as well. This is a nop if the |
263 /// This is a nop if the operand is already a legal memory operand. | 261 /// operand is already a legal memory operand. |
264 typename Traits::X86OperandMem *formMemoryOperand(Operand *Ptr, Type Ty, | 262 typename Traits::X86OperandMem *formMemoryOperand(Operand *Ptr, Type Ty, |
265 bool DoLegalize = true); | 263 bool DoLegalize = true); |
266 | 264 |
267 Variable *makeReg(Type Ty, int32_t RegNum = Variable::NoRegister); | 265 Variable *makeReg(Type Ty, int32_t RegNum = Variable::NoRegister); |
268 static Type stackSlotType(); | 266 static Type stackSlotType(); |
269 | 267 |
270 static constexpr uint32_t NoSizeLimit = 0; | 268 static constexpr uint32_t NoSizeLimit = 0; |
271 static const Type TypeForSize[]; | 269 static const Type TypeForSize[]; |
272 /// Returns the largest type which is equal to or larger than Size bytes. The | 270 /// Returns the largest type which is equal to or larger than Size bytes. The |
273 /// type is suitable for copying memory i.e. a load and store will be a | 271 /// type is suitable for copying memory i.e. a load and store will be a single |
274 /// single instruction (for example x86 will get f64 not i64). | 272 /// instruction (for example x86 will get f64 not i64). |
275 static Type largestTypeInSize(uint32_t Size, uint32_t MaxSize = NoSizeLimit); | 273 static Type largestTypeInSize(uint32_t Size, uint32_t MaxSize = NoSizeLimit); |
276 /// Returns the smallest type which is equal to or larger than Size bytes. If | 274 /// Returns the smallest type which is equal to or larger than Size bytes. If |
277 /// one doesn't exist then the largest type smaller than Size bytes is | 275 /// one doesn't exist then the largest type smaller than Size bytes is |
278 /// returned. The type is suitable for memory copies as described at | 276 /// returned. The type is suitable for memory copies as described at |
279 /// largestTypeInSize. | 277 /// largestTypeInSize. |
280 static Type firstTypeThatFitsSize(uint32_t Size, | 278 static Type firstTypeThatFitsSize(uint32_t Size, |
281 uint32_t MaxSize = NoSizeLimit); | 279 uint32_t MaxSize = NoSizeLimit); |
282 | 280 |
283 Variable *copyToReg(Operand *Src, int32_t RegNum = Variable::NoRegister); | 281 Variable *copyToReg(Operand *Src, int32_t RegNum = Variable::NoRegister); |
284 | 282 |
(...skipping 11 matching lines...) Loading... |
296 | 294 |
297 /// Return a memory operand corresponding to a stack allocated Variable. | 295 /// Return a memory operand corresponding to a stack allocated Variable. |
298 typename Traits::X86OperandMem * | 296 typename Traits::X86OperandMem * |
299 getMemoryOperandForStackSlot(Type Ty, Variable *Slot, uint32_t Offset = 0); | 297 getMemoryOperandForStackSlot(Type Ty, Variable *Slot, uint32_t Offset = 0); |
300 | 298 |
301 void | 299 void |
302 makeRandomRegisterPermutation(llvm::SmallVectorImpl<int32_t> &Permutation, | 300 makeRandomRegisterPermutation(llvm::SmallVectorImpl<int32_t> &Permutation, |
303 const llvm::SmallBitVector &ExcludeRegisters, | 301 const llvm::SmallBitVector &ExcludeRegisters, |
304 uint64_t Salt) const override; | 302 uint64_t Salt) const override; |
305 | 303 |
306 /// The following are helpers that insert lowered x86 instructions | 304 /// The following are helpers that insert lowered x86 instructions with |
307 /// with minimal syntactic overhead, so that the lowering code can | 305 /// minimal syntactic overhead, so that the lowering code can look as close to |
308 /// look as close to assembly as practical. | 306 /// assembly as practical. |
309 void _adc(Variable *Dest, Operand *Src0) { | 307 void _adc(Variable *Dest, Operand *Src0) { |
310 Context.insert(Traits::Insts::Adc::create(Func, Dest, Src0)); | 308 Context.insert(Traits::Insts::Adc::create(Func, Dest, Src0)); |
311 } | 309 } |
312 void _adc_rmw(typename Traits::X86OperandMem *DestSrc0, Operand *Src1) { | 310 void _adc_rmw(typename Traits::X86OperandMem *DestSrc0, Operand *Src1) { |
313 Context.insert(Traits::Insts::AdcRMW::create(Func, DestSrc0, Src1)); | 311 Context.insert(Traits::Insts::AdcRMW::create(Func, DestSrc0, Src1)); |
314 } | 312 } |
315 void _add(Variable *Dest, Operand *Src0) { | 313 void _add(Variable *Dest, Operand *Src0) { |
316 Context.insert(Traits::Insts::Add::create(Func, Dest, Src0)); | 314 Context.insert(Traits::Insts::Add::create(Func, Dest, Src0)); |
317 } | 315 } |
318 void _add_rmw(typename Traits::X86OperandMem *DestSrc0, Operand *Src1) { | 316 void _add_rmw(typename Traits::X86OperandMem *DestSrc0, Operand *Src1) { |
(...skipping 123 matching lines...) Loading... |
442 void _insertps(Variable *Dest, Operand *Src0, Operand *Src1) { | 440 void _insertps(Variable *Dest, Operand *Src0, Operand *Src1) { |
443 Context.insert(Traits::Insts::Insertps::create(Func, Dest, Src0, Src1)); | 441 Context.insert(Traits::Insts::Insertps::create(Func, Dest, Src0, Src1)); |
444 } | 442 } |
445 void _jmp(Operand *Target) { | 443 void _jmp(Operand *Target) { |
446 Context.insert(Traits::Insts::Jmp::create(Func, Target)); | 444 Context.insert(Traits::Insts::Jmp::create(Func, Target)); |
447 } | 445 } |
448 void _lea(Variable *Dest, Operand *Src0) { | 446 void _lea(Variable *Dest, Operand *Src0) { |
449 Context.insert(Traits::Insts::Lea::create(Func, Dest, Src0)); | 447 Context.insert(Traits::Insts::Lea::create(Func, Dest, Src0)); |
450 } | 448 } |
451 void _mfence() { Context.insert(Traits::Insts::Mfence::create(Func)); } | 449 void _mfence() { Context.insert(Traits::Insts::Mfence::create(Func)); } |
452 /// If Dest=nullptr is passed in, then a new variable is created, | 450 /// If Dest=nullptr is passed in, then a new variable is created, marked as |
453 /// marked as infinite register allocation weight, and returned | 451 /// infinite register allocation weight, and returned through the in/out Dest |
454 /// through the in/out Dest argument. | 452 /// argument. |
455 void _mov(Variable *&Dest, Operand *Src0, | 453 void _mov(Variable *&Dest, Operand *Src0, |
456 int32_t RegNum = Variable::NoRegister) { | 454 int32_t RegNum = Variable::NoRegister) { |
457 if (Dest == nullptr) | 455 if (Dest == nullptr) |
458 Dest = makeReg(Src0->getType(), RegNum); | 456 Dest = makeReg(Src0->getType(), RegNum); |
459 Context.insert(Traits::Insts::Mov::create(Func, Dest, Src0)); | 457 Context.insert(Traits::Insts::Mov::create(Func, Dest, Src0)); |
460 } | 458 } |
461 void _mov_nonkillable(Variable *Dest, Operand *Src0) { | 459 void _mov_nonkillable(Variable *Dest, Operand *Src0) { |
462 Inst *NewInst = Traits::Insts::Mov::create(Func, Dest, Src0); | 460 Inst *NewInst = Traits::Insts::Mov::create(Func, Dest, Src0); |
463 NewInst->setDestNonKillable(); | 461 NewInst->setDestNonKillable(); |
464 Context.insert(NewInst); | 462 Context.insert(NewInst); |
(...skipping 153 matching lines...) Loading... |
618 } | 616 } |
619 void _test(Operand *Src0, Operand *Src1) { | 617 void _test(Operand *Src0, Operand *Src1) { |
620 Context.insert(Traits::Insts::Test::create(Func, Src0, Src1)); | 618 Context.insert(Traits::Insts::Test::create(Func, Src0, Src1)); |
621 } | 619 } |
622 void _ucomiss(Operand *Src0, Operand *Src1) { | 620 void _ucomiss(Operand *Src0, Operand *Src1) { |
623 Context.insert(Traits::Insts::Ucomiss::create(Func, Src0, Src1)); | 621 Context.insert(Traits::Insts::Ucomiss::create(Func, Src0, Src1)); |
624 } | 622 } |
625 void _ud2() { Context.insert(Traits::Insts::UD2::create(Func)); } | 623 void _ud2() { Context.insert(Traits::Insts::UD2::create(Func)); } |
626 void _xadd(Operand *Dest, Variable *Src, bool Locked) { | 624 void _xadd(Operand *Dest, Variable *Src, bool Locked) { |
627 Context.insert(Traits::Insts::Xadd::create(Func, Dest, Src, Locked)); | 625 Context.insert(Traits::Insts::Xadd::create(Func, Dest, Src, Locked)); |
628 // The xadd exchanges Dest and Src (modifying Src). | 626 // The xadd exchanges Dest and Src (modifying Src). Model that update with |
629 // Model that update with a FakeDef followed by a FakeUse. | 627 // a FakeDef followed by a FakeUse. |
630 Context.insert( | 628 Context.insert( |
631 InstFakeDef::create(Func, Src, llvm::dyn_cast<Variable>(Dest))); | 629 InstFakeDef::create(Func, Src, llvm::dyn_cast<Variable>(Dest))); |
632 _set_dest_nonkillable(); | 630 _set_dest_nonkillable(); |
633 Context.insert(InstFakeUse::create(Func, Src)); | 631 Context.insert(InstFakeUse::create(Func, Src)); |
634 } | 632 } |
635 void _xchg(Operand *Dest, Variable *Src) { | 633 void _xchg(Operand *Dest, Variable *Src) { |
636 Context.insert(Traits::Insts::Xchg::create(Func, Dest, Src)); | 634 Context.insert(Traits::Insts::Xchg::create(Func, Dest, Src)); |
637 // The xchg modifies Dest and Src -- model that update with a | 635 // The xchg modifies Dest and Src -- model that update with a |
638 // FakeDef/FakeUse. | 636 // FakeDef/FakeUse. |
639 Context.insert( | 637 Context.insert( |
(...skipping 86 matching lines...) Loading... |
726 } | 724 } |
727 | 725 |
728 BoolFolding FoldingInfo; | 726 BoolFolding FoldingInfo; |
729 }; | 727 }; |
730 } // end of namespace X86Internal | 728 } // end of namespace X86Internal |
731 } // end of namespace Ice | 729 } // end of namespace Ice |
732 | 730 |
733 #include "IceTargetLoweringX86BaseImpl.h" | 731 #include "IceTargetLoweringX86BaseImpl.h" |
734 | 732 |
735 #endif // SUBZERO_SRC_ICETARGETLOWERINGX86BASE_H | 733 #endif // SUBZERO_SRC_ICETARGETLOWERINGX86BASE_H |
OLD | NEW |