From 954a90dae325354aa6e04ae2b3ccfcb947a0a47a Mon Sep 17 00:00:00 2001 From: Christoffer Lerno Date: Fri, 9 Apr 2021 01:49:36 +0200 Subject: [PATCH] Fix of arch target. Experimental linker support. --- .github/workflows/main.yml | 4 +- CMakeLists.txt | 59 +- src/build/build_options.c | 4 +- src/compiler/compiler.c | 12 +- src/compiler/compiler_internal.h | 31 +- src/compiler/context.c | 4 +- src/compiler/lexer.c | 4 +- src/compiler/linker.c | 90 ++- src/compiler/llvm_codegen.c | 2 +- src/compiler/llvm_codegen_c_abi.c | 4 +- src/compiler/llvm_codegen_c_abi_aarch64.c | 8 +- src/compiler/llvm_codegen_c_abi_riscv.c | 26 +- src/compiler/llvm_codegen_c_abi_x64.c | 8 +- src/compiler/llvm_codegen_c_abi_x86.c | 44 +- src/compiler/llvm_codegen_debug_info.c | 4 +- src/compiler/llvm_codegen_expr.c | 2 +- src/compiler/llvm_codegen_function.c | 2 +- src/compiler/llvm_codegen_module.c | 2 +- src/compiler/parse_global.c | 6 +- src/compiler/parse_stmt.c | 2 +- src/compiler/parser.c | 6 +- src/compiler/sema_expr.c | 2 +- src/compiler/sema_stmts.c | 8 +- src/compiler/target.c | 815 ++++++++++++---------- src/compiler/target.h | 24 +- src/compiler/types.c | 16 +- src/main.c | 3 +- wrapper/src/wrapper.cpp | 102 +++ 28 files changed, 778 insertions(+), 516 deletions(-) create mode 100644 wrapper/src/wrapper.cpp diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index b4de0555d..7cb0859bb 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -13,9 +13,9 @@ jobs: - uses: actions/checkout@v1 - name: (Linux) Download LLVM run: | - sudo apt-get install llvm-10 + sudo apt-get install libllvm11 llvm-11 llvm-11-dev llvm-11-runtime liblld-11-dev liblld-11 - name: Build run: | mkdir build && cd build - cmake -DLLVM_DIR=/usr/lib/llvm-10/cmake -DCMAKE_BUILD_TYPE=Debug .. + cmake -DLLVM_DIR=/usr/lib/llvm-11/cmake -DCMAKE_BUILD_TYPE=Debug .. cmake --build . diff --git a/CMakeLists.txt b/CMakeLists.txt index ea68e1294..09b746533 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,11 +11,13 @@ find_package(LLVM REQUIRED CONFIG) message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}") message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}") +message(STATUS "Libraries located in: ${LLVM_LIBRARY_DIRS}") include_directories(${LLVM_INCLUDE_DIRS}) add_definitions(${LLVM_DEFINITIONS}) set(CMAKE_C_STANDARD 11) +set(CMAKE_CXX_STANDARD 17) set(LLVM_LINK_COMPONENTS AllTargetsAsmParsers @@ -42,14 +44,43 @@ set(LLVM_LINK_COMPONENTS native nativecodegen AsmPrinter + Linker + LTO + Option + WindowsManifest + DebugInfoPDB + LibDriver ) -llvm_map_components_to_libnames(llvm_libs support core irreader ${LLVM_LINK_COMPONENTS}) + +llvm_map_components_to_libnames(llvm_libs ${LLVM_LINK_COMPONENTS}) file(COPY ${CMAKE_SOURCE_DIR}/resources/lib DESTINATION ${CMAKE_BINARY_DIR}) -include_directories( - "${CMAKE_SOURCE_DIR}/src/") +find_library(LLD_COFF NAMES lldCOFF.a liblldCOFF.a PATHS ${LLVM_LIBRARY_DIRS}) +find_library(LLD_COMMON NAMES lldCommon.a liblldCommon.a PATHS ${LLVM_LIBRARY_DIRS}) +find_library(LLD_CORE NAMES lldCore.a liblldCore.a PATHS ${LLVM_LIBRARY_DIRS}) +find_library(LLD_WASM NAMES lldWasm.a liblldWasm.a PATHS ${LLVM_LIBRARY_DIRS}) +find_library(LLD_MINGW NAMES lldMinGW.a liblldMinGW.a PATHS ${LLVM_LIBRARY_DIRS}) +find_library(LLD_ELF NAMES lldELF.a liblldELF.a PATHS ${LLVM_LIBRARY_DIRS}) +find_library(LLD_DRIVER NAMES lldDriver.a liblldDriver.a PATHS ${LLVM_LIBRARY_DIRS}) +find_library(LLD_READER_WRITER NAMES lldReaderWriter.a liblldReaderWriter.a PATHS ${LLVM_LIBRARY_DIRS}) +find_library(LLD_MACHO NAMES lldMachO.a liblldMachO.a PATHS ${LLVM_LIBRARY_DIRS}) +find_library(LLD_YAML NAMES lldYAML.a liblldYAML.a PATHS ${LLVM_LIBRARY_DIRS}) + +set(lld_libs + ${LLD_COFF} + ${LLD_COMMON} + ${LLD_WASM} + ${LLD_MINGW} + ${LLD_ELF} + ${LLD_DRIVER} + ${LLD_READER_WRITER} + ${LLD_MACHO} + ${LLD_YAML} + ${LLD_CORE} + ) +add_library(c3c_wrappers STATIC wrapper/src/wrapper.cpp) add_executable(c3c src/main.c @@ -107,11 +138,29 @@ add_executable(c3c src/utils/vmem.c src/utils/vmem.h src/utils/whereami.c - src/compiler/llvm_codegen_c_abi_x86.c src/compiler/c_abi_internal.h src/compiler/llvm_codegen_c_abi_x64.c src/compiler/llvm_codegen_c_abi_win64.c src/compiler/llvm_codegen_c_abi_aarch64.c src/compiler/headers.c src/compiler/llvm_codegen_c_abi_riscv.c src/compiler/llvm_codegen_c_abi_wasm.c) + src/compiler/llvm_codegen_c_abi_x86.c + src/compiler/c_abi_internal.h + src/compiler/llvm_codegen_c_abi_x64.c + src/compiler/llvm_codegen_c_abi_win64.c + src/compiler/llvm_codegen_c_abi_aarch64.c + src/compiler/headers.c + src/compiler/llvm_codegen_c_abi_riscv.c + src/compiler/llvm_codegen_c_abi_wasm.c) target_compile_options(c3c PRIVATE -Wsign-compare -Wimplicit-int -Werror -Wall -Wno-unknown-pragmas -Wextra -Wno-unused-function -Wno-unused-variable -Wno-unused-parameter) -target_link_libraries(c3c m ${llvm_libs}) +target_include_directories(c3c PRIVATE + "${CMAKE_SOURCE_DIR}/src/") + +target_include_directories(c3c_wrappers PRIVATE + "${CMAKE_SOURCE_DIR}/wrapper/src/") + + +message(STATUS "Found LLD ${lld_libs}") + +target_link_libraries(c3c_wrappers ${llvm_libs} ${lld_libs}) +#target_link_libraries(c3c m ${llvm_libs} c3c_wrappers lldCommon lldCore lldCOFF lldWASM lldMinGW lldELF lldDriver lldReaderWriter lldMachO lldYAML) +target_link_libraries(c3c m ${llvm_libs} c3c_wrappers ${lld_libs}) install(TARGETS c3c DESTINATION bin) diff --git a/src/build/build_options.c b/src/build/build_options.c index ed120e659..6d3028c76 100644 --- a/src/build/build_options.c +++ b/src/build/build_options.c @@ -330,7 +330,7 @@ static void parse_option(BuildOptions *options) if (at_end() || next_is_opt()) error_exit("error: --target needs a arch+os definition."); const char *target = next_arg(); ArchOsTarget target_arch_os = arch_os_target_from_string(target); - if (target_arch_os >= 0) + if (target_arch_os != ARCH_OS_TARGET_DEFAULT) { options->arch_os_target_override = target_arch_os; return; @@ -473,5 +473,5 @@ ArchOsTarget arch_os_target_from_string(const char *target) return i; } } - return -1; + return ARCH_OS_TARGET_DEFAULT; } \ No newline at end of file diff --git a/src/compiler/compiler.c b/src/compiler/compiler.c index 8249fbcba..e436457dc 100644 --- a/src/compiler/compiler.c +++ b/src/compiler/compiler.c @@ -31,9 +31,9 @@ void compiler_init(void) vmem_init(&tokdata_arena, 4 * 1024); vmem_init(&type_info_arena, 1024); // Create zero index value. - SourceLocation *loc = sourceloc_calloc(); - char *token_type = toktype_calloc(); - TokenData *data = tokdata_calloc(); + (void) sourceloc_calloc(); + (void) toktype_calloc(); + (void) tokdata_calloc(); compiler.lib_dir = find_lib_dir(); } @@ -172,9 +172,7 @@ void compiler_compile(BuildTarget *target) bool create_exe = !target->test_output && (target->type == TARGET_TYPE_EXECUTABLE || target->type == TARGET_TYPE_TEST); -#if PLATFORM_WINDOWS - create_exe = false; -#endif + const char **obj_files = NULL; for (unsigned i = 0; i < source_count; i++) @@ -184,7 +182,7 @@ void compiler_compile(BuildTarget *target) vec_add(obj_files, file_name); } - if (create_exe) + if (create_exe && obj_format_linking_supported(platform_target.object_format)) { linker(target->name, obj_files, source_count); if (target->run_after_compile) diff --git a/src/compiler/compiler_internal.h b/src/compiler/compiler_internal.h index e5a09ca55..278cba00d 100644 --- a/src/compiler/compiler_internal.h +++ b/src/compiler/compiler_internal.h @@ -1441,7 +1441,7 @@ static inline Ast *extend_ast_with_prev_token(Context *context, Ast *ast) -void builtin_setup(Target *target); +void builtin_setup(PlatformTarget *target); static inline bool builtin_may_negate(Type *canonical) { @@ -1554,27 +1554,24 @@ void lexer_init_for_test(Lexer *lexer, const char *text, size_t len); void lexer_init_with_file(Lexer *lexer, File *file); File* lexer_current_file(Lexer *lexer); -static inline SourceLocation *TOKILOC(TokenId token) { return sourcelocptr(token.index); } -static inline SourceLocation *TOKKLOC(Token token) { return sourcelocptr(token.id.index); } + +static inline SourceLocation *tokenid_loc(TokenId token) { return sourcelocptr(token.index); } +static inline SourceLocation *token_loc(Token token) { return sourcelocptr(token.id.index); } static inline TokenData *tokendata_from_id(TokenId token) { return tokdataptr(token.index); } +static inline TokenData *tokendata_from_token(Token token) { return tokdataptr(token.id.index); } -#define TOKLOC(T) _Generic((T), TokenId: TOKILOC, Token: TOKKLOC)(T) +#define TOKDATA(T) _Generic((T), TokenId: tokendata_from_id, Token: tokendata_from_token)(T) +#define TOKLOC(T) _Generic((T), TokenId: tokenid_loc, Token: token_loc)(T) -static inline const char *TOKISTR(TokenId token) { return tokendata_from_id(token)->string; } -static inline const char *TOKKSTR(Token token) { return tokendata_from_id(token.id)->string; } -#define TOKSTR(T) _Generic((T), TokenId: TOKISTR, Token: TOKKSTR)(T) +#define TOKSTR(T) TOKDATA(T)->string -static inline double TOKIREAL(TokenId token) { return tokendata_from_id(token)->value; } -static inline double TOKKREAL(Token token) { return tokendata_from_id(token.id)->value; } -#define TOKREAL(T) _Generic((T), TokenId: TOKIREAL, Token: TOKKREAL)(T) +#define TOKREAL(T) TOKDATA(T)->value -static inline TokenType TOKITYPE(TokenId token) { return toktypeptr(token.index)[0]; } -static inline TokenType TOKKTYPE(Token token) { return toktypeptr(token.id.index)[0]; } -#define TOKTYPE(T) _Generic((T), TokenId: TOKITYPE, Token: TOKKTYPE)(T) +static inline TokenType tokenid_type(TokenId token) { return toktypeptr(token.index)[0]; } +static inline TokenType token_type(Token token) { return toktypeptr(token.id.index)[0]; } +#define TOKTYPE(T) _Generic((T), TokenId: tokenid_type, Token: token_type)(T) -static inline uint32_t TOKILEN(TokenId token) { return TOKILOC(token)->length; } -static inline uint32_t TOKKLEN(Token token) { return TOKKLOC(token)->length; } -#define TOKLEN(T) _Generic((T), TokenId: TOKILEN, Token:TOKKLEN)(T) +#define TOKLEN(T) TOKLOC(T)->length #define TOKVALID(_tok) (_tok.index != 0) Decl *module_find_symbol(Module *module, const char *symbol, ModuleSymbolSearch search, Decl **private_decl); @@ -2000,8 +1997,10 @@ static inline size_t type_min_alignment(size_t a, size_t b) return (a | b) & (1 + ~(a | b)); } +bool obj_format_linking_supported(ObjectFormatType format_type); void linker(const char *output_file, const char **files, unsigned file_count); + #define TRY_AST_OR(_ast_stmt, _res) ({ Ast* _ast = (_ast_stmt); if (!ast_ok(_ast)) return _res; _ast; }) #define TRY_EXPR_OR(_expr_stmt, _res) ({ Expr* _expr = (_expr_stmt); if (!expr_ok(_expr)) return _res; _expr; }) #define TRY_TYPE_OR(_type_stmt, _res) ({ TypeInfo* _type = (_type_stmt); if (!type_info_ok(_type)) return _res; _type; }) diff --git a/src/compiler/context.c b/src/compiler/context.c index 65d16db4f..08ebcb064 100644 --- a/src/compiler/context.c +++ b/src/compiler/context.c @@ -191,8 +191,8 @@ bool context_add_import(Context *context, Path *path, Token token, Token alias) import->import.symbol = token.id; if (alias.type != TOKEN_INVALID_TOKEN) { - const char *alias_name = TOKKSTR(alias); - if (alias_name == TOKKSTR(token)) + const char *alias_name = TOKSTR(alias); + if (alias_name == TOKSTR(token)) { SEMA_TOKEN_ERROR(alias, "If an alias would be the same as the symbol aliased, it wouldn't have any effect."); return false; diff --git a/src/compiler/lexer.c b/src/compiler/lexer.c index 782b9291e..e924ced38 100644 --- a/src/compiler/lexer.c +++ b/src/compiler/lexer.c @@ -636,7 +636,7 @@ static inline bool scan_char(Lexer *lexer) lexer->lexing_start = start; return add_error_token(lexer, "Expected a four character hex value after \\u."); } - if (build_target.little_endian) + if (platform_target.little_endian) { bytes.b[width++] = hex & 0xFF; bytes.b[width++] = hex >> 8; @@ -656,7 +656,7 @@ static inline bool scan_char(Lexer *lexer) lexer->lexing_start = start; return add_error_token(lexer, "Expected an eight character hex value after \\U."); } - if (build_target.little_endian) + if (platform_target.little_endian) { bytes.b[width++] = hex & 0xFF; bytes.b[width++] = (hex >> 8) & 0xFF; diff --git a/src/compiler/linker.c b/src/compiler/linker.c index 46b1afc22..cb5707af2 100644 --- a/src/compiler/linker.c +++ b/src/compiler/linker.c @@ -1,30 +1,86 @@ #include "compiler_internal.h" -#if PLATFORM_WINDOWS -static void link_exe(const char *output_file, const char **files_to_link, unsigned file_count) -{ - TODO -} -#else -static void link_exe(const char *output_file, const char **files_to_link, unsigned file_count) -{ - char *result = NULL; - asprintf(&result, "cc -o %s ", output_file); +extern bool llvm_link_elf(const char **args, int arg_count, const char** error_string); +extern bool llvm_link_macho(const char **args, int arg_count, const char** error_string); +extern bool llvm_link_coff(const char **args, int arg_count, const char** error_string); +extern bool llvm_link_wasm(const char **args, int arg_count, const char** error_string); +extern bool llvm_link_mingw(const char **args, int arg_count, const char** error_string); +static void link_exe(const char *output_file, const char **files_to_link, unsigned file_count) +{ + int arg_count = (int)file_count + 2; + const char **args = NULL; + vec_add(args, "-o"); + vec_add(args, output_file); + vec_add(args, "-m"); + vec_add(args, platform_target.target_triple); for (unsigned i = 0; i < file_count; i++) { - char *new_res = NULL; - asprintf(&new_res, "%s %s", result, files_to_link[i]); - free(result); - result = new_res; + args[i + 2] = files_to_link[i]; } - if (system(result) != EXIT_SUCCESS) + const char *error = NULL; + + switch (platform_target.os) { - error_exit("Failed to create an executable."); + case OS_TYPE_WIN32: + break; + case OS_TYPE_WATCHOS: + case OS_TYPE_MACOSX: + vec_add(args, "-lSystem"); + vec_add(args, "-lm"); + vec_add(args, "-syslibroot"); + vec_add(args, "/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk"); + break; + case OS_TYPE_LINUX: + vec_add(args, "-lc"); + vec_add(args, "-lm"); + break; + default: + break; + } + + bool success; + switch (platform_target.object_format) + { + case OBJ_FORMAT_COFF: + success = llvm_link_coff(args, arg_count, &error); + break; + case OBJ_FORMAT_ELF: + success = llvm_link_elf(args, arg_count, &error); + break; + case OBJ_FORMAT_MACHO: + success = llvm_link_macho(args, arg_count, &error); + break; + case OBJ_FORMAT_WASM: + success = llvm_link_wasm(args, arg_count, &error); + break; + default: + UNREACHABLE + } + if (!success) + { + error_exit("Failed to create an executable: %s", error); } } -#endif +bool obj_format_linking_supported(ObjectFormatType format_type) +{ + switch (format_type) + { + case OBJ_FORMAT_XCOFF: + case OBJ_FORMAT_AOUT: + case OBJ_FORMAT_GOFF: + case OBJ_FORMAT_UNSUPPORTED: + return false; + case OBJ_FORMAT_COFF: + case OBJ_FORMAT_ELF: + case OBJ_FORMAT_MACHO: + case OBJ_FORMAT_WASM: + return true; + } + UNREACHABLE + +} void linker(const char *output_file, const char **files, unsigned file_count) { link_exe(output_file, files, file_count); diff --git a/src/compiler/llvm_codegen.c b/src/compiler/llvm_codegen.c index f6744d216..89b702b9e 100644 --- a/src/compiler/llvm_codegen.c +++ b/src/compiler/llvm_codegen.c @@ -419,7 +419,7 @@ static void gencontext_verify_ir(GenContext *context) void gencontext_emit_object_file(GenContext *context) { char *err = ""; - LLVMSetTarget(context->module, build_target.target_triple); + LLVMSetTarget(context->module, platform_target.target_triple); char *layout = LLVMCopyStringRepOfTargetData(target_data_layout()); LLVMSetDataLayout(context->module, layout); LLVMDisposeMessage(layout); diff --git a/src/compiler/llvm_codegen_c_abi.c b/src/compiler/llvm_codegen_c_abi.c index 590849c23..b6f48fcdf 100644 --- a/src/compiler/llvm_codegen_c_abi.c +++ b/src/compiler/llvm_codegen_c_abi.c @@ -183,7 +183,7 @@ ABIArgInfo *abi_arg_new_expand_padded(Type *padding) void c_abi_func_create(FunctionSignature *signature) { - switch (build_target.abi) + switch (platform_target.abi) { case ABI_X64: c_abi_func_create_x64(signature); @@ -223,7 +223,7 @@ ABIArgInfo *c_abi_classify_argument_type_default(Type *type) // Struct-likes are returned by sret if (type_is_abi_aggregate(type)) return abi_arg_new_indirect_by_val(); - if (type_is_int128(type) && !build_target.int_128) return abi_arg_new_indirect_by_val(); + if (type_is_int128(type) && !platform_target.int128) return abi_arg_new_indirect_by_val(); // Otherwise do we have a type that needs promotion? if (type_is_promotable_integer(type)) return abi_arg_new_direct_int_ext(type); diff --git a/src/compiler/llvm_codegen_c_abi_aarch64.c b/src/compiler/llvm_codegen_c_abi_aarch64.c index a0a207977..8edda5edb 100644 --- a/src/compiler/llvm_codegen_c_abi_aarch64.c +++ b/src/compiler/llvm_codegen_c_abi_aarch64.c @@ -32,7 +32,7 @@ ABIArgInfo *aarch64_classify_argument_type(Type *type) { // Over 128 bits should be indirect, but // we don't have that (yet?) - if (type_is_promotable_integer(type) && build_target.aarch64.is_darwin_pcs) + if (type_is_promotable_integer(type) && platform_target.aarch64.is_darwin_pcs) { return abi_arg_new_direct_int_ext(type); } @@ -57,7 +57,7 @@ ABIArgInfo *aarch64_classify_argument_type(Type *type) { // For RenderScript <= 16 needs to be coerced. AlignSize alignment = type_abi_alignment(type); - if (build_target.aarch64.is_aapcs) + if (platform_target.aarch64.is_aapcs) { alignment = alignment < 16 ? 8 : 16; } @@ -100,7 +100,7 @@ ABIArgInfo *aarch64_classify_return_type(Type *type, bool variadic) if (!type_is_abi_aggregate(type)) { - if (type_is_promotable_integer(type) && build_target.aarch64.is_darwin_pcs) + if (type_is_promotable_integer(type) && platform_target.aarch64.is_darwin_pcs) { return abi_arg_new_direct_int_ext(type); } @@ -115,7 +115,7 @@ ABIArgInfo *aarch64_classify_return_type(Type *type, bool variadic) Type *base = NULL; unsigned members = 0; if (type_is_homogenous_aggregate(type, &base, &members) && - !(build_target.arch == ARCH_TYPE_AARCH64_32 && variadic)) + !(platform_target.arch == ARCH_TYPE_AARCH64_32 && variadic)) { return abi_arg_ignore(); } diff --git a/src/compiler/llvm_codegen_c_abi_riscv.c b/src/compiler/llvm_codegen_c_abi_riscv.c index a1c9b37fb..3201d16da 100644 --- a/src/compiler/llvm_codegen_c_abi_riscv.c +++ b/src/compiler/llvm_codegen_c_abi_riscv.c @@ -36,11 +36,11 @@ static bool riscv_detect_fpcc_struct_internal(Type *type, unsigned current_offse { bool is_int = type_is_integer(type); bool is_float = type_is_float(type); - unsigned flen = build_target.riscv.flen; + unsigned flen = platform_target.riscv.flen; unsigned size = type_size(type); if (is_int || is_float) { - if (is_int && size > build_target.riscv.xlen) return false; + if (is_int && size > platform_target.riscv.xlen) return false; // Can't be eligible if larger than the FP registers. Half precision isn't // currently supported on RISC-V and the ABI hasn't been confirmed, so // default to the integer ABI in that case. @@ -162,7 +162,7 @@ static ABIArgInfo *riscv_classify_argument_type(Type *type, bool is_fixed, unsig assert(type == type->canonical); - unsigned xlen = build_target.riscv.xlen; + unsigned xlen = platform_target.riscv.xlen; // Ignore empty structs/unions. if (type_is_empty_union_struct(type, true)) return abi_arg_ignore(); @@ -170,7 +170,7 @@ static ABIArgInfo *riscv_classify_argument_type(Type *type, bool is_fixed, unsig ByteSize size = type_size(type); // Pass floating point values via FPRs if possible. - if (is_fixed && type_is_float(type) && build_target.riscv.flen >= size && *fprs) + if (is_fixed && type_is_float(type) && platform_target.riscv.flen >= size && *fprs) { (*fprs)--; return abi_arg_new_direct(); @@ -181,7 +181,7 @@ static ABIArgInfo *riscv_classify_argument_type(Type *type, bool is_fixed, unsig if (is_fixed && type->type_kind == TYPE_COMPLEX && *fprs >= 2) { Type *element_type = type->complex; - if (type_size(element_type) <= build_target.riscv.flen) + if (type_size(element_type) <= platform_target.riscv.flen) { (*fprs) -= 2; // TODO check that this will expand correctly. @@ -189,7 +189,7 @@ static ABIArgInfo *riscv_classify_argument_type(Type *type, bool is_fixed, unsig } } - if (is_fixed && build_target.riscv.flen && (type->type_kind == TYPE_STRUCT || type->type_kind == TYPE_ERRTYPE)) + if (is_fixed && platform_target.riscv.flen && (type->type_kind == TYPE_STRUCT || type->type_kind == TYPE_ERRTYPE)) { AbiType *field1 = NULL; AbiType *field2 = NULL; @@ -242,7 +242,7 @@ static ABIArgInfo *riscv_classify_argument_type(Type *type, bool is_fixed, unsig { return abi_arg_new_expand_padded(type_int_unsigned_by_bitsize(xlen * 8)); } - if (size > 16 || (size > 8 && !build_target.int_128)) + if (size > 16 || (size > 8 && !platform_target.int128)) { return abi_arg_new_indirect_not_by_val(); } @@ -259,7 +259,7 @@ static ABIArgInfo *riscv_classify_argument_type(Type *type, bool is_fixed, unsig { return abi_arg_new_direct_coerce(abi_type_new_int_bits(xlen * 8)); } - if (alignment == 2 * build_target.riscv.xlen) + if (alignment == 2 * platform_target.riscv.xlen) { return abi_arg_new_direct_coerce(abi_type_new_int_bits(xlen * 16)); } @@ -275,7 +275,7 @@ static ABIArgInfo *riscv_classify_return(Type *return_type) if (return_type->type_kind == TYPE_VOID) return abi_arg_ignore(); unsigned arg_gpr_left = 2; - unsigned arg_fpr_left = build_target.riscv.flen ? 2 : 0; + unsigned arg_fpr_left = platform_target.riscv.flen ? 2 : 0; // The rules for return and argument types are the same, so defer to // classifyArgumentType. @@ -306,11 +306,11 @@ void c_abi_func_create_riscv(FunctionSignature *signature) // in LLVM IR, relying on the backend lowering code to rewrite the argument // list and pass indirectly on RV32. bool is_ret_indirect = abi_arg_is_indirect(return_abi); - if (!is_ret_indirect && type_is_scalar(return_type) && type_size(return_type) > 2 * build_target.riscv.xlen) + if (!is_ret_indirect && type_is_scalar(return_type) && type_size(return_type) > 2 * platform_target.riscv.xlen) { - if (return_type->type_kind == TYPE_COMPLEX && build_target.riscv.flen) + if (return_type->type_kind == TYPE_COMPLEX && platform_target.riscv.flen) { - is_ret_indirect = type_size(return_type->complex) > build_target.riscv.flen; + is_ret_indirect = type_size(return_type->complex) > platform_target.riscv.flen; } else { @@ -324,7 +324,7 @@ void c_abi_func_create_riscv(FunctionSignature *signature) // different for variadic arguments, we must also track whether we are // examining a vararg or not. unsigned arg_gprs_left = is_ret_indirect ? gpr - 1 : gpr; - unsigned arg_fprs_left = build_target.riscv.flen ? fpr : 0; + unsigned arg_fprs_left = platform_target.riscv.flen ? fpr : 0; // If we have a failable, then the return type is a parameter. if (signature->failable && signature->rtype->type->type_kind != TYPE_VOID) diff --git a/src/compiler/llvm_codegen_c_abi_x64.c b/src/compiler/llvm_codegen_c_abi_x64.c index ba2110154..1330fd958 100644 --- a/src/compiler/llvm_codegen_c_abi_x64.c +++ b/src/compiler/llvm_codegen_c_abi_x64.c @@ -53,7 +53,7 @@ ABIArgInfo *x64_indirect_return_result(Type *type) } static ByteSize x64_native_vector_size_for_avx(void) { - switch (build_target.x64.avx_level) + switch (platform_target.x64.avx_level) { case AVX_NONE: return 16; @@ -74,7 +74,7 @@ static bool x64_type_is_illegal_vector(Type *type) // Less than 64 bits or larger than the avx native size => not allowed. if (size <= 8 || size > x64_native_vector_size_for_avx()) return true; // If we pass i128 in mem, then check for that. - if (build_target.x64.pass_int128_vector_in_mem) + if (platform_target.x64.pass_int128_vector_in_mem) { // Illegal if i128/u128 TypeKind kind = type->vector.base->type_kind; @@ -354,7 +354,7 @@ void x64_classify_vector(Type *type, ByteSize offset_base, X64Class *current, X6 } if (size == 16 || named_arg || size <= x64_native_vector_size_for_avx()) { - if (build_target.x64.pass_int128_vector_in_mem) return; + if (platform_target.x64.pass_int128_vector_in_mem) return; *lo_class = CLASS_SSE; *hi_class = CLASS_SSEUP; @@ -668,7 +668,7 @@ static AbiType *x64_get_byte_vector_type(Type *type) if (type->type_kind == TYPE_VECTOR) { Type *element = type->vector.base->canonical; - if (build_target.x64.pass_int128_vector_in_mem && type_is_int128(element)) + if (platform_target.x64.pass_int128_vector_in_mem && type_is_int128(element)) { // Convert to u64 return abi_type_new_plain(type_get_vector(type_ulong, type_size(type) / 8)); diff --git a/src/compiler/llvm_codegen_c_abi_x86.c b/src/compiler/llvm_codegen_c_abi_x86.c index 73d688048..36a71fc5b 100644 --- a/src/compiler/llvm_codegen_c_abi_x86.c +++ b/src/compiler/llvm_codegen_c_abi_x86.c @@ -35,7 +35,7 @@ static unsigned x86_stack_alignment(Type *type, unsigned alignment) if (alignment < MIN_ABI_STACK_ALIGN) return 0; // On non-Darwin, the stack type alignment is always 4. - if (!build_target.x86.is_darwin_vector_abi) return MIN_ABI_STACK_ALIGN; + if (!platform_target.x86.is_darwin_vector_abi) return MIN_ABI_STACK_ALIGN; // Otherwise, if the type contains an SSE vector type, the alignment is 16. if (alignment >= 16 && (type_is_simd_vector(type) || type_is_union_struct_with_simd_vector(type))) @@ -55,7 +55,7 @@ static ABIArgInfo *x86_create_indirect_result(Regs *regs, Type *type, ByVal by_v if (regs->int_regs) { regs->int_regs--; - if (!build_target.x86.is_mcu_api) info->attributes.by_reg = true; + if (!platform_target.x86.is_mcu_api) info->attributes.by_reg = true; } return info; } @@ -85,7 +85,7 @@ ABIArgInfo *create_indirect_return_x86(Regs *regs) if (!regs->int_regs) return info; // Consume a register for the return. regs->int_regs--; - if (build_target.x86.is_mcu_api) return info; + if (platform_target.x86.is_mcu_api) return info; return abi_arg_by_reg_attr(info); } @@ -97,7 +97,7 @@ static bool x86_should_return_type_in_reg(Type *type) if (size > 8) return false; // Require power of two for everything except mcu. - if (!build_target.x86.is_mcu_api && !is_power_of_two(size)) return false; + if (!platform_target.x86.is_mcu_api && !is_power_of_two(size)) return false; if (type->type_kind == TYPE_VECTOR) { @@ -172,7 +172,7 @@ ABIArgInfo *x86_classify_return(CallConvention call, Regs *regs, Type *type) if (type->type_kind == TYPE_VECTOR) { // On Darwin, vectors may be returned in registers. - if (build_target.x86.is_darwin_vector_abi) + if (platform_target.x86.is_darwin_vector_abi) { unsigned size = type_size(type); if (size == 16) @@ -194,7 +194,7 @@ ABIArgInfo *x86_classify_return(CallConvention call, Regs *regs, Type *type) if (type_is_abi_aggregate(type)) { // If we don't allow small structs in reg: - if (!build_target.x86.return_small_struct_in_reg_abi && type->type_kind == TYPE_COMPLEX) + if (!platform_target.x86.return_small_struct_in_reg_abi && type->type_kind == TYPE_COMPLEX) { return create_indirect_return_x86(regs); } @@ -212,7 +212,7 @@ ABIArgInfo *x86_classify_return(CallConvention call, Regs *regs, Type *type) Type *single_element = type_abi_find_single_struct_element(type); if (single_element) { - if ((type_is_float(single_element) && !build_target.x86.is_win32_float_struct_abi)) + if ((type_is_float(single_element) && !platform_target.x86.is_win32_float_struct_abi)) { return abi_arg_new_expand(); } @@ -246,13 +246,13 @@ static inline bool x86_should_aggregate_use_direct(CallConvention call, Regs *re // On Windows, aggregates other than HFAs are never passed in registers, and // they do not consume register slots. Homogenous floating-point aggregates // (HFAs) have already been dealt with at this point. - if (build_target.x86.is_win32_float_struct_abi) return false; + if (platform_target.x86.is_win32_float_struct_abi) return false; *needs_padding = false; if (!x86_try_use_free_regs(regs, type)) return false; - if (build_target.x86.is_mcu_api) return true; + if (platform_target.x86.is_mcu_api) return true; switch (call) { @@ -324,7 +324,7 @@ static inline bool x86_can_expand_indirect_aggregate_arg(Type *type) static bool x86_try_use_free_regs(Regs *regs, Type *type) { // 1. Floats are not passed in regs on soft floats. - if (!build_target.x86.use_soft_float && type_is_float(type)) return false; + if (!platform_target.x86.use_soft_float && type_is_float(type)) return false; unsigned size = type_size(type); @@ -338,7 +338,7 @@ static bool x86_try_use_free_regs(Regs *regs, Type *type) // earlier parameters that are passed on the stack. Also, // it does not allow passing >8-byte structs in-register, // even if there are 3 free registers available. - if (build_target.x86.is_mcu_api) + if (platform_target.x86.is_mcu_api) { // 4a. Just return if there are not enough registers. if (size_in_regs > regs->int_regs) return false; @@ -377,7 +377,7 @@ static bool x86_try_put_primitive_in_reg(CallConvention call, Regs *regs, Type * if (!x86_try_use_free_regs(regs, type)) return false; // 2. On MCU, do not use the inreg attribute. - if (build_target.x86.is_mcu_api) return false; + if (platform_target.x86.is_mcu_api) return false; // 3. Reg/fast/vec calls limit it to 32 bits // and integer / pointer types. @@ -442,7 +442,7 @@ static inline ABIArgInfo *x86_classify_vector(Regs *regs, Type *type) // On Windows, vectors are passed directly if registers are available, or // indirectly if not. This avoids the need to align argument memory. Pass // user-defined vector types larger than 512 bits indirectly for simplicity. - if (build_target.x86.is_win32_float_struct_abi) + if (platform_target.x86.is_win32_float_struct_abi) { if (size < 64 && regs->float_regs) { @@ -453,7 +453,7 @@ static inline ABIArgInfo *x86_classify_vector(Regs *regs, Type *type) } // On Darwin, some vectors are passed in memory, we handle this by passing // it as an i8/i16/i32/i64. - if (build_target.x86.is_darwin_vector_abi) + if (platform_target.x86.is_darwin_vector_abi) { if ((size == 1 || size == 2 || size == 4) || (size == 8 && type->vector.len == 1)) { @@ -481,7 +481,7 @@ static inline ABIArgInfo *x86_classify_aggregate(CallConvention call, Regs *regs assert(type_is_abi_aggregate(type)); // Ignore empty unions / structs on non-win. - if (!build_target.x86.is_win32_float_struct_abi && type_is_empty_union_struct(type, true)) + if (!platform_target.x86.is_win32_float_struct_abi && type_is_empty_union_struct(type, true)) { return abi_arg_ignore(); } @@ -491,7 +491,7 @@ static inline ABIArgInfo *x86_classify_aggregate(CallConvention call, Regs *regs // Pass over-aligned aggregates on Windows indirectly. This behavior was // added in MSVC 2015. - if (build_target.x86.is_win32_float_struct_abi && type_abi_alignment(type) > 4) + if (platform_target.x86.is_win32_float_struct_abi && type_abi_alignment(type) > 4) { return x86_create_indirect_result(regs, type, BY_VAL_SKIP); } @@ -506,7 +506,7 @@ static inline ABIArgInfo *x86_classify_aggregate(CallConvention call, Regs *regs ABIArgInfo *info = abi_arg_new_direct_coerce(abi_type_new_int_bits(32)); info->direct_coerce.elements = size_in_regs; // Not in reg on MCU - if (!build_target.x86.is_mcu_api) info->attributes.by_reg = true; + if (!platform_target.x86.is_mcu_api) info->attributes.by_reg = true; return info; } @@ -516,8 +516,8 @@ static inline ABIArgInfo *x86_classify_aggregate(CallConvention call, Regs *regs // optimizations. // Don't do this for the MCU if there are still free integer registers // (see X86_64 ABI for full explanation). - if (size <= 16 && (!build_target.x86.is_mcu_api || !regs->int_regs) && - x86_can_expand_indirect_aggregate_arg(type)) + if (size <= 16 && (!platform_target.x86.is_mcu_api || !regs->int_regs) && + x86_can_expand_indirect_aggregate_arg(type)) { if (!needs_padding_in_reg) return abi_arg_new_expand(); @@ -626,11 +626,11 @@ void c_abi_func_create_x86(FunctionSignature *signature) { case CALL_CONVENTION_NORMAL: case CALL_CONVENTION_SYSCALL: - if (build_target.x86.is_win32_float_struct_abi) + if (platform_target.x86.is_win32_float_struct_abi) { regs.float_regs = 3; } - regs.int_regs = build_target.default_number_regs; + regs.int_regs = platform_target.default_number_regs; break; case CALL_CONVENTION_REGCALL: regs.int_regs = 5; @@ -646,7 +646,7 @@ void c_abi_func_create_x86(FunctionSignature *signature) default: UNREACHABLE } - if (build_target.x86.is_mcu_api) + if (platform_target.x86.is_mcu_api) { regs.float_regs = 0; regs.int_regs = 3; diff --git a/src/compiler/llvm_codegen_debug_info.c b/src/compiler/llvm_codegen_debug_info.c index 83692d5b8..80780aa0a 100644 --- a/src/compiler/llvm_codegen_debug_info.c +++ b/src/compiler/llvm_codegen_debug_info.c @@ -111,10 +111,10 @@ void llvm_emit_debug_function(GenContext *c, Decl *decl) flags |= LLVMDIFlagPrototyped; if (decl->func.attr_noreturn) flags |= LLVMDIFlagNoReturn; - SourceLocation *loc = TOKILOC(decl->span.loc); + SourceLocation *loc = TOKLOC(decl->span.loc); c->debug.function = LLVMDIBuilderCreateFunction(c->debug.builder, c->debug.file, - decl->name, TOKILEN(decl->name_token), + decl->name, TOKLEN(decl->name_token), decl->external_name, strlen(decl->external_name), c->debug.file, loc->line, diff --git a/src/compiler/llvm_codegen_expr.c b/src/compiler/llvm_codegen_expr.c index 2b8174635..6eb512969 100644 --- a/src/compiler/llvm_codegen_expr.c +++ b/src/compiler/llvm_codegen_expr.c @@ -1657,7 +1657,7 @@ static inline LLVMValueRef llvm_fixup_shift_rhs(GenContext *c, LLVMValueRef left LLVMTypeRef left_type = LLVMTypeOf(left); LLVMTypeRef right_type = LLVMTypeOf(right); if (left_type == right_type) return right; - if (LLVMStoreSizeOfType(build_target.target, left_type) < LLVMStoreSizeOfType(build_target.target, right_type)) + if (LLVMStoreSizeOfType(platform_target.target, left_type) < LLVMStoreSizeOfType(platform_target.target, right_type)) { return LLVMBuildTrunc(c->builder, right, left_type, ""); } diff --git a/src/compiler/llvm_codegen_function.c b/src/compiler/llvm_codegen_function.c index 1d26ec404..b8065449e 100644 --- a/src/compiler/llvm_codegen_function.c +++ b/src/compiler/llvm_codegen_function.c @@ -578,7 +578,7 @@ void llvm_emit_function_decl(GenContext *c, Decl *decl) } llvm_attribute_add(c, function, attribute_nounwind, -1); - if (decl->func.attr_stdcall && (build_target.os == OS_TYPE_WIN32)) + if (decl->func.attr_stdcall && (platform_target.os == OS_TYPE_WIN32)) { LLVMSetFunctionCallConv(function, LLVMX86StdcallCallConv); LLVMSetDLLStorageClass(function, LLVMDLLImportStorageClass); diff --git a/src/compiler/llvm_codegen_module.c b/src/compiler/llvm_codegen_module.c index 755aad075..3fd6b68fc 100644 --- a/src/compiler/llvm_codegen_module.c +++ b/src/compiler/llvm_codegen_module.c @@ -32,7 +32,7 @@ void gencontext_begin_module(GenContext *c) LLVMAddModuleFlag(c->module, LLVMModuleFlagBehaviorOverride, pie_level, strlen(pie_level), setting); } - LLVMSetTarget(c->module, build_target.target_triple); + LLVMSetTarget(c->module, platform_target.target_triple); if (c->build_target->debug_info != DEBUG_INFO_NONE) { const char *filename = c->ast_context->file->name; diff --git a/src/compiler/parse_global.c b/src/compiler/parse_global.c index 191ef6b74..972445f4e 100644 --- a/src/compiler/parse_global.c +++ b/src/compiler/parse_global.c @@ -22,7 +22,7 @@ static bool context_next_is_type_with_path_prefix(Context *context) while (1) { current.index += 1; - tok = TOKITYPE(current); + tok = TOKTYPE(current); if (tok != TOKEN_COMMENT) break; } @@ -36,7 +36,7 @@ static bool context_next_is_type_with_path_prefix(Context *context) while (1) { current.index += 1; - tok = TOKITYPE(current); + tok = TOKTYPE(current); if (tok != TOKEN_COMMENT) break; } @@ -816,7 +816,7 @@ static Decl *parse_const_declaration(Context *context, Visibility visibility) { decl->var.type_info = TRY_TYPE_OR(parse_type(context), poisoned_decl); } - decl->name = TOKKSTR(context->tok); + decl->name = TOKSTR(context->tok); decl->name_token = context->tok.id; if (!consume_const_name(context, "const")) return poisoned_decl; diff --git a/src/compiler/parse_stmt.c b/src/compiler/parse_stmt.c index c82e1e426..bdf7324c8 100644 --- a/src/compiler/parse_stmt.c +++ b/src/compiler/parse_stmt.c @@ -42,7 +42,7 @@ static inline void parse_optional_label_target(Context *context, Label *label) if (TOKEN_IS(TOKEN_CONST_IDENT)) { label->span = context->tok.id; - label->name = TOKKSTR(context->tok); + label->name = TOKSTR(context->tok); advance_and_verify(context, TOKEN_CONST_IDENT); } } diff --git a/src/compiler/parser.c b/src/compiler/parser.c index 2b4f9431d..936b71e69 100644 --- a/src/compiler/parser.c +++ b/src/compiler/parser.c @@ -44,8 +44,8 @@ inline void advance(Context *context) // Handle doc comments if (context->next_tok.type == TOKEN_DOC_COMMENT) { - SourceLocation *curr = TOKKLOC(context->tok); - SourceLocation *next = TOKKLOC(context->next_tok); + SourceLocation *curr = TOKLOC(context->tok); + SourceLocation *next = TOKLOC(context->next_tok); vec_add(context->comments, context->next_tok); if (curr->line == next->line) @@ -98,7 +98,7 @@ bool consume(Context *context, TokenType type, const char *message, ...) va_list args; va_start(args, message); - sema_verror_range(TOKKLOC(context->tok), message, args); + sema_verror_range(TOKLOC(context->tok), message, args); va_end(args); return false; } diff --git a/src/compiler/sema_expr.c b/src/compiler/sema_expr.c index df8f9efd0..0e72bd61b 100644 --- a/src/compiler/sema_expr.c +++ b/src/compiler/sema_expr.c @@ -3181,7 +3181,7 @@ static Type *numeric_arithmetic_promotion(Type *type) { case ALL_SIGNED_INTS: case ALL_UNSIGNED_INTS: - if (type->builtin.bitsize < build_target.width_c_int) return type_c_int->canonical; + if (type->builtin.bitsize < platform_target.width_c_int) return type_c_int->canonical; return type; case TYPE_F16: // Promote F16 to a real type. diff --git a/src/compiler/sema_stmts.c b/src/compiler/sema_stmts.c index 100ec9bbb..0357112ba 100644 --- a/src/compiler/sema_stmts.c +++ b/src/compiler/sema_stmts.c @@ -326,8 +326,8 @@ static inline bool sema_analyse_cond(Context *context, Expr *expr, bool cast_to_ static inline bool sema_analyse_stmt_placement(Expr *cond, Ast *stmt) { if (stmt->ast_kind == AST_COMPOUND_STMT) return true; - SourceLocation *end_of_cond = TOKILOC(cond->span.end_loc); - SourceLocation *start_of_then = TOKILOC(stmt->span.loc); + SourceLocation *end_of_cond = TOKLOC(cond->span.end_loc); + SourceLocation *start_of_then = TOKLOC(stmt->span.loc); return end_of_cond->line == start_of_then->line; } @@ -880,8 +880,8 @@ static inline bool sema_analyse_if_stmt(Context *context, Ast *statement) } if (success && statement->if_stmt.then_body->ast_kind != AST_COMPOUND_STMT) { - SourceLocation *end_of_cond = TOKILOC(cond->span.end_loc); - SourceLocation *start_of_then = TOKILOC(statement->if_stmt.then_body->span.loc); + SourceLocation *end_of_cond = TOKLOC(cond->span.end_loc); + SourceLocation *start_of_then = TOKLOC(statement->if_stmt.then_body->span.loc); if (end_of_cond->line != start_of_then->line) { SEMA_ERROR(statement->if_stmt.then_body, diff --git a/src/compiler/target.c b/src/compiler/target.c index 34f66d669..a10e6af88 100644 --- a/src/compiler/target.c +++ b/src/compiler/target.c @@ -13,18 +13,19 @@ static unsigned os_target_alignment_of_int(OsType os, ArchType arch, int bits); static unsigned os_target_alignment_of_float(OsType os, ArchType arch, int bits); static OsType os_from_llvm_string(const char *string); static VendorType vendor_from_llvm_string(const char *string); -unsigned os_target_supports_int128(OsType os, ArchType arch); -unsigned os_target_supports_float16(OsType os, ArchType arch); -unsigned os_target_supports_float128(OsType os, ArchType arch); -unsigned os_target_supports_vec(OsType os, ArchType arch, int bits, bool is_int); +static ObjectFormatType object_format_from_os(OsType os); +static unsigned os_target_supports_int128(OsType os, ArchType arch); +static unsigned os_target_supports_float16(OsType os, ArchType arch); +static unsigned os_target_supports_float128(OsType os, ArchType arch); +static unsigned os_target_supports_vec(OsType os, ArchType arch, int bits, bool is_int); -Target build_target = {}; +PlatformTarget platform_target = {}; int target_alloca_addr_space() { - return build_target.alloca_address_space; + return platform_target.alloca_address_space; } static void type_dump(LLVMTargetDataRef llvm_target_data, LLVMTypeRef type) @@ -203,89 +204,89 @@ void llvm_dump(void) static inline bool os_is_apple(OsType os_type) { - return os_type == OS_TYPE_TVOS || os_type == OS_TYPE_WATCHOS || os_type == OS_TYPE_DARWIN || + return os_type == OS_TYPE_TVOS || os_type == OS_TYPE_WATCHOS || os_type == OS_TYPE_MACOSX || os_type == OS_TYPE_IOS; } static inline void target_setup_arm_abi(void) { - build_target.abi = ABI_ARM; - if (build_target.os) + platform_target.abi = ABI_ARM; + if (platform_target.os) { - build_target.arm.is_win32 = true; - build_target.arm.variant = ARM_AAPCS; - build_target.arm.abi_variant = ARM_ABI_AAPCS16_VFP; + platform_target.arm.is_win32 = true; + platform_target.arm.variant = ARM_AAPCS; + platform_target.arm.abi_variant = ARM_ABI_AAPCS16_VFP; return; } - if (build_target.object_format == OBJ_FORMAT_MACHO) + if (platform_target.object_format == OBJ_FORMAT_MACHO) { - if (build_target.environment_type == ENV_TYPE_EABI - || build_target.os == OS_TYPE_UNKNOWN /* or is M */) + if (platform_target.environment_type == ENV_TYPE_EABI + || platform_target.os == OS_TYPE_UNKNOWN /* or is M */) { - build_target.arm.variant = ARM_AAPCS; + platform_target.arm.variant = ARM_AAPCS; return; } // TODO if (/* is watch abi */ false) { - build_target.arm.variant = ARM_AAPCS16; + platform_target.arm.variant = ARM_AAPCS16; goto SET_ABI; } - build_target.arm.variant = ARM_APCS_GNU; + platform_target.arm.variant = ARM_APCS_GNU; goto SET_ABI; } - switch (build_target.environment_type) + switch (platform_target.environment_type) { case ENV_TYPE_ANDROID: case ENV_TYPE_GNUEABI: case ENV_TYPE_GNUEABIHF: case ENV_TYPE_MUSLEABI: case ENV_TYPE_MUSLEABIHF: - build_target.arm.variant = ARM_AAPCS_LINUX; + platform_target.arm.variant = ARM_AAPCS_LINUX; goto SET_ABI; case ENV_TYPE_EABI: case ENV_TYPE_EABIHF: - build_target.arm.variant = ARM_AAPCS; + platform_target.arm.variant = ARM_AAPCS; goto SET_ABI; case ENV_TYPE_GNU: - build_target.arm.variant = ARM_APCS_GNU; + platform_target.arm.variant = ARM_APCS_GNU; goto SET_ABI; default: break; } - switch (build_target.os) + switch (platform_target.os) { case OS_TYPE_NETBSD: - build_target.arm.variant = ARM_APCS_GNU; + platform_target.arm.variant = ARM_APCS_GNU; break; case OS_TYPE_OPENBSD: - build_target.arm.variant = ARM_AAPCS_LINUX; + platform_target.arm.variant = ARM_AAPCS_LINUX; break; default: - build_target.arm.variant = ARM_AAPCS; + platform_target.arm.variant = ARM_AAPCS; break; } SET_ABI: - switch (build_target.arm.variant) + switch (platform_target.arm.variant) { case ARM_APCS_GNU: - build_target.arm.abi_variant = ARM_ABI_APCS; + platform_target.arm.abi_variant = ARM_ABI_APCS; return; case ARM_AAPCS16: - build_target.arm.abi_variant = ARM_ABI_AAPCS16_VFP; + platform_target.arm.abi_variant = ARM_ABI_AAPCS16_VFP; return; case ARM_AAPCS: case ARM_AAPCS_LINUX: - if (build_target.float_abi == FLOAT_ABI_HARD || - (build_target.float_abi != FLOAT_ABI_SOFT && - (build_target.environment_type == ENV_TYPE_GNUEABIHF || - build_target.environment_type == ENV_TYPE_MUSLEABIHF || - build_target.environment_type == ENV_TYPE_EABIHF))) + if (platform_target.float_abi == FLOAT_ABI_HARD || + (platform_target.float_abi != FLOAT_ABI_SOFT && + (platform_target.environment_type == ENV_TYPE_GNUEABIHF || + platform_target.environment_type == ENV_TYPE_MUSLEABIHF || + platform_target.environment_type == ENV_TYPE_EABIHF))) { - build_target.arm.abi_variant = ARM_ABI_AAPCS_VFP; + platform_target.arm.abi_variant = ARM_ABI_AAPCS_VFP; return; } - build_target.arm.abi_variant = ARM_ABI_AAPCS; + platform_target.arm.abi_variant = ARM_ABI_AAPCS; break; } UNREACHABLE @@ -293,62 +294,61 @@ static inline void target_setup_arm_abi(void) static inline void target_setup_x86_abi(BuildTarget *target) { - build_target.abi = ABI_X86; - build_target.x86.is_win_api = build_target.os == OS_TYPE_WIN32; - if (os_is_apple(build_target.os)) + platform_target.abi = ABI_X86; + platform_target.x86.is_win_api = platform_target.os == OS_TYPE_WIN32; + if (os_is_apple(platform_target.os)) { - build_target.x86.is_darwin_vector_abi = true; + platform_target.x86.is_darwin_vector_abi = true; } - build_target.x86.use_soft_float = build_target.float_abi == FLOAT_ABI_SOFT; + platform_target.x86.use_soft_float = platform_target.float_abi == FLOAT_ABI_SOFT; // Build target override. if (target->feature.soft_float != SOFT_FLOAT_DEFAULT) { - build_target.x86.use_soft_float = target->feature.soft_float == SOFT_FLOAT_YES; + platform_target.x86.use_soft_float = target->feature.soft_float == SOFT_FLOAT_YES; } - build_target.x86.is_win32_float_struct_abi = build_target.os == OS_TYPE_WIN32; - build_target.x86.is_mcu_api = build_target.os == OS_TYPE_ELFIAMCU; - if (build_target.environment_type == ENV_TYPE_CYGNUS - || build_target.environment_type == ENV_TYPE_GNU) + platform_target.x86.is_win32_float_struct_abi = platform_target.os == OS_TYPE_WIN32; + platform_target.x86.is_mcu_api = platform_target.os == OS_TYPE_ELFIAMCU; + if (platform_target.environment_type == ENV_TYPE_CYGNUS + || platform_target.environment_type == ENV_TYPE_GNU) { - build_target.x86.is_win32_float_struct_abi = false; + platform_target.x86.is_win32_float_struct_abi = false; } - switch (build_target.os) + switch (platform_target.os) { case OS_TYPE_MACOSX: case OS_TYPE_IOS: case OS_TYPE_WATCHOS: case OS_TYPE_TVOS: - case OS_TYPE_DARWIN: case OS_TYPE_DRAGON_FLY: case OS_TYPE_FREE_BSD: case OS_TYPE_ELFIAMCU: case OS_TYPE_OPENBSD: case OS_TYPE_WIN32: - build_target.x86.return_small_struct_in_reg_abi = true; + platform_target.x86.return_small_struct_in_reg_abi = true; break; default: break; } if (target->feature.struct_return != STRUCT_RETURN_DEFAULT) { - build_target.x86.return_small_struct_in_reg_abi = target->feature.struct_return == STRUCT_RETURN_REG; + platform_target.x86.return_small_struct_in_reg_abi = target->feature.struct_return == STRUCT_RETURN_REG; } } static inline void target_setup_x64_abi(void) { - build_target.abi = ABI_X64; - build_target.x64.avx_level = AVX; - build_target.x64.is_win64 = build_target.os == OS_TYPE_WIN32; - if (build_target.environment_type == ENV_TYPE_GNU) + platform_target.abi = ABI_X64; + platform_target.x64.avx_level = AVX; + platform_target.x64.is_win64 = platform_target.os == OS_TYPE_WIN32; + if (platform_target.environment_type == ENV_TYPE_GNU) { - build_target.x64.is_mingw64 = build_target.x64.is_win64; + platform_target.x64.is_mingw64 = platform_target.x64.is_win64; } - if (build_target.os == OS_TYPE_LINUX || build_target.os == OS_TYPE_NETBSD) + if (platform_target.os == OS_TYPE_LINUX || platform_target.os == OS_TYPE_NETBSD) { - build_target.x64.pass_int128_vector_in_mem = true; + platform_target.x64.pass_int128_vector_in_mem = true; } } @@ -372,270 +372,25 @@ static char *arch_to_target_triple[ARCH_OS_TARGET_LAST + 1] = { }; -void target_setup(BuildTarget *target) -{ - assert(!build_target.target); - - LLVMInitializeAllTargetInfos(); - LLVMInitializeAllTargetMCs(); - LLVMInitializeAllTargets(); - LLVMInitializeAllAsmPrinters(); - LLVMInitializeAllAsmParsers(); - - build_target.target = NULL; - - const char *triple; - if (target->arch_os_target == ARCH_OS_TARGET_DEFAULT) - { - triple = LLVMGetDefaultTargetTriple(); - } - else - { - triple = arch_to_target_triple[target->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. - } - - build_target.alloca_address_space = 0; - - DEBUG_LOG("Target set to %s.", triple); - // Create a specific target machine - LLVMCodeGenOptLevel level; - LLVMRelocMode reloc_mode = LLVMRelocDefault; - - switch (target->optimization_level) - { - case OPTIMIZATION_NOT_SET: - UNREACHABLE; - case OPTIMIZATION_AGGRESSIVE: - level = LLVMCodeGenLevelAggressive; - break; - case OPTIMIZATION_DEFAULT: - level = LLVMCodeGenLevelDefault; - break; - case OPTIMIZATION_LESS: - level = LLVMCodeGenLevelLess; - break; - case OPTIMIZATION_NONE: - level = LLVMCodeGenLevelNone; - break; - default: - UNREACHABLE; - } - if (target->pic == PIC_BIG || target->pic == PIC_SMALL || (target->type != TARGET_TYPE_EXECUTABLE && target->type != TARGET_TYPE_TEST)) - { - reloc_mode = LLVMRelocPIC; - } - if (target->pic == PIC_NONE) - { - reloc_mode = LLVMRelocStatic; - } - - /* - if (!opt->features) - { - opt->features = ""; - }*/ - if (!(build_target.machine = LLVMCreateTargetMachine(build_target.target, triple, "", "", level, reloc_mode, - LLVMCodeModelDefault))) { - error_exit("Failed to create target machine."); - } - - build_target.llvm_data_layout = LLVMCreateTargetDataLayout(build_target.machine); - - char *target_triple = LLVMGetTargetMachineTriple(build_target.machine); - - 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.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); - build_target.alloca_address_space = 0; - - // Todo PIC or no PIC depending on architecture. - switch (build_target.arch) - { - case ARCH_TYPE_X86_64: - case ARCH_TYPE_X86: - case ARCH_TYPE_PPC64LE: - case ARCH_TYPE_ARM: - case ARCH_TYPE_RISCV32: - case ARCH_TYPE_RISCV64: - build_target.max_size_for_return = build_target.width_pointer * 2 / 8; - break; - case ARCH_TYPE_PPC64: - build_target.max_size_for_return = 0; - break; - default: - FATAL_ERROR("Unsupported architecture."); - } - - build_target.int_128 = os_target_supports_int128(build_target.os, build_target.arch); - build_target.vec_128f = os_target_supports_vec(build_target.os, build_target.arch, 128, false); - build_target.vec_128i = os_target_supports_vec(build_target.os, build_target.arch, 128, true); - build_target.vec_64f = os_target_supports_vec(build_target.os, build_target.arch, 64, false); - build_target.vec_64i = os_target_supports_vec(build_target.os, build_target.arch, 64, true); - build_target.float_128 = os_target_supports_float128(build_target.os, build_target.arch); - build_target.float_16 = os_target_supports_float16(build_target.os, build_target.arch); - build_target.align_byte = os_target_alignment_of_int(build_target.os, build_target.arch, 8); - build_target.align_short = os_target_alignment_of_int(build_target.os, build_target.arch, 16); - build_target.align_int = os_target_alignment_of_int(build_target.os, build_target.arch, 32); - build_target.align_long = os_target_alignment_of_int(build_target.os, build_target.arch, 64); - build_target.align_i128 = os_target_alignment_of_int(build_target.os, build_target.arch, 128); - build_target.align_half = os_target_alignment_of_float(build_target.os, build_target.arch, 16); - build_target.align_float = os_target_alignment_of_float(build_target.os, build_target.arch, 32); - build_target.align_double = os_target_alignment_of_float(build_target.os, build_target.arch, 64); - build_target.align_f128 = os_target_alignment_of_float(build_target.os, build_target.arch, 128); - build_target.align_int = os_target_alignment_of_int(build_target.os, build_target.arch, 32); - build_target.align_pointer = build_target.width_pointer / 8; - build_target.little_endian = LLVMByteOrder(build_target.llvm_data_layout) == LLVMLittleEndian; - build_target.width_c_short = os_target_c_type_bits(build_target.os, build_target.arch, CTYPE_SHORT); - build_target.width_c_int = os_target_c_type_bits(build_target.os, build_target.arch, CTYPE_INT); - build_target.width_c_long = os_target_c_type_bits(build_target.os, build_target.arch, CTYPE_LONG); - build_target.width_c_long_long = os_target_c_type_bits(build_target.os, build_target.arch, CTYPE_LONG_LONG); - - /** - * x86-64: CMOV, CMPXCHG8B, FPU, FXSR, MMX, FXSR, SCE, SSE, SSE2 - * x86-64-v2: (close to Nehalem) CMPXCHG16B, LAHF-SAHF, POPCNT, SSE3, SSE4.1, SSE4.2, SSSE3 - * x86-64-v3: (close to Haswell) AVX, AVX2, BMI1, BMI2, F16C, FMA, LZCNT, MOVBE, XSAVE - * x86-64-v4: AVX512F, AVX512BW, AVX512CD, AVX512DQ, AVX512VL - */ - switch (build_target.arch) - { - case ARCH_TYPE_AARCH64_32: - case ARCH_TYPE_BPFEL: - case ARCH_TYPE_BPFEB: - case ARCH_TYPE_SPARCEL: - case ARCH_TYPE_LE64: - case ARCH_TYPE_AMDIL: - case ARCH_TYPE_AMDIL64: - case ARCH_TYPE_HSAIL: - case ARCH_TYPE_HSAIL64: - case ARCH_TYPE_KALIMBA: - case ARCH_TYPE_SHAVE: - case ARCH_TYPE_RSCRIPT32: - case ARCH_TYPE_RSCRIPT64: - case ARCH_TYPE_LE32: - case ARCH_TYPE_MIPS: - case ARCH_TYPE_MIPSEL: - case ARCH_TYPE_MIPS64EL: - case ARCH_TYPE_MIPS64: - case ARCH_TYPE_AVR: - case ARCH_TYPE_NVPTX64: - case ARCH_TYPE_NVPTX: - case ARCH_TYPE_MSP430: - case ARCH_TYPE_SYSTEMZ: - case ARCH_TYPE_TCELE: - case ARCH_TYPE_TCE: - case ARCH_TYPE_LANAI: - case ARCH_TYPE_HEXAGON: - case ARCH_TYPE_AMDGCN: - case ARCH_TYPE_R600: - case ARCH_TYPE_SPARC: - case ARCH_TYPE_SPARCV9: - case ARCH_TYPE_XCORE: - case ARCH_TYPE_ARC: - case ARCH_TYPE_SPIR64: - case ARCH_TYPE_SPIR: - UNREACHABLE - break; - case ARCH_TYPE_AARCH64: - case ARCH_TYPE_AARCH64_BE: - build_target.aarch.is_darwin = os_is_apple(build_target.os); - build_target.aarch.is_win32 = build_target.os == OS_TYPE_WIN32; - build_target.abi = ABI_AARCH64; - break; - case ARCH_TYPE_WASM32: - case ARCH_TYPE_WASM64: - build_target.abi = ABI_WASM; - break; - case ARCH_TYPE_ARMB: - case ARCH_TYPE_ARM: - case ARCH_TYPE_THUMBEB: - case ARCH_TYPE_THUMB: - target_setup_arm_abi(); - break; - case ARCH_TYPE_PPC: - FATAL_ERROR("PPC32 is not supported."); - case ARCH_TYPE_PPC64: - case ARCH_TYPE_PPC64LE: - if (build_target.object_format != OBJ_FORMAT_ELF) - { - if (build_target.arch == ARCH_TYPE_PPC64LE) - { - FATAL_ERROR("PPC64 LE non-ELF not supported."); - } - FATAL_ERROR("PPC64 not supported"); - } - /** Here we need to have different codegen depending on elf version :( */ - build_target.abi = ABI_PPC64_SVR4; - build_target.ppc64.is_softfp = build_target.float_abi == FLOAT_ABI_SOFT; - /* todo enable if elfv2 */ - build_target.ppc64.is_elfv2 = build_target.arch == ARCH_TYPE_PPC64LE; - /* todo enable if elfv1-qpx */ - build_target.ppc64.has_qpx = false; - break; - case ARCH_TYPE_RISCV64: - case ARCH_TYPE_RISCV32: - build_target.riscv.xlen = 0; // pointer width - build_target.riscv.flen = 32; // ends with f / d (64) - build_target.abi = ABI_RISCV; - TODO - case ARCH_TYPE_X86: - target_setup_x86_abi(target); - break; - case ARCH_TYPE_X86_64: - target_setup_x64_abi(); - build_target.x64.avx_level = 0; /* TODO */ - if (build_target.os == OS_TYPE_WIN32) - { - build_target.abi = ABI_WIN64; - break; - } - build_target.abi = ABI_X64; - break; - case ARCH_TYPE_UNKNOWN: - build_target.abi = ABI_UNKNOWN; - break; - } - // TODO remove - builtin_setup(&build_target); -} void target_destroy() { - assert(build_target.machine); - LLVMDisposeTargetMachine(build_target.machine); + assert(platform_target.machine); + LLVMDisposeTargetMachine(platform_target.machine); } void *target_target() { - return build_target.target; + return platform_target.target; } void *target_machine() { - return build_target.machine; + return platform_target.machine; } void *target_data_layout() { - return build_target.llvm_data_layout; + return platform_target.llvm_data_layout; } static bool arch_is_supported(ArchType arch) @@ -769,12 +524,16 @@ static EnvironmentType environment_type_from_llvm_string(const char *string) #undef STRCASE } -static OsType os_from_llvm_string(const char *string) +static OsType os_from_llvm_string(const char *os_string) { -#define STRCASE(_str, _os) if (strcmp(string, _str) == 0) return _os; + char *string = strdup(os_string); + int len = 0; + while (string[len] >= 'A') len++; + string[len] = '\0'; +#define STRCASE(_str, _os) if (strncmp(string, _str, sizeof(_str)) == 0) { free(string); return _os; } STRCASE("ananas", OS_TYPE_ANANAS) STRCASE("cloudabi", OS_TYPE_CLOUD_ABI) - STRCASE("darwin", OS_TYPE_DARWIN) + STRCASE("darwin", OS_TYPE_MACOSX) STRCASE("dragonfly", OS_TYPE_DRAGON_FLY) STRCASE("freebsd", OS_TYPE_FREE_BSD) STRCASE("fuchsia", OS_TYPE_FUCHSIA) @@ -807,6 +566,7 @@ static OsType os_from_llvm_string(const char *string) STRCASE("hurd", OS_TYPE_HURD) STRCASE("wasi", OS_TYPE_WASI) STRCASE("emscripten", OS_TYPE_EMSCRIPTEN) + free(string); return OS_TYPE_UNKNOWN; #undef STRCASE } @@ -903,68 +663,7 @@ static unsigned arch_pointer_bit_width(OsType os, ArchType arch) } } -unsigned arch_is_big_endian(ArchType arch) -{ - switch (arch) - { - case ARCH_TYPE_UNKNOWN: - case ARCH_TYPE_AVR: - case ARCH_TYPE_ARC: - case ARCH_TYPE_TCE: - case ARCH_TYPE_TCELE: - case ARCH_TYPE_LE32: - case ARCH_TYPE_LE64: - case ARCH_TYPE_AMDIL: - case ARCH_TYPE_AMDIL64: - case ARCH_TYPE_HSAIL: - case ARCH_TYPE_HSAIL64: - case ARCH_TYPE_SPIR: - case ARCH_TYPE_SPIR64: - case ARCH_TYPE_KALIMBA: - case ARCH_TYPE_SHAVE: - case ARCH_TYPE_RSCRIPT32: - case ARCH_TYPE_RSCRIPT64: - UNREACHABLE - case ARCH_TYPE_X86: - case ARCH_TYPE_X86_64: - case ARCH_TYPE_AARCH64: - case ARCH_TYPE_AARCH64_32: - case ARCH_TYPE_ARM: - case ARCH_TYPE_BPFEL: - case ARCH_TYPE_HEXAGON: - case ARCH_TYPE_MIPSEL: - case ARCH_TYPE_MIPS64EL: - case ARCH_TYPE_MSP430: - case ARCH_TYPE_PPC64LE: - case ARCH_TYPE_R600: - case ARCH_TYPE_AMDGCN: - case ARCH_TYPE_RISCV32: - case ARCH_TYPE_RISCV64: - case ARCH_TYPE_SPARCEL: - case ARCH_TYPE_THUMB: - case ARCH_TYPE_XCORE: - case ARCH_TYPE_NVPTX: - case ARCH_TYPE_NVPTX64: - case ARCH_TYPE_WASM64: - case ARCH_TYPE_WASM32: - return false; - case ARCH_TYPE_AARCH64_BE: - case ARCH_TYPE_ARMB: - case ARCH_TYPE_BPFEB: - case ARCH_TYPE_MIPS: - case ARCH_TYPE_MIPS64: - case ARCH_TYPE_PPC64: - case ARCH_TYPE_PPC: - case ARCH_TYPE_SPARC: - case ARCH_TYPE_SPARCV9: - case ARCH_TYPE_SYSTEMZ: - case ARCH_TYPE_THUMBEB: - case ARCH_TYPE_LANAI: - return true; - } - UNREACHABLE -} -unsigned os_target_supports_float16(OsType os, ArchType arch) +static unsigned os_target_supports_float16(OsType os, ArchType arch) { switch (arch) { @@ -975,7 +674,7 @@ unsigned os_target_supports_float16(OsType os, ArchType arch) } } -unsigned os_target_supports_float128(OsType os, ArchType arch) +static unsigned os_target_supports_float128(OsType os, ArchType arch) { switch (arch) { @@ -988,14 +687,14 @@ unsigned os_target_supports_float128(OsType os, ArchType arch) if (os == OS_TYPE_MACOSX) return false; // Only for later OS X 10.4+ return false; case ARCH_TYPE_X86: - if (os == OS_TYPE_DARWIN || os == OS_TYPE_MACOSX) return true; + if (os == OS_TYPE_MACOSX) return true; return false; default: return false; } } -unsigned os_target_supports_vec(OsType os, ArchType arch, int bits, bool is_int) +static unsigned os_target_supports_vec(OsType os, ArchType arch, int bits, bool is_int) { if (bits != 64 && bits != 128) return false; switch (arch) @@ -1005,7 +704,7 @@ unsigned os_target_supports_vec(OsType os, ArchType arch, int bits, bool is_int) case ARCH_TYPE_PPC: return true; case ARCH_TYPE_X86: - if (os == OS_TYPE_DARWIN || os == OS_TYPE_MACOSX) + if (os == OS_TYPE_MACOSX) { // 64i 128f 128i return bits == 128 || is_int; @@ -1016,7 +715,55 @@ unsigned os_target_supports_vec(OsType os, ArchType arch, int bits, bool is_int) } } -unsigned os_target_supports_int128(OsType os, ArchType arch) +static ObjectFormatType object_format_from_os(OsType os) +{ + switch (os) + { + case OS_TYPE_LINUX: + case OS_TYPE_UNKNOWN: + case OS_TYPE_NETBSD: + case OS_TYPE_OPENBSD: + return OBJ_FORMAT_ELF; + case OS_TYPE_ANANAS: + case OS_TYPE_CLOUD_ABI: + case OS_TYPE_DRAGON_FLY: + case OS_TYPE_FREE_BSD: + case OS_TYPE_FUCHSIA: + case OS_TYPE_KFREEBSD: + case OS_TYPE_PS3: + case OS_TYPE_SOLARIS: + case OS_TYPE_HAIKU: + case OS_TYPE_MINIX: + case OS_TYPE_RTEMS: + case OS_TYPE_NACL: + case OS_TYPE_CNK: + case OS_TYPE_CUDA: + case OS_TYPE_NVOPENCL: + case OS_TYPE_AMDHSA: + case OS_TYPE_PS4: + case OS_TYPE_ELFIAMCU: + case OS_TYPE_MESA3D: + case OS_TYPE_CONTIKI: + case OS_TYPE_AMDPAL: + case OS_TYPE_HERMITCORE: + case OS_TYPE_HURD: + case OS_TYPE_EMSCRIPTEN: + return OBJ_FORMAT_UNSUPPORTED; + case OS_TYPE_MACOSX: + case OS_TYPE_IOS: + case OS_TYPE_TVOS: + case OS_TYPE_WATCHOS: + return OBJ_FORMAT_MACHO; + case OS_TYPE_WIN32: + return OBJ_FORMAT_COFF; + case OS_TYPE_AIX: + return OBJ_FORMAT_XCOFF; + case OS_TYPE_WASI: + return OBJ_FORMAT_WASM; + } + UNREACHABLE +} +static unsigned os_target_supports_int128(OsType os, ArchType arch) { switch (arch) { @@ -1028,7 +775,7 @@ unsigned os_target_supports_int128(OsType os, ArchType arch) } } -unsigned os_target_c_type_bits(OsType os, ArchType arch, CType type) +static unsigned os_target_c_type_bits(OsType os, ArchType arch, CType type) { switch (os) { @@ -1050,7 +797,6 @@ unsigned os_target_c_type_bits(OsType os, ArchType arch, CType type) } // Use default break; - case OS_TYPE_DARWIN: case OS_TYPE_MACOSX: case OS_TYPE_LINUX: case OS_TYPE_FREE_BSD: @@ -1202,6 +948,68 @@ static unsigned os_target_alignment_of_int(OsType os, ArchType arch, int bits) UNREACHABLE } +static unsigned arch_little_endian(ArchType arch) +{ + switch (arch) + { + case ARCH_TYPE_UNKNOWN: + case ARCH_TYPE_X86: + case ARCH_TYPE_AARCH64: + case ARCH_TYPE_AARCH64_32: + case ARCH_TYPE_ARM: + case ARCH_TYPE_THUMB: + case ARCH_TYPE_BPFEL: + case ARCH_TYPE_AVR: + case ARCH_TYPE_HEXAGON: + case ARCH_TYPE_PPC64LE: + case ARCH_TYPE_MIPSEL: + case ARCH_TYPE_MIPS64EL: + case ARCH_TYPE_MSP430: + case ARCH_TYPE_X86_64: + case ARCH_TYPE_R600: + case ARCH_TYPE_AMDGCN: + case ARCH_TYPE_RISCV32: + case ARCH_TYPE_RISCV64: + case ARCH_TYPE_SPARCEL: + case ARCH_TYPE_XCORE: + case ARCH_TYPE_NVPTX: + case ARCH_TYPE_NVPTX64: + case ARCH_TYPE_WASM32: + case ARCH_TYPE_WASM64: + return true; + case ARCH_TYPE_ARMB: + case ARCH_TYPE_THUMBEB: + case ARCH_TYPE_AARCH64_BE: + case ARCH_TYPE_BPFEB: + case ARCH_TYPE_MIPS: + case ARCH_TYPE_MIPS64: + case ARCH_TYPE_PPC64: + case ARCH_TYPE_PPC: + case ARCH_TYPE_SPARC: + case ARCH_TYPE_SPARCV9: + case ARCH_TYPE_SYSTEMZ: + case ARCH_TYPE_LANAI: + return false; + case ARCH_TYPE_ARC: + case ARCH_TYPE_LE32: + case ARCH_TYPE_LE64: + case ARCH_TYPE_AMDIL: + case ARCH_TYPE_AMDIL64: + case ARCH_TYPE_HSAIL: + case ARCH_TYPE_HSAIL64: + case ARCH_TYPE_SPIR: + case ARCH_TYPE_SPIR64: + case ARCH_TYPE_KALIMBA: + case ARCH_TYPE_SHAVE: + case ARCH_TYPE_RSCRIPT32: + case ARCH_TYPE_RSCRIPT64: + case ARCH_TYPE_TCE: + case ARCH_TYPE_TCELE: + UNREACHABLE + } + UNREACHABLE +} + static unsigned os_target_pref_alignment_of_int(OsType os, ArchType arch, int bits) { switch (arch) @@ -1427,3 +1235,250 @@ static unsigned os_target_pref_alignment_of_float(OsType os, ArchType arch, int UNREACHABLE } +void target_setup(BuildTarget *target) +{ + assert(!platform_target.target); + + LLVMInitializeAllTargetInfos(); + LLVMInitializeAllTargetMCs(); + LLVMInitializeAllTargets(); + LLVMInitializeAllAsmPrinters(); + LLVMInitializeAllAsmParsers(); + + platform_target.target = NULL; + + const char *triple; + if (target->arch_os_target == ARCH_OS_TARGET_DEFAULT) + { + triple = LLVMGetDefaultTargetTriple(); + } + else + { + triple = arch_to_target_triple[target->arch_os_target]; + } + + char *err = NULL; + if (LLVMGetTargetFromTriple(triple, ((LLVMTargetRef *)&platform_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. + } + + platform_target.alloca_address_space = 0; + + DEBUG_LOG("Target set to %s.", triple); + // Create a specific target machine + LLVMCodeGenOptLevel level; + LLVMRelocMode reloc_mode = LLVMRelocDefault; + + switch (target->optimization_level) + { + case OPTIMIZATION_NOT_SET: + UNREACHABLE; + case OPTIMIZATION_AGGRESSIVE: + level = LLVMCodeGenLevelAggressive; + break; + case OPTIMIZATION_DEFAULT: + level = LLVMCodeGenLevelDefault; + break; + case OPTIMIZATION_LESS: + level = LLVMCodeGenLevelLess; + break; + case OPTIMIZATION_NONE: + level = LLVMCodeGenLevelNone; + break; + default: + UNREACHABLE; + } + if (target->pic == PIC_BIG || target->pic == PIC_SMALL || (target->type != TARGET_TYPE_EXECUTABLE && target->type != TARGET_TYPE_TEST)) + { + reloc_mode = LLVMRelocPIC; + } + if (target->pic == PIC_NONE) + { + reloc_mode = LLVMRelocStatic; + } + + /* + if (!opt->features) + { + opt->features = ""; + }*/ + if (!(platform_target.machine = LLVMCreateTargetMachine(platform_target.target, triple, "", "", level, reloc_mode, + LLVMCodeModelDefault))) { + error_exit("Failed to create target machine."); + } + + platform_target.llvm_data_layout = LLVMCreateTargetDataLayout(platform_target.machine); + + char *target_triple = LLVMGetTargetMachineTriple(platform_target.machine); + + platform_target.target_triple = strdup(target_triple); + platform_target.arch = arch_from_llvm_string(strtok(target_triple, "-")); + if (!arch_is_supported(platform_target.arch)) + { + printf("WARNING! This architecture is not supported.\n"); + } + platform_target.vendor = vendor_from_llvm_string(strtok(NULL, "-")); + platform_target.os = os_from_llvm_string(strtok(NULL, "-")); + char *env = strtok(NULL, "0123456789"); + platform_target.environment_type = env ? environment_type_from_llvm_string(env) : ENV_TYPE_UNKNOWN; + + LLVMDisposeMessage(target_triple); + + platform_target.float_abi = false; + platform_target.little_endian = arch_little_endian(platform_target.arch); + platform_target.width_pointer = arch_pointer_bit_width(platform_target.os, platform_target.arch); + assert(platform_target.width_pointer == LLVMPointerSize(platform_target.llvm_data_layout) * 8); + platform_target.alloca_address_space = 0; + + // Todo PIC or no PIC depending on architecture. + switch (platform_target.arch) + { + case ARCH_TYPE_X86_64: + case ARCH_TYPE_X86: + case ARCH_TYPE_PPC64LE: + case ARCH_TYPE_ARM: + case ARCH_TYPE_RISCV32: + case ARCH_TYPE_RISCV64: + platform_target.max_size_for_return = platform_target.width_pointer * 2 / 8; + break; + case ARCH_TYPE_PPC64: + platform_target.max_size_for_return = 0; + break; + default: + FATAL_ERROR("Unsupported architecture."); + } + + platform_target.object_format = object_format_from_os(platform_target.os); + + platform_target.int128 = os_target_supports_int128(platform_target.os, platform_target.arch); + platform_target.vec128f = os_target_supports_vec(platform_target.os, platform_target.arch, 128, false); + platform_target.vec128i = os_target_supports_vec(platform_target.os, platform_target.arch, 128, true); + platform_target.vec64f = os_target_supports_vec(platform_target.os, platform_target.arch, 64, false); + platform_target.vec64i = os_target_supports_vec(platform_target.os, platform_target.arch, 64, true); + platform_target.float128 = os_target_supports_float128(platform_target.os, platform_target.arch); + platform_target.float16 = os_target_supports_float16(platform_target.os, platform_target.arch); + platform_target.align_byte = os_target_alignment_of_int(platform_target.os, platform_target.arch, 8); + platform_target.align_short = os_target_alignment_of_int(platform_target.os, platform_target.arch, 16); + platform_target.align_int = os_target_alignment_of_int(platform_target.os, platform_target.arch, 32); + platform_target.align_long = os_target_alignment_of_int(platform_target.os, platform_target.arch, 64); + platform_target.align_i128 = os_target_alignment_of_int(platform_target.os, platform_target.arch, 128); + platform_target.align_half = os_target_alignment_of_float(platform_target.os, platform_target.arch, 16); + platform_target.align_float = os_target_alignment_of_float(platform_target.os, platform_target.arch, 32); + platform_target.align_double = os_target_alignment_of_float(platform_target.os, platform_target.arch, 64); + platform_target.align_f128 = os_target_alignment_of_float(platform_target.os, platform_target.arch, 128); + platform_target.align_int = os_target_alignment_of_int(platform_target.os, platform_target.arch, 32); + platform_target.align_pointer = platform_target.width_pointer / 8; + platform_target.width_c_short = os_target_c_type_bits(platform_target.os, platform_target.arch, CTYPE_SHORT); + platform_target.width_c_int = os_target_c_type_bits(platform_target.os, platform_target.arch, CTYPE_INT); + platform_target.width_c_long = os_target_c_type_bits(platform_target.os, platform_target.arch, CTYPE_LONG); + platform_target.width_c_long_long = os_target_c_type_bits(platform_target.os, platform_target.arch, CTYPE_LONG_LONG); + + /** + * x86-64: CMOV, CMPXCHG8B, FPU, FXSR, MMX, FXSR, SCE, SSE, SSE2 + * x86-64-v2: (close to Nehalem) CMPXCHG16B, LAHF-SAHF, POPCNT, SSE3, SSE4.1, SSE4.2, SSSE3 + * x86-64-v3: (close to Haswell) AVX, AVX2, BMI1, BMI2, F16C, FMA, LZCNT, MOVBE, XSAVE + * x86-64-v4: AVX512F, AVX512BW, AVX512CD, AVX512DQ, AVX512VL + */ + switch (platform_target.arch) + { + case ARCH_TYPE_AARCH64_32: + case ARCH_TYPE_BPFEL: + case ARCH_TYPE_BPFEB: + case ARCH_TYPE_SPARCEL: + case ARCH_TYPE_LE64: + case ARCH_TYPE_AMDIL: + case ARCH_TYPE_AMDIL64: + case ARCH_TYPE_HSAIL: + case ARCH_TYPE_HSAIL64: + case ARCH_TYPE_KALIMBA: + case ARCH_TYPE_SHAVE: + case ARCH_TYPE_RSCRIPT32: + case ARCH_TYPE_RSCRIPT64: + case ARCH_TYPE_LE32: + case ARCH_TYPE_MIPS: + case ARCH_TYPE_MIPSEL: + case ARCH_TYPE_MIPS64EL: + case ARCH_TYPE_MIPS64: + case ARCH_TYPE_AVR: + case ARCH_TYPE_NVPTX64: + case ARCH_TYPE_NVPTX: + case ARCH_TYPE_MSP430: + case ARCH_TYPE_SYSTEMZ: + case ARCH_TYPE_TCELE: + case ARCH_TYPE_TCE: + case ARCH_TYPE_LANAI: + case ARCH_TYPE_HEXAGON: + case ARCH_TYPE_AMDGCN: + case ARCH_TYPE_R600: + case ARCH_TYPE_SPARC: + case ARCH_TYPE_SPARCV9: + case ARCH_TYPE_XCORE: + case ARCH_TYPE_ARC: + case ARCH_TYPE_SPIR64: + case ARCH_TYPE_SPIR: + UNREACHABLE + break; + case ARCH_TYPE_AARCH64: + case ARCH_TYPE_AARCH64_BE: + platform_target.aarch.is_darwin = os_is_apple(platform_target.os); + platform_target.aarch.is_win32 = platform_target.os == OS_TYPE_WIN32; + platform_target.abi = ABI_AARCH64; + break; + case ARCH_TYPE_WASM32: + case ARCH_TYPE_WASM64: + platform_target.abi = ABI_WASM; + break; + case ARCH_TYPE_ARMB: + case ARCH_TYPE_ARM: + case ARCH_TYPE_THUMBEB: + case ARCH_TYPE_THUMB: + target_setup_arm_abi(); + break; + case ARCH_TYPE_PPC: + FATAL_ERROR("PPC32 is not supported."); + case ARCH_TYPE_PPC64: + case ARCH_TYPE_PPC64LE: + if (platform_target.object_format != OBJ_FORMAT_ELF) + { + if (platform_target.arch == ARCH_TYPE_PPC64LE) + { + FATAL_ERROR("PPC64 LE non-ELF not supported."); + } + FATAL_ERROR("PPC64 not supported"); + } + /** Here we need to have different codegen depending on elf version :( */ + platform_target.abi = ABI_PPC64_SVR4; + platform_target.ppc64.is_softfp = platform_target.float_abi == FLOAT_ABI_SOFT; + /* todo enable if elfv2 */ + platform_target.ppc64.is_elfv2 = platform_target.arch == ARCH_TYPE_PPC64LE; + /* todo enable if elfv1-qpx */ + platform_target.ppc64.has_qpx = false; + break; + case ARCH_TYPE_RISCV64: + case ARCH_TYPE_RISCV32: + platform_target.riscv.xlen = 0; // pointer width + platform_target.riscv.flen = 32; // ends with f / d (64) + platform_target.abi = ABI_RISCV; + TODO + case ARCH_TYPE_X86: + target_setup_x86_abi(target); + break; + case ARCH_TYPE_X86_64: + target_setup_x64_abi(); + platform_target.x64.avx_level = 0; /* TODO */ + if (platform_target.os == OS_TYPE_WIN32) + { + platform_target.abi = ABI_WIN64; + break; + } + platform_target.abi = ABI_X64; + break; + case ARCH_TYPE_UNKNOWN: + platform_target.abi = ABI_UNKNOWN; + break; + } + // TODO remove + builtin_setup(&platform_target); +} diff --git a/src/compiler/target.h b/src/compiler/target.h index b66111def..3f4ec55df 100644 --- a/src/compiler/target.h +++ b/src/compiler/target.h @@ -76,7 +76,6 @@ typedef enum OS_TYPE_UNKNOWN, OS_TYPE_ANANAS, OS_TYPE_CLOUD_ABI, - OS_TYPE_DARWIN, OS_TYPE_DRAGON_FLY, OS_TYPE_FREE_BSD, OS_TYPE_FUCHSIA, @@ -141,11 +140,14 @@ typedef enum typedef enum { + OBJ_FORMAT_UNSUPPORTED, OBJ_FORMAT_COFF, + OBJ_FORMAT_GOFF, OBJ_FORMAT_ELF, OBJ_FORMAT_MACHO, OBJ_FORMAT_WASM, - OBJ_FORMAT_XCOFF + OBJ_FORMAT_XCOFF, + OBJ_FORMAT_AOUT, } ObjectFormatType; typedef enum @@ -291,13 +293,13 @@ typedef struct bool little_endian; bool tls_supported; bool asm_supported; - bool float_128; - bool float_16; - bool vec_128i; - bool vec_64i; - bool vec_128f; - bool vec_64f; - bool int_128; + bool float128; + bool float16; + bool vec128i; + bool vec64i; + bool vec128f; + bool vec64f; + bool int128; unsigned align_pref_pointer; unsigned align_pref_byte; unsigned align_pref_short; @@ -343,7 +345,7 @@ typedef struct unsigned max_size_for_return; char *platform_name; -} Target; +} PlatformTarget; -extern Target build_target; \ No newline at end of file +extern PlatformTarget platform_target; \ No newline at end of file diff --git a/src/compiler/types.c b/src/compiler/types.c index 8db82640e..36538e1b1 100644 --- a/src/compiler/types.c +++ b/src/compiler/types.c @@ -333,7 +333,7 @@ Type *type_abi_find_single_struct_element(Type *type) static bool type_is_qpx_vector(Type *type) { - if (build_target.abi != ABI_PPC64_SVR4 || !build_target.ppc64.has_qpx) return false; + if (platform_target.abi != ABI_PPC64_SVR4 || !platform_target.ppc64.has_qpx) return false; type = type->canonical; if (type->type_kind != TYPE_VECTOR) return false; if (type->vector.len == 1) return false; @@ -389,17 +389,17 @@ bool type_is_abi_aggregate(Type *type) bool type_is_homogenous_base_type(Type *type) { type = type->canonical; - switch (build_target.abi) + switch (platform_target.abi) { case ABI_PPC64_SVR4: switch (type->type_kind) { case TYPE_F128: - if (!build_target.float_128) return false; + if (!platform_target.float128) return false; FALLTHROUGH; case TYPE_F32: case TYPE_F64: - return !build_target.ppc64.is_softfp; + return !platform_target.ppc64.is_softfp; case TYPE_VECTOR: return type_size(type) == 128 / 8 || type_is_qpx_vector(type); default: @@ -474,10 +474,10 @@ bool type_is_homogenous_base_type(Type *type) bool type_homogenous_aggregate_small_enough(Type *type, unsigned members) { - switch (build_target.abi) + switch (platform_target.abi) { case ABI_PPC64_SVR4: - if (type->type_kind == TYPE_F128 && build_target.float_128) return members <= 8; + if (type->type_kind == TYPE_F128 && platform_target.float128) return members <= 8; if (type->type_kind == TYPE_VECTOR) return members <= 8; return ((type_size(type) + 7) / 8) * members <= 8; case ABI_X64: @@ -614,7 +614,7 @@ bool type_is_homogenous_aggregate(Type *type, Type **base, unsigned *elements) AlignSize type_alloca_alignment(Type *type) { - if (build_target.abi == ABI_X64) + if (platform_target.abi == ABI_X64) { type = type_flatten(type); if (type->type_kind == TYPE_ARRAY && type_size(type) >= 16) return 16; @@ -1035,7 +1035,7 @@ static void type_create_alias(const char *name, Type *location, Type *canonical) } -void builtin_setup(Target *target) +void builtin_setup(PlatformTarget *target) { /*TODO diff --git a/src/main.c b/src/main.c index a1469509a..ac9f5aade 100644 --- a/src/main.c +++ b/src/main.c @@ -6,12 +6,13 @@ #include "utils/lib.h" static int version = 102; - int main(int argc, const char *argv[]) { // First setup memory memory_init(); + + DEBUG_LOG("Version: %d", version); // Init the compiler diff --git a/wrapper/src/wrapper.cpp b/wrapper/src/wrapper.cpp new file mode 100644 index 000000000..84497f1a3 --- /dev/null +++ b/wrapper/src/wrapper.cpp @@ -0,0 +1,102 @@ + +#include +#include + +namespace lld { + namespace coff { + bool link(llvm::ArrayRef args, bool canExitEarly, + llvm::raw_ostream &stdoutOS, llvm::raw_ostream &stderrOS); + } + + namespace mingw { + bool link(llvm::ArrayRef args, bool canExitEarly, + llvm::raw_ostream &stdoutOS, llvm::raw_ostream &stderrOS); + } + + namespace elf { + bool link(llvm::ArrayRef args, bool canExitEarly, + llvm::raw_ostream &stdoutOS, llvm::raw_ostream &stderrOS); + } + + namespace mach_o { + bool link(llvm::ArrayRef args, bool canExitEarly, + llvm::raw_ostream &stdoutOS, llvm::raw_ostream &stderrOS); + } + + namespace macho { + bool link(llvm::ArrayRef args, bool canExitEarly, + llvm::raw_ostream &stdoutOS, llvm::raw_ostream &stderrOS); + } + + namespace wasm { + bool link(llvm::ArrayRef args, bool canExitEarly, + llvm::raw_ostream &stdoutOS, llvm::raw_ostream &stderrOS); + } +} + +typedef enum +{ + ELF, + WASM, + MACHO, + COFF, + MINGW +} ObjFormat; + +static bool llvm_link(ObjFormat format, const char **args, int arg_count, const char** error_string) +{ + std::vector arg_vector = std::vector(arg_count + 1); + for (int i = 0; i < arg_count; i++) arg_vector.push_back(args[i]); + std::string output_string {}; + std::string output_err_string {}; + llvm::raw_string_ostream output { output_string }; + llvm::raw_string_ostream output_err { output_err_string }; + switch (format) + { + case ELF: + if (lld::elf::link(arg_vector, false, output, output_err)) return true; + break; + case MACHO: + if (lld::mach_o::link(arg_vector, false, output, output_err)) return true; + break; + case WASM: + if (lld::wasm::link(arg_vector, false, output, output_err)) return true; + break; + case COFF: + if (lld::coff::link(arg_vector, false, output, output_err)) return true; + break; + default: + exit(-1); + } + *error_string = strdup(output_err_string.c_str()); + return false; +} + +extern "C" { + +bool llvm_link_elf(const char **args, int arg_count, const char** error_string) +{ + return llvm_link(ELF, args, arg_count, error_string); +} + +bool llvm_link_macho(const char **args, int arg_count, const char** error_string) +{ + return llvm_link(MACHO, args, arg_count, error_string); +} + +bool llvm_link_coff(const char **args, int arg_count, const char** error_string) +{ + return llvm_link(COFF, args, arg_count, error_string); +} + +bool llvm_link_wasm(const char **args, int arg_count, const char** error_string) +{ + return llvm_link(WASM, args, arg_count, error_string); +} + +bool llvm_link_mingw(const char **args, int arg_count, const char** error_string) +{ + return llvm_link(MINGW, args, arg_count, error_string); +} + +}