Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: ziglang/zig
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 2ea08561cf69
Choose a base ref
...
head repository: ziglang/zig
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 02713e8d8aa9
Choose a head ref
  • 2 commits
  • 12 files changed
  • 1 contributor

Commits on Jul 25, 2018

  1. Copy the full SHA
    adefd1a View commit details
  2. fix race conditions in self-hosted compiler; add test

     * fix race condition in std.event.Channel deinit
     * add support to zig build for --no-rosegment
     * add passing self-hosted compare-output test for calling a function
     * put a global lock on LLD linking because it's not thread safe
    andrewrk committed Jul 25, 2018
    Copy the full SHA
    02713e8 View commit details
Showing with 664 additions and 207 deletions.
  1. +4 −0 build.zig
  2. +157 −3 src-self-hosted/codegen.zig
  3. +38 −37 src-self-hosted/compilation.zig
  4. +176 −21 src-self-hosted/ir.zig
  5. +23 −10 src-self-hosted/link.zig
  6. +14 −1 src-self-hosted/llvm.zig
  7. +128 −73 src-self-hosted/scope.zig
  8. +68 −37 src-self-hosted/type.zig
  9. +19 −3 src-self-hosted/value.zig
  10. +21 −0 std/build.zig
  11. +3 −22 std/event/channel.zig
  12. +13 −0 test/stage2/compare_output.zig
4 changes: 4 additions & 0 deletions build.zig
Original file line number Diff line number Diff line change
@@ -45,6 +45,7 @@ pub fn build(b: *Builder) !void {
.c_header_files = nextValue(&index, build_info),
.dia_guids_lib = nextValue(&index, build_info),
.llvm = undefined,
.no_rosegment = b.option(bool, "no-rosegment", "Workaround to enable valgrind builds") orelse false,
};
ctx.llvm = try findLLVM(b, ctx.llvm_config_exe);

@@ -228,6 +229,8 @@ fn configureStage2(b: *Builder, exe: var, ctx: Context) !void {
// TODO turn this into -Dextra-lib-path=/lib option
exe.addLibPath("/lib");

exe.setNoRoSegment(ctx.no_rosegment);

exe.addIncludeDir("src");
exe.addIncludeDir(ctx.cmake_binary_dir);
addCppLib(b, exe, ctx.cmake_binary_dir, "zig_cpp");
@@ -286,4 +289,5 @@ const Context = struct {
c_header_files: []const u8,
dia_guids_lib: []const u8,
llvm: LibraryDep,
no_rosegment: bool,
};
160 changes: 157 additions & 3 deletions src-self-hosted/codegen.zig
Original file line number Diff line number Diff line change
@@ -6,6 +6,7 @@ const c = @import("c.zig");
const ir = @import("ir.zig");
const Value = @import("value.zig").Value;
const Type = @import("type.zig").Type;
const Scope = @import("scope.zig").Scope;
const event = std.event;
const assert = std.debug.assert;
const DW = std.dwarf;
@@ -156,7 +157,7 @@ pub fn renderToLlvmModule(ofile: *ObjectFile, fn_val: *Value.Fn, code: *ir.Code)
llvm_fn_type,
) orelse return error.OutOfMemory;

const want_fn_safety = fn_val.block_scope.safety.get(ofile.comp);
const want_fn_safety = fn_val.block_scope.?.safety.get(ofile.comp);
if (want_fn_safety and ofile.comp.haveLibC()) {
try addLLVMFnAttr(ofile, llvm_fn, "sspstrong");
try addLLVMFnAttrStr(ofile, llvm_fn, "stack-protector-buffer-size", "4");
@@ -227,9 +228,86 @@ pub fn renderToLlvmModule(ofile: *ObjectFile, fn_val: *Value.Fn, code: *ir.Code)

// TODO set up error return tracing
// TODO allocate temporary stack values
// TODO create debug variable declarations for variables and allocate all local variables

const var_list = fn_type.non_key.Normal.variable_list.toSliceConst();
// create debug variable declarations for variables and allocate all local variables
for (var_list) |var_scope, i| {
const var_type = switch (var_scope.data) {
Scope.Var.Data.Const => unreachable,
Scope.Var.Data.Param => |param| param.typ,
};
// if (!type_has_bits(var->value->type)) {
// continue;
// }
// if (ir_get_var_is_comptime(var))
// continue;
// if (type_requires_comptime(var->value->type))
// continue;
// if (var->src_arg_index == SIZE_MAX) {
// var->value_ref = build_alloca(g, var->value->type, buf_ptr(&var->name), var->align_bytes);

// var->di_loc_var = ZigLLVMCreateAutoVariable(g->dbuilder, get_di_scope(g, var->parent_scope),
// buf_ptr(&var->name), import->di_file, (unsigned)(var->decl_node->line + 1),
// var->value->type->di_type, !g->strip_debug_symbols, 0);

// } else {
// it's a parameter
// assert(var->gen_arg_index != SIZE_MAX);
// TypeTableEntry *gen_type;
// FnGenParamInfo *gen_info = &fn_table_entry->type_entry->data.fn.gen_param_info[var->src_arg_index];

if (var_type.handleIsPtr()) {
// if (gen_info->is_byval) {
// gen_type = var->value->type;
// } else {
// gen_type = gen_info->type;
// }
var_scope.data.Param.llvm_value = llvm.GetParam(llvm_fn, @intCast(c_uint, i));
} else {
// gen_type = var->value->type;
var_scope.data.Param.llvm_value = try renderAlloca(ofile, var_type, var_scope.name, Type.Pointer.Align.Abi);
}
// if (var->decl_node) {
// var->di_loc_var = ZigLLVMCreateParameterVariable(g->dbuilder, get_di_scope(g, var->parent_scope),
// buf_ptr(&var->name), import->di_file,
// (unsigned)(var->decl_node->line + 1),
// gen_type->di_type, !g->strip_debug_symbols, 0, (unsigned)(var->gen_arg_index + 1));
// }

// }
}

// TODO finishing error return trace setup. we have to do this after all the allocas.
// TODO create debug variable declarations for parameters

// create debug variable declarations for parameters
// rely on the first variables in the variable_list being parameters.
//size_t next_var_i = 0;
for (fn_type.key.data.Normal.params) |param, i| {
//FnGenParamInfo *info = &fn_table_entry->type_entry->data.fn.gen_param_info[param_i];
//if (info->gen_index == SIZE_MAX)
// continue;
const scope_var = var_list[i];
//assert(variable->src_arg_index != SIZE_MAX);
//next_var_i += 1;
//assert(variable);
//assert(variable->value_ref);

if (!param.typ.handleIsPtr()) {
//clear_debug_source_node(g);
const llvm_param = llvm.GetParam(llvm_fn, @intCast(c_uint, i));
_ = renderStoreUntyped(
ofile,
llvm_param,
scope_var.data.Param.llvm_value,
Type.Pointer.Align.Abi,
Type.Pointer.Vol.Non,
);
}

//if (variable->decl_node) {
// gen_var_debug_decl(g, variable);
//}
}

for (code.basic_block_list.toSlice()) |current_block| {
llvm.PositionBuilderAtEnd(ofile.builder, current_block.llvm_block);
@@ -294,3 +372,79 @@ fn addLLVMFnAttrStr(ofile: *ObjectFile, fn_val: llvm.ValueRef, attr_name: []cons
fn addLLVMFnAttrInt(ofile: *ObjectFile, fn_val: llvm.ValueRef, attr_name: []const u8, attr_val: u64) !void {
return addLLVMAttrInt(ofile, fn_val, @maxValue(llvm.AttributeIndex), attr_name, attr_val);
}

fn renderLoadUntyped(
ofile: *ObjectFile,
ptr: llvm.ValueRef,
alignment: Type.Pointer.Align,
vol: Type.Pointer.Vol,
name: [*]const u8,
) !llvm.ValueRef {
const result = llvm.BuildLoad(ofile.builder, ptr, name) orelse return error.OutOfMemory;
switch (vol) {
Type.Pointer.Vol.Non => {},
Type.Pointer.Vol.Volatile => llvm.SetVolatile(result, 1),
}
llvm.SetAlignment(result, resolveAlign(ofile, alignment, llvm.GetElementType(llvm.TypeOf(ptr))));
return result;
}

fn renderLoad(ofile: *ObjectFile, ptr: llvm.ValueRef, ptr_type: *Type.Pointer, name: [*]const u8) !llvm.ValueRef {
return renderLoadUntyped(ofile, ptr, ptr_type.key.alignment, ptr_type.key.vol, name);
}

pub fn getHandleValue(ofile: *ObjectFile, ptr: llvm.ValueRef, ptr_type: *Type.Pointer) !?llvm.ValueRef {
const child_type = ptr_type.key.child_type;
if (!child_type.hasBits()) {
return null;
}
if (child_type.handleIsPtr()) {
return ptr;
}
return try renderLoad(ofile, ptr, ptr_type, c"");
}

pub fn renderStoreUntyped(
ofile: *ObjectFile,
value: llvm.ValueRef,
ptr: llvm.ValueRef,
alignment: Type.Pointer.Align,
vol: Type.Pointer.Vol,
) !llvm.ValueRef {
const result = llvm.BuildStore(ofile.builder, value, ptr) orelse return error.OutOfMemory;
switch (vol) {
Type.Pointer.Vol.Non => {},
Type.Pointer.Vol.Volatile => llvm.SetVolatile(result, 1),
}
llvm.SetAlignment(result, resolveAlign(ofile, alignment, llvm.TypeOf(value)));
return result;
}

pub fn renderStore(
ofile: *ObjectFile,
value: llvm.ValueRef,
ptr: llvm.ValueRef,
ptr_type: *Type.Pointer,
) !llvm.ValueRef {
return renderStoreUntyped(ofile, value, ptr, ptr_type.key.alignment, ptr_type.key.vol);
}

pub fn renderAlloca(
ofile: *ObjectFile,
var_type: *Type,
name: []const u8,
alignment: Type.Pointer.Align,
) !llvm.ValueRef {
const llvm_var_type = try var_type.getLlvmType(ofile.arena, ofile.context);
const name_with_null = try std.cstr.addNullByte(ofile.arena, name);
const result = llvm.BuildAlloca(ofile.builder, llvm_var_type, name_with_null.ptr) orelse return error.OutOfMemory;
llvm.SetAlignment(result, resolveAlign(ofile, alignment, llvm_var_type));
return result;
}

pub fn resolveAlign(ofile: *ObjectFile, alignment: Type.Pointer.Align, llvm_type: llvm.TypeRef) u32 {
return switch (alignment) {
Type.Pointer.Align.Abi => return llvm.ABIAlignmentOfType(ofile.comp.target_data_ref, llvm_type),
Type.Pointer.Align.Override => |a| a,
};
}
75 changes: 38 additions & 37 deletions src-self-hosted/compilation.zig
Original file line number Diff line number Diff line change
@@ -35,6 +35,7 @@ const CInt = @import("c_int.zig").CInt;
pub const EventLoopLocal = struct {
loop: *event.Loop,
llvm_handle_pool: std.atomic.Stack(llvm.ContextRef),
lld_lock: event.Lock,

/// TODO pool these so that it doesn't have to lock
prng: event.Locked(std.rand.DefaultPrng),
@@ -55,6 +56,7 @@ pub const EventLoopLocal = struct {

return EventLoopLocal{
.loop = loop,
.lld_lock = event.Lock.init(loop),
.llvm_handle_pool = std.atomic.Stack(llvm.ContextRef).init(),
.prng = event.Locked(std.rand.DefaultPrng).init(loop, std.rand.DefaultPrng.init(seed)),
.native_libc = event.Future(LibCInstallation).init(loop),
@@ -63,6 +65,7 @@ pub const EventLoopLocal = struct {

/// Must be called only after EventLoop.run completes.
fn deinit(self: *EventLoopLocal) void {
self.lld_lock.deinit();
while (self.llvm_handle_pool.pop()) |node| {
c.LLVMContextDispose(node.data);
self.loop.allocator.destroy(node);
@@ -1165,49 +1168,47 @@ async fn generateDeclFn(comp: *Compilation, fn_decl: *Decl.Fn) !void {
symbol_name_consumed = true;

// Define local parameter variables
//for (size_t i = 0; i < fn_type_id->param_count; i += 1) {
// FnTypeParamInfo *param_info = &fn_type_id->param_info[i];
// AstNode *param_decl_node = get_param_decl_node(fn_table_entry, i);
// Buf *param_name;
// bool is_var_args = param_decl_node && param_decl_node->data.param_decl.is_var_args;
// if (param_decl_node && !is_var_args) {
// param_name = param_decl_node->data.param_decl.name;
// } else {
// param_name = buf_sprintf("arg%" ZIG_PRI_usize "", i);
// }
// if (param_name == nullptr) {
// continue;
// }

// TypeTableEntry *param_type = param_info->type;
// bool is_noalias = param_info->is_noalias;

// if (is_noalias && get_codegen_ptr_type(param_type) == nullptr) {
// add_node_error(g, param_decl_node, buf_sprintf("noalias on non-pointer parameter"));
// }

// VariableTableEntry *var = add_variable(g, param_decl_node, fn_table_entry->child_scope,
// param_name, true, create_const_runtime(param_type), nullptr);
// var->src_arg_index = i;
// fn_table_entry->child_scope = var->child_scope;
// var->shadowable = var->shadowable || is_var_args;

// if (type_has_bits(param_type)) {
// fn_table_entry->variable_list.append(var);
// }

// if (fn_type->data.fn.gen_param_info) {
// var->gen_arg_index = fn_type->data.fn.gen_param_info[i].gen_index;
// }
//}
const root_scope = fn_decl.base.findRootScope();
for (fn_type.key.data.Normal.params) |param, i| {
//AstNode *param_decl_node = get_param_decl_node(fn_table_entry, i);
const param_decl = @fieldParentPtr(ast.Node.ParamDecl, "base", fn_decl.fn_proto.params.at(i).*);
const name_token = param_decl.name_token orelse {
try comp.addCompileError(root_scope, Span{
.first = param_decl.firstToken(),
.last = param_decl.type_node.firstToken(),
}, "missing parameter name");
return error.SemanticAnalysisFailed;
};
const param_name = root_scope.tree.tokenSlice(name_token);

// if (is_noalias && get_codegen_ptr_type(param_type) == nullptr) {
// add_node_error(g, param_decl_node, buf_sprintf("noalias on non-pointer parameter"));
// }

// TODO check for shadowing

const var_scope = try Scope.Var.createParam(
comp,
fn_val.child_scope,
param_name,
&param_decl.base,
i,
param.typ,
);
fn_val.child_scope = &var_scope.base;

try fn_type.non_key.Normal.variable_list.append(var_scope);
}

const analyzed_code = try await (async comp.genAndAnalyzeCode(
&fndef_scope.base,
fn_val.child_scope,
body_node,
fn_type.key.data.Normal.return_type,
) catch unreachable);
errdefer analyzed_code.destroy(comp.gpa());

assert(fn_val.block_scope != null);

// Kick off rendering to LLVM module, but it doesn't block the fn decl
// analysis from being complete.
try comp.prelink_group.call(codegen.renderToLlvm, comp, fn_val, analyzed_code);
@@ -1263,7 +1264,7 @@ async fn analyzeFnType(comp: *Compilation, scope: *Scope, fn_proto: *ast.Node.Fn
const key = Type.Fn.Key{
.alignment = null,
.data = Type.Fn.Key.Data{
.Normal = Type.Fn.Normal{
.Normal = Type.Fn.Key.Normal{
.return_type = return_type,
.params = params.toOwnedSlice(),
.is_var_args = false, // TODO
Loading