Fix of arch target. Experimental linker support.

This commit is contained in:
Christoffer Lerno
2021-04-09 01:49:36 +02:00
committed by Christoffer Lerno
parent 3a74c4adfc
commit 954a90dae3
28 changed files with 778 additions and 516 deletions

View File

@@ -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 .

View File

@@ -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)

View File

@@ -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;
}

View File

@@ -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)

View File

@@ -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; })

View File

@@ -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;

View File

@@ -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;

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);

View File

@@ -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();
}

View File

@@ -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)

View File

@@ -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));

View File

@@ -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;

View File

@@ -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,

View File

@@ -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, "");
}

View File

@@ -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);

View File

@@ -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;

View File

@@ -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;

View File

@@ -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);
}
}

View File

@@ -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;
}

View File

@@ -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.

View File

@@ -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,

File diff suppressed because it is too large Load Diff

View File

@@ -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;
extern PlatformTarget platform_target;

View File

@@ -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

View File

@@ -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

102
wrapper/src/wrapper.cpp Normal file
View File

@@ -0,0 +1,102 @@
#include <llvm/ADT/ArrayRef.h>
#include <llvm/Support/raw_ostream.h>
namespace lld {
namespace coff {
bool link(llvm::ArrayRef<const char *> args, bool canExitEarly,
llvm::raw_ostream &stdoutOS, llvm::raw_ostream &stderrOS);
}
namespace mingw {
bool link(llvm::ArrayRef<const char *> args, bool canExitEarly,
llvm::raw_ostream &stdoutOS, llvm::raw_ostream &stderrOS);
}
namespace elf {
bool link(llvm::ArrayRef<const char *> args, bool canExitEarly,
llvm::raw_ostream &stdoutOS, llvm::raw_ostream &stderrOS);
}
namespace mach_o {
bool link(llvm::ArrayRef<const char *> args, bool canExitEarly,
llvm::raw_ostream &stdoutOS, llvm::raw_ostream &stderrOS);
}
namespace macho {
bool link(llvm::ArrayRef<const char *> args, bool canExitEarly,
llvm::raw_ostream &stdoutOS, llvm::raw_ostream &stderrOS);
}
namespace wasm {
bool link(llvm::ArrayRef<const char *> 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<const char*> arg_vector = std::vector<const char *>(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);
}
}