- 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.
This commit is contained in:
Tomas Lindquist Olsen 2009-02-26 14:11:49 +01:00
parent f61733cb57
commit 57a69e8177
20 changed files with 334 additions and 2264 deletions

View file

@ -55,8 +55,8 @@ struct DVCondition : Condition
struct DebugCondition : DVCondition struct DebugCondition : DVCondition
{ {
static void setGlobalLevel(unsigned level); static void setGlobalLevel(unsigned level);
static void addGlobalIdent(char *ident); static void addGlobalIdent(const char *ident);
static void addPredefinedGlobalIdent(char *ident); static void addPredefinedGlobalIdent(const char *ident);
DebugCondition(Module *mod, unsigned level, Identifier *ident); DebugCondition(Module *mod, unsigned level, Identifier *ident);
@ -67,9 +67,9 @@ struct DebugCondition : DVCondition
struct VersionCondition : DVCondition struct VersionCondition : DVCondition
{ {
static void setGlobalLevel(unsigned level); static void setGlobalLevel(unsigned level);
static void checkPredefined(Loc loc, char *ident); static void checkPredefined(Loc loc, const char *ident);
static void addGlobalIdent(char *ident); static void addGlobalIdent(const char *ident);
static void addPredefinedGlobalIdent(char *ident); static void addPredefinedGlobalIdent(const char *ident);
VersionCondition(Module *mod, unsigned level, Identifier *ident); VersionCondition(Module *mod, unsigned level, Identifier *ident);

View file

@ -47,7 +47,7 @@ char *strupr(char *s)
* inifile .ini file name * 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 *path; // need path for @P macro
char *filename; char *filename;

View file

@ -36,48 +36,8 @@
#include "expression.h" #include "expression.h"
#include "lexer.h" #include "lexer.h"
#include "gen/logger.h"
#include "gen/linker.h"
#include "revisions.h" #include "revisions.h"
#include "gen/cl_options.h"
#include "gen/cl_helpers.h"
using namespace opts;
static cl::opt<bool> forceBE("forcebe",
cl::desc("Force big-endian"),
cl::Hidden,
cl::ZeroOrMore);
static cl::opt<bool> 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<std::string, ArrayAdapter> 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<std::string, ArrayAdapter> 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<std::string, ArrayAdapter> 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;
Global::Global() Global::Global()
@ -187,763 +147,6 @@ void halt()
#endif #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<std::string>& list, char* type,
void (*setLevel)(unsigned), void (*addIdent)(char*)) {
typedef std::vector<std::string>::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<std::string>& 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<std::string>::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 * Parse and append contents of environment variable envvar
* to argc and argv[]. * to argc and argv[].

View file

@ -144,7 +144,6 @@ struct Param
char *exefile; char *exefile;
// LDC stuff // LDC stuff
const char *llvmArch;
OUTPUTFLAG output_ll; OUTPUTFLAG output_ll;
OUTPUTFLAG output_bc; OUTPUTFLAG output_bc;
OUTPUTFLAG output_s; OUTPUTFLAG output_s;
@ -154,8 +153,9 @@ struct Param
bool useInlineAsm; bool useInlineAsm;
// target stuff // target stuff
char *targetTriple; const char* llvmArch;
char *dataLayout; const char *targetTriple;
const char *dataLayout;
}; };
struct Global struct Global
@ -341,7 +341,7 @@ void error(Loc loc, const char *format, ...);
void verror(Loc loc, const char *format, va_list); void verror(Loc loc, const char *format, va_list);
void fatal(); void fatal();
void err_nomem(); void err_nomem();
void inifile(char *argv0, char *inifile); void inifile(char *argv0, const char *inifile);
void halt(); void halt();
/*** Where to send error messages ***/ /*** Where to send error messages ***/

View file

@ -33,6 +33,15 @@
#include "../gen/enums.h" #include "../gen/enums.h"
#include "llvm/Support/CommandLine.h"
static llvm::cl::opt<bool> ignoreUnsupportedPragmas("ignore",
llvm::cl::desc("Ignore unsupported pragmas"),
llvm::cl::ZeroOrMore);
extern void obj_includelib(const char *name); extern void obj_includelib(const char *name);
void obj_startaddress(Symbol *s); void obj_startaddress(Symbol *s);
@ -1001,7 +1010,7 @@ void PragmaDeclaration::semantic(Scope *sc)
///////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////
else if (global.params.ignoreUnsupportedPragmas) else if (ignoreUnsupportedPragmas)
{ {
if (global.params.verbose) if (global.params.verbose)
{ {

View file

@ -43,7 +43,7 @@ char *strupr(char *s)
* inifile .ini file name * inifile .ini file name
*/ */
void inifile(const char *argv0x, const char *inifilex) void inifile(char *argv0x, const char *inifilex)
{ {
char *argv0 = (char *)argv0x; char *argv0 = (char *)argv0x;
char *inifile = (char *)inifilex; // do const-correct later char *inifile = (char *)inifilex; // do const-correct later

File diff suppressed because it is too large Load diff

View file

@ -17,6 +17,7 @@
#include <stdint.h> #include <stdint.h>
#include <stdarg.h> #include <stdarg.h>
#include <stddef.h>
#define __STDC_FORMAT_MACROS 1 #define __STDC_FORMAT_MACROS 1
#include <inttypes.h> #include <inttypes.h>
#include <stdarg.h> #include <stdarg.h>
@ -72,54 +73,41 @@ enum OS
// Put command line switches in here // Put command line switches in here
struct Param struct Param
{ {
char obj; // write object file bool obj; // write object file
char link; // perform link bool link; // perform link
char lib; // write library file instead of object file(s) bool verbose; // verbose compile
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 symdebug; // insert debug symbolic information
char optimize; // run optimizer bool optimize; // run optimizer
char optimizeLevel; // optimization level char optimizeLevel; // optimization level
ARCH cpu; // target CPU ARCH cpu; // target CPU
OS os; // target OS OS os; // target OS
char is64bit; // generate 64 bit code bool is64bit; // generate 64 bit code
char isLE; // generate little endian code bool isLE; // generate little endian code
char scheduler; // which scheduler to use bool useDeprecated; // allow use of deprecated features
char useDeprecated; // allow use of deprecated features bool useAssert; // generate runtime code for assert()'s
char useAssert; // generate runtime code for assert()'s bool useInvariants; // generate class invariant checks
char useInvariants; // generate class invariant checks bool useIn; // generate precondition checks
char useIn; // generate precondition checks bool useOut; // generate postcondition checks
char useOut; // generate postcondition checks bool useArrayBounds; // generate array bounds checks
char useArrayBounds; // generate array bounds checks bool useSwitchError; // check for switches without a default
char useSwitchError; // check for switches without a default bool useUnitTests; // generate unittest code
char useUnitTests; // generate unittest code bool useInline; // inline expand functions
char useInline; // inline expand functions bool warnings; // enable warnings
char release; // build release version bool safe; // enforce safe memory model
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 Dversion; // D version number
char ignoreUnsupportedPragmas; // rather than error on them
char safe; // enforce safe memory model
char *argv0; // program name char *argv0; // program name
Array *imppath; // array of char*'s of where to look for import modules 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 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 *objdir; // .obj file output directory
char *objname; // .obj file output name char *objname; // .obj file output name
char doDocComments; // process embedded documentation comments bool doDocComments; // process embedded documentation comments
char *docdir; // write documentation file to docdir directory char *docdir; // write documentation file to docdir directory
char *docname; // write documentation file to docname char *docname; // write documentation file to docname
Array *ddocfiles; // macro include files for Ddoc Array *ddocfiles; // macro include files for Ddoc
char doHdrGeneration; // process embedded documentation comments bool doHdrGeneration; // process embedded documentation comments
char *hdrdir; // write 'header' file to docdir directory char *hdrdir; // write 'header' file to docdir directory
char *hdrname; // write 'header' file to docname char *hdrname; // write 'header' file to docname
@ -134,21 +122,19 @@ struct Param
Array *defaultlibnames; // default libraries for non-debug builds Array *defaultlibnames; // default libraries for non-debug builds
Array *debuglibnames; // default libraries for 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 // Hidden debug switches
char debuga; bool debuga;
char debugb; bool debugb;
char debugc; bool debugc;
char debugf; bool debugf;
char debugr; bool debugr;
char debugw; bool debugw;
char debugx; bool debugx;
char debugy; bool debugy;
char run; // run resulting executable bool run; // run resulting executable
size_t runargs_length;
char** runargs; // arguments for executable
// Linker stuff // Linker stuff
Array *objfiles; Array *objfiles;
@ -159,46 +145,42 @@ struct Param
char *exefile; char *exefile;
// LDC stuff // LDC stuff
const char *llvmArch; OUTPUTFLAG output_ll;
char forceBE; OUTPUTFLAG output_bc;
char output_ll; OUTPUTFLAG output_s;
char output_bc; OUTPUTFLAG output_o;
char output_s; bool llvmInline;
char output_o; bool llvmAnnotate;
char llvmInline; bool useInlineAsm;
char llvmAnnotate;
char useInlineAsm;
char fqnNames; // use fully qualified object names
char noDefaultLib;
// target stuff // target stuff
const char* llvmArch;
const char *targetTriple; const char *targetTriple;
const char *dataLayout; const char *dataLayout;
}; };
struct Global struct Global
{ {
const char *mars_ext; char *mars_ext;
const char *sym_ext; char *sym_ext;
const char *obj_ext; char *obj_ext;
#if _WIN32 #if _WIN32
const char *obj_ext_alt; char *obj_ext_alt;
#endif #endif
const char *ll_ext; char *ll_ext;
const char *bc_ext; char *bc_ext;
const char *s_ext; char *s_ext;
const char *lib_ext; char *doc_ext; // for Ddoc generated files
const char *doc_ext; // for Ddoc generated files char *ddoc_ext; // for Ddoc macro include files
const char *ddoc_ext; // for Ddoc macro include files char *hdr_ext; // for D 'header' import files
const char *hdr_ext; // for D 'header' import files char *copyright;
const char *copyright; char *written;
const char *written;
Array *path; // Array of char*'s which form the import lookup path 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 Array *filePath; // Array of char*'s which form the file import lookup path
int structalign; int structalign;
const char *version; char *version;
const char *ldc_version; char *ldc_version;
const char *llvm_version; char *llvm_version;
Param params; Param params;
unsigned errors; // number of errors reported so far unsigned errors; // number of errors reported so far
@ -212,7 +194,7 @@ extern Global global;
/* Set if Windows Structured Exception Handling C extensions are supported. /* Set if Windows Structured Exception Handling C extensions are supported.
* Apparently, VC has dropped support for these? * Apparently, VC has dropped support for these?
*/ */
#define WINDOWS_SEH _WIN32 && __DMC__ #define WINDOWS_SEH (_WIN32 && __DMC__)
#if __GNUC__ #if __GNUC__
@ -360,7 +342,7 @@ void error(Loc loc, const char *format, ...);
void verror(Loc loc, const char *format, va_list); void verror(Loc loc, const char *format, va_list);
void fatal(); void fatal();
void err_nomem(); void err_nomem();
void inifile(const char *argv0, const char *inifile); void inifile(char *argv0, const char *inifile);
void halt(); void halt();
/*** Where to send error messages ***/ /*** Where to send error messages ***/

View file

@ -40,6 +40,19 @@
#include "d-dmd-gcc.h" #include "d-dmd-gcc.h"
#endif #endif
#include "llvm/Support/CommandLine.h"
static llvm::cl::opt<bool> preservePaths("op",
llvm::cl::desc("Do not strip paths from source file"),
llvm::cl::ZeroOrMore);
static llvm::cl::opt<bool> fqnNames("oq",
llvm::cl::desc("Write object files with fully qualified names"),
llvm::cl::ZeroOrMore);
ClassDeclaration *Module::moduleinfo; ClassDeclaration *Module::moduleinfo;
Module *Module::rootModule; Module *Module::rootModule;
@ -139,12 +152,12 @@ File* Module::buildFilePath(char* forcename, const char* path, const char* ext)
argobj = forcename; argobj = forcename;
else else
{ {
if (global.params.preservePaths) if (preservePaths)
argobj = (char*)this->arg; argobj = (char*)this->arg;
else else
argobj = FileName::name((char*)this->arg); argobj = FileName::name((char*)this->arg);
if (global.params.fqnNames) if (fqnNames)
{ {
if(md) if(md)
argobj = FileName::replaceName(argobj, md->toChars()); argobj = FileName::replaceName(argobj, md->toChars());

View file

@ -230,22 +230,18 @@ static cl::alias m("m",
cl::Prefix, cl::Prefix,
cl::aliasopt(mArch)); cl::aliasopt(mArch));
cl::opt<std::string> mCPU("mcpu",
cl::desc("Target a specific cpu type (-mcpu=help for details)"),
cl::value_desc("cpu-name"),
cl::init(""));
static cl::opt<OS, true> os("t", cl::list<std::string> mAttrs("mattr",
cl::desc("Emit code for the specified OS:"), cl::CommaSeparated,
cl::values( cl::desc("Target specific attributes (-mattr=help for details)"),
#define ENUMVAL_N(Name, Desc) clEnumValN(OS##Name, #Name, Desc) cl::value_desc("a1,+a2,-a3,..."));
#define ENUMVAL(Name) ENUMVAL_N(Name, #Name)
ENUMVAL(Linux), cl::opt<std::string> mTargetTriple("mtriple",
ENUMVAL(Windows), cl::desc("Override target triple"));
ENUMVAL_N(MacOSX, "Mac OS X"),
ENUMVAL(FreeBSD),
ENUMVAL(Solaris),
#undef ENUMVAL
#undef ENUMVAL_N
clEnumValEnd),
cl::Prefix,
cl::location(global.params.os));
// "Hidden debug switches" // "Hidden debug switches"

View file

@ -38,6 +38,9 @@ namespace opts {
extern cl::opt<const llvm::TargetMachineRegistry::entry*, false, extern cl::opt<const llvm::TargetMachineRegistry::entry*, false,
llvm::RegistryParser<llvm::TargetMachine> > mArch; llvm::RegistryParser<llvm::TargetMachine> > mArch;
extern cl::opt<std::string> mCPU;
extern cl::list<std::string> mAttrs;
extern cl::opt<std::string> mTargetTriple;
// Arguments to -d-debug // Arguments to -d-debug
extern std::vector<std::string> debugArgs; extern std::vector<std::string> debugArgs;

View file

@ -20,6 +20,7 @@
#include "gen/todebug.h" #include "gen/todebug.h"
#include "gen/classes.h" #include "gen/classes.h"
#include "gen/dvalue.h" #include "gen/dvalue.h"
#include "gen/abi.h"
#include <algorithm> #include <algorithm>
@ -53,6 +54,7 @@ const llvm::FunctionType* DtoFunctionType(Type* type, const LLType* thistype, co
// parameter types // parameter types
std::vector<const LLType*> paramvec; std::vector<const LLType*> paramvec;
// special case main
if (ismain) if (ismain)
{ {
rettype = LLType::Int32Ty; rettype = LLType::Int32Ty;
@ -64,29 +66,37 @@ const llvm::FunctionType* DtoFunctionType(Type* type, const LLType* thistype, co
paramvec.push_back(arrArrTy); paramvec.push_back(arrArrTy);
} }
} }
else{ // default handling
else
{
assert(rt); assert(rt);
if (DtoIsReturnedInArg(rt)) { if (gABI->returnInArg(rt))
{
rettype = getPtrToType(DtoType(rt)); rettype = getPtrToType(DtoType(rt));
actualRettype = LLType::VoidTy; actualRettype = LLType::VoidTy;
f->retInPtr = retinptr = true; f->retInPtr = retinptr = true;
} }
else { else
{
rettype = DtoType(rt); 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)) if (unsigned ea = DtoShouldExtend(rt))
{ {
f->retAttrs |= ea; f->retAttrs |= ea;
} }
} }
// build up parameter list
if (retinptr) { if (retinptr) {
//Logger::cout() << "returning through pointer parameter: " << *rettype << '\n'; //Logger::cout() << "returning through pointer parameter: " << *rettype << '\n';
paramvec.push_back(rettype); paramvec.push_back(rettype);
} }
// this/context param
if (thistype) { if (thistype) {
paramvec.push_back(thistype); paramvec.push_back(thistype);
usesthis = true; usesthis = true;
@ -96,6 +106,7 @@ const llvm::FunctionType* DtoFunctionType(Type* type, const LLType* thistype, co
usesnest = true; usesnest = true;
} }
// dstyle vararg
if (dVararg) { if (dVararg) {
paramvec.push_back(DtoType(Type::typeinfo->type->arrayOf())); // _arguments paramvec.push_back(DtoType(Type::typeinfo->type->arrayOf())); // _arguments
paramvec.push_back(getVoidPtrType()); // _argptr paramvec.push_back(getVoidPtrType()); // _argptr

View file

@ -16,7 +16,9 @@
#include "tollvm.h" #include "tollvm.h"
IRState* gIR = 0; IRState* gIR = 0;
llvm::TargetMachine* gTargetMachine = 0;
const llvm::TargetData* gTargetData = 0; const llvm::TargetData* gTargetData = 0;
TargetABI* gABI = 0;
////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////
IRScope::IRScope() IRScope::IRScope()

View file

@ -13,10 +13,18 @@
#include "ir/irstruct.h" #include "ir/irstruct.h"
#include "ir/irvar.h" #include "ir/irvar.h"
namespace llvm {
class TargetMachine;
}
// global ir state for current module // global ir state for current module
struct IRState; struct IRState;
struct TargetABI;
extern IRState* gIR; extern IRState* gIR;
extern llvm::TargetMachine* gTargetMachine;
extern const llvm::TargetData* gTargetData; extern const llvm::TargetData* gTargetData;
extern TargetABI* gABI;
struct TypeFunction; struct TypeFunction;
struct TypeStruct; struct TypeStruct;

View file

@ -218,6 +218,8 @@ void emitABIReturnAsmStmt(IRAsmBlock* asmblock, Loc loc, FuncDeclaration* fdecl)
// this is to show how to allocate a temporary for the return value // this is to show how to allocate a temporary for the return value
// in case the appropriate multi register constraint isn't supported. // in case the appropriate multi register constraint isn't supported.
// this way abi return from inline asm can still be emulated. // this way abi return from inline asm can still be emulated.
// note that "$<<out0>>" etc in the asm will translate to the correct
// numbered output when the asm block in finalized
// generate asm // generate asm
as->out_c = "=*m,=*m,"; as->out_c = "=*m,=*m,";
@ -231,7 +233,7 @@ void emitABIReturnAsmStmt(IRAsmBlock* asmblock, Loc loc, FuncDeclaration* fdecl)
asmblock->retemu = true; asmblock->retemu = true;
asmblock->asmBlock->abiret = tmp; asmblock->asmBlock->abiret = tmp;
// add "ret" stmt // add "ret" stmt at the end of the block
asmblock->s.push_back(as); asmblock->s.push_back(as);
// done, we don't want anything pushed in the front of the block // done, we don't want anything pushed in the front of the block
@ -276,17 +278,9 @@ void emitABIReturnAsmStmt(IRAsmBlock* asmblock, Loc loc, FuncDeclaration* fdecl)
// LLVM and GCC disagree on how to return {float, float}. // LLVM and GCC disagree on how to return {float, float}.
// For compatibility, use the GCC/LLVM-GCC way for extern(C/Windows) // For compatibility, use the GCC/LLVM-GCC way for extern(C/Windows)
// extern(C) cfloat -> %xmm0 (extract two floats) // 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},"; as->out_c = "={xmm0},";
asmblock->retty = LLStructType::get(LLType::DoubleTy, NULL);; asmblock->retty = LLStructType::get(LLType::DoubleTy, NULL);;
asmblock->retfixup = &x86_64_cfloatRetFixup; asmblock->retfixup = &x86_64_cfloatRetFixup;
#else
error(loc, "unimplemented return type '%s' for implicit abi return", rt->toChars());
fatal();
#endif
} else if (rt->iscomplex()) { } else if (rt->iscomplex()) {
// cdouble and extern(D) cfloat -> re=%xmm0, im=%xmm1 // cdouble and extern(D) cfloat -> re=%xmm0, im=%xmm1
as->out_c = "={xmm0},={xmm1},"; as->out_c = "={xmm0},={xmm1},";

View file

@ -25,6 +25,7 @@
#include "gen/arrays.h" #include "gen/arrays.h"
#include "gen/todebug.h" #include "gen/todebug.h"
#include "gen/dvalue.h" #include "gen/dvalue.h"
#include "gen/abi.h"
#include "ir/irfunction.h" #include "ir/irfunction.h"
#include "ir/irmodule.h" #include "ir/irmodule.h"
@ -54,38 +55,47 @@ void ReturnStatement::toIR(IRState* p)
Logger::println("ReturnStatement::toIR(): %s", loc.toChars()); Logger::println("ReturnStatement::toIR(): %s", loc.toChars());
LOG_SCOPE; LOG_SCOPE;
// is there a return value expression?
if (exp) 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(); IrFunction* f = p->func();
assert(f->type->retInPtr); assert(f->type->retInPtr);
assert(f->decl->ir.irFunc->retArg); assert(f->decl->ir.irFunc->retArg);
// emit dbg line
if (global.params.symdebug) DtoDwarfStopPoint(loc.linnum); if (global.params.symdebug) DtoDwarfStopPoint(loc.linnum);
// get return pointer
DValue* rvar = new DVarValue(f->type->next, f->decl->ir.irFunc->retArg); DValue* rvar = new DVarValue(f->type->next, f->decl->ir.irFunc->retArg);
DValue* e = exp->toElem(p); DValue* e = exp->toElem(p);
// store return value
DtoAssign(loc, rvar, e); DtoAssign(loc, rvar, e);
// emit scopes
DtoEnclosingHandlers(enclosinghandler, NULL); DtoEnclosingHandlers(enclosinghandler, NULL);
// emit dbg end function
if (global.params.symdebug) DtoDwarfFuncEnd(f->decl); if (global.params.symdebug) DtoDwarfFuncEnd(f->decl);
// emit ret
llvm::ReturnInst::Create(p->scopebb()); 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); if (global.params.symdebug) DtoDwarfStopPoint(loc.linnum);
DValue* e = exp->toElem(p); DValue* e = exp->toElem(p);
LLValue* v = e->getRVal(); LLValue* v = e->getRVal();
delete e; delete e;
// swap real/imag parts on a x87 // do abi specific transformations on the return value
if (global.params.cpu == ARCHx86 && exp->type->toBasetype()->iscomplex()) v = gABI->putRet(p->func()->type, v);
{
v = DtoAggrPairSwap(v);
}
if (Logger::enabled()) if (Logger::enabled())
Logger::cout() << "return value is '" <<*v << "'\n"; Logger::cout() << "return value is '" <<*v << "'\n";
@ -113,6 +123,7 @@ void ReturnStatement::toIR(IRState* p)
llvm::ReturnInst::Create(v, p->scopebb()); llvm::ReturnInst::Create(v, p->scopebb());
} }
} }
// no return value expression means it's a void function
else else
{ {
assert(p->topfunc()->getReturnType() == LLType::VoidTy); assert(p->topfunc()->getReturnType() == LLType::VoidTy);

View file

@ -8,6 +8,7 @@
#include "gen/irstate.h" #include "gen/irstate.h"
#include "gen/dvalue.h" #include "gen/dvalue.h"
#include "gen/functions.h" #include "gen/functions.h"
#include "gen/abi.h"
#include "gen/logger.h" #include "gen/logger.h"
@ -463,11 +464,8 @@ DValue* DtoCallFunction(Loc& loc, Type* resulttype, DValue* fnval, Expressions*
// get return value // get return value
LLValue* retllval = (retinptr) ? args[0] : call->get(); LLValue* retllval = (retinptr) ? args[0] : call->get();
// swap real/imag parts on a x87 // do abi specific return value fixups
if (global.params.cpu == ARCHx86 && tf->nextOf()->toBasetype()->iscomplex()) retllval = gABI->getRet(tf, retllval);
{
retllval = DtoAggrPairSwap(retllval);
}
// repaint the type if necessary // repaint the type if necessary
if (resulttype) if (resulttype)

View file

@ -28,13 +28,6 @@ bool DtoIsPassedByRef(Type* type)
return (t == Tstruct || t == Tsarray); 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) unsigned DtoShouldExtend(Type* type)
{ {
type = type->toBasetype(); type = type->toBasetype();

View file

@ -18,9 +18,7 @@ const LLType* DtoTypeNotVoid(Type* t);
// returns true is the type must be passed by pointer // returns true is the type must be passed by pointer
bool DtoIsPassedByRef(Type* type); bool DtoIsPassedByRef(Type* type);
// returns if the type should be returned in a hidden pointer arguement // should argument be zero or sign extended
bool DtoIsReturnedInArg(Type* type);
unsigned DtoShouldExtend(Type* type); unsigned DtoShouldExtend(Type* type);
// tuple helper // tuple helper

View file

@ -14,9 +14,6 @@
#include "gen/llvm.h" #include "gen/llvm.h"
#include "llvm/Analysis/Verifier.h" #include "llvm/Analysis/Verifier.h"
#include "llvm/Bitcode/ReaderWriter.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/Module.h"
#include "llvm/ModuleProvider.h" #include "llvm/ModuleProvider.h"
#include "llvm/PassManager.h" #include "llvm/PassManager.h"
@ -25,6 +22,7 @@
#include "llvm/System/Path.h" #include "llvm/System/Path.h"
#include "llvm/Support/raw_ostream.h" #include "llvm/Support/raw_ostream.h"
#include "llvm/Support/CommandLine.h" #include "llvm/Support/CommandLine.h"
#include "llvm/Target/TargetMachine.h"
#include "mars.h" #include "mars.h"
#include "module.h" #include "module.h"
@ -50,6 +48,8 @@
#include "gen/functions.h" #include "gen/functions.h"
#include "gen/todebug.h" #include "gen/todebug.h"
#include "gen/runtime.h" #include "gen/runtime.h"
#include "gen/abi.h"
#include "gen/cl_options.h"
#include "ir/irvar.h" #include "ir/irvar.h"
#include "ir/irmodule.h" #include "ir/irmodule.h"
@ -110,40 +110,16 @@ void Module::genobjfile(int multiobj)
// FIXME: but shouldn't this always get reset between modules? like other IrSymbols // FIXME: but shouldn't this always get reset between modules? like other IrSymbols
this->ir.irModule = new IrModule(this, srcfile->toChars()); this->ir.irModule = new IrModule(this, srcfile->toChars());
// set target stuff // set target triple
ir.module->setTargetTriple(global.params.targetTriple); 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<llvm::TargetMachine> 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 // set final data layout
std::string datalayout = gTargetData->getStringRepresentation(); ir.module->setDataLayout(global.params.dataLayout);
ir.module->setDataLayout(datalayout);
if (Logger::enabled()) if (Logger::enabled())
Logger::cout() << "Final data layout: " << datalayout << '\n'; Logger::cout() << "Final data layout: " << global.params.dataLayout << '\n';
assert(memcmp(global.params.dataLayout, datalayout.c_str(), 9) == 0); // "E-p:xx:xx"
// allocate the target abi
gABI = TargetABI::getTarget();
// debug info // debug info
if (global.params.symdebug) { if (global.params.symdebug) {
@ -252,7 +228,7 @@ void Module::genobjfile(int multiobj)
std::string err; std::string err;
{ {
llvm::raw_fd_ostream out(spath.c_str(), false, 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 // call gcc to convert assembly to object file