mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
Moving llvm-emit / debug output separately. Started work on C headers. Started work getting packed unions and structs to work correctly. Also added some unfinished PIC code.
This commit is contained in:
@@ -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)
|
||||
|
||||
|
||||
@@ -11,19 +11,26 @@
|
||||
#include <string.h>
|
||||
#include <utils/lib.h>
|
||||
|
||||
#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 [<target>] Benchmark a target.");
|
||||
OUTPUT(" clean-run [<target>] Clean, then run the target.");
|
||||
OUTPUT(" compile-run <file1> [<file2> ...] Compile files then immediately run the result.");
|
||||
OUTPUT(" headers <file1> [<file2> ...] Analyse files and generate C headers for public methods.");
|
||||
OUTPUT("");
|
||||
OUTPUT("Options:");
|
||||
OUTPUT(" --lib <dir> - 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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
258
src/compiler/headers.c
Normal file
258
src/compiler/headers.c
Normal file
@@ -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 <stdint.h>\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);
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
func void test()
|
||||
{
|
||||
int[3] x = { 1, 2, 3 };
|
||||
|
||||
Reference in New Issue
Block a user