Add a new "target" command line option to set the target without the need for a full target triple. Add debug command line options. Fix bug with coerce for x64 SysV ABI.

This commit is contained in:
Christoffer Lerno
2020-11-23 23:23:15 +01:00
committed by Christoffer Lerno
parent 1057432913
commit 162bb9dac8
8 changed files with 133 additions and 34 deletions

View File

@@ -16,6 +16,16 @@
static const int DEFAULT_SYMTAB_SIZE = 64 * 1024;
static const int MAX_SYMTAB_SIZE = 1024 * 1024;
static char *arch_os_target[ARCH_OS_TARGET_LAST + 1] = {
[X86_DARWIN] = "x86_darwin",
[X86_LINUX] = "x86_linux",
[X64_DARWIN] = "x64_darwin",
[X64_LINUX] = "x64_linux",
[X64_WINDOWS] = "x64_windows",
[AARCH64_LINUX] = "aarch64_linux",
[AARCH64_DARWIN] = "aarch64_darwin",
};
BuildOptions build_options;
static int arg_index;
static int arg_count;
@@ -23,6 +33,7 @@ static const char** args;
static const char* current_arg;
#define EOUTPUT(string, ...) fprintf(stderr, string "\n", ##__VA_ARGS__)
#define OUTPUT(string, ...) fprintf(stdout, string "\n", ##__VA_ARGS__)
#define FAIL_WITH_ERR(string, ...) do { fprintf(stderr, "Error: " string "\n\n", ##__VA_ARGS__); usage(); exit(EXIT_FAILURE); } while (0)
@@ -57,6 +68,12 @@ static void usage(void)
OUTPUT(" -Os - Optimize for size.");
OUTPUT(" -O3 - Aggressive optimization.");
OUTPUT(" --emit-llvm - Emit LLVM IR as a .ll file per module.");
OUTPUT(" --target <target> - Compile for a particular architecture + OS target.");
OUTPUT(" --target-list - List all architectures the compiler supports.");
OUTPUT("");
OUTPUT(" -g - Emit full debug info.");
OUTPUT(" -g0 - Emit no debug info.");
OUTPUT(" -gline-tables-only - Only emit line tables for debugging.");
OUTPUT("");
OUTPUT(" -freg-struct-return - Override default ABI to return small structs in registers.");
OUTPUT(" -fpcc-struct-return - Override default ABI to return small structs on the stack.");
@@ -129,11 +146,11 @@ static void parse_optional_target()
{
if (at_end() || next_is_opt())
{
build_options.target = NULL;
build_options.target_select = NULL;
}
else
{
build_options.target = next_arg();
build_options.target_select = next_arg();
}
}
@@ -205,10 +222,36 @@ static void parse_command(void)
}
FAIL_WITH_ERR("Cannot process the unknown command \"%s\".", current_arg);
}
static void parse_option()
static void print_all_targets(void)
{
OUTPUT("Available targets:");
for (unsigned i = 0; i <= ARCH_OS_TARGET_LAST; i++)
{
OUTPUT(" %s", arch_os_target[i]);
}
}
static void parse_option(void)
{
switch (current_arg[1])
{
case 'g':
if (match_shortopt("gline-tables-only"))
{
build_options.debug_info = DEBUG_INFO_LINE_TABLES;
FATAL_ERROR("Line tables only are currently not available");
}
if (match_shortopt("g") || match_shortopt("g1"))
{
build_options.debug_info = DEBUG_INFO_FULL;
return;
}
if (match_shortopt("g0"))
{
build_options.debug_info = DEBUG_INFO_NONE;
return;
}
FAIL_WITH_ERR("Unknown debug argument -%s.", &current_arg[1]);
case 'h':
break;
case 'f':
@@ -299,6 +342,37 @@ static void parse_option()
OUTPUT("C3 is low level programming language based on C.");
exit(EXIT_SUCCESS);
}
if (match_longopt("target"))
{
if (at_end() || next_is_opt()) error_exit("error: --target needs a arch+os definition.");
const char *target = next_arg();
for (unsigned i = 1; i <= ARCH_OS_TARGET_LAST; i++)
{
if (strcasecmp(arch_os_target[i], target) == 0)
{
build_options.arch_os_target = i;
return;
}
}
OUTPUT("Available targets:");
EOUTPUT("Invalid target %s.", target);
EOUTPUT("These targets are supported:");
for (unsigned i = 1; i <= ARCH_OS_TARGET_LAST; i++)
{
EOUTPUT(" %s", arch_os_target[i]);
}
exit(EXIT_FAILURE);
}
if (match_longopt("target-list"))
{
print_all_targets();
OUTPUT("Available targets:");
for (unsigned i = 1; i <= ARCH_OS_TARGET_LAST; i++)
{
OUTPUT(" %s", arch_os_target[i]);
}
exit(EXIT_SUCCESS);
}
if (match_longopt("emit-llvm"))
{
build_options.emit_llvm = true;
@@ -361,7 +435,7 @@ void parse_arguments(int argc, const char *argv[])
build_options.emit_bitcode = true;
build_options.optimization_level = OPTIMIZATION_NOT_SET;
build_options.size_optimization_level = SIZE_OPTIMIZATION_NOT_SET;
build_options.debug_info = DEBUG_INFO_FULL;
build_options.debug_info = DEBUG_INFO_NONE;
build_options.debug_mode = false;
build_options.command = COMMAND_MISSING;
build_options.symtab_size = DEFAULT_SYMTAB_SIZE;

View File

@@ -93,13 +93,27 @@ typedef enum
DEBUG_INFO_FULL
} DebugInfo;
typedef enum
{
ARCH_OS_TARGET_DEFAULT = 0,
X86_DARWIN,
X86_LINUX,
X64_DARWIN,
X64_LINUX,
X64_WINDOWS,
AARCH64_LINUX,
AARCH64_DARWIN,
ARCH_OS_TARGET_LAST = AARCH64_DARWIN
} ArchOsTarget;
typedef struct
{
const char* lib_dir[MAX_LIB_DIRS];
int lib_count;
const char** files;
const char* project_name;
const char* target;
ArchOsTarget arch_os_target;
const char* target_select;
const char* path;
const char* cpu;
const char* target_triple;
@@ -127,6 +141,7 @@ typedef struct
typedef enum
{
TARGET_TYPE_EXECUTABLE,

View File

@@ -16,7 +16,7 @@ void build(void)
file_find_top_dir();
// Parse it
Project *project = project_load();
BuildTarget *target = project_select_target(project, build_options.target);
BuildTarget *target = project_select_target(project, build_options.target_select);
if (!target->target_triple && build_options.target_triple)
{

View File

@@ -122,7 +122,7 @@ static void gencontext_verify_ir(GenContext *context)
void gencontext_emit_object_file(GenContext *context)
{
char *err = "";
LLVMSetTarget(context->module, build_options.target);
LLVMSetTarget(context->module, build_options.target_triple);
char *layout = LLVMCopyStringRepOfTargetData(target_data_layout());
LLVMSetDataLayout(context->module, layout);
LLVMDisposeMessage(layout);

View File

@@ -174,7 +174,7 @@ static inline void llvm_process_parameter_value(GenContext *c, Decl *decl, unsig
{
LLVMValueRef param = llvm_get_next_param(c, index);
// Store it with the alignment of the decl.
llvm_store_aligned_decl(c, decl, param);
llvm_store_aligned(c, cast, param, decl->alignment);
return;
}

View File

@@ -14,7 +14,7 @@ void gencontext_begin_module(GenContext *context)
LLVMSetModuleDataLayout(context->module, target_data_layout());
LLVMSetSourceFileName(context->module, full_path, strlen(context->ast_context->file->full_path));
LLVMSetTarget(context->module, build_options.target);
LLVMSetTarget(context->module, build_target.target_triple);
if (build_options.debug_info != DEBUG_INFO_NONE)
{
const char *filename = context->ast_context->file->name;

View File

@@ -344,6 +344,16 @@ static inline void target_setup_x64_abi(void)
}
}
static char *arch_to_target_triple[ARCH_OS_TARGET_LAST + 1] = {
[X86_DARWIN] = "i386-apple-darwin",
[X86_LINUX] = "i386-pc-linux",
[X64_DARWIN] = "x86_64-apple-darwin",
[X64_LINUX] = "x86_64-pc-linux",
[X64_WINDOWS] = "x86_64-pc-win32",
[AARCH64_LINUX] = "aarch64-pc-linux",
[AARCH64_DARWIN] = "aarch64-apple-darwin",
};
void target_setup(void)
{
assert(!build_target.target);
@@ -355,13 +365,19 @@ void target_setup(void)
LLVMInitializeAllAsmParsers();
build_target.target = NULL;
if (!build_options.target)
{
build_options.target = LLVMGetDefaultTargetTriple();
}
char *err = NULL;
if (LLVMGetTargetFromTriple(build_options.target, ((LLVMTargetRef *)&build_target.target), &err) != 0)
const char *triple;
if (build_options.arch_os_target == ARCH_OS_TARGET_DEFAULT)
{
triple = LLVMGetDefaultTargetTriple();
}
else
{
triple = arch_to_target_triple[build_options.arch_os_target];
}
char *err = NULL;
if (LLVMGetTargetFromTriple(triple, ((LLVMTargetRef *)&build_target.target), &err) != 0)
{
error_exit("Could not create target: %s", err);
// Usually we would dispose of err, but no need to do it due to exit.
@@ -369,7 +385,7 @@ void target_setup(void)
build_target.alloca_address_space = 0;
DEBUG_LOG("Target set to %s.", build_options.target);
DEBUG_LOG("Target set to %s.", triple);
// Create a specific target machine
LLVMCodeGenOptLevel level;
LLVMRelocMode reloc_mode = LLVMRelocDefault;
@@ -403,7 +419,7 @@ void target_setup(void)
{
opt->features = "";
}*/
if (!(build_target.machine = LLVMCreateTargetMachine(build_target.target, build_options.target, "", "", level, reloc_mode,
if (!(build_target.machine = LLVMCreateTargetMachine(build_target.target, triple, "", "", level, reloc_mode,
LLVMCodeModelDefault))) {
error_exit("Failed to create target machine.");
}
@@ -412,22 +428,19 @@ void target_setup(void)
char *target_triple = LLVMGetTargetMachineTriple(build_target.machine);
build_target.arch_name = strdup(strtok(target_triple, "-"));
build_target.vendor_name = strdup(strtok(NULL, "-"));
build_target.os_name = strdup(strtok(NULL, "-"));
char *env = strtok(NULL, "0123456789");
build_target.environment_name = env ? strdup(env) : "unknown";
LLVMDisposeMessage(target_triple);
build_target.arch = arch_from_llvm_string(build_target.arch_name);
build_target.target_triple = strdup(target_triple);
build_target.arch = arch_from_llvm_string(strtok(target_triple, "-"));
if (!arch_is_supported(build_target.arch))
{
printf("WARNING! This architecture is not supported.\n");
}
build_target.environment_type = environment_type_from_llvm_string(build_target.environment_name);
build_target.os = os_from_llvm_string(build_target.os_name);
build_target.vendor = vendor_from_llvm_string(build_target.vendor_name);
build_target.vendor = vendor_from_llvm_string(strtok(NULL, "-"));
build_target.os = os_from_llvm_string(strtok(NULL, "-"));
char *env = strtok(NULL, "0123456789");
build_target.environment_type = env ? environment_type_from_llvm_string(env) : ENV_TYPE_UNKNOWN;
LLVMDisposeMessage(target_triple);
build_target.float_abi = false;
build_target.width_pointer = arch_pointer_bit_width(build_target.os, build_target.arch);
assert(build_target.width_pointer == LLVMPointerSize(build_target.llvm_data_layout) * 8);
@@ -512,7 +525,7 @@ void target_setup(void)
case ARCH_TYPE_ARC:
case ARCH_TYPE_SPIR64:
case ARCH_TYPE_SPIR:
FATAL_ERROR("Unsupported arch %s.", build_target.arch_name);
UNREACHABLE
break;
case ARCH_TYPE_AARCH64:
case ARCH_TYPE_AARCH64_BE:

View File

@@ -220,14 +220,11 @@ typedef struct
void *target;
void *machine;
void *llvm_data_layout;
const char *target_triple;
ArchType arch;
const char *arch_name;
OsType os;
const char *os_name;
VendorType vendor;
const char *vendor_name;
EnvironmentType environment_type;
const char *environment_name;
ObjectFormatType object_format;
int alloca_address_space;
ABI abi;