Chromium Code Reviews| Index: src/IceTargetLoweringX8664.cpp |
| diff --git a/src/IceTargetLoweringX8664.cpp b/src/IceTargetLoweringX8664.cpp |
| index f2be0c15948f5f8858acc27cebfb8b2970bca862..7f409423965ccfc01caadc3a5c0e017c5faa20bd 100644 |
| --- a/src/IceTargetLoweringX8664.cpp |
| +++ b/src/IceTargetLoweringX8664.cpp |
| @@ -1,4 +1,4 @@ |
| -//===- subzero/src/IceTargetLoweringX8664.cpp - lowering for x86-64 -------===// |
| +//===- subzero/src/IceTargetLoweringX8664.cpp - x86-64 lowering -----------===// |
| // |
| // The Subzero Code Generator |
| // |
| @@ -8,25 +8,343 @@ |
| //===----------------------------------------------------------------------===// |
| /// |
| /// \file |
| -/// Implements the Target Lowering for x86-64. |
| +/// This file implements the TargetLoweringX8664 class, which |
| +/// consists almost entirely of the lowering sequence for each |
| +/// high-level instruction. |
| /// |
| //===----------------------------------------------------------------------===// |
| -#include "IceDefs.h" |
| #include "IceTargetLoweringX8664.h" |
| +#include "IceTargetLoweringX8664Traits.h" |
| +#include "IceTargetLoweringX86Base.h" |
| + |
| namespace Ice { |
| -TargetX8664 *TargetX8664::create(Cfg *) { |
| - llvm::report_fatal_error("Not yet implemented"); |
| -} |
| -void TargetDataX8664::lowerGlobals(const VariableDeclarationList &, |
| - const IceString &) { |
| - llvm::report_fatal_error("Not yet implemented"); |
| +namespace X86Internal { |
| +const MachineTraits<TargetX8664>::TableFcmpType |
| + MachineTraits<TargetX8664>::TableFcmp[] = { |
| +#define X(val, dflt, swapS, C1, C2, swapV, pred) \ |
| + { \ |
| + dflt, swapS, X8664::Traits::Cond::C1, X8664::Traits::Cond::C2, swapV, \ |
| + X8664::Traits::Cond::pred \ |
| + } \ |
| + , |
| + FCMPX8664_TABLE |
| +#undef X |
| +}; |
| + |
| +const size_t MachineTraits<TargetX8664>::TableFcmpSize = |
| + llvm::array_lengthof(TableFcmp); |
| + |
| +const MachineTraits<TargetX8664>::TableIcmp32Type |
| + MachineTraits<TargetX8664>::TableIcmp32[] = { |
| +#define X(val, C_32, C1_64, C2_64, C3_64) \ |
| + { X8664::Traits::Cond::C_32 } \ |
| + , |
| + ICMPX8664_TABLE |
| +#undef X |
| +}; |
| + |
| +const size_t MachineTraits<TargetX8664>::TableIcmp32Size = |
| + llvm::array_lengthof(TableIcmp32); |
| + |
| +const MachineTraits<TargetX8664>::TableIcmp64Type |
|
Jim Stichnoth
2015/07/30 19:11:08
Presumably this is just cargo-culting that will la
John
2015/07/31 21:05:54
Correct. As the CL description states I did not im
|
| + MachineTraits<TargetX8664>::TableIcmp64[] = { |
| +#define X(val, C_32, C1_64, C2_64, C3_64) \ |
| + { \ |
| + X8664::Traits::Cond::C1_64, X8664::Traits::Cond::C2_64, \ |
| + X8664::Traits::Cond::C3_64 \ |
| + } \ |
| + , |
| + ICMPX8664_TABLE |
| +#undef X |
| +}; |
| + |
| +const size_t MachineTraits<TargetX8664>::TableIcmp64Size = |
| + llvm::array_lengthof(TableIcmp64); |
| + |
| +const MachineTraits<TargetX8664>::TableTypeX8664AttributesType |
| + MachineTraits<TargetX8664>::TableTypeX8664Attributes[] = { |
| +#define X(tag, elementty, cvt, sdss, pack, width, fld) \ |
| + { elementty } \ |
| + , |
| + ICETYPEX8664_TABLE |
| +#undef X |
| +}; |
| + |
| +const size_t MachineTraits<TargetX8664>::TableTypeX8664AttributesSize = |
| + llvm::array_lengthof(TableTypeX8664Attributes); |
| + |
| +const uint32_t MachineTraits<TargetX8664>::X86_STACK_ALIGNMENT_BYTES = 16; |
|
Jim Stichnoth
2015/07/30 19:11:08
Can/should this be constexpr?
John
2015/07/31 21:05:54
No, it can not. having this as a constexpr causes
|
| +const char *MachineTraits<TargetX8664>::TargetName = "X8664"; |
| + |
| +} // end of namespace X86Internal |
| + |
| +namespace { |
| +template <typename T> struct PoolTypeConverter {}; |
| + |
| +template <> struct PoolTypeConverter<float> { |
| + typedef uint32_t PrimitiveIntType; |
| + typedef ConstantFloat IceType; |
| + static const Type Ty = IceType_f32; |
| + static const char *TypeName; |
| + static const char *AsmTag; |
| + static const char *PrintfString; |
| +}; |
| +const char *PoolTypeConverter<float>::TypeName = "float"; |
| +const char *PoolTypeConverter<float>::AsmTag = ".long"; |
| +const char *PoolTypeConverter<float>::PrintfString = "0x%x"; |
| + |
| +template <> struct PoolTypeConverter<double> { |
| + typedef uint64_t PrimitiveIntType; |
| + typedef ConstantDouble IceType; |
| + static const Type Ty = IceType_f64; |
| + static const char *TypeName; |
| + static const char *AsmTag; |
| + static const char *PrintfString; |
| +}; |
| +const char *PoolTypeConverter<double>::TypeName = "double"; |
| +const char *PoolTypeConverter<double>::AsmTag = ".quad"; |
| +const char *PoolTypeConverter<double>::PrintfString = "0x%llx"; |
| + |
| +// Add converter for int type constant pooling |
| +template <> struct PoolTypeConverter<uint32_t> { |
| + typedef uint32_t PrimitiveIntType; |
| + typedef ConstantInteger32 IceType; |
| + static const Type Ty = IceType_i32; |
| + static const char *TypeName; |
| + static const char *AsmTag; |
| + static const char *PrintfString; |
| +}; |
| +const char *PoolTypeConverter<uint32_t>::TypeName = "i32"; |
| +const char *PoolTypeConverter<uint32_t>::AsmTag = ".long"; |
| +const char *PoolTypeConverter<uint32_t>::PrintfString = "0x%x"; |
| + |
| +// Add converter for int type constant pooling |
| +template <> struct PoolTypeConverter<uint16_t> { |
| + typedef uint32_t PrimitiveIntType; |
| + typedef ConstantInteger32 IceType; |
| + static const Type Ty = IceType_i16; |
| + static const char *TypeName; |
| + static const char *AsmTag; |
| + static const char *PrintfString; |
| +}; |
| +const char *PoolTypeConverter<uint16_t>::TypeName = "i16"; |
| +const char *PoolTypeConverter<uint16_t>::AsmTag = ".short"; |
| +const char *PoolTypeConverter<uint16_t>::PrintfString = "0x%x"; |
| + |
| +// Add converter for int type constant pooling |
| +template <> struct PoolTypeConverter<uint8_t> { |
| + typedef uint32_t PrimitiveIntType; |
| + typedef ConstantInteger32 IceType; |
| + static const Type Ty = IceType_i8; |
| + static const char *TypeName; |
| + static const char *AsmTag; |
| + static const char *PrintfString; |
| +}; |
| +const char *PoolTypeConverter<uint8_t>::TypeName = "i8"; |
| +const char *PoolTypeConverter<uint8_t>::AsmTag = ".byte"; |
| +const char *PoolTypeConverter<uint8_t>::PrintfString = "0x%x"; |
| +} // end of anonymous namespace |
| + |
| +template <typename T> |
| +void TargetDataX8664::emitConstantPool(GlobalContext *Ctx) { |
| + if (!BuildDefs::dump()) |
| + return; |
| + Ostream &Str = Ctx->getStrEmit(); |
| + Type Ty = T::Ty; |
| + SizeT Align = typeAlignInBytes(Ty); |
| + ConstantList Pool = Ctx->getConstantPool(Ty); |
| + |
| + Str << "\t.section\t.rodata.cst" << Align << ",\"aM\",@progbits," << Align |
| + << "\n"; |
| + Str << "\t.align\t" << Align << "\n"; |
| + |
| + // If reorder-pooled-constants option is set to true, we need to shuffle the |
| + // constant pool before emitting it. |
| + if (Ctx->getFlags().shouldReorderPooledConstants()) |
| + RandomShuffle(Pool.begin(), Pool.end(), [Ctx](uint64_t N) { |
| + return (uint32_t)Ctx->getRNG().next(N); |
| + }); |
| + |
| + for (Constant *C : Pool) { |
| + if (!C->getShouldBePooled()) |
| + continue; |
| + typename T::IceType *Const = llvm::cast<typename T::IceType>(C); |
| + typename T::IceType::PrimType Value = Const->getValue(); |
| + // Use memcpy() to copy bits from Value into RawValue in a way |
| + // that avoids breaking strict-aliasing rules. |
| + typename T::PrimitiveIntType RawValue; |
| + memcpy(&RawValue, &Value, sizeof(Value)); |
| + char buf[30]; |
| + int CharsPrinted = |
| + snprintf(buf, llvm::array_lengthof(buf), T::PrintfString, RawValue); |
| + assert(CharsPrinted >= 0 && |
| + (size_t)CharsPrinted < llvm::array_lengthof(buf)); |
| + (void)CharsPrinted; // avoid warnings if asserts are disabled |
| + Const->emitPoolLabel(Str); |
| + Str << ":\n\t" << T::AsmTag << "\t" << buf << "\t# " << T::TypeName << " " |
| + << Value << "\n"; |
| + } |
| } |
| void TargetDataX8664::lowerConstants() { |
| - llvm::report_fatal_error("Not yet implemented"); |
| + if (Ctx->getFlags().getDisableTranslation()) |
| + return; |
| + // No need to emit constants from the int pool since (for x86) they |
| + // are embedded as immediates in the instructions, just emit float/double. |
| + switch (Ctx->getFlags().getOutFileType()) { |
| + case FT_Elf: { |
| + ELFObjectWriter *Writer = Ctx->getObjectWriter(); |
| + |
| + Writer->writeConstantPool<ConstantInteger32>(IceType_i8); |
| + Writer->writeConstantPool<ConstantInteger32>(IceType_i16); |
| + Writer->writeConstantPool<ConstantInteger32>(IceType_i32); |
| + |
| + Writer->writeConstantPool<ConstantFloat>(IceType_f32); |
| + Writer->writeConstantPool<ConstantDouble>(IceType_f64); |
| + } break; |
| + case FT_Asm: |
| + case FT_Iasm: { |
| + OstreamLocker L(Ctx); |
| + |
| + emitConstantPool<PoolTypeConverter<uint8_t>>(Ctx); |
| + emitConstantPool<PoolTypeConverter<uint16_t>>(Ctx); |
| + emitConstantPool<PoolTypeConverter<uint32_t>>(Ctx); |
| + |
| + emitConstantPool<PoolTypeConverter<float>>(Ctx); |
| + emitConstantPool<PoolTypeConverter<double>>(Ctx); |
| + } break; |
| + } |
| +} |
| + |
| +void TargetDataX8664::lowerGlobals(const VariableDeclarationList &Vars, |
| + const IceString &SectionSuffix) { |
| + switch (Ctx->getFlags().getOutFileType()) { |
| + case FT_Elf: { |
| + ELFObjectWriter *Writer = Ctx->getObjectWriter(); |
| + Writer->writeDataSection(Vars, llvm::ELF::R_386_32, SectionSuffix); |
|
jvoung (off chromium)
2015/07/30 21:16:22
TODO(jpp) to change this reloc to be not 386.
John
2015/07/31 21:05:54
Done.
|
| + } break; |
| + case FT_Asm: |
| + case FT_Iasm: { |
| + const IceString &TranslateOnly = Ctx->getFlags().getTranslateOnly(); |
| + OstreamLocker L(Ctx); |
| + for (const VariableDeclaration *Var : Vars) { |
| + if (GlobalContext::matchSymbolName(Var->getName(), TranslateOnly)) { |
| + emitGlobal(*Var, SectionSuffix); |
| + } |
| + } |
| + } break; |
| + } |
| } |
| +// In some cases, there are x-macros tables for both high-level and |
| +// low-level instructions/operands that use the same enum key value. |
| +// The tables are kept separate to maintain a proper separation |
| +// between abstraction layers. There is a risk that the tables could |
| +// get out of sync if enum values are reordered or if entries are |
| +// added or deleted. The following dummy namespaces use |
| +// static_asserts to ensure everything is kept in sync. |
| + |
| +namespace { |
| +// Validate the enum values in FCMPX8664_TABLE. |
| +namespace dummy1 { |
| +// Define a temporary set of enum values based on low-level table |
| +// entries. |
| +enum _tmp_enum { |
| +#define X(val, dflt, swapS, C1, C2, swapV, pred) _tmp_##val, |
| + FCMPX8664_TABLE |
| +#undef X |
| + _num |
| +}; |
| +// Define a set of constants based on high-level table entries. |
| +#define X(tag, str) static const int _table1_##tag = InstFcmp::tag; |
| +ICEINSTFCMP_TABLE |
| +#undef X |
| +// Define a set of constants based on low-level table entries, and |
| +// ensure the table entry keys are consistent. |
| +#define X(val, dflt, swapS, C1, C2, swapV, pred) \ |
| + static const int _table2_##val = _tmp_##val; \ |
| + static_assert( \ |
| + _table1_##val == _table2_##val, \ |
| + "Inconsistency between FCMPX8664_TABLE and ICEINSTFCMP_TABLE"); |
| +FCMPX8664_TABLE |
| +#undef X |
| +// Repeat the static asserts with respect to the high-level table |
| +// entries in case the high-level table has extra entries. |
| +#define X(tag, str) \ |
| + static_assert( \ |
| + _table1_##tag == _table2_##tag, \ |
| + "Inconsistency between FCMPX8664_TABLE and ICEINSTFCMP_TABLE"); |
| +ICEINSTFCMP_TABLE |
| +#undef X |
| +} // end of namespace dummy1 |
| + |
| +// Validate the enum values in ICMPX8664_TABLE. |
| +namespace dummy2 { |
| +// Define a temporary set of enum values based on low-level table |
| +// entries. |
| +enum _tmp_enum { |
| +#define X(val, C_32, C1_64, C2_64, C3_64) _tmp_##val, |
| + ICMPX8664_TABLE |
| +#undef X |
| + _num |
| +}; |
| +// Define a set of constants based on high-level table entries. |
| +#define X(tag, str) static const int _table1_##tag = InstIcmp::tag; |
| +ICEINSTICMP_TABLE |
| +#undef X |
| +// Define a set of constants based on low-level table entries, and |
| +// ensure the table entry keys are consistent. |
| +#define X(val, C_32, C1_64, C2_64, C3_64) \ |
| + static const int _table2_##val = _tmp_##val; \ |
| + static_assert( \ |
| + _table1_##val == _table2_##val, \ |
| + "Inconsistency between ICMPX8664_TABLE and ICEINSTICMP_TABLE"); |
| +ICMPX8664_TABLE |
| +#undef X |
| +// Repeat the static asserts with respect to the high-level table |
| +// entries in case the high-level table has extra entries. |
| +#define X(tag, str) \ |
| + static_assert( \ |
| + _table1_##tag == _table2_##tag, \ |
| + "Inconsistency between ICMPX8664_TABLE and ICEINSTICMP_TABLE"); |
| +ICEINSTICMP_TABLE |
| +#undef X |
| +} // end of namespace dummy2 |
| + |
| +// Validate the enum values in ICETYPEX8664_TABLE. |
| +namespace dummy3 { |
| +// Define a temporary set of enum values based on low-level table |
| +// entries. |
| +enum _tmp_enum { |
| +#define X(tag, elementty, cvt, sdss, pack, width, fld) _tmp_##tag, |
| + ICETYPEX8664_TABLE |
| +#undef X |
| + _num |
| +}; |
| +// Define a set of constants based on high-level table entries. |
| +#define X(tag, sizeLog2, align, elts, elty, str) \ |
| + static const int _table1_##tag = tag; |
| +ICETYPE_TABLE |
| +#undef X |
| +// Define a set of constants based on low-level table entries, and |
| +// ensure the table entry keys are consistent. |
| +#define X(tag, elementty, cvt, sdss, pack, width, fld) \ |
| + static const int _table2_##tag = _tmp_##tag; \ |
| + static_assert(_table1_##tag == _table2_##tag, \ |
| + "Inconsistency between ICETYPEX8664_TABLE and ICETYPE_TABLE"); |
| +ICETYPEX8664_TABLE |
| +#undef X |
| +// Repeat the static asserts with respect to the high-level table |
| +// entries in case the high-level table has extra entries. |
| +#define X(tag, sizeLog2, align, elts, elty, str) \ |
| + static_assert(_table1_##tag == _table2_##tag, \ |
| + "Inconsistency between ICETYPEX8664_TABLE and ICETYPE_TABLE"); |
| +ICETYPE_TABLE |
| +#undef X |
| +} // end of namespace dummy3 |
| +} // end of anonymous namespace |
| + |
| } // end of namespace Ice |