# HG changeset patch # User Tomas Lindquist Olsen # Date 1235653909 -3600 # Node ID 2667e3a145beff79531fe9707755cf015692511f # Parent 73ff89728d85d422d6b2437fdfff226826266174 - Fixed LLVM style CL args for D2. - Moved main() into its own file gen/main.cpp - Fixed basic cross compilation - removed the option for setting OS - added support for llc's mattr, mcpu and mtriple switches - added basic ABI abstraction for return value rewrites, it's not perfect and will probably be completely rewritten once I get to handling parameter rewrites as well. - x86-64 extern(C) abi for cfloat returns now match (llvm-)gcc. diff -r 73ff89728d85 -r 2667e3a145be dmd/cond.h --- a/dmd/cond.h Wed Feb 25 19:30:06 2009 +0100 +++ b/dmd/cond.h Thu Feb 26 14:11:49 2009 +0100 @@ -55,8 +55,8 @@ struct DebugCondition : DVCondition { static void setGlobalLevel(unsigned level); - static void addGlobalIdent(char *ident); - static void addPredefinedGlobalIdent(char *ident); + static void addGlobalIdent(const char *ident); + static void addPredefinedGlobalIdent(const char *ident); DebugCondition(Module *mod, unsigned level, Identifier *ident); @@ -67,9 +67,9 @@ struct VersionCondition : DVCondition { static void setGlobalLevel(unsigned level); - static void checkPredefined(Loc loc, char *ident); - static void addGlobalIdent(char *ident); - static void addPredefinedGlobalIdent(char *ident); + static void checkPredefined(Loc loc, const char *ident); + static void addGlobalIdent(const char *ident); + static void addPredefinedGlobalIdent(const char *ident); VersionCondition(Module *mod, unsigned level, Identifier *ident); diff -r 73ff89728d85 -r 2667e3a145be dmd/inifile.c --- a/dmd/inifile.c Wed Feb 25 19:30:06 2009 +0100 +++ b/dmd/inifile.c Thu Feb 26 14:11:49 2009 +0100 @@ -47,7 +47,7 @@ * inifile .ini file name */ -void inifile(char *argv0, char *inifile) +void inifile(char *argv0, const char *inifile) { char *path; // need path for @P macro char *filename; diff -r 73ff89728d85 -r 2667e3a145be dmd/mars.c --- a/dmd/mars.c Wed Feb 25 19:30:06 2009 +0100 +++ b/dmd/mars.c Thu Feb 26 14:11:49 2009 +0100 @@ -36,48 +36,8 @@ #include "expression.h" #include "lexer.h" -#include "gen/logger.h" -#include "gen/linker.h" #include "revisions.h" -#include "gen/cl_options.h" -#include "gen/cl_helpers.h" -using namespace opts; - - -static cl::opt forceBE("forcebe", - cl::desc("Force big-endian"), - cl::Hidden, - cl::ZeroOrMore); - -static cl::opt noDefaultLib("nodefaultlib", - cl::desc("Don't add a default library for linking implicitly"), - cl::ZeroOrMore); - -static ArrayAdapter impPathsStore("I", global.params.imppath); -static cl::list importPaths("I", - cl::desc("Where to look for imports"), - cl::value_desc("path"), - cl::location(impPathsStore), - cl::Prefix); - -static ArrayAdapter defaultLibStore("defaultlib", global.params.defaultlibnames); -static cl::list defaultlibs("defaultlib", - cl::desc("Set default libraries for non-debug build"), - cl::value_desc("lib,..."), - cl::location(defaultLibStore), - cl::CommaSeparated); - -static ArrayAdapter debugLibStore("debuglib", global.params.debuglibnames); -static cl::list debuglibs("debuglib", - cl::desc("Set default libraries for debug build"), - cl::value_desc("lib,..."), - cl::location(debugLibStore), - cl::CommaSeparated); - - -void getenv_setargv(const char *envvar, int *pargc, char** *pargv); - Global global; Global::Global() @@ -187,763 +147,6 @@ #endif } -extern void backend_init(); -extern void backend_term(); - -void printVersion() { - printf("LLVM D Compiler %s\nbased on DMD %s and %s\n%s\n%s\n", - global.ldc_version, global.version, global.llvm_version, global.copyright, global.written); - printf("D Language Documentation: http://www.digitalmars.com/d/1.0/index.html\n" - "LDC Homepage: http://www.dsource.org/projects/ldc\n"); -} - -// Helper function to handle -d-debug=* and -d-version=* -static void processVersions(std::vector& list, char* type, - void (*setLevel)(unsigned), void (*addIdent)(char*)) { - typedef std::vector::iterator It; - - for(It I = list.begin(), E = list.end(); I != E; ++I) { - const char* value = I->c_str(); - if (isdigit(value[0])) { - errno = 0; - char* end; - long level = strtol(value, &end, 10); - if (*end || errno || level > INT_MAX) { - error("Invalid %s level: %s", type, I->c_str()); - } else { - setLevel((unsigned)level); - } - } else { - char* cstr = mem.strdup(value); - if (Lexer::isValidIdentifier(cstr)) { - addIdent(cstr); - continue; - } else { - error("Invalid %s identifier or level: '%s'", type, I->c_str()); - } - } - } -} - -// Helper function to handle -of, -od, etc. -static void initFromString(char*& dest, const cl::opt& src) { - dest = 0; - if (src.getNumOccurrences() != 0) { - if (src.empty()) - error("Expected argument to '-%s'", src.ArgStr); - dest = mem.strdup(src.c_str()); - } -} - -int main(int argc, char *argv[]) -{ - int i; - Array files; - char *p, *ext; - Module *m; - int status = EXIT_SUCCESS; - - // Set default values -#if _WIN32 - char buf[MAX_PATH]; - GetModuleFileName(NULL, buf, MAX_PATH); - global.params.argv0 = buf; -#else - global.params.argv0 = argv[0]; -#endif - global.params.useSwitchError = 1; - - global.params.linkswitches = new Array(); - global.params.libfiles = new Array(); - global.params.objfiles = new Array(); - global.params.ddocfiles = new Array(); - - global.params.is64bit = sizeof(void*) == 8 ? 1 : 0; - - uint16_t endiantest = 0xFF00; - uint8_t endianres = ((uint8_t*)&endiantest)[0]; - if (endianres == 0x00) - global.params.isLE = true; - else if (endianres == 0xFF) - global.params.isLE = false; - else { - error("Endian test is broken"); - fatal(); - } - - // Predefine version identifiers -#if IN_LLVM - VersionCondition::addPredefinedGlobalIdent("LLVM"); - VersionCondition::addPredefinedGlobalIdent("LDC"); -#endif - - // setup default target os to be build os -#if _WIN32 - global.params.os = OSWindows; -#elif linux - global.params.os = OSLinux; -#elif __APPLE__ - global.params.os = OSMacOSX; -#elif __FreeBSD__ - global.params.os = OSFreeBSD; -#elif defined (__SVR4) && defined (__sun) - global.params.os = OSSolaris; -#else - #error Unsupported OS -#endif /* linux */ - - assert(global.params.os != OSinvalid); - - //VersionCondition::addPredefinedGlobalIdent("D_Bits"); - VersionCondition::addPredefinedGlobalIdent("all"); - -//#if _WIN32 -// inifile(global.params.argv0, "ldc.ini"); -//#elif POSIX - inifile(global.params.argv0, "ldc.conf"); -//#else -//#error -//#endif - getenv_setargv("DFLAGS", &argc, &argv); - -#if 0 - for (i = 0; i < argc; i++) - { - printf("argv[%d] = '%s'\n", i, argv[i]); - } -#endif - - cl::SetVersionPrinter(&printVersion); - cl::ParseCommandLineOptions(argc, argv, "LLVM-based D Compiler\n"); - - global.params.optimize = (global.params.optimizeLevel >= 0); - - // Negated options - global.params.link = !compileOnly; - global.params.obj = !dontWriteObj; - global.params.useInlineAsm = !noAsm; - - // 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); - global.params.doHdrGeneration |= - global.params.hdrdir || global.params.hdrname; -#endif - - processVersions(debugArgs, "debug", - DebugCondition::setGlobalLevel, - DebugCondition::addGlobalIdent); - processVersions(versions, "version", - VersionCondition::setGlobalLevel, - VersionCondition::addGlobalIdent); - - global.params.output_o = - opts::output_o == cl::BOU_UNSET - ? OUTPUTFLAGdefault - : opts::output_o == cl::BOU_TRUE - ? OUTPUTFLAGset - : OUTPUTFLAGno; - global.params.output_bc = opts::output_bc ? OUTPUTFLAGset : OUTPUTFLAGno; - global.params.output_ll = opts::output_ll ? OUTPUTFLAGset : OUTPUTFLAGno; - global.params.output_s = opts::output_s ? OUTPUTFLAGset : OUTPUTFLAGno; - - if (global.params.run || !runargs.empty()) { - // FIXME: how to properly detect the presence of a PositionalEatsArgs - // option without parameters? We want to emit an error in that case... - // You'd think getNumOccurrences would do it, but it just returns the - // number of parameters) - // NOTE: Hacked around it by detecting -run in getenv_setargv(), where - // we're looking for it anyway, and pre-setting the flag... - global.params.run = true; - if (!runargs.empty()) { - files.push(mem.strdup(runargs[0].c_str())); - } else { - global.params.run = false; - error("Expected at least one argument to '-run'\n"); - } - } - - if (mArch) - global.params.llvmArch = mArch->Name; - - files.reserve(fileList.size()); - typedef std::vector::iterator It; - for(It I = fileList.begin(), E = fileList.end(); I != E; ++I) - if (!I->empty()) - files.push(mem.strdup(I->c_str())); - - if (global.errors) - { - fatal(); - } - if (files.dim == 0) - { - cl::PrintHelpMessage(); - return EXIT_FAILURE; - } - - Array* libs; - if (global.params.symdebug) - libs = global.params.debuglibnames; - else - libs = global.params.defaultlibnames; - - if (libs) - { - for (int i = 0; i < libs->dim; i++) - { - char *arg = (char *)mem.malloc(64); - strcpy(arg, "-l"); - strncat(arg, (char *)libs->data[i], 64); - global.params.linkswitches->push(arg); - } - } - else if (!noDefaultLib) - { - char *arg; - arg = (char *)mem.malloc(64); - strcpy(arg, "-lldc-runtime"); - global.params.linkswitches->push(arg); - arg = (char *)mem.malloc(64); - strcpy(arg, "-ltango-cc-tango"); - global.params.linkswitches->push(arg); - arg = (char *)mem.malloc(64); - strcpy(arg, "-ltango-gc-basic"); - global.params.linkswitches->push(arg); - // pass the runtime again to resolve issues - // with linking order - arg = (char *)mem.malloc(64); - strcpy(arg, "-lldc-runtime"); - global.params.linkswitches->push(arg); - } - - if (global.params.run) - quiet = 1; - - if (global.params.useUnitTests) - global.params.useAssert = 1; - - // LDC output determination - - // if we don't link, autodetect target from extension - if(!global.params.link && global.params.objname) { - ext = FileName::ext(global.params.objname); - bool autofound = false; - if (!ext) { - // keep things as they are - } else if (strcmp(ext, global.ll_ext) == 0) { - global.params.output_ll = OUTPUTFLAGset; - autofound = true; - } else if (strcmp(ext, global.bc_ext) == 0) { - global.params.output_bc = OUTPUTFLAGset; - autofound = true; - } else if (strcmp(ext, global.s_ext) == 0) { - global.params.output_s = OUTPUTFLAGset; - autofound = true; - } else if (strcmp(ext, global.obj_ext) == 0) { - global.params.output_o = OUTPUTFLAGset; - autofound = true; - } else { - // append dot, so forceExt won't change existing name even if it contains dots - size_t len = strlen(global.params.objname); - size_t extlen = strlen("."); - char* s = (char *)mem.malloc(len + 1 + extlen + 1); - memcpy(s, global.params.objname, len); - s[len] = '.'; - s[len+1+extlen] = 0; - global.params.objname = s; - - } - if(autofound && global.params.output_o == OUTPUTFLAGdefault) - global.params.output_o = OUTPUTFLAGno; - } - - // only link if possible - if (!global.params.obj || !global.params.output_o) - global.params.link = 0; - - if (global.params.link) - { - global.params.exefile = global.params.objname; - if (files.dim > 1) - global.params.objname = NULL; - } - else if (global.params.run) - { - error("flags conflict with -run"); - fatal(); - } - else - { - if (global.params.objname && files.dim > 1) - { - error("multiple source files, but only one .obj name"); - fatal(); - } - } - - bool allowForceEndianness = false; - - if (global.params.llvmArch == 0) { - #if defined(__x86_64__) || defined(_M_X64) - global.params.llvmArch = "x86-64"; - #elif defined(__i386__) || defined(_M_IX86) - global.params.llvmArch = "x86"; - #elif defined(__ppc__) || defined(_M_PPC) - if (global.params.is64bit) - global.params.llvmArch = "ppc64"; - else - global.params.llvmArch = "ppc32"; - #elif defined(__arm__) - global.params.llvmArch = "arm"; - #elif defined(__thumb__) - global.params.llvmArch = "thumb"; - #else - #error - #endif - } - - if (strcmp(global.params.llvmArch,"x86")==0) { - VersionCondition::addPredefinedGlobalIdent("X86"); - global.params.isLE = true; - global.params.is64bit = false; - global.params.cpu = ARCHx86; - if (global.params.useInlineAsm) { - VersionCondition::addPredefinedGlobalIdent("LLVM_InlineAsm_X86"); - } - } - else if (strcmp(global.params.llvmArch,"x86-64")==0) { - VersionCondition::addPredefinedGlobalIdent("X86_64"); - global.params.isLE = true; - global.params.is64bit = true; - global.params.cpu = ARCHx86_64; - if (global.params.useInlineAsm) { - VersionCondition::addPredefinedGlobalIdent("LLVM_InlineAsm_X86_64"); - } - } - else if (strcmp(global.params.llvmArch,"ppc32")==0) { - VersionCondition::addPredefinedGlobalIdent("PPC"); - global.params.isLE = false; - global.params.is64bit = false; - global.params.cpu = ARCHppc; - } - else if (strcmp(global.params.llvmArch,"ppc64")==0) { - VersionCondition::addPredefinedGlobalIdent("PPC64"); - global.params.isLE = false; - global.params.is64bit = true; - global.params.cpu = ARCHppc_64; - } - else if (strcmp(global.params.llvmArch,"arm")==0) { - VersionCondition::addPredefinedGlobalIdent("ARM"); - global.params.isLE = true; - global.params.is64bit = false; - global.params.cpu = ARCHarm; - } - else if (strcmp(global.params.llvmArch,"thumb")==0) { - VersionCondition::addPredefinedGlobalIdent("Thumb"); - global.params.isLE = true; - global.params.is64bit = false; - global.params.cpu = ARCHthumb; - } - else { - error("invalid cpu architecture specified: %s", global.params.llvmArch); - } - - assert(global.params.cpu != ARCHinvalid); - - if (allowForceEndianness && forceBE) { - VersionCondition::addPredefinedGlobalIdent("BigEndian"); - global.params.isLE = false; - } - else if (global.params.isLE) { - VersionCondition::addPredefinedGlobalIdent("LittleEndian"); - } - else { - VersionCondition::addPredefinedGlobalIdent("BigEndian"); - } - - if (global.params.is64bit) { - VersionCondition::addPredefinedGlobalIdent("LLVM64"); - } - - - // setup version idents and tt_os for chosen target os - switch(global.params.os) - { - case OSWindows: - // TODO Win64 stuff! - VersionCondition::addPredefinedGlobalIdent("Windows"); - VersionCondition::addPredefinedGlobalIdent("Win32"); - VersionCondition::addPredefinedGlobalIdent("mingw32"); - break; - - case OSLinux: - VersionCondition::addPredefinedGlobalIdent("linux"); - VersionCondition::addPredefinedGlobalIdent("Posix"); - break; - - case OSMacOSX: - VersionCondition::addPredefinedGlobalIdent("OSX"); - VersionCondition::addPredefinedGlobalIdent("darwin"); - VersionCondition::addPredefinedGlobalIdent("Posix"); - break; - - case OSFreeBSD: - VersionCondition::addPredefinedGlobalIdent("freebsd"); - VersionCondition::addPredefinedGlobalIdent("Posix"); - break; - - case OSSolaris: - VersionCondition::addPredefinedGlobalIdent("solaris"); - VersionCondition::addPredefinedGlobalIdent("Posix"); - break; - - default: - assert(false && "Target OS not supported"); - } - - if (!global.params.targetTriple) - global.params.targetTriple = DEFAULT_TARGET_TRIPLE; - - Logger::println("Target triple: %s", global.params.targetTriple); - - // build a minimal data layout so llvm can find the target - global.params.dataLayout = global.params.isLE - ? (char*)(global.params.is64bit ? "e-p:64:64" : "e-p:32:32") - : (char*)(global.params.is64bit ? "E-p:64:64" : "E-p:32:32"); - Logger::println("Layout: %s", global.params.dataLayout); - - // added in 1.039 - if (global.params.doDocComments) - VersionCondition::addPredefinedGlobalIdent("D_Ddoc"); - - // Initialization - Type::init(); - Id::initialize(); - Module::init(); - initPrecedence(); - - backend_init(); - - //printf("%d source files\n",files.dim); - - // Build import search path - if (global.params.imppath) - { - for (i = 0; i < global.params.imppath->dim; i++) - { - char *path = (char *)global.params.imppath->data[i]; - Array *a = FileName::splitPath(path); - - if (a) - { - if (!global.path) - global.path = new Array(); - global.path->append(a); - } - } - } - - // Build string import search path - if (global.params.fileImppath) - { - for (i = 0; i < global.params.fileImppath->dim; i++) - { - char *path = (char *)global.params.fileImppath->data[i]; - Array *a = FileName::splitPath(path); - - if (a) - { - if (!global.filePath) - global.filePath = new Array(); - global.filePath->append(a); - } - } - } - - // Create Modules - Array modules; - modules.reserve(files.dim); - for (i = 0; i < files.dim; i++) - { Identifier *id; - char *ext; - char *name; - - p = (char *) files.data[i]; - - p = FileName::name(p); // strip path - ext = FileName::ext(p); - if (ext) - { -#if POSIX - if (strcmp(ext, global.obj_ext) == 0 || - strcmp(ext, global.bc_ext) == 0) -#else - if (stricmp(ext, global.obj_ext) == 0 || - stricmp(ext, global.bc_ext) == 0) -#endif - { - global.params.objfiles->push(files.data[i]); - continue; - } - -#if POSIX - if (strcmp(ext, "a") == 0) -#elif __MINGW32__ - if (stricmp(ext, "a") == 0) -#else - if (stricmp(ext, "lib") == 0) -#endif - { - global.params.libfiles->push(files.data[i]); - continue; - } - - if (strcmp(ext, global.ddoc_ext) == 0) - { - global.params.ddocfiles->push(files.data[i]); - continue; - } - -#if !POSIX - if (stricmp(ext, "res") == 0) - { - global.params.resfile = (char *)files.data[i]; - continue; - } - - if (stricmp(ext, "def") == 0) - { - global.params.deffile = (char *)files.data[i]; - continue; - } - - if (stricmp(ext, "exe") == 0) - { - global.params.exefile = (char *)files.data[i]; - continue; - } -#endif - - if (stricmp(ext, global.mars_ext) == 0 || - stricmp(ext, global.hdr_ext) == 0 || - stricmp(ext, "htm") == 0 || - stricmp(ext, "html") == 0 || - stricmp(ext, "xhtml") == 0) - { - ext--; // skip onto '.' - assert(*ext == '.'); - name = (char *)mem.malloc((ext - p) + 1); - memcpy(name, p, ext - p); - name[ext - p] = 0; // strip extension - - if (name[0] == 0 || - strcmp(name, "..") == 0 || - strcmp(name, ".") == 0) - { - Linvalid: - error("invalid file name '%s'", (char *)files.data[i]); - fatal(); - } - } - else - { error("unrecognized file extension %s\n", ext); - fatal(); - } - } - else - { name = p; - if (!*name) - goto Linvalid; - } - - id = new Identifier(name, 0); - m = new Module((char *) files.data[i], id, global.params.doDocComments, global.params.doHdrGeneration); - modules.push(m); - } - - // Read files, parse them - for (i = 0; i < modules.dim; i++) - { - m = (Module *)modules.data[i]; - if (global.params.verbose) - printf("parse %s\n", m->toChars()); - if (!Module::rootModule) - Module::rootModule = m; - m->importedFrom = m; - m->read(0); - m->parse(); - m->buildTargetFiles(); - m->deleteObjFile(); - if (m->isDocFile) - { - m->gendocfile(); - - // Remove m from list of modules - modules.remove(i); - i--; - } - } - if (global.errors) - fatal(); -#ifdef _DH - if (global.params.doHdrGeneration) - { - /* Generate 'header' import files. - * Since 'header' import files must be independent of command - * line switches and what else is imported, they are generated - * before any semantic analysis. - */ - for (i = 0; i < modules.dim; i++) - { - m = (Module *)modules.data[i]; - if (global.params.verbose) - printf("import %s\n", m->toChars()); - m->genhdrfile(); - } - } - if (global.errors) - fatal(); -#endif - - // Do semantic analysis - for (i = 0; i < modules.dim; i++) - { - m = (Module *)modules.data[i]; - if (global.params.verbose) - printf("semantic %s\n", m->toChars()); - m->semantic(); - } - if (global.errors) - fatal(); - - // Do pass 2 semantic analysis - for (i = 0; i < modules.dim; i++) - { - m = (Module *)modules.data[i]; - if (global.params.verbose) - printf("semantic2 %s\n", m->toChars()); - m->semantic2(); - } - if (global.errors) - fatal(); - - // Do pass 3 semantic analysis - for (i = 0; i < modules.dim; i++) - { - m = (Module *)modules.data[i]; - if (global.params.verbose) - printf("semantic3 %s\n", m->toChars()); - m->semantic3(); - } - if (global.errors) - fatal(); - -#if !IN_LLVM - // Scan for functions to inline - if (global.params.useInline) - { - /* The problem with useArrayBounds and useAssert is that the - * module being linked to may not have generated them, so if - * we inline functions from those modules, the symbols for them will - * not be found at link time. - */ - if (!global.params.useArrayBounds && !global.params.useAssert) - { -#endif - // Do pass 3 semantic analysis on all imported modules, - // since otherwise functions in them cannot be inlined - for (i = 0; i < Module::amodules.dim; i++) - { - m = (Module *)Module::amodules.data[i]; - if (global.params.verbose) - printf("semantic3 %s\n", m->toChars()); - m->semantic3(); - } - if (global.errors) - fatal(); -#if !IN_LLVM - } - - for (i = 0; i < modules.dim; i++) - { - m = (Module *)modules.data[i]; - if (global.params.verbose) - printf("inline scan %s\n", m->toChars()); - m->inlineScan(); - } - } -#endif - if (global.errors) - fatal(); - - // Generate output files - for (i = 0; i < modules.dim; i++) - { - m = (Module *)modules.data[i]; - if (global.params.verbose) - printf("code %s\n", m->toChars()); - if (global.params.obj) - { - m->genobjfile(0); - global.params.objfiles->push(m->objfile->name->str); - } - if (global.errors) - m->deleteObjFile(); - else - { - if (global.params.doDocComments) - m->gendocfile(); - } - } - - backend_term(); - if (global.errors) - fatal(); - - if (!global.params.objfiles->dim) - { - if (global.params.link) - error("no object files to link"); - } - else - { - if (global.params.link) - //status = runLINK(); - linkObjToExecutable(global.params.argv0); - - if (global.params.run) - { - if (!status) - { - status = runExectuable(); - - /* Delete .obj files and .exe file - */ - for (i = 0; i < modules.dim; i++) - { - m = (Module *)modules.data[i]; - m->deleteObjFile(); - } - deleteExecutable(); - } - } - } - - return status; -} - - - /*********************************** * Parse and append contents of environment variable envvar * to argc and argv[]. diff -r 73ff89728d85 -r 2667e3a145be dmd/mars.h --- a/dmd/mars.h Wed Feb 25 19:30:06 2009 +0100 +++ b/dmd/mars.h Thu Feb 26 14:11:49 2009 +0100 @@ -144,7 +144,6 @@ char *exefile; // LDC stuff - const char *llvmArch; OUTPUTFLAG output_ll; OUTPUTFLAG output_bc; OUTPUTFLAG output_s; @@ -154,8 +153,9 @@ bool useInlineAsm; // target stuff - char *targetTriple; - char *dataLayout; + const char* llvmArch; + const char *targetTriple; + const char *dataLayout; }; struct Global @@ -341,7 +341,7 @@ void verror(Loc loc, const char *format, va_list); void fatal(); void err_nomem(); -void inifile(char *argv0, char *inifile); +void inifile(char *argv0, const char *inifile); void halt(); /*** Where to send error messages ***/ diff -r 73ff89728d85 -r 2667e3a145be dmd2/attrib.c --- a/dmd2/attrib.c Wed Feb 25 19:30:06 2009 +0100 +++ b/dmd2/attrib.c Thu Feb 26 14:11:49 2009 +0100 @@ -33,6 +33,15 @@ #include "../gen/enums.h" + +#include "llvm/Support/CommandLine.h" + +static llvm::cl::opt ignoreUnsupportedPragmas("ignore", + llvm::cl::desc("Ignore unsupported pragmas"), + llvm::cl::ZeroOrMore); + + + extern void obj_includelib(const char *name); void obj_startaddress(Symbol *s); @@ -1001,7 +1010,7 @@ ///////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////// - else if (global.params.ignoreUnsupportedPragmas) + else if (ignoreUnsupportedPragmas) { if (global.params.verbose) { diff -r 73ff89728d85 -r 2667e3a145be dmd2/inifile.c --- a/dmd2/inifile.c Wed Feb 25 19:30:06 2009 +0100 +++ b/dmd2/inifile.c Thu Feb 26 14:11:49 2009 +0100 @@ -43,7 +43,7 @@ * inifile .ini file name */ -void inifile(const char *argv0x, const char *inifilex) +void inifile(char *argv0x, const char *inifilex) { char *argv0 = (char *)argv0x; char *inifile = (char *)inifilex; // do const-correct later diff -r 73ff89728d85 -r 2667e3a145be dmd2/mars.c --- a/dmd2/mars.c Wed Feb 25 19:30:06 2009 +0100 +++ b/dmd2/mars.c Thu Feb 26 14:11:49 2009 +0100 @@ -1,5 +1,5 @@ // Compiler implementation of the D programming language -// Copyright (c) 1999-2008 by Digital Mars +// Copyright (c) 1999-2009 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -36,13 +36,8 @@ #include "expression.h" #include "lexer.h" -#include "gen/logger.h" -#include "gen/linker.h" - #include "revisions.h" -void getenv_setargv(const char *envvar, int *pargc, char** *pargv); - Global global; Global::Global() @@ -62,27 +57,32 @@ obj_ext_alt = "obj"; #endif - copyright = "Copyright (c) 1999-2008 by Digital Mars and Tomas Lindquist Olsen"; + copyright = "Copyright (c) 1999-2009 by Digital Mars and Tomas Lindquist Olsen"; written = "written by Walter Bright and Tomas Lindquist Olsen"; version = "v2.021"; - ldc_version = "0.1"; + ldc_version = LDC_REV; + llvm_version = LLVM_REV; global.structalign = 8; - memset(¶ms, 0, sizeof(Param)); + // This should only be used as a global, so the other fields are + // automatically initialized to zero when the program is loaded. + // In particular, DO NOT zero-initialize .params here (like DMD + // does) because command-line options initialize some of those + // fields to non-zero defaults, and do so from constructors that + // may run before this one. } char *Loc::toChars() const { OutBuffer buf; - char *p; if (filename) { - buf.printf("%s", filename); + buf.printf("%s", filename); } if (linnum) - buf.printf("(%d)", linnum); + buf.printf("(%d)", linnum); buf.writeByte(0); return (char *)buf.extractData(); } @@ -109,16 +109,16 @@ { if (!global.gag) { - char *p = loc.toChars(); + char *p = loc.toChars(); - if (*p) - fprintf(stdmsg, "%s: ", p); - mem.free(p); + if (*p) + fprintf(stdmsg, "%s: ", p); + mem.free(p); - fprintf(stdmsg, "Error: "); - vfprintf(stdmsg, format, ap); - fprintf(stdmsg, "\n"); - fflush(stdmsg); + fprintf(stdmsg, "Error: "); + vfprintf(stdmsg, format, ap); + fprintf(stdmsg, "\n"); + fflush(stdmsg); } global.errors++; } @@ -147,1154 +147,6 @@ #endif } -extern void backend_init(); -extern void backend_term(); - -void usage() -{ - printf("LLVM D Compiler %s\nbased on DMD %s and %s\n%s\n%s\n", - global.ldc_version, global.version, global.llvm_version, global.copyright, global.written); - printf("\ -D Language Documentation: http://www.digitalmars.com/d/2.0/index.html\n\ -LDC Homepage: http://www.dsource.org/projects/ldc\n\ -Usage:\n\ - ldc files.d ... { -switch }\n\ -\n\ - files.d D source files\n%s\ - -o- do not write object file\n\ - -od write object files to directory \n\ - -op do not strip paths from source file\n\ - -oq write object files with fully qualified names\n\ - -of name output file to \n\ - if -c and extension of is known, it determines the output type\n\ -\n\ - -output-ll write LLVM IR\n\ - -output-bc write LLVM bitcode\n\ - -output-s write native assembly\n\ - -output-o write native object (default if no -output switch passed)\n\ -\n\ - -c do not link\n\ - -L pass to linker\n\ -\n\ - -w enable warnings\n\ -\n\ - -H generate 'header' file\n\ - -Hd write 'header' file to directory\n\ - -Hf write 'header' file to \n\ -\n\ - -D generate documentation\n\ - -Dd write documentation file to directory\n\ - -Df write documentation file to \n\ -\n\ -Codegen control:\n\ - -m emit code specific to being one of:\n\ - x86 x86-64 ppc32 ppc64 arm thumb\n\ - -t emit code specific to being one of:\n\ - Linux, Windows, MacOSX, FreeBSD, Solaris\n\ -\n\ - -g, -gc add symbolic debug info\n\ -\n\ - -O optimize, same as -O2\n\ - -O optimize at level (0-5)\n\ - -inline do function inlining\n\ -\n\ - -debug enables asserts, invariants, contracts, boundscheck\n\ - and sets debug=1\n\ - -release disables asserts, invariants, contracts, boundscheck\n\ -\n\ - -enable- and\n\ - -disable- where is one of\n\ - asserts assert statements (default: on)\n\ - invariants class and struct invariants (default: on)\n\ - contracts function contracts (default: on)\n\ - boundscheck array bounds checking (default: on)\n\ - -debug=level compile in debug stmts <= level (default: 0)\n\ - -debug=ident compile in debug stmts identified by ident\n\ - -version=level compile in version code >= level\n\ - -version=ident compile in version code identified by ident\n\ -\n\ - -noasm do not allow use of inline asm\n\ - -noruntime do not allow code that generates implicit runtime calls\n\ - -noverify do not run the validation pass before writing bitcode\n\ - -unittest compile in unit tests\n\ - -d allow deprecated features\n\ -\n\ - -annotate annotate the bitcode with human readable source code\n\ - -ignore ignore unsupported pragmas\n\ -\n\ -Path options:\n\ - -I where to look for imports\n\ - -J where to look for string imports\n\ - -defaultlib=name set default library for non-debug build\n\ - -debuglib=name set default library for debug build\n\ - -nodefaultlib don't add a default library for linking implicitly\n\ -\n\ -Misc options:\n\ - -v verbose\n\ - -vv very verbose (does not include -v)\n\ - -quiet suppress unnecessary messages\n\ - -run srcfile args... run resulting program, passing args\n\ - --help print help\n\ -", -#if WIN32 -" @cmdfile read arguments from cmdfile\n" -#else -"" -#endif -); -} - -int main(int argc, char *argv[]) -{ - int i; - Array files; - char *p, *ext; - Module *m; - int status = EXIT_SUCCESS; - int argcstart = argc; - bool very_verbose = false; - - // Check for malformed input - if (argc < 1 || !argv) - { - Largs: - error("missing or null command line arguments"); - fatal(); - } - for (i = 0; i < argc; i++) - { - if (!argv[i]) - goto Largs; - } - -#if __DMC__ // DMC unique support for response files - if (response_expand(&argc,&argv)) // expand response files - error("can't open response file"); -#endif - - files.reserve(argc - 1); - - // Set default values -#if _WIN32 - char buf[MAX_PATH]; - GetModuleFileName(NULL, buf, MAX_PATH); - global.params.argv0 = buf; -#else - global.params.argv0 = argv[0]; -#endif - global.params.link = 1; - global.params.useAssert = 1; - global.params.useInvariants = 1; - global.params.useIn = 1; - global.params.useOut = 1; - global.params.useArrayBounds = 1; - global.params.useSwitchError = 1; - global.params.useInline = 0; // this one messes things up to a point where codegen breaks - global.params.llvmInline = 0; // use this one instead to know if inline passes should be run - global.params.obj = 1; - global.params.Dversion = 2; - global.params.quiet = 1; - - global.params.output_o = OUTPUTFLAGdefault; - - global.params.linkswitches = new Array(); - global.params.libfiles = new Array(); - global.params.objfiles = new Array(); - global.params.ddocfiles = new Array(); - - global.params.is64bit = sizeof(void*) == 8 ? 1 : 0; - - uint16_t endiantest = 0xFF00; - uint8_t endianres = ((uint8_t*)&endiantest)[0]; - if (endianres == 0x00) - global.params.isLE = true; - else if (endianres == 0xFF) - global.params.isLE = false; - else { - error("Endian test is broken"); - fatal(); - } - - global.params.llvmArch = 0; - global.params.forceBE = 0; - global.params.noruntime = 0; - global.params.novalidate = 0; - global.params.optimizeLevel = -1; - global.params.runtimeImppath = 0; - global.params.useInlineAsm = 1; - - // Predefine version identifiers -#if IN_LLVM - VersionCondition::addPredefinedGlobalIdent("LLVM"); - VersionCondition::addPredefinedGlobalIdent("LDC"); -#endif - - // D2 -#if DMDV2 - VersionCondition::addPredefinedGlobalIdent("D_Version2"); -#endif - - // setup default target os to be build os -#if _WIN32 - global.params.os = OSWindows; -#elif linux - global.params.os = OSLinux; -#elif __APPLE__ - global.params.os = OSMacOSX; -#elif __FreeBSD__ - global.params.os = OSFreeBSD; -#elif defined (__SVR4) && defined (__sun) - global.params.os = OSSolaris; -#else -#error Unsupported OS -#endif /* linux */ - - assert(global.params.os != OSinvalid); - - //VersionCondition::addPredefinedGlobalIdent("D_Bits"); - VersionCondition::addPredefinedGlobalIdent("all"); - -//#if _WIN32 - -//#if DMDV2 -// inifile(global.params.argv0, "ldc2.ini"); -//#else -// inifile(global.params.argv0, "ldc.ini"); -//#endif - -//#elif POSIX - -#if DMDV2 - inifile(global.params.argv0, "ldc2.conf"); -#else - inifile(global.params.argv0, "ldc.conf"); -#endif - -//#else -//#error -//#endif - getenv_setargv("DFLAGS", &argc, &argv); - -#if 0 - for (i = 0; i < argc; i++) - { - printf("argv[%d] = '%s'\n", i, argv[i]); - } -#endif - - for (i = 1; i < argc; i++) - { - p = argv[i]; - if (*p == '-') - { - if (strcmp(p + 1, "d") == 0) - global.params.useDeprecated = 1; - else if (strcmp(p + 1, "c") == 0) - global.params.link = 0; - else if (strcmp(p + 1, "fPIC") == 0) - global.params.pic = 1; - else if (strcmp(p + 1, "g") == 0) - global.params.symdebug = 1; - else if (strcmp(p + 1, "gc") == 0) - global.params.symdebug = 2; - else if (strcmp(p + 1, "v") == 0) - global.params.verbose = 1; - else if (strcmp(p + 1, "vv") == 0) { - Logger::enable(); - very_verbose = true; - } - else if (strcmp(p + 1, "v1") == 0) - global.params.Dversion = 1; - else if (strcmp(p + 1, "w") == 0) - global.params.warnings = 1; - else if (p[1] == 'O') - { - global.params.optimize = 1; - global.params.optimizeLevel = 2; - if (p[2] != 0) { - int optlevel = atoi(p+2); - if (optlevel < 0 || optlevel > 5) { - error("Optimization level must be between 0 and 5. Using default (%d)", - global.params.optimizeLevel); - } - else { - global.params.optimizeLevel = optlevel; - } - } - } - else if (strcmp(p + 1, "forcebe") == 0) - global.params.forceBE = 1; - else if (strcmp(p + 1, "noruntime") == 0) - global.params.noruntime = 1; - else if (strcmp(p + 1, "noverify") == 0) - global.params.novalidate = 1; - else if (strcmp(p + 1, "annotate") == 0) - global.params.llvmAnnotate = 1; - else if (strncmp(p + 1, "enable-", 7) == 0 || - strncmp(p + 1, "disable-", 8) == 0) - { - bool enable = (p[1] == 'e'); - char* feature = p + 1 + (enable ? 7 : 8); - if (strcmp(feature, "asserts") == 0) - global.params.useAssert = enable; - else if (strcmp(feature, "boundscheck") == 0) - global.params.useArrayBounds = enable; - else if (strcmp(feature, "contracts") == 0) - { - global.params.useIn = enable; - global.params.useOut = enable; - } - else if (strcmp(feature, "invariants") == 0) - global.params.useInvariants = enable; - else - error("unrecognized feature '%s'", feature); - } - else if (strcmp(p + 1, "noasm") == 0) - global.params.useInlineAsm = 0; - else if (strcmp(p + 1, "nodefaultlib") == 0) - global.params.noDefaultLib = 1; - else if (p[1] == 'o') - { - switch (p[2]) - { - case '-': - global.params.obj = 0; - break; - - case 'd': - if (!p[3]) - goto Lnoarg; - global.params.objdir = p + 3; - break; - - case 'f': - if (!p[3]) - goto Lnoarg; - global.params.objname = p + 3; - break; - - case 'p': - if (p[3]) - goto Lerror; - global.params.preservePaths = 1; - break; - - case 'q': - if (p[3]) - goto Lerror; - global.params.fqnNames = 1; - break; - - case 'u': - if (strncmp(p+1, "output-", 7) != 0) - goto Lerror; - - // remove default output - if (global.params.output_o == OUTPUTFLAGdefault) - global.params.output_o = OUTPUTFLAGno; - - if (strcmp(p+8, global.ll_ext) == 0) - global.params.output_ll = OUTPUTFLAGset; - else if (strcmp(p+8, global.bc_ext) == 0) - global.params.output_bc = OUTPUTFLAGset; - else if (strcmp(p+8, global.s_ext) == 0) - global.params.output_s = OUTPUTFLAGset; - else if (strcmp(p+8, global.obj_ext) == 0) - global.params.output_o = OUTPUTFLAGset; - else - goto Lerror; - - break; - - case 0: - error("-o no longer supported, use -of or -od"); - break; - - default: - goto Lerror; - } - } - else if (p[1] == 'D') - { global.params.doDocComments = 1; - switch (p[2]) - { - case 'd': - if (!p[3]) - goto Lnoarg; - global.params.docdir = p + 3; - break; - case 'f': - if (!p[3]) - goto Lnoarg; - global.params.docname = p + 3; - break; - - case 0: - break; - - default: - goto Lerror; - } - } -#ifdef _DH - else if (p[1] == 'H') - { global.params.doHdrGeneration = 1; - switch (p[2]) - { - case 'd': - if (!p[3]) - goto Lnoarg; - global.params.hdrdir = p + 3; - break; - - case 'f': - if (!p[3]) - goto Lnoarg; - global.params.hdrname = p + 3; - break; - - case 0: - break; - - default: - goto Lerror; - } - } -#endif - else if (strcmp(p + 1, "ignore") == 0) - global.params.ignoreUnsupportedPragmas = 1; - else if (strcmp(p + 1, "inline") == 0) { - // TODO - // the ast rewrites dmd does for inlining messes up the ast. - // someday maybe we can support it, for now llvm does an excellent job at inlining - global.params.useInline = 0; //1 - global.params.llvmInline = 1; - } - else if (strcmp(p + 1, "quiet") == 0) - global.params.quiet = 1; - else if (strcmp(p + 1, "release") == 0) - { - global.params.useInvariants = 0; - global.params.useIn = 0; - global.params.useOut = 0; - global.params.useAssert = 0; - global.params.useArrayBounds = 0; - } - else if (strcmp(p + 1, "unittest") == 0) - global.params.useUnitTests = 1; - else if (p[1] == 'I') - { - if (!global.params.imppath) - global.params.imppath = new Array(); - global.params.imppath->push(p + 2); - } - else if (p[1] == 'J') - { - if (!global.params.fileImppath) - global.params.fileImppath = new Array(); - global.params.fileImppath->push(p + 2); - } - else if (memcmp(p + 1, "debug", 5) == 0 && p[6] != 'l') - { - // Parse: - // -debug - // -debug=number - // -debug=identifier - if (p[6] == '=') - { - if (isdigit(p[7])) - { long level; - - errno = 0; - level = strtol(p + 7, &p, 10); - if (*p || errno || level > INT_MAX) - goto Lerror; - DebugCondition::setGlobalLevel((int)level); - } - else if (Lexer::isValidIdentifier(p + 7)) - DebugCondition::addGlobalIdent(p + 7); - else - goto Lerror; - } - else if (p[6]) - goto Lerror; - else - { - global.params.useInvariants = 1; - global.params.useIn = 1; - global.params.useOut = 1; - global.params.useAssert = 1; - global.params.useArrayBounds = 1; - global.params.debuglevel = 1; - } - } - else if (memcmp(p + 1, "version", 5) == 0) - { - // Parse: - // -version=number - // -version=identifier - if (p[8] == '=') - { - if (isdigit(p[9])) - { long level; - - errno = 0; - level = strtol(p + 9, &p, 10); - if (*p || errno || level > INT_MAX) - goto Lerror; - VersionCondition::setGlobalLevel((int)level); - } - else if (Lexer::isValidIdentifier(p + 9)) - VersionCondition::addGlobalIdent(p + 9); - else - goto Lerror; - } - else - goto Lerror; - } - else if (strcmp(p + 1, "-b") == 0) - global.params.debugb = 1; - else if (strcmp(p + 1, "-c") == 0) - global.params.debugc = 1; - else if (strcmp(p + 1, "-f") == 0) - global.params.debugf = 1; - else if (strcmp(p + 1, "-help") == 0) - { usage(); - exit(EXIT_SUCCESS); - } - else if (strcmp(p + 1, "-r") == 0) - global.params.debugr = 1; - else if (strcmp(p + 1, "-x") == 0) - global.params.debugx = 1; - else if (strcmp(p + 1, "-y") == 0) - global.params.debugy = 1; - else if (p[1] == 'L') - { - global.params.linkswitches->push(p + 2); - } - else if (memcmp(p + 1, "defaultlib=", 11) == 0) - { - if(!global.params.defaultlibnames) - global.params.defaultlibnames = new Array(); - global.params.defaultlibnames->push(p + 1 + 11); - } - else if (memcmp(p + 1, "debuglib=", 9) == 0) - { - if(!global.params.debuglibnames) - global.params.debuglibnames = new Array(); - global.params.debuglibnames->push(p + 1 + 9); - } - else if (strcmp(p + 1, "run") == 0) - { global.params.run = 1; - global.params.runargs_length = ((i >= argcstart) ? argc : argcstart) - i - 1; - if (global.params.runargs_length) - { - files.push(argv[i + 1]); - global.params.runargs = &argv[i + 2]; - i += global.params.runargs_length; - global.params.runargs_length--; - } - else - { global.params.run = 0; - goto Lnoarg; - } - } - else if (p[1] == 'm') - { - global.params.llvmArch = p+2; - } - else if (p[1] == 't') - { - if(strcmp(p + 2, "Linux") == 0) - global.params.os = OSLinux; - else if(strcmp(p + 2, "Windows") == 0) - global.params.os = OSWindows; - else if(strcmp(p + 2, "MacOSX") == 0) - global.params.os = OSMacOSX; - else if(strcmp(p + 2, "FreeBSD") == 0) - global.params.os = OSFreeBSD; - else if(strcmp(p + 2, "Solaris") == 0) - global.params.os = OSSolaris; - else - error("unrecognized target os '%s'", p + 2); - } - else - { - Lerror: - error("unrecognized switch '%s'", argv[i]); - continue; - - Lnoarg: - error("argument expected for switch '%s'", argv[i]); - continue; - } - } - else - files.push(p); - } - if (global.errors) - { - fatal(); - } - if (files.dim == 0) - { usage(); - return EXIT_FAILURE; - } - - Array* libs; - if (global.params.symdebug) - libs = global.params.debuglibnames; - else - libs = global.params.defaultlibnames; - - if (libs) - { - for (int i = 0; i < libs->dim; i++) - { - char *arg = (char *)mem.malloc(64); - strcpy(arg, "-l"); - strncat(arg, (char *)libs->data[i], 64); - global.params.linkswitches->push(arg); - } - } - else if (!global.params.noDefaultLib) - { -#if DMDV2 - char *arg; - arg = (char *)mem.malloc(64); - strcpy(arg, "-ldruntime-ldc"); - global.params.linkswitches->push(arg); -#else - char *arg; - arg = (char *)mem.malloc(64); - strcpy(arg, "-lldc-runtime"); - global.params.linkswitches->push(arg); - arg = (char *)mem.malloc(64); - strcpy(arg, "-ltango-cc-tango"); - global.params.linkswitches->push(arg); - arg = (char *)mem.malloc(64); - strcpy(arg, "-ltango-gc-basic"); - global.params.linkswitches->push(arg); - // pass the runtime again to resolve issues - // with linking order - arg = (char *)mem.malloc(64); - strcpy(arg, "-lldc-runtime"); - global.params.linkswitches->push(arg); -#endif - } - - if (global.params.run) - global.params.quiet = 1; - - if (global.params.useUnitTests) - global.params.useAssert = 1; - - // LDC output determination - - // if we don't link, autodetect target from extension - if(!global.params.link && global.params.objname) { - ext = FileName::ext(global.params.objname); - bool autofound = false; - if (!ext) { - // keep things as they are - } else if (strcmp(ext, global.ll_ext) == 0) { - global.params.output_ll = OUTPUTFLAGset; - autofound = true; - } else if (strcmp(ext, global.bc_ext) == 0) { - global.params.output_bc = OUTPUTFLAGset; - autofound = true; - } else if (strcmp(ext, global.s_ext) == 0) { - global.params.output_s = OUTPUTFLAGset; - autofound = true; - } else if (strcmp(ext, global.obj_ext) == 0) { - global.params.output_o = OUTPUTFLAGset; - autofound = true; - } else { - // append dot, so forceExt won't change existing name even if it contains dots - size_t len = strlen(global.params.objname); - size_t extlen = strlen("."); - char* s = (char *)mem.malloc(len + 1 + extlen + 1); - memcpy(s, global.params.objname, len); - s[len] = '.'; - s[len+1+extlen] = 0; - global.params.objname = s; - - } - if(autofound && global.params.output_o == OUTPUTFLAGdefault) - global.params.output_o = OUTPUTFLAGno; - } - - // only link if possible - if (!global.params.obj || !global.params.output_o) - global.params.link = 0; - - if (global.params.link) - { - global.params.exefile = global.params.objname; - if (files.dim > 1) - global.params.objname = NULL; - } - else if (global.params.run) - { - error("flags conflict with -run"); - fatal(); - } - else - { - if (global.params.objname && files.dim > 1) - { - error("multiple source files, but only one .obj name"); - fatal(); - } - } - - bool allowForceEndianness = false; - - if (global.params.llvmArch == 0) { - #if defined(__x86_64__) || defined(_M_X64) - global.params.llvmArch = "x86-64"; - #elif defined(__i386__) || defined(_M_IX86) - global.params.llvmArch = "x86"; - #elif defined(__ppc__) || defined(_M_PPC) - if (global.params.is64bit) - global.params.llvmArch = "ppc64"; - else - global.params.llvmArch = "ppc32"; - #elif defined(__arm__) - global.params.llvmArch = "arm"; - #elif defined(__thumb__) - global.params.llvmArch = "thumb"; - #else - #error - #endif - } - - if (strcmp(global.params.llvmArch,"x86")==0) { - VersionCondition::addPredefinedGlobalIdent("X86"); - global.params.isLE = true; - global.params.is64bit = false; - global.params.cpu = ARCHx86; - if (global.params.useInlineAsm) { - VersionCondition::addPredefinedGlobalIdent("LLVM_InlineAsm_X86"); - } - } - else if (strcmp(global.params.llvmArch,"x86-64")==0) { - VersionCondition::addPredefinedGlobalIdent("X86_64"); - global.params.isLE = true; - global.params.is64bit = true; - global.params.cpu = ARCHx86_64; - if (global.params.useInlineAsm) { - VersionCondition::addPredefinedGlobalIdent("LLVM_InlineAsm_X86_64"); - } - } - else if (strcmp(global.params.llvmArch,"ppc32")==0) { - VersionCondition::addPredefinedGlobalIdent("PPC"); - global.params.isLE = false; - global.params.is64bit = false; - global.params.cpu = ARCHppc; - } - else if (strcmp(global.params.llvmArch,"ppc64")==0) { - VersionCondition::addPredefinedGlobalIdent("PPC64"); - global.params.isLE = false; - global.params.is64bit = true; - global.params.cpu = ARCHppc_64; - } - else if (strcmp(global.params.llvmArch,"arm")==0) { - VersionCondition::addPredefinedGlobalIdent("ARM"); - global.params.isLE = true; - global.params.is64bit = false; - global.params.cpu = ARCHarm; - } - else if (strcmp(global.params.llvmArch,"thumb")==0) { - VersionCondition::addPredefinedGlobalIdent("Thumb"); - global.params.isLE = true; - global.params.is64bit = false; - global.params.cpu = ARCHthumb; - } - else { - error("invalid cpu architecture specified: %s", global.params.llvmArch); - } - - assert(global.params.cpu != ARCHinvalid); - - if (allowForceEndianness && global.params.forceBE) { - VersionCondition::addPredefinedGlobalIdent("BigEndian"); - global.params.isLE = false; - } - else if (global.params.isLE) { - VersionCondition::addPredefinedGlobalIdent("LittleEndian"); - } - else { - VersionCondition::addPredefinedGlobalIdent("BigEndian"); - } - - if (global.params.is64bit) { - VersionCondition::addPredefinedGlobalIdent("LLVM64"); - } - - - // setup version idents and tt_os for chosen target os - switch(global.params.os) - { - case OSWindows: - VersionCondition::addPredefinedGlobalIdent("Windows"); - VersionCondition::addPredefinedGlobalIdent("Win32"); - VersionCondition::addPredefinedGlobalIdent("mingw32"); - break; - - case OSLinux: - VersionCondition::addPredefinedGlobalIdent("linux"); - VersionCondition::addPredefinedGlobalIdent("Posix"); - break; - - case OSMacOSX: - VersionCondition::addPredefinedGlobalIdent("darwin"); - VersionCondition::addPredefinedGlobalIdent("Posix"); - break; - - case OSFreeBSD: - VersionCondition::addPredefinedGlobalIdent("freebsd"); - VersionCondition::addPredefinedGlobalIdent("Posix"); - break; - - case OSSolaris: - VersionCondition::addPredefinedGlobalIdent("solaris"); - VersionCondition::addPredefinedGlobalIdent("Posix"); - break; - - default: - assert(false && "Target OS not supported"); - } - - if (!global.params.targetTriple) - global.params.targetTriple = DEFAULT_TARGET_TRIPLE; - - Logger::println("Target triple: %s", global.params.targetTriple); - - // build a minimal data layout so llvm can find the target - global.params.dataLayout = global.params.isLE - ? (char*)(global.params.is64bit ? "e-p:64:64" : "e-p:32:32") - : (char*)(global.params.is64bit ? "E-p:64:64" : "E-p:32:32"); - Logger::println("Layout: %s", global.params.dataLayout); - - // Initialization - Type::init(); - Id::initialize(); - Module::init(); - initPrecedence(); - - backend_init(); - - //printf("%d source files\n",files.dim); - - // Build import search path - if (global.params.imppath) - { - for (i = 0; i < global.params.imppath->dim; i++) - { - char *path = (char *)global.params.imppath->data[i]; - Array *a = FileName::splitPath(path); - - if (a) - { - if (!global.path) - global.path = new Array(); - global.path->append(a); - } - } - } - - // Build string import search path - if (global.params.fileImppath) - { - for (i = 0; i < global.params.fileImppath->dim; i++) - { - char *path = (char *)global.params.fileImppath->data[i]; - Array *a = FileName::splitPath(path); - - if (a) - { - if (!global.filePath) - global.filePath = new Array(); - global.filePath->append(a); - } - } - } - - // Create Modules - Array modules; - modules.reserve(files.dim); - for (i = 0; i < files.dim; i++) - { Identifier *id; - char *ext; - char *name; - - p = (char *) files.data[i]; - - p = FileName::name(p); // strip path - ext = FileName::ext(p); - if (ext) - { -#if POSIX - if (strcmp(ext, global.obj_ext) == 0 || - strcmp(ext, global.bc_ext) == 0) -#else - if (stricmp(ext, global.obj_ext) == 0 || - stricmp(ext, global.bc_ext) == 0) -#endif - { - global.params.objfiles->push(files.data[i]); - continue; - } - -#if POSIX - if (strcmp(ext, "a") == 0) -#elif __MINGW32__ - if (stricmp(ext, "a") == 0) -#else - if (stricmp(ext, "lib") == 0) -#endif - { - global.params.libfiles->push(files.data[i]); - continue; - } - - if (strcmp(ext, global.ddoc_ext) == 0) - { - global.params.ddocfiles->push(files.data[i]); - continue; - } - -#if !POSIX - if (stricmp(ext, "res") == 0) - { - global.params.resfile = (char *)files.data[i]; - continue; - } - - if (stricmp(ext, "def") == 0) - { - global.params.deffile = (char *)files.data[i]; - continue; - } - - if (stricmp(ext, "exe") == 0) - { - global.params.exefile = (char *)files.data[i]; - continue; - } -#endif - - if (stricmp(ext, global.mars_ext) == 0 || - stricmp(ext, global.hdr_ext) == 0 || - stricmp(ext, "htm") == 0 || - stricmp(ext, "html") == 0 || - stricmp(ext, "xhtml") == 0) - { - ext--; // skip onto '.' - assert(*ext == '.'); - name = (char *)mem.malloc((ext - p) + 1); - memcpy(name, p, ext - p); - name[ext - p] = 0; // strip extension - - if (name[0] == 0 || - strcmp(name, "..") == 0 || - strcmp(name, ".") == 0) - { - Linvalid: - error("invalid file name '%s'", (char *)files.data[i]); - fatal(); - } - } - else - { error("unrecognized file extension %s\n", ext); - fatal(); - } - } - else - { name = p; - if (!*name) - goto Linvalid; - } - - id = new Identifier(name, 0); - m = new Module((char *) files.data[i], id, global.params.doDocComments, global.params.doHdrGeneration); - modules.push(m); - } - - // Read files, parse them - for (i = 0; i < modules.dim; i++) - { - m = (Module *)modules.data[i]; - if (global.params.verbose) - printf("parse %s\n", m->toChars()); - if (!Module::rootModule) - Module::rootModule = m; - m->importedFrom = m; - m->read(0); - m->parse(); - m->buildTargetFiles(); - m->deleteObjFile(); - if (m->isDocFile) - { - m->gendocfile(); - - // Remove m from list of modules - modules.remove(i); - i--; - } - } - if (global.errors) - fatal(); -#ifdef _DH - if (global.params.doHdrGeneration) - { - /* Generate 'header' import files. - * Since 'header' import files must be independent of command - * line switches and what else is imported, they are generated - * before any semantic analysis. - */ - for (i = 0; i < modules.dim; i++) - { - m = (Module *)modules.data[i]; - if (global.params.verbose) - printf("import %s\n", m->toChars()); - m->genhdrfile(); - } - } - if (global.errors) - fatal(); -#endif - - // Do semantic analysis - for (i = 0; i < modules.dim; i++) - { - m = (Module *)modules.data[i]; - if (global.params.verbose) - printf("semantic %s\n", m->toChars()); - m->semantic(); - } - if (global.errors) - fatal(); - - // Do pass 2 semantic analysis - for (i = 0; i < modules.dim; i++) - { - m = (Module *)modules.data[i]; - if (global.params.verbose) - printf("semantic2 %s\n", m->toChars()); - m->semantic2(); - } - if (global.errors) - fatal(); - - // Do pass 3 semantic analysis - for (i = 0; i < modules.dim; i++) - { - m = (Module *)modules.data[i]; - if (global.params.verbose) - printf("semantic3 %s\n", m->toChars()); - m->semantic3(); - } - if (global.errors) - fatal(); - -#if !IN_LLVM - // Scan for functions to inline - if (global.params.useInline) - { - /* The problem with useArrayBounds and useAssert is that the - * module being linked to may not have generated them, so if - * we inline functions from those modules, the symbols for them will - * not be found at link time. - */ - if (!global.params.useArrayBounds && !global.params.useAssert) - { -#endif - // Do pass 3 semantic analysis on all imported modules, - // since otherwise functions in them cannot be inlined - for (i = 0; i < Module::amodules.dim; i++) - { - m = (Module *)Module::amodules.data[i]; - if (global.params.verbose) - printf("semantic3 %s\n", m->toChars()); - m->semantic3(); - } - if (global.errors) - fatal(); -#if !IN_LLVM - } - - for (i = 0; i < modules.dim; i++) - { - m = (Module *)modules.data[i]; - if (global.params.verbose) - printf("inline scan %s\n", m->toChars()); - m->inlineScan(); - } - } -#endif - if (global.errors) - fatal(); - - // Generate output files - for (i = 0; i < modules.dim; i++) - { - m = (Module *)modules.data[i]; - if (global.params.verbose) - printf("code %s\n", m->toChars()); - if (global.params.obj) - { - m->genobjfile(0); - global.params.objfiles->push(m->objfile->name->str); - } - if (global.errors) - m->deleteObjFile(); - else - { - if (global.params.doDocComments) - m->gendocfile(); - } - } - - backend_term(); - if (global.errors) - fatal(); - - if (!global.params.objfiles->dim) - { - if (global.params.link) - error("no object files to link"); - } - else - { - if (global.params.link) - //status = runLINK(); - linkObjToExecutable(global.params.argv0); - - if (global.params.run) - { - if (!status) - { - status = runExectuable(); - - /* Delete .obj files and .exe file - */ - for (i = 0; i < modules.dim; i++) - { - m = (Module *)modules.data[i]; - m->deleteObjFile(); - } - deleteExecutable(); - } - } - } - - return status; -} - - - /*********************************** * Parse and append contents of environment variable envvar * to argc and argv[]. @@ -1308,7 +160,7 @@ Array *argv; int argc; - int wildcard; // do wildcard expansion + int wildcard; // do wildcard expansion int instring; int slash; char c; @@ -1316,90 +168,111 @@ env = getenv(envvar); if (!env) - return; + return; - env = mem.strdup(env); // create our own writable copy + env = mem.strdup(env); // create our own writable copy argc = *pargc; argv = new Array(); argv->setDim(argc); - for (int i = 0; i < argc; i++) - argv->data[i] = (void *)(*pargv)[i]; + int argc_left = 0; + for (int i = 0; i < argc; i++) { + if (!strcmp((*pargv)[i], "-run") || !strcmp((*pargv)[i], "--run")) { + // HACK: set flag to indicate we saw '-run' here + global.params.run = true; + // Don't eat -run yet so the program arguments don't get changed + argc_left = argc - i; + argc = i; + *pargv = &(*pargv)[i]; + argv->setDim(i); + break; + } else { + argv->data[i] = (void *)(*pargv)[i]; + } + } + // HACK to stop required values from command line being drawn from DFLAGS + argv->push((char*)""); + argc++; - j = 1; // leave argv[0] alone + j = 1; // leave argv[0] alone while (1) { - wildcard = 1; - switch (*env) - { - case ' ': - case '\t': - env++; - break; + wildcard = 1; + switch (*env) + { + case ' ': + case '\t': + env++; + break; - case 0: - goto Ldone; + case 0: + goto Ldone; - case '"': - wildcard = 0; - default: - argv->push(env); // append - //argv->insert(j, env); // insert at position j - j++; - argc++; - p = env; - slash = 0; - instring = 0; - c = 0; + case '"': + wildcard = 0; + default: + argv->push(env); // append + //argv->insert(j, env); // insert at position j + j++; + argc++; + p = env; + slash = 0; + instring = 0; + c = 0; - while (1) - { - c = *env++; - switch (c) - { - case '"': - p -= (slash >> 1); - if (slash & 1) - { p--; - goto Laddc; - } - instring ^= 1; - slash = 0; - continue; + while (1) + { + c = *env++; + switch (c) + { + case '"': + p -= (slash >> 1); + if (slash & 1) + { p--; + goto Laddc; + } + instring ^= 1; + slash = 0; + continue; - case ' ': - case '\t': - if (instring) - goto Laddc; - *p = 0; - //if (wildcard) - //wildcardexpand(); // not implemented - break; + case ' ': + case '\t': + if (instring) + goto Laddc; + *p = 0; + //if (wildcard) + //wildcardexpand(); // not implemented + break; - case '\\': - slash++; - *p++ = c; - continue; + case '\\': + slash++; + *p++ = c; + continue; - case 0: - *p = 0; - //if (wildcard) - //wildcardexpand(); // not implemented - goto Ldone; + case 0: + *p = 0; + //if (wildcard) + //wildcardexpand(); // not implemented + goto Ldone; - default: - Laddc: - slash = 0; - *p++ = c; - continue; - } - break; - } - } + default: + Laddc: + slash = 0; + *p++ = c; + continue; + } + break; + } + } } Ldone: + assert(argc == argv->dim); + argv->reserve(argc_left); + for (int i = 0; i < argc_left; i++) + argv->data[argc++] = (void *)(*pargv)[i]; + *pargc = argc; *pargv = (char **)argv->data; } diff -r 73ff89728d85 -r 2667e3a145be dmd2/mars.h --- a/dmd2/mars.h Wed Feb 25 19:30:06 2009 +0100 +++ b/dmd2/mars.h Thu Feb 26 14:11:49 2009 +0100 @@ -17,6 +17,7 @@ #include #include +#include #define __STDC_FORMAT_MACROS 1 #include #include @@ -32,8 +33,8 @@ /* Changes for the GDC compiler by David Friedman */ #endif -#define BREAKABI 1 // 0 if not ready to break the ABI just yet -#define STRUCTTHISREF V2 // if 'this' for struct is a reference, not a pointer +#define BREAKABI 1 // 0 if not ready to break the ABI just yet +#define STRUCTTHISREF V2 // if 'this' for struct is a reference, not a pointer struct Array; @@ -72,83 +73,68 @@ // Put command line switches in here struct Param { - char obj; // write object file - char link; // perform link - char lib; // write library file instead of object file(s) - char multiobj; // break one object file into multiple ones - char oneobj; // write one object file instead of multiple ones - char trace; // insert profiling hooks - char quiet; // suppress non-error messages - char verbose; // verbose compile - char symdebug; // insert debug symbolic information - char optimize; // run optimizer + bool obj; // write object file + bool link; // perform link + bool verbose; // verbose compile + char symdebug; // insert debug symbolic information + bool optimize; // run optimizer char optimizeLevel; // optimization level - ARCH cpu; // target CPU - OS os; // target OS - char is64bit; // generate 64 bit code - char isLE; // generate little endian code - char scheduler; // which scheduler to use - char useDeprecated; // allow use of deprecated features - char useAssert; // generate runtime code for assert()'s - char useInvariants; // generate class invariant checks - char useIn; // generate precondition checks - char useOut; // generate postcondition checks - char useArrayBounds; // generate array bounds checks - char useSwitchError; // check for switches without a default - char useUnitTests; // generate unittest code - char useInline; // inline expand functions - char release; // build release version - char preservePaths; // !=0 means don't strip path from source file - char warnings; // enable warnings - char pic; // generate position-independent-code for shared libs - char noruntime; // code is not allowed to make implicit calls to the runtime - char novalidate;// no bitcode validation - char Dversion; // D version number - char ignoreUnsupportedPragmas; // rather than error on them - char safe; // enforce safe memory model + ARCH cpu; // target CPU + OS os; // target OS + bool is64bit; // generate 64 bit code + bool isLE; // generate little endian code + bool useDeprecated; // allow use of deprecated features + bool useAssert; // generate runtime code for assert()'s + bool useInvariants; // generate class invariant checks + bool useIn; // generate precondition checks + bool useOut; // generate postcondition checks + bool useArrayBounds; // generate array bounds checks + bool useSwitchError; // check for switches without a default + bool useUnitTests; // generate unittest code + bool useInline; // inline expand functions + bool warnings; // enable warnings + bool safe; // enforce safe memory model + char Dversion; // D version number - char *argv0; // program name - Array *imppath; // array of char*'s of where to look for import modules - Array *fileImppath; // array of char*'s of where to look for file import modules - char *runtimeImppath; // char* of where to look for the core runtime - char *objdir; // .obj file output directory - char *objname; // .obj file output name + char *argv0; // program name + Array *imppath; // array of char*'s of where to look for import modules + Array *fileImppath; // array of char*'s of where to look for file import modules + char *objdir; // .obj file output directory + char *objname; // .obj file output name - char doDocComments; // process embedded documentation comments - char *docdir; // write documentation file to docdir directory - char *docname; // write documentation file to docname - Array *ddocfiles; // macro include files for Ddoc + bool doDocComments; // process embedded documentation comments + char *docdir; // write documentation file to docdir directory + char *docname; // write documentation file to docname + Array *ddocfiles; // macro include files for Ddoc - char doHdrGeneration; // process embedded documentation comments - char *hdrdir; // write 'header' file to docdir directory - char *hdrname; // write 'header' file to docname + bool doHdrGeneration; // process embedded documentation comments + char *hdrdir; // write 'header' file to docdir directory + char *hdrname; // write 'header' file to docname - unsigned debuglevel; // debug level - Array *debugids; // debug identifiers + unsigned debuglevel; // debug level + Array *debugids; // debug identifiers - unsigned versionlevel; // version level - Array *versionids; // version identifiers + unsigned versionlevel; // version level + Array *versionids; // version identifiers bool dump_source; - Array *defaultlibnames; // default libraries for non-debug builds - Array *debuglibnames; // default libraries for debug builds + Array *defaultlibnames; // default libraries for non-debug builds + Array *debuglibnames; // default libraries for debug builds - const char *xmlname; // filename for XML output + char *xmlname; // filename for XML output // Hidden debug switches - char debuga; - char debugb; - char debugc; - char debugf; - char debugr; - char debugw; - char debugx; - char debugy; + bool debuga; + bool debugb; + bool debugc; + bool debugf; + bool debugr; + bool debugw; + bool debugx; + bool debugy; - char run; // run resulting executable - size_t runargs_length; - char** runargs; // arguments for executable + bool run; // run resulting executable // Linker stuff Array *objfiles; @@ -159,50 +145,46 @@ char *exefile; // LDC stuff - const char *llvmArch; - char forceBE; - char output_ll; - char output_bc; - char output_s; - char output_o; - char llvmInline; - char llvmAnnotate; - char useInlineAsm; - char fqnNames; // use fully qualified object names - char noDefaultLib; + OUTPUTFLAG output_ll; + OUTPUTFLAG output_bc; + OUTPUTFLAG output_s; + OUTPUTFLAG output_o; + bool llvmInline; + bool llvmAnnotate; + bool useInlineAsm; // target stuff + const char* llvmArch; const char *targetTriple; const char *dataLayout; }; struct Global { - const char *mars_ext; - const char *sym_ext; - const char *obj_ext; + char *mars_ext; + char *sym_ext; + char *obj_ext; #if _WIN32 - const char *obj_ext_alt; + char *obj_ext_alt; #endif - const char *ll_ext; - const char *bc_ext; - const char *s_ext; - const char *lib_ext; - const char *doc_ext; // for Ddoc generated files - const char *ddoc_ext; // for Ddoc macro include files - const char *hdr_ext; // for D 'header' import files - const char *copyright; - const char *written; - Array *path; // Array of char*'s which form the import lookup path - Array *filePath; // Array of char*'s which form the file import lookup path + char *ll_ext; + char *bc_ext; + char *s_ext; + char *doc_ext; // for Ddoc generated files + char *ddoc_ext; // for Ddoc macro include files + char *hdr_ext; // for D 'header' import files + char *copyright; + char *written; + Array *path; // Array of char*'s which form the import lookup path + Array *filePath; // Array of char*'s which form the file import lookup path int structalign; - const char *version; - const char *ldc_version; - const char *llvm_version; + char *version; + char *ldc_version; + char *llvm_version; Param params; - unsigned errors; // number of errors reported so far - unsigned gag; // !=0 means gag reporting of errors + unsigned errors; // number of errors reported so far + unsigned gag; // !=0 means gag reporting of errors Global(); }; @@ -212,7 +194,7 @@ /* Set if Windows Structured Exception Handling C extensions are supported. * Apparently, VC has dropped support for these? */ -#define WINDOWS_SEH _WIN32 && __DMC__ +#define WINDOWS_SEH (_WIN32 && __DMC__) #if __GNUC__ @@ -239,22 +221,22 @@ typedef int64_t sinteger_t; typedef uint64_t uinteger_t; -typedef int8_t d_int8; -typedef uint8_t d_uns8; -typedef int16_t d_int16; -typedef uint16_t d_uns16; -typedef int32_t d_int32; -typedef uint32_t d_uns32; -typedef int64_t d_int64; -typedef uint64_t d_uns64; +typedef int8_t d_int8; +typedef uint8_t d_uns8; +typedef int16_t d_int16; +typedef uint16_t d_uns16; +typedef int32_t d_int32; +typedef uint32_t d_uns32; +typedef int64_t d_int64; +typedef uint64_t d_uns64; -typedef float d_float32; -typedef double d_float64; -typedef long double d_float80; +typedef float d_float32; +typedef double d_float64; +typedef long double d_float80; -typedef d_uns8 d_char; -typedef d_uns16 d_wchar; -typedef d_uns32 d_dchar; +typedef d_uns8 d_char; +typedef d_uns16 d_wchar; +typedef d_uns32 d_dchar; #ifdef IN_GCC #include "d-gcc-real.h" @@ -289,7 +271,7 @@ struct Module; -//typedef unsigned Loc; // file location +//typedef unsigned Loc; // file location struct Loc { char *filename; @@ -297,14 +279,14 @@ Loc() { - linnum = 0; - filename = NULL; + linnum = 0; + filename = NULL; } Loc(int x) { - linnum = x; - filename = NULL; + linnum = x; + filename = NULL; } Loc(Module *mod, unsigned linnum); @@ -313,15 +295,15 @@ }; #ifndef GCC_SAFE_DMD -#define TRUE 1 -#define FALSE 0 +#define TRUE 1 +#define FALSE 0 #endif -#define INTERFACE_OFFSET 0 // if 1, put classinfo as first entry - // in interface vtbl[]'s -#define INTERFACE_VIRTUAL 0 // 1 means if an interface appears - // in the inheritance graph multiple - // times, only one is used +#define INTERFACE_OFFSET 0 // if 1, put classinfo as first entry + // in interface vtbl[]'s +#define INTERFACE_VIRTUAL 0 // 1 means if an interface appears + // in the inheritance graph multiple + // times, only one is used enum LINK { @@ -348,19 +330,19 @@ enum MATCH { - MATCHnomatch, // no match - MATCHconvert, // match with conversions + MATCHnomatch, // no match + MATCHconvert, // match with conversions #if DMDV2 - MATCHconst, // match with conversion to const + MATCHconst, // match with conversion to const #endif - MATCHexact // exact match + MATCHexact // exact match }; void error(Loc loc, const char *format, ...); void verror(Loc loc, const char *format, va_list); void fatal(); void err_nomem(); -void inifile(const char *argv0, const char *inifile); +void inifile(char *argv0, const char *inifile); void halt(); /*** Where to send error messages ***/ diff -r 73ff89728d85 -r 2667e3a145be dmd2/module.c --- a/dmd2/module.c Wed Feb 25 19:30:06 2009 +0100 +++ b/dmd2/module.c Thu Feb 26 14:11:49 2009 +0100 @@ -40,6 +40,19 @@ #include "d-dmd-gcc.h" #endif + +#include "llvm/Support/CommandLine.h" + +static llvm::cl::opt preservePaths("op", + llvm::cl::desc("Do not strip paths from source file"), + llvm::cl::ZeroOrMore); + +static llvm::cl::opt fqnNames("oq", + llvm::cl::desc("Write object files with fully qualified names"), + llvm::cl::ZeroOrMore); + + + ClassDeclaration *Module::moduleinfo; Module *Module::rootModule; @@ -139,12 +152,12 @@ argobj = forcename; else { - if (global.params.preservePaths) + if (preservePaths) argobj = (char*)this->arg; else argobj = FileName::name((char*)this->arg); - if (global.params.fqnNames) + if (fqnNames) { if(md) argobj = FileName::replaceName(argobj, md->toChars()); diff -r 73ff89728d85 -r 2667e3a145be gen/cl_options.cpp --- a/gen/cl_options.cpp Wed Feb 25 19:30:06 2009 +0100 +++ b/gen/cl_options.cpp Thu Feb 26 14:11:49 2009 +0100 @@ -230,22 +230,18 @@ cl::Prefix, cl::aliasopt(mArch)); +cl::opt mCPU("mcpu", + cl::desc("Target a specific cpu type (-mcpu=help for details)"), + cl::value_desc("cpu-name"), + cl::init("")); -static cl::opt os("t", - cl::desc("Emit code for the specified OS:"), - cl::values( -#define ENUMVAL_N(Name, Desc) clEnumValN(OS##Name, #Name, Desc) -#define ENUMVAL(Name) ENUMVAL_N(Name, #Name) - ENUMVAL(Linux), - ENUMVAL(Windows), - ENUMVAL_N(MacOSX, "Mac OS X"), - ENUMVAL(FreeBSD), - ENUMVAL(Solaris), -#undef ENUMVAL -#undef ENUMVAL_N - clEnumValEnd), - cl::Prefix, - cl::location(global.params.os)); +cl::list mAttrs("mattr", + cl::CommaSeparated, + cl::desc("Target specific attributes (-mattr=help for details)"), + cl::value_desc("a1,+a2,-a3,...")); + +cl::opt mTargetTriple("mtriple", + cl::desc("Override target triple")); // "Hidden debug switches" diff -r 73ff89728d85 -r 2667e3a145be gen/cl_options.h --- a/gen/cl_options.h Wed Feb 25 19:30:06 2009 +0100 +++ b/gen/cl_options.h Thu Feb 26 14:11:49 2009 +0100 @@ -38,7 +38,10 @@ extern cl::opt > mArch; - + extern cl::opt mCPU; + extern cl::list mAttrs; + extern cl::opt mTargetTriple; + // Arguments to -d-debug extern std::vector debugArgs; // Arguments to -run diff -r 73ff89728d85 -r 2667e3a145be gen/functions.cpp --- a/gen/functions.cpp Wed Feb 25 19:30:06 2009 +0100 +++ b/gen/functions.cpp Thu Feb 26 14:11:49 2009 +0100 @@ -20,6 +20,7 @@ #include "gen/todebug.h" #include "gen/classes.h" #include "gen/dvalue.h" +#include "gen/abi.h" #include @@ -53,40 +54,49 @@ // parameter types std::vector paramvec; + // special case main if (ismain) { rettype = LLType::Int32Ty; actualRettype = rettype; if (Argument::dim(f->parameters) == 0) { - const LLType* arrTy = DtoArrayType(LLType::Int8Ty); - const LLType* arrArrTy = DtoArrayType(arrTy); - paramvec.push_back(arrArrTy); + const LLType* arrTy = DtoArrayType(LLType::Int8Ty); + const LLType* arrArrTy = DtoArrayType(arrTy); + paramvec.push_back(arrArrTy); } } - else{ + // default handling + else + { assert(rt); - if (DtoIsReturnedInArg(rt)) { + if (gABI->returnInArg(rt)) + { rettype = getPtrToType(DtoType(rt)); actualRettype = LLType::VoidTy; f->retInPtr = retinptr = true; } - else { + else + { rettype = DtoType(rt); - actualRettype = rettype; + // do abi specific transformations + actualRettype = gABI->getRetType(f, rettype); } + // FIXME: should probably be part of the abi if (unsigned ea = DtoShouldExtend(rt)) { f->retAttrs |= ea; } } + // build up parameter list if (retinptr) { //Logger::cout() << "returning through pointer parameter: " << *rettype << '\n'; paramvec.push_back(rettype); } + // this/context param if (thistype) { paramvec.push_back(thistype); usesthis = true; @@ -96,6 +106,7 @@ usesnest = true; } + // dstyle vararg if (dVararg) { paramvec.push_back(DtoType(Type::typeinfo->type->arrayOf())); // _arguments paramvec.push_back(getVoidPtrType()); // _argptr diff -r 73ff89728d85 -r 2667e3a145be gen/irstate.cpp --- a/gen/irstate.cpp Wed Feb 25 19:30:06 2009 +0100 +++ b/gen/irstate.cpp Thu Feb 26 14:11:49 2009 +0100 @@ -16,7 +16,9 @@ #include "tollvm.h" IRState* gIR = 0; +llvm::TargetMachine* gTargetMachine = 0; const llvm::TargetData* gTargetData = 0; +TargetABI* gABI = 0; ////////////////////////////////////////////////////////////////////////////////////////// IRScope::IRScope() diff -r 73ff89728d85 -r 2667e3a145be gen/irstate.h --- a/gen/irstate.h Wed Feb 25 19:30:06 2009 +0100 +++ b/gen/irstate.h Thu Feb 26 14:11:49 2009 +0100 @@ -13,10 +13,18 @@ #include "ir/irstruct.h" #include "ir/irvar.h" +namespace llvm { + class TargetMachine; +} + // global ir state for current module struct IRState; +struct TargetABI; + extern IRState* gIR; +extern llvm::TargetMachine* gTargetMachine; extern const llvm::TargetData* gTargetData; +extern TargetABI* gABI; struct TypeFunction; struct TypeStruct; diff -r 73ff89728d85 -r 2667e3a145be gen/naked.cpp --- a/gen/naked.cpp Wed Feb 25 19:30:06 2009 +0100 +++ b/gen/naked.cpp Thu Feb 26 14:11:49 2009 +0100 @@ -218,6 +218,8 @@ // this is to show how to allocate a temporary for the return value // in case the appropriate multi register constraint isn't supported. // this way abi return from inline asm can still be emulated. + // note that "$<>" etc in the asm will translate to the correct + // numbered output when the asm block in finalized // generate asm as->out_c = "=*m,=*m,"; @@ -231,7 +233,7 @@ asmblock->retemu = true; asmblock->asmBlock->abiret = tmp; - // add "ret" stmt + // add "ret" stmt at the end of the block asmblock->s.push_back(as); // done, we don't want anything pushed in the front of the block @@ -276,17 +278,9 @@ // LLVM and GCC disagree on how to return {float, float}. // For compatibility, use the GCC/LLVM-GCC way for extern(C/Windows) // extern(C) cfloat -> %xmm0 (extract two floats) - #if 0 - // Disabled because "regular" extern(C) functions aren't - // ABI-compatible with GCC yet. - // TODO: enable when "extern(C) cfloat foo();" compiles to "declare { double } @foo();" as->out_c = "={xmm0},"; asmblock->retty = LLStructType::get(LLType::DoubleTy, NULL);; asmblock->retfixup = &x86_64_cfloatRetFixup; - #else - error(loc, "unimplemented return type '%s' for implicit abi return", rt->toChars()); - fatal(); - #endif } else if (rt->iscomplex()) { // cdouble and extern(D) cfloat -> re=%xmm0, im=%xmm1 as->out_c = "={xmm0},={xmm1},"; diff -r 73ff89728d85 -r 2667e3a145be gen/statements.cpp --- a/gen/statements.cpp Wed Feb 25 19:30:06 2009 +0100 +++ b/gen/statements.cpp Thu Feb 26 14:11:49 2009 +0100 @@ -25,6 +25,7 @@ #include "gen/arrays.h" #include "gen/todebug.h" #include "gen/dvalue.h" +#include "gen/abi.h" #include "ir/irfunction.h" #include "ir/irmodule.h" @@ -54,38 +55,47 @@ Logger::println("ReturnStatement::toIR(): %s", loc.toChars()); LOG_SCOPE; + // is there a return value expression? if (exp) { - if (p->topfunc()->getReturnType() == LLType::VoidTy) { + // if the functions return type is void this means that + // we are returning through a pointer argument + if (p->topfunc()->getReturnType() == LLType::VoidTy) + { + // sanity check IrFunction* f = p->func(); assert(f->type->retInPtr); assert(f->decl->ir.irFunc->retArg); + // emit dbg line if (global.params.symdebug) DtoDwarfStopPoint(loc.linnum); + // get return pointer DValue* rvar = new DVarValue(f->type->next, f->decl->ir.irFunc->retArg); - DValue* e = exp->toElem(p); - + // store return value DtoAssign(loc, rvar, e); + // emit scopes DtoEnclosingHandlers(enclosinghandler, NULL); + // emit dbg end function if (global.params.symdebug) DtoDwarfFuncEnd(f->decl); + + // emit ret llvm::ReturnInst::Create(p->scopebb()); } - else { + // the return type is not void, so this is a normal "register" return + else + { if (global.params.symdebug) DtoDwarfStopPoint(loc.linnum); DValue* e = exp->toElem(p); LLValue* v = e->getRVal(); delete e; - // swap real/imag parts on a x87 - if (global.params.cpu == ARCHx86 && exp->type->toBasetype()->iscomplex()) - { - v = DtoAggrPairSwap(v); - } + // do abi specific transformations on the return value + v = gABI->putRet(p->func()->type, v); if (Logger::enabled()) Logger::cout() << "return value is '" <<*v << "'\n"; @@ -113,6 +123,7 @@ llvm::ReturnInst::Create(v, p->scopebb()); } } + // no return value expression means it's a void function else { assert(p->topfunc()->getReturnType() == LLType::VoidTy); diff -r 73ff89728d85 -r 2667e3a145be gen/tocall.cpp --- a/gen/tocall.cpp Wed Feb 25 19:30:06 2009 +0100 +++ b/gen/tocall.cpp Thu Feb 26 14:11:49 2009 +0100 @@ -8,6 +8,7 @@ #include "gen/irstate.h" #include "gen/dvalue.h" #include "gen/functions.h" +#include "gen/abi.h" #include "gen/logger.h" @@ -463,11 +464,8 @@ // get return value LLValue* retllval = (retinptr) ? args[0] : call->get(); - // swap real/imag parts on a x87 - if (global.params.cpu == ARCHx86 && tf->nextOf()->toBasetype()->iscomplex()) - { - retllval = DtoAggrPairSwap(retllval); - } + // do abi specific return value fixups + retllval = gABI->getRet(tf, retllval); // repaint the type if necessary if (resulttype) diff -r 73ff89728d85 -r 2667e3a145be gen/tollvm.cpp --- a/gen/tollvm.cpp Wed Feb 25 19:30:06 2009 +0100 +++ b/gen/tollvm.cpp Thu Feb 26 14:11:49 2009 +0100 @@ -28,13 +28,6 @@ return (t == Tstruct || t == Tsarray); } -bool DtoIsReturnedInArg(Type* type) -{ - Type* typ = type->toBasetype(); - TY t = typ->ty; - return (t == Tstruct || t == Tsarray); -} - unsigned DtoShouldExtend(Type* type) { type = type->toBasetype(); diff -r 73ff89728d85 -r 2667e3a145be gen/tollvm.h --- a/gen/tollvm.h Wed Feb 25 19:30:06 2009 +0100 +++ b/gen/tollvm.h Thu Feb 26 14:11:49 2009 +0100 @@ -18,9 +18,7 @@ // returns true is the type must be passed by pointer bool DtoIsPassedByRef(Type* type); -// returns if the type should be returned in a hidden pointer arguement -bool DtoIsReturnedInArg(Type* type); - +// should argument be zero or sign extended unsigned DtoShouldExtend(Type* type); // tuple helper diff -r 73ff89728d85 -r 2667e3a145be gen/toobj.cpp --- a/gen/toobj.cpp Wed Feb 25 19:30:06 2009 +0100 +++ b/gen/toobj.cpp Thu Feb 26 14:11:49 2009 +0100 @@ -14,9 +14,6 @@ #include "gen/llvm.h" #include "llvm/Analysis/Verifier.h" #include "llvm/Bitcode/ReaderWriter.h" -#include "llvm/Target/SubtargetFeature.h" -#include "llvm/Target/TargetMachine.h" -#include "llvm/Target/TargetMachineRegistry.h" #include "llvm/Module.h" #include "llvm/ModuleProvider.h" #include "llvm/PassManager.h" @@ -25,6 +22,7 @@ #include "llvm/System/Path.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Support/CommandLine.h" +#include "llvm/Target/TargetMachine.h" #include "mars.h" #include "module.h" @@ -50,6 +48,8 @@ #include "gen/functions.h" #include "gen/todebug.h" #include "gen/runtime.h" +#include "gen/abi.h" +#include "gen/cl_options.h" #include "ir/irvar.h" #include "ir/irmodule.h" @@ -110,40 +110,16 @@ // FIXME: but shouldn't this always get reset between modules? like other IrSymbols this->ir.irModule = new IrModule(this, srcfile->toChars()); - // set target stuff - + // set target triple ir.module->setTargetTriple(global.params.targetTriple); - ir.module->setDataLayout(global.params.dataLayout); - - // get the target machine - const llvm::TargetMachineRegistry::entry* MArch; - - std::string Err; - MArch = llvm::TargetMachineRegistry::getClosestStaticTargetForModule(*ir.module, Err); - if (MArch == 0) { - error("error auto-selecting target for module '%s'", Err.c_str()); - fatal(); - } - - llvm::SubtargetFeatures Features; -//TODO: Features? -// Features.setCPU(MCPU); -// for (unsigned i = 0; i != MAttrs.size(); ++i) -// Features.AddFeature(MAttrs[i]); - - // allocate the target machine - std::auto_ptr target(MArch->CtorFn(*ir.module, Features.getString())); - assert(target.get() && "Could not allocate target machine!"); - llvm::TargetMachine &Target = *target.get(); - - gTargetData = Target.getTargetData(); // set final data layout - std::string datalayout = gTargetData->getStringRepresentation(); - ir.module->setDataLayout(datalayout); + ir.module->setDataLayout(global.params.dataLayout); if (Logger::enabled()) - Logger::cout() << "Final data layout: " << datalayout << '\n'; - assert(memcmp(global.params.dataLayout, datalayout.c_str(), 9) == 0); // "E-p:xx:xx" + Logger::cout() << "Final data layout: " << global.params.dataLayout << '\n'; + + // allocate the target abi + gABI = TargetABI::getTarget(); // debug info if (global.params.symdebug) { @@ -252,7 +228,7 @@ std::string err; { llvm::raw_fd_ostream out(spath.c_str(), false, err); - write_asm_to_file(Target, *ir.module, out); + write_asm_to_file(*gTargetMachine, *ir.module, out); } // call gcc to convert assembly to object file