| 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 105 matching lines...) Expand 10 before | Expand all | Expand 10 after 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...) Expand all 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...) Expand 10 before | Expand all | Expand 10 after 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...) Expand 10 before | Expand all | Expand 10 after 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...) Expand 10 before | Expand all | Expand 10 after 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 |