Merge remote-tracking branch 'origin/master' into llvm7
This commit is contained in:
530
src/codegen.cpp
530
src/codegen.cpp
@@ -8,12 +8,12 @@
|
||||
#include "analyze.hpp"
|
||||
#include "ast_render.hpp"
|
||||
#include "codegen.hpp"
|
||||
#include "compiler.hpp"
|
||||
#include "config.h"
|
||||
#include "errmsg.hpp"
|
||||
#include "error.hpp"
|
||||
#include "hash_map.hpp"
|
||||
#include "ir.hpp"
|
||||
#include "link.hpp"
|
||||
#include "os.hpp"
|
||||
#include "translate_c.hpp"
|
||||
#include "target.hpp"
|
||||
@@ -183,14 +183,14 @@ CodeGen *codegen_create(Buf *root_src_path, const ZigTarget *target, OutType out
|
||||
return g;
|
||||
}
|
||||
|
||||
void codegen_destroy(CodeGen *codegen) {
|
||||
LLVMDisposeTargetMachine(codegen->target_machine);
|
||||
}
|
||||
|
||||
void codegen_set_output_h_path(CodeGen *g, Buf *h_path) {
|
||||
g->out_h_path = h_path;
|
||||
}
|
||||
|
||||
void codegen_set_output_path(CodeGen *g, Buf *path) {
|
||||
g->wanted_output_file_path = path;
|
||||
}
|
||||
|
||||
void codegen_set_clang_argv(CodeGen *g, const char **args, size_t len) {
|
||||
g->clang_argv = args;
|
||||
g->clang_argv_len = len;
|
||||
@@ -243,10 +243,6 @@ void codegen_set_out_name(CodeGen *g, Buf *out_name) {
|
||||
g->root_out_name = out_name;
|
||||
}
|
||||
|
||||
void codegen_set_cache_dir(CodeGen *g, Buf cache_dir) {
|
||||
g->cache_dir = cache_dir;
|
||||
}
|
||||
|
||||
void codegen_set_libc_lib_dir(CodeGen *g, Buf *libc_lib_dir) {
|
||||
g->libc_lib_dir = libc_lib_dir;
|
||||
}
|
||||
@@ -779,7 +775,8 @@ static LLVMValueRef gen_store_untyped(CodeGen *g, LLVMValueRef value, LLVMValueR
|
||||
|
||||
static LLVMValueRef gen_store(CodeGen *g, LLVMValueRef value, LLVMValueRef ptr, ZigType *ptr_type) {
|
||||
assert(ptr_type->id == ZigTypeIdPointer);
|
||||
return gen_store_untyped(g, value, ptr, ptr_type->data.pointer.alignment, ptr_type->data.pointer.is_volatile);
|
||||
uint32_t alignment = get_ptr_align(g, ptr_type);
|
||||
return gen_store_untyped(g, value, ptr, alignment, ptr_type->data.pointer.is_volatile);
|
||||
}
|
||||
|
||||
static LLVMValueRef gen_load_untyped(CodeGen *g, LLVMValueRef ptr, uint32_t alignment, bool is_volatile,
|
||||
@@ -797,7 +794,8 @@ static LLVMValueRef gen_load_untyped(CodeGen *g, LLVMValueRef ptr, uint32_t alig
|
||||
|
||||
static LLVMValueRef gen_load(CodeGen *g, LLVMValueRef ptr, ZigType *ptr_type, const char *name) {
|
||||
assert(ptr_type->id == ZigTypeIdPointer);
|
||||
return gen_load_untyped(g, ptr, ptr_type->data.pointer.alignment, ptr_type->data.pointer.is_volatile, name);
|
||||
uint32_t alignment = get_ptr_align(g, ptr_type);
|
||||
return gen_load_untyped(g, ptr, alignment, ptr_type->data.pointer.is_volatile, name);
|
||||
}
|
||||
|
||||
static LLVMValueRef get_handle_value(CodeGen *g, LLVMValueRef ptr, ZigType *type, ZigType *ptr_type) {
|
||||
@@ -1772,7 +1770,7 @@ static LLVMValueRef gen_assign_raw(CodeGen *g, LLVMValueRef ptr, ZigType *ptr_ty
|
||||
|
||||
ZigType *usize = g->builtin_types.entry_usize;
|
||||
uint64_t size_bytes = LLVMStoreSizeOfType(g->target_data_ref, child_type->type_ref);
|
||||
uint64_t align_bytes = ptr_type->data.pointer.alignment;
|
||||
uint64_t align_bytes = get_ptr_align(g, ptr_type);
|
||||
assert(size_bytes > 0);
|
||||
assert(align_bytes > 0);
|
||||
|
||||
@@ -3162,7 +3160,8 @@ static LLVMValueRef ir_render_decl_var(CodeGen *g, IrExecutable *executable,
|
||||
assert(var->value->type == init_value->value.type);
|
||||
ZigType *var_ptr_type = get_pointer_to_type_extra(g, var->value->type, false, false,
|
||||
PtrLenSingle, var->align_bytes, 0, 0);
|
||||
gen_assign_raw(g, var->value_ref, var_ptr_type, ir_llvm_value(g, init_value));
|
||||
LLVMValueRef llvm_init_val = ir_llvm_value(g, init_value);
|
||||
gen_assign_raw(g, var->value_ref, var_ptr_type, llvm_init_val);
|
||||
} else {
|
||||
bool want_safe = ir_want_runtime_safety(g, &decl_var_instruction->base);
|
||||
if (want_safe) {
|
||||
@@ -4022,7 +4021,7 @@ static LLVMValueRef ir_render_align_cast(CodeGen *g, IrExecutable *executable, I
|
||||
LLVMValueRef ptr_val;
|
||||
|
||||
if (target_type->id == ZigTypeIdPointer) {
|
||||
align_bytes = target_type->data.pointer.alignment;
|
||||
align_bytes = get_ptr_align(g, target_type);
|
||||
ptr_val = target_val;
|
||||
} else if (target_type->id == ZigTypeIdFn) {
|
||||
align_bytes = target_type->data.fn.fn_type_id.alignment;
|
||||
@@ -4030,7 +4029,7 @@ static LLVMValueRef ir_render_align_cast(CodeGen *g, IrExecutable *executable, I
|
||||
} else if (target_type->id == ZigTypeIdOptional &&
|
||||
target_type->data.maybe.child_type->id == ZigTypeIdPointer)
|
||||
{
|
||||
align_bytes = target_type->data.maybe.child_type->data.pointer.alignment;
|
||||
align_bytes = get_ptr_align(g, target_type->data.maybe.child_type);
|
||||
ptr_val = target_val;
|
||||
} else if (target_type->id == ZigTypeIdOptional &&
|
||||
target_type->data.maybe.child_type->id == ZigTypeIdFn)
|
||||
@@ -4043,7 +4042,7 @@ static LLVMValueRef ir_render_align_cast(CodeGen *g, IrExecutable *executable, I
|
||||
zig_panic("TODO audit this function");
|
||||
} else if (target_type->id == ZigTypeIdStruct && target_type->data.structure.is_slice) {
|
||||
ZigType *slice_ptr_type = target_type->data.structure.fields[slice_ptr_index].type_entry;
|
||||
align_bytes = slice_ptr_type->data.pointer.alignment;
|
||||
align_bytes = get_ptr_align(g, slice_ptr_type);
|
||||
|
||||
size_t ptr_index = target_type->data.structure.fields[slice_ptr_index].gen_index;
|
||||
LLVMValueRef ptr_val_ptr = LLVMBuildStructGEP(g->builder, target_val, (unsigned)ptr_index, "");
|
||||
@@ -4195,7 +4194,7 @@ static LLVMValueRef ir_render_memset(CodeGen *g, IrExecutable *executable, IrIns
|
||||
ZigType *ptr_type = instruction->dest_ptr->value.type;
|
||||
assert(ptr_type->id == ZigTypeIdPointer);
|
||||
|
||||
ZigLLVMBuildMemSet(g->builder, dest_ptr_casted, char_val, len_val, ptr_type->data.pointer.alignment, ptr_type->data.pointer.is_volatile);
|
||||
ZigLLVMBuildMemSet(g->builder, dest_ptr_casted, char_val, len_val, get_ptr_align(g, ptr_type), ptr_type->data.pointer.is_volatile);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -4216,9 +4215,8 @@ static LLVMValueRef ir_render_memcpy(CodeGen *g, IrExecutable *executable, IrIns
|
||||
assert(src_ptr_type->id == ZigTypeIdPointer);
|
||||
|
||||
bool is_volatile = (dest_ptr_type->data.pointer.is_volatile || src_ptr_type->data.pointer.is_volatile);
|
||||
|
||||
ZigLLVMBuildMemCpy(g->builder, dest_ptr_casted, dest_ptr_type->data.pointer.alignment,
|
||||
src_ptr_casted, src_ptr_type->data.pointer.alignment, len_val, is_volatile);
|
||||
ZigLLVMBuildMemCpy(g->builder, dest_ptr_casted, get_ptr_align(g, dest_ptr_type),
|
||||
src_ptr_casted, get_ptr_align(g, src_ptr_type), len_val, is_volatile);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -4629,7 +4627,6 @@ static LLVMValueRef ir_render_err_wrap_payload(CodeGen *g, IrExecutable *executa
|
||||
|
||||
static LLVMValueRef ir_render_union_tag(CodeGen *g, IrExecutable *executable, IrInstructionUnionTag *instruction) {
|
||||
ZigType *union_type = instruction->value->value.type;
|
||||
assert(union_type->data.unionation.gen_tag_index != SIZE_MAX);
|
||||
|
||||
ZigType *tag_type = union_type->data.unionation.tag_type;
|
||||
if (!type_has_bits(tag_type))
|
||||
@@ -4639,6 +4636,7 @@ static LLVMValueRef ir_render_union_tag(CodeGen *g, IrExecutable *executable, Ir
|
||||
if (union_type->data.unionation.gen_field_count == 0)
|
||||
return union_val;
|
||||
|
||||
assert(union_type->data.unionation.gen_tag_index != SIZE_MAX);
|
||||
LLVMValueRef tag_field_ptr = LLVMBuildStructGEP(g->builder, union_val,
|
||||
union_type->data.unionation.gen_tag_index, "");
|
||||
ZigType *ptr_type = get_pointer_to_type(g, tag_type, false);
|
||||
@@ -5393,7 +5391,6 @@ static LLVMValueRef pack_const_int(CodeGen *g, LLVMTypeRef big_int_type_ref, Con
|
||||
case ZigTypeIdErrorUnion:
|
||||
case ZigTypeIdErrorSet:
|
||||
case ZigTypeIdNamespace:
|
||||
case ZigTypeIdBlock:
|
||||
case ZigTypeIdBoundFn:
|
||||
case ZigTypeIdArgTuple:
|
||||
case ZigTypeIdVoid:
|
||||
@@ -5774,12 +5771,24 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c
|
||||
LLVMValueRef tag_value = bigint_to_llvm_const(type_entry->data.unionation.tag_type->type_ref,
|
||||
&const_val->data.x_union.tag);
|
||||
|
||||
LLVMValueRef fields[2];
|
||||
LLVMValueRef fields[3];
|
||||
fields[type_entry->data.unionation.gen_union_index] = union_value_ref;
|
||||
fields[type_entry->data.unionation.gen_tag_index] = tag_value;
|
||||
|
||||
if (make_unnamed_struct) {
|
||||
return LLVMConstStruct(fields, 2, false);
|
||||
LLVMValueRef result = LLVMConstStruct(fields, 2, false);
|
||||
uint64_t last_field_offset = LLVMOffsetOfElement(g->target_data_ref, LLVMTypeOf(result), 1);
|
||||
uint64_t end_offset = last_field_offset +
|
||||
LLVMStoreSizeOfType(g->target_data_ref, LLVMTypeOf(fields[1]));
|
||||
uint64_t expected_sz = LLVMStoreSizeOfType(g->target_data_ref, type_entry->type_ref);
|
||||
unsigned pad_sz = expected_sz - end_offset;
|
||||
if (pad_sz != 0) {
|
||||
fields[2] = LLVMGetUndef(LLVMArrayType(LLVMInt8Type(), pad_sz));
|
||||
result = LLVMConstStruct(fields, 3, false);
|
||||
}
|
||||
uint64_t actual_sz = LLVMStoreSizeOfType(g->target_data_ref, LLVMTypeOf(result));
|
||||
assert(actual_sz == expected_sz);
|
||||
return result;
|
||||
} else {
|
||||
return LLVMConstNamedStruct(type_entry->type_ref, fields, 2);
|
||||
}
|
||||
@@ -5789,9 +5798,16 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c
|
||||
case ZigTypeIdEnum:
|
||||
return bigint_to_llvm_const(type_entry->type_ref, &const_val->data.x_enum_tag);
|
||||
case ZigTypeIdFn:
|
||||
assert(const_val->data.x_ptr.special == ConstPtrSpecialFunction);
|
||||
assert(const_val->data.x_ptr.mut == ConstPtrMutComptimeConst);
|
||||
return fn_llvm_value(g, const_val->data.x_ptr.data.fn.fn_entry);
|
||||
if (const_val->data.x_ptr.special == ConstPtrSpecialFunction) {
|
||||
assert(const_val->data.x_ptr.mut == ConstPtrMutComptimeConst);
|
||||
return fn_llvm_value(g, const_val->data.x_ptr.data.fn.fn_entry);
|
||||
} else if (const_val->data.x_ptr.special == ConstPtrSpecialHardCodedAddr) {
|
||||
LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->type_ref;
|
||||
uint64_t addr = const_val->data.x_ptr.data.hard_coded_addr.addr;
|
||||
return LLVMConstIntToPtr(LLVMConstInt(usize_type_ref, addr, false), type_entry->type_ref);
|
||||
} else {
|
||||
zig_unreachable();
|
||||
}
|
||||
case ZigTypeIdPointer:
|
||||
return gen_const_val_ptr(g, const_val, name);
|
||||
case ZigTypeIdErrorUnion:
|
||||
@@ -5819,13 +5835,29 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c
|
||||
err_payload_value = gen_const_val(g, payload_val, "");
|
||||
make_unnamed_struct = is_llvm_value_unnamed_type(payload_val->type, err_payload_value);
|
||||
}
|
||||
LLVMValueRef fields[] = {
|
||||
err_tag_value,
|
||||
err_payload_value,
|
||||
};
|
||||
if (make_unnamed_struct) {
|
||||
return LLVMConstStruct(fields, 2, false);
|
||||
uint64_t payload_off = LLVMOffsetOfElement(g->target_data_ref, type_entry->type_ref, 1);
|
||||
uint64_t err_sz = LLVMStoreSizeOfType(g->target_data_ref, LLVMTypeOf(err_tag_value));
|
||||
unsigned pad_sz = payload_off - err_sz;
|
||||
if (pad_sz == 0) {
|
||||
LLVMValueRef fields[] = {
|
||||
err_tag_value,
|
||||
err_payload_value,
|
||||
};
|
||||
return LLVMConstStruct(fields, 2, false);
|
||||
} else {
|
||||
LLVMValueRef fields[] = {
|
||||
err_tag_value,
|
||||
LLVMGetUndef(LLVMArrayType(LLVMInt8Type(), pad_sz)),
|
||||
err_payload_value,
|
||||
};
|
||||
return LLVMConstStruct(fields, 3, false);
|
||||
}
|
||||
} else {
|
||||
LLVMValueRef fields[] = {
|
||||
err_tag_value,
|
||||
err_payload_value,
|
||||
};
|
||||
return LLVMConstNamedStruct(type_entry->type_ref, fields, 2);
|
||||
}
|
||||
}
|
||||
@@ -5840,7 +5872,6 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c
|
||||
case ZigTypeIdUndefined:
|
||||
case ZigTypeIdNull:
|
||||
case ZigTypeIdNamespace:
|
||||
case ZigTypeIdBlock:
|
||||
case ZigTypeIdBoundFn:
|
||||
case ZigTypeIdArgTuple:
|
||||
case ZigTypeIdOpaque:
|
||||
@@ -5958,13 +5989,6 @@ static void gen_global_var(CodeGen *g, ZigVar *var, LLVMValueRef init_val,
|
||||
// TODO ^^ make an actual global variable
|
||||
}
|
||||
|
||||
static void ensure_cache_dir(CodeGen *g) {
|
||||
int err;
|
||||
if ((err = os_make_path(&g->cache_dir))) {
|
||||
zig_panic("unable to make cache dir: %s", err_str(err));
|
||||
}
|
||||
}
|
||||
|
||||
static void validate_inline_fns(CodeGen *g) {
|
||||
for (size_t i = 0; i < g->inline_fns.length; i += 1) {
|
||||
ZigFn *fn_entry = g->inline_fns.at(i);
|
||||
@@ -5979,8 +6003,6 @@ static void validate_inline_fns(CodeGen *g) {
|
||||
static void do_code_gen(CodeGen *g) {
|
||||
assert(!g->errors.length);
|
||||
|
||||
codegen_add_time_event(g, "Code Generation");
|
||||
|
||||
{
|
||||
// create debug type for error sets
|
||||
assert(g->err_enumerators.length == g->errors_by_index.length);
|
||||
@@ -6283,45 +6305,18 @@ static void do_code_gen(CodeGen *g) {
|
||||
char *error = nullptr;
|
||||
LLVMVerifyModule(g->module, LLVMAbortProcessAction, &error);
|
||||
#endif
|
||||
}
|
||||
|
||||
codegen_add_time_event(g, "LLVM Emit Output");
|
||||
|
||||
char *err_msg = nullptr;
|
||||
Buf *o_basename = buf_create_from_buf(g->root_out_name);
|
||||
|
||||
switch (g->emit_file_type) {
|
||||
case EmitFileTypeBinary:
|
||||
{
|
||||
const char *o_ext = target_o_file_ext(&g->zig_target);
|
||||
buf_append_str(o_basename, o_ext);
|
||||
break;
|
||||
}
|
||||
case EmitFileTypeAssembly:
|
||||
{
|
||||
const char *asm_ext = target_asm_file_ext(&g->zig_target);
|
||||
buf_append_str(o_basename, asm_ext);
|
||||
break;
|
||||
}
|
||||
case EmitFileTypeLLVMIr:
|
||||
{
|
||||
const char *llvm_ir_ext = target_llvm_ir_file_ext(&g->zig_target);
|
||||
buf_append_str(o_basename, llvm_ir_ext);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
zig_unreachable();
|
||||
}
|
||||
|
||||
Buf *output_path = buf_alloc();
|
||||
os_path_join(&g->cache_dir, o_basename, output_path);
|
||||
ensure_cache_dir(g);
|
||||
|
||||
static void zig_llvm_emit_output(CodeGen *g) {
|
||||
bool is_small = g->build_mode == BuildModeSmallRelease;
|
||||
|
||||
Buf *output_path = &g->o_file_output_path;
|
||||
char *err_msg = nullptr;
|
||||
switch (g->emit_file_type) {
|
||||
case EmitFileTypeBinary:
|
||||
if (ZigLLVMTargetMachineEmitToFile(g->target_machine, g->module, buf_ptr(output_path),
|
||||
ZigLLVM_EmitBinary, &err_msg, g->build_mode == BuildModeDebug, is_small))
|
||||
ZigLLVM_EmitBinary, &err_msg, g->build_mode == BuildModeDebug, is_small,
|
||||
g->enable_time_report))
|
||||
{
|
||||
zig_panic("unable to write object file %s: %s", buf_ptr(output_path), err_msg);
|
||||
}
|
||||
@@ -6331,22 +6326,22 @@ static void do_code_gen(CodeGen *g) {
|
||||
|
||||
case EmitFileTypeAssembly:
|
||||
if (ZigLLVMTargetMachineEmitToFile(g->target_machine, g->module, buf_ptr(output_path),
|
||||
ZigLLVM_EmitAssembly, &err_msg, g->build_mode == BuildModeDebug, is_small))
|
||||
ZigLLVM_EmitAssembly, &err_msg, g->build_mode == BuildModeDebug, is_small,
|
||||
g->enable_time_report))
|
||||
{
|
||||
zig_panic("unable to write assembly file %s: %s", buf_ptr(output_path), err_msg);
|
||||
}
|
||||
validate_inline_fns(g);
|
||||
g->link_objects.append(output_path);
|
||||
break;
|
||||
|
||||
case EmitFileTypeLLVMIr:
|
||||
if (ZigLLVMTargetMachineEmitToFile(g->target_machine, g->module, buf_ptr(output_path),
|
||||
ZigLLVM_EmitLLVMIr, &err_msg, g->build_mode == BuildModeDebug, is_small))
|
||||
ZigLLVM_EmitLLVMIr, &err_msg, g->build_mode == BuildModeDebug, is_small,
|
||||
g->enable_time_report))
|
||||
{
|
||||
zig_panic("unable to write llvm-ir file %s: %s", buf_ptr(output_path), err_msg);
|
||||
}
|
||||
validate_inline_fns(g);
|
||||
g->link_objects.append(output_path);
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -6399,12 +6394,6 @@ static void define_builtin_types(CodeGen *g) {
|
||||
entry->zero_bits = true;
|
||||
g->builtin_types.entry_namespace = entry;
|
||||
}
|
||||
{
|
||||
ZigType *entry = new_type_table_entry(ZigTypeIdBlock);
|
||||
buf_init_from_str(&entry->name, "(block)");
|
||||
entry->zero_bits = true;
|
||||
g->builtin_types.entry_block = entry;
|
||||
}
|
||||
{
|
||||
ZigType *entry = new_type_table_entry(ZigTypeIdComptimeFloat);
|
||||
buf_init_from_str(&entry->name, "comptime_float");
|
||||
@@ -6651,7 +6640,7 @@ static void define_builtin_fns(CodeGen *g) {
|
||||
create_builtin_fn(g, BuiltinFnIdIntType, "IntType", 2); // TODO rename to Int
|
||||
create_builtin_fn(g, BuiltinFnIdSetCold, "setCold", 1);
|
||||
create_builtin_fn(g, BuiltinFnIdSetRuntimeSafety, "setRuntimeSafety", 1);
|
||||
create_builtin_fn(g, BuiltinFnIdSetFloatMode, "setFloatMode", 2);
|
||||
create_builtin_fn(g, BuiltinFnIdSetFloatMode, "setFloatMode", 1);
|
||||
create_builtin_fn(g, BuiltinFnIdPanic, "panic", 1);
|
||||
create_builtin_fn(g, BuiltinFnIdPtrCast, "ptrCast", 2);
|
||||
create_builtin_fn(g, BuiltinFnIdBitCast, "bitCast", 2);
|
||||
@@ -6685,6 +6674,7 @@ static void define_builtin_fns(CodeGen *g) {
|
||||
create_builtin_fn(g, BuiltinFnIdErrSetCast, "errSetCast", 2);
|
||||
create_builtin_fn(g, BuiltinFnIdToBytes, "sliceToBytes", 1);
|
||||
create_builtin_fn(g, BuiltinFnIdFromBytes, "bytesToSlice", 2);
|
||||
create_builtin_fn(g, BuiltinFnIdThis, "This", 0);
|
||||
}
|
||||
|
||||
static const char *bool_to_str(bool b) {
|
||||
@@ -6866,7 +6856,6 @@ Buf *codegen_generate_builtin_source(CodeGen *g) {
|
||||
" Union: Union,\n"
|
||||
" Fn: Fn,\n"
|
||||
" Namespace: void,\n"
|
||||
" Block: void,\n"
|
||||
" BoundFn: Fn,\n"
|
||||
" ArgTuple: void,\n"
|
||||
" Opaque: void,\n"
|
||||
@@ -7037,11 +7026,11 @@ Buf *codegen_generate_builtin_source(CodeGen *g) {
|
||||
{
|
||||
buf_appendf(contents,
|
||||
"pub const FloatMode = enum {\n"
|
||||
" Optimized,\n"
|
||||
" Strict,\n"
|
||||
" Optimized,\n"
|
||||
"};\n\n");
|
||||
assert(FloatModeOptimized == 0);
|
||||
assert(FloatModeStrict == 1);
|
||||
assert(FloatModeStrict == 0);
|
||||
assert(FloatModeOptimized == 1);
|
||||
}
|
||||
{
|
||||
buf_appendf(contents,
|
||||
@@ -7049,8 +7038,8 @@ Buf *codegen_generate_builtin_source(CodeGen *g) {
|
||||
" Big,\n"
|
||||
" Little,\n"
|
||||
"};\n\n");
|
||||
assert(FloatModeOptimized == 0);
|
||||
assert(FloatModeStrict == 1);
|
||||
//assert(EndianBig == 0);
|
||||
//assert(EndianLittle == 1);
|
||||
}
|
||||
{
|
||||
const char *endian_str = g->is_big_endian ? "Endian.Big" : "Endian.Little";
|
||||
@@ -7071,36 +7060,84 @@ Buf *codegen_generate_builtin_source(CodeGen *g) {
|
||||
return contents;
|
||||
}
|
||||
|
||||
static void define_builtin_compile_vars(CodeGen *g) {
|
||||
static Error define_builtin_compile_vars(CodeGen *g) {
|
||||
if (g->std_package == nullptr)
|
||||
return;
|
||||
return ErrorNone;
|
||||
|
||||
Error err;
|
||||
|
||||
Buf *manifest_dir = buf_alloc();
|
||||
os_path_join(get_stage1_cache_path(), buf_create_from_str("builtin"), manifest_dir);
|
||||
|
||||
CacheHash cache_hash;
|
||||
cache_init(&cache_hash, manifest_dir);
|
||||
|
||||
Buf *compiler_id;
|
||||
if ((err = get_compiler_id(&compiler_id)))
|
||||
return err;
|
||||
|
||||
// Only a few things affect builtin.zig
|
||||
cache_buf(&cache_hash, compiler_id);
|
||||
cache_int(&cache_hash, g->build_mode);
|
||||
cache_bool(&cache_hash, g->is_test_build);
|
||||
cache_int(&cache_hash, g->zig_target.arch.arch);
|
||||
cache_int(&cache_hash, g->zig_target.arch.sub_arch);
|
||||
cache_int(&cache_hash, g->zig_target.vendor);
|
||||
cache_int(&cache_hash, g->zig_target.os);
|
||||
cache_int(&cache_hash, g->zig_target.env_type);
|
||||
cache_int(&cache_hash, g->zig_target.oformat);
|
||||
cache_bool(&cache_hash, g->have_err_ret_tracing);
|
||||
cache_bool(&cache_hash, g->libc_link_lib != nullptr);
|
||||
|
||||
Buf digest = BUF_INIT;
|
||||
buf_resize(&digest, 0);
|
||||
if ((err = cache_hit(&cache_hash, &digest)))
|
||||
return err;
|
||||
|
||||
// We should always get a cache hit because there are no
|
||||
// files in the input hash.
|
||||
assert(buf_len(&digest) != 0);
|
||||
|
||||
Buf *this_dir = buf_alloc();
|
||||
os_path_join(manifest_dir, &digest, this_dir);
|
||||
|
||||
if ((err = os_make_path(this_dir)))
|
||||
return err;
|
||||
|
||||
const char *builtin_zig_basename = "builtin.zig";
|
||||
Buf *builtin_zig_path = buf_alloc();
|
||||
os_path_join(&g->cache_dir, buf_create_from_str(builtin_zig_basename), builtin_zig_path);
|
||||
os_path_join(this_dir, buf_create_from_str(builtin_zig_basename), builtin_zig_path);
|
||||
|
||||
Buf *contents = codegen_generate_builtin_source(g);
|
||||
ensure_cache_dir(g);
|
||||
os_write_file(builtin_zig_path, contents);
|
||||
|
||||
Buf *resolved_path = buf_alloc();
|
||||
Buf *resolve_paths[] = {builtin_zig_path};
|
||||
*resolved_path = os_path_resolve(resolve_paths, 1);
|
||||
bool hit;
|
||||
if ((err = os_file_exists(builtin_zig_path, &hit)))
|
||||
return err;
|
||||
Buf *contents;
|
||||
if (hit) {
|
||||
contents = buf_alloc();
|
||||
if ((err = os_fetch_file_path(builtin_zig_path, contents, false))) {
|
||||
fprintf(stderr, "Unable to open '%s': %s\n", buf_ptr(builtin_zig_path), err_str(err));
|
||||
exit(1);
|
||||
}
|
||||
} else {
|
||||
contents = codegen_generate_builtin_source(g);
|
||||
os_write_file(builtin_zig_path, contents);
|
||||
}
|
||||
|
||||
assert(g->root_package);
|
||||
assert(g->std_package);
|
||||
g->compile_var_package = new_package(buf_ptr(&g->cache_dir), builtin_zig_basename);
|
||||
g->compile_var_package = new_package(buf_ptr(this_dir), builtin_zig_basename);
|
||||
g->root_package->package_table.put(buf_create_from_str("builtin"), g->compile_var_package);
|
||||
g->std_package->package_table.put(buf_create_from_str("builtin"), g->compile_var_package);
|
||||
g->compile_var_import = add_source_file(g, g->compile_var_package, resolved_path, contents);
|
||||
g->compile_var_import = add_source_file(g, g->compile_var_package, builtin_zig_path, contents);
|
||||
scan_import(g, g->compile_var_import);
|
||||
|
||||
return ErrorNone;
|
||||
}
|
||||
|
||||
static void init(CodeGen *g) {
|
||||
if (g->module)
|
||||
return;
|
||||
|
||||
|
||||
if (g->llvm_argv_len > 0) {
|
||||
const char **args = allocate_nonzero<const char *>(g->llvm_argv_len + 2);
|
||||
args[0] = "zig (LLVM option parsing)";
|
||||
@@ -7207,7 +7244,11 @@ static void init(CodeGen *g) {
|
||||
g->have_err_ret_tracing = g->build_mode != BuildModeFastRelease && g->build_mode != BuildModeSmallRelease;
|
||||
|
||||
define_builtin_fns(g);
|
||||
define_builtin_compile_vars(g);
|
||||
Error err;
|
||||
if ((err = define_builtin_compile_vars(g))) {
|
||||
fprintf(stderr, "Unable to create builtin.zig: %s\n", err_str(err));
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
void codegen_translate_c(CodeGen *g, Buf *full_path) {
|
||||
@@ -7253,8 +7294,8 @@ static ImportTableEntry *add_special_code(CodeGen *g, PackageTableEntry *package
|
||||
Buf *resolved_path = buf_alloc();
|
||||
*resolved_path = os_path_resolve(resolve_paths, 1);
|
||||
Buf *import_code = buf_alloc();
|
||||
int err;
|
||||
if ((err = os_fetch_file_path(resolved_path, import_code, false))) {
|
||||
Error err;
|
||||
if ((err = file_fetch(g, resolved_path, import_code))) {
|
||||
zig_panic("unable to open '%s': %s\n", buf_ptr(&path_to_code_src), err_str(err));
|
||||
}
|
||||
|
||||
@@ -7327,23 +7368,32 @@ static void create_test_compile_var_and_add_test_runner(CodeGen *g) {
|
||||
g->test_runner_import = add_special_code(g, g->test_runner_package, "test_runner.zig");
|
||||
}
|
||||
|
||||
static void gen_root_source(CodeGen *g) {
|
||||
static Buf *get_resolved_root_src_path(CodeGen *g) {
|
||||
// TODO memoize
|
||||
if (buf_len(&g->root_package->root_src_path) == 0)
|
||||
return;
|
||||
return nullptr;
|
||||
|
||||
codegen_add_time_event(g, "Semantic Analysis");
|
||||
|
||||
Buf *rel_full_path = buf_alloc();
|
||||
os_path_join(&g->root_package->root_src_dir, &g->root_package->root_src_path, rel_full_path);
|
||||
Buf rel_full_path = BUF_INIT;
|
||||
os_path_join(&g->root_package->root_src_dir, &g->root_package->root_src_path, &rel_full_path);
|
||||
|
||||
Buf *resolved_path = buf_alloc();
|
||||
Buf *resolve_paths[] = {rel_full_path};
|
||||
Buf *resolve_paths[] = {&rel_full_path};
|
||||
*resolved_path = os_path_resolve(resolve_paths, 1);
|
||||
|
||||
return resolved_path;
|
||||
}
|
||||
|
||||
static void gen_root_source(CodeGen *g) {
|
||||
Buf *resolved_path = get_resolved_root_src_path(g);
|
||||
if (resolved_path == nullptr)
|
||||
return;
|
||||
|
||||
Buf *source_code = buf_alloc();
|
||||
int err;
|
||||
if ((err = os_fetch_file_path(rel_full_path, source_code, true))) {
|
||||
fprintf(stderr, "unable to open '%s': %s\n", buf_ptr(rel_full_path), err_str(err));
|
||||
// No need for using the caching system for this file fetch because it is handled
|
||||
// separately.
|
||||
if ((err = os_fetch_file_path(resolved_path, source_code, true))) {
|
||||
fprintf(stderr, "unable to open '%s': %s\n", buf_ptr(resolved_path), err_str(err));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
@@ -7408,6 +7458,8 @@ static void gen_global_asm(CodeGen *g) {
|
||||
int err;
|
||||
for (size_t i = 0; i < g->assembly_files.length; i += 1) {
|
||||
Buf *asm_file = g->assembly_files.at(i);
|
||||
// No need to use the caching system for these fetches because they
|
||||
// are handled separately.
|
||||
if ((err = os_fetch_file_path(asm_file, &contents, false))) {
|
||||
zig_panic("Unable to read %s: %s", buf_ptr(asm_file), err_str(err));
|
||||
}
|
||||
@@ -7448,7 +7500,6 @@ static void prepend_c_type_to_decl_list(CodeGen *g, GenH *gen_h, ZigType *type_e
|
||||
case ZigTypeIdUndefined:
|
||||
case ZigTypeIdNull:
|
||||
case ZigTypeIdNamespace:
|
||||
case ZigTypeIdBlock:
|
||||
case ZigTypeIdBoundFn:
|
||||
case ZigTypeIdArgTuple:
|
||||
case ZigTypeIdErrorUnion:
|
||||
@@ -7627,7 +7678,6 @@ static void get_c_type(CodeGen *g, GenH *gen_h, ZigType *type_entry, Buf *out_bu
|
||||
case ZigTypeIdMetaType:
|
||||
case ZigTypeIdBoundFn:
|
||||
case ZigTypeIdNamespace:
|
||||
case ZigTypeIdBlock:
|
||||
case ZigTypeIdComptimeFloat:
|
||||
case ZigTypeIdComptimeInt:
|
||||
case ZigTypeIdUndefined:
|
||||
@@ -7671,19 +7721,11 @@ static Buf *preprocessor_mangle(Buf *src) {
|
||||
}
|
||||
|
||||
static void gen_h_file(CodeGen *g) {
|
||||
if (!g->want_h_file)
|
||||
return;
|
||||
|
||||
GenH gen_h_data = {0};
|
||||
GenH *gen_h = &gen_h_data;
|
||||
|
||||
codegen_add_time_event(g, "Generate .h");
|
||||
|
||||
assert(!g->is_test_build);
|
||||
|
||||
if (!g->out_h_path) {
|
||||
g->out_h_path = buf_sprintf("%s.h", buf_ptr(g->root_out_name));
|
||||
}
|
||||
assert(g->out_h_path != nullptr);
|
||||
|
||||
FILE *out_h = fopen(buf_ptr(g->out_h_path), "wb");
|
||||
if (!out_h)
|
||||
@@ -7788,7 +7830,6 @@ static void gen_h_file(CodeGen *g) {
|
||||
case ZigTypeIdErrorUnion:
|
||||
case ZigTypeIdErrorSet:
|
||||
case ZigTypeIdNamespace:
|
||||
case ZigTypeIdBlock:
|
||||
case ZigTypeIdBoundFn:
|
||||
case ZigTypeIdArgTuple:
|
||||
case ZigTypeIdOptional:
|
||||
@@ -7886,14 +7927,231 @@ void codegen_add_time_event(CodeGen *g, const char *name) {
|
||||
g->timing_events.append({os_get_time(), name});
|
||||
}
|
||||
|
||||
void codegen_build(CodeGen *g) {
|
||||
assert(g->out_type != OutTypeUnknown);
|
||||
init(g);
|
||||
static void add_cache_pkg(CodeGen *g, CacheHash *ch, PackageTableEntry *pkg) {
|
||||
if (buf_len(&pkg->root_src_path) == 0)
|
||||
return;
|
||||
|
||||
gen_global_asm(g);
|
||||
gen_root_source(g);
|
||||
do_code_gen(g);
|
||||
gen_h_file(g);
|
||||
Buf *rel_full_path = buf_alloc();
|
||||
os_path_join(&pkg->root_src_dir, &pkg->root_src_path, rel_full_path);
|
||||
cache_file(ch, rel_full_path);
|
||||
|
||||
auto it = pkg->package_table.entry_iterator();
|
||||
for (;;) {
|
||||
auto *entry = it.next();
|
||||
if (!entry)
|
||||
break;
|
||||
|
||||
cache_buf(ch, entry->key);
|
||||
add_cache_pkg(g, ch, entry->value);
|
||||
}
|
||||
}
|
||||
|
||||
// Called before init()
|
||||
static Error check_cache(CodeGen *g, Buf *manifest_dir, Buf *digest) {
|
||||
Error err;
|
||||
|
||||
Buf *compiler_id;
|
||||
if ((err = get_compiler_id(&compiler_id)))
|
||||
return err;
|
||||
|
||||
CacheHash *ch = &g->cache_hash;
|
||||
cache_init(ch, manifest_dir);
|
||||
|
||||
add_cache_pkg(g, ch, g->root_package);
|
||||
if (g->linker_script != nullptr) {
|
||||
cache_file(ch, buf_create_from_str(g->linker_script));
|
||||
}
|
||||
cache_buf(ch, compiler_id);
|
||||
cache_buf(ch, g->root_out_name);
|
||||
cache_list_of_link_lib(ch, g->link_libs_list.items, g->link_libs_list.length);
|
||||
cache_list_of_buf(ch, g->darwin_frameworks.items, g->darwin_frameworks.length);
|
||||
cache_list_of_buf(ch, g->rpath_list.items, g->rpath_list.length);
|
||||
cache_list_of_buf(ch, g->forbidden_libs.items, g->forbidden_libs.length);
|
||||
cache_list_of_file(ch, g->link_objects.items, g->link_objects.length);
|
||||
cache_list_of_file(ch, g->assembly_files.items, g->assembly_files.length);
|
||||
cache_int(ch, g->emit_file_type);
|
||||
cache_int(ch, g->build_mode);
|
||||
cache_int(ch, g->out_type);
|
||||
cache_int(ch, g->zig_target.arch.arch);
|
||||
cache_int(ch, g->zig_target.arch.sub_arch);
|
||||
cache_int(ch, g->zig_target.vendor);
|
||||
cache_int(ch, g->zig_target.os);
|
||||
cache_int(ch, g->zig_target.env_type);
|
||||
cache_int(ch, g->zig_target.oformat);
|
||||
cache_bool(ch, g->is_static);
|
||||
cache_bool(ch, g->strip_debug_symbols);
|
||||
cache_bool(ch, g->is_test_build);
|
||||
cache_bool(ch, g->is_native_target);
|
||||
cache_bool(ch, g->windows_subsystem_windows);
|
||||
cache_bool(ch, g->windows_subsystem_console);
|
||||
cache_bool(ch, g->linker_rdynamic);
|
||||
cache_bool(ch, g->no_rosegment_workaround);
|
||||
cache_bool(ch, g->each_lib_rpath);
|
||||
cache_buf_opt(ch, g->mmacosx_version_min);
|
||||
cache_buf_opt(ch, g->mios_version_min);
|
||||
cache_usize(ch, g->version_major);
|
||||
cache_usize(ch, g->version_minor);
|
||||
cache_usize(ch, g->version_patch);
|
||||
cache_buf_opt(ch, g->test_filter);
|
||||
cache_buf_opt(ch, g->test_name_prefix);
|
||||
cache_list_of_str(ch, g->llvm_argv, g->llvm_argv_len);
|
||||
cache_list_of_str(ch, g->clang_argv, g->clang_argv_len);
|
||||
cache_list_of_str(ch, g->lib_dirs.items, g->lib_dirs.length);
|
||||
|
||||
buf_resize(digest, 0);
|
||||
if ((err = cache_hit(ch, digest)))
|
||||
return err;
|
||||
|
||||
return ErrorNone;
|
||||
}
|
||||
|
||||
static void resolve_out_paths(CodeGen *g) {
|
||||
Buf *o_basename = buf_create_from_buf(g->root_out_name);
|
||||
|
||||
switch (g->emit_file_type) {
|
||||
case EmitFileTypeBinary:
|
||||
{
|
||||
const char *o_ext = target_o_file_ext(&g->zig_target);
|
||||
buf_append_str(o_basename, o_ext);
|
||||
break;
|
||||
}
|
||||
case EmitFileTypeAssembly:
|
||||
{
|
||||
const char *asm_ext = target_asm_file_ext(&g->zig_target);
|
||||
buf_append_str(o_basename, asm_ext);
|
||||
break;
|
||||
}
|
||||
case EmitFileTypeLLVMIr:
|
||||
{
|
||||
const char *llvm_ir_ext = target_llvm_ir_file_ext(&g->zig_target);
|
||||
buf_append_str(o_basename, llvm_ir_ext);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
zig_unreachable();
|
||||
}
|
||||
|
||||
if (g->enable_cache || g->out_type != OutTypeObj) {
|
||||
os_path_join(&g->artifact_dir, o_basename, &g->o_file_output_path);
|
||||
} else if (g->wanted_output_file_path != nullptr && g->out_type == OutTypeObj) {
|
||||
buf_init_from_buf(&g->o_file_output_path, g->wanted_output_file_path);
|
||||
} else {
|
||||
buf_init_from_buf(&g->o_file_output_path, o_basename);
|
||||
}
|
||||
|
||||
if (g->out_type == OutTypeObj) {
|
||||
buf_init_from_buf(&g->output_file_path, &g->o_file_output_path);
|
||||
} else if (g->out_type == OutTypeExe) {
|
||||
if (!g->enable_cache && g->wanted_output_file_path != nullptr) {
|
||||
buf_init_from_buf(&g->output_file_path, g->wanted_output_file_path);
|
||||
} else {
|
||||
assert(g->root_out_name);
|
||||
|
||||
Buf basename = BUF_INIT;
|
||||
buf_init_from_buf(&basename, g->root_out_name);
|
||||
buf_append_str(&basename, target_exe_file_ext(&g->zig_target));
|
||||
if (g->enable_cache || g->is_test_build) {
|
||||
os_path_join(&g->artifact_dir, &basename, &g->output_file_path);
|
||||
} else {
|
||||
buf_init_from_buf(&g->output_file_path, &basename);
|
||||
}
|
||||
}
|
||||
} else if (g->out_type == OutTypeLib) {
|
||||
if (!g->enable_cache && g->wanted_output_file_path != nullptr) {
|
||||
buf_init_from_buf(&g->output_file_path, g->wanted_output_file_path);
|
||||
} else {
|
||||
Buf basename = BUF_INIT;
|
||||
buf_init_from_buf(&basename, g->root_out_name);
|
||||
buf_append_str(&basename, target_lib_file_ext(&g->zig_target, g->is_static,
|
||||
g->version_major, g->version_minor, g->version_patch));
|
||||
if (g->enable_cache) {
|
||||
os_path_join(&g->artifact_dir, &basename, &g->output_file_path);
|
||||
} else {
|
||||
buf_init_from_buf(&g->output_file_path, &basename);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
zig_unreachable();
|
||||
}
|
||||
|
||||
if (g->want_h_file && !g->out_h_path) {
|
||||
assert(g->root_out_name);
|
||||
Buf *h_basename = buf_sprintf("%s.h", buf_ptr(g->root_out_name));
|
||||
if (g->enable_cache) {
|
||||
g->out_h_path = buf_alloc();
|
||||
os_path_join(&g->artifact_dir, h_basename, g->out_h_path);
|
||||
} else {
|
||||
g->out_h_path = h_basename;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void codegen_build_and_link(CodeGen *g) {
|
||||
Error err;
|
||||
assert(g->out_type != OutTypeUnknown);
|
||||
|
||||
Buf *stage1_dir = get_stage1_cache_path();
|
||||
Buf *artifact_dir = buf_alloc();
|
||||
Buf digest = BUF_INIT;
|
||||
if (g->enable_cache) {
|
||||
codegen_add_time_event(g, "Check Cache");
|
||||
|
||||
Buf *manifest_dir = buf_alloc();
|
||||
os_path_join(stage1_dir, buf_create_from_str("build"), manifest_dir);
|
||||
|
||||
if ((err = check_cache(g, manifest_dir, &digest))) {
|
||||
fprintf(stderr, "Unable to check cache: %s\n", err_str(err));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
os_path_join(stage1_dir, buf_create_from_str("artifact"), artifact_dir);
|
||||
}
|
||||
|
||||
if (g->enable_cache && buf_len(&digest) != 0) {
|
||||
os_path_join(artifact_dir, &digest, &g->artifact_dir);
|
||||
resolve_out_paths(g);
|
||||
} else {
|
||||
init(g);
|
||||
|
||||
codegen_add_time_event(g, "Semantic Analysis");
|
||||
|
||||
gen_global_asm(g);
|
||||
gen_root_source(g);
|
||||
|
||||
if (g->enable_cache) {
|
||||
if ((err = cache_final(&g->cache_hash, &digest))) {
|
||||
fprintf(stderr, "Unable to finalize cache hash: %s\n", err_str(err));
|
||||
exit(1);
|
||||
}
|
||||
os_path_join(artifact_dir, &digest, &g->artifact_dir);
|
||||
} else {
|
||||
buf_init_from_buf(&g->artifact_dir, &g->cache_dir);
|
||||
}
|
||||
if ((err = os_make_path(&g->artifact_dir))) {
|
||||
fprintf(stderr, "Unable to create artifact directory: %s\n", err_str(err));
|
||||
exit(1);
|
||||
}
|
||||
resolve_out_paths(g);
|
||||
|
||||
codegen_add_time_event(g, "Code Generation");
|
||||
do_code_gen(g);
|
||||
codegen_add_time_event(g, "LLVM Emit Output");
|
||||
zig_llvm_emit_output(g);
|
||||
|
||||
if (g->want_h_file) {
|
||||
codegen_add_time_event(g, "Generate .h");
|
||||
gen_h_file(g);
|
||||
}
|
||||
if (g->out_type != OutTypeObj) {
|
||||
codegen_link(g);
|
||||
}
|
||||
}
|
||||
|
||||
if (g->enable_cache) {
|
||||
cache_release(&g->cache_hash);
|
||||
}
|
||||
codegen_add_time_event(g, "Done");
|
||||
}
|
||||
|
||||
PackageTableEntry *codegen_create_package(CodeGen *g, const char *root_src_dir, const char *root_src_path) {
|
||||
|
||||
Reference in New Issue
Block a user