aboutsummaryrefslogtreecommitdiff
path: root/src/codegen.cpp
diff options
context:
space:
mode:
authorhryx <codroid@gmail.com>2019-05-12 02:00:49 -0700
committerhryx <codroid@gmail.com>2019-05-12 02:00:49 -0700
commit3787f3428625e830fd852a8f5a40c7d8a2d429f6 (patch)
tree23fb493b9d2f07c7abe57955874682959936319a /src/codegen.cpp
parent16aee1f58a80295f7599a8290d764a5c7040c373 (diff)
parentedcc7c72d1a684a8a16ca23ad26689f2cce4e803 (diff)
downloadzig-3787f3428625e830fd852a8f5a40c7d8a2d429f6.tar.gz
zig-3787f3428625e830fd852a8f5a40c7d8a2d429f6.zip
Merge branch 'master' into rebased
Diffstat (limited to 'src/codegen.cpp')
-rw-r--r--src/codegen.cpp509
1 files changed, 353 insertions, 156 deletions
diff --git a/src/codegen.cpp b/src/codegen.cpp
index 568344fc09..d21ada1b23 100644
--- a/src/codegen.cpp
+++ b/src/codegen.cpp
@@ -19,6 +19,7 @@
#include "target.hpp"
#include "util.hpp"
#include "zig_llvm.h"
+#include "userland.h"
#include <stdio.h>
#include <errno.h>
@@ -92,7 +93,7 @@ static const char *symbols_that_llvm_depends_on[] = {
};
CodeGen *codegen_create(Buf *main_pkg_path, Buf *root_src_path, const ZigTarget *target,
- OutType out_type, BuildMode build_mode, Buf *zig_lib_dir, Buf *override_std_dir,
+ OutType out_type, BuildMode build_mode, Buf *override_lib_dir, Buf *override_std_dir,
ZigLibCInstallation *libc, Buf *cache_dir)
{
CodeGen *g = allocate<CodeGen>(1);
@@ -100,19 +101,24 @@ CodeGen *codegen_create(Buf *main_pkg_path, Buf *root_src_path, const ZigTarget
codegen_add_time_event(g, "Initialize");
g->libc = libc;
- g->zig_lib_dir = zig_lib_dir;
g->zig_target = target;
g->cache_dir = cache_dir;
+ if (override_lib_dir == nullptr) {
+ g->zig_lib_dir = get_zig_lib_dir();
+ } else {
+ g->zig_lib_dir = override_lib_dir;
+ }
+
if (override_std_dir == nullptr) {
g->zig_std_dir = buf_alloc();
- os_path_join(zig_lib_dir, buf_create_from_str("std"), g->zig_std_dir);
+ os_path_join(g->zig_lib_dir, buf_create_from_str("std"), g->zig_std_dir);
} else {
g->zig_std_dir = override_std_dir;
}
g->zig_c_headers_dir = buf_alloc();
- os_path_join(zig_lib_dir, buf_create_from_str("include"), g->zig_c_headers_dir);
+ os_path_join(g->zig_lib_dir, buf_create_from_str("include"), g->zig_c_headers_dir);
g->build_mode = build_mode;
g->out_type = out_type;
@@ -393,6 +399,15 @@ static void add_uwtable_attr(CodeGen *g, LLVMValueRef fn_val) {
}
}
+static void add_probe_stack_attr(CodeGen *g, LLVMValueRef fn_val) {
+ // Windows already emits its own stack probes
+ if (!g->disable_stack_probing && g->zig_target->os != OsWindows &&
+ (g->zig_target->arch == ZigLLVM_x86 ||
+ g->zig_target->arch == ZigLLVM_x86_64)) {
+ addLLVMFnAttrStr(fn_val, "probe-stack", "__zig_probe_stack");
+ }
+}
+
static LLVMLinkage to_llvm_linkage(GlobalLinkageId id) {
switch (id) {
case GlobalLinkageIdInternal:
@@ -424,7 +439,7 @@ static uint32_t get_err_ret_trace_arg_index(CodeGen *g, ZigFn *fn_table_entry) {
}
static void maybe_export_dll(CodeGen *g, LLVMValueRef global_value, GlobalLinkageId linkage) {
- if (linkage != GlobalLinkageIdInternal && g->zig_target->os == OsWindows) {
+ if (linkage != GlobalLinkageIdInternal && g->zig_target->os == OsWindows && g->is_dynamic) {
LLVMSetDLLStorageClass(global_value, LLVMDLLExportStorageClass);
}
}
@@ -495,6 +510,14 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, ZigFn *fn_table_entry) {
auto entry = g->exported_symbol_names.maybe_get(symbol_name);
if (entry == nullptr) {
fn_table_entry->llvm_value = LLVMAddFunction(g->module, buf_ptr(symbol_name), fn_llvm_type);
+
+ if (target_is_wasm(g->zig_target)) {
+ assert(fn_table_entry->proto_node->type == NodeTypeFnProto);
+ AstNodeFnProto *fn_proto = &fn_table_entry->proto_node->data.fn_proto;
+ if (fn_proto-> is_extern && fn_proto->lib_name != nullptr ) {
+ addLLVMFnAttrStr(fn_table_entry->llvm_value, "wasm-import-module", buf_ptr(fn_proto->lib_name));
+ }
+ }
} else {
assert(entry->value->id == TldIdFn);
TldFn *tld_fn = reinterpret_cast<TldFn *>(entry->value);
@@ -573,6 +596,8 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, ZigFn *fn_table_entry) {
addLLVMFnAttr(fn_table_entry->llvm_value, "sspstrong");
addLLVMFnAttrStr(fn_table_entry->llvm_value, "stack-protector-buffer-size", "4");
}
+
+ add_probe_stack_attr(g, fn_table_entry->llvm_value);
}
} else {
maybe_import_dll(g, fn_table_entry->llvm_value, linkage);
@@ -983,10 +1008,19 @@ static void gen_panic(CodeGen *g, LLVMValueRef msg_arg, LLVMValueRef stack_trace
LLVMBuildUnreachable(g->builder);
}
+// TODO update most callsites to call gen_assertion instead of this
static void gen_safety_crash(CodeGen *g, PanicMsgId msg_id) {
gen_panic(g, get_panic_msg_ptr_val(g, msg_id), nullptr);
}
+static void gen_assertion(CodeGen *g, PanicMsgId msg_id, IrInstruction *source_instruction) {
+ if (ir_want_runtime_safety(g, source_instruction)) {
+ gen_safety_crash(g, msg_id);
+ } else {
+ LLVMBuildUnreachable(g->builder);
+ }
+}
+
static LLVMValueRef get_stacksave_fn_val(CodeGen *g) {
if (g->stacksave_fn_val)
return g->stacksave_fn_val;
@@ -1022,7 +1056,7 @@ static LLVMValueRef get_write_register_fn_val(CodeGen *g) {
// !0 = !{!"sp\00"}
LLVMTypeRef param_types[] = {
- LLVMMetadataTypeInContext(LLVMGetGlobalContext()),
+ LLVMMetadataTypeInContext(LLVMGetGlobalContext()),
LLVMIntType(g->pointer_size_bytes * 8),
};
@@ -1541,11 +1575,19 @@ static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) {
LLVMValueRef offset_buf_ptr = LLVMConstInBoundsGEP(global_array, offset_ptr_indices, 2);
Buf *fn_name = get_mangled_name(g, buf_create_from_str("__zig_fail_unwrap"), false);
- LLVMTypeRef arg_types[] = {
- get_llvm_type(g, g->ptr_to_stack_trace_type),
- get_llvm_type(g, g->err_tag_type),
- };
- LLVMTypeRef fn_type_ref = LLVMFunctionType(LLVMVoidType(), arg_types, 2, false);
+ LLVMTypeRef fn_type_ref;
+ if (g->have_err_ret_tracing) {
+ LLVMTypeRef arg_types[] = {
+ get_llvm_type(g, g->ptr_to_stack_trace_type),
+ get_llvm_type(g, g->err_tag_type),
+ };
+ fn_type_ref = LLVMFunctionType(LLVMVoidType(), arg_types, 2, false);
+ } else {
+ LLVMTypeRef arg_types[] = {
+ get_llvm_type(g, g->err_tag_type),
+ };
+ fn_type_ref = LLVMFunctionType(LLVMVoidType(), arg_types, 1, false);
+ }
LLVMValueRef fn_val = LLVMAddFunction(g->module, buf_ptr(fn_name), fn_type_ref);
addLLVMFnAttr(fn_val, "noreturn");
addLLVMFnAttr(fn_val, "cold");
@@ -1567,7 +1609,15 @@ static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) {
LLVMPositionBuilderAtEnd(g->builder, entry_block);
ZigLLVMClearCurrentDebugLocation(g->builder);
- LLVMValueRef err_val = LLVMGetParam(fn_val, 1);
+ LLVMValueRef err_ret_trace_arg;
+ LLVMValueRef err_val;
+ if (g->have_err_ret_tracing) {
+ err_ret_trace_arg = LLVMGetParam(fn_val, 0);
+ err_val = LLVMGetParam(fn_val, 1);
+ } else {
+ err_ret_trace_arg = nullptr;
+ err_val = LLVMGetParam(fn_val, 0);
+ }
LLVMValueRef err_table_indices[] = {
LLVMConstNull(g->builtin_types.entry_usize->llvm_type),
@@ -1589,7 +1639,7 @@ static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) {
LLVMValueRef global_slice_len_field_ptr = LLVMBuildStructGEP(g->builder, global_slice, slice_len_index, "");
gen_store(g, full_buf_len, global_slice_len_field_ptr, u8_ptr_type);
- gen_panic(g, global_slice, LLVMGetParam(fn_val, 0));
+ gen_panic(g, global_slice, err_ret_trace_arg);
LLVMPositionBuilderAtEnd(g->builder, prev_block);
LLVMSetCurrentDebugLocation(g->builder, prev_debug_location);
@@ -1625,17 +1675,26 @@ static LLVMValueRef get_cur_err_ret_trace_val(CodeGen *g, Scope *scope) {
static void gen_safety_crash_for_err(CodeGen *g, LLVMValueRef err_val, Scope *scope) {
LLVMValueRef safety_crash_err_fn = get_safety_crash_err_fn(g);
- LLVMValueRef err_ret_trace_val = get_cur_err_ret_trace_val(g, scope);
- if (err_ret_trace_val == nullptr) {
- ZigType *ptr_to_stack_trace_type = get_ptr_to_stack_trace_type(g);
- err_ret_trace_val = LLVMConstNull(get_llvm_type(g, ptr_to_stack_trace_type));
+ LLVMValueRef call_instruction;
+ if (g->have_err_ret_tracing) {
+ LLVMValueRef err_ret_trace_val = get_cur_err_ret_trace_val(g, scope);
+ if (err_ret_trace_val == nullptr) {
+ ZigType *ptr_to_stack_trace_type = get_ptr_to_stack_trace_type(g);
+ err_ret_trace_val = LLVMConstNull(get_llvm_type(g, ptr_to_stack_trace_type));
+ }
+ LLVMValueRef args[] = {
+ err_ret_trace_val,
+ err_val,
+ };
+ call_instruction = ZigLLVMBuildCall(g->builder, safety_crash_err_fn, args, 2,
+ get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAuto, "");
+ } else {
+ LLVMValueRef args[] = {
+ err_val,
+ };
+ call_instruction = ZigLLVMBuildCall(g->builder, safety_crash_err_fn, args, 1,
+ get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAuto, "");
}
- LLVMValueRef args[] = {
- err_ret_trace_val,
- err_val,
- };
- LLVMValueRef call_instruction = ZigLLVMBuildCall(g->builder, safety_crash_err_fn, args, 2, get_llvm_cc(g, CallingConventionUnspecified),
- ZigLLVM_FnInlineAuto, "");
LLVMSetTailCall(call_instruction, true);
LLVMBuildUnreachable(g->builder);
}
@@ -3452,6 +3511,15 @@ static bool want_valgrind_support(CodeGen *g) {
zig_unreachable();
}
+static void gen_valgrind_undef(CodeGen *g, LLVMValueRef dest_ptr, LLVMValueRef byte_count) {
+ static const uint32_t VG_USERREQ__MAKE_MEM_UNDEFINED = 1296236545;
+ ZigType *usize = g->builtin_types.entry_usize;
+ LLVMValueRef zero = LLVMConstInt(usize->llvm_type, 0, false);
+ LLVMValueRef req = LLVMConstInt(usize->llvm_type, VG_USERREQ__MAKE_MEM_UNDEFINED, false);
+ LLVMValueRef ptr_as_usize = LLVMBuildPtrToInt(g->builder, dest_ptr, usize->llvm_type, "");
+ gen_valgrind_client_request(g, zero, req, ptr_as_usize, byte_count, zero, zero, zero);
+}
+
static void gen_undef_init(CodeGen *g, uint32_t ptr_align_bytes, ZigType *value_type, LLVMValueRef ptr) {
assert(type_has_bits(value_type));
uint64_t size_bytes = LLVMStoreSizeOfType(g->target_data_ref, get_llvm_type(g, value_type));
@@ -3466,11 +3534,7 @@ static void gen_undef_init(CodeGen *g, uint32_t ptr_align_bytes, ZigType *value_
ZigLLVMBuildMemSet(g->builder, dest_ptr, fill_char, byte_count, ptr_align_bytes, false);
// then tell valgrind that the memory is undefined even though we just memset it
if (want_valgrind_support(g)) {
- static const uint32_t VG_USERREQ__MAKE_MEM_UNDEFINED = 1296236545;
- LLVMValueRef zero = LLVMConstInt(usize->llvm_type, 0, false);
- LLVMValueRef req = LLVMConstInt(usize->llvm_type, VG_USERREQ__MAKE_MEM_UNDEFINED, false);
- LLVMValueRef ptr_as_usize = LLVMBuildPtrToInt(g->builder, dest_ptr, usize->llvm_type, "");
- gen_valgrind_client_request(g, zero, req, ptr_as_usize, byte_count, zero, zero, zero);
+ gen_valgrind_undef(g, dest_ptr, byte_count);
}
}
@@ -3480,14 +3544,14 @@ static LLVMValueRef ir_render_store_ptr(CodeGen *g, IrExecutable *executable, Ir
if (!type_has_bits(ptr_type))
return nullptr;
- bool have_init_expr = !value_is_all_undef(&instruction->value->value);
+ bool have_init_expr = !value_is_all_undef(&instruction->value->value);
if (have_init_expr) {
LLVMValueRef ptr = ir_llvm_value(g, instruction->ptr);
LLVMValueRef value = ir_llvm_value(g, instruction->value);
gen_assign_raw(g, ptr, ptr_type, value);
} else if (ir_want_runtime_safety(g, &instruction->base)) {
gen_undef_init(g, get_ptr_align(g, ptr_type), instruction->value->value.type,
- ir_llvm_value(g, instruction->ptr));
+ ir_llvm_value(g, instruction->ptr));
}
return nullptr;
}
@@ -3690,7 +3754,7 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
}
FnWalk fn_walk = {};
fn_walk.id = FnWalkIdCall;
- fn_walk.data.call.inst = instruction;
+ fn_walk.data.call.inst = instruction;
fn_walk.data.call.is_var_args = is_var_args;
fn_walk.data.call.gen_param_values = &gen_param_values;
walk_function_params(g, fn_type, &fn_walk);
@@ -3710,7 +3774,7 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
LLVMCallConv llvm_cc = get_llvm_cc(g, cc);
LLVMValueRef result;
-
+
if (instruction->new_stack == nullptr) {
result = ZigLLVMBuildCall(g->builder, fn_val,
gen_param_values.items, (unsigned)gen_param_values.length, llvm_cc, fn_inline, "");
@@ -3968,19 +4032,19 @@ static LLVMValueRef ir_render_asm(CodeGen *g, IrExecutable *executable, IrInstru
}
static LLVMValueRef gen_non_null_bit(CodeGen *g, ZigType *maybe_type, LLVMValueRef maybe_handle) {
- assert(maybe_type->id == ZigTypeIdOptional);
+ assert(maybe_type->id == ZigTypeIdOptional ||
+ (maybe_type->id == ZigTypeIdPointer && maybe_type->data.pointer.allow_zero));
+
ZigType *child_type = maybe_type->data.maybe.child_type;
- if (!type_has_bits(child_type)) {
+ if (!type_has_bits(child_type))
return maybe_handle;
- } else {
- bool is_scalar = !handle_is_ptr(maybe_type);
- if (is_scalar) {
- return LLVMBuildICmp(g->builder, LLVMIntNE, maybe_handle, LLVMConstNull(get_llvm_type(g, maybe_type)), "");
- } else {
- LLVMValueRef maybe_field_ptr = LLVMBuildStructGEP(g->builder, maybe_handle, maybe_null_index, "");
- return gen_load_untyped(g, maybe_field_ptr, 0, false, "");
- }
- }
+
+ bool is_scalar = !handle_is_ptr(maybe_type);
+ if (is_scalar)
+ return LLVMBuildICmp(g->builder, LLVMIntNE, maybe_handle, LLVMConstNull(get_llvm_type(g, maybe_type)), "");
+
+ LLVMValueRef maybe_field_ptr = LLVMBuildStructGEP(g->builder, maybe_handle, maybe_null_index, "");
+ return gen_load_untyped(g, maybe_field_ptr, 0, false, "");
}
static LLVMValueRef ir_render_test_non_null(CodeGen *g, IrExecutable *executable,
@@ -4001,8 +4065,8 @@ static LLVMValueRef ir_render_optional_unwrap_ptr(CodeGen *g, IrExecutable *exec
if (ir_want_runtime_safety(g, &instruction->base) && instruction->safety_check_on) {
LLVMValueRef maybe_handle = get_handle_value(g, maybe_ptr, maybe_type, ptr_type);
LLVMValueRef non_null_bit = gen_non_null_bit(g, maybe_type, maybe_handle);
- LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnwrapOptionalOk");
LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnwrapOptionalFail");
+ LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnwrapOptionalOk");
LLVMBuildCondBr(g->builder, non_null_bit, ok_block, fail_block);
LLVMPositionBuilderAtEnd(g->builder, fail_block);
@@ -4190,7 +4254,7 @@ static LLVMValueRef get_enum_tag_name_function(CodeGen *g, ZigType *enum_type) {
LLVMTypeRef tag_int_llvm_type = get_llvm_type(g, tag_int_type);
LLVMTypeRef fn_type_ref = LLVMFunctionType(LLVMPointerType(get_llvm_type(g, u8_slice_type), 0),
&tag_int_llvm_type, 1, false);
-
+
Buf *fn_name = get_mangled_name(g, buf_sprintf("__zig_tag_name_%s", buf_ptr(&enum_type->name)), false);
LLVMValueRef fn_val = LLVMAddFunction(g->module, buf_ptr(fn_name), fn_type_ref);
LLVMSetLinkage(fn_val, LLVMInternalLinkage);
@@ -4490,17 +4554,27 @@ static LLVMValueRef ir_render_truncate(CodeGen *g, IrExecutable *executable, IrI
static LLVMValueRef ir_render_memset(CodeGen *g, IrExecutable *executable, IrInstructionMemset *instruction) {
LLVMValueRef dest_ptr = ir_llvm_value(g, instruction->dest_ptr);
- LLVMValueRef char_val = ir_llvm_value(g, instruction->byte);
LLVMValueRef len_val = ir_llvm_value(g, instruction->count);
LLVMTypeRef ptr_u8 = LLVMPointerType(LLVMInt8Type(), 0);
-
LLVMValueRef dest_ptr_casted = LLVMBuildBitCast(g->builder, dest_ptr, ptr_u8, "");
ZigType *ptr_type = instruction->dest_ptr->value.type;
assert(ptr_type->id == ZigTypeIdPointer);
- ZigLLVMBuildMemSet(g->builder, dest_ptr_casted, char_val, len_val, get_ptr_align(g, ptr_type), ptr_type->data.pointer.is_volatile);
+ bool val_is_undef = value_is_all_undef(&instruction->byte->value);
+ LLVMValueRef fill_char;
+ if (val_is_undef) {
+ fill_char = LLVMConstInt(LLVMInt8Type(), 0xaa, false);
+ } else {
+ fill_char = ir_llvm_value(g, instruction->byte);
+ }
+ ZigLLVMBuildMemSet(g->builder, dest_ptr_casted, fill_char, len_val, get_ptr_align(g, ptr_type),
+ ptr_type->data.pointer.is_volatile);
+
+ if (val_is_undef && want_valgrind_support(g)) {
+ gen_valgrind_undef(g, dest_ptr_casted, len_val);
+ }
return nullptr;
}
@@ -5422,6 +5496,31 @@ static LLVMValueRef ir_render_assert_zero(CodeGen *g, IrExecutable *executable,
return nullptr;
}
+static LLVMValueRef ir_render_assert_non_null(CodeGen *g, IrExecutable *executable,
+ IrInstructionAssertNonNull *instruction)
+{
+ LLVMValueRef target = ir_llvm_value(g, instruction->target);
+ ZigType *target_type = instruction->target->value.type;
+
+ if (target_type->id == ZigTypeIdPointer) {
+ assert(target_type->data.pointer.ptr_len == PtrLenC);
+ LLVMValueRef non_null_bit = LLVMBuildICmp(g->builder, LLVMIntNE, target,
+ LLVMConstNull(get_llvm_type(g, target_type)), "");
+
+ LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "AssertNonNullFail");
+ LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "AssertNonNullOk");
+ LLVMBuildCondBr(g->builder, non_null_bit, ok_block, fail_block);
+
+ LLVMPositionBuilderAtEnd(g->builder, fail_block);
+ gen_assertion(g, PanicMsgIdUnwrapOptionalFail, &instruction->base);
+
+ LLVMPositionBuilderAtEnd(g->builder, ok_block);
+ } else {
+ zig_unreachable();
+ }
+ return nullptr;
+}
+
static void set_debug_location(CodeGen *g, IrInstruction *instruction) {
AstNode *source_node = instruction->source_node;
Scope *scope = instruction->scope;
@@ -5676,6 +5775,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
return ir_render_vector_to_array(g, executable, (IrInstructionVectorToArray *)instruction);
case IrInstructionIdAssertZero:
return ir_render_assert_zero(g, executable, (IrInstructionAssertZero *)instruction);
+ case IrInstructionIdAssertNonNull:
+ return ir_render_assert_non_null(g, executable, (IrInstructionAssertNonNull *)instruction);
case IrInstructionIdResizeSlice:
return ir_render_resize_slice(g, executable, (IrInstructionResizeSlice *)instruction);
}
@@ -6585,7 +6686,7 @@ static void validate_inline_fns(CodeGen *g) {
}
static void set_global_tls(CodeGen *g, ZigVar *var, LLVMValueRef global_value) {
- if (var->is_thread_local && !g->is_single_threaded) {
+ if (var->is_thread_local && (!g->is_single_threaded || var->linkage != VarLinkageInternal)) {
LLVMSetThreadLocalMode(global_value, LLVMGeneralDynamicTLSModel);
}
}
@@ -6905,7 +7006,7 @@ static void do_code_gen(CodeGen *g) {
ir_render(g, fn_table_entry);
}
-
+
assert(!g->errors.length);
if (buf_len(&g->global_asm) != 0) {
@@ -6942,6 +7043,11 @@ static void zig_llvm_emit_output(CodeGen *g) {
}
validate_inline_fns(g);
g->link_objects.append(output_path);
+ if (g->bundle_compiler_rt && (g->out_type == OutTypeObj ||
+ (g->out_type == OutTypeLib && !g->is_dynamic)))
+ {
+ zig_link_add_compiler_rt(g);
+ }
break;
case EmitFileTypeAssembly:
@@ -7337,9 +7443,26 @@ static bool detect_pic(CodeGen *g) {
zig_unreachable();
}
+static bool detect_single_threaded(CodeGen *g) {
+ if (g->want_single_threaded)
+ return true;
+ if (target_is_single_threaded(g->zig_target)) {
+ return true;
+ }
+ return false;
+}
+
+static bool detect_err_ret_tracing(CodeGen *g) {
+ return !target_is_wasm(g->zig_target) &&
+ g->build_mode != BuildModeFastRelease &&
+ g->build_mode != BuildModeSmallRelease;
+}
+
Buf *codegen_generate_builtin_source(CodeGen *g) {
g->have_dynamic_link = detect_dynamic_link(g);
g->have_pic = detect_pic(g);
+ g->is_single_threaded = detect_single_threaded(g);
+ g->have_err_ret_tracing = detect_err_ret_tracing(g);
Buf *contents = buf_alloc();
@@ -7696,7 +7819,7 @@ Buf *codegen_generate_builtin_source(CodeGen *g) {
assert(ContainerLayoutAuto == 0);
assert(ContainerLayoutExtern == 1);
assert(ContainerLayoutPacked == 2);
-
+
assert(CallingConventionUnspecified == 0);
assert(CallingConventionC == 1);
assert(CallingConventionCold == 2);
@@ -7814,7 +7937,7 @@ static Error define_builtin_compile_vars(CodeGen *g) {
Buf *contents;
if (hit) {
contents = buf_alloc();
- if ((err = os_fetch_file_path(builtin_zig_path, contents, false))) {
+ if ((err = os_fetch_file_path(builtin_zig_path, contents))) {
fprintf(stderr, "Unable to open '%s': %s\n", buf_ptr(builtin_zig_path), err_str(err));
exit(1);
}
@@ -7844,6 +7967,12 @@ static void init(CodeGen *g) {
g->have_dynamic_link = detect_dynamic_link(g);
g->have_pic = detect_pic(g);
+ g->is_single_threaded = detect_single_threaded(g);
+ g->have_err_ret_tracing = detect_err_ret_tracing(g);
+
+ if (target_is_single_threaded(g->zig_target)) {
+ g->is_single_threaded = true;
+ }
if (g->is_test_build) {
g->subsystem = TargetSubsystemConsole;
@@ -7953,8 +8082,6 @@ static void init(CodeGen *g) {
}
}
- g->have_err_ret_tracing = g->build_mode != BuildModeFastRelease && g->build_mode != BuildModeSmallRelease;
-
define_builtin_fns(g);
Error err;
if ((err = define_builtin_compile_vars(g))) {
@@ -8093,7 +8220,126 @@ static void detect_libc(CodeGen *g) {
}
}
-AstNode *codegen_translate_c(CodeGen *g, Buf *full_path) {
+// does not add the "cc" arg
+void add_cc_args(CodeGen *g, ZigList<const char *> &args, const char *out_dep_path, bool translate_c) {
+ if (translate_c) {
+ args.append("-x");
+ args.append("c");
+ }
+
+ if (out_dep_path != nullptr) {
+ args.append("-MD");
+ args.append("-MV");
+ args.append("-MF");
+ args.append(out_dep_path);
+ }
+
+ args.append("-nostdinc");
+ args.append("-fno-spell-checking");
+
+ if (translate_c) {
+ // this gives us access to preprocessing entities, presumably at
+ // the cost of performance
+ args.append("-Xclang");
+ args.append("-detailed-preprocessing-record");
+ } else {
+ switch (g->err_color) {
+ case ErrColorAuto:
+ break;
+ case ErrColorOff:
+ args.append("-fno-color-diagnostics");
+ args.append("-fno-caret-diagnostics");
+ break;
+ case ErrColorOn:
+ args.append("-fcolor-diagnostics");
+ args.append("-fcaret-diagnostics");
+ break;
+ }
+ }
+
+ args.append("-isystem");
+ args.append(buf_ptr(g->zig_c_headers_dir));
+
+ for (size_t i = 0; i < g->libc_include_dir_len; i += 1) {
+ Buf *include_dir = g->libc_include_dir_list[i];
+ args.append("-isystem");
+ args.append(buf_ptr(include_dir));
+ }
+
+ if (g->zig_target->is_native) {
+ args.append("-march=native");
+ } else {
+ args.append("-target");
+ args.append(buf_ptr(&g->triple_str));
+ }
+ if (g->zig_target->os == OsFreestanding) {
+ args.append("-ffreestanding");
+ }
+
+ if (!g->strip_debug_symbols) {
+ args.append("-g");
+ }
+
+ switch (g->build_mode) {
+ case BuildModeDebug:
+ // windows c runtime requires -D_DEBUG if using debug libraries
+ args.append("-D_DEBUG");
+
+ if (g->libc_link_lib != nullptr) {
+ args.append("-fstack-protector-strong");
+ args.append("--param");
+ args.append("ssp-buffer-size=4");
+ } else {
+ args.append("-fno-stack-protector");
+ }
+ args.append("-fno-omit-frame-pointer");
+ break;
+ case BuildModeSafeRelease:
+ // See the comment in the BuildModeFastRelease case for why we pass -O2 rather
+ // than -O3 here.
+ args.append("-O2");
+ if (g->libc_link_lib != nullptr) {
+ args.append("-D_FORTIFY_SOURCE=2");
+ args.append("-fstack-protector-strong");
+ args.append("--param");
+ args.append("ssp-buffer-size=4");
+ } else {
+ args.append("-fno-stack-protector");
+ }
+ args.append("-fomit-frame-pointer");
+ break;
+ case BuildModeFastRelease:
+ args.append("-DNDEBUG");
+ // Here we pass -O2 rather than -O3 because, although we do the equivalent of
+ // -O3 in Zig code, the justification for the difference here is that Zig
+ // has better detection and prevention of undefined behavior, so -O3 is safer for
+ // Zig code than it is for C code. Also, C programmers are used to their code
+ // running in -O2 and thus the -O3 path has been tested less.
+ args.append("-O2");
+ args.append("-fno-stack-protector");
+ args.append("-fomit-frame-pointer");
+ break;
+ case BuildModeSmallRelease:
+ args.append("-DNDEBUG");
+ args.append("-Os");
+ args.append("-fno-stack-protector");
+ args.append("-fomit-frame-pointer");
+ break;
+ }
+
+ if (target_supports_fpic(g->zig_target) && g->have_pic) {
+ args.append("-fPIC");
+ }
+
+ for (size_t arg_i = 0; arg_i < g->clang_argv_len; arg_i += 1) {
+ args.append(g->clang_argv[arg_i]);
+ }
+
+
+}
+
+void codegen_translate_c(CodeGen *g, Buf *full_path, FILE *out_file, bool use_userland_implementation) {
+ Error err;
Buf *src_basename = buf_alloc();
Buf *src_dirname = buf_alloc();
os_path_split(full_path, src_dirname, src_basename);
@@ -8105,13 +8351,47 @@ AstNode *codegen_translate_c(CodeGen *g, Buf *full_path) {
init(g);
- ZigList<ErrorMsg *> errors = {0};
+ Stage2TranslateMode trans_mode = buf_ends_with_str(full_path, ".h") ?
+ Stage2TranslateModeImport : Stage2TranslateModeTranslate;
+
+
+ ZigList<const char *> clang_argv = {0};
+ add_cc_args(g, clang_argv, nullptr, true);
+
+ clang_argv.append(buf_ptr(full_path));
+
+ if (g->verbose_cc) {
+ fprintf(stderr, "clang");
+ for (size_t i = 0; i < clang_argv.length; i += 1) {
+ fprintf(stderr, " %s", clang_argv.at(i));
+ }
+ fprintf(stderr, "\n");
+ }
+
+ clang_argv.append(nullptr); // to make the [start...end] argument work
+
+ const char *resources_path = buf_ptr(g->zig_c_headers_dir);
+ Stage2ErrorMsg *errors_ptr;
+ size_t errors_len;
+ Stage2Ast *ast;
AstNode *root_node;
- Error err = parse_h_file(&root_node, &errors, buf_ptr(full_path), g, nullptr);
- if (err == ErrorCCompileErrors && errors.length > 0) {
- for (size_t i = 0; i < errors.length; i += 1) {
- ErrorMsg *err_msg = errors.at(i);
+ if (use_userland_implementation) {
+ err = stage2_translate_c(&ast, &errors_ptr, &errors_len,
+ &clang_argv.at(0), &clang_argv.last(), trans_mode, resources_path);
+ } else {
+ err = parse_h_file(g, &root_node, &errors_ptr, &errors_len, &clang_argv.at(0), &clang_argv.last(),
+ trans_mode, resources_path);
+ }
+
+ if (err == ErrorCCompileErrors && errors_len > 0) {
+ for (size_t i = 0; i < errors_len; i += 1) {
+ Stage2ErrorMsg *clang_err = &errors_ptr[i];
+ ErrorMsg *err_msg = err_msg_create_with_offset(
+ clang_err->filename_ptr ?
+ buf_create_from_mem(clang_err->filename_ptr, clang_err->filename_len) : buf_alloc(),
+ clang_err->line, clang_err->column, clang_err->offset, clang_err->source,
+ buf_create_from_mem(clang_err->msg_ptr, clang_err->msg_len));
print_err_msg(err_msg, g->err_color);
}
exit(1);
@@ -8122,7 +8402,12 @@ AstNode *codegen_translate_c(CodeGen *g, Buf *full_path) {
exit(1);
}
- return root_node;
+
+ if (use_userland_implementation) {
+ stage2_render_ast(ast, out_file);
+ } else {
+ ast_render(out_file, root_node, 4);
+ }
}
static ZigType *add_special_code(CodeGen *g, ZigPackage *package, const char *basename) {
@@ -8233,7 +8518,7 @@ static void gen_root_source(CodeGen *g) {
Error 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))) {
+ if ((err = os_fetch_file_path(resolved_path, source_code))) {
fprintf(stderr, "unable to open '%s': %s\n", buf_ptr(resolved_path), err_str(err));
exit(1);
}
@@ -8308,7 +8593,7 @@ static void gen_global_asm(CodeGen *g) {
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))) {
+ if ((err = os_fetch_file_path(asm_file, &contents))) {
zig_panic("Unable to read %s: %s", buf_ptr(asm_file), err_str(err));
}
buf_append_buf(&g->global_asm, &contents);
@@ -8441,90 +8726,7 @@ static void gen_c_object(CodeGen *g, Buf *self_exe_path, CFile *c_file) {
args.append("cc");
Buf *out_dep_path = buf_sprintf("%s.d", buf_ptr(out_obj_path));
- args.append("-MD");
- args.append("-MV");
- args.append("-MF");
- args.append(buf_ptr(out_dep_path));
-
- args.append("-nostdinc");
- args.append("-fno-spell-checking");
-
- switch (g->err_color) {
- case ErrColorAuto:
- break;
- case ErrColorOff:
- args.append("-fno-color-diagnostics");
- args.append("-fno-caret-diagnostics");
- break;
- case ErrColorOn:
- args.append("-fcolor-diagnostics");
- args.append("-fcaret-diagnostics");
- break;
- }
-
- args.append("-isystem");
- args.append(buf_ptr(g->zig_c_headers_dir));
-
- for (size_t i = 0; i < g->libc_include_dir_len; i += 1) {
- Buf *include_dir = g->libc_include_dir_list[i];
- args.append("-isystem");
- args.append(buf_ptr(include_dir));
- }
-
- if (g->zig_target->is_native) {
- args.append("-march=native");
- } else {
- args.append("-target");
- args.append(buf_ptr(&g->triple_str));
- }
-
- if (!g->strip_debug_symbols) {
- args.append("-g");
- }
-
- switch (g->build_mode) {
- case BuildModeDebug:
- if (g->libc_link_lib != nullptr) {
- args.append("-fstack-protector-strong");
- args.append("--param");
- args.append("ssp-buffer-size=4");
- } else {
- args.append("-fno-stack-protector");
- }
- args.append("-fno-omit-frame-pointer");
- break;
- case BuildModeSafeRelease:
- // See the comment in the BuildModeFastRelease case for why we pass -O2 rather
- // than -O3 here.
- args.append("-O2");
- if (g->libc_link_lib != nullptr) {
- args.append("-D_FORTIFY_SOURCE=2");
- args.append("-fstack-protector-strong");
- args.append("--param");
- args.append("ssp-buffer-size=4");
- } else {
- args.append("-fno-stack-protector");
- }
- args.append("-fomit-frame-pointer");
- break;
- case BuildModeFastRelease:
- args.append("-DNDEBUG");
- // Here we pass -O2 rather than -O3 because, although we do the equivalent of
- // -O3 in Zig code, the justification for the difference here is that Zig
- // has better detection and prevention of undefined behavior, so -O3 is safer for
- // Zig code than it is for C code. Also, C programmers are used to their code
- // running in -O2 and thus the -O3 path has been tested less.
- args.append("-O2");
- args.append("-fno-stack-protector");
- args.append("-fomit-frame-pointer");
- break;
- case BuildModeSmallRelease:
- args.append("-DNDEBUG");
- args.append("-Os");
- args.append("-fno-stack-protector");
- args.append("-fomit-frame-pointer");
- break;
- }
+ add_cc_args(g, args, buf_ptr(out_dep_path), false);
args.append("-o");
args.append(buf_ptr(out_obj_path));
@@ -8532,19 +8734,10 @@ static void gen_c_object(CodeGen *g, Buf *self_exe_path, CFile *c_file) {
args.append("-c");
args.append(buf_ptr(c_source_file));
- if (target_supports_fpic(g->zig_target) && g->have_pic) {
- args.append("-fPIC");
- }
-
- for (size_t arg_i = 0; arg_i < g->clang_argv_len; arg_i += 1) {
- args.append(g->clang_argv[arg_i]);
- }
-
for (size_t arg_i = 0; arg_i < c_file->args.length; arg_i += 1) {
args.append(c_file->args.at(arg_i));
}
-
if (g->verbose_cc) {
print_zig_cc_cmd("zig", &args);
}
@@ -9158,6 +9351,8 @@ static Error check_cache(CodeGen *g, Buf *manifest_dir, Buf *digest) {
cache_bool(ch, g->linker_rdynamic);
cache_bool(ch, g->each_lib_rpath);
cache_bool(ch, g->disable_gen_h);
+ cache_bool(ch, g->bundle_compiler_rt);
+ cache_bool(ch, g->disable_stack_probing);
cache_bool(ch, want_valgrind_support(g));
cache_bool(ch, g->have_pic);
cache_bool(ch, g->have_dynamic_link);
@@ -9268,6 +9463,8 @@ void codegen_build_and_link(CodeGen *g) {
g->have_dynamic_link = detect_dynamic_link(g);
g->have_pic = detect_pic(g);
+ g->is_single_threaded = detect_single_threaded(g);
+ g->have_err_ret_tracing = detect_err_ret_tracing(g);
detect_libc(g);
detect_dynamic_linker(g);