Commit 6b80cf10 by David Sehr

Merge x86 data and header lowering

BUG= R=stichnot@chromium.org Review URL: https://codereview.chromium.org/1616673004 .
parent 2c3c82e2
...@@ -250,6 +250,7 @@ SRCS = \ ...@@ -250,6 +250,7 @@ SRCS = \
IceTargetLowering.cpp \ IceTargetLowering.cpp \
IceTargetLoweringARM32.cpp \ IceTargetLoweringARM32.cpp \
IceTargetLoweringMIPS32.cpp \ IceTargetLoweringMIPS32.cpp \
IceTargetLoweringX86.cpp \
IceTargetLoweringX8632.cpp \ IceTargetLoweringX8632.cpp \
IceTargetLoweringX8664.cpp \ IceTargetLoweringX8664.cpp \
IceAssembler.cpp \ IceAssembler.cpp \
......
//===---- 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
...@@ -24,12 +24,13 @@ std::unique_ptr<::Ice::TargetLowering> createTargetLowering(::Ice::Cfg *Func) { ...@@ -24,12 +24,13 @@ std::unique_ptr<::Ice::TargetLowering> createTargetLowering(::Ice::Cfg *Func) {
std::unique_ptr<::Ice::TargetDataLowering> std::unique_ptr<::Ice::TargetDataLowering>
createTargetDataLowering(::Ice::GlobalContext *Ctx) { createTargetDataLowering(::Ice::GlobalContext *Ctx) {
return ::Ice::X8632::TargetDataX8632::create(Ctx); return ::Ice::X8632::TargetDataX86<::Ice::X8632::TargetX8632Traits>::create(
Ctx);
} }
std::unique_ptr<::Ice::TargetHeaderLowering> std::unique_ptr<::Ice::TargetHeaderLowering>
createTargetHeaderLowering(::Ice::GlobalContext *Ctx) { createTargetHeaderLowering(::Ice::GlobalContext *Ctx) {
return ::Ice::X8632::TargetHeaderX8632::create(Ctx); return ::Ice::X8632::TargetHeaderX86::create(Ctx);
} }
void staticInit(::Ice::GlobalContext *Ctx) { void staticInit(::Ice::GlobalContext *Ctx) {
...@@ -269,228 +270,6 @@ void TargetX8632::emitSandboxedReturn() { ...@@ -269,228 +270,6 @@ void TargetX8632::emitSandboxedReturn() {
lowerIndirectJump(T_ecx); 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 // 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 // instructions/operands that use the same enum key value. The tables are kept
// separate to maintain a proper separation between abstraction layers. There // separate to maintain a proper separation between abstraction layers. There
......
...@@ -34,9 +34,6 @@ class TargetX8632 final : public ::Ice::X8632::TargetX86Base<X8632::Traits> { ...@@ -34,9 +34,6 @@ class TargetX8632 final : public ::Ice::X8632::TargetX86Base<X8632::Traits> {
TargetX8632(const TargetX8632 &) = delete; TargetX8632(const TargetX8632 &) = delete;
TargetX8632 &operator=(const TargetX8632 &) = delete; TargetX8632 &operator=(const TargetX8632 &) = delete;
void emitJumpTable(const Cfg *Func,
const InstJumpTable *JumpTable) const override;
public: public:
~TargetX8632() = default; ~TargetX8632() = default;
...@@ -70,55 +67,14 @@ private: ...@@ -70,55 +67,14 @@ private:
ENABLE_MAKE_UNIQUE; ENABLE_MAKE_UNIQUE;
friend class X8632::TargetX86Base<X8632::Traits>; friend class X8632::TargetX86Base<X8632::Traits>;
explicit TargetX8632(Cfg *Func) : TargetX86Base(Func) {}
Operand *createNaClReadTPSrcOperand() { Operand *createNaClReadTPSrcOperand() {
Constant *Zero = Ctx->getConstantZero(IceType_i32); Constant *Zero = Ctx->getConstantZero(IceType_i32);
return Traits::X86OperandMem::create(Func, IceType_i32, nullptr, Zero, return Traits::X86OperandMem::create(Func, IceType_i32, nullptr, Zero,
nullptr, 0, nullptr, 0,
Traits::X86OperandMem::SegReg_GS); 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 } // end of namespace X8632
......
...@@ -24,12 +24,13 @@ std::unique_ptr<::Ice::TargetLowering> createTargetLowering(::Ice::Cfg *Func) { ...@@ -24,12 +24,13 @@ std::unique_ptr<::Ice::TargetLowering> createTargetLowering(::Ice::Cfg *Func) {
std::unique_ptr<::Ice::TargetDataLowering> std::unique_ptr<::Ice::TargetDataLowering>
createTargetDataLowering(::Ice::GlobalContext *Ctx) { createTargetDataLowering(::Ice::GlobalContext *Ctx) {
return ::Ice::X8664::TargetDataX8664::create(Ctx); return ::Ice::X8664::TargetDataX86<::Ice::X8664::TargetX8664Traits>::create(
Ctx);
} }
std::unique_ptr<::Ice::TargetHeaderLowering> std::unique_ptr<::Ice::TargetHeaderLowering>
createTargetHeaderLowering(::Ice::GlobalContext *Ctx) { createTargetHeaderLowering(::Ice::GlobalContext *Ctx) {
return ::Ice::X8664::TargetHeaderX8664::create(Ctx); return ::Ice::X8664::TargetHeaderX86::create(Ctx);
} }
void staticInit(::Ice::GlobalContext *Ctx) { void staticInit(::Ice::GlobalContext *Ctx) {
...@@ -547,218 +548,6 @@ void TargetX8664::emitSandboxedReturn() { ...@@ -547,218 +548,6 @@ void TargetX8664::emitSandboxedReturn() {
} }
} }
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 // 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 // instructions/operands that use the same enum key value. The tables are kept
// separate to maintain a proper separation between abstraction layers. There // separate to maintain a proper separation between abstraction layers. There
......
...@@ -34,9 +34,6 @@ class TargetX8664 final : public X8664::TargetX86Base<X8664::Traits> { ...@@ -34,9 +34,6 @@ class TargetX8664 final : public X8664::TargetX86Base<X8664::Traits> {
TargetX8664(const TargetX8664 &) = delete; TargetX8664(const TargetX8664 &) = delete;
TargetX8664 &operator=(const TargetX8664 &) = delete; TargetX8664 &operator=(const TargetX8664 &) = delete;
void emitJumpTable(const Cfg *Func,
const InstJumpTable *JumpTable) const override;
public: public:
~TargetX8664() = default; ~TargetX8664() = default;
...@@ -49,12 +46,9 @@ public: ...@@ -49,12 +46,9 @@ public:
return makeUnique<X8664::AssemblerX8664>(EmitAddrSizeOverridePrefix); return makeUnique<X8664::AssemblerX8664>(EmitAddrSizeOverridePrefix);
} }
bool needSandboxing() const { return NeedSandboxing; }
protected: protected:
void _add_sp(Operand *Adjustment); void _add_sp(Operand *Adjustment);
void _mov_sp(Operand *NewValue); void _mov_sp(Operand *NewValue);
void _push_rbp();
Traits::X86OperandMem *_sandbox_mem_reference(X86OperandMem *Mem); Traits::X86OperandMem *_sandbox_mem_reference(X86OperandMem *Mem);
void _sub_sp(Operand *Adjustment); void _sub_sp(Operand *Adjustment);
void _link_bp(); void _link_bp();
...@@ -72,8 +66,9 @@ private: ...@@ -72,8 +66,9 @@ private:
ENABLE_MAKE_UNIQUE; ENABLE_MAKE_UNIQUE;
friend class X8664::TargetX86Base<X8664::Traits>; friend class X8664::TargetX86Base<X8664::Traits>;
explicit TargetX8664(Cfg *Func) explicit TargetX8664(Cfg *Func) : TargetX86Base(Func) {}
: ::Ice::X8664::TargetX86Base<X8664::Traits>(Func) {}
void _push_rbp();
Operand *createNaClReadTPSrcOperand() { Operand *createNaClReadTPSrcOperand() {
Variable *TDB = makeReg(IceType_i32); Variable *TDB = makeReg(IceType_i32);
...@@ -83,49 +78,6 @@ private: ...@@ -83,49 +78,6 @@ private:
} }
}; };
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 X8664
} // end of namespace Ice } // end of namespace Ice
......
...@@ -298,6 +298,10 @@ protected: ...@@ -298,6 +298,10 @@ protected:
virtual Variable *moveReturnValueToRegister(Operand *Value, virtual Variable *moveReturnValueToRegister(Operand *Value,
Type ReturnType) = 0; 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 /// Emit a fake use of esp to make sure esp stays alive for the entire
/// function. Otherwise some esp adjustments get dead-code eliminated. /// function. Otherwise some esp adjustments get dead-code eliminated.
void keepEspLiveAtExit() { void keepEspLiveAtExit() {
...@@ -1020,6 +1024,51 @@ private: ...@@ -1020,6 +1024,51 @@ private:
static FixupKind PcRelFixup; static FixupKind PcRelFixup;
static FixupKind AbsFixup; 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 X86NAMESPACE
} // end of namespace Ice } // end of namespace Ice
......
...@@ -33,6 +33,58 @@ ...@@ -33,6 +33,58 @@
#include <stack> #include <stack>
namespace Ice { 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 { namespace X86NAMESPACE {
/// A helper class to ease the settings of RandomizationPoolingPause to disable /// A helper class to ease the settings of RandomizationPoolingPause to disable
...@@ -7229,6 +7281,156 @@ TargetX86Base<TraitsType>::randomizeOrPoolImmediate(X86OperandMem *MemOperand, ...@@ -7229,6 +7281,156 @@ TargetX86Base<TraitsType>::randomizeOrPoolImmediate(X86OperandMem *MemOperand,
} }
} }
} }
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 X86NAMESPACE
} // end of namespace Ice } // end of namespace Ice
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment