IceTargetLowering.cpp \
IceTargetLoweringARM32.cpp \
IceTargetLoweringMIPS32.cpp \
+ IceTargetLoweringX86.cpp \
IceTargetLoweringX8632.cpp \
IceTargetLoweringX8664.cpp \
IceAssembler.cpp \
--- /dev/null
+//===---- subzero/src/IceTargetLoweringX86.cpp - x86 lowering -*- C++ -*---===//
+//
+// The Subzero Code Generator
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief Implements portions of the TargetLoweringX86Base class, and related
+/// classes.
+///
+//===----------------------------------------------------------------------===//
+
+// Choose one namespace, since including this file should not cause the
+// templates to be instantiated. This avoids duplicating the PoolTypeConverter
+// data items, but is ugly as code common to all of x86 is including code
+// specific to one of 32 or 64.
+// TODO(jpp): replace this ugliness with the beauty of extern template.
+
+#define X86NAMESPACE X8632
+#include "IceTargetLoweringX86Base.h"
+#undef X86NAMESPACE
+
+namespace Ice {
+namespace X86 {
+
+const char *PoolTypeConverter<float>::TypeName = "float";
+const char *PoolTypeConverter<float>::AsmTag = ".long";
+const char *PoolTypeConverter<float>::PrintfString = "0x%x";
+
+const char *PoolTypeConverter<double>::TypeName = "double";
+const char *PoolTypeConverter<double>::AsmTag = ".quad";
+const char *PoolTypeConverter<double>::PrintfString = "0x%llx";
+
+const char *PoolTypeConverter<uint32_t>::TypeName = "i32";
+const char *PoolTypeConverter<uint32_t>::AsmTag = ".long";
+const char *PoolTypeConverter<uint32_t>::PrintfString = "0x%x";
+
+const char *PoolTypeConverter<uint16_t>::TypeName = "i16";
+const char *PoolTypeConverter<uint16_t>::AsmTag = ".short";
+const char *PoolTypeConverter<uint16_t>::PrintfString = "0x%x";
+
+const char *PoolTypeConverter<uint8_t>::TypeName = "i8";
+const char *PoolTypeConverter<uint8_t>::AsmTag = ".byte";
+const char *PoolTypeConverter<uint8_t>::PrintfString = "0x%x";
+
+} // end of namespace X86
+} // end of namespace Ice
std::unique_ptr<::Ice::TargetDataLowering>
createTargetDataLowering(::Ice::GlobalContext *Ctx) {
- return ::Ice::X8632::TargetDataX8632::create(Ctx);
+ return ::Ice::X8632::TargetDataX86<::Ice::X8632::TargetX8632Traits>::create(
+ Ctx);
}
std::unique_ptr<::Ice::TargetHeaderLowering>
createTargetHeaderLowering(::Ice::GlobalContext *Ctx) {
- return ::Ice::X8632::TargetHeaderX8632::create(Ctx);
+ return ::Ice::X8632::TargetHeaderX86::create(Ctx);
}
void staticInit(::Ice::GlobalContext *Ctx) {
lowerIndirectJump(T_ecx);
}
-void TargetX8632::emitJumpTable(const Cfg *Func,
- const InstJumpTable *JumpTable) const {
- if (!BuildDefs::dump())
- return;
- Ostream &Str = Ctx->getStrEmit();
- const bool UseNonsfi = Ctx->getFlags().getUseNonsfi();
- const IceString MangledName = Ctx->mangleName(Func->getFunctionName());
- const IceString Prefix = UseNonsfi ? ".data.rel.ro." : ".rodata.";
- Str << "\t.section\t" << Prefix << MangledName
- << "$jumptable,\"a\",@progbits\n";
- Str << "\t.align\t" << typeWidthInBytes(getPointerType()) << "\n";
- Str << InstJumpTable::makeName(MangledName, JumpTable->getId()) << ":";
-
- // On X8632 pointers are 32-bit hence the use of .long
- for (SizeT I = 0; I < JumpTable->getNumTargets(); ++I)
- Str << "\n\t.long\t" << JumpTable->getTarget(I)->getAsmName();
- Str << "\n";
-}
-
-TargetDataX8632::TargetDataX8632(GlobalContext *Ctx)
- : TargetDataLowering(Ctx) {}
-
-namespace {
-template <typename T> struct PoolTypeConverter {};
-
-template <> struct PoolTypeConverter<float> {
- using PrimitiveIntType = uint32_t;
- using IceType = ConstantFloat;
- 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> {
- using PrimitiveIntType = uint64_t;
- using IceType = ConstantDouble;
- 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> {
- using PrimitiveIntType = uint32_t;
- using IceType = ConstantInteger32;
- 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> {
- using PrimitiveIntType = uint32_t;
- using IceType = ConstantInteger32;
- 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> {
- using PrimitiveIntType = uint32_t;
- using IceType = ConstantInteger32;
- 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 TargetDataX8632::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() && !Pool.empty()) {
- // Use the constant's kind value as the salt for creating random number
- // generator.
- Operand::OperandKind K = (*Pool.begin())->getKind();
-
- RandomNumberGenerator RNG(Ctx->getFlags().getRandomSeed(),
- RPE_PooledConstantReordering, K);
- RandomShuffle(Pool.begin(), Pool.end(),
- [&RNG](uint64_t N) { return (uint32_t)RNG.next(N); });
- }
-
- for (Constant *C : Pool) {
- if (!C->getShouldBePooled())
- continue;
- auto *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, Ctx);
- Str << ":\n\t" << T::AsmTag << "\t" << buf << "\t/* " << T::TypeName << " "
- << Value << " */\n";
- }
-}
-
-void TargetDataX8632::lowerConstants() {
- 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 TargetDataX8632::lowerJumpTables() {
- const bool IsPIC = Ctx->getFlags().getUseNonsfi();
- switch (Ctx->getFlags().getOutFileType()) {
- case FT_Elf: {
- ELFObjectWriter *Writer = Ctx->getObjectWriter();
- for (const JumpTableData &JT : Ctx->getJumpTables())
- Writer->writeJumpTable(JT, TargetX8632::Traits::FK_Abs, IsPIC);
- } break;
- case FT_Asm:
- // Already emitted from Cfg
- break;
- case FT_Iasm: {
- if (!BuildDefs::dump())
- return;
- Ostream &Str = Ctx->getStrEmit();
- const IceString Prefix = IsPIC ? ".data.rel.ro." : ".rodata.";
- for (const JumpTableData &JT : Ctx->getJumpTables()) {
- Str << "\t.section\t" << Prefix << JT.getFunctionName()
- << "$jumptable,\"a\",@progbits\n";
- Str << "\t.align\t" << typeWidthInBytes(getPointerType()) << "\n";
- Str << InstJumpTable::makeName(JT.getFunctionName(), JT.getId()) << ":";
-
- // On X8632 pointers are 32-bit hence the use of .long
- for (intptr_t TargetOffset : JT.getTargetOffsets())
- Str << "\n\t.long\t" << JT.getFunctionName() << "+" << TargetOffset;
- Str << "\n";
- }
- } break;
- }
-}
-
-void TargetDataX8632::lowerGlobals(const VariableDeclarationList &Vars,
- const IceString &SectionSuffix) {
- const bool IsPIC = Ctx->getFlags().getUseNonsfi();
- switch (Ctx->getFlags().getOutFileType()) {
- case FT_Elf: {
- ELFObjectWriter *Writer = Ctx->getObjectWriter();
- Writer->writeDataSection(Vars, TargetX8632::Traits::FK_Abs, SectionSuffix,
- IsPIC);
- } 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;
- }
-}
-
-TargetHeaderX8632::TargetHeaderX8632(GlobalContext *Ctx)
- : TargetHeaderLowering(Ctx) {}
-
// 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
TargetX8632(const TargetX8632 &) = delete;
TargetX8632 &operator=(const TargetX8632 &) = delete;
- void emitJumpTable(const Cfg *Func,
- const InstJumpTable *JumpTable) const override;
-
public:
~TargetX8632() = default;
ENABLE_MAKE_UNIQUE;
friend class X8632::TargetX86Base<X8632::Traits>;
+ explicit TargetX8632(Cfg *Func) : TargetX86Base(Func) {}
+
Operand *createNaClReadTPSrcOperand() {
Constant *Zero = Ctx->getConstantZero(IceType_i32);
return Traits::X86OperandMem::create(Func, IceType_i32, nullptr, Zero,
nullptr, 0,
Traits::X86OperandMem::SegReg_GS);
}
-
- explicit TargetX8632(Cfg *Func) : TargetX86Base(Func) {}
-};
-
-class TargetDataX8632 final : public TargetDataLowering {
- TargetDataX8632() = delete;
- TargetDataX8632(const TargetDataX8632 &) = delete;
- TargetDataX8632 &operator=(const TargetDataX8632 &) = delete;
-
-public:
- ~TargetDataX8632() override = default;
-
- static std::unique_ptr<TargetDataLowering> create(GlobalContext *Ctx) {
- return makeUnique<TargetDataX8632>(Ctx);
- }
-
- void lowerGlobals(const VariableDeclarationList &Vars,
- const IceString &SectionSuffix) override;
- void lowerConstants() override;
- void lowerJumpTables() override;
-
-private:
- ENABLE_MAKE_UNIQUE;
-
- explicit TargetDataX8632(GlobalContext *Ctx);
- template <typename T> static void emitConstantPool(GlobalContext *Ctx);
-};
-
-class TargetHeaderX8632 final : public TargetHeaderLowering {
- TargetHeaderX8632() = delete;
- TargetHeaderX8632(const TargetHeaderX8632 &) = delete;
- TargetHeaderX8632 &operator=(const TargetHeaderX8632 &) = delete;
-
-public:
- static std::unique_ptr<TargetHeaderLowering> create(GlobalContext *Ctx) {
- return std::unique_ptr<TargetHeaderLowering>(new TargetHeaderX8632(Ctx));
- }
-
-protected:
- explicit TargetHeaderX8632(GlobalContext *Ctx);
-
-private:
- ~TargetHeaderX8632() = default;
};
} // end of namespace X8632
std::unique_ptr<::Ice::TargetDataLowering>
createTargetDataLowering(::Ice::GlobalContext *Ctx) {
- return ::Ice::X8664::TargetDataX8664::create(Ctx);
+ return ::Ice::X8664::TargetDataX86<::Ice::X8664::TargetX8664Traits>::create(
+ Ctx);
}
std::unique_ptr<::Ice::TargetHeaderLowering>
createTargetHeaderLowering(::Ice::GlobalContext *Ctx) {
- return ::Ice::X8664::TargetHeaderX8664::create(Ctx);
+ return ::Ice::X8664::TargetHeaderX86::create(Ctx);
}
void staticInit(::Ice::GlobalContext *Ctx) {
}
}
-void TargetX8664::emitJumpTable(const Cfg *Func,
- const InstJumpTable *JumpTable) const {
- if (!BuildDefs::dump())
- return;
- Ostream &Str = Ctx->getStrEmit();
- IceString MangledName = Ctx->mangleName(Func->getFunctionName());
- Str << "\t.section\t.rodata." << MangledName
- << "$jumptable,\"a\",@progbits\n";
- Str << "\t.align\t" << typeWidthInBytes(getPointerType()) << "\n";
- Str << InstJumpTable::makeName(MangledName, JumpTable->getId()) << ":";
-
- // On X8664 ILP32 pointers are 32-bit hence the use of .long
- for (SizeT I = 0; I < JumpTable->getNumTargets(); ++I)
- Str << "\n\t.long\t" << JumpTable->getTarget(I)->getAsmName();
- Str << "\n";
-}
-
-namespace {
-template <typename T> struct PoolTypeConverter {};
-
-template <> struct PoolTypeConverter<float> {
- using PrimitiveIntType = uint32_t;
- using IceType = ConstantFloat;
- 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> {
- using PrimitiveIntType = uint64_t;
- using IceType = ConstantDouble;
- 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> {
- using PrimitiveIntType = uint32_t;
- using IceType = ConstantInteger32;
- 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> {
- using PrimitiveIntType = uint32_t;
- using IceType = ConstantInteger32;
- 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> {
- using PrimitiveIntType = uint32_t;
- using IceType = ConstantInteger32;
- 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()) {
- // Use the constant's kind value as the salt for creating random number
- // generator.
- Operand::OperandKind K = (*Pool.begin())->getKind();
- RandomNumberGenerator RNG(Ctx->getFlags().getRandomSeed(),
- RPE_PooledConstantReordering, K);
- RandomShuffle(Pool.begin(), Pool.end(),
- [&RNG](uint64_t N) { return (uint32_t)RNG.next(N); });
- }
-
- for (Constant *C : Pool) {
- if (!C->getShouldBePooled())
- continue;
- auto *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, Ctx);
- Str << ":\n\t" << T::AsmTag << "\t" << buf << "\t/* " << T::TypeName << " "
- << Value << " */\n";
- }
-}
-
-void TargetDataX8664::lowerConstants() {
- 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::lowerJumpTables() {
- const bool IsPIC = Ctx->getFlags().getUseNonsfi();
- switch (Ctx->getFlags().getOutFileType()) {
- case FT_Elf: {
- ELFObjectWriter *Writer = Ctx->getObjectWriter();
- for (const JumpTableData &JumpTable : Ctx->getJumpTables())
- Writer->writeJumpTable(JumpTable, TargetX8664::Traits::FK_Abs, IsPIC);
- } break;
- case FT_Asm:
- // Already emitted from Cfg
- break;
- case FT_Iasm: {
- if (!BuildDefs::dump())
- return;
- Ostream &Str = Ctx->getStrEmit();
- for (const JumpTableData &JT : Ctx->getJumpTables()) {
- Str << "\t.section\t.rodata." << JT.getFunctionName()
- << "$jumptable,\"a\",@progbits\n";
- Str << "\t.align\t" << typeWidthInBytes(getPointerType()) << "\n";
- Str << InstJumpTable::makeName(JT.getFunctionName(), JT.getId()) << ":";
-
- // On X8664 ILP32 pointers are 32-bit hence the use of .long
- for (intptr_t TargetOffset : JT.getTargetOffsets())
- Str << "\n\t.long\t" << JT.getFunctionName() << "+" << TargetOffset;
- Str << "\n";
- }
- } break;
- }
-}
-
-void TargetDataX8664::lowerGlobals(const VariableDeclarationList &Vars,
- const IceString &SectionSuffix) {
- const bool IsPIC = Ctx->getFlags().getUseNonsfi();
- switch (Ctx->getFlags().getOutFileType()) {
- case FT_Elf: {
- ELFObjectWriter *Writer = Ctx->getObjectWriter();
- Writer->writeDataSection(Vars, TargetX8664::Traits::FK_Abs, SectionSuffix,
- IsPIC);
- } 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
TargetX8664(const TargetX8664 &) = delete;
TargetX8664 &operator=(const TargetX8664 &) = delete;
- void emitJumpTable(const Cfg *Func,
- const InstJumpTable *JumpTable) const override;
-
public:
~TargetX8664() = default;
return makeUnique<X8664::AssemblerX8664>(EmitAddrSizeOverridePrefix);
}
- bool needSandboxing() const { return NeedSandboxing; }
-
protected:
void _add_sp(Operand *Adjustment);
void _mov_sp(Operand *NewValue);
- void _push_rbp();
Traits::X86OperandMem *_sandbox_mem_reference(X86OperandMem *Mem);
void _sub_sp(Operand *Adjustment);
void _link_bp();
ENABLE_MAKE_UNIQUE;
friend class X8664::TargetX86Base<X8664::Traits>;
- explicit TargetX8664(Cfg *Func)
- : ::Ice::X8664::TargetX86Base<X8664::Traits>(Func) {}
+ explicit TargetX8664(Cfg *Func) : TargetX86Base(Func) {}
+
+ void _push_rbp();
Operand *createNaClReadTPSrcOperand() {
Variable *TDB = makeReg(IceType_i32);
}
};
-class TargetDataX8664 : public TargetDataLowering {
- TargetDataX8664() = delete;
- TargetDataX8664(const TargetDataX8664 &) = delete;
- TargetDataX8664 &operator=(const TargetDataX8664 &) = delete;
-
-public:
- ~TargetDataX8664() override = default;
-
- static std::unique_ptr<TargetDataLowering> create(GlobalContext *Ctx) {
- return makeUnique<TargetDataX8664>(Ctx);
- }
-
- void lowerGlobals(const VariableDeclarationList &Vars,
- const IceString &SectionSuffix) override;
-
- void lowerConstants() override;
- void lowerJumpTables() override;
-
-private:
- ENABLE_MAKE_UNIQUE;
-
- explicit TargetDataX8664(GlobalContext *Ctx) : TargetDataLowering(Ctx) {}
- template <typename T> static void emitConstantPool(GlobalContext *Ctx);
-};
-
-class TargetHeaderX8664 : public TargetHeaderLowering {
- TargetHeaderX8664() = delete;
- TargetHeaderX8664(const TargetHeaderX8664 &) = delete;
- TargetHeaderX8664 &operator=(const TargetHeaderX8664 &) = delete;
-
-public:
- ~TargetHeaderX8664() = default;
-
- static std::unique_ptr<TargetHeaderLowering> create(GlobalContext *Ctx) {
- return makeUnique<TargetHeaderX8664>(Ctx);
- }
-
-private:
- ENABLE_MAKE_UNIQUE;
-
- explicit TargetHeaderX8664(GlobalContext *Ctx) : TargetHeaderLowering(Ctx) {}
-};
-
} // end of namespace X8664
} // end of namespace Ice
virtual Variable *moveReturnValueToRegister(Operand *Value,
Type ReturnType) = 0;
+ /// Emit a jump table to the constant pool.
+ void emitJumpTable(const Cfg *Func,
+ const InstJumpTable *JumpTable) const override;
+
/// Emit a fake use of esp to make sure esp stays alive for the entire
/// function. Otherwise some esp adjustments get dead-code eliminated.
void keepEspLiveAtExit() {
static FixupKind PcRelFixup;
static FixupKind AbsFixup;
};
+
+template <typename TraitsType>
+class TargetDataX86 final : public TargetDataLowering {
+ using Traits = TraitsType;
+ TargetDataX86() = delete;
+ TargetDataX86(const TargetDataX86 &) = delete;
+ TargetDataX86 &operator=(const TargetDataX86 &) = delete;
+
+public:
+ ~TargetDataX86() override = default;
+
+ static std::unique_ptr<TargetDataLowering> create(GlobalContext *Ctx) {
+ return makeUnique<TargetDataX86>(Ctx);
+ }
+
+ void lowerGlobals(const VariableDeclarationList &Vars,
+ const IceString &SectionSuffix) override;
+ void lowerConstants() override;
+ void lowerJumpTables() override;
+
+private:
+ ENABLE_MAKE_UNIQUE;
+
+ explicit TargetDataX86(GlobalContext *Ctx) : TargetDataLowering(Ctx){};
+ template <typename T> static void emitConstantPool(GlobalContext *Ctx);
+};
+
+class TargetHeaderX86 : public TargetHeaderLowering {
+ TargetHeaderX86() = delete;
+ TargetHeaderX86(const TargetHeaderX86 &) = delete;
+ TargetHeaderX86 &operator=(const TargetHeaderX86 &) = delete;
+
+public:
+ ~TargetHeaderX86() = default;
+
+ static std::unique_ptr<TargetHeaderLowering> create(GlobalContext *Ctx) {
+ return makeUnique<TargetHeaderX86>(Ctx);
+ }
+
+private:
+ ENABLE_MAKE_UNIQUE;
+
+ explicit TargetHeaderX86(GlobalContext *Ctx) : TargetHeaderLowering(Ctx) {}
+};
+
} // end of namespace X86NAMESPACE
} // end of namespace Ice
#include <stack>
namespace Ice {
+namespace X86 {
+template <typename T> struct PoolTypeConverter {};
+
+template <> struct PoolTypeConverter<float> {
+ using PrimitiveIntType = uint32_t;
+ using IceType = ConstantFloat;
+ static const Type Ty = IceType_f32;
+ static const char *TypeName;
+ static const char *AsmTag;
+ static const char *PrintfString;
+};
+
+template <> struct PoolTypeConverter<double> {
+ using PrimitiveIntType = uint64_t;
+ using IceType = ConstantDouble;
+ static const Type Ty = IceType_f64;
+ static const char *TypeName;
+ static const char *AsmTag;
+ static const char *PrintfString;
+};
+
+// Add converter for int type constant pooling
+template <> struct PoolTypeConverter<uint32_t> {
+ using PrimitiveIntType = uint32_t;
+ using IceType = ConstantInteger32;
+ static const Type Ty = IceType_i32;
+ static const char *TypeName;
+ static const char *AsmTag;
+ static const char *PrintfString;
+};
+
+// Add converter for int type constant pooling
+template <> struct PoolTypeConverter<uint16_t> {
+ using PrimitiveIntType = uint32_t;
+ using IceType = ConstantInteger32;
+ static const Type Ty = IceType_i16;
+ static const char *TypeName;
+ static const char *AsmTag;
+ static const char *PrintfString;
+};
+
+// Add converter for int type constant pooling
+template <> struct PoolTypeConverter<uint8_t> {
+ using PrimitiveIntType = uint32_t;
+ using IceType = ConstantInteger32;
+ static const Type Ty = IceType_i8;
+ static const char *TypeName;
+ static const char *AsmTag;
+ static const char *PrintfString;
+};
+} // end of namespace X86
+
namespace X86NAMESPACE {
/// A helper class to ease the settings of RandomizationPoolingPause to disable
}
}
}
+
+template <typename TraitsType>
+void TargetX86Base<TraitsType>::emitJumpTable(
+ const Cfg *Func, const InstJumpTable *JumpTable) const {
+ if (!BuildDefs::dump())
+ return;
+ Ostream &Str = Ctx->getStrEmit();
+ const bool UseNonsfi = Ctx->getFlags().getUseNonsfi();
+ const IceString MangledName = Ctx->mangleName(Func->getFunctionName());
+ const IceString Prefix = UseNonsfi ? ".data.rel.ro." : ".rodata.";
+ Str << "\t.section\t" << Prefix << MangledName
+ << "$jumptable,\"a\",@progbits\n";
+ Str << "\t.align\t" << typeWidthInBytes(getPointerType()) << "\n";
+ Str << InstJumpTable::makeName(MangledName, JumpTable->getId()) << ":";
+
+ // On X86 ILP32 pointers are 32-bit hence the use of .long
+ for (SizeT I = 0; I < JumpTable->getNumTargets(); ++I)
+ Str << "\n\t.long\t" << JumpTable->getTarget(I)->getAsmName();
+ Str << "\n";
+}
+
+template <typename TraitsType>
+template <typename T>
+void TargetDataX86<TraitsType>::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() && !Pool.empty()) {
+ // Use the constant's kind value as the salt for creating random number
+ // generator.
+ Operand::OperandKind K = (*Pool.begin())->getKind();
+ RandomNumberGenerator RNG(Ctx->getFlags().getRandomSeed(),
+ RPE_PooledConstantReordering, K);
+ RandomShuffle(Pool.begin(), Pool.end(),
+ [&RNG](uint64_t N) { return (uint32_t)RNG.next(N); });
+ }
+
+ for (Constant *C : Pool) {
+ if (!C->getShouldBePooled())
+ continue;
+ auto *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);
+ assert((size_t)CharsPrinted < llvm::array_lengthof(buf));
+ (void)CharsPrinted; // avoid warnings if asserts are disabled
+ Const->emitPoolLabel(Str, Ctx);
+ Str << ":\n\t" << T::AsmTag << "\t" << buf << "\t/* " << T::TypeName << " "
+ << Value << " */\n";
+ }
+}
+
+template <typename TraitsType>
+void TargetDataX86<TraitsType>::lowerConstants() {
+ if (Ctx->getFlags().getDisableTranslation())
+ return;
+ 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;
+ }
+}
+
+template <typename TraitsType>
+void TargetDataX86<TraitsType>::lowerJumpTables() {
+ const bool IsPIC = Ctx->getFlags().getUseNonsfi();
+ switch (Ctx->getFlags().getOutFileType()) {
+ case FT_Elf: {
+ ELFObjectWriter *Writer = Ctx->getObjectWriter();
+ for (const JumpTableData &JT : Ctx->getJumpTables())
+ Writer->writeJumpTable(JT, Traits::FK_Abs, IsPIC);
+ } break;
+ case FT_Asm:
+ // Already emitted from Cfg
+ break;
+ case FT_Iasm: {
+ if (!BuildDefs::dump())
+ return;
+ Ostream &Str = Ctx->getStrEmit();
+ const IceString Prefix = IsPIC ? ".data.rel.ro." : ".rodata.";
+ for (const JumpTableData &JT : Ctx->getJumpTables()) {
+ Str << "\t.section\t" << Prefix << JT.getFunctionName()
+ << "$jumptable,\"a\",@progbits\n";
+ Str << "\t.align\t" << typeWidthInBytes(getPointerType()) << "\n";
+ Str << InstJumpTable::makeName(JT.getFunctionName(), JT.getId()) << ":";
+
+ // On X8664 ILP32 pointers are 32-bit hence the use of .long
+ for (intptr_t TargetOffset : JT.getTargetOffsets())
+ Str << "\n\t.long\t" << JT.getFunctionName() << "+" << TargetOffset;
+ Str << "\n";
+ }
+ } break;
+ }
+}
+
+template <typename TraitsType>
+void TargetDataX86<TraitsType>::lowerGlobals(
+ const VariableDeclarationList &Vars, const IceString &SectionSuffix) {
+ const bool IsPIC = Ctx->getFlags().getUseNonsfi();
+ switch (Ctx->getFlags().getOutFileType()) {
+ case FT_Elf: {
+ ELFObjectWriter *Writer = Ctx->getObjectWriter();
+ Writer->writeDataSection(Vars, Traits::FK_Abs, SectionSuffix, IsPIC);
+ } 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;
+ }
+}
} // end of namespace X86NAMESPACE
} // end of namespace Ice