diff --git a/src/build/build_options.c b/src/build/build_options.c index ad879d1d9..2ba014ba7 100644 --- a/src/build/build_options.c +++ b/src/build/build_options.c @@ -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 - 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.", ¤t_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; diff --git a/src/build/build_options.h b/src/build/build_options.h index f2cc5352b..a59a1b8fb 100644 --- a/src/build/build_options.h +++ b/src/build/build_options.h @@ -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, diff --git a/src/build/builder.c b/src/build/builder.c index e05844a17..5301b1c90 100644 --- a/src/build/builder.c +++ b/src/build/builder.c @@ -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) { diff --git a/src/compiler/llvm_codegen.c b/src/compiler/llvm_codegen.c index 93735c078..7471d302d 100644 --- a/src/compiler/llvm_codegen.c +++ b/src/compiler/llvm_codegen.c @@ -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); diff --git a/src/compiler/llvm_codegen_function.c b/src/compiler/llvm_codegen_function.c index 5fc4e5e5c..75662e1e2 100644 --- a/src/compiler/llvm_codegen_function.c +++ b/src/compiler/llvm_codegen_function.c @@ -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; } diff --git a/src/compiler/llvm_codegen_module.c b/src/compiler/llvm_codegen_module.c index 69f4b1654..9c611a0bd 100644 --- a/src/compiler/llvm_codegen_module.c +++ b/src/compiler/llvm_codegen_module.c @@ -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; diff --git a/src/compiler/target.c b/src/compiler/target.c index e84a44e77..0382c99c2 100644 --- a/src/compiler/target.c +++ b/src/compiler/target.c @@ -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: diff --git a/src/compiler/target.h b/src/compiler/target.h index 3480cd3a6..3694e6990 100644 --- a/src/compiler/target.h +++ b/src/compiler/target.h @@ -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;