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:
Christoffer Lerno
2020-11-27 23:43:39 +01:00
parent bf7318305a
commit 29730345b0
13 changed files with 574 additions and 88 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,3 +1,4 @@
func void test()
{
int[3] x = { 1, 2, 3 };