| OLD | NEW |
| 1 //===- subzero/src/IceTargetLoweringX8632.cpp - x86-32 lowering -----------===// | 1 //===- subzero/src/IceTargetLoweringX8632.cpp - x86-32 lowering -----------===// |
| 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 // This file implements the TargetLoweringX8632 class, which | 10 // This file implements the TargetLoweringX8632 class, which |
| (...skipping 879 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 890 this->FrameSizeLocals = NextStackOffset - SpillAreaPaddingBytes; | 890 this->FrameSizeLocals = NextStackOffset - SpillAreaPaddingBytes; |
| 891 this->HasComputedFrame = true; | 891 this->HasComputedFrame = true; |
| 892 | 892 |
| 893 // Assign stack offsets to variables that have been linked to spilled | 893 // Assign stack offsets to variables that have been linked to spilled |
| 894 // variables. | 894 // variables. |
| 895 for (Variable *Var : VariablesLinkedToSpillSlots) { | 895 for (Variable *Var : VariablesLinkedToSpillSlots) { |
| 896 Variable *Linked = (llvm::cast<SpillVariable>(Var))->getLinkedTo(); | 896 Variable *Linked = (llvm::cast<SpillVariable>(Var))->getLinkedTo(); |
| 897 Var->setStackOffset(Linked->getStackOffset()); | 897 Var->setStackOffset(Linked->getStackOffset()); |
| 898 } | 898 } |
| 899 | 899 |
| 900 if (ALLOW_DUMP && Func->getContext()->isVerbose(IceV_Frame)) { | 900 if (ALLOW_DUMP && Func->isVerbose(IceV_Frame)) { |
| 901 OstreamLocker L(Func->getContext()); | 901 OstreamLocker L(Func->getContext()); |
| 902 Ostream &Str = Func->getContext()->getStrDump(); | 902 Ostream &Str = Func->getContext()->getStrDump(); |
| 903 | 903 |
| 904 Str << "Stack layout:\n"; | 904 Str << "Stack layout:\n"; |
| 905 uint32_t EspAdjustmentPaddingSize = | 905 uint32_t EspAdjustmentPaddingSize = |
| 906 SpillAreaSizeBytes - LocalsSpillAreaSize - | 906 SpillAreaSizeBytes - LocalsSpillAreaSize - |
| 907 GlobalsAndSubsequentPaddingSize - SpillAreaPaddingBytes; | 907 GlobalsAndSubsequentPaddingSize - SpillAreaPaddingBytes; |
| 908 Str << " in-args = " << InArgsSizeBytes << " bytes\n" | 908 Str << " in-args = " << InArgsSizeBytes << " bytes\n" |
| 909 << " return address = " << X86_RET_IP_SIZE_BYTES << " bytes\n" | 909 << " return address = " << X86_RET_IP_SIZE_BYTES << " bytes\n" |
| 910 << " preserved registers = " << PreservedRegsSizeBytes << " bytes\n" | 910 << " preserved registers = " << PreservedRegsSizeBytes << " bytes\n" |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 959 for (SizeT i = 0; i < CalleeSaves.size(); ++i) { | 959 for (SizeT i = 0; i < CalleeSaves.size(); ++i) { |
| 960 SizeT j = CalleeSaves.size() - i - 1; | 960 SizeT j = CalleeSaves.size() - i - 1; |
| 961 if (j == RegX8632::Reg_ebp && IsEbpBasedFrame) | 961 if (j == RegX8632::Reg_ebp && IsEbpBasedFrame) |
| 962 continue; | 962 continue; |
| 963 if (CalleeSaves[j] && RegsUsed[j]) { | 963 if (CalleeSaves[j] && RegsUsed[j]) { |
| 964 _pop(getPhysicalRegister(j)); | 964 _pop(getPhysicalRegister(j)); |
| 965 } | 965 } |
| 966 } | 966 } |
| 967 } | 967 } |
| 968 | 968 |
| 969 template <typename T> struct PoolTypeConverter {}; | |
| 970 | |
| 971 template <> struct PoolTypeConverter<float> { | |
| 972 typedef uint32_t PrimitiveIntType; | |
| 973 typedef ConstantFloat IceType; | |
| 974 static const Type Ty = IceType_f32; | |
| 975 static const char *TypeName; | |
| 976 static const char *AsmTag; | |
| 977 static const char *PrintfString; | |
| 978 }; | |
| 979 const char *PoolTypeConverter<float>::TypeName = "float"; | |
| 980 const char *PoolTypeConverter<float>::AsmTag = ".long"; | |
| 981 const char *PoolTypeConverter<float>::PrintfString = "0x%x"; | |
| 982 | |
| 983 template <> struct PoolTypeConverter<double> { | |
| 984 typedef uint64_t PrimitiveIntType; | |
| 985 typedef ConstantDouble IceType; | |
| 986 static const Type Ty = IceType_f64; | |
| 987 static const char *TypeName; | |
| 988 static const char *AsmTag; | |
| 989 static const char *PrintfString; | |
| 990 }; | |
| 991 const char *PoolTypeConverter<double>::TypeName = "double"; | |
| 992 const char *PoolTypeConverter<double>::AsmTag = ".quad"; | |
| 993 const char *PoolTypeConverter<double>::PrintfString = "0x%llx"; | |
| 994 | |
| 995 template <typename T> void TargetX8632::emitConstantPool() const { | |
| 996 // Note: Still used by emit IAS. | |
| 997 Ostream &Str = Ctx->getStrEmit(); | |
| 998 Type Ty = T::Ty; | |
| 999 SizeT Align = typeAlignInBytes(Ty); | |
| 1000 ConstantList Pool = Ctx->getConstantPool(Ty); | |
| 1001 | |
| 1002 Str << "\t.section\t.rodata.cst" << Align << ",\"aM\",@progbits," << Align | |
| 1003 << "\n"; | |
| 1004 Str << "\t.align\t" << Align << "\n"; | |
| 1005 for (Constant *C : Pool) { | |
| 1006 typename T::IceType *Const = llvm::cast<typename T::IceType>(C); | |
| 1007 typename T::IceType::PrimType Value = Const->getValue(); | |
| 1008 // Use memcpy() to copy bits from Value into RawValue in a way | |
| 1009 // that avoids breaking strict-aliasing rules. | |
| 1010 typename T::PrimitiveIntType RawValue; | |
| 1011 memcpy(&RawValue, &Value, sizeof(Value)); | |
| 1012 char buf[30]; | |
| 1013 int CharsPrinted = | |
| 1014 snprintf(buf, llvm::array_lengthof(buf), T::PrintfString, RawValue); | |
| 1015 assert(CharsPrinted >= 0 && | |
| 1016 (size_t)CharsPrinted < llvm::array_lengthof(buf)); | |
| 1017 (void)CharsPrinted; // avoid warnings if asserts are disabled | |
| 1018 Const->emitPoolLabel(Str); | |
| 1019 Str << ":\n\t" << T::AsmTag << "\t" << buf << "\t# " << T::TypeName << " " | |
| 1020 << Value << "\n"; | |
| 1021 } | |
| 1022 } | |
| 1023 | |
| 1024 void TargetX8632::emitConstants() const { | |
| 1025 // No need to emit constants from the int pool since (for x86) they | |
| 1026 // are embedded as immediates in the instructions, just emit float/double. | |
| 1027 if (Ctx->getFlags().UseELFWriter) { | |
| 1028 ELFObjectWriter *Writer = Ctx->getObjectWriter(); | |
| 1029 Writer->writeConstantPool<ConstantFloat>(IceType_f32); | |
| 1030 Writer->writeConstantPool<ConstantDouble>(IceType_f64); | |
| 1031 } else { | |
| 1032 OstreamLocker L(Ctx); | |
| 1033 emitConstantPool<PoolTypeConverter<float>>(); | |
| 1034 emitConstantPool<PoolTypeConverter<double>>(); | |
| 1035 } | |
| 1036 } | |
| 1037 | |
| 1038 void TargetX8632::split64(Variable *Var) { | 969 void TargetX8632::split64(Variable *Var) { |
| 1039 switch (Var->getType()) { | 970 switch (Var->getType()) { |
| 1040 default: | 971 default: |
| 1041 return; | 972 return; |
| 1042 case IceType_i64: | 973 case IceType_i64: |
| 1043 // TODO: Only consider F64 if we need to push each half when | 974 // TODO: Only consider F64 if we need to push each half when |
| 1044 // passing as an argument to a function call. Note that each half | 975 // passing as an argument to a function call. Note that each half |
| 1045 // is still typed as I32. | 976 // is still typed as I32. |
| 1046 case IceType_f64: | 977 case IceType_f64: |
| 1047 break; | 978 break; |
| (...skipping 2512 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3560 return (Arith->getOp() == InstArithmetic::Add); | 3491 return (Arith->getOp() == InstArithmetic::Add); |
| 3561 } | 3492 } |
| 3562 return false; | 3493 return false; |
| 3563 } | 3494 } |
| 3564 | 3495 |
| 3565 void dumpAddressOpt(const Cfg *Func, const Variable *Base, | 3496 void dumpAddressOpt(const Cfg *Func, const Variable *Base, |
| 3566 const Variable *Index, uint16_t Shift, int32_t Offset, | 3497 const Variable *Index, uint16_t Shift, int32_t Offset, |
| 3567 const Inst *Reason) { | 3498 const Inst *Reason) { |
| 3568 if (!ALLOW_DUMP) | 3499 if (!ALLOW_DUMP) |
| 3569 return; | 3500 return; |
| 3570 if (!Func->getContext()->isVerbose(IceV_AddrOpt)) | 3501 if (!Func->isVerbose(IceV_AddrOpt)) |
| 3571 return; | 3502 return; |
| 3572 OstreamLocker L(Func->getContext()); | 3503 OstreamLocker L(Func->getContext()); |
| 3573 Ostream &Str = Func->getContext()->getStrDump(); | 3504 Ostream &Str = Func->getContext()->getStrDump(); |
| 3574 Str << "Instruction: "; | 3505 Str << "Instruction: "; |
| 3575 Reason->dumpDecorated(Func); | 3506 Reason->dumpDecorated(Func); |
| 3576 Str << " results in Base="; | 3507 Str << " results in Base="; |
| 3577 if (Base) | 3508 if (Base) |
| 3578 Base->dump(Func); | 3509 Base->dump(Func); |
| 3579 else | 3510 else |
| 3580 Str << "<null>"; | 3511 Str << "<null>"; |
| (...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3733 Offset += MoreOffset; | 3664 Offset += MoreOffset; |
| 3734 Reason = BaseInst; | 3665 Reason = BaseInst; |
| 3735 return true; | 3666 return true; |
| 3736 } | 3667 } |
| 3737 return false; | 3668 return false; |
| 3738 } | 3669 } |
| 3739 | 3670 |
| 3740 void computeAddressOpt(Cfg *Func, const Inst *Instr, Variable *&Base, | 3671 void computeAddressOpt(Cfg *Func, const Inst *Instr, Variable *&Base, |
| 3741 Variable *&Index, uint16_t &Shift, int32_t &Offset) { | 3672 Variable *&Index, uint16_t &Shift, int32_t &Offset) { |
| 3742 Func->resetCurrentNode(); | 3673 Func->resetCurrentNode(); |
| 3743 if (Func->getContext()->isVerbose(IceV_AddrOpt)) { | 3674 if (Func->isVerbose(IceV_AddrOpt)) { |
| 3744 OstreamLocker L(Func->getContext()); | 3675 OstreamLocker L(Func->getContext()); |
| 3745 Ostream &Str = Func->getContext()->getStrDump(); | 3676 Ostream &Str = Func->getContext()->getStrDump(); |
| 3746 Str << "\nStarting computeAddressOpt for instruction:\n "; | 3677 Str << "\nStarting computeAddressOpt for instruction:\n "; |
| 3747 Instr->dumpDecorated(Func); | 3678 Instr->dumpDecorated(Func); |
| 3748 } | 3679 } |
| 3749 (void)Offset; // TODO: pattern-match for non-zero offsets. | 3680 (void)Offset; // TODO: pattern-match for non-zero offsets. |
| 3750 if (Base == nullptr) | 3681 if (Base == nullptr) |
| 3751 return; | 3682 return; |
| 3752 // If the Base has more than one use or is live across multiple | 3683 // If the Base has more than one use or is live across multiple |
| 3753 // blocks, then don't go further. Alternatively (?), never consider | 3684 // blocks, then don't go further. Alternatively (?), never consider |
| (...skipping 821 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4575 RegisterList Shuffled(List); | 4506 RegisterList Shuffled(List); |
| 4576 std::random_shuffle(Shuffled.begin(), Shuffled.end(), RNG); | 4507 std::random_shuffle(Shuffled.begin(), Shuffled.end(), RNG); |
| 4577 for (size_t SI = 0, SE = Shuffled.size(); SI < SE; ++SI) { | 4508 for (size_t SI = 0, SE = Shuffled.size(); SI < SE; ++SI) { |
| 4578 Permutation[List[SI]] = Shuffled[SI]; | 4509 Permutation[List[SI]] = Shuffled[SI]; |
| 4579 ++NumShuffled; | 4510 ++NumShuffled; |
| 4580 } | 4511 } |
| 4581 } | 4512 } |
| 4582 | 4513 |
| 4583 assert(NumShuffled + NumPreserved == RegX8632::Reg_NUM); | 4514 assert(NumShuffled + NumPreserved == RegX8632::Reg_NUM); |
| 4584 | 4515 |
| 4585 if (Func->getContext()->isVerbose(IceV_Random)) { | 4516 if (Func->isVerbose(IceV_Random)) { |
| 4586 OstreamLocker L(Func->getContext()); | 4517 OstreamLocker L(Func->getContext()); |
| 4587 Ostream &Str = Func->getContext()->getStrDump(); | 4518 Ostream &Str = Func->getContext()->getStrDump(); |
| 4588 Str << "Register equivalence classes:\n"; | 4519 Str << "Register equivalence classes:\n"; |
| 4589 for (auto I : EquivalenceClasses) { | 4520 for (auto I : EquivalenceClasses) { |
| 4590 Str << "{"; | 4521 Str << "{"; |
| 4591 const RegisterList &List = I.second; | 4522 const RegisterList &List = I.second; |
| 4592 bool First = true; | 4523 bool First = true; |
| 4593 for (int32_t Register : List) { | 4524 for (int32_t Register : List) { |
| 4594 if (!First) | 4525 if (!First) |
| 4595 Str << " "; | 4526 Str << " "; |
| (...skipping 27 matching lines...) Expand all Loading... |
| 4623 if (!ALLOW_DUMP) | 4554 if (!ALLOW_DUMP) |
| 4624 return; | 4555 return; |
| 4625 Ostream &Str = Ctx->getStrEmit(); | 4556 Ostream &Str = Ctx->getStrEmit(); |
| 4626 emitPoolLabel(Str); | 4557 emitPoolLabel(Str); |
| 4627 } | 4558 } |
| 4628 | 4559 |
| 4629 void ConstantUndef::emit(GlobalContext *) const { | 4560 void ConstantUndef::emit(GlobalContext *) const { |
| 4630 llvm_unreachable("undef value encountered by emitter."); | 4561 llvm_unreachable("undef value encountered by emitter."); |
| 4631 } | 4562 } |
| 4632 | 4563 |
| 4633 TargetGlobalInitX8632::TargetGlobalInitX8632(GlobalContext *Ctx) | 4564 TargetGlobalX8632::TargetGlobalX8632(GlobalContext *Ctx) |
| 4634 : TargetGlobalInitLowering(Ctx) {} | 4565 : TargetGlobalLowering(Ctx) {} |
| 4635 | 4566 |
| 4636 void TargetGlobalInitX8632::lower(const VariableDeclaration &Var) { | 4567 void TargetGlobalX8632::lowerInit(const VariableDeclaration &Var) const { |
| 4637 // TODO(jvoung): handle this without text. | 4568 // TODO(jvoung): handle this without text. |
| 4638 if (Ctx->getFlags().UseELFWriter) | 4569 if (Ctx->getFlags().UseELFWriter) |
| 4639 return; | 4570 return; |
| 4640 | 4571 |
| 4641 Ostream &Str = Ctx->getStrEmit(); | 4572 Ostream &Str = Ctx->getStrEmit(); |
| 4642 | 4573 |
| 4643 const VariableDeclaration::InitializerListType &Initializers = | 4574 const VariableDeclaration::InitializerListType &Initializers = |
| 4644 Var.getInitializers(); | 4575 Var.getInitializers(); |
| 4645 | 4576 |
| 4646 // If external and not initialized, this must be a cross test. | 4577 // If external and not initialized, this must be a cross test. |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4707 } else | 4638 } else |
| 4708 // NOTE: for non-constant zero initializers, this is BSS (no bits), | 4639 // NOTE: for non-constant zero initializers, this is BSS (no bits), |
| 4709 // so an ELF writer would not write to the file, and only track | 4640 // so an ELF writer would not write to the file, and only track |
| 4710 // virtual offsets, but the .s writer still needs this .zero and | 4641 // virtual offsets, but the .s writer still needs this .zero and |
| 4711 // cannot simply use the .size to advance offsets. | 4642 // cannot simply use the .size to advance offsets. |
| 4712 Str << "\t.zero\t" << Size << "\n"; | 4643 Str << "\t.zero\t" << Size << "\n"; |
| 4713 | 4644 |
| 4714 Str << "\t.size\t" << MangledName << ", " << Size << "\n"; | 4645 Str << "\t.size\t" << MangledName << ", " << Size << "\n"; |
| 4715 } | 4646 } |
| 4716 | 4647 |
| 4648 template <typename T> struct PoolTypeConverter {}; |
| 4649 |
| 4650 template <> struct PoolTypeConverter<float> { |
| 4651 typedef uint32_t PrimitiveIntType; |
| 4652 typedef ConstantFloat IceType; |
| 4653 static const Type Ty = IceType_f32; |
| 4654 static const char *TypeName; |
| 4655 static const char *AsmTag; |
| 4656 static const char *PrintfString; |
| 4657 }; |
| 4658 const char *PoolTypeConverter<float>::TypeName = "float"; |
| 4659 const char *PoolTypeConverter<float>::AsmTag = ".long"; |
| 4660 const char *PoolTypeConverter<float>::PrintfString = "0x%x"; |
| 4661 |
| 4662 template <> struct PoolTypeConverter<double> { |
| 4663 typedef uint64_t PrimitiveIntType; |
| 4664 typedef ConstantDouble IceType; |
| 4665 static const Type Ty = IceType_f64; |
| 4666 static const char *TypeName; |
| 4667 static const char *AsmTag; |
| 4668 static const char *PrintfString; |
| 4669 }; |
| 4670 const char *PoolTypeConverter<double>::TypeName = "double"; |
| 4671 const char *PoolTypeConverter<double>::AsmTag = ".quad"; |
| 4672 const char *PoolTypeConverter<double>::PrintfString = "0x%llx"; |
| 4673 |
| 4674 template <typename T> |
| 4675 void TargetGlobalX8632::emitConstantPool(GlobalContext *Ctx) { |
| 4676 // Note: Still used by emit IAS. |
| 4677 Ostream &Str = Ctx->getStrEmit(); |
| 4678 Type Ty = T::Ty; |
| 4679 SizeT Align = typeAlignInBytes(Ty); |
| 4680 ConstantList Pool = Ctx->getConstantPool(Ty); |
| 4681 |
| 4682 Str << "\t.section\t.rodata.cst" << Align << ",\"aM\",@progbits," << Align |
| 4683 << "\n"; |
| 4684 Str << "\t.align\t" << Align << "\n"; |
| 4685 for (Constant *C : Pool) { |
| 4686 typename T::IceType *Const = llvm::cast<typename T::IceType>(C); |
| 4687 typename T::IceType::PrimType Value = Const->getValue(); |
| 4688 // Use memcpy() to copy bits from Value into RawValue in a way |
| 4689 // that avoids breaking strict-aliasing rules. |
| 4690 typename T::PrimitiveIntType RawValue; |
| 4691 memcpy(&RawValue, &Value, sizeof(Value)); |
| 4692 char buf[30]; |
| 4693 int CharsPrinted = |
| 4694 snprintf(buf, llvm::array_lengthof(buf), T::PrintfString, RawValue); |
| 4695 assert(CharsPrinted >= 0 && |
| 4696 (size_t)CharsPrinted < llvm::array_lengthof(buf)); |
| 4697 (void)CharsPrinted; // avoid warnings if asserts are disabled |
| 4698 Const->emitPoolLabel(Str); |
| 4699 Str << ":\n\t" << T::AsmTag << "\t" << buf << "\t# " << T::TypeName << " " |
| 4700 << Value << "\n"; |
| 4701 } |
| 4702 } |
| 4703 |
| 4704 void TargetGlobalX8632::lowerConstants(GlobalContext *Ctx) const { |
| 4705 if (Ctx->getFlags().DisableTranslation) |
| 4706 return; |
| 4707 // No need to emit constants from the int pool since (for x86) they |
| 4708 // are embedded as immediates in the instructions, just emit float/double. |
| 4709 if (Ctx->getFlags().UseELFWriter) { |
| 4710 ELFObjectWriter *Writer = Ctx->getObjectWriter(); |
| 4711 Writer->writeConstantPool<ConstantFloat>(IceType_f32); |
| 4712 Writer->writeConstantPool<ConstantDouble>(IceType_f64); |
| 4713 } else { |
| 4714 OstreamLocker L(Ctx); |
| 4715 emitConstantPool<PoolTypeConverter<float>>(Ctx); |
| 4716 emitConstantPool<PoolTypeConverter<double>>(Ctx); |
| 4717 } |
| 4718 } |
| 4719 |
| 4717 } // end of namespace Ice | 4720 } // end of namespace Ice |
| OLD | NEW |