mirror of
https://github.com/xomboverlord/ldc.git
synced 2026-04-02 01:59:03 +02:00
Update to work with LLVM 2.7.
Removed use of dyn_cast, llvm no compiles without exceptions and rtti by default. We do need exceptions for the libconfig stuff, but rtti isn't necessary (anymore). Debug info needs to be rewritten, as in LLVM 2.7 the format has completely changed. To have something to look at while rewriting, the old code has been wrapped inside #ifndef DISABLE_DEBUG_INFO , this means that you have to define this to compile at the moment. Updated tango 0.99.9 patch to include updated EH runtime code, which is needed for LLVM 2.7 as well.
This commit is contained in:
@@ -309,7 +309,7 @@ LLConstant* DtoConstArrayInitializer(ArrayInitializer* arrinit)
|
||||
|
||||
LLConstant* constarr;
|
||||
if (mismatch)
|
||||
constarr = LLConstantStruct::get(gIR->context(), initvals);
|
||||
constarr = LLConstantStruct::get(gIR->context(), initvals, false); // FIXME should this pack?
|
||||
else
|
||||
constarr = LLConstantArray::get(LLArrayType::get(llelemty, arrlen), initvals);
|
||||
|
||||
@@ -394,7 +394,7 @@ void DtoStaticArrayCopy(LLValue* dst, LLValue* src)
|
||||
LLConstant* DtoConstSlice(LLConstant* dim, LLConstant* ptr)
|
||||
{
|
||||
LLConstant* values[2] = { dim, ptr };
|
||||
return LLConstantStruct::get(gIR->context(), values, 2);
|
||||
return LLConstantStruct::get(gIR->context(), values, 2, false);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -94,8 +94,8 @@ void AsmStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
|
||||
{
|
||||
bool sep = 0, nsep = 0;
|
||||
buf->writestring("asm { ");
|
||||
|
||||
for (Token * t = tokens; t; t = t->next) {
|
||||
|
||||
for (Token * t = tokens; t; t = t->next) {
|
||||
switch (t->value) {
|
||||
case TOKlparen:
|
||||
case TOKrparen:
|
||||
@@ -161,11 +161,11 @@ Statement *AsmStatement::semantic(Scope *sc)
|
||||
sc->func->inlineStatus = ILSno; // %% not sure
|
||||
// %% need to set DECL_UNINLINABLE too?
|
||||
sc->func->hasReturnExp = 1; // %% DMD does this, apparently...
|
||||
|
||||
|
||||
// empty statement -- still do the above things because they might be expected?
|
||||
if (! tokens)
|
||||
return this;
|
||||
|
||||
|
||||
if (!asmparser)
|
||||
if (global.params.cpu == ARCHx86)
|
||||
asmparser = new AsmParserx8632::AsmParser;
|
||||
@@ -196,9 +196,11 @@ AsmStatement::toIR(IRState * irs)
|
||||
IRAsmBlock* asmblock = irs->asmBlock;
|
||||
assert(asmblock);
|
||||
|
||||
#ifndef DISABLE_DEBUG_INFO
|
||||
// debug info
|
||||
if (global.params.symdebug)
|
||||
DtoDwarfStopPoint(loc.linnum);
|
||||
#endif
|
||||
|
||||
if (! asmcode)
|
||||
return;
|
||||
@@ -257,8 +259,7 @@ AsmStatement::toIR(IRState * irs)
|
||||
break;
|
||||
case Arg_FrameRelative:
|
||||
// FIXME
|
||||
llvm::cout << "asm fixme Arg_FrameRelative" << std::endl;
|
||||
assert(0);
|
||||
assert(0 && "asm fixme Arg_FrameRelative");
|
||||
/* if (arg->expr->op == TOKvar)
|
||||
arg_val = ((VarExp *) arg->expr)->var->toSymbol()->Stree;
|
||||
else
|
||||
@@ -275,8 +276,7 @@ assert(0);
|
||||
break;*/
|
||||
case Arg_LocalSize:
|
||||
// FIXME
|
||||
llvm::cout << "asm fixme Arg_LocalSize" << std::endl;
|
||||
assert(0);
|
||||
assert(0 && "asm fixme Arg_LocalSize");
|
||||
/* var_frame_offset = cfun->x_frame_offset;
|
||||
if (var_frame_offset < 0)
|
||||
var_frame_offset = - var_frame_offset;
|
||||
@@ -300,7 +300,7 @@ assert(0);
|
||||
// Telling GCC that callee-saved registers are clobbered makes it preserve
|
||||
// those registers. This changes the stack from what a naked function
|
||||
// expects.
|
||||
|
||||
|
||||
// FIXME
|
||||
// if (! irs->func->naked) {
|
||||
assert(asmparser);
|
||||
@@ -318,7 +318,7 @@ assert(0);
|
||||
if (arg_map[i] < 0)
|
||||
arg_map[i] = -arg_map[i] - 1 + n_outputs;
|
||||
}
|
||||
|
||||
|
||||
bool pct = false;
|
||||
std::string::iterator
|
||||
p = code->insnTemplate.begin(),
|
||||
@@ -343,14 +343,14 @@ assert(0);
|
||||
if (Logger::enabled()) {
|
||||
Logger::cout() << "final asm: " << code->insnTemplate << '\n';
|
||||
std::ostringstream ss;
|
||||
|
||||
|
||||
ss << "GCC-style output constraints: {";
|
||||
for (It i = output_constraints.begin(), e = output_constraints.end(); i != e; ++i) {
|
||||
ss << " " << *i;
|
||||
}
|
||||
ss << " }";
|
||||
Logger::println("%s", ss.str().c_str());
|
||||
|
||||
|
||||
ss.str("");
|
||||
ss << "GCC-style input constraints: {";
|
||||
for (It i = input_constraints.begin(), e = input_constraints.end(); i != e; ++i) {
|
||||
@@ -358,7 +358,7 @@ assert(0);
|
||||
}
|
||||
ss << " }";
|
||||
Logger::println("%s", ss.str().c_str());
|
||||
|
||||
|
||||
ss.str("");
|
||||
ss << "GCC-style clobbers: {";
|
||||
for (It i = clobbers.begin(), e = clobbers.end(); i != e; ++i) {
|
||||
@@ -379,10 +379,10 @@ assert(0);
|
||||
/* LLVM doesn't support updating operands, so split into an input
|
||||
* and an output operand.
|
||||
*/
|
||||
|
||||
|
||||
// Change update operand to pure output operand.
|
||||
*i = mw_cns;
|
||||
|
||||
|
||||
// Add input operand with same value, with original as "matching output".
|
||||
std::ostringstream ss;
|
||||
ss << '*' << (n + asmblock->outputcount);
|
||||
@@ -572,7 +572,7 @@ void AsmBlockStatement::toIR(IRState* p)
|
||||
for(it = asmblock->internalLabels.begin(); it != end; ++it)
|
||||
if((*it)->equals(a->isBranchToLabel))
|
||||
skip = true;
|
||||
if(skip)
|
||||
if(skip)
|
||||
continue;
|
||||
|
||||
// if we already set things up for this branch target, skip
|
||||
|
||||
@@ -17,19 +17,19 @@ static char toLower(char c) {
|
||||
return c;
|
||||
}
|
||||
|
||||
bool FlagParser::parse(cl::Option &O, const char *ArgName, const std::string &Arg, bool &Val) {
|
||||
bool FlagParser::parse(cl::Option &O, llvm::StringRef ArgName, llvm::StringRef Arg, bool &Val) {
|
||||
// Make a std::string out of it to make comparisons easier
|
||||
// (and avoid repeated conversion)
|
||||
std::string argname = ArgName;
|
||||
|
||||
llvm::StringRef argname = ArgName;
|
||||
|
||||
typedef std::vector<std::pair<std::string, bool> >::iterator It;
|
||||
for (It I = switches.begin(), E = switches.end(); I != E; ++I) {
|
||||
std::string name = I->first;
|
||||
llvm::StringRef name = I->first;
|
||||
if (name == argname
|
||||
|| (name.length() < argname.length()
|
||||
&& argname.substr(0, name.length()) == name
|
||||
&& argname[name.length()] == '=')) {
|
||||
|
||||
|| (name.size() < argname.size()
|
||||
&& argname.substr(0, name.size()) == name
|
||||
&& argname[name.size()] == '=')) {
|
||||
|
||||
if (!cl::parser<bool>::parse(O, ArgName, Arg, Val)) {
|
||||
Val = (Val == I->second);
|
||||
return false;
|
||||
@@ -41,10 +41,10 @@ bool FlagParser::parse(cl::Option &O, const char *ArgName, const std::string &Ar
|
||||
return true;
|
||||
}
|
||||
|
||||
void FlagParser::getExtraOptionNames(std::vector<const char*> &Names) {
|
||||
void FlagParser::getExtraOptionNames(llvm::SmallVectorImpl<const char*> &Names) {
|
||||
typedef std::vector<std::pair<std::string, bool> >::iterator It;
|
||||
for (It I = switches.begin() + 1, E = switches.end(); I != E; ++I) {
|
||||
Names.push_back(I->first.c_str());
|
||||
Names.push_back(I->first.data());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,7 +60,7 @@ MultiSetter::MultiSetter(bool invert, bool* p, ...) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void MultiSetter::operator=(bool val) {
|
||||
typedef std::vector<bool*>::iterator It;
|
||||
for (It I = locations.begin(), E = locations.end(); I != E; ++I) {
|
||||
@@ -72,7 +72,7 @@ void MultiSetter::operator=(bool val) {
|
||||
void ArrayAdapter::push_back(const char* cstr) {
|
||||
if (!cstr || !*cstr)
|
||||
error("Expected argument to '-%s'", name);
|
||||
|
||||
|
||||
if (!*arrp)
|
||||
*arrp = new Array;
|
||||
(*arrp)->push(mem.strdup(cstr));
|
||||
|
||||
@@ -10,7 +10,7 @@ struct Array;
|
||||
|
||||
namespace opts {
|
||||
namespace cl = llvm::cl;
|
||||
|
||||
|
||||
/// Helper class for fancier options
|
||||
class FlagParser : public cl::parser<bool> {
|
||||
std::vector<std::pair<std::string, bool> > switches;
|
||||
@@ -21,14 +21,14 @@ namespace opts {
|
||||
switches.push_back(make_pair("enable-" + Name, true));
|
||||
switches.push_back(make_pair("disable-" + Name, false));
|
||||
// Replace <foo> with -enable-<foo>
|
||||
O.ArgStr = switches[0].first.c_str();
|
||||
O.ArgStr = switches[0].first.data();
|
||||
}
|
||||
|
||||
bool parse(cl::Option &O, const char *ArgName, const std::string &ArgValue, bool &Val);
|
||||
|
||||
void getExtraOptionNames(std::vector<const char*> &Names);
|
||||
|
||||
bool parse(cl::Option &O, llvm::StringRef ArgName, llvm::StringRef ArgValue, bool &Val);
|
||||
|
||||
void getExtraOptionNames(llvm::SmallVectorImpl<const char*> &Names);
|
||||
};
|
||||
|
||||
|
||||
/// Helper class for options that set multiple flags
|
||||
class MultiSetter {
|
||||
std::vector<bool*> locations;
|
||||
@@ -36,10 +36,10 @@ namespace opts {
|
||||
MultiSetter(bool); //not implemented, disable auto-conversion
|
||||
public:
|
||||
MultiSetter(bool invert, bool* p, ...) END_WITH_NULL;
|
||||
|
||||
|
||||
void operator=(bool val);
|
||||
};
|
||||
|
||||
|
||||
/// Helper class to fill Array with char* when given strings
|
||||
/// (Errors on empty strings)
|
||||
class ArrayAdapter {
|
||||
@@ -52,14 +52,14 @@ namespace opts {
|
||||
assert(name);
|
||||
assert(arrp);
|
||||
}
|
||||
|
||||
|
||||
void push_back(const char* cstr);
|
||||
|
||||
|
||||
void push_back(const std::string& str) {
|
||||
push_back(str.c_str());
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/// Helper class to allow use of a parser<bool> with BoolOrDefault
|
||||
class BoolOrDefaultAdapter {
|
||||
cl::boolOrDefault value;
|
||||
@@ -67,11 +67,11 @@ namespace opts {
|
||||
operator cl::boolOrDefault() {
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
void operator=(cl::boolOrDefault val) {
|
||||
value = val;
|
||||
}
|
||||
|
||||
|
||||
void operator=(bool val) {
|
||||
*this = (val ? cl::BOU_TRUE : cl::BOU_FALSE);
|
||||
}
|
||||
|
||||
@@ -94,7 +94,7 @@ bool ConfigFile::locate(sys::Path& p, const char* argv0, void* mainAddr, const c
|
||||
p.appendComponent(filename);
|
||||
if (p.exists())
|
||||
return true;
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -102,14 +102,14 @@ bool ConfigFile::read(const char* argv0, void* mainAddr, const char* filename)
|
||||
{
|
||||
sys::Path p;
|
||||
if (!locate(p, argv0, mainAddr, filename))
|
||||
{
|
||||
{
|
||||
// failed to find cfg, users still have the DFLAGS environment var
|
||||
std::cerr << "Error failed to locate the configuration file: " << filename << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// save config file path for -v output
|
||||
pathstr = p.toString();
|
||||
pathstr = p.str();
|
||||
|
||||
try
|
||||
{
|
||||
@@ -141,12 +141,12 @@ bool ConfigFile::read(const char* argv0, void* mainAddr, const char* filename)
|
||||
for (int i=0; i<len; i++)
|
||||
{
|
||||
std::string v = arr[i];
|
||||
|
||||
|
||||
// replace binpathkey with binpath
|
||||
size_t p;
|
||||
while (std::string::npos != (p = v.find(binpathkey)))
|
||||
v.replace(p, binpathkey.size(), binpath);
|
||||
|
||||
|
||||
switches.push_back(strdup(v.c_str()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -599,10 +599,11 @@ void DtoDefineFunction(FuncDeclaration* fd)
|
||||
return;
|
||||
}
|
||||
|
||||
#ifndef DISABLE_DEBUG_INFO
|
||||
// debug info
|
||||
if (global.params.symdebug) {
|
||||
if (global.params.symdebug)
|
||||
fd->ir.irFunc->diSubprogram = DtoDwarfSubProgram(fd);
|
||||
}
|
||||
#endif
|
||||
|
||||
Type* t = fd->type->toBasetype();
|
||||
TypeFunction* f = (TypeFunction*)t;
|
||||
@@ -642,8 +643,10 @@ void DtoDefineFunction(FuncDeclaration* fd)
|
||||
llvm::Instruction* allocaPoint = new llvm::AllocaInst(LLType::getInt32Ty(gIR->context()), "alloca point", beginbb);
|
||||
irfunction->allocapoint = allocaPoint;
|
||||
|
||||
#ifndef DISABLE_DEBUG_INFO
|
||||
// debug info - after all allocas, but before any llvm.dbg.declare etc
|
||||
if (global.params.symdebug) DtoDwarfFuncStart(fd);
|
||||
#endif
|
||||
|
||||
// this hack makes sure the frame pointer elimination optimization is disabled.
|
||||
// this this eliminates a bunch of inline asm related issues.
|
||||
@@ -668,8 +671,10 @@ void DtoDefineFunction(FuncDeclaration* fd)
|
||||
fd->vthis->ir.irLocal = new IrLocal(fd->vthis);
|
||||
fd->vthis->ir.irLocal->value = thismem;
|
||||
|
||||
#ifndef DISABLE_DEBUG_INFO
|
||||
if (global.params.symdebug)
|
||||
DtoDwarfLocalVariable(thismem, fd->vthis);
|
||||
#endif
|
||||
|
||||
#if DMDV1
|
||||
if (fd->vthis->nestedref)
|
||||
@@ -722,8 +727,10 @@ void DtoDefineFunction(FuncDeclaration* fd)
|
||||
irloc->value = mem;
|
||||
}
|
||||
|
||||
#ifndef DISABLE_DEBUG_INFO
|
||||
if (global.params.symdebug && !(isaArgument(irloc->value) && !isaArgument(irloc->value)->hasByValAttr()) && !refout)
|
||||
DtoDwarfLocalVariable(irloc->value, vd);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -758,7 +765,7 @@ void DtoDefineFunction(FuncDeclaration* fd)
|
||||
fd->vresult->ir.irLocal = new IrLocal(fd->vresult);
|
||||
fd->vresult->ir.irLocal->value = DtoAlloca(fd->vresult->type, fd->vresult->toChars());
|
||||
}
|
||||
|
||||
|
||||
// copy _argptr and _arguments to a memory location
|
||||
if (f->linkage == LINKd && f->varargs == 1)
|
||||
{
|
||||
@@ -794,9 +801,11 @@ void DtoDefineFunction(FuncDeclaration* fd)
|
||||
} else if (!gIR->scopereturned()) {
|
||||
// llvm requires all basic blocks to end with a TerminatorInst but DMD does not put a return statement
|
||||
// in automatically, so we do it here.
|
||||
|
||||
|
||||
// pass the previous block into this block
|
||||
#ifndef DISABLE_DEBUG_INFO
|
||||
if (global.params.symdebug) DtoDwarfFuncEnd(fd);
|
||||
#endif
|
||||
if (func->getReturnType() == LLType::getVoidTy(gIR->context())) {
|
||||
llvm::ReturnInst::Create(gIR->context(), gIR->scopebb());
|
||||
}
|
||||
|
||||
@@ -106,7 +106,7 @@ int linkExecutable(const char* argv0)
|
||||
error("failed to create path to linking output: %s\n%s", exedir.c_str(), errstr.c_str());
|
||||
fatal();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// strip debug info
|
||||
if (!global.params.symdebug)
|
||||
@@ -222,13 +222,13 @@ int linkObjToExecutable(const char* argv0)
|
||||
// find gcc for linking
|
||||
llvm::sys::Path gcc = getGcc();
|
||||
// get a string version for argv[0]
|
||||
std::string gccStr = gcc.toString();
|
||||
const char* gccStr = gcc.c_str();
|
||||
|
||||
// build arguments
|
||||
std::vector<const char*> args;
|
||||
|
||||
// first the program name ??
|
||||
args.push_back(gccStr.c_str());
|
||||
args.push_back(gccStr);
|
||||
|
||||
// object files
|
||||
for (int i = 0; i < global.params.objfiles->dim; i++)
|
||||
@@ -274,7 +274,7 @@ int linkObjToExecutable(const char* argv0)
|
||||
error("failed to create path to linking output: %s\n%s", exedir.c_str(), errstr.c_str());
|
||||
fatal();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// additional linker switches
|
||||
for (int i = 0; i < global.params.linkswitches->dim; i++)
|
||||
@@ -292,7 +292,7 @@ int linkObjToExecutable(const char* argv0)
|
||||
|
||||
// default libs
|
||||
switch(global.params.os) {
|
||||
case OSLinux:
|
||||
case OSLinux:
|
||||
case OSMacOSX:
|
||||
args.push_back("-ldl");
|
||||
// fallthrough
|
||||
@@ -330,12 +330,12 @@ int linkObjToExecutable(const char* argv0)
|
||||
}
|
||||
|
||||
Logger::println("Linking with: ");
|
||||
std::vector<const char*>::const_iterator I = args.begin(), E = args.end();
|
||||
std::vector<const char*>::const_iterator I = args.begin(), E = args.end();
|
||||
Stream logstr = Logger::cout();
|
||||
for (; I != E; ++I)
|
||||
if (*I)
|
||||
logstr << "'" << *I << "'" << " ";
|
||||
logstr << "\n" << std::flush;
|
||||
logstr << "\n"; // FIXME where's flush ?
|
||||
|
||||
|
||||
// terminate args list
|
||||
@@ -349,7 +349,7 @@ int linkObjToExecutable(const char* argv0)
|
||||
error("message: %s", errstr.c_str());
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -375,7 +375,7 @@ int runExecutable()
|
||||
// build arguments
|
||||
std::vector<const char*> args;
|
||||
// args[0] should be the name of the executable
|
||||
args.push_back(gExePath.toString().c_str());
|
||||
args.push_back(gExePath.c_str());
|
||||
// Skip first argument to -run; it's a D source file.
|
||||
for (size_t i = 1, length = opts::runargs.size(); i < length; i++)
|
||||
{
|
||||
|
||||
@@ -160,9 +160,11 @@ void DtoAssert(Module* M, Loc loc, DValue* msg)
|
||||
// call
|
||||
gIR->CreateCallOrInvoke(fn, args.begin(), args.end());
|
||||
|
||||
#ifndef DISABLE_DEBUG_INFO
|
||||
// end debug info
|
||||
if (global.params.symdebug)
|
||||
DtoDwarfFuncEnd(gIR->func()->decl);
|
||||
#endif
|
||||
|
||||
// after assert is always unreachable
|
||||
gIR->ir->CreateUnreachable();
|
||||
@@ -268,7 +270,7 @@ void DtoEnclosingHandlers(Loc loc, Statement* target)
|
||||
{
|
||||
// labels are a special case: they are not required to enclose the current scope
|
||||
// for them we use the enclosing scope handler as a reference point
|
||||
LabelStatement* lblstmt = dynamic_cast<LabelStatement*>(target);
|
||||
LabelStatement* lblstmt = target ? target->isLabelStatement() : 0;
|
||||
if (lblstmt)
|
||||
target = lblstmt->enclosingScopeExit;
|
||||
|
||||
@@ -485,7 +487,7 @@ DValue* DtoNullValue(Type* type)
|
||||
}
|
||||
|
||||
// unknown
|
||||
llvm::cout << "unsupported: null value for " << type->toChars() << '\n';
|
||||
error("unsupported: null value for %s", type->toChars());
|
||||
assert(0);
|
||||
return 0;
|
||||
|
||||
@@ -854,6 +856,7 @@ void DtoConstInitGlobal(VarDeclaration* vd)
|
||||
|
||||
gvar->setInitializer(initVal);
|
||||
|
||||
#ifndef DISABLE_DEBUG_INFO
|
||||
// do debug info
|
||||
if (global.params.symdebug)
|
||||
{
|
||||
@@ -861,6 +864,7 @@ void DtoConstInitGlobal(VarDeclaration* vd)
|
||||
// keep a reference so GDCE doesn't delete it !
|
||||
gIR->usedArray.push_back(llvm::ConstantExpr::getBitCast(gv, getVoidPtrType()));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -906,11 +910,11 @@ DValue* DtoDeclarationExp(Dsymbol* declaration)
|
||||
ExpInitializer* ex = vd->init->isExpInitializer();
|
||||
assert(ex && "ref vars must have expression initializer");
|
||||
assert(ex->exp);
|
||||
AssignExp* as = dynamic_cast<AssignExp*>(ex->exp);
|
||||
AssignExp* as = ex->exp->isAssignExp();
|
||||
assert(as && "ref vars must be initialized by an assign exp");
|
||||
vd->ir.irLocal->value = as->e2->toElem(gIR)->getLVal();
|
||||
}
|
||||
|
||||
|
||||
// referenced by nested delegate?
|
||||
#if DMDV2
|
||||
if (vd->nestedrefs.dim) {
|
||||
@@ -919,7 +923,7 @@ DValue* DtoDeclarationExp(Dsymbol* declaration)
|
||||
#endif
|
||||
Logger::println("has nestedref set");
|
||||
assert(vd->ir.irLocal);
|
||||
|
||||
|
||||
DtoNestedInit(vd);
|
||||
}
|
||||
// normal stack variable, allocate storage on the stack if it has not already been done
|
||||
@@ -937,10 +941,10 @@ DValue* DtoDeclarationExp(Dsymbol* declaration)
|
||||
//allocainst->setAlignment(vd->type->alignsize()); // TODO
|
||||
vd->ir.irLocal->value = allocainst;
|
||||
|
||||
#ifndef DISABLE_DEBUG_INFO
|
||||
if (global.params.symdebug)
|
||||
{
|
||||
DtoDwarfLocalVariable(allocainst, vd);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1046,18 +1050,20 @@ LLValue* DtoRawVarDeclaration(VarDeclaration* var, LLValue* addr)
|
||||
|
||||
// we don't handle aliases either
|
||||
assert(!var->aliassym);
|
||||
|
||||
|
||||
// alloca if necessary
|
||||
LLValue* allocaval = NULL;
|
||||
if (!addr && (!var->ir.irLocal || !var->ir.irLocal->value))
|
||||
{
|
||||
addr = DtoAlloca(var->type, var->toChars());
|
||||
|
||||
|
||||
#ifndef DISABLE_DEBUG_INFO
|
||||
// add debug info
|
||||
if (global.params.symdebug)
|
||||
DtoDwarfLocalVariable(addr, var);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
// referenced by nested function?
|
||||
#if DMDV2
|
||||
if (var->nestedrefs.dim)
|
||||
@@ -1294,7 +1300,7 @@ void DtoOverloadedIntrinsicName(TemplateInstance* ti, TemplateDeclaration* td, s
|
||||
Logger::println("template instance: %s", ti->toChars());
|
||||
Logger::println("template declaration: %s", td->toChars());
|
||||
Logger::println("intrinsic name: %s", td->intrinsicName.c_str());
|
||||
|
||||
|
||||
// for now use the size in bits of the first template param in the instance
|
||||
assert(ti->tdtypes.dim == 1);
|
||||
Type* T = (Type*)ti->tdtypes.data[0];
|
||||
@@ -1307,7 +1313,7 @@ void DtoOverloadedIntrinsicName(TemplateInstance* ti, TemplateDeclaration* td, s
|
||||
|
||||
char tmp[21]; // probably excessive, but covers a uint64_t
|
||||
sprintf(tmp, "%lu", (unsigned long) gTargetData->getTypeSizeInBits(DtoType(T)));
|
||||
|
||||
|
||||
// replace # in name with bitsize
|
||||
name = td->intrinsicName;
|
||||
|
||||
@@ -1330,7 +1336,7 @@ void DtoOverloadedIntrinsicName(TemplateInstance* ti, TemplateDeclaration* td, s
|
||||
fatal(); // or LLVM asserts
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Logger::println("final intrinsic name: %s", name.c_str());
|
||||
}
|
||||
|
||||
@@ -1340,7 +1346,7 @@ bool mustDefineSymbol(Dsymbol* s)
|
||||
{
|
||||
if (FuncDeclaration* fd = s->isFuncDeclaration())
|
||||
{
|
||||
// we can't (and probably shouldn't?) define functions
|
||||
// we can't (and probably shouldn't?) define functions
|
||||
// that weren't semantic3'ed
|
||||
if (fd->semanticRun < 4)
|
||||
return false;
|
||||
@@ -1352,7 +1358,7 @@ bool mustDefineSymbol(Dsymbol* s)
|
||||
// Emit extra functions if we're inlining.
|
||||
// These will get available_externally linkage,
|
||||
// so they shouldn't end up in object code.
|
||||
|
||||
|
||||
assert(fd->type->ty == Tfunction);
|
||||
TypeFunction* tf = (TypeFunction*) fd->type;
|
||||
// * If we define extra static constructors, static destructors
|
||||
@@ -1371,7 +1377,7 @@ bool mustDefineSymbol(Dsymbol* s)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// This was only semantic'ed for inlining checks.
|
||||
// We won't be inlining this, so we only need to emit a declaration.
|
||||
return false;
|
||||
@@ -1396,7 +1402,7 @@ bool mustDefineSymbol(Dsymbol* s)
|
||||
{
|
||||
if (!opts::singleObj)
|
||||
return true;
|
||||
|
||||
|
||||
if (!tinst->emittedInModule)
|
||||
{
|
||||
gIR->seenTemplateInstances.insert(tinst);
|
||||
@@ -1404,7 +1410,7 @@ bool mustDefineSymbol(Dsymbol* s)
|
||||
}
|
||||
return tinst->emittedInModule == gIR->dmodule;
|
||||
}
|
||||
|
||||
|
||||
return s->getModule() == gIR->dmodule;
|
||||
}
|
||||
|
||||
|
||||
@@ -156,7 +156,7 @@ LLValue* makeLValue(Loc& loc, DValue* value);
|
||||
////////////////////////////////////////////
|
||||
|
||||
/// convert DMD calling conv to LLVM
|
||||
unsigned DtoCallingConv(Loc loc, LINK l);
|
||||
llvm::CallingConv::ID DtoCallingConv(Loc loc, LINK l);
|
||||
|
||||
///
|
||||
TypeFunction* DtoTypeFunction(DValue* fnval);
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
#include "llvm/GlobalValue.h"
|
||||
#include "llvm/Support/Casting.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include "llvm/Support/raw_os_ostream.h"
|
||||
#include "llvm/Assembly/Writer.h"
|
||||
|
||||
#include "gen/logger.h"
|
||||
@@ -27,10 +27,11 @@ void Stream::writeValue(std::ostream& OS, const llvm::Value& V) {
|
||||
// Constants don't always get their types pretty-printed.
|
||||
// (Only treat non-global constants like this, so that e.g. global variables
|
||||
// still get their initializers printed)
|
||||
llvm::raw_os_ostream raw(OS);
|
||||
if (llvm::isa<llvm::Constant>(V) && !llvm::isa<llvm::GlobalValue>(V))
|
||||
llvm::WriteAsOperand(OS, &V, true, gIR->module);
|
||||
llvm::WriteAsOperand(raw, &V, true, gIR->module);
|
||||
else
|
||||
OS << V;
|
||||
V.print(raw);
|
||||
}
|
||||
|
||||
namespace Logger
|
||||
|
||||
22
gen/logger.h
22
gen/logger.h
@@ -20,36 +20,38 @@ struct Loc;
|
||||
|
||||
class Stream {
|
||||
std::ostream* OS;
|
||||
|
||||
|
||||
public:
|
||||
Stream() : OS(0) {}
|
||||
Stream(std::ostream* S) : OS(S) {}
|
||||
Stream(std::ostream& S) : OS(&S) {}
|
||||
|
||||
|
||||
/*
|
||||
Stream operator << (std::ios_base &(*Func)(std::ios_base&)) {
|
||||
if (OS) *OS << Func;
|
||||
return *this;
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
Stream operator << (std::ostream &(*Func)(std::ostream&)) {
|
||||
if (OS) *OS << Func;
|
||||
if (OS) Func(*OS);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
template<typename Ty>
|
||||
Stream& operator << (const Ty& Thing) {
|
||||
if (OS)
|
||||
Writer<Ty, sizeof(sfinae_bait(Thing))>::write(*OS, Thing);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
// Implementation details to treat llvm::Value, llvm::Type and their
|
||||
// subclasses specially (to pretty-print types).
|
||||
|
||||
|
||||
static void writeType(std::ostream& OS, const llvm::Type& Ty);
|
||||
static void writeValue(std::ostream& OS, const llvm::Value& Ty);
|
||||
|
||||
|
||||
template<typename Ty, int N> friend struct Writer;
|
||||
// error: function template partial specialization is not allowed
|
||||
// So I guess type partial specialization + member function will have to do...
|
||||
@@ -59,7 +61,7 @@ private:
|
||||
OS << Thing;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<typename Ty>
|
||||
struct Writer<Ty, 1> {
|
||||
static void write(std::ostream& OS, const llvm::Type& Thing) {
|
||||
@@ -69,7 +71,7 @@ private:
|
||||
Stream::writeValue(OS, Thing);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// NOT IMPLEMENTED
|
||||
char sfinae_bait(const llvm::Type&);
|
||||
char sfinae_bait(const llvm::Value&);
|
||||
|
||||
41
gen/main.cpp
41
gen/main.cpp
@@ -148,7 +148,7 @@ int main(int argc, char** argv)
|
||||
global.params.libfiles = new Array();
|
||||
global.params.objfiles = new Array();
|
||||
global.params.ddocfiles = new Array();
|
||||
|
||||
|
||||
global.params.moduleDeps = NULL;
|
||||
global.params.moduleDepsFile = NULL;
|
||||
|
||||
@@ -223,12 +223,12 @@ int main(int argc, char** argv)
|
||||
// String options: std::string --> char*
|
||||
initFromString(global.params.objname, objectFile);
|
||||
initFromString(global.params.objdir, objectDir);
|
||||
|
||||
|
||||
initFromString(global.params.docdir, ddocDir);
|
||||
initFromString(global.params.docname, ddocFile);
|
||||
global.params.doDocComments |=
|
||||
global.params.docdir || global.params.docname;
|
||||
|
||||
|
||||
#ifdef _DH
|
||||
initFromString(global.params.hdrdir, hdrDir);
|
||||
initFromString(global.params.hdrname, hdrFile);
|
||||
@@ -237,9 +237,9 @@ int main(int argc, char** argv)
|
||||
#endif
|
||||
|
||||
initFromString(global.params.moduleDepsFile, moduleDepsFile);
|
||||
if (global.params.moduleDepsFile != NULL)
|
||||
{
|
||||
global.params.moduleDeps = new OutBuffer;
|
||||
if (global.params.moduleDepsFile != NULL)
|
||||
{
|
||||
global.params.moduleDeps = new OutBuffer;
|
||||
}
|
||||
|
||||
processVersions(debugArgs, "debug",
|
||||
@@ -435,7 +435,7 @@ int main(int argc, char** argv)
|
||||
std::string triple = global.params.targetTriple;
|
||||
|
||||
// Allocate target machine.
|
||||
|
||||
|
||||
// first initialize llvm
|
||||
#define LLVM_TARGET(A) LLVMInitialize##A##TargetInfo(); LLVMInitialize##A##Target(); LLVMInitialize##A##AsmPrinter();
|
||||
// this is defined to be LLVM_TARGET(target name 1) LLVM_TARGET(target name 2) ...
|
||||
@@ -484,10 +484,15 @@ LDC_TARGETS
|
||||
FeaturesStr = Features.getString();
|
||||
}
|
||||
|
||||
std::auto_ptr<llvm::TargetMachine> target(theTarget->createTargetMachine(triple, FeaturesStr));
|
||||
assert(target.get() && "Could not allocate target machine!");
|
||||
gTargetMachine = target.get();
|
||||
gTargetData = gTargetMachine->getTargetData();
|
||||
// FIXME
|
||||
//std::auto_ptr<llvm::TargetMachine> target(theTarget->createTargetMachine(triple, FeaturesStr));
|
||||
//assert(target.get() && "Could not allocate target machine!");
|
||||
//gTargetMachine = target.get();
|
||||
|
||||
llvm::TargetMachine* target = theTarget->createTargetMachine(triple, FeaturesStr);
|
||||
gTargetMachine = target;
|
||||
|
||||
gTargetData = target->getTargetData();
|
||||
|
||||
// get final data layout
|
||||
std::string datalayout = gTargetData->getStringRepresentation();
|
||||
@@ -903,12 +908,12 @@ LDC_TARGETS
|
||||
fatal();
|
||||
|
||||
// write module dependencies to file if requested
|
||||
if (global.params.moduleDepsFile != NULL)
|
||||
{
|
||||
if (global.params.moduleDepsFile != NULL)
|
||||
{
|
||||
assert (global.params.moduleDepsFile != NULL);
|
||||
|
||||
File deps(global.params.moduleDepsFile);
|
||||
OutBuffer* ob = global.params.moduleDeps;
|
||||
OutBuffer* ob = global.params.moduleDeps;
|
||||
deps.setbuffer((void*)ob->data, ob->offset);
|
||||
deps.write();
|
||||
}
|
||||
@@ -944,14 +949,14 @@ LDC_TARGETS
|
||||
m->gendocfile();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// internal linking for singleobj
|
||||
if (singleObj && llvmModules.size() > 0)
|
||||
{
|
||||
Module* m = (Module*)modules.data[0];
|
||||
char* name = m->toChars();
|
||||
char* filename = m->objfile->name->str;
|
||||
|
||||
|
||||
llvm::Linker linker(name, name, context);
|
||||
|
||||
std::string errormsg;
|
||||
@@ -961,12 +966,12 @@ LDC_TARGETS
|
||||
error("%s", errormsg.c_str());
|
||||
delete llvmModules[i];
|
||||
}
|
||||
|
||||
|
||||
m->deleteObjFile();
|
||||
writeModule(linker.getModule(), filename);
|
||||
global.params.objfiles->push(filename);
|
||||
}
|
||||
|
||||
|
||||
backend_term();
|
||||
if (global.errors)
|
||||
fatal();
|
||||
|
||||
@@ -95,7 +95,7 @@ bool optimize() {
|
||||
|
||||
static void addPass(PassManager& pm, Pass* pass) {
|
||||
pm.add(pass);
|
||||
|
||||
|
||||
if (verifyEach) pm.add(createVerifierPass());
|
||||
}
|
||||
|
||||
@@ -107,7 +107,7 @@ static void addPassesForOptLevel(PassManager& pm) {
|
||||
{
|
||||
//addPass(pm, createStripDeadPrototypesPass());
|
||||
addPass(pm, createGlobalDCEPass());
|
||||
addPass(pm, createRaiseAllocationsPass());
|
||||
addPass(pm, createPromoteMemoryToRegisterPass());
|
||||
addPass(pm, createCFGSimplificationPass());
|
||||
if (optimizeLevel == 1)
|
||||
addPass(pm, createPromoteMemoryToRegisterPass());
|
||||
@@ -165,7 +165,7 @@ static void addPassesForOptLevel(PassManager& pm) {
|
||||
addPass(pm, createCFGSimplificationPass());
|
||||
addPass(pm, createInstructionCombiningPass());
|
||||
}
|
||||
|
||||
|
||||
// -O3
|
||||
if (optimizeLevel >= 3)
|
||||
{
|
||||
@@ -177,7 +177,7 @@ static void addPassesForOptLevel(PassManager& pm) {
|
||||
addPass(pm, createCFGSimplificationPass());
|
||||
addPass(pm, createScalarReplAggregatesPass());
|
||||
addPass(pm, createInstructionCombiningPass());
|
||||
addPass(pm, createCondPropagationPass());
|
||||
addPass(pm, createConstantPropagationPass());
|
||||
|
||||
addPass(pm, createReassociatePass());
|
||||
addPass(pm, createLoopRotatePass());
|
||||
@@ -194,7 +194,7 @@ static void addPassesForOptLevel(PassManager& pm) {
|
||||
addPass(pm, createSCCPPass());
|
||||
|
||||
addPass(pm, createInstructionCombiningPass());
|
||||
addPass(pm, createCondPropagationPass());
|
||||
addPass(pm, createConstantPropagationPass());
|
||||
|
||||
addPass(pm, createDeadStoreEliminationPass());
|
||||
addPass(pm, createAggressiveDCEPass());
|
||||
@@ -220,9 +220,9 @@ bool ldc_optimize_module(llvm::Module* m)
|
||||
return false;
|
||||
|
||||
PassManager pm;
|
||||
|
||||
|
||||
if (verifyEach) pm.add(createVerifierPass());
|
||||
|
||||
|
||||
addPass(pm, new TargetData(m));
|
||||
|
||||
bool optimize = optimizeLevel != 0 || doInline();
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
|
||||
#include "Passes.h"
|
||||
|
||||
#include "llvm/Function.h"
|
||||
#include "llvm/Pass.h"
|
||||
#include "llvm/Intrinsics.h"
|
||||
#include "llvm/Support/IRBuilder.h"
|
||||
@@ -48,25 +49,25 @@ namespace {
|
||||
const TargetData *TD;
|
||||
AliasAnalysis *AA;
|
||||
LLVMContext *Context;
|
||||
|
||||
|
||||
/// CastToCStr - Return V if it is an i8*, otherwise cast it to i8*.
|
||||
Value *CastToCStr(Value *V, IRBuilder<> &B);
|
||||
|
||||
|
||||
/// EmitMemCpy - Emit a call to the memcpy function to the builder. This
|
||||
/// always expects that the size has type 'intptr_t' and Dst/Src are pointers.
|
||||
Value *EmitMemCpy(Value *Dst, Value *Src, Value *Len,
|
||||
Value *EmitMemCpy(Value *Dst, Value *Src, Value *Len,
|
||||
unsigned Align, IRBuilder<> &B);
|
||||
public:
|
||||
LibCallOptimization() { }
|
||||
virtual ~LibCallOptimization() {}
|
||||
|
||||
|
||||
/// CallOptimizer - This pure virtual method is implemented by base classes to
|
||||
/// do various optimizations. If this returns null then no transformation was
|
||||
/// performed. If it returns CI, then it transformed the call and CI is to be
|
||||
/// deleted. If it returns something else, replace CI with the new value and
|
||||
/// delete CI.
|
||||
virtual Value *CallOptimizer(Function *Callee, CallInst *CI, IRBuilder<> &B)=0;
|
||||
|
||||
|
||||
Value *OptimizeCall(CallInst *CI, bool& Changed, const TargetData &TD,
|
||||
AliasAnalysis& AA, IRBuilder<> &B) {
|
||||
Caller = CI->getParent()->getParent();
|
||||
@@ -116,27 +117,27 @@ struct VISIBILITY_HIDDEN ArraySetLengthOpt : public LibCallOptimization {
|
||||
FT->getParamType(1) != FT->getParamType(2) ||
|
||||
FT->getParamType(3) != FT->getReturnType())
|
||||
return 0;
|
||||
|
||||
|
||||
// Whether or not this allocates is irrelevant if the result isn't used.
|
||||
// Just delete if that's the case.
|
||||
if (CI->use_empty())
|
||||
return CI;
|
||||
|
||||
|
||||
Value* NewLen = CI->getOperand(2);
|
||||
if (Constant* NewCst = dyn_cast<Constant>(NewLen)) {
|
||||
Value* Data = CI->getOperand(4);
|
||||
|
||||
|
||||
// For now, we just catch the simplest of cases.
|
||||
//
|
||||
// TODO: Implement a more general way to compare old and new
|
||||
// lengths, to catch cases like "arr.length = arr.length - 1;"
|
||||
// (But beware of unsigned overflow! For example, we can't
|
||||
// safely transform that example if arr.length may be 0)
|
||||
|
||||
|
||||
// Setting length to 0 never reallocates, so replace by data argument
|
||||
if (NewCst->isNullValue())
|
||||
return Data;
|
||||
|
||||
|
||||
// If both lengths are constant integers, see if NewLen <= OldLen
|
||||
Value* OldLen = CI->getOperand(3);
|
||||
if (ConstantInt* OldInt = dyn_cast<ConstantInt>(OldLen))
|
||||
@@ -157,27 +158,27 @@ struct VISIBILITY_HIDDEN ArrayCastLenOpt : public LibCallOptimization {
|
||||
if (Callee->arg_size() != 3 || !isa<IntegerType>(RetTy) ||
|
||||
FT->getParamType(1) != RetTy || FT->getParamType(2) != RetTy)
|
||||
return 0;
|
||||
|
||||
|
||||
Value* OldLen = CI->getOperand(1);
|
||||
Value* OldSize = CI->getOperand(2);
|
||||
Value* NewSize = CI->getOperand(3);
|
||||
|
||||
|
||||
// If the old length was zero, always return zero.
|
||||
if (Constant* LenCst = dyn_cast<Constant>(OldLen))
|
||||
if (LenCst->isNullValue())
|
||||
return OldLen;
|
||||
|
||||
|
||||
// Equal sizes are much faster to check for, so do so now.
|
||||
if (OldSize == NewSize)
|
||||
return OldLen;
|
||||
|
||||
|
||||
// If both sizes are constant integers, see if OldSize is a multiple of NewSize
|
||||
if (ConstantInt* OldInt = dyn_cast<ConstantInt>(OldSize))
|
||||
if (ConstantInt* NewInt = dyn_cast<ConstantInt>(NewSize)) {
|
||||
// Don't crash on NewSize == 0, even though it shouldn't happen.
|
||||
if (NewInt->isNullValue())
|
||||
return 0;
|
||||
|
||||
|
||||
APInt Quot, Rem;
|
||||
APInt::udivrem(OldInt->getValue(), NewInt->getValue(), Quot, Rem);
|
||||
if (Rem == 0)
|
||||
@@ -195,7 +196,7 @@ struct VISIBILITY_HIDDEN AllocationOpt : public LibCallOptimization {
|
||||
// the start of inlined member functions)
|
||||
for (CallInst::use_iterator I = CI->use_begin(), E = CI->use_end() ; I != E;) {
|
||||
Instruction* User = cast<Instruction>(*I++);
|
||||
|
||||
|
||||
if (ICmpInst* Cmp = dyn_cast<ICmpInst>(User)) {
|
||||
if (!Cmp->isEquality())
|
||||
continue;
|
||||
@@ -215,7 +216,7 @@ struct VISIBILITY_HIDDEN AllocationOpt : public LibCallOptimization {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// If it's not used (anymore), pre-emptively GC it.
|
||||
if (CI->use_empty())
|
||||
return CI;
|
||||
@@ -235,23 +236,23 @@ struct VISIBILITY_HIDDEN ArraySliceCopyOpt : public LibCallOptimization {
|
||||
FT->getParamType(2) != VoidPtrTy ||
|
||||
FT->getParamType(3) != FT->getParamType(1))
|
||||
return 0;
|
||||
|
||||
|
||||
Value* Size = CI->getOperand(2);
|
||||
|
||||
|
||||
// Check the lengths match
|
||||
if (CI->getOperand(4) != Size)
|
||||
return 0;
|
||||
|
||||
|
||||
// Assume unknown size unless we have constant size (that fits in an uint)
|
||||
unsigned Sz = ~0U;
|
||||
if (ConstantInt* Int = dyn_cast<ConstantInt>(Size))
|
||||
if (Int->getValue().isIntN(32))
|
||||
Sz = Int->getValue().getZExtValue();
|
||||
|
||||
|
||||
// Check if the pointers may alias
|
||||
if (AA->alias(CI->getOperand(1), Sz, CI->getOperand(3), Sz))
|
||||
return 0;
|
||||
|
||||
|
||||
// Equal length and the pointers definitely don't alias, so it's safe to
|
||||
// replace the call with memcpy
|
||||
return EmitMemCpy(CI->getOperand(1), CI->getOperand(3), Size, 0, B);
|
||||
@@ -271,24 +272,24 @@ namespace {
|
||||
///
|
||||
class VISIBILITY_HIDDEN SimplifyDRuntimeCalls : public FunctionPass {
|
||||
StringMap<LibCallOptimization*> Optimizations;
|
||||
|
||||
|
||||
// Array operations
|
||||
ArraySetLengthOpt ArraySetLength;
|
||||
ArrayCastLenOpt ArrayCastLen;
|
||||
ArraySliceCopyOpt ArraySliceCopy;
|
||||
|
||||
|
||||
// GC allocations
|
||||
AllocationOpt Allocation;
|
||||
|
||||
|
||||
public:
|
||||
static char ID; // Pass identification
|
||||
SimplifyDRuntimeCalls() : FunctionPass(&ID) {}
|
||||
|
||||
|
||||
void InitOptimizations();
|
||||
bool runOnFunction(Function &F);
|
||||
|
||||
|
||||
bool runOnce(Function &F, const TargetData& TD, AliasAnalysis& AA);
|
||||
|
||||
|
||||
virtual void getAnalysisUsage(AnalysisUsage &AU) const {
|
||||
AU.addRequired<TargetData>();
|
||||
AU.addRequired<AliasAnalysis>();
|
||||
@@ -302,7 +303,7 @@ X("simplify-drtcalls", "Simplify calls to D runtime");
|
||||
|
||||
// Public interface to the pass.
|
||||
FunctionPass *createSimplifyDRuntimeCalls() {
|
||||
return new SimplifyDRuntimeCalls();
|
||||
return new SimplifyDRuntimeCalls();
|
||||
}
|
||||
|
||||
/// Optimizations - Populate the Optimizations map with all the optimizations
|
||||
@@ -313,7 +314,7 @@ void SimplifyDRuntimeCalls::InitOptimizations() {
|
||||
Optimizations["_d_arraysetlengthiT"] = &ArraySetLength;
|
||||
Optimizations["_d_array_cast_len"] = &ArrayCastLen;
|
||||
Optimizations["_d_array_slice_copy"] = &ArraySliceCopy;
|
||||
|
||||
|
||||
/* Delete calls to runtime functions which aren't needed if their result is
|
||||
* unused. That comes down to functions that don't do anything but
|
||||
* GC-allocate and initialize some memory.
|
||||
@@ -339,10 +340,10 @@ void SimplifyDRuntimeCalls::InitOptimizations() {
|
||||
bool SimplifyDRuntimeCalls::runOnFunction(Function &F) {
|
||||
if (Optimizations.empty())
|
||||
InitOptimizations();
|
||||
|
||||
|
||||
const TargetData &TD = getAnalysis<TargetData>();
|
||||
AliasAnalysis &AA = getAnalysis<AliasAnalysis>();
|
||||
|
||||
|
||||
// Iterate to catch opportunities opened up by other optimizations,
|
||||
// such as calls that are only used as arguments to unused calls:
|
||||
// When the second call gets deleted the first call will become unused, but
|
||||
@@ -354,7 +355,7 @@ bool SimplifyDRuntimeCalls::runOnFunction(Function &F) {
|
||||
Changed = runOnce(F, TD, AA);
|
||||
EverChanged |= Changed;
|
||||
} while (Changed);
|
||||
|
||||
|
||||
return EverChanged;
|
||||
}
|
||||
|
||||
@@ -367,33 +368,33 @@ bool SimplifyDRuntimeCalls::runOnce(Function &F, const TargetData& TD, AliasAnal
|
||||
// Ignore non-calls.
|
||||
CallInst *CI = dyn_cast<CallInst>(I++);
|
||||
if (!CI) continue;
|
||||
|
||||
|
||||
// Ignore indirect calls and calls to non-external functions.
|
||||
Function *Callee = CI->getCalledFunction();
|
||||
if (Callee == 0 || !Callee->isDeclaration() ||
|
||||
!(Callee->hasExternalLinkage() || Callee->hasDLLImportLinkage()))
|
||||
continue;
|
||||
|
||||
|
||||
// Ignore unknown calls.
|
||||
StringMap<LibCallOptimization*>::iterator OMI =
|
||||
Optimizations.find(Callee->getName());
|
||||
if (OMI == Optimizations.end()) continue;
|
||||
|
||||
|
||||
DEBUG(errs() << "SimplifyDRuntimeCalls inspecting: " << *CI);
|
||||
|
||||
|
||||
// Set the builder to the instruction after the call.
|
||||
Builder.SetInsertPoint(BB, I);
|
||||
|
||||
|
||||
// Try to optimize this call.
|
||||
Value *Result = OMI->second->OptimizeCall(CI, Changed, TD, AA, Builder);
|
||||
if (Result == 0) continue;
|
||||
|
||||
|
||||
DEBUG(errs() << "SimplifyDRuntimeCalls simplified: " << *CI;
|
||||
errs() << " into: " << *Result << "\n");
|
||||
|
||||
|
||||
// Something changed!
|
||||
Changed = true;
|
||||
|
||||
|
||||
if (Result == CI) {
|
||||
assert(CI->use_empty());
|
||||
++NumDeleted;
|
||||
@@ -401,18 +402,18 @@ bool SimplifyDRuntimeCalls::runOnce(Function &F, const TargetData& TD, AliasAnal
|
||||
} else {
|
||||
++NumSimplified;
|
||||
AA.replaceWithNewValue(CI, Result);
|
||||
|
||||
|
||||
if (!CI->use_empty())
|
||||
CI->replaceAllUsesWith(Result);
|
||||
|
||||
|
||||
if (!Result->hasName())
|
||||
Result->takeName(CI);
|
||||
}
|
||||
|
||||
|
||||
// Inspect the instruction after the call (which was potentially just
|
||||
// added) next.
|
||||
I = CI; ++I;
|
||||
|
||||
|
||||
CI->eraseFromParent();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,9 +53,11 @@ void ReturnStatement::toIR(IRState* p)
|
||||
Logger::println("ReturnStatement::toIR(): %s", loc.toChars());
|
||||
LOG_SCOPE;
|
||||
|
||||
#ifndef DISABLE_DEBUG_INFO
|
||||
if (global.params.symdebug)
|
||||
DtoDwarfStopPoint(loc.linnum);
|
||||
|
||||
#endif
|
||||
|
||||
// is there a return value expression?
|
||||
if (exp || (!exp && (p->topfunc() == p->mainFunc)) )
|
||||
{
|
||||
@@ -78,8 +80,10 @@ void ReturnStatement::toIR(IRState* p)
|
||||
// emit scopes
|
||||
DtoEnclosingHandlers(loc, NULL);
|
||||
|
||||
#ifndef DISABLE_DEBUG_INFO
|
||||
// emit dbg end function
|
||||
if (global.params.symdebug) DtoDwarfFuncEnd(f->decl);
|
||||
#endif
|
||||
|
||||
// emit ret
|
||||
llvm::ReturnInst::Create(gIR->context(), p->scopebb());
|
||||
@@ -126,7 +130,9 @@ void ReturnStatement::toIR(IRState* p)
|
||||
|
||||
DtoEnclosingHandlers(loc, NULL);
|
||||
|
||||
#ifndef DISABLE_DEBUG_INFO
|
||||
if (global.params.symdebug) DtoDwarfFuncEnd(p->func()->decl);
|
||||
#endif
|
||||
llvm::ReturnInst::Create(gIR->context(), v, p->scopebb());
|
||||
}
|
||||
}
|
||||
@@ -136,7 +142,9 @@ void ReturnStatement::toIR(IRState* p)
|
||||
assert(p->topfunc()->getReturnType() == LLType::getVoidTy(gIR->context()));
|
||||
DtoEnclosingHandlers(loc, NULL);
|
||||
|
||||
#ifndef DISABLE_DEBUG_INFO
|
||||
if (global.params.symdebug) DtoDwarfFuncEnd(p->func()->decl);
|
||||
#endif
|
||||
llvm::ReturnInst::Create(gIR->context(), p->scopebb());
|
||||
}
|
||||
|
||||
@@ -153,8 +161,10 @@ void ExpStatement::toIR(IRState* p)
|
||||
Logger::println("ExpStatement::toIR(): %s", loc.toChars());
|
||||
LOG_SCOPE;
|
||||
|
||||
#ifndef DISABLE_DEBUG_INFO
|
||||
if (global.params.symdebug)
|
||||
DtoDwarfStopPoint(loc.linnum);
|
||||
#endif
|
||||
|
||||
if (exp) {
|
||||
if (global.params.llvmAnnotate)
|
||||
@@ -182,8 +192,10 @@ void IfStatement::toIR(IRState* p)
|
||||
Logger::println("IfStatement::toIR(): %s", loc.toChars());
|
||||
LOG_SCOPE;
|
||||
|
||||
#ifndef DISABLE_DEBUG_INFO
|
||||
if (global.params.symdebug)
|
||||
DtoDwarfStopPoint(loc.linnum);
|
||||
#endif
|
||||
|
||||
if (match)
|
||||
DtoRawVarDeclaration(match);
|
||||
@@ -270,8 +282,10 @@ void WhileStatement::toIR(IRState* p)
|
||||
Logger::println("WhileStatement::toIR(): %s", loc.toChars());
|
||||
LOG_SCOPE;
|
||||
|
||||
#ifndef DISABLE_DEBUG_INFO
|
||||
if (global.params.symdebug)
|
||||
DtoDwarfStopPoint(loc.linnum);
|
||||
#endif
|
||||
|
||||
// create while blocks
|
||||
llvm::BasicBlock* oldend = gIR->scopeend();
|
||||
@@ -318,8 +332,10 @@ void DoStatement::toIR(IRState* p)
|
||||
Logger::println("DoStatement::toIR(): %s", loc.toChars());
|
||||
LOG_SCOPE;
|
||||
|
||||
#ifndef DISABLE_DEBUG_INFO
|
||||
if (global.params.symdebug)
|
||||
DtoDwarfStopPoint(loc.linnum);
|
||||
#endif
|
||||
|
||||
// create while blocks
|
||||
llvm::BasicBlock* oldend = gIR->scopeend();
|
||||
@@ -363,8 +379,10 @@ void ForStatement::toIR(IRState* p)
|
||||
Logger::println("ForStatement::toIR(): %s", loc.toChars());
|
||||
LOG_SCOPE;
|
||||
|
||||
#ifndef DISABLE_DEBUG_INFO
|
||||
if (global.params.symdebug)
|
||||
DtoDwarfStopPoint(loc.linnum);
|
||||
#endif
|
||||
|
||||
// create for blocks
|
||||
llvm::BasicBlock* oldend = gIR->scopeend();
|
||||
@@ -443,8 +461,10 @@ void BreakStatement::toIR(IRState* p)
|
||||
if (p->scopereturned())
|
||||
return;
|
||||
|
||||
#ifndef DISABLE_DEBUG_INFO
|
||||
if (global.params.symdebug)
|
||||
DtoDwarfStopPoint(loc.linnum);
|
||||
#endif
|
||||
|
||||
if (ident != 0) {
|
||||
Logger::println("ident = %s", ident->toChars());
|
||||
@@ -498,8 +518,10 @@ void ContinueStatement::toIR(IRState* p)
|
||||
Logger::println("ContinueStatement::toIR(): %s", loc.toChars());
|
||||
LOG_SCOPE;
|
||||
|
||||
#ifndef DISABLE_DEBUG_INFO
|
||||
if (global.params.symdebug)
|
||||
DtoDwarfStopPoint(loc.linnum);
|
||||
#endif
|
||||
|
||||
if (ident != 0) {
|
||||
Logger::println("ident = %s", ident->toChars());
|
||||
@@ -564,8 +586,10 @@ void TryFinallyStatement::toIR(IRState* p)
|
||||
Logger::println("TryFinallyStatement::toIR(): %s", loc.toChars());
|
||||
LOG_SCOPE;
|
||||
|
||||
#ifndef DISABLE_DEBUG_INFO
|
||||
if (global.params.symdebug)
|
||||
DtoDwarfStopPoint(loc.linnum);
|
||||
#endif
|
||||
|
||||
// if there's no finalbody or no body, things are simple
|
||||
if (!finalbody) {
|
||||
@@ -642,8 +666,10 @@ void TryCatchStatement::toIR(IRState* p)
|
||||
Logger::println("TryCatchStatement::toIR(): %s", loc.toChars());
|
||||
LOG_SCOPE;
|
||||
|
||||
#ifndef DISABLE_DEBUG_INFO
|
||||
if (global.params.symdebug)
|
||||
DtoDwarfStopPoint(loc.linnum);
|
||||
#endif
|
||||
|
||||
// create basic blocks
|
||||
llvm::BasicBlock* oldend = p->scopeend();
|
||||
@@ -698,13 +724,17 @@ void ThrowStatement::toIR(IRState* p)
|
||||
Logger::println("ThrowStatement::toIR(): %s", loc.toChars());
|
||||
LOG_SCOPE;
|
||||
|
||||
#ifndef DISABLE_DEBUG_INFO
|
||||
if (global.params.symdebug)
|
||||
DtoDwarfStopPoint(loc.linnum);
|
||||
#endif
|
||||
|
||||
assert(exp);
|
||||
DValue* e = exp->toElem(p);
|
||||
|
||||
#ifndef DISABLE_DEBUG_INFO
|
||||
if (global.params.symdebug) DtoDwarfFuncEnd(gIR->func()->decl);
|
||||
#endif
|
||||
|
||||
llvm::Function* fn = LLVM_D_GetRuntimeFunction(gIR->module, "_d_throw_exception");
|
||||
//Logger::cout() << "calling: " << *fn << '\n';
|
||||
@@ -780,8 +810,10 @@ void SwitchStatement::toIR(IRState* p)
|
||||
Logger::println("SwitchStatement::toIR(): %s", loc.toChars());
|
||||
LOG_SCOPE;
|
||||
|
||||
#ifndef DISABLE_DEBUG_INFO
|
||||
if (global.params.symdebug)
|
||||
DtoDwarfStopPoint(loc.linnum);
|
||||
#endif
|
||||
|
||||
llvm::BasicBlock* oldend = gIR->scopeend();
|
||||
|
||||
@@ -951,8 +983,10 @@ void UnrolledLoopStatement::toIR(IRState* p)
|
||||
if (!statements || !statements->dim)
|
||||
return;
|
||||
|
||||
#ifndef DISABLE_DEBUG_INFO
|
||||
if (global.params.symdebug)
|
||||
DtoDwarfStopPoint(loc.linnum);
|
||||
#endif
|
||||
|
||||
// DMD doesn't fold stuff like continue/break, and since this isn't really a loop
|
||||
// we have to keep track of each statement and jump to the next/end on continue/break
|
||||
@@ -1017,8 +1051,10 @@ void ForeachStatement::toIR(IRState* p)
|
||||
Logger::println("ForeachStatement::toIR(): %s", loc.toChars());
|
||||
LOG_SCOPE;
|
||||
|
||||
#ifndef DISABLE_DEBUG_INFO
|
||||
if (global.params.symdebug)
|
||||
DtoDwarfStopPoint(loc.linnum);
|
||||
#endif
|
||||
|
||||
//assert(arguments->dim == 1);
|
||||
assert(value != 0);
|
||||
@@ -1149,8 +1185,10 @@ void ForeachRangeStatement::toIR(IRState* p)
|
||||
Logger::println("ForeachRangeStatement::toIR(): %s", loc.toChars());
|
||||
LOG_SCOPE;
|
||||
|
||||
#ifndef DISABLE_DEBUG_INFO
|
||||
if (global.params.symdebug)
|
||||
DtoDwarfStopPoint(loc.linnum);
|
||||
#endif
|
||||
|
||||
// evaluate lwr/upr
|
||||
assert(lwr->type->isintegral());
|
||||
@@ -1298,8 +1336,10 @@ void GotoStatement::toIR(IRState* p)
|
||||
Logger::println("GotoStatement::toIR(): %s", loc.toChars());
|
||||
LOG_SCOPE;
|
||||
|
||||
#ifndef DISABLE_DEBUG_INFO
|
||||
if (global.params.symdebug)
|
||||
DtoDwarfStopPoint(loc.linnum);
|
||||
#endif
|
||||
|
||||
llvm::BasicBlock* oldend = gIR->scopeend();
|
||||
llvm::BasicBlock* bb = llvm::BasicBlock::Create(gIR->context(), "aftergoto", p->topfunc(), oldend);
|
||||
@@ -1316,8 +1356,10 @@ void GotoDefaultStatement::toIR(IRState* p)
|
||||
Logger::println("GotoDefaultStatement::toIR(): %s", loc.toChars());
|
||||
LOG_SCOPE;
|
||||
|
||||
#ifndef DISABLE_DEBUG_INFO
|
||||
if (global.params.symdebug)
|
||||
DtoDwarfStopPoint(loc.linnum);
|
||||
#endif
|
||||
|
||||
llvm::BasicBlock* oldend = gIR->scopeend();
|
||||
llvm::BasicBlock* bb = llvm::BasicBlock::Create(gIR->context(), "aftergotodefault", p->topfunc(), oldend);
|
||||
@@ -1338,8 +1380,10 @@ void GotoCaseStatement::toIR(IRState* p)
|
||||
Logger::println("GotoCaseStatement::toIR(): %s", loc.toChars());
|
||||
LOG_SCOPE;
|
||||
|
||||
#ifndef DISABLE_DEBUG_INFO
|
||||
if (global.params.symdebug)
|
||||
DtoDwarfStopPoint(loc.linnum);
|
||||
#endif
|
||||
|
||||
llvm::BasicBlock* oldend = gIR->scopeend();
|
||||
llvm::BasicBlock* bb = llvm::BasicBlock::Create(gIR->context(), "aftergotocase", p->topfunc(), oldend);
|
||||
@@ -1363,8 +1407,10 @@ void WithStatement::toIR(IRState* p)
|
||||
Logger::println("WithStatement::toIR(): %s", loc.toChars());
|
||||
LOG_SCOPE;
|
||||
|
||||
#ifndef DISABLE_DEBUG_INFO
|
||||
if (global.params.symdebug)
|
||||
DtoDwarfStopPoint(loc.linnum);
|
||||
#endif
|
||||
|
||||
assert(exp);
|
||||
assert(body);
|
||||
@@ -1393,8 +1439,10 @@ void SynchronizedStatement::toIR(IRState* p)
|
||||
Logger::println("SynchronizedStatement::toIR(): %s", loc.toChars());
|
||||
LOG_SCOPE;
|
||||
|
||||
#ifndef DISABLE_DEBUG_INFO
|
||||
if (global.params.symdebug)
|
||||
DtoDwarfStopPoint(loc.linnum);
|
||||
#endif
|
||||
|
||||
// enter lock
|
||||
if (exp)
|
||||
@@ -1430,8 +1478,10 @@ void VolatileStatement::toIR(IRState* p)
|
||||
Logger::println("VolatileStatement::toIR(): %s", loc.toChars());
|
||||
LOG_SCOPE;
|
||||
|
||||
#ifndef DISABLE_DEBUG_INFO
|
||||
if (global.params.symdebug)
|
||||
DtoDwarfStopPoint(loc.linnum);
|
||||
#endif
|
||||
|
||||
// mark in-volatile
|
||||
// FIXME
|
||||
|
||||
@@ -35,7 +35,7 @@ TypeFunction* DtoTypeFunction(DValue* fnval)
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
unsigned DtoCallingConv(Loc loc, LINK l)
|
||||
llvm::CallingConv::ID DtoCallingConv(Loc loc, LINK l)
|
||||
{
|
||||
if (l == LINKc || l == LINKcpp || l == LINKintrinsic)
|
||||
return llvm::CallingConv::C;
|
||||
@@ -207,7 +207,7 @@ void DtoBuildDVarArgList(std::vector<LLValue*>& args, std::vector<llvm::Attribut
|
||||
pinits.push_back(DtoConstSize_t(vtype->getNumElements()));
|
||||
pinits.push_back(llvm::ConstantExpr::getBitCast(typeinfomem, getPtrToType(typeinfotype)));
|
||||
const LLType* tiarrty = DtoType(Type::typeinfo->type->arrayOf());
|
||||
tiinits = LLConstantStruct::get(gIR->context(), pinits);
|
||||
tiinits = LLConstantStruct::get(gIR->context(), pinits, false);
|
||||
LLValue* typeinfoarrayparam = new llvm::GlobalVariable(*gIR->module, tiarrty,
|
||||
true, llvm::GlobalValue::InternalLinkage, tiinits, "._arguments.array");
|
||||
|
||||
@@ -279,7 +279,7 @@ DValue* DtoCallFunction(Loc& loc, Type* resulttype, DValue* fnval, Expressions*
|
||||
bool nestedcall = tf->fty.arg_nest;
|
||||
bool dvarargs = (tf->linkage == LINKd && tf->varargs == 1);
|
||||
|
||||
unsigned callconv = DtoCallingConv(loc, tf->linkage);
|
||||
llvm::CallingConv::ID callconv = DtoCallingConv(loc, tf->linkage);
|
||||
|
||||
// get callee llvm value
|
||||
LLValue* callable = DtoCallableValue(fnval);
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
|
||||
using namespace llvm::dwarf;
|
||||
|
||||
#ifndef DISABLE_DEBUG_INFO
|
||||
|
||||
#define DBG_NULL ( LLConstant::getNullValue(DBG_TYPE) )
|
||||
#define DBG_TYPE ( getPtrToType(llvm::StructType::get(gIR->context(),NULL,NULL)) )
|
||||
#define DBG_CAST(X) ( llvm::ConstantExpr::getBitCast(X, DBG_TYPE) )
|
||||
@@ -220,7 +222,7 @@ static void add_base_fields(
|
||||
}
|
||||
}
|
||||
|
||||
//FIXME: This does not use llvm's DIFactory as it can't
|
||||
//FIXME: This does not use llvm's DIFactory as it can't
|
||||
// handle recursive types properly.
|
||||
static llvm::DICompositeType dwarfCompositeType(Type* type, llvm::DICompileUnit compileUnit)
|
||||
{
|
||||
@@ -530,7 +532,7 @@ llvm::DICompileUnit DtoDwarfCompileUnit(Module* m)
|
||||
false, // isMain,
|
||||
false // isOptimized
|
||||
);
|
||||
|
||||
|
||||
// if the linkage stays internal, we can't llvm-link the generated modules together:
|
||||
// llvm's DwarfWriter uses path and filename to determine the symbol name and we'd
|
||||
// end up with duplicate symbols
|
||||
@@ -636,3 +638,5 @@ void DtoDwarfStopPoint(unsigned ln)
|
||||
gIR->scopebb()
|
||||
);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
#ifndef LDC_GEN_TODEBUG_H
|
||||
#define LDC_GEN_TODEBUG_H
|
||||
|
||||
#ifndef DISABLE_DEBUG_INFO
|
||||
|
||||
void RegisterDwarfSymbols(llvm::Module* mod);
|
||||
|
||||
/**
|
||||
@@ -19,7 +21,7 @@ llvm::DISubprogram DtoDwarfSubProgram(FuncDeclaration* fd);
|
||||
|
||||
/**
|
||||
* Emit the Dwarf subprogram global for a internal function.
|
||||
* This is used for generated functions like moduleinfoctors,
|
||||
* This is used for generated functions like moduleinfoctors,
|
||||
* module ctors/dtors and unittests.
|
||||
* @return the Dwarf subprogram global.
|
||||
*/
|
||||
@@ -39,12 +41,12 @@ void DtoDwarfLocalVariable(LLValue* ll, VarDeclaration* vd);
|
||||
|
||||
/**
|
||||
* Emits all things necessary for making debug info for a global variable vd.
|
||||
* @param ll
|
||||
* @param vd
|
||||
* @return
|
||||
* @param ll
|
||||
* @param vd
|
||||
* @return
|
||||
*/
|
||||
llvm::DIGlobalVariable DtoDwarfGlobalVariable(LLGlobalVariable* ll, VarDeclaration* vd);
|
||||
|
||||
#endif // DISABLE_DEBUG_INFO
|
||||
|
||||
#endif // LDC_GEN_TODEBUG_H
|
||||
|
||||
|
||||
|
||||
@@ -157,7 +157,7 @@ const LLType* DtoType(Type* t)
|
||||
return getVoidPtrType();
|
||||
|
||||
/*
|
||||
Not needed atm as VarDecls for tuples are rewritten as a string of
|
||||
Not needed atm as VarDecls for tuples are rewritten as a string of
|
||||
VarDecls for the fields (u -> _u_field_0, ...)
|
||||
|
||||
case Ttuple:
|
||||
@@ -289,12 +289,12 @@ LLGlobalValue::LinkageTypes DtoLinkage(Dsymbol* sym)
|
||||
{
|
||||
assert(0 && "not global/function");
|
||||
}
|
||||
|
||||
|
||||
// The following breaks for nested naked functions and other declarations, so check for that.
|
||||
bool skipNestedCheck = !mustDefineSymbol(sym);
|
||||
if (FuncDeclaration* fd = sym->isFuncDeclaration())
|
||||
skipNestedCheck = (fd->naked != 0);
|
||||
|
||||
|
||||
// Any symbol nested in a function can't be referenced directly from
|
||||
// outside that function, so we can give such symbols internal linkage.
|
||||
// This holds even if nested indirectly, such as member functions of
|
||||
@@ -313,7 +313,7 @@ LLGlobalValue::LinkageTypes DtoLinkage(Dsymbol* sym)
|
||||
if (parent->isFuncDeclaration())
|
||||
return llvm::GlobalValue::InternalLinkage;
|
||||
}
|
||||
|
||||
|
||||
// default to external linkage
|
||||
return llvm::GlobalValue::ExternalLinkage;
|
||||
}
|
||||
@@ -362,7 +362,7 @@ LLValue* DtoPointedType(LLValue* ptr, LLValue* val)
|
||||
return val;
|
||||
}
|
||||
// ptr is integer pointer
|
||||
else if (ptrTy->isInteger())
|
||||
else if (ptrTy->isIntegerTy())
|
||||
{
|
||||
// val is integer
|
||||
assert(valTy->isInteger());
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
#include "llvm/Analysis/Verifier.h"
|
||||
#include "llvm/Bitcode/ReaderWriter.h"
|
||||
#include "llvm/Module.h"
|
||||
#include "llvm/ModuleProvider.h"
|
||||
#include "llvm/PassManager.h"
|
||||
#include "llvm/LinkAllPasses.h"
|
||||
#include "llvm/System/Program.h"
|
||||
@@ -22,6 +21,7 @@
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
#include "llvm/Support/FormattedStream.h"
|
||||
#include "llvm/Target/TargetMachine.h"
|
||||
#include "llvm/CodeGen/MachineCodeEmitter.h"
|
||||
|
||||
#include "mars.h"
|
||||
#include "module.h"
|
||||
@@ -114,11 +114,13 @@ llvm::Module* Module::genLLVMModule(llvm::LLVMContext& context, Ir* sir)
|
||||
// allocate the target abi
|
||||
gABI = TargetABI::getTarget();
|
||||
|
||||
#ifndef DISABLE_DEBUG_INFO
|
||||
// debug info
|
||||
if (global.params.symdebug) {
|
||||
RegisterDwarfSymbols(ir.module);
|
||||
DtoDwarfCompileUnit(this);
|
||||
}
|
||||
#endif
|
||||
|
||||
// handle invalid 'objectø module
|
||||
if (!ClassDeclaration::object) {
|
||||
@@ -129,7 +131,7 @@ llvm::Module* Module::genLLVMModule(llvm::LLVMContext& context, Ir* sir)
|
||||
error("is missing 'class ClassInfo'");
|
||||
fatal();
|
||||
}
|
||||
|
||||
|
||||
LLVM_D_InitRuntime();
|
||||
|
||||
// process module members
|
||||
@@ -225,10 +227,11 @@ void writeModule(llvm::Module* m, std::string filename)
|
||||
bcpath.eraseSuffix();
|
||||
bcpath.appendSuffix(std::string(global.bc_ext));
|
||||
Logger::println("Writing LLVM bitcode to: %s\n", bcpath.c_str());
|
||||
std::ofstream bos(bcpath.c_str(), std::ios::binary);
|
||||
if (bos.fail())
|
||||
std::string errinfo;
|
||||
llvm::raw_fd_ostream bos(bcpath.c_str(), errinfo, llvm::raw_fd_ostream::F_Binary);
|
||||
if (bos.has_error())
|
||||
{
|
||||
error("cannot write LLVM bitcode, failed to open file '%s'", bcpath.c_str());
|
||||
error("cannot write LLVM bitcode file '%s': %s", bcpath.c_str(), errinfo.c_str());
|
||||
fatal();
|
||||
}
|
||||
llvm::WriteBitcodeToFile(m, bos);
|
||||
@@ -240,10 +243,11 @@ void writeModule(llvm::Module* m, std::string filename)
|
||||
llpath.eraseSuffix();
|
||||
llpath.appendSuffix(std::string(global.ll_ext));
|
||||
Logger::println("Writing LLVM asm to: %s\n", llpath.c_str());
|
||||
std::ofstream aos(llpath.c_str());
|
||||
if (aos.fail())
|
||||
std::string errinfo;
|
||||
llvm::raw_fd_ostream aos(llpath.c_str(), errinfo);
|
||||
if (aos.has_error())
|
||||
{
|
||||
error("cannot write LLVM asm, failed to open file '%s'", llpath.c_str());
|
||||
error("cannot write LLVM asm file '%s': %s", llpath.c_str(), errinfo.c_str());
|
||||
fatal();
|
||||
}
|
||||
m->print(aos, NULL);
|
||||
@@ -260,7 +264,7 @@ void writeModule(llvm::Module* m, std::string filename)
|
||||
Logger::println("Writing native asm to: %s\n", spath.c_str());
|
||||
std::string err;
|
||||
{
|
||||
llvm::raw_fd_ostream out(spath.c_str(), false, true, err);
|
||||
llvm::raw_fd_ostream out(spath.c_str(), err);
|
||||
if (err.empty())
|
||||
{
|
||||
write_asm_to_file(*gTargetMachine, *m, out);
|
||||
@@ -292,17 +296,13 @@ void write_asm_to_file(llvm::TargetMachine &Target, llvm::Module& m, llvm::raw_f
|
||||
using namespace llvm;
|
||||
|
||||
// Build up all of the passes that we want to do to the module.
|
||||
ExistingModuleProvider Provider(&m);
|
||||
FunctionPassManager Passes(&Provider);
|
||||
FunctionPassManager Passes(&m);
|
||||
|
||||
if (const TargetData *TD = Target.getTargetData())
|
||||
Passes.add(new TargetData(*TD));
|
||||
else
|
||||
Passes.add(new TargetData(&m));
|
||||
|
||||
// Ask the target to add backend passes as necessary.
|
||||
MachineCodeEmitter *MCE = 0;
|
||||
|
||||
// Last argument is enum CodeGenOpt::Level OptLevel
|
||||
// debug info doesn't work properly with OptLevel != None!
|
||||
CodeGenOpt::Level LastArg = CodeGenOpt::Default;
|
||||
@@ -312,11 +312,8 @@ void write_asm_to_file(llvm::TargetMachine &Target, llvm::Module& m, llvm::raw_f
|
||||
LastArg = CodeGenOpt::Aggressive;
|
||||
|
||||
llvm::formatted_raw_ostream fout(out);
|
||||
FileModel::Model mod = Target.addPassesToEmitFile(Passes, fout, TargetMachine::AssemblyFile, LastArg);
|
||||
assert(mod == FileModel::AsmFile);
|
||||
|
||||
bool err = Target.addPassesToEmitFileFinish(Passes, MCE, LastArg);
|
||||
assert(!err);
|
||||
if (Target.addPassesToEmitFile(Passes, fout, TargetMachine::CGFT_AssemblyFile, LastArg))
|
||||
assert(0 && "no support for asm output");
|
||||
|
||||
Passes.doInitialization();
|
||||
|
||||
@@ -328,9 +325,9 @@ void write_asm_to_file(llvm::TargetMachine &Target, llvm::Module& m, llvm::raw_f
|
||||
Passes.doFinalization();
|
||||
|
||||
// release module from module provider so we can delete it ourselves
|
||||
std::string Err;
|
||||
llvm::Module* rmod = Provider.releaseModule(&Err);
|
||||
assert(rmod);
|
||||
//std::string Err;
|
||||
//llvm::Module* rmod = Provider.releaseModule(&Err);
|
||||
//assert(rmod);
|
||||
}
|
||||
|
||||
/* ================================================================== */
|
||||
@@ -350,14 +347,14 @@ void assemble(const llvm::sys::Path& asmpath, const llvm::sys::Path& objpath)
|
||||
// and linker because we don't know where to put the _start symbol.
|
||||
// GCC mysteriously knows how to do it.
|
||||
std::vector<std::string> args;
|
||||
args.push_back(gcc.toString());
|
||||
args.push_back(gcc.str());
|
||||
args.push_back("-fno-strict-aliasing");
|
||||
args.push_back("-O3");
|
||||
args.push_back("-c");
|
||||
args.push_back("-xassembler");
|
||||
args.push_back(asmpath.toString());
|
||||
args.push_back(asmpath.str());
|
||||
args.push_back("-o");
|
||||
args.push_back(objpath.toString());
|
||||
args.push_back(objpath.str());
|
||||
|
||||
//FIXME: only use this if needed?
|
||||
args.push_back("-fpic");
|
||||
@@ -431,11 +428,13 @@ llvm::Function* build_module_ctor()
|
||||
IRBuilder<> builder(bb);
|
||||
|
||||
// debug info
|
||||
#ifndef DISABLE_DEBUG_INFO
|
||||
LLGlobalVariable* subprog;
|
||||
if(global.params.symdebug) {
|
||||
subprog = DtoDwarfSubProgramInternal(name.c_str(), name.c_str()).getGV();
|
||||
builder.CreateCall(gIR->module->getFunction("llvm.dbg.func.start"), DBG_CAST(subprog));
|
||||
}
|
||||
#endif
|
||||
|
||||
for (size_t i=0; i<n; i++) {
|
||||
llvm::Function* f = gIR->ctors[i]->ir.irFunc->func;
|
||||
@@ -444,8 +443,10 @@ llvm::Function* build_module_ctor()
|
||||
}
|
||||
|
||||
// debug info end
|
||||
#ifndef DISABLE_DEBUG_INFO
|
||||
if(global.params.symdebug)
|
||||
builder.CreateCall(gIR->module->getFunction("llvm.dbg.region.end"), DBG_CAST(subprog));
|
||||
#endif
|
||||
|
||||
builder.CreateRetVoid();
|
||||
return fn;
|
||||
@@ -475,12 +476,14 @@ static llvm::Function* build_module_dtor()
|
||||
llvm::BasicBlock* bb = llvm::BasicBlock::Create(gIR->context(), "entry", fn);
|
||||
IRBuilder<> builder(bb);
|
||||
|
||||
#ifndef DISABLE_DEBUG_INFO
|
||||
// debug info
|
||||
LLGlobalVariable* subprog;
|
||||
if(global.params.symdebug) {
|
||||
subprog = DtoDwarfSubProgramInternal(name.c_str(), name.c_str()).getGV();
|
||||
builder.CreateCall(gIR->module->getFunction("llvm.dbg.func.start"), DBG_CAST(subprog));
|
||||
}
|
||||
#endif
|
||||
|
||||
for (size_t i=0; i<n; i++) {
|
||||
llvm::Function* f = gIR->dtors[i]->ir.irFunc->func;
|
||||
@@ -488,9 +491,11 @@ static llvm::Function* build_module_dtor()
|
||||
call->setCallingConv(DtoCallingConv(0, LINKd));
|
||||
}
|
||||
|
||||
#ifndef DISABLE_DEBUG_INFO
|
||||
// debug info end
|
||||
if(global.params.symdebug)
|
||||
builder.CreateCall(gIR->module->getFunction("llvm.dbg.region.end"), DBG_CAST(subprog));
|
||||
#endif
|
||||
|
||||
builder.CreateRetVoid();
|
||||
return fn;
|
||||
@@ -520,12 +525,14 @@ static llvm::Function* build_module_unittest()
|
||||
llvm::BasicBlock* bb = llvm::BasicBlock::Create(gIR->context(), "entry", fn);
|
||||
IRBuilder<> builder(bb);
|
||||
|
||||
#ifndef DISABLE_DEBUG_INFO
|
||||
// debug info
|
||||
LLGlobalVariable* subprog;
|
||||
if(global.params.symdebug) {
|
||||
subprog = DtoDwarfSubProgramInternal(name.c_str(), name.c_str()).getGV();
|
||||
builder.CreateCall(gIR->module->getFunction("llvm.dbg.func.start"), DBG_CAST(subprog));
|
||||
}
|
||||
#endif
|
||||
|
||||
for (size_t i=0; i<n; i++) {
|
||||
llvm::Function* f = gIR->unitTests[i]->ir.irFunc->func;
|
||||
@@ -533,9 +540,11 @@ static llvm::Function* build_module_unittest()
|
||||
call->setCallingConv(DtoCallingConv(0, LINKd));
|
||||
}
|
||||
|
||||
#ifndef DISABLE_DEBUG_INFO
|
||||
// debug info end
|
||||
if(global.params.symdebug)
|
||||
builder.CreateCall(gIR->module->getFunction("llvm.dbg.region.end"), DBG_CAST(subprog));
|
||||
#endif
|
||||
|
||||
builder.CreateRetVoid();
|
||||
return fn;
|
||||
@@ -578,11 +587,13 @@ static LLFunction* build_module_reference_and_ctor(LLConstant* moduleinfo)
|
||||
IRBuilder<> builder(bb);
|
||||
|
||||
// debug info
|
||||
#ifndef DISABLE_DEBUG_INFO
|
||||
LLGlobalVariable* subprog;
|
||||
if(global.params.symdebug) {
|
||||
subprog = DtoDwarfSubProgramInternal(fname.c_str(), fname.c_str()).getGV();
|
||||
builder.CreateCall(gIR->module->getFunction("llvm.dbg.func.start"), DBG_CAST(subprog));
|
||||
}
|
||||
#endif
|
||||
|
||||
// get current beginning
|
||||
LLValue* curbeg = builder.CreateLoad(mref, "current");
|
||||
@@ -594,9 +605,11 @@ static LLFunction* build_module_reference_and_ctor(LLConstant* moduleinfo)
|
||||
// replace beginning
|
||||
builder.CreateStore(thismref, mref);
|
||||
|
||||
#ifndef DISABLE_DEBUG_INFO
|
||||
// debug info end
|
||||
if(global.params.symdebug)
|
||||
builder.CreateCall(gIR->module->getFunction("llvm.dbg.region.end"), DBG_CAST(subprog));
|
||||
#endif
|
||||
|
||||
// return
|
||||
builder.CreateRetVoid();
|
||||
@@ -614,11 +627,11 @@ void Module::genmoduleinfo()
|
||||
// ModuleInfo[] importedModules;
|
||||
// ClassInfo[] localClasses;
|
||||
// uint flags;
|
||||
//
|
||||
//
|
||||
// void function() ctor;
|
||||
// void function() dtor;
|
||||
// void function() unitTest;
|
||||
//
|
||||
//
|
||||
// void* xgetMembers;
|
||||
// void function() ictor;
|
||||
//
|
||||
|
||||
Reference in New Issue
Block a user