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