Commit 989a703f by Jim Stichnoth

Subzero: Add the "llvm2ice -ffunction-sections" argument.

The purpose is to enable bisection debugging of Subzero-translated functions, using objcopy to selectively splice functions from llc and Subzero into the binary. Note that llvm-mc claims to take this argument, but actually does nothing with it, so we need to implement it in Subzero. Also moves the ClFlags object into the GlobalContext so everyone can access it. BUG= none R=wala@chromium.org Review URL: https://codereview.chromium.org/455633002
parent 51e8cfba
......@@ -14,6 +14,7 @@
#include "IceCfg.h"
#include "IceCfgNode.h"
#include "IceClFlags.h"
#include "IceDefs.h"
#include "IceInst.h"
#include "IceLiveness.h"
......@@ -300,8 +301,10 @@ void Cfg::emit() {
<< "\n\n";
}
Str << "\t.text\n";
IceString MangledName = getContext()->mangleName(getFunctionName());
if (Ctx->getFlags().FunctionSections)
Str << "\t.section\t.text." << MangledName << "\n";
if (!getInternal()) {
IceString MangledName = getContext()->mangleName(getFunctionName());
Str << "\t.globl\t" << MangledName << "\n";
Str << "\t.type\t" << MangledName << ",@function\n";
}
......
......@@ -20,12 +20,15 @@ class ClFlags {
public:
ClFlags()
: DisableInternal(false), SubzeroTimingEnabled(false),
DisableTranslation(false), DisableGlobals(false) {}
DisableTranslation(false), DisableGlobals(false),
FunctionSections(false) {}
bool DisableInternal;
bool SubzeroTimingEnabled;
bool DisableTranslation;
bool DisableGlobals;
bool FunctionSections;
};
}
} // end of namespace Ice
#endif // SUBZERO_SRC_ICECLFLAGS_H
......@@ -676,12 +676,12 @@ private:
std::map<const BasicBlock *, Ice::CfgNode *> NodeMap;
};
} // end of anonymous namespace.
} // end of anonymous namespace
namespace Ice {
void Converter::convertToIce(Module *Mod) {
if (!Flags.DisableGlobals)
if (!Ctx->getFlags().DisableGlobals)
convertGlobals(Mod);
convertFunctions(Mod);
}
......@@ -723,7 +723,8 @@ void Converter::convertGlobals(Module *Mod) {
}
GlobalLowering->lower(Name, Align, IsInternal, IsConst, IsZeroInitializer,
NumElements, Data, Flags.DisableTranslation);
NumElements, Data,
Ctx->getFlags().DisableTranslation);
}
GlobalLowering.reset();
}
......@@ -736,7 +737,7 @@ void Converter::convertFunctions(Module *Mod) {
Timer TConvert;
Cfg *Fcn = FunctionConverter.convertFunction(I);
if (Flags.SubzeroTimingEnabled) {
if (Ctx->getFlags().SubzeroTimingEnabled) {
std::cerr << "[Subzero timing] Convert function "
<< Fcn->getFunctionName() << ": " << TConvert.getElapsedSec()
<< " sec\n";
......@@ -747,4 +748,4 @@ void Converter::convertFunctions(Module *Mod) {
emitConstants();
}
} // end of Ice namespace.
} // end of namespace Ice
......@@ -24,7 +24,7 @@ namespace Ice {
class Converter : public Translator {
public:
Converter(GlobalContext *Ctx, Ice::ClFlags &Flags) : Translator(Ctx, Flags) {}
Converter(GlobalContext *Ctx) : Translator(Ctx) {}
/// Converts the LLVM Module to ICE. Sets exit status to false if successful,
/// true otherwise.
void convertToIce(llvm::Module *Mod);
......
......@@ -18,6 +18,7 @@
#include "IceDefs.h"
#include "IceTypes.h"
#include "IceCfg.h"
#include "IceClFlags.h"
#include "IceGlobalContext.h"
#include "IceOperand.h"
#include "IceTargetLowering.h"
......@@ -116,10 +117,10 @@ public:
GlobalContext::GlobalContext(llvm::raw_ostream *OsDump,
llvm::raw_ostream *OsEmit, VerboseMask Mask,
TargetArch Arch, OptLevel Opt,
IceString TestPrefix)
IceString TestPrefix, const ClFlags &Flags)
: StrDump(OsDump), StrEmit(OsEmit), VMask(Mask),
ConstPool(new ConstantPool()), Arch(Arch), Opt(Opt),
TestPrefix(TestPrefix), HasEmittedFirstMethod(false) {}
TestPrefix(TestPrefix), Flags(Flags), HasEmittedFirstMethod(false) {}
// Scan a string for S[0-9A-Z]*_ patterns and replace them with
// S<num>_ where <num> is the next base-36 value. If a type name
......
......@@ -25,6 +25,8 @@
namespace Ice {
class ClFlags;
// TODO: Accesses to all non-const fields of GlobalContext need to
// be synchronized, especially the constant pool, the allocator, and
// the output streams.
......@@ -32,7 +34,7 @@ class GlobalContext {
public:
GlobalContext(llvm::raw_ostream *OsDump, llvm::raw_ostream *OsEmit,
VerboseMask Mask, TargetArch Arch, OptLevel Opt,
IceString TestPrefix);
IceString TestPrefix, const ClFlags &Flags);
~GlobalContext();
// Returns true if any of the specified options in the verbose mask
......@@ -86,6 +88,8 @@ public:
// constants of a given type.
ConstantList getConstantPool(Type Ty) const;
const ClFlags &getFlags() const { return Flags; }
// Allocate data of type T using the global allocator.
template <typename T> T *allocate() { return Allocator.Allocate<T>(); }
......@@ -102,6 +106,7 @@ private:
const TargetArch Arch;
const OptLevel Opt;
const IceString TestPrefix;
const ClFlags &Flags;
bool HasEmittedFirstMethod;
GlobalContext(const GlobalContext &) LLVM_DELETED_FUNCTION;
GlobalContext &operator=(const GlobalContext &) LLVM_DELETED_FUNCTION;
......
......@@ -179,7 +179,7 @@ const struct IceIntrinsicsEntry_ {
};
const size_t IceIntrinsicsTableSize = llvm::array_lengthof(IceIntrinsicsTable);
} // end of namespace
} // end of anonymous namespace
Intrinsics::Intrinsics() {
for (size_t I = 0; I < IceIntrinsicsTableSize; ++I) {
......
......@@ -26,14 +26,14 @@ Translator::~Translator() {}
void Translator::translateFcn(Ice::Cfg *Fcn) {
Func.reset(Fcn);
if (Flags.DisableInternal)
if (Ctx->getFlags().DisableInternal)
Func->setInternal(false);
if (Flags.DisableTranslation) {
if (Ctx->getFlags().DisableTranslation) {
Func->dump();
} else {
Ice::Timer TTranslate;
Func->translate();
if (Flags.SubzeroTimingEnabled) {
if (Ctx->getFlags().SubzeroTimingEnabled) {
std::cerr << "[Subzero timing] Translate function "
<< Func->getFunctionName() << ": " << TTranslate.getElapsedSec()
<< " sec\n";
......@@ -45,7 +45,7 @@ void Translator::translateFcn(Ice::Cfg *Fcn) {
Ice::Timer TEmit;
Func->emit();
if (Flags.SubzeroTimingEnabled) {
if (Ctx->getFlags().SubzeroTimingEnabled) {
std::cerr << "[Subzero timing] Emit function " << Func->getFunctionName()
<< ": " << TEmit.getElapsedSec() << " sec\n";
}
......@@ -53,6 +53,6 @@ void Translator::translateFcn(Ice::Cfg *Fcn) {
}
void Translator::emitConstants() {
if (!Flags.DisableTranslation && Func)
if (!Ctx->getFlags().DisableTranslation && Func)
Func->getTarget()->emitConstants();
}
......@@ -29,15 +29,13 @@ class GlobalContext;
// machine instructions.
class Translator {
public:
Translator(GlobalContext *Ctx, ClFlags &Flags)
: Ctx(Ctx), Flags(Flags), ErrorStatus(0) {}
Translator(GlobalContext *Ctx) : Ctx(Ctx), ErrorStatus(0) {}
~Translator();
bool getErrorStatus() const { return ErrorStatus; }
protected:
GlobalContext *Ctx;
ClFlags &Flags;
// The exit status of the translation. False is successful. True
// otherwise.
bool ErrorStatus;
......
......@@ -801,7 +801,7 @@ bool TopLevelParser::ParseBlock(unsigned BlockID) {
return Parser.ParseThisBlock();
}
} // end of anonymous namespace.
} // end of anonymous namespace
namespace Ice {
......@@ -856,4 +856,4 @@ void PNaClTranslator::translate(const std::string &IRFilename) {
return;
}
} // end of anonymous namespace.
} // end of namespace Ice
......@@ -22,8 +22,7 @@ namespace Ice {
class PNaClTranslator : public Translator {
public:
PNaClTranslator(GlobalContext *Ctx, ClFlags &Flags)
: Translator(Ctx, Flags) {}
PNaClTranslator(GlobalContext *Ctx) : Translator(Ctx) {}
// Reads the PNaCl bitcode file and translates to ICE, which is then
// converted to machine code. Sets ErrorStatus to true if any
// errors occurred.
......
......@@ -59,6 +59,9 @@ static cl::opt<Ice::TargetArch> TargetArch(
clEnumValN(Ice::Target_ARM32, "arm", "arm32"),
clEnumValN(Ice::Target_ARM32, "arm32", "arm32 (same as arm)"),
clEnumValN(Ice::Target_ARM64, "arm64", "arm64"), clEnumValEnd));
static cl::opt<bool>
FunctionSections("ffunction-sections",
cl::desc("Emit functions into separate sections"));
static cl::opt<Ice::OptLevel>
OptLevel(cl::desc("Optimization level"), cl::init(Ice::Opt_m1),
cl::value_desc("level"),
......@@ -126,16 +129,18 @@ int main(int argc, char **argv) {
raw_os_ostream *Ls = new raw_os_ostream(LogFilename == "-" ? std::cout : Lfs);
Ls->SetUnbuffered();
Ice::GlobalContext Ctx(Ls, Os, VMask, TargetArch, OptLevel, TestPrefix);
Ice::ClFlags Flags;
Flags.DisableInternal = DisableInternal;
Flags.SubzeroTimingEnabled = SubzeroTimingEnabled;
Flags.DisableTranslation = DisableTranslation;
Flags.DisableGlobals = DisableGlobals;
Flags.FunctionSections = FunctionSections;
Ice::GlobalContext Ctx(Ls, Os, VMask, TargetArch, OptLevel, TestPrefix,
Flags);
if (BuildOnRead) {
Ice::PNaClTranslator Translator(&Ctx, Flags);
Ice::PNaClTranslator Translator(&Ctx);
Translator.translate(IRFilename);
return Translator.getErrorStatus();
} else {
......@@ -155,7 +160,7 @@ int main(int argc, char **argv) {
return 1;
}
Ice::Converter Converter(&Ctx, Flags);
Ice::Converter Converter(&Ctx);
Converter.convertToIce(Mod);
return Converter.getErrorStatus();
}
......
; Tests the Subzero "name mangling" when using the "llvm2ice --prefix"
; option.
; option. Also does a quick smoke test of -ffunction-sections.
; RUN: %llvm2ice --verbose none %s | FileCheck %s
; RUN: %llvm2ice --verbose none -ffunction-sections %s | FileCheck %s
; TODO: The following line causes this test to fail.
; RUIN: %llvm2ice --verbose none %s \
; RUIN: | llvm-mc -arch=x86 -x86-asm-syntax=intel -filetype=obj
; RUN: %llvm2ice --verbose none --prefix Subzero %s | FileCheck --check-prefix=MANGLE %s
; RUN: %llvm2ice --verbose none --prefix Subzero -ffunction-sections %s \
; RUN: | FileCheck --check-prefix=MANGLE %s
; RUN: %llvm2ice --verbose none %s | FileCheck --check-prefix=ERRORS %s
; RUN: %llvm2iceinsts %s | %szdiff %s | FileCheck --check-prefix=DUMP %s
; RUN: %llvm2iceinsts --pnacl %s | %szdiff %s \
......@@ -16,15 +17,19 @@ entry:
ret void
}
; FuncC is a C symbol that isn't recognized as a C++ mangled symbol.
; CHECK-LABEL: .text.FuncC
; CHECK: FuncC:
; MANGLE: SubzeroFuncC
; MANGLE-LABEL: .text.SubzeroFuncC
; MANGLE: SubzeroFuncC:
define internal void @_ZN13TestNamespace4FuncEi(i32 %i) {
entry:
ret void
}
; This is Func(int) nested inside namespace TestNamespace.
; CHECK-LABEL: .text._ZN13TestNamespace4FuncEi
; CHECK: _ZN13TestNamespace4FuncEi:
; MANGLE-LABEL: .text._ZN7Subzero13TestNamespace4FuncEi
; MANGLE: _ZN7Subzero13TestNamespace4FuncEi:
define internal void @_ZN13TestNamespace15NestedNamespace4FuncEi(i32 %i) {
......@@ -32,7 +37,9 @@ entry:
ret void
}
; This is Func(int) nested inside two namespaces.
; CHECK-LABEL: .text._ZN13TestNamespace15NestedNamespace4FuncEi
; CHECK: _ZN13TestNamespace15NestedNamespace4FuncEi:
; MANGLE-LABEL: .text._ZN7Subzero13TestNamespace15NestedNamespace4FuncEi
; MANGLE: _ZN7Subzero13TestNamespace15NestedNamespace4FuncEi:
define internal void @_Z13FuncCPlusPlusi(i32 %i) {
......@@ -40,7 +47,9 @@ entry:
ret void
}
; This is a non-nested, mangled C++ symbol.
; CHECK-LABEL: .text._Z13FuncCPlusPlusi
; CHECK: _Z13FuncCPlusPlusi:
; MANGLE-LABEL: .text._ZN7Subzero13FuncCPlusPlusEi
; MANGLE: _ZN7Subzero13FuncCPlusPlusEi:
define internal void @_ZN12_GLOBAL__N_18FuncAnonEi(i32 %i) {
......@@ -48,7 +57,9 @@ entry:
ret void
}
; This is FuncAnon(int) nested inside an anonymous namespace.
; CHECK-LABEL: .text._ZN12_GLOBAL__N_18FuncAnonEi
; CHECK: _ZN12_GLOBAL__N_18FuncAnonEi:
; MANGLE-LABEL: .text._ZN7Subzero12_GLOBAL__N_18FuncAnonEi
; MANGLE: _ZN7Subzero12_GLOBAL__N_18FuncAnonEi:
; Now for the illegitimate examples.
......@@ -58,6 +69,7 @@ define internal void @_ZN(i32 %i) {
entry:
ret void
}
; MANGLE-LABEL: .text.Subzero_ZN
; MANGLE: Subzero_ZN:
; Test for _Z<len><str> where <len> is smaller than it should be.
......@@ -65,6 +77,7 @@ define internal void @_Z12FuncCPlusPlusi(i32 %i) {
entry:
ret void
}
; MANGLE-LABEL: .text._ZN7Subzero12FuncCPlusPluEsi
; MANGLE: _ZN7Subzero12FuncCPlusPluEsi:
; Test for _Z<len><str> where <len> is slightly larger than it should be.
......@@ -72,6 +85,7 @@ define internal void @_Z14FuncCPlusPlusi(i32 %i) {
entry:
ret void
}
; MANGLE-LABEL: .text._ZN7Subzero14FuncCPlusPlusiE
; MANGLE: _ZN7Subzero14FuncCPlusPlusiE:
; Test for _Z<len><str> where <len> is much larger than it should be.
......@@ -79,6 +93,7 @@ define internal void @_Z114FuncCPlusPlusi(i32 %i) {
entry:
ret void
}
; MANGLE-LABEL: .text.Subzero_Z114FuncCPlusPlusi
; MANGLE: Subzero_Z114FuncCPlusPlusi:
; Test for _Z<len><str> where we try to overflow the uint32_t holding <len>.
......@@ -86,6 +101,7 @@ define internal void @_Z4294967296FuncCPlusPlusi(i32 %i) {
entry:
ret void
}
; MANGLE-LABEL: .text.Subzero_Z4294967296FuncCPlusPlusi
; MANGLE: Subzero_Z4294967296FuncCPlusPlusi:
; Test for _Z<len><str> where <len> is 0.
......@@ -93,6 +109,7 @@ define internal void @_Z0FuncCPlusPlusi(i32 %i) {
entry:
ret void
}
; MANGLE-LABEL: .text._ZN7Subzero0EFuncCPlusPlusi
; MANGLE: _ZN7Subzero0EFuncCPlusPlusi:
; Test for _Z<len><str> where <len> is -1. LLVM explicitly allows the
......@@ -102,6 +119,7 @@ define internal void @_Z-1FuncCPlusPlusi(i32 %i) {
entry:
ret void
}
; MANGLE-LABEL: .text.Subzero_Z-1FuncCPlusPlusi
; MANGLE: Subzero_Z-1FuncCPlusPlusi:
......@@ -115,14 +133,16 @@ entry:
; (to test parser edge cases)
define internal void @_Z3fooP10MyClassS1xP10MyClassS2xRS_RS1_S_S1_SZZZ_SZ9ZZ_S12345() {
; MANGLE: _ZN7Subzero3fooEP10MyClassS1xP10MyClassS2xRS0_RS2_S0_S2_S1000_SZA00_S12345:
; MANGLE-LABEL: .text._ZN7Subzero3fooEP10MyClassS1xP10MyClassS2xRS0_RS2_S0_S2_S1000_SZA00_S12345
; MANGLE: _ZN7Subzero3fooEP10MyClassS1xP10MyClassS2xRS0_RS2_S0_S2_S1000_SZA00_S12345:
entry:
ret void
}
; Test that unmangled (non-C++) strings don't have substitutions updated.
define internal void @foo_S_S0_SZ_S() {
; MANGLE: Subzerofoo_S_S0_SZ_S:
; MANGLE-LABEL: .text.Subzerofoo_S_S0_SZ_S
; MANGLE: Subzerofoo_S_S0_SZ_S:
entry:
ret void
}
......
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