| OLD | NEW |
| 1 //===- subzero/src/IceTargetLoweringX8664.cpp - x86-64 lowering -----------===// | 1 //===- subzero/src/IceTargetLoweringX8664.cpp - x86-64 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 /// \file | 10 /// \file |
| 11 /// \brief Implements the TargetLoweringX8664 class, which consists almost | 11 /// \brief Implements the TargetLoweringX8664 class, which consists almost |
| 12 /// entirely of the lowering sequence for each high-level instruction. | 12 /// entirely of the lowering sequence for each high-level instruction. |
| 13 /// | 13 /// |
| 14 //===----------------------------------------------------------------------===// | 14 //===----------------------------------------------------------------------===// |
| 15 #include "IceTargetLoweringX8664.h" | 15 #include "IceTargetLoweringX8664.h" |
| 16 | 16 |
| 17 #include "IceDefs.h" | 17 #include "IceDefs.h" |
| 18 #include "IceTargetLoweringX8664Traits.h" | 18 #include "IceTargetLoweringX8664Traits.h" |
| 19 | 19 |
| 20 namespace X8664 { | 20 namespace X8664 { |
| 21 std::unique_ptr<::Ice::TargetLowering> createTargetLowering(::Ice::Cfg *Func) { | 21 std::unique_ptr<::Ice::TargetLowering> createTargetLowering(::Ice::Cfg *Func) { |
| 22 return ::Ice::X8664::TargetX8664::create(Func); | 22 return ::Ice::X8664::TargetX8664::create(Func); |
| 23 } | 23 } |
| 24 | 24 |
| 25 std::unique_ptr<::Ice::TargetDataLowering> | 25 std::unique_ptr<::Ice::TargetDataLowering> |
| 26 createTargetDataLowering(::Ice::GlobalContext *Ctx) { | 26 createTargetDataLowering(::Ice::GlobalContext *Ctx) { |
| 27 return ::Ice::X8664::TargetDataX8664::create(Ctx); | 27 return ::Ice::X8664::TargetDataX86<::Ice::X8664::TargetX8664Traits>::create( |
| 28 Ctx); |
| 28 } | 29 } |
| 29 | 30 |
| 30 std::unique_ptr<::Ice::TargetHeaderLowering> | 31 std::unique_ptr<::Ice::TargetHeaderLowering> |
| 31 createTargetHeaderLowering(::Ice::GlobalContext *Ctx) { | 32 createTargetHeaderLowering(::Ice::GlobalContext *Ctx) { |
| 32 return ::Ice::X8664::TargetHeaderX8664::create(Ctx); | 33 return ::Ice::X8664::TargetHeaderX86::create(Ctx); |
| 33 } | 34 } |
| 34 | 35 |
| 35 void staticInit(::Ice::GlobalContext *Ctx) { | 36 void staticInit(::Ice::GlobalContext *Ctx) { |
| 36 ::Ice::X8664::TargetX8664::staticInit(Ctx); | 37 ::Ice::X8664::TargetX8664::staticInit(Ctx); |
| 37 } | 38 } |
| 38 } // end of namespace X8664 | 39 } // end of namespace X8664 |
| 39 | 40 |
| 40 namespace Ice { | 41 namespace Ice { |
| 41 namespace X8664 { | 42 namespace X8664 { |
| 42 | 43 |
| (...skipping 497 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 540 const SizeT BundleSize = | 541 const SizeT BundleSize = |
| 541 1 << Func->getAssembler<>()->getBundleAlignLog2Bytes(); | 542 1 << Func->getAssembler<>()->getBundleAlignLog2Bytes(); |
| 542 _and(T_ecx, Ctx->getConstantInt32(~(BundleSize - 1))); | 543 _and(T_ecx, Ctx->getConstantInt32(~(BundleSize - 1))); |
| 543 Context.insert<InstFakeDef>(T_rcx, T_ecx); | 544 Context.insert<InstFakeDef>(T_rcx, T_ecx); |
| 544 _add(T_rcx, r15); | 545 _add(T_rcx, r15); |
| 545 | 546 |
| 546 _jmp(T_rcx); | 547 _jmp(T_rcx); |
| 547 } | 548 } |
| 548 } | 549 } |
| 549 | 550 |
| 550 void TargetX8664::emitJumpTable(const Cfg *Func, | |
| 551 const InstJumpTable *JumpTable) const { | |
| 552 if (!BuildDefs::dump()) | |
| 553 return; | |
| 554 Ostream &Str = Ctx->getStrEmit(); | |
| 555 IceString MangledName = Ctx->mangleName(Func->getFunctionName()); | |
| 556 Str << "\t.section\t.rodata." << MangledName | |
| 557 << "$jumptable,\"a\",@progbits\n"; | |
| 558 Str << "\t.align\t" << typeWidthInBytes(getPointerType()) << "\n"; | |
| 559 Str << InstJumpTable::makeName(MangledName, JumpTable->getId()) << ":"; | |
| 560 | |
| 561 // On X8664 ILP32 pointers are 32-bit hence the use of .long | |
| 562 for (SizeT I = 0; I < JumpTable->getNumTargets(); ++I) | |
| 563 Str << "\n\t.long\t" << JumpTable->getTarget(I)->getAsmName(); | |
| 564 Str << "\n"; | |
| 565 } | |
| 566 | |
| 567 namespace { | |
| 568 template <typename T> struct PoolTypeConverter {}; | |
| 569 | |
| 570 template <> struct PoolTypeConverter<float> { | |
| 571 using PrimitiveIntType = uint32_t; | |
| 572 using IceType = ConstantFloat; | |
| 573 static const Type Ty = IceType_f32; | |
| 574 static const char *TypeName; | |
| 575 static const char *AsmTag; | |
| 576 static const char *PrintfString; | |
| 577 }; | |
| 578 const char *PoolTypeConverter<float>::TypeName = "float"; | |
| 579 const char *PoolTypeConverter<float>::AsmTag = ".long"; | |
| 580 const char *PoolTypeConverter<float>::PrintfString = "0x%x"; | |
| 581 | |
| 582 template <> struct PoolTypeConverter<double> { | |
| 583 using PrimitiveIntType = uint64_t; | |
| 584 using IceType = ConstantDouble; | |
| 585 static const Type Ty = IceType_f64; | |
| 586 static const char *TypeName; | |
| 587 static const char *AsmTag; | |
| 588 static const char *PrintfString; | |
| 589 }; | |
| 590 const char *PoolTypeConverter<double>::TypeName = "double"; | |
| 591 const char *PoolTypeConverter<double>::AsmTag = ".quad"; | |
| 592 const char *PoolTypeConverter<double>::PrintfString = "0x%llx"; | |
| 593 | |
| 594 // Add converter for int type constant pooling | |
| 595 template <> struct PoolTypeConverter<uint32_t> { | |
| 596 using PrimitiveIntType = uint32_t; | |
| 597 using IceType = ConstantInteger32; | |
| 598 static const Type Ty = IceType_i32; | |
| 599 static const char *TypeName; | |
| 600 static const char *AsmTag; | |
| 601 static const char *PrintfString; | |
| 602 }; | |
| 603 const char *PoolTypeConverter<uint32_t>::TypeName = "i32"; | |
| 604 const char *PoolTypeConverter<uint32_t>::AsmTag = ".long"; | |
| 605 const char *PoolTypeConverter<uint32_t>::PrintfString = "0x%x"; | |
| 606 | |
| 607 // Add converter for int type constant pooling | |
| 608 template <> struct PoolTypeConverter<uint16_t> { | |
| 609 using PrimitiveIntType = uint32_t; | |
| 610 using IceType = ConstantInteger32; | |
| 611 static const Type Ty = IceType_i16; | |
| 612 static const char *TypeName; | |
| 613 static const char *AsmTag; | |
| 614 static const char *PrintfString; | |
| 615 }; | |
| 616 const char *PoolTypeConverter<uint16_t>::TypeName = "i16"; | |
| 617 const char *PoolTypeConverter<uint16_t>::AsmTag = ".short"; | |
| 618 const char *PoolTypeConverter<uint16_t>::PrintfString = "0x%x"; | |
| 619 | |
| 620 // Add converter for int type constant pooling | |
| 621 template <> struct PoolTypeConverter<uint8_t> { | |
| 622 using PrimitiveIntType = uint32_t; | |
| 623 using IceType = ConstantInteger32; | |
| 624 static const Type Ty = IceType_i8; | |
| 625 static const char *TypeName; | |
| 626 static const char *AsmTag; | |
| 627 static const char *PrintfString; | |
| 628 }; | |
| 629 const char *PoolTypeConverter<uint8_t>::TypeName = "i8"; | |
| 630 const char *PoolTypeConverter<uint8_t>::AsmTag = ".byte"; | |
| 631 const char *PoolTypeConverter<uint8_t>::PrintfString = "0x%x"; | |
| 632 } // end of anonymous namespace | |
| 633 | |
| 634 template <typename T> | |
| 635 void TargetDataX8664::emitConstantPool(GlobalContext *Ctx) { | |
| 636 if (!BuildDefs::dump()) | |
| 637 return; | |
| 638 Ostream &Str = Ctx->getStrEmit(); | |
| 639 Type Ty = T::Ty; | |
| 640 SizeT Align = typeAlignInBytes(Ty); | |
| 641 ConstantList Pool = Ctx->getConstantPool(Ty); | |
| 642 | |
| 643 Str << "\t.section\t.rodata.cst" << Align << ",\"aM\",@progbits," << Align | |
| 644 << "\n"; | |
| 645 Str << "\t.align\t" << Align << "\n"; | |
| 646 | |
| 647 // If reorder-pooled-constants option is set to true, we need to shuffle the | |
| 648 // constant pool before emitting it. | |
| 649 if (Ctx->getFlags().shouldReorderPooledConstants()) { | |
| 650 // Use the constant's kind value as the salt for creating random number | |
| 651 // generator. | |
| 652 Operand::OperandKind K = (*Pool.begin())->getKind(); | |
| 653 RandomNumberGenerator RNG(Ctx->getFlags().getRandomSeed(), | |
| 654 RPE_PooledConstantReordering, K); | |
| 655 RandomShuffle(Pool.begin(), Pool.end(), | |
| 656 [&RNG](uint64_t N) { return (uint32_t)RNG.next(N); }); | |
| 657 } | |
| 658 | |
| 659 for (Constant *C : Pool) { | |
| 660 if (!C->getShouldBePooled()) | |
| 661 continue; | |
| 662 auto *Const = llvm::cast<typename T::IceType>(C); | |
| 663 typename T::IceType::PrimType Value = Const->getValue(); | |
| 664 // Use memcpy() to copy bits from Value into RawValue in a way that avoids | |
| 665 // breaking strict-aliasing rules. | |
| 666 typename T::PrimitiveIntType RawValue; | |
| 667 memcpy(&RawValue, &Value, sizeof(Value)); | |
| 668 char buf[30]; | |
| 669 int CharsPrinted = | |
| 670 snprintf(buf, llvm::array_lengthof(buf), T::PrintfString, RawValue); | |
| 671 assert(CharsPrinted >= 0 && | |
| 672 (size_t)CharsPrinted < llvm::array_lengthof(buf)); | |
| 673 (void)CharsPrinted; // avoid warnings if asserts are disabled | |
| 674 Const->emitPoolLabel(Str, Ctx); | |
| 675 Str << ":\n\t" << T::AsmTag << "\t" << buf << "\t/* " << T::TypeName << " " | |
| 676 << Value << " */\n"; | |
| 677 } | |
| 678 } | |
| 679 | |
| 680 void TargetDataX8664::lowerConstants() { | |
| 681 if (Ctx->getFlags().getDisableTranslation()) | |
| 682 return; | |
| 683 // No need to emit constants from the int pool since (for x86) they are | |
| 684 // embedded as immediates in the instructions, just emit float/double. | |
| 685 switch (Ctx->getFlags().getOutFileType()) { | |
| 686 case FT_Elf: { | |
| 687 ELFObjectWriter *Writer = Ctx->getObjectWriter(); | |
| 688 | |
| 689 Writer->writeConstantPool<ConstantInteger32>(IceType_i8); | |
| 690 Writer->writeConstantPool<ConstantInteger32>(IceType_i16); | |
| 691 Writer->writeConstantPool<ConstantInteger32>(IceType_i32); | |
| 692 | |
| 693 Writer->writeConstantPool<ConstantFloat>(IceType_f32); | |
| 694 Writer->writeConstantPool<ConstantDouble>(IceType_f64); | |
| 695 } break; | |
| 696 case FT_Asm: | |
| 697 case FT_Iasm: { | |
| 698 OstreamLocker L(Ctx); | |
| 699 | |
| 700 emitConstantPool<PoolTypeConverter<uint8_t>>(Ctx); | |
| 701 emitConstantPool<PoolTypeConverter<uint16_t>>(Ctx); | |
| 702 emitConstantPool<PoolTypeConverter<uint32_t>>(Ctx); | |
| 703 | |
| 704 emitConstantPool<PoolTypeConverter<float>>(Ctx); | |
| 705 emitConstantPool<PoolTypeConverter<double>>(Ctx); | |
| 706 } break; | |
| 707 } | |
| 708 } | |
| 709 | |
| 710 void TargetDataX8664::lowerJumpTables() { | |
| 711 const bool IsPIC = Ctx->getFlags().getUseNonsfi(); | |
| 712 switch (Ctx->getFlags().getOutFileType()) { | |
| 713 case FT_Elf: { | |
| 714 ELFObjectWriter *Writer = Ctx->getObjectWriter(); | |
| 715 for (const JumpTableData &JumpTable : Ctx->getJumpTables()) | |
| 716 Writer->writeJumpTable(JumpTable, TargetX8664::Traits::FK_Abs, IsPIC); | |
| 717 } break; | |
| 718 case FT_Asm: | |
| 719 // Already emitted from Cfg | |
| 720 break; | |
| 721 case FT_Iasm: { | |
| 722 if (!BuildDefs::dump()) | |
| 723 return; | |
| 724 Ostream &Str = Ctx->getStrEmit(); | |
| 725 for (const JumpTableData &JT : Ctx->getJumpTables()) { | |
| 726 Str << "\t.section\t.rodata." << JT.getFunctionName() | |
| 727 << "$jumptable,\"a\",@progbits\n"; | |
| 728 Str << "\t.align\t" << typeWidthInBytes(getPointerType()) << "\n"; | |
| 729 Str << InstJumpTable::makeName(JT.getFunctionName(), JT.getId()) << ":"; | |
| 730 | |
| 731 // On X8664 ILP32 pointers are 32-bit hence the use of .long | |
| 732 for (intptr_t TargetOffset : JT.getTargetOffsets()) | |
| 733 Str << "\n\t.long\t" << JT.getFunctionName() << "+" << TargetOffset; | |
| 734 Str << "\n"; | |
| 735 } | |
| 736 } break; | |
| 737 } | |
| 738 } | |
| 739 | |
| 740 void TargetDataX8664::lowerGlobals(const VariableDeclarationList &Vars, | |
| 741 const IceString &SectionSuffix) { | |
| 742 const bool IsPIC = Ctx->getFlags().getUseNonsfi(); | |
| 743 switch (Ctx->getFlags().getOutFileType()) { | |
| 744 case FT_Elf: { | |
| 745 ELFObjectWriter *Writer = Ctx->getObjectWriter(); | |
| 746 Writer->writeDataSection(Vars, TargetX8664::Traits::FK_Abs, SectionSuffix, | |
| 747 IsPIC); | |
| 748 } break; | |
| 749 case FT_Asm: | |
| 750 case FT_Iasm: { | |
| 751 const IceString &TranslateOnly = Ctx->getFlags().getTranslateOnly(); | |
| 752 OstreamLocker L(Ctx); | |
| 753 for (const VariableDeclaration *Var : Vars) { | |
| 754 if (GlobalContext::matchSymbolName(Var->getName(), TranslateOnly)) { | |
| 755 emitGlobal(*Var, SectionSuffix); | |
| 756 } | |
| 757 } | |
| 758 } break; | |
| 759 } | |
| 760 } | |
| 761 | |
| 762 // In some cases, there are x-macros tables for both high-level and low-level | 551 // In some cases, there are x-macros tables for both high-level and low-level |
| 763 // instructions/operands that use the same enum key value. The tables are kept | 552 // instructions/operands that use the same enum key value. The tables are kept |
| 764 // separate to maintain a proper separation between abstraction layers. There | 553 // separate to maintain a proper separation between abstraction layers. There |
| 765 // is a risk that the tables could get out of sync if enum values are reordered | 554 // is a risk that the tables could get out of sync if enum values are reordered |
| 766 // or if entries are added or deleted. The following dummy namespaces use | 555 // or if entries are added or deleted. The following dummy namespaces use |
| 767 // static_asserts to ensure everything is kept in sync. | 556 // static_asserts to ensure everything is kept in sync. |
| 768 | 557 |
| 769 namespace { | 558 namespace { |
| 770 // Validate the enum values in FCMPX8664_TABLE. | 559 // Validate the enum values in FCMPX8664_TABLE. |
| 771 namespace dummy1 { | 560 namespace dummy1 { |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 858 #define X(tag, sizeLog2, align, elts, elty, str) \ | 647 #define X(tag, sizeLog2, align, elts, elty, str) \ |
| 859 static_assert(_table1_##tag == _table2_##tag, \ | 648 static_assert(_table1_##tag == _table2_##tag, \ |
| 860 "Inconsistency between ICETYPEX8664_TABLE and ICETYPE_TABLE"); | 649 "Inconsistency between ICETYPEX8664_TABLE and ICETYPE_TABLE"); |
| 861 ICETYPE_TABLE | 650 ICETYPE_TABLE |
| 862 #undef X | 651 #undef X |
| 863 } // end of namespace dummy3 | 652 } // end of namespace dummy3 |
| 864 } // end of anonymous namespace | 653 } // end of anonymous namespace |
| 865 | 654 |
| 866 } // end of namespace X8664 | 655 } // end of namespace X8664 |
| 867 } // end of namespace Ice | 656 } // end of namespace Ice |
| OLD | NEW |