mirror of
https://github.com/ldc-developers/ldc.git
synced 2025-05-11 13:26:08 +03: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:
parent
5707961243
commit
1fac40d2bd
27 changed files with 992 additions and 242 deletions
|
@ -41,6 +41,7 @@ struct TemplateDeclaration;
|
||||||
struct ClassDeclaration;
|
struct ClassDeclaration;
|
||||||
struct HdrGenState;
|
struct HdrGenState;
|
||||||
struct BinExp;
|
struct BinExp;
|
||||||
|
struct AssignExp;
|
||||||
struct InterState;
|
struct InterState;
|
||||||
struct OverloadSet;
|
struct OverloadSet;
|
||||||
|
|
||||||
|
@ -177,6 +178,8 @@ struct Expression : Object
|
||||||
virtual void cacheLvalue(IRState* irs);
|
virtual void cacheLvalue(IRState* irs);
|
||||||
|
|
||||||
llvm::Value* cachedLvalue;
|
llvm::Value* cachedLvalue;
|
||||||
|
|
||||||
|
virtual AssignExp* isAssignExp() { return NULL; }
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -942,7 +945,7 @@ struct DotIdExp : UnaExp
|
||||||
struct DotTemplateExp : UnaExp
|
struct DotTemplateExp : UnaExp
|
||||||
{
|
{
|
||||||
TemplateDeclaration *td;
|
TemplateDeclaration *td;
|
||||||
|
|
||||||
DotTemplateExp(Loc loc, Expression *e, TemplateDeclaration *td);
|
DotTemplateExp(Loc loc, Expression *e, TemplateDeclaration *td);
|
||||||
void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
|
void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
|
||||||
};
|
};
|
||||||
|
@ -1378,6 +1381,8 @@ struct AssignExp : BinExp
|
||||||
#if IN_LLVM
|
#if IN_LLVM
|
||||||
DValue* toElem(IRState* irs);
|
DValue* toElem(IRState* irs);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
AssignExp* isAssignExp() { return this; }
|
||||||
};
|
};
|
||||||
|
|
||||||
#if IN_DMD
|
#if IN_DMD
|
||||||
|
|
|
@ -141,6 +141,7 @@ struct Statement : Object
|
||||||
virtual ReturnStatement *isReturnStatement() { return NULL; }
|
virtual ReturnStatement *isReturnStatement() { return NULL; }
|
||||||
virtual IfStatement *isIfStatement() { return NULL; }
|
virtual IfStatement *isIfStatement() { return NULL; }
|
||||||
virtual CaseStatement* isCaseStatement() { return NULL; }
|
virtual CaseStatement* isCaseStatement() { return NULL; }
|
||||||
|
virtual LabelStatement* isLabelStatement() { return NULL; }
|
||||||
|
|
||||||
#if IN_LLVM
|
#if IN_LLVM
|
||||||
virtual void toNakedIR(IRState *irs);
|
virtual void toNakedIR(IRState *irs);
|
||||||
|
@ -492,7 +493,7 @@ struct SwitchStatement : Statement
|
||||||
Array gotoCases; // array of unresolved GotoCaseStatement's
|
Array gotoCases; // array of unresolved GotoCaseStatement's
|
||||||
Array *cases; // array of CaseStatement's
|
Array *cases; // array of CaseStatement's
|
||||||
int hasNoDefault; // !=0 if no default statement
|
int hasNoDefault; // !=0 if no default statement
|
||||||
|
|
||||||
// LDC
|
// LDC
|
||||||
Statement *enclosingScopeExit;
|
Statement *enclosingScopeExit;
|
||||||
|
|
||||||
|
@ -536,7 +537,7 @@ struct CaseStatement : Statement
|
||||||
void toIR(IRState *irs);
|
void toIR(IRState *irs);
|
||||||
|
|
||||||
CaseStatement* isCaseStatement() { return this; }
|
CaseStatement* isCaseStatement() { return this; }
|
||||||
|
|
||||||
// LDC
|
// LDC
|
||||||
llvm::BasicBlock* bodyBB;
|
llvm::BasicBlock* bodyBB;
|
||||||
llvm::ConstantInt* llvmIdx;
|
llvm::ConstantInt* llvmIdx;
|
||||||
|
@ -863,6 +864,8 @@ struct LabelStatement : Statement
|
||||||
// LDC
|
// LDC
|
||||||
bool asmLabel; // for labels inside inline assembler
|
bool asmLabel; // for labels inside inline assembler
|
||||||
void toNakedIR(IRState *irs);
|
void toNakedIR(IRState *irs);
|
||||||
|
|
||||||
|
LabelStatement* isLabelStatement() { return this; }
|
||||||
};
|
};
|
||||||
|
|
||||||
struct LabelDsymbol : Dsymbol
|
struct LabelDsymbol : Dsymbol
|
||||||
|
|
|
@ -309,7 +309,7 @@ LLConstant* DtoConstArrayInitializer(ArrayInitializer* arrinit)
|
||||||
|
|
||||||
LLConstant* constarr;
|
LLConstant* constarr;
|
||||||
if (mismatch)
|
if (mismatch)
|
||||||
constarr = LLConstantStruct::get(gIR->context(), initvals);
|
constarr = LLConstantStruct::get(gIR->context(), initvals, false); // FIXME should this pack?
|
||||||
else
|
else
|
||||||
constarr = LLConstantArray::get(LLArrayType::get(llelemty, arrlen), initvals);
|
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* DtoConstSlice(LLConstant* dim, LLConstant* ptr)
|
||||||
{
|
{
|
||||||
LLConstant* values[2] = { dim, 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;
|
bool sep = 0, nsep = 0;
|
||||||
buf->writestring("asm { ");
|
buf->writestring("asm { ");
|
||||||
|
|
||||||
for (Token * t = tokens; t; t = t->next) {
|
for (Token * t = tokens; t; t = t->next) {
|
||||||
switch (t->value) {
|
switch (t->value) {
|
||||||
case TOKlparen:
|
case TOKlparen:
|
||||||
case TOKrparen:
|
case TOKrparen:
|
||||||
|
@ -161,11 +161,11 @@ Statement *AsmStatement::semantic(Scope *sc)
|
||||||
sc->func->inlineStatus = ILSno; // %% not sure
|
sc->func->inlineStatus = ILSno; // %% not sure
|
||||||
// %% need to set DECL_UNINLINABLE too?
|
// %% need to set DECL_UNINLINABLE too?
|
||||||
sc->func->hasReturnExp = 1; // %% DMD does this, apparently...
|
sc->func->hasReturnExp = 1; // %% DMD does this, apparently...
|
||||||
|
|
||||||
// empty statement -- still do the above things because they might be expected?
|
// empty statement -- still do the above things because they might be expected?
|
||||||
if (! tokens)
|
if (! tokens)
|
||||||
return this;
|
return this;
|
||||||
|
|
||||||
if (!asmparser)
|
if (!asmparser)
|
||||||
if (global.params.cpu == ARCHx86)
|
if (global.params.cpu == ARCHx86)
|
||||||
asmparser = new AsmParserx8632::AsmParser;
|
asmparser = new AsmParserx8632::AsmParser;
|
||||||
|
@ -196,9 +196,11 @@ AsmStatement::toIR(IRState * irs)
|
||||||
IRAsmBlock* asmblock = irs->asmBlock;
|
IRAsmBlock* asmblock = irs->asmBlock;
|
||||||
assert(asmblock);
|
assert(asmblock);
|
||||||
|
|
||||||
|
#ifndef DISABLE_DEBUG_INFO
|
||||||
// debug info
|
// debug info
|
||||||
if (global.params.symdebug)
|
if (global.params.symdebug)
|
||||||
DtoDwarfStopPoint(loc.linnum);
|
DtoDwarfStopPoint(loc.linnum);
|
||||||
|
#endif
|
||||||
|
|
||||||
if (! asmcode)
|
if (! asmcode)
|
||||||
return;
|
return;
|
||||||
|
@ -257,8 +259,7 @@ AsmStatement::toIR(IRState * irs)
|
||||||
break;
|
break;
|
||||||
case Arg_FrameRelative:
|
case Arg_FrameRelative:
|
||||||
// FIXME
|
// FIXME
|
||||||
llvm::cout << "asm fixme Arg_FrameRelative" << std::endl;
|
assert(0 && "asm fixme Arg_FrameRelative");
|
||||||
assert(0);
|
|
||||||
/* if (arg->expr->op == TOKvar)
|
/* if (arg->expr->op == TOKvar)
|
||||||
arg_val = ((VarExp *) arg->expr)->var->toSymbol()->Stree;
|
arg_val = ((VarExp *) arg->expr)->var->toSymbol()->Stree;
|
||||||
else
|
else
|
||||||
|
@ -275,8 +276,7 @@ assert(0);
|
||||||
break;*/
|
break;*/
|
||||||
case Arg_LocalSize:
|
case Arg_LocalSize:
|
||||||
// FIXME
|
// FIXME
|
||||||
llvm::cout << "asm fixme Arg_LocalSize" << std::endl;
|
assert(0 && "asm fixme Arg_LocalSize");
|
||||||
assert(0);
|
|
||||||
/* var_frame_offset = cfun->x_frame_offset;
|
/* var_frame_offset = cfun->x_frame_offset;
|
||||||
if (var_frame_offset < 0)
|
if (var_frame_offset < 0)
|
||||||
var_frame_offset = - var_frame_offset;
|
var_frame_offset = - var_frame_offset;
|
||||||
|
@ -300,7 +300,7 @@ assert(0);
|
||||||
// Telling GCC that callee-saved registers are clobbered makes it preserve
|
// Telling GCC that callee-saved registers are clobbered makes it preserve
|
||||||
// those registers. This changes the stack from what a naked function
|
// those registers. This changes the stack from what a naked function
|
||||||
// expects.
|
// expects.
|
||||||
|
|
||||||
// FIXME
|
// FIXME
|
||||||
// if (! irs->func->naked) {
|
// if (! irs->func->naked) {
|
||||||
assert(asmparser);
|
assert(asmparser);
|
||||||
|
@ -318,7 +318,7 @@ assert(0);
|
||||||
if (arg_map[i] < 0)
|
if (arg_map[i] < 0)
|
||||||
arg_map[i] = -arg_map[i] - 1 + n_outputs;
|
arg_map[i] = -arg_map[i] - 1 + n_outputs;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool pct = false;
|
bool pct = false;
|
||||||
std::string::iterator
|
std::string::iterator
|
||||||
p = code->insnTemplate.begin(),
|
p = code->insnTemplate.begin(),
|
||||||
|
@ -343,14 +343,14 @@ assert(0);
|
||||||
if (Logger::enabled()) {
|
if (Logger::enabled()) {
|
||||||
Logger::cout() << "final asm: " << code->insnTemplate << '\n';
|
Logger::cout() << "final asm: " << code->insnTemplate << '\n';
|
||||||
std::ostringstream ss;
|
std::ostringstream ss;
|
||||||
|
|
||||||
ss << "GCC-style output constraints: {";
|
ss << "GCC-style output constraints: {";
|
||||||
for (It i = output_constraints.begin(), e = output_constraints.end(); i != e; ++i) {
|
for (It i = output_constraints.begin(), e = output_constraints.end(); i != e; ++i) {
|
||||||
ss << " " << *i;
|
ss << " " << *i;
|
||||||
}
|
}
|
||||||
ss << " }";
|
ss << " }";
|
||||||
Logger::println("%s", ss.str().c_str());
|
Logger::println("%s", ss.str().c_str());
|
||||||
|
|
||||||
ss.str("");
|
ss.str("");
|
||||||
ss << "GCC-style input constraints: {";
|
ss << "GCC-style input constraints: {";
|
||||||
for (It i = input_constraints.begin(), e = input_constraints.end(); i != e; ++i) {
|
for (It i = input_constraints.begin(), e = input_constraints.end(); i != e; ++i) {
|
||||||
|
@ -358,7 +358,7 @@ assert(0);
|
||||||
}
|
}
|
||||||
ss << " }";
|
ss << " }";
|
||||||
Logger::println("%s", ss.str().c_str());
|
Logger::println("%s", ss.str().c_str());
|
||||||
|
|
||||||
ss.str("");
|
ss.str("");
|
||||||
ss << "GCC-style clobbers: {";
|
ss << "GCC-style clobbers: {";
|
||||||
for (It i = clobbers.begin(), e = clobbers.end(); i != e; ++i) {
|
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
|
/* LLVM doesn't support updating operands, so split into an input
|
||||||
* and an output operand.
|
* and an output operand.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Change update operand to pure output operand.
|
// Change update operand to pure output operand.
|
||||||
*i = mw_cns;
|
*i = mw_cns;
|
||||||
|
|
||||||
// Add input operand with same value, with original as "matching output".
|
// Add input operand with same value, with original as "matching output".
|
||||||
std::ostringstream ss;
|
std::ostringstream ss;
|
||||||
ss << '*' << (n + asmblock->outputcount);
|
ss << '*' << (n + asmblock->outputcount);
|
||||||
|
@ -572,7 +572,7 @@ void AsmBlockStatement::toIR(IRState* p)
|
||||||
for(it = asmblock->internalLabels.begin(); it != end; ++it)
|
for(it = asmblock->internalLabels.begin(); it != end; ++it)
|
||||||
if((*it)->equals(a->isBranchToLabel))
|
if((*it)->equals(a->isBranchToLabel))
|
||||||
skip = true;
|
skip = true;
|
||||||
if(skip)
|
if(skip)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// if we already set things up for this branch target, skip
|
// if we already set things up for this branch target, skip
|
||||||
|
|
|
@ -17,19 +17,19 @@ static char toLower(char c) {
|
||||||
return 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
|
// Make a std::string out of it to make comparisons easier
|
||||||
// (and avoid repeated conversion)
|
// (and avoid repeated conversion)
|
||||||
std::string argname = ArgName;
|
llvm::StringRef argname = ArgName;
|
||||||
|
|
||||||
typedef std::vector<std::pair<std::string, bool> >::iterator It;
|
typedef std::vector<std::pair<std::string, bool> >::iterator It;
|
||||||
for (It I = switches.begin(), E = switches.end(); I != E; ++I) {
|
for (It I = switches.begin(), E = switches.end(); I != E; ++I) {
|
||||||
std::string name = I->first;
|
llvm::StringRef name = I->first;
|
||||||
if (name == argname
|
if (name == argname
|
||||||
|| (name.length() < argname.length()
|
|| (name.size() < argname.size()
|
||||||
&& argname.substr(0, name.length()) == name
|
&& argname.substr(0, name.size()) == name
|
||||||
&& argname[name.length()] == '=')) {
|
&& argname[name.size()] == '=')) {
|
||||||
|
|
||||||
if (!cl::parser<bool>::parse(O, ArgName, Arg, Val)) {
|
if (!cl::parser<bool>::parse(O, ArgName, Arg, Val)) {
|
||||||
Val = (Val == I->second);
|
Val = (Val == I->second);
|
||||||
return false;
|
return false;
|
||||||
|
@ -41,10 +41,10 @@ bool FlagParser::parse(cl::Option &O, const char *ArgName, const std::string &Ar
|
||||||
return true;
|
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;
|
typedef std::vector<std::pair<std::string, bool> >::iterator It;
|
||||||
for (It I = switches.begin() + 1, E = switches.end(); I != E; ++I) {
|
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) {
|
void MultiSetter::operator=(bool val) {
|
||||||
typedef std::vector<bool*>::iterator It;
|
typedef std::vector<bool*>::iterator It;
|
||||||
for (It I = locations.begin(), E = locations.end(); I != E; ++I) {
|
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) {
|
void ArrayAdapter::push_back(const char* cstr) {
|
||||||
if (!cstr || !*cstr)
|
if (!cstr || !*cstr)
|
||||||
error("Expected argument to '-%s'", name);
|
error("Expected argument to '-%s'", name);
|
||||||
|
|
||||||
if (!*arrp)
|
if (!*arrp)
|
||||||
*arrp = new Array;
|
*arrp = new Array;
|
||||||
(*arrp)->push(mem.strdup(cstr));
|
(*arrp)->push(mem.strdup(cstr));
|
||||||
|
|
|
@ -10,7 +10,7 @@ struct Array;
|
||||||
|
|
||||||
namespace opts {
|
namespace opts {
|
||||||
namespace cl = llvm::cl;
|
namespace cl = llvm::cl;
|
||||||
|
|
||||||
/// Helper class for fancier options
|
/// Helper class for fancier options
|
||||||
class FlagParser : public cl::parser<bool> {
|
class FlagParser : public cl::parser<bool> {
|
||||||
std::vector<std::pair<std::string, bool> > switches;
|
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("enable-" + Name, true));
|
||||||
switches.push_back(make_pair("disable-" + Name, false));
|
switches.push_back(make_pair("disable-" + Name, false));
|
||||||
// Replace <foo> with -enable-<foo>
|
// 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);
|
bool parse(cl::Option &O, llvm::StringRef ArgName, llvm::StringRef ArgValue, bool &Val);
|
||||||
|
|
||||||
void getExtraOptionNames(std::vector<const char*> &Names);
|
void getExtraOptionNames(llvm::SmallVectorImpl<const char*> &Names);
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Helper class for options that set multiple flags
|
/// Helper class for options that set multiple flags
|
||||||
class MultiSetter {
|
class MultiSetter {
|
||||||
std::vector<bool*> locations;
|
std::vector<bool*> locations;
|
||||||
|
@ -36,10 +36,10 @@ namespace opts {
|
||||||
MultiSetter(bool); //not implemented, disable auto-conversion
|
MultiSetter(bool); //not implemented, disable auto-conversion
|
||||||
public:
|
public:
|
||||||
MultiSetter(bool invert, bool* p, ...) END_WITH_NULL;
|
MultiSetter(bool invert, bool* p, ...) END_WITH_NULL;
|
||||||
|
|
||||||
void operator=(bool val);
|
void operator=(bool val);
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Helper class to fill Array with char* when given strings
|
/// Helper class to fill Array with char* when given strings
|
||||||
/// (Errors on empty strings)
|
/// (Errors on empty strings)
|
||||||
class ArrayAdapter {
|
class ArrayAdapter {
|
||||||
|
@ -52,14 +52,14 @@ namespace opts {
|
||||||
assert(name);
|
assert(name);
|
||||||
assert(arrp);
|
assert(arrp);
|
||||||
}
|
}
|
||||||
|
|
||||||
void push_back(const char* cstr);
|
void push_back(const char* cstr);
|
||||||
|
|
||||||
void push_back(const std::string& str) {
|
void push_back(const std::string& str) {
|
||||||
push_back(str.c_str());
|
push_back(str.c_str());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Helper class to allow use of a parser<bool> with BoolOrDefault
|
/// Helper class to allow use of a parser<bool> with BoolOrDefault
|
||||||
class BoolOrDefaultAdapter {
|
class BoolOrDefaultAdapter {
|
||||||
cl::boolOrDefault value;
|
cl::boolOrDefault value;
|
||||||
|
@ -67,11 +67,11 @@ namespace opts {
|
||||||
operator cl::boolOrDefault() {
|
operator cl::boolOrDefault() {
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
void operator=(cl::boolOrDefault val) {
|
void operator=(cl::boolOrDefault val) {
|
||||||
value = val;
|
value = val;
|
||||||
}
|
}
|
||||||
|
|
||||||
void operator=(bool val) {
|
void operator=(bool val) {
|
||||||
*this = (val ? cl::BOU_TRUE : cl::BOU_FALSE);
|
*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);
|
p.appendComponent(filename);
|
||||||
if (p.exists())
|
if (p.exists())
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -102,14 +102,14 @@ bool ConfigFile::read(const char* argv0, void* mainAddr, const char* filename)
|
||||||
{
|
{
|
||||||
sys::Path p;
|
sys::Path p;
|
||||||
if (!locate(p, argv0, mainAddr, filename))
|
if (!locate(p, argv0, mainAddr, filename))
|
||||||
{
|
{
|
||||||
// failed to find cfg, users still have the DFLAGS environment var
|
// failed to find cfg, users still have the DFLAGS environment var
|
||||||
std::cerr << "Error failed to locate the configuration file: " << filename << std::endl;
|
std::cerr << "Error failed to locate the configuration file: " << filename << std::endl;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// save config file path for -v output
|
// save config file path for -v output
|
||||||
pathstr = p.toString();
|
pathstr = p.str();
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -141,12 +141,12 @@ bool ConfigFile::read(const char* argv0, void* mainAddr, const char* filename)
|
||||||
for (int i=0; i<len; i++)
|
for (int i=0; i<len; i++)
|
||||||
{
|
{
|
||||||
std::string v = arr[i];
|
std::string v = arr[i];
|
||||||
|
|
||||||
// replace binpathkey with binpath
|
// replace binpathkey with binpath
|
||||||
size_t p;
|
size_t p;
|
||||||
while (std::string::npos != (p = v.find(binpathkey)))
|
while (std::string::npos != (p = v.find(binpathkey)))
|
||||||
v.replace(p, binpathkey.size(), binpath);
|
v.replace(p, binpathkey.size(), binpath);
|
||||||
|
|
||||||
switches.push_back(strdup(v.c_str()));
|
switches.push_back(strdup(v.c_str()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -599,10 +599,11 @@ void DtoDefineFunction(FuncDeclaration* fd)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef DISABLE_DEBUG_INFO
|
||||||
// debug info
|
// debug info
|
||||||
if (global.params.symdebug) {
|
if (global.params.symdebug)
|
||||||
fd->ir.irFunc->diSubprogram = DtoDwarfSubProgram(fd);
|
fd->ir.irFunc->diSubprogram = DtoDwarfSubProgram(fd);
|
||||||
}
|
#endif
|
||||||
|
|
||||||
Type* t = fd->type->toBasetype();
|
Type* t = fd->type->toBasetype();
|
||||||
TypeFunction* f = (TypeFunction*)t;
|
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);
|
llvm::Instruction* allocaPoint = new llvm::AllocaInst(LLType::getInt32Ty(gIR->context()), "alloca point", beginbb);
|
||||||
irfunction->allocapoint = allocaPoint;
|
irfunction->allocapoint = allocaPoint;
|
||||||
|
|
||||||
|
#ifndef DISABLE_DEBUG_INFO
|
||||||
// debug info - after all allocas, but before any llvm.dbg.declare etc
|
// debug info - after all allocas, but before any llvm.dbg.declare etc
|
||||||
if (global.params.symdebug) DtoDwarfFuncStart(fd);
|
if (global.params.symdebug) DtoDwarfFuncStart(fd);
|
||||||
|
#endif
|
||||||
|
|
||||||
// this hack makes sure the frame pointer elimination optimization is disabled.
|
// this hack makes sure the frame pointer elimination optimization is disabled.
|
||||||
// this this eliminates a bunch of inline asm related issues.
|
// 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 = new IrLocal(fd->vthis);
|
||||||
fd->vthis->ir.irLocal->value = thismem;
|
fd->vthis->ir.irLocal->value = thismem;
|
||||||
|
|
||||||
|
#ifndef DISABLE_DEBUG_INFO
|
||||||
if (global.params.symdebug)
|
if (global.params.symdebug)
|
||||||
DtoDwarfLocalVariable(thismem, fd->vthis);
|
DtoDwarfLocalVariable(thismem, fd->vthis);
|
||||||
|
#endif
|
||||||
|
|
||||||
#if DMDV1
|
#if DMDV1
|
||||||
if (fd->vthis->nestedref)
|
if (fd->vthis->nestedref)
|
||||||
|
@ -722,8 +727,10 @@ void DtoDefineFunction(FuncDeclaration* fd)
|
||||||
irloc->value = mem;
|
irloc->value = mem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef DISABLE_DEBUG_INFO
|
||||||
if (global.params.symdebug && !(isaArgument(irloc->value) && !isaArgument(irloc->value)->hasByValAttr()) && !refout)
|
if (global.params.symdebug && !(isaArgument(irloc->value) && !isaArgument(irloc->value)->hasByValAttr()) && !refout)
|
||||||
DtoDwarfLocalVariable(irloc->value, vd);
|
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 = new IrLocal(fd->vresult);
|
||||||
fd->vresult->ir.irLocal->value = DtoAlloca(fd->vresult->type, fd->vresult->toChars());
|
fd->vresult->ir.irLocal->value = DtoAlloca(fd->vresult->type, fd->vresult->toChars());
|
||||||
}
|
}
|
||||||
|
|
||||||
// copy _argptr and _arguments to a memory location
|
// copy _argptr and _arguments to a memory location
|
||||||
if (f->linkage == LINKd && f->varargs == 1)
|
if (f->linkage == LINKd && f->varargs == 1)
|
||||||
{
|
{
|
||||||
|
@ -794,9 +801,11 @@ void DtoDefineFunction(FuncDeclaration* fd)
|
||||||
} else if (!gIR->scopereturned()) {
|
} else if (!gIR->scopereturned()) {
|
||||||
// llvm requires all basic blocks to end with a TerminatorInst but DMD does not put a return statement
|
// 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.
|
// in automatically, so we do it here.
|
||||||
|
|
||||||
// pass the previous block into this block
|
// pass the previous block into this block
|
||||||
|
#ifndef DISABLE_DEBUG_INFO
|
||||||
if (global.params.symdebug) DtoDwarfFuncEnd(fd);
|
if (global.params.symdebug) DtoDwarfFuncEnd(fd);
|
||||||
|
#endif
|
||||||
if (func->getReturnType() == LLType::getVoidTy(gIR->context())) {
|
if (func->getReturnType() == LLType::getVoidTy(gIR->context())) {
|
||||||
llvm::ReturnInst::Create(gIR->context(), gIR->scopebb());
|
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());
|
error("failed to create path to linking output: %s\n%s", exedir.c_str(), errstr.c_str());
|
||||||
fatal();
|
fatal();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// strip debug info
|
// strip debug info
|
||||||
if (!global.params.symdebug)
|
if (!global.params.symdebug)
|
||||||
|
@ -222,13 +222,13 @@ int linkObjToExecutable(const char* argv0)
|
||||||
// find gcc for linking
|
// find gcc for linking
|
||||||
llvm::sys::Path gcc = getGcc();
|
llvm::sys::Path gcc = getGcc();
|
||||||
// get a string version for argv[0]
|
// get a string version for argv[0]
|
||||||
std::string gccStr = gcc.toString();
|
const char* gccStr = gcc.c_str();
|
||||||
|
|
||||||
// build arguments
|
// build arguments
|
||||||
std::vector<const char*> args;
|
std::vector<const char*> args;
|
||||||
|
|
||||||
// first the program name ??
|
// first the program name ??
|
||||||
args.push_back(gccStr.c_str());
|
args.push_back(gccStr);
|
||||||
|
|
||||||
// object files
|
// object files
|
||||||
for (int i = 0; i < global.params.objfiles->dim; i++)
|
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());
|
error("failed to create path to linking output: %s\n%s", exedir.c_str(), errstr.c_str());
|
||||||
fatal();
|
fatal();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// additional linker switches
|
// additional linker switches
|
||||||
for (int i = 0; i < global.params.linkswitches->dim; i++)
|
for (int i = 0; i < global.params.linkswitches->dim; i++)
|
||||||
|
@ -292,7 +292,7 @@ int linkObjToExecutable(const char* argv0)
|
||||||
|
|
||||||
// default libs
|
// default libs
|
||||||
switch(global.params.os) {
|
switch(global.params.os) {
|
||||||
case OSLinux:
|
case OSLinux:
|
||||||
case OSMacOSX:
|
case OSMacOSX:
|
||||||
args.push_back("-ldl");
|
args.push_back("-ldl");
|
||||||
// fallthrough
|
// fallthrough
|
||||||
|
@ -330,12 +330,12 @@ int linkObjToExecutable(const char* argv0)
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger::println("Linking with: ");
|
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();
|
Stream logstr = Logger::cout();
|
||||||
for (; I != E; ++I)
|
for (; I != E; ++I)
|
||||||
if (*I)
|
if (*I)
|
||||||
logstr << "'" << *I << "'" << " ";
|
logstr << "'" << *I << "'" << " ";
|
||||||
logstr << "\n" << std::flush;
|
logstr << "\n"; // FIXME where's flush ?
|
||||||
|
|
||||||
|
|
||||||
// terminate args list
|
// terminate args list
|
||||||
|
@ -349,7 +349,7 @@ int linkObjToExecutable(const char* argv0)
|
||||||
error("message: %s", errstr.c_str());
|
error("message: %s", errstr.c_str());
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -375,7 +375,7 @@ int runExecutable()
|
||||||
// build arguments
|
// build arguments
|
||||||
std::vector<const char*> args;
|
std::vector<const char*> args;
|
||||||
// args[0] should be the name of the executable
|
// 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.
|
// Skip first argument to -run; it's a D source file.
|
||||||
for (size_t i = 1, length = opts::runargs.size(); i < length; i++)
|
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
|
// call
|
||||||
gIR->CreateCallOrInvoke(fn, args.begin(), args.end());
|
gIR->CreateCallOrInvoke(fn, args.begin(), args.end());
|
||||||
|
|
||||||
|
#ifndef DISABLE_DEBUG_INFO
|
||||||
// end debug info
|
// end debug info
|
||||||
if (global.params.symdebug)
|
if (global.params.symdebug)
|
||||||
DtoDwarfFuncEnd(gIR->func()->decl);
|
DtoDwarfFuncEnd(gIR->func()->decl);
|
||||||
|
#endif
|
||||||
|
|
||||||
// after assert is always unreachable
|
// after assert is always unreachable
|
||||||
gIR->ir->CreateUnreachable();
|
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
|
// 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
|
// 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)
|
if (lblstmt)
|
||||||
target = lblstmt->enclosingScopeExit;
|
target = lblstmt->enclosingScopeExit;
|
||||||
|
|
||||||
|
@ -485,7 +487,7 @@ DValue* DtoNullValue(Type* type)
|
||||||
}
|
}
|
||||||
|
|
||||||
// unknown
|
// unknown
|
||||||
llvm::cout << "unsupported: null value for " << type->toChars() << '\n';
|
error("unsupported: null value for %s", type->toChars());
|
||||||
assert(0);
|
assert(0);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
@ -854,6 +856,7 @@ void DtoConstInitGlobal(VarDeclaration* vd)
|
||||||
|
|
||||||
gvar->setInitializer(initVal);
|
gvar->setInitializer(initVal);
|
||||||
|
|
||||||
|
#ifndef DISABLE_DEBUG_INFO
|
||||||
// do debug info
|
// do debug info
|
||||||
if (global.params.symdebug)
|
if (global.params.symdebug)
|
||||||
{
|
{
|
||||||
|
@ -861,6 +864,7 @@ void DtoConstInitGlobal(VarDeclaration* vd)
|
||||||
// keep a reference so GDCE doesn't delete it !
|
// keep a reference so GDCE doesn't delete it !
|
||||||
gIR->usedArray.push_back(llvm::ConstantExpr::getBitCast(gv, getVoidPtrType()));
|
gIR->usedArray.push_back(llvm::ConstantExpr::getBitCast(gv, getVoidPtrType()));
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -906,11 +910,11 @@ DValue* DtoDeclarationExp(Dsymbol* declaration)
|
||||||
ExpInitializer* ex = vd->init->isExpInitializer();
|
ExpInitializer* ex = vd->init->isExpInitializer();
|
||||||
assert(ex && "ref vars must have expression initializer");
|
assert(ex && "ref vars must have expression initializer");
|
||||||
assert(ex->exp);
|
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");
|
assert(as && "ref vars must be initialized by an assign exp");
|
||||||
vd->ir.irLocal->value = as->e2->toElem(gIR)->getLVal();
|
vd->ir.irLocal->value = as->e2->toElem(gIR)->getLVal();
|
||||||
}
|
}
|
||||||
|
|
||||||
// referenced by nested delegate?
|
// referenced by nested delegate?
|
||||||
#if DMDV2
|
#if DMDV2
|
||||||
if (vd->nestedrefs.dim) {
|
if (vd->nestedrefs.dim) {
|
||||||
|
@ -919,7 +923,7 @@ DValue* DtoDeclarationExp(Dsymbol* declaration)
|
||||||
#endif
|
#endif
|
||||||
Logger::println("has nestedref set");
|
Logger::println("has nestedref set");
|
||||||
assert(vd->ir.irLocal);
|
assert(vd->ir.irLocal);
|
||||||
|
|
||||||
DtoNestedInit(vd);
|
DtoNestedInit(vd);
|
||||||
}
|
}
|
||||||
// normal stack variable, allocate storage on the stack if it has not already been done
|
// 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
|
//allocainst->setAlignment(vd->type->alignsize()); // TODO
|
||||||
vd->ir.irLocal->value = allocainst;
|
vd->ir.irLocal->value = allocainst;
|
||||||
|
|
||||||
|
#ifndef DISABLE_DEBUG_INFO
|
||||||
if (global.params.symdebug)
|
if (global.params.symdebug)
|
||||||
{
|
|
||||||
DtoDwarfLocalVariable(allocainst, vd);
|
DtoDwarfLocalVariable(allocainst, vd);
|
||||||
}
|
#endif
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -1046,18 +1050,20 @@ LLValue* DtoRawVarDeclaration(VarDeclaration* var, LLValue* addr)
|
||||||
|
|
||||||
// we don't handle aliases either
|
// we don't handle aliases either
|
||||||
assert(!var->aliassym);
|
assert(!var->aliassym);
|
||||||
|
|
||||||
// alloca if necessary
|
// alloca if necessary
|
||||||
LLValue* allocaval = NULL;
|
LLValue* allocaval = NULL;
|
||||||
if (!addr && (!var->ir.irLocal || !var->ir.irLocal->value))
|
if (!addr && (!var->ir.irLocal || !var->ir.irLocal->value))
|
||||||
{
|
{
|
||||||
addr = DtoAlloca(var->type, var->toChars());
|
addr = DtoAlloca(var->type, var->toChars());
|
||||||
|
|
||||||
|
#ifndef DISABLE_DEBUG_INFO
|
||||||
// add debug info
|
// add debug info
|
||||||
if (global.params.symdebug)
|
if (global.params.symdebug)
|
||||||
DtoDwarfLocalVariable(addr, var);
|
DtoDwarfLocalVariable(addr, var);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// referenced by nested function?
|
// referenced by nested function?
|
||||||
#if DMDV2
|
#if DMDV2
|
||||||
if (var->nestedrefs.dim)
|
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 instance: %s", ti->toChars());
|
||||||
Logger::println("template declaration: %s", td->toChars());
|
Logger::println("template declaration: %s", td->toChars());
|
||||||
Logger::println("intrinsic name: %s", td->intrinsicName.c_str());
|
Logger::println("intrinsic name: %s", td->intrinsicName.c_str());
|
||||||
|
|
||||||
// for now use the size in bits of the first template param in the instance
|
// for now use the size in bits of the first template param in the instance
|
||||||
assert(ti->tdtypes.dim == 1);
|
assert(ti->tdtypes.dim == 1);
|
||||||
Type* T = (Type*)ti->tdtypes.data[0];
|
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
|
char tmp[21]; // probably excessive, but covers a uint64_t
|
||||||
sprintf(tmp, "%lu", (unsigned long) gTargetData->getTypeSizeInBits(DtoType(T)));
|
sprintf(tmp, "%lu", (unsigned long) gTargetData->getTypeSizeInBits(DtoType(T)));
|
||||||
|
|
||||||
// replace # in name with bitsize
|
// replace # in name with bitsize
|
||||||
name = td->intrinsicName;
|
name = td->intrinsicName;
|
||||||
|
|
||||||
|
@ -1330,7 +1336,7 @@ void DtoOverloadedIntrinsicName(TemplateInstance* ti, TemplateDeclaration* td, s
|
||||||
fatal(); // or LLVM asserts
|
fatal(); // or LLVM asserts
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger::println("final intrinsic name: %s", name.c_str());
|
Logger::println("final intrinsic name: %s", name.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1340,7 +1346,7 @@ bool mustDefineSymbol(Dsymbol* s)
|
||||||
{
|
{
|
||||||
if (FuncDeclaration* fd = s->isFuncDeclaration())
|
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
|
// that weren't semantic3'ed
|
||||||
if (fd->semanticRun < 4)
|
if (fd->semanticRun < 4)
|
||||||
return false;
|
return false;
|
||||||
|
@ -1352,7 +1358,7 @@ bool mustDefineSymbol(Dsymbol* s)
|
||||||
// Emit extra functions if we're inlining.
|
// Emit extra functions if we're inlining.
|
||||||
// These will get available_externally linkage,
|
// These will get available_externally linkage,
|
||||||
// so they shouldn't end up in object code.
|
// so they shouldn't end up in object code.
|
||||||
|
|
||||||
assert(fd->type->ty == Tfunction);
|
assert(fd->type->ty == Tfunction);
|
||||||
TypeFunction* tf = (TypeFunction*) fd->type;
|
TypeFunction* tf = (TypeFunction*) fd->type;
|
||||||
// * If we define extra static constructors, static destructors
|
// * If we define extra static constructors, static destructors
|
||||||
|
@ -1371,7 +1377,7 @@ bool mustDefineSymbol(Dsymbol* s)
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// This was only semantic'ed for inlining checks.
|
// This was only semantic'ed for inlining checks.
|
||||||
// We won't be inlining this, so we only need to emit a declaration.
|
// We won't be inlining this, so we only need to emit a declaration.
|
||||||
return false;
|
return false;
|
||||||
|
@ -1396,7 +1402,7 @@ bool mustDefineSymbol(Dsymbol* s)
|
||||||
{
|
{
|
||||||
if (!opts::singleObj)
|
if (!opts::singleObj)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (!tinst->emittedInModule)
|
if (!tinst->emittedInModule)
|
||||||
{
|
{
|
||||||
gIR->seenTemplateInstances.insert(tinst);
|
gIR->seenTemplateInstances.insert(tinst);
|
||||||
|
@ -1404,7 +1410,7 @@ bool mustDefineSymbol(Dsymbol* s)
|
||||||
}
|
}
|
||||||
return tinst->emittedInModule == gIR->dmodule;
|
return tinst->emittedInModule == gIR->dmodule;
|
||||||
}
|
}
|
||||||
|
|
||||||
return s->getModule() == gIR->dmodule;
|
return s->getModule() == gIR->dmodule;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -156,7 +156,7 @@ LLValue* makeLValue(Loc& loc, DValue* value);
|
||||||
////////////////////////////////////////////
|
////////////////////////////////////////////
|
||||||
|
|
||||||
/// convert DMD calling conv to LLVM
|
/// convert DMD calling conv to LLVM
|
||||||
unsigned DtoCallingConv(Loc loc, LINK l);
|
llvm::CallingConv::ID DtoCallingConv(Loc loc, LINK l);
|
||||||
|
|
||||||
///
|
///
|
||||||
TypeFunction* DtoTypeFunction(DValue* fnval);
|
TypeFunction* DtoTypeFunction(DValue* fnval);
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
|
|
||||||
#include "llvm/GlobalValue.h"
|
#include "llvm/GlobalValue.h"
|
||||||
#include "llvm/Support/Casting.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 "llvm/Assembly/Writer.h"
|
||||||
|
|
||||||
#include "gen/logger.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.
|
// Constants don't always get their types pretty-printed.
|
||||||
// (Only treat non-global constants like this, so that e.g. global variables
|
// (Only treat non-global constants like this, so that e.g. global variables
|
||||||
// still get their initializers printed)
|
// still get their initializers printed)
|
||||||
|
llvm::raw_os_ostream raw(OS);
|
||||||
if (llvm::isa<llvm::Constant>(V) && !llvm::isa<llvm::GlobalValue>(V))
|
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
|
else
|
||||||
OS << V;
|
V.print(raw);
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace Logger
|
namespace Logger
|
||||||
|
|
22
gen/logger.h
22
gen/logger.h
|
@ -20,36 +20,38 @@ struct Loc;
|
||||||
|
|
||||||
class Stream {
|
class Stream {
|
||||||
std::ostream* OS;
|
std::ostream* OS;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Stream() : OS(0) {}
|
Stream() : OS(0) {}
|
||||||
Stream(std::ostream* S) : OS(S) {}
|
Stream(std::ostream* S) : OS(S) {}
|
||||||
Stream(std::ostream& S) : OS(&S) {}
|
Stream(std::ostream& S) : OS(&S) {}
|
||||||
|
|
||||||
|
/*
|
||||||
Stream operator << (std::ios_base &(*Func)(std::ios_base&)) {
|
Stream operator << (std::ios_base &(*Func)(std::ios_base&)) {
|
||||||
if (OS) *OS << Func;
|
if (OS) *OS << Func;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
Stream operator << (std::ostream &(*Func)(std::ostream&)) {
|
Stream operator << (std::ostream &(*Func)(std::ostream&)) {
|
||||||
if (OS) *OS << Func;
|
if (OS) Func(*OS);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Ty>
|
template<typename Ty>
|
||||||
Stream& operator << (const Ty& Thing) {
|
Stream& operator << (const Ty& Thing) {
|
||||||
if (OS)
|
if (OS)
|
||||||
Writer<Ty, sizeof(sfinae_bait(Thing))>::write(*OS, Thing);
|
Writer<Ty, sizeof(sfinae_bait(Thing))>::write(*OS, Thing);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Implementation details to treat llvm::Value, llvm::Type and their
|
// Implementation details to treat llvm::Value, llvm::Type and their
|
||||||
// subclasses specially (to pretty-print types).
|
// subclasses specially (to pretty-print types).
|
||||||
|
|
||||||
static void writeType(std::ostream& OS, const llvm::Type& Ty);
|
static void writeType(std::ostream& OS, const llvm::Type& Ty);
|
||||||
static void writeValue(std::ostream& OS, const llvm::Value& Ty);
|
static void writeValue(std::ostream& OS, const llvm::Value& Ty);
|
||||||
|
|
||||||
template<typename Ty, int N> friend struct Writer;
|
template<typename Ty, int N> friend struct Writer;
|
||||||
// error: function template partial specialization is not allowed
|
// error: function template partial specialization is not allowed
|
||||||
// So I guess type partial specialization + member function will have to do...
|
// So I guess type partial specialization + member function will have to do...
|
||||||
|
@ -59,7 +61,7 @@ private:
|
||||||
OS << Thing;
|
OS << Thing;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename Ty>
|
template<typename Ty>
|
||||||
struct Writer<Ty, 1> {
|
struct Writer<Ty, 1> {
|
||||||
static void write(std::ostream& OS, const llvm::Type& Thing) {
|
static void write(std::ostream& OS, const llvm::Type& Thing) {
|
||||||
|
@ -69,7 +71,7 @@ private:
|
||||||
Stream::writeValue(OS, Thing);
|
Stream::writeValue(OS, Thing);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// NOT IMPLEMENTED
|
// NOT IMPLEMENTED
|
||||||
char sfinae_bait(const llvm::Type&);
|
char sfinae_bait(const llvm::Type&);
|
||||||
char sfinae_bait(const llvm::Value&);
|
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.libfiles = new Array();
|
||||||
global.params.objfiles = new Array();
|
global.params.objfiles = new Array();
|
||||||
global.params.ddocfiles = new Array();
|
global.params.ddocfiles = new Array();
|
||||||
|
|
||||||
global.params.moduleDeps = NULL;
|
global.params.moduleDeps = NULL;
|
||||||
global.params.moduleDepsFile = NULL;
|
global.params.moduleDepsFile = NULL;
|
||||||
|
|
||||||
|
@ -223,12 +223,12 @@ int main(int argc, char** argv)
|
||||||
// String options: std::string --> char*
|
// String options: std::string --> char*
|
||||||
initFromString(global.params.objname, objectFile);
|
initFromString(global.params.objname, objectFile);
|
||||||
initFromString(global.params.objdir, objectDir);
|
initFromString(global.params.objdir, objectDir);
|
||||||
|
|
||||||
initFromString(global.params.docdir, ddocDir);
|
initFromString(global.params.docdir, ddocDir);
|
||||||
initFromString(global.params.docname, ddocFile);
|
initFromString(global.params.docname, ddocFile);
|
||||||
global.params.doDocComments |=
|
global.params.doDocComments |=
|
||||||
global.params.docdir || global.params.docname;
|
global.params.docdir || global.params.docname;
|
||||||
|
|
||||||
#ifdef _DH
|
#ifdef _DH
|
||||||
initFromString(global.params.hdrdir, hdrDir);
|
initFromString(global.params.hdrdir, hdrDir);
|
||||||
initFromString(global.params.hdrname, hdrFile);
|
initFromString(global.params.hdrname, hdrFile);
|
||||||
|
@ -237,9 +237,9 @@ int main(int argc, char** argv)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
initFromString(global.params.moduleDepsFile, moduleDepsFile);
|
initFromString(global.params.moduleDepsFile, moduleDepsFile);
|
||||||
if (global.params.moduleDepsFile != NULL)
|
if (global.params.moduleDepsFile != NULL)
|
||||||
{
|
{
|
||||||
global.params.moduleDeps = new OutBuffer;
|
global.params.moduleDeps = new OutBuffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
processVersions(debugArgs, "debug",
|
processVersions(debugArgs, "debug",
|
||||||
|
@ -435,7 +435,7 @@ int main(int argc, char** argv)
|
||||||
std::string triple = global.params.targetTriple;
|
std::string triple = global.params.targetTriple;
|
||||||
|
|
||||||
// Allocate target machine.
|
// Allocate target machine.
|
||||||
|
|
||||||
// first initialize llvm
|
// first initialize llvm
|
||||||
#define LLVM_TARGET(A) LLVMInitialize##A##TargetInfo(); LLVMInitialize##A##Target(); LLVMInitialize##A##AsmPrinter();
|
#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) ...
|
// this is defined to be LLVM_TARGET(target name 1) LLVM_TARGET(target name 2) ...
|
||||||
|
@ -484,10 +484,15 @@ LDC_TARGETS
|
||||||
FeaturesStr = Features.getString();
|
FeaturesStr = Features.getString();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::auto_ptr<llvm::TargetMachine> target(theTarget->createTargetMachine(triple, FeaturesStr));
|
// FIXME
|
||||||
assert(target.get() && "Could not allocate target machine!");
|
//std::auto_ptr<llvm::TargetMachine> target(theTarget->createTargetMachine(triple, FeaturesStr));
|
||||||
gTargetMachine = target.get();
|
//assert(target.get() && "Could not allocate target machine!");
|
||||||
gTargetData = gTargetMachine->getTargetData();
|
//gTargetMachine = target.get();
|
||||||
|
|
||||||
|
llvm::TargetMachine* target = theTarget->createTargetMachine(triple, FeaturesStr);
|
||||||
|
gTargetMachine = target;
|
||||||
|
|
||||||
|
gTargetData = target->getTargetData();
|
||||||
|
|
||||||
// get final data layout
|
// get final data layout
|
||||||
std::string datalayout = gTargetData->getStringRepresentation();
|
std::string datalayout = gTargetData->getStringRepresentation();
|
||||||
|
@ -903,12 +908,12 @@ LDC_TARGETS
|
||||||
fatal();
|
fatal();
|
||||||
|
|
||||||
// write module dependencies to file if requested
|
// write module dependencies to file if requested
|
||||||
if (global.params.moduleDepsFile != NULL)
|
if (global.params.moduleDepsFile != NULL)
|
||||||
{
|
{
|
||||||
assert (global.params.moduleDepsFile != NULL);
|
assert (global.params.moduleDepsFile != NULL);
|
||||||
|
|
||||||
File deps(global.params.moduleDepsFile);
|
File deps(global.params.moduleDepsFile);
|
||||||
OutBuffer* ob = global.params.moduleDeps;
|
OutBuffer* ob = global.params.moduleDeps;
|
||||||
deps.setbuffer((void*)ob->data, ob->offset);
|
deps.setbuffer((void*)ob->data, ob->offset);
|
||||||
deps.write();
|
deps.write();
|
||||||
}
|
}
|
||||||
|
@ -944,14 +949,14 @@ LDC_TARGETS
|
||||||
m->gendocfile();
|
m->gendocfile();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// internal linking for singleobj
|
// internal linking for singleobj
|
||||||
if (singleObj && llvmModules.size() > 0)
|
if (singleObj && llvmModules.size() > 0)
|
||||||
{
|
{
|
||||||
Module* m = (Module*)modules.data[0];
|
Module* m = (Module*)modules.data[0];
|
||||||
char* name = m->toChars();
|
char* name = m->toChars();
|
||||||
char* filename = m->objfile->name->str;
|
char* filename = m->objfile->name->str;
|
||||||
|
|
||||||
llvm::Linker linker(name, name, context);
|
llvm::Linker linker(name, name, context);
|
||||||
|
|
||||||
std::string errormsg;
|
std::string errormsg;
|
||||||
|
@ -961,12 +966,12 @@ LDC_TARGETS
|
||||||
error("%s", errormsg.c_str());
|
error("%s", errormsg.c_str());
|
||||||
delete llvmModules[i];
|
delete llvmModules[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
m->deleteObjFile();
|
m->deleteObjFile();
|
||||||
writeModule(linker.getModule(), filename);
|
writeModule(linker.getModule(), filename);
|
||||||
global.params.objfiles->push(filename);
|
global.params.objfiles->push(filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
backend_term();
|
backend_term();
|
||||||
if (global.errors)
|
if (global.errors)
|
||||||
fatal();
|
fatal();
|
||||||
|
|
|
@ -95,7 +95,7 @@ bool optimize() {
|
||||||
|
|
||||||
static void addPass(PassManager& pm, Pass* pass) {
|
static void addPass(PassManager& pm, Pass* pass) {
|
||||||
pm.add(pass);
|
pm.add(pass);
|
||||||
|
|
||||||
if (verifyEach) pm.add(createVerifierPass());
|
if (verifyEach) pm.add(createVerifierPass());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -107,7 +107,7 @@ static void addPassesForOptLevel(PassManager& pm) {
|
||||||
{
|
{
|
||||||
//addPass(pm, createStripDeadPrototypesPass());
|
//addPass(pm, createStripDeadPrototypesPass());
|
||||||
addPass(pm, createGlobalDCEPass());
|
addPass(pm, createGlobalDCEPass());
|
||||||
addPass(pm, createRaiseAllocationsPass());
|
addPass(pm, createPromoteMemoryToRegisterPass());
|
||||||
addPass(pm, createCFGSimplificationPass());
|
addPass(pm, createCFGSimplificationPass());
|
||||||
if (optimizeLevel == 1)
|
if (optimizeLevel == 1)
|
||||||
addPass(pm, createPromoteMemoryToRegisterPass());
|
addPass(pm, createPromoteMemoryToRegisterPass());
|
||||||
|
@ -165,7 +165,7 @@ static void addPassesForOptLevel(PassManager& pm) {
|
||||||
addPass(pm, createCFGSimplificationPass());
|
addPass(pm, createCFGSimplificationPass());
|
||||||
addPass(pm, createInstructionCombiningPass());
|
addPass(pm, createInstructionCombiningPass());
|
||||||
}
|
}
|
||||||
|
|
||||||
// -O3
|
// -O3
|
||||||
if (optimizeLevel >= 3)
|
if (optimizeLevel >= 3)
|
||||||
{
|
{
|
||||||
|
@ -177,7 +177,7 @@ static void addPassesForOptLevel(PassManager& pm) {
|
||||||
addPass(pm, createCFGSimplificationPass());
|
addPass(pm, createCFGSimplificationPass());
|
||||||
addPass(pm, createScalarReplAggregatesPass());
|
addPass(pm, createScalarReplAggregatesPass());
|
||||||
addPass(pm, createInstructionCombiningPass());
|
addPass(pm, createInstructionCombiningPass());
|
||||||
addPass(pm, createCondPropagationPass());
|
addPass(pm, createConstantPropagationPass());
|
||||||
|
|
||||||
addPass(pm, createReassociatePass());
|
addPass(pm, createReassociatePass());
|
||||||
addPass(pm, createLoopRotatePass());
|
addPass(pm, createLoopRotatePass());
|
||||||
|
@ -194,7 +194,7 @@ static void addPassesForOptLevel(PassManager& pm) {
|
||||||
addPass(pm, createSCCPPass());
|
addPass(pm, createSCCPPass());
|
||||||
|
|
||||||
addPass(pm, createInstructionCombiningPass());
|
addPass(pm, createInstructionCombiningPass());
|
||||||
addPass(pm, createCondPropagationPass());
|
addPass(pm, createConstantPropagationPass());
|
||||||
|
|
||||||
addPass(pm, createDeadStoreEliminationPass());
|
addPass(pm, createDeadStoreEliminationPass());
|
||||||
addPass(pm, createAggressiveDCEPass());
|
addPass(pm, createAggressiveDCEPass());
|
||||||
|
@ -220,9 +220,9 @@ bool ldc_optimize_module(llvm::Module* m)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
PassManager pm;
|
PassManager pm;
|
||||||
|
|
||||||
if (verifyEach) pm.add(createVerifierPass());
|
if (verifyEach) pm.add(createVerifierPass());
|
||||||
|
|
||||||
addPass(pm, new TargetData(m));
|
addPass(pm, new TargetData(m));
|
||||||
|
|
||||||
bool optimize = optimizeLevel != 0 || doInline();
|
bool optimize = optimizeLevel != 0 || doInline();
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
|
|
||||||
#include "Passes.h"
|
#include "Passes.h"
|
||||||
|
|
||||||
|
#include "llvm/Function.h"
|
||||||
#include "llvm/Pass.h"
|
#include "llvm/Pass.h"
|
||||||
#include "llvm/Intrinsics.h"
|
#include "llvm/Intrinsics.h"
|
||||||
#include "llvm/Support/IRBuilder.h"
|
#include "llvm/Support/IRBuilder.h"
|
||||||
|
@ -48,25 +49,25 @@ namespace {
|
||||||
const TargetData *TD;
|
const TargetData *TD;
|
||||||
AliasAnalysis *AA;
|
AliasAnalysis *AA;
|
||||||
LLVMContext *Context;
|
LLVMContext *Context;
|
||||||
|
|
||||||
/// CastToCStr - Return V if it is an i8*, otherwise cast it to i8*.
|
/// CastToCStr - Return V if it is an i8*, otherwise cast it to i8*.
|
||||||
Value *CastToCStr(Value *V, IRBuilder<> &B);
|
Value *CastToCStr(Value *V, IRBuilder<> &B);
|
||||||
|
|
||||||
/// EmitMemCpy - Emit a call to the memcpy function to the builder. This
|
/// 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.
|
/// 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);
|
unsigned Align, IRBuilder<> &B);
|
||||||
public:
|
public:
|
||||||
LibCallOptimization() { }
|
LibCallOptimization() { }
|
||||||
virtual ~LibCallOptimization() {}
|
virtual ~LibCallOptimization() {}
|
||||||
|
|
||||||
/// CallOptimizer - This pure virtual method is implemented by base classes to
|
/// CallOptimizer - This pure virtual method is implemented by base classes to
|
||||||
/// do various optimizations. If this returns null then no transformation was
|
/// 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
|
/// 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
|
/// deleted. If it returns something else, replace CI with the new value and
|
||||||
/// delete CI.
|
/// delete CI.
|
||||||
virtual Value *CallOptimizer(Function *Callee, CallInst *CI, IRBuilder<> &B)=0;
|
virtual Value *CallOptimizer(Function *Callee, CallInst *CI, IRBuilder<> &B)=0;
|
||||||
|
|
||||||
Value *OptimizeCall(CallInst *CI, bool& Changed, const TargetData &TD,
|
Value *OptimizeCall(CallInst *CI, bool& Changed, const TargetData &TD,
|
||||||
AliasAnalysis& AA, IRBuilder<> &B) {
|
AliasAnalysis& AA, IRBuilder<> &B) {
|
||||||
Caller = CI->getParent()->getParent();
|
Caller = CI->getParent()->getParent();
|
||||||
|
@ -116,27 +117,27 @@ struct VISIBILITY_HIDDEN ArraySetLengthOpt : public LibCallOptimization {
|
||||||
FT->getParamType(1) != FT->getParamType(2) ||
|
FT->getParamType(1) != FT->getParamType(2) ||
|
||||||
FT->getParamType(3) != FT->getReturnType())
|
FT->getParamType(3) != FT->getReturnType())
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
// Whether or not this allocates is irrelevant if the result isn't used.
|
// Whether or not this allocates is irrelevant if the result isn't used.
|
||||||
// Just delete if that's the case.
|
// Just delete if that's the case.
|
||||||
if (CI->use_empty())
|
if (CI->use_empty())
|
||||||
return CI;
|
return CI;
|
||||||
|
|
||||||
Value* NewLen = CI->getOperand(2);
|
Value* NewLen = CI->getOperand(2);
|
||||||
if (Constant* NewCst = dyn_cast<Constant>(NewLen)) {
|
if (Constant* NewCst = dyn_cast<Constant>(NewLen)) {
|
||||||
Value* Data = CI->getOperand(4);
|
Value* Data = CI->getOperand(4);
|
||||||
|
|
||||||
// For now, we just catch the simplest of cases.
|
// For now, we just catch the simplest of cases.
|
||||||
//
|
//
|
||||||
// TODO: Implement a more general way to compare old and new
|
// TODO: Implement a more general way to compare old and new
|
||||||
// lengths, to catch cases like "arr.length = arr.length - 1;"
|
// lengths, to catch cases like "arr.length = arr.length - 1;"
|
||||||
// (But beware of unsigned overflow! For example, we can't
|
// (But beware of unsigned overflow! For example, we can't
|
||||||
// safely transform that example if arr.length may be 0)
|
// safely transform that example if arr.length may be 0)
|
||||||
|
|
||||||
// Setting length to 0 never reallocates, so replace by data argument
|
// Setting length to 0 never reallocates, so replace by data argument
|
||||||
if (NewCst->isNullValue())
|
if (NewCst->isNullValue())
|
||||||
return Data;
|
return Data;
|
||||||
|
|
||||||
// If both lengths are constant integers, see if NewLen <= OldLen
|
// If both lengths are constant integers, see if NewLen <= OldLen
|
||||||
Value* OldLen = CI->getOperand(3);
|
Value* OldLen = CI->getOperand(3);
|
||||||
if (ConstantInt* OldInt = dyn_cast<ConstantInt>(OldLen))
|
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) ||
|
if (Callee->arg_size() != 3 || !isa<IntegerType>(RetTy) ||
|
||||||
FT->getParamType(1) != RetTy || FT->getParamType(2) != RetTy)
|
FT->getParamType(1) != RetTy || FT->getParamType(2) != RetTy)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
Value* OldLen = CI->getOperand(1);
|
Value* OldLen = CI->getOperand(1);
|
||||||
Value* OldSize = CI->getOperand(2);
|
Value* OldSize = CI->getOperand(2);
|
||||||
Value* NewSize = CI->getOperand(3);
|
Value* NewSize = CI->getOperand(3);
|
||||||
|
|
||||||
// If the old length was zero, always return zero.
|
// If the old length was zero, always return zero.
|
||||||
if (Constant* LenCst = dyn_cast<Constant>(OldLen))
|
if (Constant* LenCst = dyn_cast<Constant>(OldLen))
|
||||||
if (LenCst->isNullValue())
|
if (LenCst->isNullValue())
|
||||||
return OldLen;
|
return OldLen;
|
||||||
|
|
||||||
// Equal sizes are much faster to check for, so do so now.
|
// Equal sizes are much faster to check for, so do so now.
|
||||||
if (OldSize == NewSize)
|
if (OldSize == NewSize)
|
||||||
return OldLen;
|
return OldLen;
|
||||||
|
|
||||||
// If both sizes are constant integers, see if OldSize is a multiple of NewSize
|
// If both sizes are constant integers, see if OldSize is a multiple of NewSize
|
||||||
if (ConstantInt* OldInt = dyn_cast<ConstantInt>(OldSize))
|
if (ConstantInt* OldInt = dyn_cast<ConstantInt>(OldSize))
|
||||||
if (ConstantInt* NewInt = dyn_cast<ConstantInt>(NewSize)) {
|
if (ConstantInt* NewInt = dyn_cast<ConstantInt>(NewSize)) {
|
||||||
// Don't crash on NewSize == 0, even though it shouldn't happen.
|
// Don't crash on NewSize == 0, even though it shouldn't happen.
|
||||||
if (NewInt->isNullValue())
|
if (NewInt->isNullValue())
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
APInt Quot, Rem;
|
APInt Quot, Rem;
|
||||||
APInt::udivrem(OldInt->getValue(), NewInt->getValue(), Quot, Rem);
|
APInt::udivrem(OldInt->getValue(), NewInt->getValue(), Quot, Rem);
|
||||||
if (Rem == 0)
|
if (Rem == 0)
|
||||||
|
@ -195,7 +196,7 @@ struct VISIBILITY_HIDDEN AllocationOpt : public LibCallOptimization {
|
||||||
// the start of inlined member functions)
|
// the start of inlined member functions)
|
||||||
for (CallInst::use_iterator I = CI->use_begin(), E = CI->use_end() ; I != E;) {
|
for (CallInst::use_iterator I = CI->use_begin(), E = CI->use_end() ; I != E;) {
|
||||||
Instruction* User = cast<Instruction>(*I++);
|
Instruction* User = cast<Instruction>(*I++);
|
||||||
|
|
||||||
if (ICmpInst* Cmp = dyn_cast<ICmpInst>(User)) {
|
if (ICmpInst* Cmp = dyn_cast<ICmpInst>(User)) {
|
||||||
if (!Cmp->isEquality())
|
if (!Cmp->isEquality())
|
||||||
continue;
|
continue;
|
||||||
|
@ -215,7 +216,7 @@ struct VISIBILITY_HIDDEN AllocationOpt : public LibCallOptimization {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If it's not used (anymore), pre-emptively GC it.
|
// If it's not used (anymore), pre-emptively GC it.
|
||||||
if (CI->use_empty())
|
if (CI->use_empty())
|
||||||
return CI;
|
return CI;
|
||||||
|
@ -235,23 +236,23 @@ struct VISIBILITY_HIDDEN ArraySliceCopyOpt : public LibCallOptimization {
|
||||||
FT->getParamType(2) != VoidPtrTy ||
|
FT->getParamType(2) != VoidPtrTy ||
|
||||||
FT->getParamType(3) != FT->getParamType(1))
|
FT->getParamType(3) != FT->getParamType(1))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
Value* Size = CI->getOperand(2);
|
Value* Size = CI->getOperand(2);
|
||||||
|
|
||||||
// Check the lengths match
|
// Check the lengths match
|
||||||
if (CI->getOperand(4) != Size)
|
if (CI->getOperand(4) != Size)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
// Assume unknown size unless we have constant size (that fits in an uint)
|
// Assume unknown size unless we have constant size (that fits in an uint)
|
||||||
unsigned Sz = ~0U;
|
unsigned Sz = ~0U;
|
||||||
if (ConstantInt* Int = dyn_cast<ConstantInt>(Size))
|
if (ConstantInt* Int = dyn_cast<ConstantInt>(Size))
|
||||||
if (Int->getValue().isIntN(32))
|
if (Int->getValue().isIntN(32))
|
||||||
Sz = Int->getValue().getZExtValue();
|
Sz = Int->getValue().getZExtValue();
|
||||||
|
|
||||||
// Check if the pointers may alias
|
// Check if the pointers may alias
|
||||||
if (AA->alias(CI->getOperand(1), Sz, CI->getOperand(3), Sz))
|
if (AA->alias(CI->getOperand(1), Sz, CI->getOperand(3), Sz))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
// Equal length and the pointers definitely don't alias, so it's safe to
|
// Equal length and the pointers definitely don't alias, so it's safe to
|
||||||
// replace the call with memcpy
|
// replace the call with memcpy
|
||||||
return EmitMemCpy(CI->getOperand(1), CI->getOperand(3), Size, 0, B);
|
return EmitMemCpy(CI->getOperand(1), CI->getOperand(3), Size, 0, B);
|
||||||
|
@ -271,24 +272,24 @@ namespace {
|
||||||
///
|
///
|
||||||
class VISIBILITY_HIDDEN SimplifyDRuntimeCalls : public FunctionPass {
|
class VISIBILITY_HIDDEN SimplifyDRuntimeCalls : public FunctionPass {
|
||||||
StringMap<LibCallOptimization*> Optimizations;
|
StringMap<LibCallOptimization*> Optimizations;
|
||||||
|
|
||||||
// Array operations
|
// Array operations
|
||||||
ArraySetLengthOpt ArraySetLength;
|
ArraySetLengthOpt ArraySetLength;
|
||||||
ArrayCastLenOpt ArrayCastLen;
|
ArrayCastLenOpt ArrayCastLen;
|
||||||
ArraySliceCopyOpt ArraySliceCopy;
|
ArraySliceCopyOpt ArraySliceCopy;
|
||||||
|
|
||||||
// GC allocations
|
// GC allocations
|
||||||
AllocationOpt Allocation;
|
AllocationOpt Allocation;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static char ID; // Pass identification
|
static char ID; // Pass identification
|
||||||
SimplifyDRuntimeCalls() : FunctionPass(&ID) {}
|
SimplifyDRuntimeCalls() : FunctionPass(&ID) {}
|
||||||
|
|
||||||
void InitOptimizations();
|
void InitOptimizations();
|
||||||
bool runOnFunction(Function &F);
|
bool runOnFunction(Function &F);
|
||||||
|
|
||||||
bool runOnce(Function &F, const TargetData& TD, AliasAnalysis& AA);
|
bool runOnce(Function &F, const TargetData& TD, AliasAnalysis& AA);
|
||||||
|
|
||||||
virtual void getAnalysisUsage(AnalysisUsage &AU) const {
|
virtual void getAnalysisUsage(AnalysisUsage &AU) const {
|
||||||
AU.addRequired<TargetData>();
|
AU.addRequired<TargetData>();
|
||||||
AU.addRequired<AliasAnalysis>();
|
AU.addRequired<AliasAnalysis>();
|
||||||
|
@ -302,7 +303,7 @@ X("simplify-drtcalls", "Simplify calls to D runtime");
|
||||||
|
|
||||||
// Public interface to the pass.
|
// Public interface to the pass.
|
||||||
FunctionPass *createSimplifyDRuntimeCalls() {
|
FunctionPass *createSimplifyDRuntimeCalls() {
|
||||||
return new SimplifyDRuntimeCalls();
|
return new SimplifyDRuntimeCalls();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Optimizations - Populate the Optimizations map with all the optimizations
|
/// Optimizations - Populate the Optimizations map with all the optimizations
|
||||||
|
@ -313,7 +314,7 @@ void SimplifyDRuntimeCalls::InitOptimizations() {
|
||||||
Optimizations["_d_arraysetlengthiT"] = &ArraySetLength;
|
Optimizations["_d_arraysetlengthiT"] = &ArraySetLength;
|
||||||
Optimizations["_d_array_cast_len"] = &ArrayCastLen;
|
Optimizations["_d_array_cast_len"] = &ArrayCastLen;
|
||||||
Optimizations["_d_array_slice_copy"] = &ArraySliceCopy;
|
Optimizations["_d_array_slice_copy"] = &ArraySliceCopy;
|
||||||
|
|
||||||
/* Delete calls to runtime functions which aren't needed if their result is
|
/* 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
|
* unused. That comes down to functions that don't do anything but
|
||||||
* GC-allocate and initialize some memory.
|
* GC-allocate and initialize some memory.
|
||||||
|
@ -339,10 +340,10 @@ void SimplifyDRuntimeCalls::InitOptimizations() {
|
||||||
bool SimplifyDRuntimeCalls::runOnFunction(Function &F) {
|
bool SimplifyDRuntimeCalls::runOnFunction(Function &F) {
|
||||||
if (Optimizations.empty())
|
if (Optimizations.empty())
|
||||||
InitOptimizations();
|
InitOptimizations();
|
||||||
|
|
||||||
const TargetData &TD = getAnalysis<TargetData>();
|
const TargetData &TD = getAnalysis<TargetData>();
|
||||||
AliasAnalysis &AA = getAnalysis<AliasAnalysis>();
|
AliasAnalysis &AA = getAnalysis<AliasAnalysis>();
|
||||||
|
|
||||||
// Iterate to catch opportunities opened up by other optimizations,
|
// Iterate to catch opportunities opened up by other optimizations,
|
||||||
// such as calls that are only used as arguments to unused calls:
|
// 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
|
// 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);
|
Changed = runOnce(F, TD, AA);
|
||||||
EverChanged |= Changed;
|
EverChanged |= Changed;
|
||||||
} while (Changed);
|
} while (Changed);
|
||||||
|
|
||||||
return EverChanged;
|
return EverChanged;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -367,33 +368,33 @@ bool SimplifyDRuntimeCalls::runOnce(Function &F, const TargetData& TD, AliasAnal
|
||||||
// Ignore non-calls.
|
// Ignore non-calls.
|
||||||
CallInst *CI = dyn_cast<CallInst>(I++);
|
CallInst *CI = dyn_cast<CallInst>(I++);
|
||||||
if (!CI) continue;
|
if (!CI) continue;
|
||||||
|
|
||||||
// Ignore indirect calls and calls to non-external functions.
|
// Ignore indirect calls and calls to non-external functions.
|
||||||
Function *Callee = CI->getCalledFunction();
|
Function *Callee = CI->getCalledFunction();
|
||||||
if (Callee == 0 || !Callee->isDeclaration() ||
|
if (Callee == 0 || !Callee->isDeclaration() ||
|
||||||
!(Callee->hasExternalLinkage() || Callee->hasDLLImportLinkage()))
|
!(Callee->hasExternalLinkage() || Callee->hasDLLImportLinkage()))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// Ignore unknown calls.
|
// Ignore unknown calls.
|
||||||
StringMap<LibCallOptimization*>::iterator OMI =
|
StringMap<LibCallOptimization*>::iterator OMI =
|
||||||
Optimizations.find(Callee->getName());
|
Optimizations.find(Callee->getName());
|
||||||
if (OMI == Optimizations.end()) continue;
|
if (OMI == Optimizations.end()) continue;
|
||||||
|
|
||||||
DEBUG(errs() << "SimplifyDRuntimeCalls inspecting: " << *CI);
|
DEBUG(errs() << "SimplifyDRuntimeCalls inspecting: " << *CI);
|
||||||
|
|
||||||
// Set the builder to the instruction after the call.
|
// Set the builder to the instruction after the call.
|
||||||
Builder.SetInsertPoint(BB, I);
|
Builder.SetInsertPoint(BB, I);
|
||||||
|
|
||||||
// Try to optimize this call.
|
// Try to optimize this call.
|
||||||
Value *Result = OMI->second->OptimizeCall(CI, Changed, TD, AA, Builder);
|
Value *Result = OMI->second->OptimizeCall(CI, Changed, TD, AA, Builder);
|
||||||
if (Result == 0) continue;
|
if (Result == 0) continue;
|
||||||
|
|
||||||
DEBUG(errs() << "SimplifyDRuntimeCalls simplified: " << *CI;
|
DEBUG(errs() << "SimplifyDRuntimeCalls simplified: " << *CI;
|
||||||
errs() << " into: " << *Result << "\n");
|
errs() << " into: " << *Result << "\n");
|
||||||
|
|
||||||
// Something changed!
|
// Something changed!
|
||||||
Changed = true;
|
Changed = true;
|
||||||
|
|
||||||
if (Result == CI) {
|
if (Result == CI) {
|
||||||
assert(CI->use_empty());
|
assert(CI->use_empty());
|
||||||
++NumDeleted;
|
++NumDeleted;
|
||||||
|
@ -401,18 +402,18 @@ bool SimplifyDRuntimeCalls::runOnce(Function &F, const TargetData& TD, AliasAnal
|
||||||
} else {
|
} else {
|
||||||
++NumSimplified;
|
++NumSimplified;
|
||||||
AA.replaceWithNewValue(CI, Result);
|
AA.replaceWithNewValue(CI, Result);
|
||||||
|
|
||||||
if (!CI->use_empty())
|
if (!CI->use_empty())
|
||||||
CI->replaceAllUsesWith(Result);
|
CI->replaceAllUsesWith(Result);
|
||||||
|
|
||||||
if (!Result->hasName())
|
if (!Result->hasName())
|
||||||
Result->takeName(CI);
|
Result->takeName(CI);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Inspect the instruction after the call (which was potentially just
|
// Inspect the instruction after the call (which was potentially just
|
||||||
// added) next.
|
// added) next.
|
||||||
I = CI; ++I;
|
I = CI; ++I;
|
||||||
|
|
||||||
CI->eraseFromParent();
|
CI->eraseFromParent();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,9 +53,11 @@ void ReturnStatement::toIR(IRState* p)
|
||||||
Logger::println("ReturnStatement::toIR(): %s", loc.toChars());
|
Logger::println("ReturnStatement::toIR(): %s", loc.toChars());
|
||||||
LOG_SCOPE;
|
LOG_SCOPE;
|
||||||
|
|
||||||
|
#ifndef DISABLE_DEBUG_INFO
|
||||||
if (global.params.symdebug)
|
if (global.params.symdebug)
|
||||||
DtoDwarfStopPoint(loc.linnum);
|
DtoDwarfStopPoint(loc.linnum);
|
||||||
|
#endif
|
||||||
|
|
||||||
// is there a return value expression?
|
// is there a return value expression?
|
||||||
if (exp || (!exp && (p->topfunc() == p->mainFunc)) )
|
if (exp || (!exp && (p->topfunc() == p->mainFunc)) )
|
||||||
{
|
{
|
||||||
|
@ -78,8 +80,10 @@ void ReturnStatement::toIR(IRState* p)
|
||||||
// emit scopes
|
// emit scopes
|
||||||
DtoEnclosingHandlers(loc, NULL);
|
DtoEnclosingHandlers(loc, NULL);
|
||||||
|
|
||||||
|
#ifndef DISABLE_DEBUG_INFO
|
||||||
// emit dbg end function
|
// emit dbg end function
|
||||||
if (global.params.symdebug) DtoDwarfFuncEnd(f->decl);
|
if (global.params.symdebug) DtoDwarfFuncEnd(f->decl);
|
||||||
|
#endif
|
||||||
|
|
||||||
// emit ret
|
// emit ret
|
||||||
llvm::ReturnInst::Create(gIR->context(), p->scopebb());
|
llvm::ReturnInst::Create(gIR->context(), p->scopebb());
|
||||||
|
@ -126,7 +130,9 @@ void ReturnStatement::toIR(IRState* p)
|
||||||
|
|
||||||
DtoEnclosingHandlers(loc, NULL);
|
DtoEnclosingHandlers(loc, NULL);
|
||||||
|
|
||||||
|
#ifndef DISABLE_DEBUG_INFO
|
||||||
if (global.params.symdebug) DtoDwarfFuncEnd(p->func()->decl);
|
if (global.params.symdebug) DtoDwarfFuncEnd(p->func()->decl);
|
||||||
|
#endif
|
||||||
llvm::ReturnInst::Create(gIR->context(), v, p->scopebb());
|
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()));
|
assert(p->topfunc()->getReturnType() == LLType::getVoidTy(gIR->context()));
|
||||||
DtoEnclosingHandlers(loc, NULL);
|
DtoEnclosingHandlers(loc, NULL);
|
||||||
|
|
||||||
|
#ifndef DISABLE_DEBUG_INFO
|
||||||
if (global.params.symdebug) DtoDwarfFuncEnd(p->func()->decl);
|
if (global.params.symdebug) DtoDwarfFuncEnd(p->func()->decl);
|
||||||
|
#endif
|
||||||
llvm::ReturnInst::Create(gIR->context(), p->scopebb());
|
llvm::ReturnInst::Create(gIR->context(), p->scopebb());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -153,8 +161,10 @@ void ExpStatement::toIR(IRState* p)
|
||||||
Logger::println("ExpStatement::toIR(): %s", loc.toChars());
|
Logger::println("ExpStatement::toIR(): %s", loc.toChars());
|
||||||
LOG_SCOPE;
|
LOG_SCOPE;
|
||||||
|
|
||||||
|
#ifndef DISABLE_DEBUG_INFO
|
||||||
if (global.params.symdebug)
|
if (global.params.symdebug)
|
||||||
DtoDwarfStopPoint(loc.linnum);
|
DtoDwarfStopPoint(loc.linnum);
|
||||||
|
#endif
|
||||||
|
|
||||||
if (exp) {
|
if (exp) {
|
||||||
if (global.params.llvmAnnotate)
|
if (global.params.llvmAnnotate)
|
||||||
|
@ -182,8 +192,10 @@ void IfStatement::toIR(IRState* p)
|
||||||
Logger::println("IfStatement::toIR(): %s", loc.toChars());
|
Logger::println("IfStatement::toIR(): %s", loc.toChars());
|
||||||
LOG_SCOPE;
|
LOG_SCOPE;
|
||||||
|
|
||||||
|
#ifndef DISABLE_DEBUG_INFO
|
||||||
if (global.params.symdebug)
|
if (global.params.symdebug)
|
||||||
DtoDwarfStopPoint(loc.linnum);
|
DtoDwarfStopPoint(loc.linnum);
|
||||||
|
#endif
|
||||||
|
|
||||||
if (match)
|
if (match)
|
||||||
DtoRawVarDeclaration(match);
|
DtoRawVarDeclaration(match);
|
||||||
|
@ -270,8 +282,10 @@ void WhileStatement::toIR(IRState* p)
|
||||||
Logger::println("WhileStatement::toIR(): %s", loc.toChars());
|
Logger::println("WhileStatement::toIR(): %s", loc.toChars());
|
||||||
LOG_SCOPE;
|
LOG_SCOPE;
|
||||||
|
|
||||||
|
#ifndef DISABLE_DEBUG_INFO
|
||||||
if (global.params.symdebug)
|
if (global.params.symdebug)
|
||||||
DtoDwarfStopPoint(loc.linnum);
|
DtoDwarfStopPoint(loc.linnum);
|
||||||
|
#endif
|
||||||
|
|
||||||
// create while blocks
|
// create while blocks
|
||||||
llvm::BasicBlock* oldend = gIR->scopeend();
|
llvm::BasicBlock* oldend = gIR->scopeend();
|
||||||
|
@ -318,8 +332,10 @@ void DoStatement::toIR(IRState* p)
|
||||||
Logger::println("DoStatement::toIR(): %s", loc.toChars());
|
Logger::println("DoStatement::toIR(): %s", loc.toChars());
|
||||||
LOG_SCOPE;
|
LOG_SCOPE;
|
||||||
|
|
||||||
|
#ifndef DISABLE_DEBUG_INFO
|
||||||
if (global.params.symdebug)
|
if (global.params.symdebug)
|
||||||
DtoDwarfStopPoint(loc.linnum);
|
DtoDwarfStopPoint(loc.linnum);
|
||||||
|
#endif
|
||||||
|
|
||||||
// create while blocks
|
// create while blocks
|
||||||
llvm::BasicBlock* oldend = gIR->scopeend();
|
llvm::BasicBlock* oldend = gIR->scopeend();
|
||||||
|
@ -363,8 +379,10 @@ void ForStatement::toIR(IRState* p)
|
||||||
Logger::println("ForStatement::toIR(): %s", loc.toChars());
|
Logger::println("ForStatement::toIR(): %s", loc.toChars());
|
||||||
LOG_SCOPE;
|
LOG_SCOPE;
|
||||||
|
|
||||||
|
#ifndef DISABLE_DEBUG_INFO
|
||||||
if (global.params.symdebug)
|
if (global.params.symdebug)
|
||||||
DtoDwarfStopPoint(loc.linnum);
|
DtoDwarfStopPoint(loc.linnum);
|
||||||
|
#endif
|
||||||
|
|
||||||
// create for blocks
|
// create for blocks
|
||||||
llvm::BasicBlock* oldend = gIR->scopeend();
|
llvm::BasicBlock* oldend = gIR->scopeend();
|
||||||
|
@ -443,8 +461,10 @@ void BreakStatement::toIR(IRState* p)
|
||||||
if (p->scopereturned())
|
if (p->scopereturned())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
#ifndef DISABLE_DEBUG_INFO
|
||||||
if (global.params.symdebug)
|
if (global.params.symdebug)
|
||||||
DtoDwarfStopPoint(loc.linnum);
|
DtoDwarfStopPoint(loc.linnum);
|
||||||
|
#endif
|
||||||
|
|
||||||
if (ident != 0) {
|
if (ident != 0) {
|
||||||
Logger::println("ident = %s", ident->toChars());
|
Logger::println("ident = %s", ident->toChars());
|
||||||
|
@ -498,8 +518,10 @@ void ContinueStatement::toIR(IRState* p)
|
||||||
Logger::println("ContinueStatement::toIR(): %s", loc.toChars());
|
Logger::println("ContinueStatement::toIR(): %s", loc.toChars());
|
||||||
LOG_SCOPE;
|
LOG_SCOPE;
|
||||||
|
|
||||||
|
#ifndef DISABLE_DEBUG_INFO
|
||||||
if (global.params.symdebug)
|
if (global.params.symdebug)
|
||||||
DtoDwarfStopPoint(loc.linnum);
|
DtoDwarfStopPoint(loc.linnum);
|
||||||
|
#endif
|
||||||
|
|
||||||
if (ident != 0) {
|
if (ident != 0) {
|
||||||
Logger::println("ident = %s", ident->toChars());
|
Logger::println("ident = %s", ident->toChars());
|
||||||
|
@ -564,8 +586,10 @@ void TryFinallyStatement::toIR(IRState* p)
|
||||||
Logger::println("TryFinallyStatement::toIR(): %s", loc.toChars());
|
Logger::println("TryFinallyStatement::toIR(): %s", loc.toChars());
|
||||||
LOG_SCOPE;
|
LOG_SCOPE;
|
||||||
|
|
||||||
|
#ifndef DISABLE_DEBUG_INFO
|
||||||
if (global.params.symdebug)
|
if (global.params.symdebug)
|
||||||
DtoDwarfStopPoint(loc.linnum);
|
DtoDwarfStopPoint(loc.linnum);
|
||||||
|
#endif
|
||||||
|
|
||||||
// if there's no finalbody or no body, things are simple
|
// if there's no finalbody or no body, things are simple
|
||||||
if (!finalbody) {
|
if (!finalbody) {
|
||||||
|
@ -642,8 +666,10 @@ void TryCatchStatement::toIR(IRState* p)
|
||||||
Logger::println("TryCatchStatement::toIR(): %s", loc.toChars());
|
Logger::println("TryCatchStatement::toIR(): %s", loc.toChars());
|
||||||
LOG_SCOPE;
|
LOG_SCOPE;
|
||||||
|
|
||||||
|
#ifndef DISABLE_DEBUG_INFO
|
||||||
if (global.params.symdebug)
|
if (global.params.symdebug)
|
||||||
DtoDwarfStopPoint(loc.linnum);
|
DtoDwarfStopPoint(loc.linnum);
|
||||||
|
#endif
|
||||||
|
|
||||||
// create basic blocks
|
// create basic blocks
|
||||||
llvm::BasicBlock* oldend = p->scopeend();
|
llvm::BasicBlock* oldend = p->scopeend();
|
||||||
|
@ -698,13 +724,17 @@ void ThrowStatement::toIR(IRState* p)
|
||||||
Logger::println("ThrowStatement::toIR(): %s", loc.toChars());
|
Logger::println("ThrowStatement::toIR(): %s", loc.toChars());
|
||||||
LOG_SCOPE;
|
LOG_SCOPE;
|
||||||
|
|
||||||
|
#ifndef DISABLE_DEBUG_INFO
|
||||||
if (global.params.symdebug)
|
if (global.params.symdebug)
|
||||||
DtoDwarfStopPoint(loc.linnum);
|
DtoDwarfStopPoint(loc.linnum);
|
||||||
|
#endif
|
||||||
|
|
||||||
assert(exp);
|
assert(exp);
|
||||||
DValue* e = exp->toElem(p);
|
DValue* e = exp->toElem(p);
|
||||||
|
|
||||||
|
#ifndef DISABLE_DEBUG_INFO
|
||||||
if (global.params.symdebug) DtoDwarfFuncEnd(gIR->func()->decl);
|
if (global.params.symdebug) DtoDwarfFuncEnd(gIR->func()->decl);
|
||||||
|
#endif
|
||||||
|
|
||||||
llvm::Function* fn = LLVM_D_GetRuntimeFunction(gIR->module, "_d_throw_exception");
|
llvm::Function* fn = LLVM_D_GetRuntimeFunction(gIR->module, "_d_throw_exception");
|
||||||
//Logger::cout() << "calling: " << *fn << '\n';
|
//Logger::cout() << "calling: " << *fn << '\n';
|
||||||
|
@ -780,8 +810,10 @@ void SwitchStatement::toIR(IRState* p)
|
||||||
Logger::println("SwitchStatement::toIR(): %s", loc.toChars());
|
Logger::println("SwitchStatement::toIR(): %s", loc.toChars());
|
||||||
LOG_SCOPE;
|
LOG_SCOPE;
|
||||||
|
|
||||||
|
#ifndef DISABLE_DEBUG_INFO
|
||||||
if (global.params.symdebug)
|
if (global.params.symdebug)
|
||||||
DtoDwarfStopPoint(loc.linnum);
|
DtoDwarfStopPoint(loc.linnum);
|
||||||
|
#endif
|
||||||
|
|
||||||
llvm::BasicBlock* oldend = gIR->scopeend();
|
llvm::BasicBlock* oldend = gIR->scopeend();
|
||||||
|
|
||||||
|
@ -951,8 +983,10 @@ void UnrolledLoopStatement::toIR(IRState* p)
|
||||||
if (!statements || !statements->dim)
|
if (!statements || !statements->dim)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
#ifndef DISABLE_DEBUG_INFO
|
||||||
if (global.params.symdebug)
|
if (global.params.symdebug)
|
||||||
DtoDwarfStopPoint(loc.linnum);
|
DtoDwarfStopPoint(loc.linnum);
|
||||||
|
#endif
|
||||||
|
|
||||||
// DMD doesn't fold stuff like continue/break, and since this isn't really a loop
|
// 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
|
// 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());
|
Logger::println("ForeachStatement::toIR(): %s", loc.toChars());
|
||||||
LOG_SCOPE;
|
LOG_SCOPE;
|
||||||
|
|
||||||
|
#ifndef DISABLE_DEBUG_INFO
|
||||||
if (global.params.symdebug)
|
if (global.params.symdebug)
|
||||||
DtoDwarfStopPoint(loc.linnum);
|
DtoDwarfStopPoint(loc.linnum);
|
||||||
|
#endif
|
||||||
|
|
||||||
//assert(arguments->dim == 1);
|
//assert(arguments->dim == 1);
|
||||||
assert(value != 0);
|
assert(value != 0);
|
||||||
|
@ -1149,8 +1185,10 @@ void ForeachRangeStatement::toIR(IRState* p)
|
||||||
Logger::println("ForeachRangeStatement::toIR(): %s", loc.toChars());
|
Logger::println("ForeachRangeStatement::toIR(): %s", loc.toChars());
|
||||||
LOG_SCOPE;
|
LOG_SCOPE;
|
||||||
|
|
||||||
|
#ifndef DISABLE_DEBUG_INFO
|
||||||
if (global.params.symdebug)
|
if (global.params.symdebug)
|
||||||
DtoDwarfStopPoint(loc.linnum);
|
DtoDwarfStopPoint(loc.linnum);
|
||||||
|
#endif
|
||||||
|
|
||||||
// evaluate lwr/upr
|
// evaluate lwr/upr
|
||||||
assert(lwr->type->isintegral());
|
assert(lwr->type->isintegral());
|
||||||
|
@ -1298,8 +1336,10 @@ void GotoStatement::toIR(IRState* p)
|
||||||
Logger::println("GotoStatement::toIR(): %s", loc.toChars());
|
Logger::println("GotoStatement::toIR(): %s", loc.toChars());
|
||||||
LOG_SCOPE;
|
LOG_SCOPE;
|
||||||
|
|
||||||
|
#ifndef DISABLE_DEBUG_INFO
|
||||||
if (global.params.symdebug)
|
if (global.params.symdebug)
|
||||||
DtoDwarfStopPoint(loc.linnum);
|
DtoDwarfStopPoint(loc.linnum);
|
||||||
|
#endif
|
||||||
|
|
||||||
llvm::BasicBlock* oldend = gIR->scopeend();
|
llvm::BasicBlock* oldend = gIR->scopeend();
|
||||||
llvm::BasicBlock* bb = llvm::BasicBlock::Create(gIR->context(), "aftergoto", p->topfunc(), oldend);
|
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());
|
Logger::println("GotoDefaultStatement::toIR(): %s", loc.toChars());
|
||||||
LOG_SCOPE;
|
LOG_SCOPE;
|
||||||
|
|
||||||
|
#ifndef DISABLE_DEBUG_INFO
|
||||||
if (global.params.symdebug)
|
if (global.params.symdebug)
|
||||||
DtoDwarfStopPoint(loc.linnum);
|
DtoDwarfStopPoint(loc.linnum);
|
||||||
|
#endif
|
||||||
|
|
||||||
llvm::BasicBlock* oldend = gIR->scopeend();
|
llvm::BasicBlock* oldend = gIR->scopeend();
|
||||||
llvm::BasicBlock* bb = llvm::BasicBlock::Create(gIR->context(), "aftergotodefault", p->topfunc(), oldend);
|
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());
|
Logger::println("GotoCaseStatement::toIR(): %s", loc.toChars());
|
||||||
LOG_SCOPE;
|
LOG_SCOPE;
|
||||||
|
|
||||||
|
#ifndef DISABLE_DEBUG_INFO
|
||||||
if (global.params.symdebug)
|
if (global.params.symdebug)
|
||||||
DtoDwarfStopPoint(loc.linnum);
|
DtoDwarfStopPoint(loc.linnum);
|
||||||
|
#endif
|
||||||
|
|
||||||
llvm::BasicBlock* oldend = gIR->scopeend();
|
llvm::BasicBlock* oldend = gIR->scopeend();
|
||||||
llvm::BasicBlock* bb = llvm::BasicBlock::Create(gIR->context(), "aftergotocase", p->topfunc(), oldend);
|
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());
|
Logger::println("WithStatement::toIR(): %s", loc.toChars());
|
||||||
LOG_SCOPE;
|
LOG_SCOPE;
|
||||||
|
|
||||||
|
#ifndef DISABLE_DEBUG_INFO
|
||||||
if (global.params.symdebug)
|
if (global.params.symdebug)
|
||||||
DtoDwarfStopPoint(loc.linnum);
|
DtoDwarfStopPoint(loc.linnum);
|
||||||
|
#endif
|
||||||
|
|
||||||
assert(exp);
|
assert(exp);
|
||||||
assert(body);
|
assert(body);
|
||||||
|
@ -1393,8 +1439,10 @@ void SynchronizedStatement::toIR(IRState* p)
|
||||||
Logger::println("SynchronizedStatement::toIR(): %s", loc.toChars());
|
Logger::println("SynchronizedStatement::toIR(): %s", loc.toChars());
|
||||||
LOG_SCOPE;
|
LOG_SCOPE;
|
||||||
|
|
||||||
|
#ifndef DISABLE_DEBUG_INFO
|
||||||
if (global.params.symdebug)
|
if (global.params.symdebug)
|
||||||
DtoDwarfStopPoint(loc.linnum);
|
DtoDwarfStopPoint(loc.linnum);
|
||||||
|
#endif
|
||||||
|
|
||||||
// enter lock
|
// enter lock
|
||||||
if (exp)
|
if (exp)
|
||||||
|
@ -1430,8 +1478,10 @@ void VolatileStatement::toIR(IRState* p)
|
||||||
Logger::println("VolatileStatement::toIR(): %s", loc.toChars());
|
Logger::println("VolatileStatement::toIR(): %s", loc.toChars());
|
||||||
LOG_SCOPE;
|
LOG_SCOPE;
|
||||||
|
|
||||||
|
#ifndef DISABLE_DEBUG_INFO
|
||||||
if (global.params.symdebug)
|
if (global.params.symdebug)
|
||||||
DtoDwarfStopPoint(loc.linnum);
|
DtoDwarfStopPoint(loc.linnum);
|
||||||
|
#endif
|
||||||
|
|
||||||
// mark in-volatile
|
// mark in-volatile
|
||||||
// FIXME
|
// 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)
|
if (l == LINKc || l == LINKcpp || l == LINKintrinsic)
|
||||||
return llvm::CallingConv::C;
|
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(DtoConstSize_t(vtype->getNumElements()));
|
||||||
pinits.push_back(llvm::ConstantExpr::getBitCast(typeinfomem, getPtrToType(typeinfotype)));
|
pinits.push_back(llvm::ConstantExpr::getBitCast(typeinfomem, getPtrToType(typeinfotype)));
|
||||||
const LLType* tiarrty = DtoType(Type::typeinfo->type->arrayOf());
|
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,
|
LLValue* typeinfoarrayparam = new llvm::GlobalVariable(*gIR->module, tiarrty,
|
||||||
true, llvm::GlobalValue::InternalLinkage, tiinits, "._arguments.array");
|
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 nestedcall = tf->fty.arg_nest;
|
||||||
bool dvarargs = (tf->linkage == LINKd && tf->varargs == 1);
|
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
|
// get callee llvm value
|
||||||
LLValue* callable = DtoCallableValue(fnval);
|
LLValue* callable = DtoCallableValue(fnval);
|
||||||
|
|
|
@ -19,6 +19,8 @@
|
||||||
|
|
||||||
using namespace llvm::dwarf;
|
using namespace llvm::dwarf;
|
||||||
|
|
||||||
|
#ifndef DISABLE_DEBUG_INFO
|
||||||
|
|
||||||
#define DBG_NULL ( LLConstant::getNullValue(DBG_TYPE) )
|
#define DBG_NULL ( LLConstant::getNullValue(DBG_TYPE) )
|
||||||
#define DBG_TYPE ( getPtrToType(llvm::StructType::get(gIR->context(),NULL,NULL)) )
|
#define DBG_TYPE ( getPtrToType(llvm::StructType::get(gIR->context(),NULL,NULL)) )
|
||||||
#define DBG_CAST(X) ( llvm::ConstantExpr::getBitCast(X, DBG_TYPE) )
|
#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.
|
// handle recursive types properly.
|
||||||
static llvm::DICompositeType dwarfCompositeType(Type* type, llvm::DICompileUnit compileUnit)
|
static llvm::DICompositeType dwarfCompositeType(Type* type, llvm::DICompileUnit compileUnit)
|
||||||
{
|
{
|
||||||
|
@ -530,7 +532,7 @@ llvm::DICompileUnit DtoDwarfCompileUnit(Module* m)
|
||||||
false, // isMain,
|
false, // isMain,
|
||||||
false // isOptimized
|
false // isOptimized
|
||||||
);
|
);
|
||||||
|
|
||||||
// if the linkage stays internal, we can't llvm-link the generated modules together:
|
// 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
|
// llvm's DwarfWriter uses path and filename to determine the symbol name and we'd
|
||||||
// end up with duplicate symbols
|
// end up with duplicate symbols
|
||||||
|
@ -636,3 +638,5 @@ void DtoDwarfStopPoint(unsigned ln)
|
||||||
gIR->scopebb()
|
gIR->scopebb()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
#ifndef LDC_GEN_TODEBUG_H
|
#ifndef LDC_GEN_TODEBUG_H
|
||||||
#define LDC_GEN_TODEBUG_H
|
#define LDC_GEN_TODEBUG_H
|
||||||
|
|
||||||
|
#ifndef DISABLE_DEBUG_INFO
|
||||||
|
|
||||||
void RegisterDwarfSymbols(llvm::Module* mod);
|
void RegisterDwarfSymbols(llvm::Module* mod);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -19,7 +21,7 @@ llvm::DISubprogram DtoDwarfSubProgram(FuncDeclaration* fd);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Emit the Dwarf subprogram global for a internal function.
|
* 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.
|
* module ctors/dtors and unittests.
|
||||||
* @return the Dwarf subprogram global.
|
* @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.
|
* Emits all things necessary for making debug info for a global variable vd.
|
||||||
* @param ll
|
* @param ll
|
||||||
* @param vd
|
* @param vd
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
llvm::DIGlobalVariable DtoDwarfGlobalVariable(LLGlobalVariable* ll, VarDeclaration* vd);
|
llvm::DIGlobalVariable DtoDwarfGlobalVariable(LLGlobalVariable* ll, VarDeclaration* vd);
|
||||||
|
|
||||||
|
#endif // DISABLE_DEBUG_INFO
|
||||||
|
|
||||||
#endif // LDC_GEN_TODEBUG_H
|
#endif // LDC_GEN_TODEBUG_H
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -157,7 +157,7 @@ const LLType* DtoType(Type* t)
|
||||||
return getVoidPtrType();
|
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, ...)
|
VarDecls for the fields (u -> _u_field_0, ...)
|
||||||
|
|
||||||
case Ttuple:
|
case Ttuple:
|
||||||
|
@ -289,12 +289,12 @@ LLGlobalValue::LinkageTypes DtoLinkage(Dsymbol* sym)
|
||||||
{
|
{
|
||||||
assert(0 && "not global/function");
|
assert(0 && "not global/function");
|
||||||
}
|
}
|
||||||
|
|
||||||
// The following breaks for nested naked functions and other declarations, so check for that.
|
// The following breaks for nested naked functions and other declarations, so check for that.
|
||||||
bool skipNestedCheck = !mustDefineSymbol(sym);
|
bool skipNestedCheck = !mustDefineSymbol(sym);
|
||||||
if (FuncDeclaration* fd = sym->isFuncDeclaration())
|
if (FuncDeclaration* fd = sym->isFuncDeclaration())
|
||||||
skipNestedCheck = (fd->naked != 0);
|
skipNestedCheck = (fd->naked != 0);
|
||||||
|
|
||||||
// Any symbol nested in a function can't be referenced directly from
|
// Any symbol nested in a function can't be referenced directly from
|
||||||
// outside that function, so we can give such symbols internal linkage.
|
// outside that function, so we can give such symbols internal linkage.
|
||||||
// This holds even if nested indirectly, such as member functions of
|
// This holds even if nested indirectly, such as member functions of
|
||||||
|
@ -313,7 +313,7 @@ LLGlobalValue::LinkageTypes DtoLinkage(Dsymbol* sym)
|
||||||
if (parent->isFuncDeclaration())
|
if (parent->isFuncDeclaration())
|
||||||
return llvm::GlobalValue::InternalLinkage;
|
return llvm::GlobalValue::InternalLinkage;
|
||||||
}
|
}
|
||||||
|
|
||||||
// default to external linkage
|
// default to external linkage
|
||||||
return llvm::GlobalValue::ExternalLinkage;
|
return llvm::GlobalValue::ExternalLinkage;
|
||||||
}
|
}
|
||||||
|
@ -362,7 +362,7 @@ LLValue* DtoPointedType(LLValue* ptr, LLValue* val)
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
// ptr is integer pointer
|
// ptr is integer pointer
|
||||||
else if (ptrTy->isInteger())
|
else if (ptrTy->isIntegerTy())
|
||||||
{
|
{
|
||||||
// val is integer
|
// val is integer
|
||||||
assert(valTy->isInteger());
|
assert(valTy->isInteger());
|
||||||
|
|
|
@ -14,7 +14,6 @@
|
||||||
#include "llvm/Analysis/Verifier.h"
|
#include "llvm/Analysis/Verifier.h"
|
||||||
#include "llvm/Bitcode/ReaderWriter.h"
|
#include "llvm/Bitcode/ReaderWriter.h"
|
||||||
#include "llvm/Module.h"
|
#include "llvm/Module.h"
|
||||||
#include "llvm/ModuleProvider.h"
|
|
||||||
#include "llvm/PassManager.h"
|
#include "llvm/PassManager.h"
|
||||||
#include "llvm/LinkAllPasses.h"
|
#include "llvm/LinkAllPasses.h"
|
||||||
#include "llvm/System/Program.h"
|
#include "llvm/System/Program.h"
|
||||||
|
@ -22,6 +21,7 @@
|
||||||
#include "llvm/Support/CommandLine.h"
|
#include "llvm/Support/CommandLine.h"
|
||||||
#include "llvm/Support/FormattedStream.h"
|
#include "llvm/Support/FormattedStream.h"
|
||||||
#include "llvm/Target/TargetMachine.h"
|
#include "llvm/Target/TargetMachine.h"
|
||||||
|
#include "llvm/CodeGen/MachineCodeEmitter.h"
|
||||||
|
|
||||||
#include "mars.h"
|
#include "mars.h"
|
||||||
#include "module.h"
|
#include "module.h"
|
||||||
|
@ -114,11 +114,13 @@ llvm::Module* Module::genLLVMModule(llvm::LLVMContext& context, Ir* sir)
|
||||||
// allocate the target abi
|
// allocate the target abi
|
||||||
gABI = TargetABI::getTarget();
|
gABI = TargetABI::getTarget();
|
||||||
|
|
||||||
|
#ifndef DISABLE_DEBUG_INFO
|
||||||
// debug info
|
// debug info
|
||||||
if (global.params.symdebug) {
|
if (global.params.symdebug) {
|
||||||
RegisterDwarfSymbols(ir.module);
|
RegisterDwarfSymbols(ir.module);
|
||||||
DtoDwarfCompileUnit(this);
|
DtoDwarfCompileUnit(this);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// handle invalid 'objectø module
|
// handle invalid 'objectø module
|
||||||
if (!ClassDeclaration::object) {
|
if (!ClassDeclaration::object) {
|
||||||
|
@ -129,7 +131,7 @@ llvm::Module* Module::genLLVMModule(llvm::LLVMContext& context, Ir* sir)
|
||||||
error("is missing 'class ClassInfo'");
|
error("is missing 'class ClassInfo'");
|
||||||
fatal();
|
fatal();
|
||||||
}
|
}
|
||||||
|
|
||||||
LLVM_D_InitRuntime();
|
LLVM_D_InitRuntime();
|
||||||
|
|
||||||
// process module members
|
// process module members
|
||||||
|
@ -225,10 +227,11 @@ void writeModule(llvm::Module* m, std::string filename)
|
||||||
bcpath.eraseSuffix();
|
bcpath.eraseSuffix();
|
||||||
bcpath.appendSuffix(std::string(global.bc_ext));
|
bcpath.appendSuffix(std::string(global.bc_ext));
|
||||||
Logger::println("Writing LLVM bitcode to: %s\n", bcpath.c_str());
|
Logger::println("Writing LLVM bitcode to: %s\n", bcpath.c_str());
|
||||||
std::ofstream bos(bcpath.c_str(), std::ios::binary);
|
std::string errinfo;
|
||||||
if (bos.fail())
|
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();
|
fatal();
|
||||||
}
|
}
|
||||||
llvm::WriteBitcodeToFile(m, bos);
|
llvm::WriteBitcodeToFile(m, bos);
|
||||||
|
@ -240,10 +243,11 @@ void writeModule(llvm::Module* m, std::string filename)
|
||||||
llpath.eraseSuffix();
|
llpath.eraseSuffix();
|
||||||
llpath.appendSuffix(std::string(global.ll_ext));
|
llpath.appendSuffix(std::string(global.ll_ext));
|
||||||
Logger::println("Writing LLVM asm to: %s\n", llpath.c_str());
|
Logger::println("Writing LLVM asm to: %s\n", llpath.c_str());
|
||||||
std::ofstream aos(llpath.c_str());
|
std::string errinfo;
|
||||||
if (aos.fail())
|
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();
|
fatal();
|
||||||
}
|
}
|
||||||
m->print(aos, NULL);
|
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());
|
Logger::println("Writing native asm to: %s\n", spath.c_str());
|
||||||
std::string err;
|
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())
|
if (err.empty())
|
||||||
{
|
{
|
||||||
write_asm_to_file(*gTargetMachine, *m, out);
|
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;
|
using namespace llvm;
|
||||||
|
|
||||||
// Build up all of the passes that we want to do to the module.
|
// Build up all of the passes that we want to do to the module.
|
||||||
ExistingModuleProvider Provider(&m);
|
FunctionPassManager Passes(&m);
|
||||||
FunctionPassManager Passes(&Provider);
|
|
||||||
|
|
||||||
if (const TargetData *TD = Target.getTargetData())
|
if (const TargetData *TD = Target.getTargetData())
|
||||||
Passes.add(new TargetData(*TD));
|
Passes.add(new TargetData(*TD));
|
||||||
else
|
else
|
||||||
Passes.add(new TargetData(&m));
|
Passes.add(new TargetData(&m));
|
||||||
|
|
||||||
// Ask the target to add backend passes as necessary.
|
|
||||||
MachineCodeEmitter *MCE = 0;
|
|
||||||
|
|
||||||
// Last argument is enum CodeGenOpt::Level OptLevel
|
// Last argument is enum CodeGenOpt::Level OptLevel
|
||||||
// debug info doesn't work properly with OptLevel != None!
|
// debug info doesn't work properly with OptLevel != None!
|
||||||
CodeGenOpt::Level LastArg = CodeGenOpt::Default;
|
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;
|
LastArg = CodeGenOpt::Aggressive;
|
||||||
|
|
||||||
llvm::formatted_raw_ostream fout(out);
|
llvm::formatted_raw_ostream fout(out);
|
||||||
FileModel::Model mod = Target.addPassesToEmitFile(Passes, fout, TargetMachine::AssemblyFile, LastArg);
|
if (Target.addPassesToEmitFile(Passes, fout, TargetMachine::CGFT_AssemblyFile, LastArg))
|
||||||
assert(mod == FileModel::AsmFile);
|
assert(0 && "no support for asm output");
|
||||||
|
|
||||||
bool err = Target.addPassesToEmitFileFinish(Passes, MCE, LastArg);
|
|
||||||
assert(!err);
|
|
||||||
|
|
||||||
Passes.doInitialization();
|
Passes.doInitialization();
|
||||||
|
|
||||||
|
@ -328,9 +325,9 @@ void write_asm_to_file(llvm::TargetMachine &Target, llvm::Module& m, llvm::raw_f
|
||||||
Passes.doFinalization();
|
Passes.doFinalization();
|
||||||
|
|
||||||
// release module from module provider so we can delete it ourselves
|
// release module from module provider so we can delete it ourselves
|
||||||
std::string Err;
|
//std::string Err;
|
||||||
llvm::Module* rmod = Provider.releaseModule(&Err);
|
//llvm::Module* rmod = Provider.releaseModule(&Err);
|
||||||
assert(rmod);
|
//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.
|
// and linker because we don't know where to put the _start symbol.
|
||||||
// GCC mysteriously knows how to do it.
|
// GCC mysteriously knows how to do it.
|
||||||
std::vector<std::string> args;
|
std::vector<std::string> args;
|
||||||
args.push_back(gcc.toString());
|
args.push_back(gcc.str());
|
||||||
args.push_back("-fno-strict-aliasing");
|
args.push_back("-fno-strict-aliasing");
|
||||||
args.push_back("-O3");
|
args.push_back("-O3");
|
||||||
args.push_back("-c");
|
args.push_back("-c");
|
||||||
args.push_back("-xassembler");
|
args.push_back("-xassembler");
|
||||||
args.push_back(asmpath.toString());
|
args.push_back(asmpath.str());
|
||||||
args.push_back("-o");
|
args.push_back("-o");
|
||||||
args.push_back(objpath.toString());
|
args.push_back(objpath.str());
|
||||||
|
|
||||||
//FIXME: only use this if needed?
|
//FIXME: only use this if needed?
|
||||||
args.push_back("-fpic");
|
args.push_back("-fpic");
|
||||||
|
@ -431,11 +428,13 @@ llvm::Function* build_module_ctor()
|
||||||
IRBuilder<> builder(bb);
|
IRBuilder<> builder(bb);
|
||||||
|
|
||||||
// debug info
|
// debug info
|
||||||
|
#ifndef DISABLE_DEBUG_INFO
|
||||||
LLGlobalVariable* subprog;
|
LLGlobalVariable* subprog;
|
||||||
if(global.params.symdebug) {
|
if(global.params.symdebug) {
|
||||||
subprog = DtoDwarfSubProgramInternal(name.c_str(), name.c_str()).getGV();
|
subprog = DtoDwarfSubProgramInternal(name.c_str(), name.c_str()).getGV();
|
||||||
builder.CreateCall(gIR->module->getFunction("llvm.dbg.func.start"), DBG_CAST(subprog));
|
builder.CreateCall(gIR->module->getFunction("llvm.dbg.func.start"), DBG_CAST(subprog));
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
for (size_t i=0; i<n; i++) {
|
for (size_t i=0; i<n; i++) {
|
||||||
llvm::Function* f = gIR->ctors[i]->ir.irFunc->func;
|
llvm::Function* f = gIR->ctors[i]->ir.irFunc->func;
|
||||||
|
@ -444,8 +443,10 @@ llvm::Function* build_module_ctor()
|
||||||
}
|
}
|
||||||
|
|
||||||
// debug info end
|
// debug info end
|
||||||
|
#ifndef DISABLE_DEBUG_INFO
|
||||||
if(global.params.symdebug)
|
if(global.params.symdebug)
|
||||||
builder.CreateCall(gIR->module->getFunction("llvm.dbg.region.end"), DBG_CAST(subprog));
|
builder.CreateCall(gIR->module->getFunction("llvm.dbg.region.end"), DBG_CAST(subprog));
|
||||||
|
#endif
|
||||||
|
|
||||||
builder.CreateRetVoid();
|
builder.CreateRetVoid();
|
||||||
return fn;
|
return fn;
|
||||||
|
@ -475,12 +476,14 @@ static llvm::Function* build_module_dtor()
|
||||||
llvm::BasicBlock* bb = llvm::BasicBlock::Create(gIR->context(), "entry", fn);
|
llvm::BasicBlock* bb = llvm::BasicBlock::Create(gIR->context(), "entry", fn);
|
||||||
IRBuilder<> builder(bb);
|
IRBuilder<> builder(bb);
|
||||||
|
|
||||||
|
#ifndef DISABLE_DEBUG_INFO
|
||||||
// debug info
|
// debug info
|
||||||
LLGlobalVariable* subprog;
|
LLGlobalVariable* subprog;
|
||||||
if(global.params.symdebug) {
|
if(global.params.symdebug) {
|
||||||
subprog = DtoDwarfSubProgramInternal(name.c_str(), name.c_str()).getGV();
|
subprog = DtoDwarfSubProgramInternal(name.c_str(), name.c_str()).getGV();
|
||||||
builder.CreateCall(gIR->module->getFunction("llvm.dbg.func.start"), DBG_CAST(subprog));
|
builder.CreateCall(gIR->module->getFunction("llvm.dbg.func.start"), DBG_CAST(subprog));
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
for (size_t i=0; i<n; i++) {
|
for (size_t i=0; i<n; i++) {
|
||||||
llvm::Function* f = gIR->dtors[i]->ir.irFunc->func;
|
llvm::Function* f = gIR->dtors[i]->ir.irFunc->func;
|
||||||
|
@ -488,9 +491,11 @@ static llvm::Function* build_module_dtor()
|
||||||
call->setCallingConv(DtoCallingConv(0, LINKd));
|
call->setCallingConv(DtoCallingConv(0, LINKd));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef DISABLE_DEBUG_INFO
|
||||||
// debug info end
|
// debug info end
|
||||||
if(global.params.symdebug)
|
if(global.params.symdebug)
|
||||||
builder.CreateCall(gIR->module->getFunction("llvm.dbg.region.end"), DBG_CAST(subprog));
|
builder.CreateCall(gIR->module->getFunction("llvm.dbg.region.end"), DBG_CAST(subprog));
|
||||||
|
#endif
|
||||||
|
|
||||||
builder.CreateRetVoid();
|
builder.CreateRetVoid();
|
||||||
return fn;
|
return fn;
|
||||||
|
@ -520,12 +525,14 @@ static llvm::Function* build_module_unittest()
|
||||||
llvm::BasicBlock* bb = llvm::BasicBlock::Create(gIR->context(), "entry", fn);
|
llvm::BasicBlock* bb = llvm::BasicBlock::Create(gIR->context(), "entry", fn);
|
||||||
IRBuilder<> builder(bb);
|
IRBuilder<> builder(bb);
|
||||||
|
|
||||||
|
#ifndef DISABLE_DEBUG_INFO
|
||||||
// debug info
|
// debug info
|
||||||
LLGlobalVariable* subprog;
|
LLGlobalVariable* subprog;
|
||||||
if(global.params.symdebug) {
|
if(global.params.symdebug) {
|
||||||
subprog = DtoDwarfSubProgramInternal(name.c_str(), name.c_str()).getGV();
|
subprog = DtoDwarfSubProgramInternal(name.c_str(), name.c_str()).getGV();
|
||||||
builder.CreateCall(gIR->module->getFunction("llvm.dbg.func.start"), DBG_CAST(subprog));
|
builder.CreateCall(gIR->module->getFunction("llvm.dbg.func.start"), DBG_CAST(subprog));
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
for (size_t i=0; i<n; i++) {
|
for (size_t i=0; i<n; i++) {
|
||||||
llvm::Function* f = gIR->unitTests[i]->ir.irFunc->func;
|
llvm::Function* f = gIR->unitTests[i]->ir.irFunc->func;
|
||||||
|
@ -533,9 +540,11 @@ static llvm::Function* build_module_unittest()
|
||||||
call->setCallingConv(DtoCallingConv(0, LINKd));
|
call->setCallingConv(DtoCallingConv(0, LINKd));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef DISABLE_DEBUG_INFO
|
||||||
// debug info end
|
// debug info end
|
||||||
if(global.params.symdebug)
|
if(global.params.symdebug)
|
||||||
builder.CreateCall(gIR->module->getFunction("llvm.dbg.region.end"), DBG_CAST(subprog));
|
builder.CreateCall(gIR->module->getFunction("llvm.dbg.region.end"), DBG_CAST(subprog));
|
||||||
|
#endif
|
||||||
|
|
||||||
builder.CreateRetVoid();
|
builder.CreateRetVoid();
|
||||||
return fn;
|
return fn;
|
||||||
|
@ -578,11 +587,13 @@ static LLFunction* build_module_reference_and_ctor(LLConstant* moduleinfo)
|
||||||
IRBuilder<> builder(bb);
|
IRBuilder<> builder(bb);
|
||||||
|
|
||||||
// debug info
|
// debug info
|
||||||
|
#ifndef DISABLE_DEBUG_INFO
|
||||||
LLGlobalVariable* subprog;
|
LLGlobalVariable* subprog;
|
||||||
if(global.params.symdebug) {
|
if(global.params.symdebug) {
|
||||||
subprog = DtoDwarfSubProgramInternal(fname.c_str(), fname.c_str()).getGV();
|
subprog = DtoDwarfSubProgramInternal(fname.c_str(), fname.c_str()).getGV();
|
||||||
builder.CreateCall(gIR->module->getFunction("llvm.dbg.func.start"), DBG_CAST(subprog));
|
builder.CreateCall(gIR->module->getFunction("llvm.dbg.func.start"), DBG_CAST(subprog));
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// get current beginning
|
// get current beginning
|
||||||
LLValue* curbeg = builder.CreateLoad(mref, "current");
|
LLValue* curbeg = builder.CreateLoad(mref, "current");
|
||||||
|
@ -594,9 +605,11 @@ static LLFunction* build_module_reference_and_ctor(LLConstant* moduleinfo)
|
||||||
// replace beginning
|
// replace beginning
|
||||||
builder.CreateStore(thismref, mref);
|
builder.CreateStore(thismref, mref);
|
||||||
|
|
||||||
|
#ifndef DISABLE_DEBUG_INFO
|
||||||
// debug info end
|
// debug info end
|
||||||
if(global.params.symdebug)
|
if(global.params.symdebug)
|
||||||
builder.CreateCall(gIR->module->getFunction("llvm.dbg.region.end"), DBG_CAST(subprog));
|
builder.CreateCall(gIR->module->getFunction("llvm.dbg.region.end"), DBG_CAST(subprog));
|
||||||
|
#endif
|
||||||
|
|
||||||
// return
|
// return
|
||||||
builder.CreateRetVoid();
|
builder.CreateRetVoid();
|
||||||
|
@ -614,11 +627,11 @@ void Module::genmoduleinfo()
|
||||||
// ModuleInfo[] importedModules;
|
// ModuleInfo[] importedModules;
|
||||||
// ClassInfo[] localClasses;
|
// ClassInfo[] localClasses;
|
||||||
// uint flags;
|
// uint flags;
|
||||||
//
|
//
|
||||||
// void function() ctor;
|
// void function() ctor;
|
||||||
// void function() dtor;
|
// void function() dtor;
|
||||||
// void function() unitTest;
|
// void function() unitTest;
|
||||||
//
|
//
|
||||||
// void* xgetMembers;
|
// void* xgetMembers;
|
||||||
// void function() ictor;
|
// void function() ictor;
|
||||||
//
|
//
|
||||||
|
|
|
@ -121,7 +121,7 @@ LLGlobalVariable * IrStruct::getInterfaceArraySymbol()
|
||||||
name.append("16__interfaceInfosZ");
|
name.append("16__interfaceInfosZ");
|
||||||
|
|
||||||
llvm::GlobalValue::LinkageTypes _linkage = DtoExternalLinkage(aggrdecl);
|
llvm::GlobalValue::LinkageTypes _linkage = DtoExternalLinkage(aggrdecl);
|
||||||
classInterfacesArray = new llvm::GlobalVariable(*gIR->module,
|
classInterfacesArray = new llvm::GlobalVariable(*gIR->module,
|
||||||
array_type, true, _linkage, NULL, name);
|
array_type, true, _linkage, NULL, name);
|
||||||
|
|
||||||
return classInterfacesArray;
|
return classInterfacesArray;
|
||||||
|
@ -396,7 +396,7 @@ llvm::GlobalVariable * IrStruct::getInterfaceVtbl(BaseClass * b, bool new_instan
|
||||||
mangle.append("6__vtblZ");
|
mangle.append("6__vtblZ");
|
||||||
|
|
||||||
llvm::GlobalVariable* GV = new llvm::GlobalVariable(
|
llvm::GlobalVariable* GV = new llvm::GlobalVariable(
|
||||||
*gIR->module,
|
*gIR->module,
|
||||||
vtbl_constant->getType(),
|
vtbl_constant->getType(),
|
||||||
true,
|
true,
|
||||||
_linkage,
|
_linkage,
|
||||||
|
@ -483,7 +483,7 @@ LLConstant * IrStruct::getClassInfoInterfaces()
|
||||||
|
|
||||||
// create Interface struct
|
// create Interface struct
|
||||||
LLConstant* inits[3] = { ci, vtb, off };
|
LLConstant* inits[3] = { ci, vtb, off };
|
||||||
LLConstant* entry = LLConstantStruct::get(gIR->context(), inits, 3);
|
LLConstant* entry = LLConstantStruct::get(gIR->context(), inits, 3, false);
|
||||||
constants.push_back(entry);
|
constants.push_back(entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -133,7 +133,7 @@ void IRLandingPad::constructLandingPad(llvm::BasicBlock* inBB)
|
||||||
}
|
}
|
||||||
// if there's a finally, the eh table has to have a 0 action
|
// if there's a finally, the eh table has to have a 0 action
|
||||||
if(hasFinally)
|
if(hasFinally)
|
||||||
selectorargs.push_back(DtoConstSize_t(0));//LLConstantInt::get(LLType::getInt32Ty(gIR->context()), 0));
|
selectorargs.push_back(DtoConstUint(0));
|
||||||
|
|
||||||
// personality fn
|
// personality fn
|
||||||
llvm::Function* personality_fn = LLVM_D_GetRuntimeFunction(gIR->module, "_d_eh_personality");
|
llvm::Function* personality_fn = LLVM_D_GetRuntimeFunction(gIR->module, "_d_eh_personality");
|
||||||
|
@ -144,18 +144,14 @@ void IRLandingPad::constructLandingPad(llvm::BasicBlock* inBB)
|
||||||
selectorargs.insert(selectorargs.begin(), eh_ptr);
|
selectorargs.insert(selectorargs.begin(), eh_ptr);
|
||||||
|
|
||||||
// if there is a catch and some catch allocated storage, store exception object
|
// if there is a catch and some catch allocated storage, store exception object
|
||||||
if(catchToInt.size() && catch_var)
|
if(catchToInt.size() && catch_var)
|
||||||
{
|
{
|
||||||
const LLType* objectTy = DtoType(ClassDeclaration::object->type);
|
const LLType* objectTy = DtoType(ClassDeclaration::object->type);
|
||||||
gIR->ir->CreateStore(gIR->ir->CreateBitCast(eh_ptr, objectTy), catch_var);
|
gIR->ir->CreateStore(gIR->ir->CreateBitCast(eh_ptr, objectTy), catch_var);
|
||||||
}
|
}
|
||||||
|
|
||||||
// eh_sel = llvm.eh.selector(eh_ptr, cast(byte*)&_d_eh_personality, <selectorargs>);
|
// eh_sel = llvm.eh.selector(eh_ptr, cast(byte*)&_d_eh_personality, <selectorargs>);
|
||||||
llvm::Function* eh_selector_fn;
|
llvm::Function* eh_selector_fn = GET_INTRINSIC_DECL(eh_selector);
|
||||||
if (global.params.is64bit)
|
|
||||||
eh_selector_fn = GET_INTRINSIC_DECL(eh_selector_i64);
|
|
||||||
else
|
|
||||||
eh_selector_fn = GET_INTRINSIC_DECL(eh_selector_i32);
|
|
||||||
LLValue* eh_sel = gIR->ir->CreateCall(eh_selector_fn, selectorargs.begin(), selectorargs.end());
|
LLValue* eh_sel = gIR->ir->CreateCall(eh_selector_fn, selectorargs.begin(), selectorargs.end());
|
||||||
|
|
||||||
// emit finallys and switches that branch to catches until there are no more catches
|
// emit finallys and switches that branch to catches until there are no more catches
|
||||||
|
@ -186,7 +182,7 @@ void IRLandingPad::constructLandingPad(llvm::BasicBlock* inBB)
|
||||||
}
|
}
|
||||||
// dubious comment
|
// dubious comment
|
||||||
// catches matched first get the largest switchval, so do size - unique int
|
// catches matched first get the largest switchval, so do size - unique int
|
||||||
llvm::ConstantInt* switchval = LLConstantInt::get(DtoSize_t(), catchToInt[rit->catchType]);
|
llvm::ConstantInt* switchval = DtoConstUint(catchToInt[rit->catchType]);
|
||||||
// and make sure we don't add the same switchval twice, may happen with nested trys
|
// and make sure we don't add the same switchval twice, may happen with nested trys
|
||||||
if(!switchinst->findCaseValue(switchval))
|
if(!switchinst->findCaseValue(switchval))
|
||||||
switchinst->addCase(switchval, rit->target);
|
switchinst->addCase(switchval, rit->target);
|
||||||
|
|
|
@ -1,10 +1,14 @@
|
||||||
#include "llvm/DerivedTypes.h"
|
#include "llvm/DerivedTypes.h"
|
||||||
|
#include "llvm/LLVMContext.h"
|
||||||
#include "mars.h"
|
#include "mars.h"
|
||||||
#include "mtype.h"
|
#include "mtype.h"
|
||||||
#include "gen/irstate.h"
|
#include "gen/irstate.h"
|
||||||
#include "gen/logger.h"
|
#include "gen/logger.h"
|
||||||
#include "ir/irtype.h"
|
#include "ir/irtype.h"
|
||||||
|
|
||||||
|
// This code uses llvm::getGlobalContext() as these functions are invoked before gIR is set.
|
||||||
|
// ... thus it segfaults on gIR==NULL
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
extern const llvm::Type* DtoType(Type* dt);
|
extern const llvm::Type* DtoType(Type* dt);
|
||||||
|
@ -43,30 +47,31 @@ const llvm::Type * IrTypeBasic::basic2llvm(Type* t)
|
||||||
{
|
{
|
||||||
const llvm::Type* t2;
|
const llvm::Type* t2;
|
||||||
|
|
||||||
// FIXME: don't use getGlobalContext
|
llvm::LLVMContext& ctx = llvm::getGlobalContext();
|
||||||
|
|
||||||
switch(t->ty)
|
switch(t->ty)
|
||||||
{
|
{
|
||||||
case Tvoid:
|
case Tvoid:
|
||||||
return llvm::Type::getVoidTy(llvm::getGlobalContext());
|
return llvm::Type::getVoidTy(ctx);
|
||||||
|
|
||||||
case Tint8:
|
case Tint8:
|
||||||
case Tuns8:
|
case Tuns8:
|
||||||
case Tchar:
|
case Tchar:
|
||||||
return llvm::Type::getInt8Ty(llvm::getGlobalContext());
|
return llvm::Type::getInt8Ty(ctx);
|
||||||
|
|
||||||
case Tint16:
|
case Tint16:
|
||||||
case Tuns16:
|
case Tuns16:
|
||||||
case Twchar:
|
case Twchar:
|
||||||
return llvm::Type::getInt16Ty(llvm::getGlobalContext());
|
return llvm::Type::getInt16Ty(ctx);
|
||||||
|
|
||||||
case Tint32:
|
case Tint32:
|
||||||
case Tuns32:
|
case Tuns32:
|
||||||
case Tdchar:
|
case Tdchar:
|
||||||
return llvm::Type::getInt32Ty(llvm::getGlobalContext());
|
return llvm::Type::getInt32Ty(ctx);
|
||||||
|
|
||||||
case Tint64:
|
case Tint64:
|
||||||
case Tuns64:
|
case Tuns64:
|
||||||
return llvm::Type::getInt64Ty(llvm::getGlobalContext());
|
return llvm::Type::getInt64Ty(ctx);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
case Tint128:
|
case Tint128:
|
||||||
|
@ -76,37 +81,37 @@ const llvm::Type * IrTypeBasic::basic2llvm(Type* t)
|
||||||
|
|
||||||
case Tfloat32:
|
case Tfloat32:
|
||||||
case Timaginary32:
|
case Timaginary32:
|
||||||
return llvm::Type::getFloatTy(llvm::getGlobalContext());
|
return llvm::Type::getFloatTy(ctx);
|
||||||
|
|
||||||
case Tfloat64:
|
case Tfloat64:
|
||||||
case Timaginary64:
|
case Timaginary64:
|
||||||
return llvm::Type::getDoubleTy(llvm::getGlobalContext());
|
return llvm::Type::getDoubleTy(ctx);
|
||||||
|
|
||||||
case Tfloat80:
|
case Tfloat80:
|
||||||
case Timaginary80:
|
case Timaginary80:
|
||||||
// only x86 has 80bit float
|
// only x86 has 80bit float
|
||||||
if (global.params.cpu == ARCHx86 || global.params.cpu == ARCHx86_64)
|
if (global.params.cpu == ARCHx86 || global.params.cpu == ARCHx86_64)
|
||||||
return llvm::Type::getX86_FP80Ty(llvm::getGlobalContext());
|
return llvm::Type::getX86_FP80Ty(ctx);
|
||||||
// other platforms use 64bit reals
|
// other platforms use 64bit reals
|
||||||
else
|
else
|
||||||
return llvm::Type::getDoubleTy(llvm::getGlobalContext());
|
return llvm::Type::getDoubleTy(ctx);
|
||||||
|
|
||||||
case Tcomplex32:
|
case Tcomplex32:
|
||||||
t2 = llvm::Type::getFloatTy(llvm::getGlobalContext());
|
t2 = llvm::Type::getFloatTy(ctx);
|
||||||
return llvm::StructType::get(llvm::getGlobalContext(), t2, t2, NULL);
|
return llvm::StructType::get(ctx, t2, t2, NULL);
|
||||||
|
|
||||||
case Tcomplex64:
|
case Tcomplex64:
|
||||||
t2 = llvm::Type::getDoubleTy(llvm::getGlobalContext());
|
t2 = llvm::Type::getDoubleTy(ctx);
|
||||||
return llvm::StructType::get(llvm::getGlobalContext(), t2, t2, NULL);
|
return llvm::StructType::get(ctx, t2, t2, NULL);
|
||||||
|
|
||||||
case Tcomplex80:
|
case Tcomplex80:
|
||||||
t2 = (global.params.cpu == ARCHx86 || global.params.cpu == ARCHx86_64)
|
t2 = (global.params.cpu == ARCHx86 || global.params.cpu == ARCHx86_64)
|
||||||
? llvm::Type::getX86_FP80Ty(llvm::getGlobalContext())
|
? llvm::Type::getX86_FP80Ty(ctx)
|
||||||
: llvm::Type::getDoubleTy(llvm::getGlobalContext());
|
: llvm::Type::getDoubleTy(ctx);
|
||||||
return llvm::StructType::get(llvm::getGlobalContext(), t2, t2, NULL);
|
return llvm::StructType::get(ctx, t2, t2, NULL);
|
||||||
|
|
||||||
case Tbool:
|
case Tbool:
|
||||||
return llvm::Type::getInt1Ty(llvm::getGlobalContext());
|
return llvm::Type::getInt1Ty(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(0 && "not basic type");
|
assert(0 && "not basic type");
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#include "gen/llvm.h"
|
#include "gen/llvm.h"
|
||||||
#include "declaration.h"
|
#include "declaration.h"
|
||||||
|
#include "gen/irstate.h"
|
||||||
#include "ir/irvar.h"
|
#include "ir/irvar.h"
|
||||||
|
|
||||||
|
|
||||||
|
@ -18,7 +19,7 @@ IrVar::IrVar(VarDeclaration* var)
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
IrGlobal::IrGlobal(VarDeclaration* v): IrVar(v),
|
IrGlobal::IrGlobal(VarDeclaration* v): IrVar(v),
|
||||||
type(llvm::OpaqueType::get(llvm::getGlobalContext()))
|
type(llvm::OpaqueType::get(gIR->context()))
|
||||||
{
|
{
|
||||||
constInit = NULL;
|
constInit = NULL;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
Index: tango/core/rt/compiler/ldc/rt/lifetime.d
|
Index: tango/core/rt/compiler/ldc/rt/lifetime.d
|
||||||
===================================================================
|
===================================================================
|
||||||
--- tango/core/rt/compiler/ldc/rt/lifetime.d (revision 5368)
|
--- tango/core/rt/compiler/ldc/rt/lifetime.d (revision 5462)
|
||||||
+++ tango/core/rt/compiler/ldc/rt/lifetime.d (working copy)
|
+++ tango/core/rt/compiler/ldc/rt/lifetime.d (working copy)
|
||||||
@@ -786,6 +786,7 @@
|
@@ -786,6 +786,7 @@
|
||||||
return *cast(long*)px;
|
return *cast(long*)px;
|
||||||
|
@ -53,3 +53,650 @@ Index: tango/core/rt/compiler/ldc/rt/lifetime.d
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
|
Index: tango/core/rt/compiler/ldc/rt/eh.d
|
||||||
|
===================================================================
|
||||||
|
--- tango/core/rt/compiler/ldc/rt/eh.d (revision 5462)
|
||||||
|
+++ tango/core/rt/compiler/ldc/rt/eh.d (working copy)
|
||||||
|
@@ -1,38 +1,34 @@
|
||||||
|
/**
|
||||||
|
* This module contains functions and structures required for
|
||||||
|
- * exception handling.
|
||||||
|
+ * dwarf exception handling with llvm
|
||||||
|
*/
|
||||||
|
module rt.eh;
|
||||||
|
|
||||||
|
-import ldc.cstdarg;
|
||||||
|
-import rt.compiler.util.console;
|
||||||
|
+//debug = EH_personality;
|
||||||
|
|
||||||
|
-// debug = EH_personality;
|
||||||
|
-
|
||||||
|
// current EH implementation works on x86
|
||||||
|
// if it has a working unwind runtime
|
||||||
|
version(X86) {
|
||||||
|
version(linux) version=X86_UNWIND;
|
||||||
|
version(darwin) version=X86_UNWIND;
|
||||||
|
version(solaris) version=X86_UNWIND;
|
||||||
|
- version(freebsd) version=X86_UNWIND;
|
||||||
|
}
|
||||||
|
version(X86_64) {
|
||||||
|
version(linux) version=X86_UNWIND;
|
||||||
|
version(darwin) version=X86_UNWIND;
|
||||||
|
version(solaris) version=X86_UNWIND;
|
||||||
|
- version(freebsd) version=X86_UNWIND;
|
||||||
|
}
|
||||||
|
|
||||||
|
//version = HP_LIBUNWIND;
|
||||||
|
|
||||||
|
private extern(C) void abort();
|
||||||
|
private extern(C) int printf(char*, ...);
|
||||||
|
-private extern(C) int vprintf(char*, va_list va);
|
||||||
|
+//private extern(C) int vprintf(char*, va_list va);
|
||||||
|
|
||||||
|
// D runtime functions
|
||||||
|
extern(C) {
|
||||||
|
- int _d_isbaseof(ClassInfo oc, ClassInfo c);
|
||||||
|
+// int _d_isbaseof(ClassInfo oc, ClassInfo c);
|
||||||
|
+ Object _d_dynamic_cast(Object o, ClassInfo c);
|
||||||
|
}
|
||||||
|
|
||||||
|
// libunwind headers
|
||||||
|
@@ -74,16 +70,19 @@
|
||||||
|
// interface to HP's libunwind from http://www.nongnu.org/libunwind/
|
||||||
|
version(HP_LIBUNWIND)
|
||||||
|
{
|
||||||
|
+ // Haven't checked whether and how it has _Unwind_Get{Text,Data}RelBase
|
||||||
|
+ pragma (msg, "HP_LIBUNWIND interface is out of date and untested");
|
||||||
|
+
|
||||||
|
void __libunwind_Unwind_Resume(_Unwind_Exception *);
|
||||||
|
_Unwind_Reason_Code __libunwind_Unwind_RaiseException(_Unwind_Exception *);
|
||||||
|
ptrdiff_t __libunwind_Unwind_GetLanguageSpecificData(_Unwind_Context_Ptr
|
||||||
|
context);
|
||||||
|
- ptrdiff_t __libunwind_Unwind_GetIP(_Unwind_Context_Ptr context);
|
||||||
|
+ size_t __libunwind_Unwind_GetIP(_Unwind_Context_Ptr context);
|
||||||
|
ptrdiff_t __libunwind_Unwind_SetIP(_Unwind_Context_Ptr context,
|
||||||
|
ptrdiff_t new_value);
|
||||||
|
ptrdiff_t __libunwind_Unwind_SetGR(_Unwind_Context_Ptr context, int index,
|
||||||
|
ptrdiff_t new_value);
|
||||||
|
- ptrdiff_t __libunwind_Unwind_GetRegionStart(_Unwind_Context_Ptr context);
|
||||||
|
+ size_t __libunwind_Unwind_GetRegionStart(_Unwind_Context_Ptr context);
|
||||||
|
|
||||||
|
alias __libunwind_Unwind_Resume _Unwind_Resume;
|
||||||
|
alias __libunwind_Unwind_RaiseException _Unwind_RaiseException;
|
||||||
|
@@ -94,27 +93,30 @@
|
||||||
|
alias __libunwind_Unwind_SetGR _Unwind_SetGR;
|
||||||
|
alias __libunwind_Unwind_GetRegionStart _Unwind_GetRegionStart;
|
||||||
|
}
|
||||||
|
-else version(X86_UNWIND)
|
||||||
|
+else version(X86_UNWIND)
|
||||||
|
{
|
||||||
|
void _Unwind_Resume(_Unwind_Exception*);
|
||||||
|
_Unwind_Reason_Code _Unwind_RaiseException(_Unwind_Exception*);
|
||||||
|
ptrdiff_t _Unwind_GetLanguageSpecificData(_Unwind_Context_Ptr context);
|
||||||
|
- ptrdiff_t _Unwind_GetIP(_Unwind_Context_Ptr context);
|
||||||
|
+ size_t _Unwind_GetIP(_Unwind_Context_Ptr context);
|
||||||
|
ptrdiff_t _Unwind_SetIP(_Unwind_Context_Ptr context, ptrdiff_t new_value);
|
||||||
|
ptrdiff_t _Unwind_SetGR(_Unwind_Context_Ptr context, int index,
|
||||||
|
ptrdiff_t new_value);
|
||||||
|
- ptrdiff_t _Unwind_GetRegionStart(_Unwind_Context_Ptr context);
|
||||||
|
+ size_t _Unwind_GetRegionStart(_Unwind_Context_Ptr context);
|
||||||
|
+
|
||||||
|
+ size_t _Unwind_GetTextRelBase(_Unwind_Context_Ptr);
|
||||||
|
+ size_t _Unwind_GetDataRelBase(_Unwind_Context_Ptr);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// runtime calls these directly
|
||||||
|
void _Unwind_Resume(_Unwind_Exception*)
|
||||||
|
{
|
||||||
|
- console("_Unwind_Resume is not implemented on this platform.\n");
|
||||||
|
+ printf("_Unwind_Resume is not implemented on this platform.\n");
|
||||||
|
}
|
||||||
|
_Unwind_Reason_Code _Unwind_RaiseException(_Unwind_Exception*)
|
||||||
|
{
|
||||||
|
- console("_Unwind_RaiseException is not implemented on this platform.\n");
|
||||||
|
+ printf("_Unwind_RaiseException is not implemented on this platform.\n");
|
||||||
|
return _Unwind_Reason_Code.FATAL_PHASE1_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@@ -122,14 +124,161 @@
|
||||||
|
}
|
||||||
|
|
||||||
|
// error and exit
|
||||||
|
-extern(C) private void fatalerror(char[] format)
|
||||||
|
+extern(C) private void fatalerror(char* format, ...)
|
||||||
|
{
|
||||||
|
- printf("Fatal error in EH code: %.*s\n", format.length, format.ptr);
|
||||||
|
+// va_list args;
|
||||||
|
+// va_start(args, format);
|
||||||
|
+ printf("Fatal error in EH code: ");
|
||||||
|
+// vprintf(format, args);
|
||||||
|
+ printf("\n");
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
-// helpers for reading certain DWARF data
|
||||||
|
+// DWARF EH encoding enum
|
||||||
|
+// See e.g. http://refspecs.freestandards.org/LSB_3.1.1/LSB-Core-generic/LSB-Core-generic/dwarfext.html
|
||||||
|
+private enum : ubyte {
|
||||||
|
+ DW_EH_PE_omit = 0xff, // value is not present
|
||||||
|
+
|
||||||
|
+ // value format
|
||||||
|
+ DW_EH_PE_absptr = 0x00, // literal pointer
|
||||||
|
+ DW_EH_PE_uleb128 = 0x01,
|
||||||
|
+ DW_EH_PE_udata2 = 0x02, // unsigned 2-byte
|
||||||
|
+ DW_EH_PE_udata4 = 0x03,
|
||||||
|
+ DW_EH_PE_udata8 = 0x04,
|
||||||
|
+ DW_EH_PE_sleb128 = 0x09,
|
||||||
|
+ DW_EH_PE_sdata2 = 0x0a,
|
||||||
|
+ DW_EH_PE_sdata4 = 0x0b,
|
||||||
|
+ DW_EH_PE_sdata8 = 0x0c,
|
||||||
|
+
|
||||||
|
+ // value meaning
|
||||||
|
+ DW_EH_PE_pcrel = 0x10, // relative to program counter
|
||||||
|
+ DW_EH_PE_textrel = 0x20, // relative to .text
|
||||||
|
+ DW_EH_PE_datarel = 0x30, // relative to .got or .eh_frame_hdr
|
||||||
|
+ DW_EH_PE_funcrel = 0x40, // relative to beginning of function
|
||||||
|
+ DW_EH_PE_aligned = 0x50, // is an aligned void*
|
||||||
|
+
|
||||||
|
+ // value is a pointer to the actual value
|
||||||
|
+ // this is a mask on top of one of the above
|
||||||
|
+ DW_EH_PE_indirect = 0x80
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+// Helpers for reading DWARF data
|
||||||
|
+
|
||||||
|
+// Given an encoding and a context, return the base to which the encoding is
|
||||||
|
+// relative
|
||||||
|
+private size_t base_of_encoded(_Unwind_Context_Ptr context, ubyte encoding)
|
||||||
|
+{
|
||||||
|
+ if (encoding == DW_EH_PE_omit)
|
||||||
|
+ return 0;
|
||||||
|
+
|
||||||
|
+ switch (encoding & 0x70) // ignore DW_EH_PE_indirect
|
||||||
|
+ {
|
||||||
|
+ case DW_EH_PE_absptr, DW_EH_PE_pcrel, DW_EH_PE_aligned:
|
||||||
|
+ return 0;
|
||||||
|
+
|
||||||
|
+ case DW_EH_PE_textrel: return _Unwind_GetTextRelBase(context);
|
||||||
|
+ case DW_EH_PE_datarel: return _Unwind_GetDataRelBase(context);
|
||||||
|
+ case DW_EH_PE_funcrel: return _Unwind_GetRegionStart(context);
|
||||||
|
+
|
||||||
|
+ default: fatalerror("Unrecognized base for DWARF value");
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+// Only defined for fixed-size encodings
|
||||||
|
+private size_t size_of_encoded(ubyte encoding)
|
||||||
|
+{
|
||||||
|
+ if (encoding == DW_EH_PE_omit)
|
||||||
|
+ return 0;
|
||||||
|
+
|
||||||
|
+ switch (encoding & 0x07) // ignore leb128
|
||||||
|
+ {
|
||||||
|
+ case DW_EH_PE_absptr: return (void*).sizeof;
|
||||||
|
+ case DW_EH_PE_udata2: return 2;
|
||||||
|
+ case DW_EH_PE_udata4: return 4;
|
||||||
|
+ case DW_EH_PE_udata8: return 8;
|
||||||
|
+
|
||||||
|
+ default: fatalerror("Unrecognized fixed-size DWARF value encoding");
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+// Actual value readers below: read a value from the given ubyte* into the
|
||||||
|
+// output parameter and return the pointer incremented past the value.
|
||||||
|
+
|
||||||
|
+// Like read_encoded_with_base but gets the base from the given context
|
||||||
|
+private ubyte* read_encoded(_Unwind_Context_Ptr context, ubyte encoding, ubyte* p, out size_t val)
|
||||||
|
+{
|
||||||
|
+ return read_encoded_with_base(encoding, base_of_encoded(context, encoding), p, val);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+private ubyte* read_encoded_with_base(ubyte encoding, size_t base, ubyte* p, out size_t val)
|
||||||
|
+{
|
||||||
|
+ if (encoding == DW_EH_PE_aligned)
|
||||||
|
+ {
|
||||||
|
+ auto a = cast(size_t)p;
|
||||||
|
+ a = (a + (void*).sizeof - 1) & -(void*).sizeof;
|
||||||
|
+ val = *cast(size_t*)a;
|
||||||
|
+ return cast(ubyte*)(a + (void*).sizeof);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ union U
|
||||||
|
+ {
|
||||||
|
+ size_t ptr;
|
||||||
|
+ ushort udata2;
|
||||||
|
+ uint udata4;
|
||||||
|
+ ulong udata8;
|
||||||
|
+ short sdata2;
|
||||||
|
+ int sdata4;
|
||||||
|
+ long sdata8;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ auto u = cast(U*)p;
|
||||||
|
+
|
||||||
|
+ size_t result;
|
||||||
|
+
|
||||||
|
+ switch (encoding & 0x0f)
|
||||||
|
+ {
|
||||||
|
+ case DW_EH_PE_absptr:
|
||||||
|
+ result = u.ptr;
|
||||||
|
+ p += (void*).sizeof;
|
||||||
|
+ break;
|
||||||
|
+
|
||||||
|
+ case DW_EH_PE_uleb128:
|
||||||
|
+ {
|
||||||
|
+ p = get_uleb128(p, result);
|
||||||
|
+ break;
|
||||||
|
+ }
|
||||||
|
+ case DW_EH_PE_sleb128:
|
||||||
|
+ {
|
||||||
|
+ ptrdiff_t sleb128;
|
||||||
|
+ p = get_sleb128(p, sleb128);
|
||||||
|
+ result = cast(size_t)sleb128;
|
||||||
|
+ break;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ case DW_EH_PE_udata2: result = cast(size_t)u.udata2; p += 2; break;
|
||||||
|
+ case DW_EH_PE_udata4: result = cast(size_t)u.udata4; p += 4; break;
|
||||||
|
+ case DW_EH_PE_udata8: result = cast(size_t)u.udata8; p += 8; break;
|
||||||
|
+ case DW_EH_PE_sdata2: result = cast(size_t)u.sdata2; p += 2; break;
|
||||||
|
+ case DW_EH_PE_sdata4: result = cast(size_t)u.sdata4; p += 4; break;
|
||||||
|
+ case DW_EH_PE_sdata8: result = cast(size_t)u.sdata8; p += 8; break;
|
||||||
|
+
|
||||||
|
+ default: fatalerror("Unrecognized DWARF value encoding format");
|
||||||
|
+ }
|
||||||
|
+ if (result)
|
||||||
|
+ {
|
||||||
|
+ if ((encoding & 0x70) == DW_EH_PE_pcrel)
|
||||||
|
+ result += cast(size_t)u;
|
||||||
|
+ else
|
||||||
|
+ result += base;
|
||||||
|
+
|
||||||
|
+ if (encoding & DW_EH_PE_indirect)
|
||||||
|
+ result = *cast(size_t*)result;
|
||||||
|
+ }
|
||||||
|
+ val = result;
|
||||||
|
+ return p;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
private ubyte* get_uleb128(ubyte* addr, ref size_t res)
|
||||||
|
{
|
||||||
|
res = 0;
|
||||||
|
@@ -137,7 +286,7 @@
|
||||||
|
|
||||||
|
// read as long as high bit is set
|
||||||
|
while(*addr & 0x80) {
|
||||||
|
- res |= (*addr & 0x7f) << bitsize;
|
||||||
|
+ res |= (*addr & 0x7fU) << bitsize;
|
||||||
|
bitsize += 7;
|
||||||
|
addr += 1;
|
||||||
|
if(bitsize >= size_t.sizeof*8)
|
||||||
|
@@ -153,12 +302,12 @@
|
||||||
|
|
||||||
|
private ubyte* get_sleb128(ubyte* addr, ref ptrdiff_t res)
|
||||||
|
{
|
||||||
|
- res = 0;
|
||||||
|
+ size_t tres = 0;
|
||||||
|
size_t bitsize = 0;
|
||||||
|
|
||||||
|
// read as long as high bit is set
|
||||||
|
while(*addr & 0x80) {
|
||||||
|
- res |= (*addr & 0x7f) << bitsize;
|
||||||
|
+ tres |= (*addr & 0x7fU) << bitsize;
|
||||||
|
bitsize += 7;
|
||||||
|
addr += 1;
|
||||||
|
if(bitsize >= size_t.sizeof*8)
|
||||||
|
@@ -167,12 +316,14 @@
|
||||||
|
// read last
|
||||||
|
if(bitsize != 0 && *addr >= 1 << size_t.sizeof*8 - bitsize)
|
||||||
|
fatalerror("tried to read sleb128 that exceeded size of size_t");
|
||||||
|
- res |= (*addr) << bitsize;
|
||||||
|
+ tres |= (*addr) << bitsize;
|
||||||
|
|
||||||
|
// take care of sign
|
||||||
|
- if(bitsize < size_t.sizeof*8 && ((*addr) & 0x40))
|
||||||
|
- res |= cast(ptrdiff_t)(-1) ^ ((1 << (bitsize+7)) - 1);
|
||||||
|
+ if(bitsize < size_t.sizeof*8 && (*addr & 0x40U) != 0)
|
||||||
|
+ tres |= cast(size_t)(-1) ^ ((1 << (bitsize+7)) - 1);
|
||||||
|
|
||||||
|
+ res = cast(ptrdiff_t)tres;
|
||||||
|
+
|
||||||
|
return addr + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -190,8 +341,7 @@
|
||||||
|
|
||||||
|
// the 8-byte string identifying the type of exception
|
||||||
|
// the first 4 are for vendor, the second 4 for language
|
||||||
|
-//TODO: This may be the wrong way around
|
||||||
|
-const char[8] _d_exception_class = "LLDCD1\0\0";
|
||||||
|
+const char[8] _d_exception_class = "LDC_D_10";
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
@@ -201,118 +351,174 @@
|
||||||
|
version(X86_UNWIND)
|
||||||
|
{
|
||||||
|
|
||||||
|
+// Various stuff we need
|
||||||
|
+struct Region
|
||||||
|
+{
|
||||||
|
+ ubyte* callsite_table;
|
||||||
|
+ ubyte* action_table;
|
||||||
|
+
|
||||||
|
+ // Note: classinfo_table points past the end of the table
|
||||||
|
+ ubyte* classinfo_table;
|
||||||
|
+
|
||||||
|
+ size_t start;
|
||||||
|
+ size_t lpStart_base; // landing pad base
|
||||||
|
+
|
||||||
|
+ ubyte ttypeEnc;
|
||||||
|
+ size_t ttype_base; // typeinfo base
|
||||||
|
+
|
||||||
|
+ ubyte callSiteEnc;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
// the personality routine gets called by the unwind handler and is responsible for
|
||||||
|
// reading the EH tables and deciding what to do
|
||||||
|
extern(C) _Unwind_Reason_Code _d_eh_personality(int ver, _Unwind_Action actions, ulong exception_class, _Unwind_Exception* exception_info, _Unwind_Context_Ptr context)
|
||||||
|
{
|
||||||
|
+ debug(EH_personality) printf("Entering personality routine, context=%p\n", context);
|
||||||
|
// check ver: the C++ Itanium ABI only allows ver == 1
|
||||||
|
if(ver != 1)
|
||||||
|
+ {
|
||||||
|
+ debug(EH_personality) printf("eh version mismatch\n");
|
||||||
|
return _Unwind_Reason_Code.FATAL_PHASE1_ERROR;
|
||||||
|
+ }
|
||||||
|
|
||||||
|
// check exceptionClass
|
||||||
|
//TODO: Treat foreign exceptions with more respect
|
||||||
|
- if((cast(char*)&exception_class)[0..8] != _d_exception_class)
|
||||||
|
+ auto wanted_ec = *cast(ulong*)_d_exception_class.ptr;
|
||||||
|
+ if(exception_class != wanted_ec)
|
||||||
|
+ {
|
||||||
|
+ debug(EH_personality) printf("exception class mismatch %p vs %p\n", exception_class, wanted_ec);
|
||||||
|
return _Unwind_Reason_Code.FATAL_PHASE1_ERROR;
|
||||||
|
+ }
|
||||||
|
|
||||||
|
// find call site table, action table and classinfo table
|
||||||
|
// Note: callsite and action tables do not contain static-length
|
||||||
|
// data and will be parsed as needed
|
||||||
|
- // Note: classinfo_table points past the end of the table
|
||||||
|
- ubyte* callsite_table;
|
||||||
|
- ubyte* action_table;
|
||||||
|
- ClassInfo* classinfo_table;
|
||||||
|
- _d_getLanguageSpecificTables(context, callsite_table, action_table, classinfo_table);
|
||||||
|
- if (!callsite_table)
|
||||||
|
+
|
||||||
|
+ Region region;
|
||||||
|
+
|
||||||
|
+ _d_getLanguageSpecificTables(context, region);
|
||||||
|
+
|
||||||
|
+ // workaround. this should not happen
|
||||||
|
+ if (!region.callsite_table)
|
||||||
|
+ {
|
||||||
|
+ debug(EH_personality) printf("callsite_table is null\n");
|
||||||
|
return _Unwind_Reason_Code.CONTINUE_UNWIND;
|
||||||
|
+ }
|
||||||
|
|
||||||
|
+ debug(EH_personality) printf("yay, checking\n");
|
||||||
|
+ debug(EH_personality) printf("region.start = %p\n", region.start);
|
||||||
|
+
|
||||||
|
/*
|
||||||
|
find landing pad and action table index belonging to ip by walking
|
||||||
|
the callsite_table
|
||||||
|
*/
|
||||||
|
- ubyte* callsite_walker = callsite_table;
|
||||||
|
+ ubyte* callsite_walker = region.callsite_table;
|
||||||
|
+ debug(EH_personality) printf("callsite table at: %p\n", region.callsite_table);
|
||||||
|
+ debug(EH_personality) printf("action table at: %p\n", region.action_table);
|
||||||
|
+ debug(EH_personality) printf("rtti table at %p\n", region.classinfo_table);
|
||||||
|
|
||||||
|
// get the instruction pointer
|
||||||
|
// will be used to find the right entry in the callsite_table
|
||||||
|
// -1 because it will point past the last instruction
|
||||||
|
- ptrdiff_t ip = _Unwind_GetIP(context) - 1;
|
||||||
|
+ debug(EH_personality) printf("check1\n");
|
||||||
|
+ size_t ip = _Unwind_GetIP(context) - 1;
|
||||||
|
+ debug(EH_personality) printf("check2\n");
|
||||||
|
|
||||||
|
- // address block_start is relative to
|
||||||
|
- ptrdiff_t region_start = _Unwind_GetRegionStart(context);
|
||||||
|
-
|
||||||
|
// table entries
|
||||||
|
- uint block_start_offset, block_size;
|
||||||
|
- ptrdiff_t landing_pad;
|
||||||
|
+ size_t landing_pad;
|
||||||
|
size_t action_offset;
|
||||||
|
|
||||||
|
while(true) {
|
||||||
|
// if we've gone through the list and found nothing...
|
||||||
|
- if(callsite_walker >= action_table)
|
||||||
|
+ if(callsite_walker >= region.action_table)
|
||||||
|
+ {
|
||||||
|
+ debug(EH_personality) printf("found nothing\n");
|
||||||
|
return _Unwind_Reason_Code.CONTINUE_UNWIND;
|
||||||
|
+ }
|
||||||
|
|
||||||
|
- block_start_offset = *cast(uint*)callsite_walker;
|
||||||
|
- block_size = *(cast(uint*)callsite_walker + 1);
|
||||||
|
- landing_pad = *(cast(uint*)callsite_walker + 2);
|
||||||
|
- if(landing_pad)
|
||||||
|
- landing_pad += region_start;
|
||||||
|
- callsite_walker = get_uleb128(callsite_walker + 3*uint.sizeof, action_offset);
|
||||||
|
+ size_t block_start, block_size;
|
||||||
|
|
||||||
|
- debug(EH_personality_verbose) printf("ip=%llx %d %d %llx\n", ip, block_start_offset, block_size, landing_pad);
|
||||||
|
+ callsite_walker = read_encoded(null, region.callSiteEnc, callsite_walker, block_start);
|
||||||
|
+ callsite_walker = read_encoded(null, region.callSiteEnc, callsite_walker, block_size);
|
||||||
|
+ callsite_walker = read_encoded(null, region.callSiteEnc, callsite_walker, landing_pad);
|
||||||
|
+ callsite_walker = get_uleb128(callsite_walker, action_offset);
|
||||||
|
|
||||||
|
+ debug(EH_personality) printf("*block start offset = %p\n", block_start);
|
||||||
|
+ debug(EH_personality) printf(" block size = %p\n", block_size);
|
||||||
|
+ debug(EH_personality) printf(" landing pad = %p\n", landing_pad);
|
||||||
|
+ debug(EH_personality) printf(" ip=%p %p %p %p\n", ip, block_start, block_size, landing_pad);
|
||||||
|
+
|
||||||
|
// since the list is sorted, as soon as we're past the ip
|
||||||
|
// there's no handler to be found
|
||||||
|
- if(ip < region_start + block_start_offset)
|
||||||
|
+ if(ip < region.start + block_start)
|
||||||
|
+ {
|
||||||
|
+ debug(EH_personality) printf("found nothing2\n");
|
||||||
|
return _Unwind_Reason_Code.CONTINUE_UNWIND;
|
||||||
|
+ }
|
||||||
|
|
||||||
|
+ if(landing_pad)
|
||||||
|
+ landing_pad += region.lpStart_base;
|
||||||
|
+
|
||||||
|
// if we've found our block, exit
|
||||||
|
- if(ip < region_start + block_start_offset + block_size)
|
||||||
|
+ if(ip < region.start + block_start + block_size)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
- debug(EH_personality) printf("Found correct landing pad and actionOffset %d\n", action_offset);
|
||||||
|
+ debug(EH_personality) printf("Found correct landing pad %p and actionOffset %p\n", landing_pad, action_offset);
|
||||||
|
|
||||||
|
// now we need the exception's classinfo to find a handler
|
||||||
|
// the exception_info is actually a member of a larger _d_exception struct
|
||||||
|
// the runtime allocated. get that now
|
||||||
|
- _d_exception* exception_struct = cast(_d_exception*)(cast(ubyte*)exception_info - _d_exception.unwind_info.offsetof);
|
||||||
|
+ _d_exception* exception_struct = cast(_d_exception*)(cast(ubyte*)exception_info - size_t.sizeof); //_d_exception.unwind_info.offsetof);
|
||||||
|
|
||||||
|
// if there's no action offset and no landing pad, continue unwinding
|
||||||
|
if(!action_offset && !landing_pad)
|
||||||
|
return _Unwind_Reason_Code.CONTINUE_UNWIND;
|
||||||
|
|
||||||
|
// if there's no action offset but a landing pad, this is a cleanup handler
|
||||||
|
- else if(!action_offset && landing_pad)
|
||||||
|
- return _d_eh_install_finally_context(actions, landing_pad, exception_struct, context);
|
||||||
|
+ else if(!action_offset && landing_pad != 0)
|
||||||
|
+ {
|
||||||
|
+ debug(EH_personality) printf("installing finally context\n");
|
||||||
|
+ return _d_eh_install_finally_context(actions, cast(ptrdiff_t)landing_pad, exception_struct, context);
|
||||||
|
+ }
|
||||||
|
|
||||||
|
/*
|
||||||
|
walk action table chain, comparing classinfos using _d_isbaseof
|
||||||
|
*/
|
||||||
|
- ubyte* action_walker = action_table + action_offset - 1;
|
||||||
|
+ ubyte* action_walker = region.action_table + action_offset - 1;
|
||||||
|
|
||||||
|
- ptrdiff_t ti_offset, next_action_offset;
|
||||||
|
while(true) {
|
||||||
|
+ ptrdiff_t ti_offset, next_action_offset;
|
||||||
|
+
|
||||||
|
action_walker = get_sleb128(action_walker, ti_offset);
|
||||||
|
// it is intentional that we not modify action_walker here
|
||||||
|
// next_action_offset is from current action_walker position
|
||||||
|
get_sleb128(action_walker, next_action_offset);
|
||||||
|
|
||||||
|
// negative are 'filters' which we don't use
|
||||||
|
- if(!(ti_offset >= 0))
|
||||||
|
+ if(ti_offset < 0)
|
||||||
|
fatalerror("Filter actions are unsupported");
|
||||||
|
|
||||||
|
// zero means cleanup, which we require to be the last action
|
||||||
|
if(ti_offset == 0) {
|
||||||
|
- if(!(next_action_offset == 0))
|
||||||
|
+ if(next_action_offset != 0)
|
||||||
|
fatalerror("Cleanup action must be last in chain");
|
||||||
|
- return _d_eh_install_finally_context(actions, landing_pad, exception_struct, context);
|
||||||
|
+ return _d_eh_install_finally_context(actions, cast(ptrdiff_t)landing_pad, exception_struct, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
// get classinfo for action and check if the one in the
|
||||||
|
// exception structure is a base
|
||||||
|
- ClassInfo catch_ci = *(classinfo_table - ti_offset);
|
||||||
|
- debug(EH_personality) printf("Comparing catch %s to exception %s\n", catch_ci.name.ptr, exception_struct.exception_object.classinfo.name.ptr);
|
||||||
|
- if(_d_isbaseof(exception_struct.exception_object.classinfo, catch_ci))
|
||||||
|
- return _d_eh_install_catch_context(actions, ti_offset, landing_pad, exception_struct, context);
|
||||||
|
+ size_t typeinfo;
|
||||||
|
+ auto filter = cast(size_t)ti_offset * size_of_encoded(region.ttypeEnc);
|
||||||
|
+ read_encoded_with_base(region.ttypeEnc, region.ttype_base, region.classinfo_table - filter, typeinfo);
|
||||||
|
|
||||||
|
+ debug(EH_personality)
|
||||||
|
+ printf("classinfo at %zx (enc %zx (size %zx) base %zx ptr %zx)\n", typeinfo, region.ttypeEnc, size_of_encoded(region.ttypeEnc), region.ttype_base, region.classinfo_table - filter);
|
||||||
|
+
|
||||||
|
+ auto catch_ci = *cast(ClassInfo*)&typeinfo;
|
||||||
|
+ if(_d_dynamic_cast(exception_struct.exception_object, catch_ci) !is null)
|
||||||
|
+ return _d_eh_install_catch_context(actions, ti_offset, cast(ptrdiff_t)landing_pad, exception_struct, context);
|
||||||
|
+
|
||||||
|
// we've walked through all actions and found nothing...
|
||||||
|
if(next_action_offset == 0)
|
||||||
|
return _Unwind_Reason_Code.CONTINUE_UNWIND;
|
||||||
|
@@ -356,6 +562,7 @@
|
||||||
|
}
|
||||||
|
|
||||||
|
fatalerror("reached unreachable");
|
||||||
|
+
|
||||||
|
return _Unwind_Reason_Code.FATAL_PHASE2_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -370,56 +577,78 @@
|
||||||
|
_Unwind_SetGR(context, eh_exception_regno, cast(ptrdiff_t)exception_struct);
|
||||||
|
_Unwind_SetGR(context, eh_selector_regno, 0);
|
||||||
|
_Unwind_SetIP(context, landing_pad);
|
||||||
|
+
|
||||||
|
return _Unwind_Reason_Code.INSTALL_CONTEXT;
|
||||||
|
}
|
||||||
|
|
||||||
|
-private void _d_getLanguageSpecificTables(_Unwind_Context_Ptr context, ref ubyte* callsite, ref ubyte* action, ref ClassInfo* ci)
|
||||||
|
+private void _d_getLanguageSpecificTables(_Unwind_Context_Ptr context, out Region region)
|
||||||
|
{
|
||||||
|
- ubyte* data = cast(ubyte*)_Unwind_GetLanguageSpecificData(context);
|
||||||
|
+ auto data = cast(ubyte*)_Unwind_GetLanguageSpecificData(context);
|
||||||
|
+
|
||||||
|
+ // workaround. this should not be 0...
|
||||||
|
if (!data)
|
||||||
|
{
|
||||||
|
- callsite = null;
|
||||||
|
- action = null;
|
||||||
|
- ci = null;
|
||||||
|
- return;
|
||||||
|
+ //printf("language specific data is null\n");
|
||||||
|
+ return;
|
||||||
|
}
|
||||||
|
|
||||||
|
- //TODO: Do proper DWARF reading here
|
||||||
|
- if(*data++ != 0xff)
|
||||||
|
- fatalerror("DWARF header has unexpected format 1");
|
||||||
|
+ region.start = _Unwind_GetRegionStart(context);
|
||||||
|
|
||||||
|
- if(*data++ != 0x00)
|
||||||
|
- fatalerror("DWARF header has unexpected format 2");
|
||||||
|
- size_t cioffset;
|
||||||
|
- data = get_uleb128(data, cioffset);
|
||||||
|
- ci = cast(ClassInfo*)(data + cioffset);
|
||||||
|
+ // Read the C++-style LSDA: this is implementation-defined by GCC but LLVM
|
||||||
|
+ // outputs the same kind of table
|
||||||
|
|
||||||
|
- if(*data++ != 0x03)
|
||||||
|
- fatalerror("DWARF header has unexpected format 3");
|
||||||
|
- size_t callsitelength;
|
||||||
|
- data = get_uleb128(data, callsitelength);
|
||||||
|
- action = data + callsitelength;
|
||||||
|
+ // Get @LPStart: landing pad offsets are relative to it
|
||||||
|
+ auto lpStartEnc = *data++;
|
||||||
|
+ if (lpStartEnc == DW_EH_PE_omit)
|
||||||
|
+ region.lpStart_base = region.start;
|
||||||
|
+ else
|
||||||
|
+ data = read_encoded(context, lpStartEnc, data, region.lpStart_base);
|
||||||
|
|
||||||
|
- callsite = data;
|
||||||
|
+ // Get @TType: the offset to the handler and typeinfo
|
||||||
|
+ region.ttypeEnc = *data++;
|
||||||
|
+ if (region.ttypeEnc == DW_EH_PE_omit)
|
||||||
|
+ // Not sure about this one...
|
||||||
|
+ fatalerror("@TType must not be omitted from DWARF header");
|
||||||
|
+
|
||||||
|
+ size_t ciOffset;
|
||||||
|
+ data = get_uleb128(data, ciOffset);
|
||||||
|
+ region.classinfo_table = data + ciOffset;
|
||||||
|
+
|
||||||
|
+ region.ttype_base = base_of_encoded(context, region.ttypeEnc);
|
||||||
|
+
|
||||||
|
+ // Get encoding and length of the call site table, which precedes the action
|
||||||
|
+ // table.
|
||||||
|
+ region.callSiteEnc = *data++;
|
||||||
|
+ if (region.callSiteEnc == DW_EH_PE_omit)
|
||||||
|
+ fatalerror("Call site table encoding must not be omitted from DWARF header");
|
||||||
|
+
|
||||||
|
+ size_t callSiteLength;
|
||||||
|
+ region.callsite_table = get_uleb128(data, callSiteLength);
|
||||||
|
+ region.action_table = region.callsite_table + callSiteLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // end of x86 Linux specific implementation
|
||||||
|
|
||||||
|
-
|
||||||
|
-extern(C) void _d_throw_exception(Object e)
|
||||||
|
+// called to throw object
|
||||||
|
+extern(C)
|
||||||
|
+void _d_throw_exception(Object e)
|
||||||
|
{
|
||||||
|
+ //printf("throwing %p, rtti = %p\n", e, **cast(ClassRTTI***)e);
|
||||||
|
if (e !is null)
|
||||||
|
{
|
||||||
|
_d_exception* exc_struct = new _d_exception;
|
||||||
|
exc_struct.unwind_info.exception_class = *cast(ulong*)_d_exception_class.ptr;
|
||||||
|
exc_struct.exception_object = e;
|
||||||
|
_Unwind_Reason_Code ret = _Unwind_RaiseException(&exc_struct.unwind_info);
|
||||||
|
- console("_Unwind_RaiseException failed with reason code: ")(ret)("\n");
|
||||||
|
+ printf("Error: returned %d from raise exception.\n", ret);
|
||||||
|
+ //console("_Unwind_RaiseException failed with reason code: ")(ret)("\n");
|
||||||
|
}
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
-extern(C) void _d_eh_resume_unwind(_d_exception* exception_struct)
|
||||||
|
+// called to resume unwinding
|
||||||
|
+extern(C)
|
||||||
|
+void _d_eh_resume_unwind(void* exception_struct)
|
||||||
|
{
|
||||||
|
- _Unwind_Resume(&exception_struct.unwind_info);
|
||||||
|
+ _Unwind_Resume(&(cast(_d_exception*)exception_struct).unwind_info);
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue