| 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 |