diff --git a/CMakeLists.txt b/CMakeLists.txt index 36dfa2dc1..71abf5684 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -106,7 +106,7 @@ 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/llvm_codegen_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/llvm_codegen_c_abi_x86.c src/compiler/llvm_codegen_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) target_compile_options(c3c PRIVATE -Wimplicit-int -Werror -Wall -Wno-unknown-pragmas -Wextra -Wno-unused-function -Wno-unused-variable -Wno-unused-parameter) diff --git a/src/build/build_options.c b/src/build/build_options.c index 2ba014ba7..0e4698d22 100644 --- a/src/build/build_options.c +++ b/src/build/build_options.c @@ -11,19 +11,26 @@ #include #include -#include "../utils/errors.h" - static const int DEFAULT_SYMTAB_SIZE = 64 * 1024; static const int MAX_SYMTAB_SIZE = 1024 * 1024; static char *arch_os_target[ARCH_OS_TARGET_LAST + 1] = { - [X86_DARWIN] = "x86_darwin", + [X86_FREEBSD] = "x86_freebsd", + [X86_OPENBSD] = "x86_openbsd", + [X86_MCU] = "x86_mcu", + [X86_WINDOWS] = "x86-windows", [X86_LINUX] = "x86_linux", [X64_DARWIN] = "x64_darwin", [X64_LINUX] = "x64_linux", [X64_WINDOWS] = "x64_windows", + [X64_WINDOWS_GNU] = "x64_mingw", + [X64_NETBSD] = "x64_netbsd", [AARCH64_LINUX] = "aarch64_linux", [AARCH64_DARWIN] = "aarch64_darwin", + [RISCV32_LINUX] = "riscv32-linux", + [RISCV64_LINUX] = "riscv64-linux", + [WASM32] = "wasm32", + [WASM64] = "wasm64", }; BuildOptions build_options; @@ -53,6 +60,7 @@ static void usage(void) OUTPUT(" bench [] Benchmark a target."); OUTPUT(" clean-run [] Clean, then run the target."); OUTPUT(" compile-run [ ...] Compile files then immediately run the result."); + OUTPUT(" headers [ ...] Analyse files and generate C headers for public methods."); OUTPUT(""); OUTPUT("Options:"); OUTPUT(" --lib - Use this directory as the c3 library path."); @@ -78,6 +86,10 @@ static void usage(void) OUTPUT(" -freg-struct-return - Override default ABI to return small structs in registers."); OUTPUT(" -fpcc-struct-return - Override default ABI to return small structs on the stack."); OUTPUT(" -fno-memcpy-pass - Prevents compiler from doing a mem copy pass (for debug)."); + OUTPUT(" -fpic - Generate position independent (PIC) code if suitable."); + OUTPUT(" -fno-pic - Do not generate position independent code."); + OUTPUT(" -fPIC - Always generate position independent (PIC) code."); + OUTPUT(" -fno-PIC - generate position independent (PIC) code."); OUTPUT(""); OUTPUT(" -msoft-float - Use software floating point."); OUTPUT(" -mno-soft-float - Prevent use of software floating point."); @@ -173,6 +185,11 @@ static void parse_command(void) build_options.command = COMMAND_COMPILE; return; } + if (arg_match("headers")) + { + build_options.command = COMMAND_GENERATE_HEADERS; + return; + } if (arg_match("build")) { build_options.command = COMMAND_BUILD; @@ -260,6 +277,21 @@ static void parse_option(void) build_options.feature.reg_struct_return = true; return; } + if (match_shortopt("fpic")) + { + build_options.pic = SMALL_PIC_USE; + return; + } + if (match_shortopt("fPIC")) + { + build_options.pic = BIG_PIC_USE; + return; + } + if (match_shortopt("fno-pic")) + { + build_options.pic = PIC_NONE; + return; + } if (match_shortopt("fpcc-struct-return")) { build_options.feature.stack_struct_return = true; @@ -466,7 +498,9 @@ void parse_arguments(int argc, const char *argv[]) parse_command(); continue; } - if (build_options.command == COMMAND_COMPILE_RUN || build_options.command == COMMAND_COMPILE) + if (build_options.command == COMMAND_COMPILE_RUN + || build_options.command == COMMAND_COMPILE + || build_options.command == COMMAND_GENERATE_HEADERS) { append_file(); continue; diff --git a/src/build/build_options.h b/src/build/build_options.h index a59a1b8fb..99a899f29 100644 --- a/src/build/build_options.h +++ b/src/build/build_options.h @@ -13,6 +13,7 @@ typedef enum { COMMAND_MISSING = 0, COMMAND_COMPILE, + COMMAND_GENERATE_HEADERS, COMMAND_INIT, COMMAND_BUILD, COMMAND_COMPILE_RUN, @@ -66,6 +67,7 @@ typedef enum COMPILE_NORMAL, COMPILE_LEX_ONLY, COMPILE_LEX_PARSE_ONLY, + COMPILE_OUTPUT_HEADERS, COMPILE_OUTPUT_AST, } CompileOption; @@ -86,6 +88,14 @@ typedef enum SIZE_OPTIMIZATION_TINY = 2, // -Oz } SizeOptimizationLevel; +typedef enum +{ + PIC_DEFAULT, + PIC_NONE, + BIG_PIC_USE, + SMALL_PIC_USE, +} PicGeneration; + typedef enum { DEBUG_INFO_NONE, @@ -96,14 +106,23 @@ typedef enum typedef enum { ARCH_OS_TARGET_DEFAULT = 0, - X86_DARWIN, + X86_FREEBSD, + X86_OPENBSD, X86_LINUX, + X86_WINDOWS, + X86_MCU, X64_DARWIN, X64_LINUX, + X64_NETBSD, X64_WINDOWS, + X64_WINDOWS_GNU, AARCH64_LINUX, AARCH64_DARWIN, - ARCH_OS_TARGET_LAST = AARCH64_DARWIN + RISCV32_LINUX, + RISCV64_LINUX, + WASM32, + WASM64, + ARCH_OS_TARGET_LAST = WASM64 } ArchOsTarget; typedef struct @@ -117,6 +136,8 @@ typedef struct const char* path; const char* cpu; const char* target_triple; + PicGeneration pic; + bool generate_lib; struct { bool reg_struct_return : 1; diff --git a/src/compiler/compiler.c b/src/compiler/compiler.c index d2d162a42..9e03763f2 100644 --- a/src/compiler/compiler.c +++ b/src/compiler/compiler.c @@ -86,20 +86,6 @@ void compiler_compile(BuildTarget *target) vec_add(contexts, context); parse_file(context); } - /* - const char *printf = "printf"; - TokenType t_type = TOKEN_IDENT; - const char *interned = symtab_add(printf, (uint32_t) 6, fnv1a(printf, (uint32_t)6), &t_type); - Decl *decl = decl_new(DECL_FUNC, wrap(interned), VISIBLE_PUBLIC); - Type *type = type_new(TYPE_POINTER); - type->base = type_char; - sema_resolve_type(contexts[0], type); - Decl *param = decl_new_var(wrap("str"), type, VARDECL_PARAM, VISIBLE_LOCAL); - vec_add(decl->func.function_signature.params, param); - decl->func.function_signature.rtype = type_void; - decl->resolve_status = RESOLVE_DONE; - context_register_global_decl(contexts[0], decl); -*/ assert(contexts); VECEACH(contexts, i) { @@ -137,6 +123,16 @@ void compiler_compile(BuildTarget *target) } if (diagnostics.errors > 0) exit(EXIT_FAILURE); + if (build_options.command == COMMAND_GENERATE_HEADERS) + { + VECEACH(contexts, i) + { + Context *context = contexts[i]; + header_gen(context); + } + return; + } + llvm_codegen_setup(); VECEACH(contexts, i) { @@ -216,6 +212,7 @@ void compile_files(BuildTarget *target) case COMPILE_LEX_PARSE_ONLY: compiler_parse(target); break; + case COMPILE_OUTPUT_HEADERS: default: compiler_compile(target); break; diff --git a/src/compiler/compiler_internal.h b/src/compiler/compiler_internal.h index fd859fb63..bdd522fb6 100644 --- a/src/compiler/compiler_internal.h +++ b/src/compiler/compiler_internal.h @@ -442,7 +442,7 @@ typedef struct _Decl Visibility visibility : 2; ResolveStatus resolve_status : 2; bool is_packed : 1; - bool has_addr : 1; + bool needs_additional_pad : 1; void *backend_ref; const char *cname; uint32_t alignment; @@ -1250,6 +1250,7 @@ bool cast_implicitly_to_runtime(Context *context, Expr *expr); void llvm_codegen(Context *context); void llvm_codegen_setup(); +void header_gen(Context *context); void compiler_add_type(Type *type); Decl *compiler_find_symbol(const char *name); diff --git a/src/compiler/headers.c b/src/compiler/headers.c new file mode 100644 index 000000000..492f17e63 --- /dev/null +++ b/src/compiler/headers.c @@ -0,0 +1,258 @@ +// Copyright (c) 2020 Christoffer Lerno. All rights reserved. +// Use of this source code is governed by a LGPLv3.0 +// a copy of which can be found in the LICENSE file. + +#include "compiler_internal.h" + +#define OUTPUT(x, ...) fprintf(file, x, ## __VA_ARGS__) +#define INDENT() indent_line(file, indent) + +static void indent_line(FILE *file, int indent) +{ + for (int i = 0; i < indent * 3; i++) + { + fputc(' ', file); + } +} +static void header_gen_decl(FILE *file, int indent, Decl *decl); + +static void header_gen_method(FILE *file, Context *c, Decl *decl) +{ + fprintf(file, "/* method */\n"); +} + +static void header_gen_function(FILE *file, Context *c, Decl *decl) +{ + fprintf(file, "/* function */\n"); +} + +static void header_print_type(FILE *file, Type *type) +{ + switch (type->type_kind) + { + case TYPE_POISONED: + UNREACHABLE + case TYPE_VOID: + OUTPUT("void"); + return; + case TYPE_BOOL: + OUTPUT("bool"); + return; + case TYPE_I8: + OUTPUT("int8_t"); + return; + case TYPE_I16: + OUTPUT("int16_t"); + return; + case TYPE_I32: + OUTPUT("int32_t"); + return; + case TYPE_I64: + case TYPE_IXX: + OUTPUT("int64_t"); + return; + case TYPE_I128: + TODO + case TYPE_U8: + OUTPUT("uint8_t"); + return; + case TYPE_U16: + OUTPUT("uint16_t"); + return; + case TYPE_U32: + OUTPUT("uint32_t"); + return; + case TYPE_U64: + OUTPUT("uint64_t"); + return; + case TYPE_U128: + TODO + case TYPE_F16: + TODO + case TYPE_F32: + OUTPUT("float"); + return; + case TYPE_F64: + case TYPE_FXX: + OUTPUT("double"); + return; + case TYPE_F128: + TODO + case TYPE_TYPEID: + OUTPUT("c3typeid_t"); + return; + case TYPE_POINTER: + header_print_type(file, type->pointer); + OUTPUT("*"); + return; + case TYPE_ENUM: + OUTPUT("enum %s__", type->decl->external_name); + return; + case TYPE_FUNC: + TODO + case TYPE_STRUCT: + OUTPUT("struct %s__", type->decl->external_name); + return; + case TYPE_UNION: + OUTPUT("union %s__", type->decl->external_name); + return; + case TYPE_ERRTYPE: + break; + case TYPE_ERR_UNION: + break; + case TYPE_TYPEDEF: + break; + case TYPE_STRING: + break; + case TYPE_ARRAY: + break; + case TYPE_VARARRAY: + break; + case TYPE_SUBARRAY: + break; + case TYPE_TYPEINFO: + break; + case TYPE_MEMBER: + break; + case TYPE_VECTOR: + break; + case TYPE_COMPLEX: + break; + } + TODO +} + +static void header_gen_members(FILE *file, int indent, Decl **members) +{ + VECEACH(members, i) + { + Decl *member = members[i]; + if (member->decl_kind == DECL_VAR) + { + INDENT(); + header_print_type(file, member->type); + OUTPUT(" %s;\n", member->name); + } + else + { + TODO + } + } +} +static void header_gen_struct(FILE *file, int indent, Decl *decl) +{ + if (!indent) + { + OUTPUT("typedef struct %s__ %s;\n", decl->external_name, decl->external_name); + } + INDENT(); + if (decl->name) + { + OUTPUT("struct %s__\n{\n", decl->external_name); + } + else + { + OUTPUT("struct\n{\n"); + } + header_gen_members(file, indent + 1, decl->strukt.members); + INDENT(); + OUTPUT("};\n"); +} + +static void header_gen_union(FILE *file, int indent, Decl *decl) +{ + OUTPUT("typedef union %s__ %s;\n", decl->external_name, decl->external_name); + OUTPUT("union %s__\n{\n", decl->external_name); + header_gen_members(file, indent, decl->strukt.members); + OUTPUT("};\n"); +} + +static void header_gen_enum(FILE *file, int indent, Decl *decl) +{ + TODO +} + +static void header_gen_err(FILE *file, int indent, Decl *decl) +{ + OUTPUT("typedef struct %s_error__ %s_error;\n", decl->external_name, decl->external_name); + OUTPUT("struct %s_error__\n{\n", decl->external_name); + header_gen_members(file, indent, decl->strukt.members); + OUTPUT("};\n"); +} + + +static void header_gen_decl(FILE *file, int indent, Decl *decl) +{ + switch (decl->decl_kind) + { + case DECL_POISONED: + case DECL_VAR: + case DECL_LABEL: + case DECL_ENUM_CONSTANT: + case DECL_ARRAY_VALUE: + case DECL_IMPORT: + case DECL_MACRO: + case DECL_GENERIC: + case DECL_CT_IF: + case DECL_CT_ELSE: + case DECL_CT_ELIF: + case DECL_CT_SWITCH: + case DECL_CT_CASE: + case DECL_ATTRIBUTE: + case DECL_DEFINE: + UNREACHABLE + case DECL_FUNC: + TODO + case DECL_TYPEDEF: + TODO + case DECL_STRUCT: + header_gen_struct(file, indent, decl); + return; + case DECL_UNION: + header_gen_union(file, indent, decl); + return; + case DECL_ENUM: + header_gen_enum(file, indent, decl); + return; + case DECL_ERR: + header_gen_err(file, indent, decl); + return; + } + UNREACHABLE +} + +static void header_gen_var(FILE *file, Context *c, Decl *decl) +{ + fprintf(file, "/* vars */\n"); +} + +void header_gen(Context *context) +{ + const char *filename = strcat_arena(context->file->name, ".h"); + FILE *file = fopen(filename, "w"); + OUTPUT("#include \n"); + OUTPUT("#ifndef __c3__\n"); + OUTPUT("#define __c3__\n"); + OUTPUT("typedef "); + header_print_type(file, type_lowering(type_typeid)); + OUTPUT(" c3typeid_t;\n"); + OUTPUT("#endif\n"); + VECEACH(context->types, i) + { + header_gen_decl(file, 0, context->types[i]); + } + + VECEACH(context->vars, i) + { + header_gen_var(file, context, context->vars[i]); + } + VECEACH(context->methods, i) + { + header_gen_method(file, context, context->methods[i]); + } + VECEACH(context->functions, i) + { + header_gen_function(file, context, context->functions[i]); + } + fclose(file); +} diff --git a/src/compiler/llvm_codegen.c b/src/compiler/llvm_codegen.c index d755bbc60..dec1d7615 100644 --- a/src/compiler/llvm_codegen.c +++ b/src/compiler/llvm_codegen.c @@ -488,7 +488,13 @@ void llvm_codegen(Context *context) } if (llvm_use_debug(&gen_context)) LLVMDIBuilderFinalize(gen_context.debug.builder); - gencontext_print_llvm_ir(&gen_context); + + // If it's in test, then we want to serialize the IR before it is optimized. + if (build_options.test_mode) + { + gencontext_print_llvm_ir(&gen_context); + gencontext_verify_ir(&gen_context); + } // Starting from here we could potentially thread this: LLVMPassManagerBuilderRef pass_manager_builder = LLVMPassManagerBuilderCreate(); @@ -524,10 +530,12 @@ void llvm_codegen(Context *context) LLVMRunPassManager(pass_manager, gen_context.module); LLVMDisposePassManager(pass_manager); - // Serialize the LLVM IR, if requested - if (build_options.emit_llvm) gencontext_print_llvm_ir(&gen_context); - - gencontext_verify_ir(&gen_context); + // Serialize the LLVM IR, if requested, also verify the IR in this case + if (build_options.emit_llvm) + { + gencontext_print_llvm_ir(&gen_context); + gencontext_verify_ir(&gen_context); + } if (build_options.emit_bitcode) gencontext_emit_object_file(&gen_context); diff --git a/src/compiler/llvm_codegen_type.c b/src/compiler/llvm_codegen_type.c index 29b330490..52c8f7117 100644 --- a/src/compiler/llvm_codegen_type.c +++ b/src/compiler/llvm_codegen_type.c @@ -36,9 +36,25 @@ static inline LLVMTypeRef llvm_type_from_decl(GenContext *context, Decl *decl) LLVMTypeRef type = LLVMStructCreateNamed(context->context, decl->external_name); // Avoid recursive issues. decl->type->backend_type = type; - VECEACH(decl->strukt.members, i) + Decl **members = decl->strukt.members; + VECEACH(members, i) { - vec_add(types, llvm_get_type(context, decl->strukt.members[i]->type)); + vec_add(types, llvm_get_type(context, members[i]->type)); + } + if (decl->needs_additional_pad) + { + Decl *last_member = VECLAST(members); + unsigned member_end = last_member->offset + type_size(last_member->type); + unsigned bytes = decl->strukt.size - member_end; + assert(bytes > 0); + if (bytes == 1) + { + vec_add(types, llvm_get_type(context, type_byte)); + } + else + { + vec_add(types, LLVMArrayType(llvm_get_type(context, type_byte), bytes)); + } } LLVMStructSetBody(type, types, vec_size(types), decl->is_packed); return type; diff --git a/src/compiler/sema_decls.c b/src/compiler/sema_decls.c index a48094a30..0ee903da6 100644 --- a/src/compiler/sema_decls.c +++ b/src/compiler/sema_decls.c @@ -44,6 +44,172 @@ static inline bool sema_analyse_struct_member(Context *context, Decl *decl) } } +static bool sema_analyse_union_members(Context *context, Decl *decl, Decl **members) +{ + unsigned max_size = 0; + unsigned max_size_element = 0; + unsigned max_alignment_element = 0; + unsigned max_alignment = 0; + + VECEACH(members, i) + { + Decl *member = members[i]; + if (!decl_ok(member)) + { + decl_poison(decl); + continue; + } + if (!sema_analyse_struct_member(context, member)) + { + if (decl_ok(decl)) + { + decl_poison(decl); + continue; + } + continue; + } + + size_t member_alignment = type_abi_alignment(member->type); + size_t member_size = type_size(member->type); + + // Update max alignment + if (member_alignment > max_alignment) + { + max_alignment = member_alignment; + max_alignment_element = i; + } + // Update max size + if (member_size > max_size) + { + max_size_element = i; + max_size = member_size; + // If this is bigger than the previous with max + // alignment, pick this as the maximum size element. + if (max_alignment_element != i && max_alignment == member_alignment) + { + max_alignment_element = i; + } + } + // Offset is always 0 + member->offset = 0; + } + + if (!decl_ok(decl)) return false; + + // 1. If packed, then the alignment is zero, unless previously given + if (decl->is_packed && !decl->alignment) decl->alignment = 1; + + // 2. Otherwise pick the highest of the natural alignment and the given alignment. + if (!decl->is_packed) decl->alignment = MAX(decl->alignment, max_alignment); + + // We're only packed if the max alignment is > 1 + decl->is_packed = max_alignment > 1; + + // The actual size might be larger than the max size due to alignment. + unsigned size = aligned_offset(max_size, decl->alignment); + + // If the actual size is bigger than the real size, add + // padding. + decl->needs_additional_pad = size > max_size; + + decl->strukt.size = size; + + return true; +} + +static bool sema_analyse_struct_members(Context *context, Decl *decl, Decl **members) +{ + // Default alignment is 1 even if the it is empty. + size_t natural_alignment = 1; + bool is_unaligned = false; + size_t size = 0; + size_t offset = 0; + bool is_packed = decl->is_packed; + VECEACH(members, i) + { + Decl *member = decl->strukt.members[i]; + if (!decl_ok(member)) + { + decl_poison(decl); + continue; + } + if (!sema_analyse_struct_member(context, member)) + { + if (decl_ok(decl)) + { + decl_poison(decl); + continue; + } + continue; + } + + if (!decl_ok(decl)) return false; + + size_t member_alignment = type_abi_alignment(member->type); + + // If the member alignment is higher than the currently detected alignment, + // then we update the natural alignment + if (member_alignment > natural_alignment) + { + natural_alignment = member_alignment; + } + // In the case of a struct, we will align this to the next offset, + // using the alignment of the member. + unsigned align_offset = aligned_offset(offset, member_alignment); + + // Usually we align things, but if this is a packed struct we don't + // so offsets may mismatch + if (align_offset > offset) + { + if (is_packed) + { + // If it is packed, we note that the packing made it unaligned. + is_unaligned = true; + } + else + { + // Otherwise we insert the (implicit) padding by moving to the aligned offset. + offset = align_offset; + } + } + member->offset = offset; + offset += type_size(member->type); + ; + } + + // Set the alignment: + + // 1. If packed, use the alignment given, otherwise set to 1. + if (decl->is_packed && !decl->alignment) decl->alignment = 1; + + // 2. Otherwise pick the highest of the natural alignment and the given alignment. + if (!decl->is_packed) decl->alignment = MAX(decl->alignment, natural_alignment); + + // We must now possibly add the end padding. + // First we calculate the actual size + size = aligned_offset(offset, decl->alignment); + + // We might get a size that is greater than the natural alignment + // in this case we need an additional padding + if (size > aligned_offset(offset, natural_alignment)) + { + decl->needs_additional_pad = true; + } + + // If the size is smaller the naturally aligned struct, then it is also unaligned + if (size < aligned_offset(offset, natural_alignment)) + { + is_unaligned = true; + } + if (is_unaligned && size > offset) + { + decl->needs_additional_pad = true; + } + decl->is_packed = is_unaligned; + decl->strukt.size = size; + return true; +} + static bool sema_analyse_struct_union(Context *context, Decl *decl) { AttributeDomain domain; @@ -100,60 +266,20 @@ static bool sema_analyse_struct_union(Context *context, Decl *decl) } DEBUG_LOG("Beginning analysis of %s.", decl->name ? decl->name : "anon"); - size_t offset = 0; - // Default alignment is 1. - size_t alignment = 1; - size_t size = 0; if (decl->name) context_push_scope(context); - VECEACH(decl->strukt.members, i) + bool success; + if (decl->decl_kind == DECL_UNION) { - Decl *member = decl->strukt.members[i]; - if (!decl_ok(member)) - { - decl_poison(decl); - continue; - } - if (!sema_analyse_struct_member(context, member)) - { - if (decl_ok(decl)) - { - decl_poison(decl); - continue; - } - continue; - } - - size_t member_alignment = type_abi_alignment(member->type); - size_t member_size = type_size(member->type); - if (member_alignment > alignment) alignment = member_alignment; - if (decl->decl_kind == DECL_UNION) - { - if (member_size > size) size = member_size; - member->offset = 0; - } - else - { - if (!decl->is_packed) - { - offset = aligned_offset(offset, member_alignment); - } - member->offset = offset; - offset += member_size; - } + success = sema_analyse_union_members(context, decl, decl->strukt.members); } - if (!decl->alignment) decl->alignment = alignment; - if (decl->decl_kind != DECL_UNION) + else { - size = offset; - if (!decl->is_packed) - { - size = aligned_offset(size, decl->alignment); - } + success = sema_analyse_struct_members(context, decl, decl->strukt.members); } - decl->strukt.size = size; - DEBUG_LOG("Struct/union size %d, alignment %d.", (int)size, (int)decl->alignment); + DEBUG_LOG("Struct/union size %d, alignment %d.", (int)decl->strukt.size, (int)decl->alignment); if (decl->name) context_pop_scope(context); DEBUG_LOG("Analysis complete."); + if (!success) return decl_poison(decl); return decl_ok(decl); } diff --git a/src/compiler/sema_expr.c b/src/compiler/sema_expr.c index e1854450a..b9abfcad3 100644 --- a/src/compiler/sema_expr.c +++ b/src/compiler/sema_expr.c @@ -3364,7 +3364,6 @@ static inline bool sema_take_addr_of_var(Expr *expr, Decl *decl) case VARDECL_GLOBAL: case VARDECL_PARAM: case VARDECL_PARAM_REF: - decl->has_addr = true; return true; case VARDECL_CONST: if (!decl->var.type_info) @@ -3373,7 +3372,6 @@ static inline bool sema_take_addr_of_var(Expr *expr, Decl *decl) SEMA_PREV(decl, "The constant was defined here."); return false; } - decl->has_addr = true; return true; case VARDECL_PARAM_EXPR: SEMA_ERROR(expr, "It is not possible to take the address of a captured expression, but you can use && to take a reference to the temporary value."); @@ -3399,7 +3397,6 @@ static inline bool sema_take_addr_of_ident(Expr *inner) { case DECL_ENUM_CONSTANT: case DECL_FUNC: - decl->has_addr = true; return true; case DECL_VAR: return sema_take_addr_of_var(inner, decl); diff --git a/src/compiler/target.c b/src/compiler/target.c index 0382c99c2..6e2f7aba2 100644 --- a/src/compiler/target.c +++ b/src/compiler/target.c @@ -345,15 +345,25 @@ static inline void target_setup_x64_abi(void) } static char *arch_to_target_triple[ARCH_OS_TARGET_LAST + 1] = { - [X86_DARWIN] = "i386-apple-darwin", - [X86_LINUX] = "i386-pc-linux", + [X86_FREEBSD] = "i386-unknown-freebsd", + [X86_OPENBSD] = "i386-unknown-openbsd", + [X86_MCU] = "i386-pc-elfiamcu", + [X86_WINDOWS] = "i386-pc-win32", + [X86_LINUX] = "i386-unknown-linux", [X64_DARWIN] = "x86_64-apple-darwin", - [X64_LINUX] = "x86_64-pc-linux", - [X64_WINDOWS] = "x86_64-pc-win32", - [AARCH64_LINUX] = "aarch64-pc-linux", + [X64_LINUX] = "x86_64-unknown-linux-gnu", + [X64_WINDOWS] = "x86_64-pc-windows-msvc", + [X64_WINDOWS_GNU] = "x86_64-pc-windows-gnu", + [X64_NETBSD] = "x86_64-unknown-netbsd", + [AARCH64_LINUX] = "aarch64-unknown-linux-gnu", [AARCH64_DARWIN] = "aarch64-apple-darwin", + [RISCV32_LINUX] = "riscv32-unknown-linux", + [RISCV64_LINUX] = "riscv32-unknown-linux", + [WASM32] = "wasm32-unknown-unknown", + [WASM64] = "wasm64-unknown-unknown", }; + void target_setup(void) { assert(!build_target.target); @@ -409,7 +419,15 @@ void target_setup(void) default: UNREACHABLE; } -// reloc = (opt->pic || opt->library)? LLVMRelocPIC : LLVMRelocDefault; + if (build_options.pic == BIG_PIC_USE || build_options.pic == SMALL_PIC_USE || build_options.generate_lib) + { + reloc_mode = LLVMRelocPIC; + } + if (build_options.pic == PIC_NONE) + { + reloc_mode = LLVMRelocStatic; + } + if (!build_options.cpu) { build_options.cpu = "generic"; @@ -446,6 +464,7 @@ void target_setup(void) 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: @@ -488,6 +507,12 @@ void target_setup(void) 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: @@ -544,9 +569,7 @@ void target_setup(void) target_setup_arm_abi(); break; case ARCH_TYPE_PPC: - build_target.abi = ABI_PPC32; - build_target.ppc.is_softfp = /** has spe || **/ build_target.float_abi == FLOAT_ABI_SOFT; - break; + FATAL_ERROR("PPC32 is not supported."); case ARCH_TYPE_PPC64: case ARCH_TYPE_PPC64LE: if (build_target.object_format != OBJ_FORMAT_ELF) diff --git a/src/main.c b/src/main.c index 5f9acf0a5..0424091a3 100644 --- a/src/main.c +++ b/src/main.c @@ -31,6 +31,10 @@ int main(int argc, const char *argv[]) case COMMAND_UNIT_TEST: compiler_tests(); break; + case COMMAND_GENERATE_HEADERS: + build_options.compile_option = COMPILE_OUTPUT_HEADERS; + compile_files(NULL); + break; case COMMAND_COMPILE: compile_files(NULL); break; diff --git a/test/test_suite/subarrays/slice_offset_neg_end.c3t b/test/test_suite/subarrays/slice_offset_neg_end.c3t index 15252cba0..b7f227b60 100644 --- a/test/test_suite/subarrays/slice_offset_neg_end.c3t +++ b/test/test_suite/subarrays/slice_offset_neg_end.c3t @@ -1,3 +1,4 @@ + func void test() { int[3] x = { 1, 2, 3 };