Skip to content

Commit 278829f

Browse files
committedJul 14, 2018
self-hosted: adding a fn to an llvm module
·
0.15.10.3.0
1 parent 91636f1 commit 278829f

File tree

10 files changed

+346
-63
lines changed

10 files changed

+346
-63
lines changed
 

‎src-self-hosted/codegen.zig‎

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
const std = @import("std");
2+
// TODO codegen pretends that Module is renamed to Build because I plan to
3+
// do that refactor at some point
4+
const Build = @import("module.zig").Module;
5+
// we go through llvm instead of c for 2 reasons:
6+
// 1. to avoid accidentally calling the non-thread-safe functions
7+
// 2. patch up some of the types to remove nullability
8+
const llvm = @import("llvm.zig");
9+
const ir = @import("ir.zig");
10+
const Value = @import("value.zig").Value;
11+
const Type = @import("type.zig").Type;
12+
const event = std.event;
13+
14+
pub async fn renderToLlvm(build: *Build, fn_val: *Value.Fn, code: *ir.Code) !void {
15+
fn_val.base.ref();
16+
defer fn_val.base.deref(build);
17+
defer code.destroy(build.a());
18+
19+
const llvm_handle = try build.event_loop_local.getAnyLlvmContext();
20+
defer llvm_handle.release(build.event_loop_local);
21+
22+
const context = llvm_handle.node.data;
23+
24+
const module = llvm.ModuleCreateWithNameInContext(build.name.ptr(), context) orelse return error.OutOfMemory;
25+
defer llvm.DisposeModule(module);
26+
27+
const builder = llvm.CreateBuilderInContext(context) orelse return error.OutOfMemory;
28+
defer llvm.DisposeBuilder(builder);
29+
30+
var cunit = CompilationUnit{
31+
.build = build,
32+
.module = module,
33+
.builder = builder,
34+
.context = context,
35+
.lock = event.Lock.init(build.loop),
36+
};
37+
38+
try renderToLlvmModule(&cunit, fn_val, code);
39+
40+
if (build.verbose_llvm_ir) {
41+
llvm.DumpModule(cunit.module);
42+
}
43+
}
44+
45+
pub const CompilationUnit = struct {
46+
build: *Build,
47+
module: llvm.ModuleRef,
48+
builder: llvm.BuilderRef,
49+
context: llvm.ContextRef,
50+
lock: event.Lock,
51+
52+
fn a(self: *CompilationUnit) *std.mem.Allocator {
53+
return self.build.a();
54+
}
55+
};
56+
57+
pub fn renderToLlvmModule(cunit: *CompilationUnit, fn_val: *Value.Fn, code: *ir.Code) !void {
58+
// TODO audit more of codegen.cpp:fn_llvm_value and port more logic
59+
const llvm_fn_type = try fn_val.base.typeof.getLlvmType(cunit);
60+
const llvm_fn = llvm.AddFunction(cunit.module, fn_val.symbol_name.ptr(), llvm_fn_type);
61+
}

‎src-self-hosted/ir.zig‎

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -375,15 +375,8 @@ pub const Instruction = struct {
375375

376376
pub fn analyze(self: *const AddImplicitReturnType, ira: *Analyze) !*Instruction {
377377
const target = try self.params.target.getAsParam();
378-
379378
try ira.src_implicit_return_type_list.append(target);
380-
381-
return ira.irb.build(
382-
AddImplicitReturnType,
383-
self.base.scope,
384-
self.base.span,
385-
Params{ .target = target },
386-
);
379+
return ira.irb.buildConstVoid(self.base.scope, self.base.span, true);
387380
}
388381
};
389382
};

‎src-self-hosted/llvm.zig‎

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,27 @@ const builtin = @import("builtin");
22
const c = @import("c.zig");
33
const assert = @import("std").debug.assert;
44

5-
pub const ValueRef = removeNullability(c.LLVMValueRef);
6-
pub const ModuleRef = removeNullability(c.LLVMModuleRef);
7-
pub const ContextRef = removeNullability(c.LLVMContextRef);
85
pub const BuilderRef = removeNullability(c.LLVMBuilderRef);
6+
pub const ContextRef = removeNullability(c.LLVMContextRef);
7+
pub const ModuleRef = removeNullability(c.LLVMModuleRef);
8+
pub const ValueRef = removeNullability(c.LLVMValueRef);
9+
pub const TypeRef = removeNullability(c.LLVMTypeRef);
10+
11+
pub const AddFunction = c.LLVMAddFunction;
12+
pub const CreateBuilderInContext = c.LLVMCreateBuilderInContext;
13+
pub const DisposeBuilder = c.LLVMDisposeBuilder;
14+
pub const DisposeModule = c.LLVMDisposeModule;
15+
pub const DumpModule = c.LLVMDumpModule;
16+
pub const ModuleCreateWithNameInContext = c.LLVMModuleCreateWithNameInContext;
17+
pub const VoidTypeInContext = c.LLVMVoidTypeInContext;
18+
19+
pub const FunctionType = LLVMFunctionType;
20+
extern fn LLVMFunctionType(
21+
ReturnType: TypeRef,
22+
ParamTypes: [*]TypeRef,
23+
ParamCount: c_uint,
24+
IsVarArg: c_int,
25+
) ?TypeRef;
926

1027
fn removeNullability(comptime T: type) type {
1128
comptime assert(@typeId(T) == builtin.TypeId.Optional);

‎src-self-hosted/main.zig‎

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ const c = @import("c.zig");
1414
const introspect = @import("introspect.zig");
1515
const Args = arg.Args;
1616
const Flag = arg.Flag;
17+
const EventLoopLocal = @import("module.zig").EventLoopLocal;
1718
const Module = @import("module.zig").Module;
1819
const Target = @import("target.zig").Target;
1920
const errmsg = @import("errmsg.zig");
@@ -386,9 +387,13 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Mo
386387

387388
var loop: event.Loop = undefined;
388389
try loop.initMultiThreaded(allocator);
390+
defer loop.deinit();
391+
392+
var event_loop_local = EventLoopLocal.init(&loop);
393+
defer event_loop_local.deinit();
389394

390395
var module = try Module.create(
391-
&loop,
396+
&event_loop_local,
392397
root_name,
393398
root_source_file,
394399
Target.Native,

‎src-self-hosted/module.zig‎

Lines changed: 77 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -25,14 +25,58 @@ const ParsedFile = @import("parsed_file.zig").ParsedFile;
2525
const Value = @import("value.zig").Value;
2626
const Type = Value.Type;
2727
const Span = errmsg.Span;
28+
const codegen = @import("codegen.zig");
29+
30+
/// Data that is local to the event loop.
31+
pub const EventLoopLocal = struct {
32+
loop: *event.Loop,
33+
llvm_handle_pool: std.atomic.Stack(llvm.ContextRef),
34+
35+
fn init(loop: *event.Loop) EventLoopLocal {
36+
return EventLoopLocal{
37+
.loop = loop,
38+
.llvm_handle_pool = std.atomic.Stack(llvm.ContextRef).init(),
39+
};
40+
}
41+
42+
fn deinit(self: *EventLoopLocal) void {
43+
while (self.llvm_handle_pool.pop()) |node| {
44+
c.LLVMContextDispose(node.data);
45+
self.loop.allocator.destroy(node);
46+
}
47+
}
48+
49+
/// Gets an exclusive handle on any LlvmContext.
50+
/// Caller must release the handle when done.
51+
pub fn getAnyLlvmContext(self: *EventLoopLocal) !LlvmHandle {
52+
if (self.llvm_handle_pool.pop()) |node| return LlvmHandle{ .node = node };
53+
54+
const context_ref = c.LLVMContextCreate() orelse return error.OutOfMemory;
55+
errdefer c.LLVMContextDispose(context_ref);
56+
57+
const node = try self.loop.allocator.create(std.atomic.Stack(llvm.ContextRef).Node{
58+
.next = undefined,
59+
.data = context_ref,
60+
});
61+
errdefer self.loop.allocator.destroy(node);
62+
63+
return LlvmHandle{ .node = node };
64+
}
65+
};
66+
67+
pub const LlvmHandle = struct {
68+
node: *std.atomic.Stack(llvm.ContextRef).Node,
69+
70+
pub fn release(self: LlvmHandle, event_loop_local: *EventLoopLocal) void {
71+
event_loop_local.llvm_handle_pool.push(self.node);
72+
}
73+
};
2874

2975
pub const Module = struct {
76+
event_loop_local: *EventLoopLocal,
3077
loop: *event.Loop,
3178
name: Buffer,
3279
root_src_path: ?[]const u8,
33-
llvm_module: llvm.ModuleRef,
34-
context: llvm.ContextRef,
35-
builder: llvm.BuilderRef,
3680
target: Target,
3781
build_mode: builtin.Mode,
3882
zig_lib_dir: []const u8,
@@ -187,7 +231,7 @@ pub const Module = struct {
187231
};
188232

189233
pub fn create(
190-
loop: *event.Loop,
234+
event_loop_local: *EventLoopLocal,
191235
name: []const u8,
192236
root_src_path: ?[]const u8,
193237
target: *const Target,
@@ -196,29 +240,20 @@ pub const Module = struct {
196240
zig_lib_dir: []const u8,
197241
cache_dir: []const u8,
198242
) !*Module {
243+
const loop = event_loop_local.loop;
244+
199245
var name_buffer = try Buffer.init(loop.allocator, name);
200246
errdefer name_buffer.deinit();
201247

202-
const context = c.LLVMContextCreate() orelse return error.OutOfMemory;
203-
errdefer c.LLVMContextDispose(context);
204-
205-
const llvm_module = c.LLVMModuleCreateWithNameInContext(name_buffer.ptr(), context) orelse return error.OutOfMemory;
206-
errdefer c.LLVMDisposeModule(llvm_module);
207-
208-
const builder = c.LLVMCreateBuilderInContext(context) orelse return error.OutOfMemory;
209-
errdefer c.LLVMDisposeBuilder(builder);
210-
211248
const events = try event.Channel(Event).create(loop, 0);
212249
errdefer events.destroy();
213250

214251
const module = try loop.allocator.create(Module{
215252
.loop = loop,
253+
.event_loop_local = event_loop_local,
216254
.events = events,
217255
.name = name_buffer,
218256
.root_src_path = root_src_path,
219-
.llvm_module = llvm_module,
220-
.context = context,
221-
.builder = builder,
222257
.target = target.*,
223258
.kind = kind,
224259
.build_mode = build_mode,
@@ -290,7 +325,7 @@ pub const Module = struct {
290325
.base = Value{
291326
.id = Value.Id.Type,
292327
.typeof = undefined,
293-
.ref_count = 3, // 3 because it references itself twice
328+
.ref_count = std.atomic.Int(usize).init(3), // 3 because it references itself twice
294329
},
295330
.id = builtin.TypeId.Type,
296331
},
@@ -305,7 +340,7 @@ pub const Module = struct {
305340
.base = Value{
306341
.id = Value.Id.Type,
307342
.typeof = &Type.MetaType.get(module).base,
308-
.ref_count = 1,
343+
.ref_count = std.atomic.Int(usize).init(1),
309344
},
310345
.id = builtin.TypeId.Void,
311346
},
@@ -317,7 +352,7 @@ pub const Module = struct {
317352
.base = Value{
318353
.id = Value.Id.Type,
319354
.typeof = &Type.MetaType.get(module).base,
320-
.ref_count = 1,
355+
.ref_count = std.atomic.Int(usize).init(1),
321356
},
322357
.id = builtin.TypeId.NoReturn,
323358
},
@@ -329,7 +364,7 @@ pub const Module = struct {
329364
.base = Value{
330365
.id = Value.Id.Type,
331366
.typeof = &Type.MetaType.get(module).base,
332-
.ref_count = 1,
367+
.ref_count = std.atomic.Int(usize).init(1),
333368
},
334369
.id = builtin.TypeId.Bool,
335370
},
@@ -340,7 +375,7 @@ pub const Module = struct {
340375
.base = Value{
341376
.id = Value.Id.Void,
342377
.typeof = &Type.Void.get(module).base,
343-
.ref_count = 1,
378+
.ref_count = std.atomic.Int(usize).init(1),
344379
},
345380
});
346381
errdefer module.a().destroy(module.void_value);
@@ -349,7 +384,7 @@ pub const Module = struct {
349384
.base = Value{
350385
.id = Value.Id.Bool,
351386
.typeof = &Type.Bool.get(module).base,
352-
.ref_count = 1,
387+
.ref_count = std.atomic.Int(usize).init(1),
353388
},
354389
.x = true,
355390
});
@@ -359,7 +394,7 @@ pub const Module = struct {
359394
.base = Value{
360395
.id = Value.Id.Bool,
361396
.typeof = &Type.Bool.get(module).base,
362-
.ref_count = 1,
397+
.ref_count = std.atomic.Int(usize).init(1),
363398
},
364399
.x = false,
365400
});
@@ -369,16 +404,12 @@ pub const Module = struct {
369404
.base = Value{
370405
.id = Value.Id.NoReturn,
371406
.typeof = &Type.NoReturn.get(module).base,
372-
.ref_count = 1,
407+
.ref_count = std.atomic.Int(usize).init(1),
373408
},
374409
});
375410
errdefer module.a().destroy(module.noreturn_value);
376411
}
377412

378-
fn dump(self: *Module) void {
379-
c.LLVMDumpModule(self.module);
380-
}
381-
382413
pub fn destroy(self: *Module) void {
383414
self.noreturn_value.base.deref(self);
384415
self.void_value.base.deref(self);
@@ -389,9 +420,6 @@ pub const Module = struct {
389420
self.meta_type.base.base.deref(self);
390421

391422
self.events.destroy();
392-
c.LLVMDisposeBuilder(self.builder);
393-
c.LLVMDisposeModule(self.llvm_module);
394-
c.LLVMContextDispose(self.context);
395423
self.name.deinit();
396424

397425
self.a().destroy(self);
@@ -657,10 +685,19 @@ async fn generateDeclFn(module: *Module, fn_decl: *Decl.Fn) !void {
657685
const fndef_scope = try Scope.FnDef.create(module, fn_decl.base.parent_scope);
658686
defer fndef_scope.base.deref(module);
659687

660-
const fn_type = try Type.Fn.create(module);
688+
// TODO actually look at the return type of the AST
689+
const return_type = &Type.Void.get(module).base;
690+
defer return_type.base.deref(module);
691+
692+
const is_var_args = false;
693+
const params = ([*]Type.Fn.Param)(undefined)[0..0];
694+
const fn_type = try Type.Fn.create(module, return_type, params, is_var_args);
661695
defer fn_type.base.base.deref(module);
662696

663-
const fn_val = try Value.Fn.create(module, fn_type, fndef_scope);
697+
var symbol_name = try std.Buffer.init(module.a(), fn_decl.base.name);
698+
errdefer symbol_name.deinit();
699+
700+
const fn_val = try Value.Fn.create(module, fn_type, fndef_scope, symbol_name);
664701
defer fn_val.base.deref(module);
665702

666703
fn_decl.value = Decl.Fn.Val{ .Ok = fn_val };
@@ -674,6 +711,7 @@ async fn generateDeclFn(module: *Module, fn_decl: *Decl.Fn) !void {
674711
) catch unreachable)) catch |err| switch (err) {
675712
// This poison value should not cause the errdefers to run. It simply means
676713
// that self.compile_errors is populated.
714+
// TODO https://github.com/ziglang/zig/issues/769
677715
error.SemanticAnalysisFailed => return {},
678716
else => return err,
679717
};
@@ -692,14 +730,18 @@ async fn generateDeclFn(module: *Module, fn_decl: *Decl.Fn) !void {
692730
) catch unreachable)) catch |err| switch (err) {
693731
// This poison value should not cause the errdefers to run. It simply means
694732
// that self.compile_errors is populated.
733+
// TODO https://github.com/ziglang/zig/issues/769
695734
error.SemanticAnalysisFailed => return {},
696735
else => return err,
697736
};
698-
defer analyzed_code.destroy(module.a());
737+
errdefer analyzed_code.destroy(module.a());
699738

700739
if (module.verbose_ir) {
701740
std.debug.warn("analyzed:\n");
702741
analyzed_code.dump();
703742
}
704-
// TODO now render to LLVM module
743+
744+
// Kick off rendering to LLVM module, but it doesn't block the fn decl
745+
// analysis from being complete.
746+
try module.build_group.call(codegen.renderToLlvm, module, fn_val, analyzed_code);
705747
}

‎src-self-hosted/test.zig‎

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ const Module = @import("module.zig").Module;
66
const introspect = @import("introspect.zig");
77
const assertOrPanic = std.debug.assertOrPanic;
88
const errmsg = @import("errmsg.zig");
9+
const EventLoopLocal = @import("module.zig").EventLoopLocal;
910

1011
test "compile errors" {
1112
var ctx: TestContext = undefined;
@@ -22,6 +23,7 @@ const allocator = std.heap.c_allocator;
2223

2324
pub const TestContext = struct {
2425
loop: std.event.Loop,
26+
event_loop_local: EventLoopLocal,
2527
zig_lib_dir: []u8,
2628
zig_cache_dir: []u8,
2729
file_index: std.atomic.Int(usize),
@@ -34,6 +36,7 @@ pub const TestContext = struct {
3436
self.* = TestContext{
3537
.any_err = {},
3638
.loop = undefined,
39+
.event_loop_local = undefined,
3740
.zig_lib_dir = undefined,
3841
.zig_cache_dir = undefined,
3942
.group = undefined,
@@ -43,6 +46,9 @@ pub const TestContext = struct {
4346
try self.loop.initMultiThreaded(allocator);
4447
errdefer self.loop.deinit();
4548

49+
self.event_loop_local = EventLoopLocal.init(&self.loop);
50+
errdefer self.event_loop_local.deinit();
51+
4652
self.group = std.event.Group(error!void).init(&self.loop);
4753
errdefer self.group.cancelAll();
4854

@@ -60,6 +66,7 @@ pub const TestContext = struct {
6066
std.os.deleteTree(allocator, tmp_dir_name) catch {};
6167
allocator.free(self.zig_cache_dir);
6268
allocator.free(self.zig_lib_dir);
69+
self.event_loop_local.deinit();
6370
self.loop.deinit();
6471
}
6572

@@ -83,7 +90,7 @@ pub const TestContext = struct {
8390
msg: []const u8,
8491
) !void {
8592
var file_index_buf: [20]u8 = undefined;
86-
const file_index = try std.fmt.bufPrint(file_index_buf[0..], "{}", self.file_index.next());
93+
const file_index = try std.fmt.bufPrint(file_index_buf[0..], "{}", self.file_index.incr());
8794
const file1_path = try std.os.path.join(allocator, tmp_dir_name, file_index, file1);
8895

8996
if (std.os.path.dirname(file1_path)) |dirname| {
@@ -94,7 +101,7 @@ pub const TestContext = struct {
94101
try std.io.writeFile(allocator, file1_path, source);
95102

96103
var module = try Module.create(
97-
&self.loop,
104+
&self.event_loop_local,
98105
"test",
99106
file1_path,
100107
Target.Native,

‎src-self-hosted/type.zig‎

Lines changed: 144 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
1+
const std = @import("std");
12
const builtin = @import("builtin");
23
const Scope = @import("scope.zig").Scope;
34
const Module = @import("module.zig").Module;
45
const Value = @import("value.zig").Value;
6+
const llvm = @import("llvm.zig");
7+
const CompilationUnit = @import("codegen.zig").CompilationUnit;
58

69
pub const Type = struct {
710
base: Value,
@@ -39,6 +42,36 @@ pub const Type = struct {
3942
}
4043
}
4144

45+
pub fn getLlvmType(base: *Type, cunit: *CompilationUnit) (error{OutOfMemory}!llvm.TypeRef) {
46+
switch (base.id) {
47+
Id.Struct => return @fieldParentPtr(Struct, "base", base).getLlvmType(cunit),
48+
Id.Fn => return @fieldParentPtr(Fn, "base", base).getLlvmType(cunit),
49+
Id.Type => unreachable,
50+
Id.Void => unreachable,
51+
Id.Bool => return @fieldParentPtr(Bool, "base", base).getLlvmType(cunit),
52+
Id.NoReturn => unreachable,
53+
Id.Int => return @fieldParentPtr(Int, "base", base).getLlvmType(cunit),
54+
Id.Float => return @fieldParentPtr(Float, "base", base).getLlvmType(cunit),
55+
Id.Pointer => return @fieldParentPtr(Pointer, "base", base).getLlvmType(cunit),
56+
Id.Array => return @fieldParentPtr(Array, "base", base).getLlvmType(cunit),
57+
Id.ComptimeFloat => unreachable,
58+
Id.ComptimeInt => unreachable,
59+
Id.Undefined => unreachable,
60+
Id.Null => unreachable,
61+
Id.Optional => return @fieldParentPtr(Optional, "base", base).getLlvmType(cunit),
62+
Id.ErrorUnion => return @fieldParentPtr(ErrorUnion, "base", base).getLlvmType(cunit),
63+
Id.ErrorSet => return @fieldParentPtr(ErrorSet, "base", base).getLlvmType(cunit),
64+
Id.Enum => return @fieldParentPtr(Enum, "base", base).getLlvmType(cunit),
65+
Id.Union => return @fieldParentPtr(Union, "base", base).getLlvmType(cunit),
66+
Id.Namespace => unreachable,
67+
Id.Block => unreachable,
68+
Id.BoundFn => return @fieldParentPtr(BoundFn, "base", base).getLlvmType(cunit),
69+
Id.ArgTuple => unreachable,
70+
Id.Opaque => return @fieldParentPtr(Opaque, "base", base).getLlvmType(cunit),
71+
Id.Promise => return @fieldParentPtr(Promise, "base", base).getLlvmType(cunit),
72+
}
73+
}
74+
4275
pub fn dump(base: *const Type) void {
4376
std.debug.warn("{}", @tagName(base.id));
4477
}
@@ -54,27 +87,72 @@ pub const Type = struct {
5487
pub fn destroy(self: *Struct, module: *Module) void {
5588
module.a().destroy(self);
5689
}
90+
91+
pub fn getLlvmType(self: *Struct, cunit: *CompilationUnit) llvm.TypeRef {
92+
@panic("TODO");
93+
}
5794
};
5895

5996
pub const Fn = struct {
6097
base: Type,
98+
return_type: *Type,
99+
params: []Param,
100+
is_var_args: bool,
61101

62-
pub fn create(module: *Module) !*Fn {
63-
return module.a().create(Fn{
102+
pub const Param = struct {
103+
is_noalias: bool,
104+
typeof: *Type,
105+
};
106+
107+
pub fn create(module: *Module, return_type: *Type, params: []Param, is_var_args: bool) !*Fn {
108+
const result = try module.a().create(Fn{
64109
.base = Type{
65110
.base = Value{
66111
.id = Value.Id.Type,
67112
.typeof = &MetaType.get(module).base,
68-
.ref_count = 1,
113+
.ref_count = std.atomic.Int(usize).init(1),
69114
},
70115
.id = builtin.TypeId.Fn,
71116
},
117+
.return_type = return_type,
118+
.params = params,
119+
.is_var_args = is_var_args,
72120
});
121+
errdefer module.a().destroy(result);
122+
123+
result.return_type.base.ref();
124+
for (result.params) |param| {
125+
param.typeof.base.ref();
126+
}
127+
return result;
73128
}
74129

75130
pub fn destroy(self: *Fn, module: *Module) void {
131+
self.return_type.base.deref(module);
132+
for (self.params) |param| {
133+
param.typeof.base.deref(module);
134+
}
76135
module.a().destroy(self);
77136
}
137+
138+
pub fn getLlvmType(self: *Fn, cunit: *CompilationUnit) !llvm.TypeRef {
139+
const llvm_return_type = switch (self.return_type.id) {
140+
Type.Id.Void => llvm.VoidTypeInContext(cunit.context) orelse return error.OutOfMemory,
141+
else => try self.return_type.getLlvmType(cunit),
142+
};
143+
const llvm_param_types = try cunit.a().alloc(llvm.TypeRef, self.params.len);
144+
defer cunit.a().free(llvm_param_types);
145+
for (llvm_param_types) |*llvm_param_type, i| {
146+
llvm_param_type.* = try self.params[i].typeof.getLlvmType(cunit);
147+
}
148+
149+
return llvm.FunctionType(
150+
llvm_return_type,
151+
llvm_param_types.ptr,
152+
@intCast(c_uint, llvm_param_types.len),
153+
@boolToInt(self.is_var_args),
154+
) orelse error.OutOfMemory;
155+
}
78156
};
79157

80158
pub const MetaType = struct {
@@ -118,6 +196,10 @@ pub const Type = struct {
118196
pub fn destroy(self: *Bool, module: *Module) void {
119197
module.a().destroy(self);
120198
}
199+
200+
pub fn getLlvmType(self: *Bool, cunit: *CompilationUnit) llvm.TypeRef {
201+
@panic("TODO");
202+
}
121203
};
122204

123205
pub const NoReturn = struct {
@@ -140,6 +222,10 @@ pub const Type = struct {
140222
pub fn destroy(self: *Int, module: *Module) void {
141223
module.a().destroy(self);
142224
}
225+
226+
pub fn getLlvmType(self: *Int, cunit: *CompilationUnit) llvm.TypeRef {
227+
@panic("TODO");
228+
}
143229
};
144230

145231
pub const Float = struct {
@@ -148,6 +234,10 @@ pub const Type = struct {
148234
pub fn destroy(self: *Float, module: *Module) void {
149235
module.a().destroy(self);
150236
}
237+
238+
pub fn getLlvmType(self: *Float, cunit: *CompilationUnit) llvm.TypeRef {
239+
@panic("TODO");
240+
}
151241
};
152242
pub const Pointer = struct {
153243
base: Type,
@@ -180,77 +270,116 @@ pub const Type = struct {
180270
) *Pointer {
181271
@panic("TODO get pointer");
182272
}
273+
274+
pub fn getLlvmType(self: *Pointer, cunit: *CompilationUnit) llvm.TypeRef {
275+
@panic("TODO");
276+
}
183277
};
278+
184279
pub const Array = struct {
185280
base: Type,
186281

187282
pub fn destroy(self: *Array, module: *Module) void {
188283
module.a().destroy(self);
189284
}
285+
286+
pub fn getLlvmType(self: *Array, cunit: *CompilationUnit) llvm.TypeRef {
287+
@panic("TODO");
288+
}
190289
};
290+
191291
pub const ComptimeFloat = struct {
192292
base: Type,
193293

194294
pub fn destroy(self: *ComptimeFloat, module: *Module) void {
195295
module.a().destroy(self);
196296
}
197297
};
298+
198299
pub const ComptimeInt = struct {
199300
base: Type,
200301

201302
pub fn destroy(self: *ComptimeInt, module: *Module) void {
202303
module.a().destroy(self);
203304
}
204305
};
306+
205307
pub const Undefined = struct {
206308
base: Type,
207309

208310
pub fn destroy(self: *Undefined, module: *Module) void {
209311
module.a().destroy(self);
210312
}
211313
};
314+
212315
pub const Null = struct {
213316
base: Type,
214317

215318
pub fn destroy(self: *Null, module: *Module) void {
216319
module.a().destroy(self);
217320
}
218321
};
322+
219323
pub const Optional = struct {
220324
base: Type,
221325

222326
pub fn destroy(self: *Optional, module: *Module) void {
223327
module.a().destroy(self);
224328
}
329+
330+
pub fn getLlvmType(self: *Optional, cunit: *CompilationUnit) llvm.TypeRef {
331+
@panic("TODO");
332+
}
225333
};
334+
226335
pub const ErrorUnion = struct {
227336
base: Type,
228337

229338
pub fn destroy(self: *ErrorUnion, module: *Module) void {
230339
module.a().destroy(self);
231340
}
341+
342+
pub fn getLlvmType(self: *ErrorUnion, cunit: *CompilationUnit) llvm.TypeRef {
343+
@panic("TODO");
344+
}
232345
};
346+
233347
pub const ErrorSet = struct {
234348
base: Type,
235349

236350
pub fn destroy(self: *ErrorSet, module: *Module) void {
237351
module.a().destroy(self);
238352
}
353+
354+
pub fn getLlvmType(self: *ErrorSet, cunit: *CompilationUnit) llvm.TypeRef {
355+
@panic("TODO");
356+
}
239357
};
358+
240359
pub const Enum = struct {
241360
base: Type,
242361

243362
pub fn destroy(self: *Enum, module: *Module) void {
244363
module.a().destroy(self);
245364
}
365+
366+
pub fn getLlvmType(self: *Enum, cunit: *CompilationUnit) llvm.TypeRef {
367+
@panic("TODO");
368+
}
246369
};
370+
247371
pub const Union = struct {
248372
base: Type,
249373

250374
pub fn destroy(self: *Union, module: *Module) void {
251375
module.a().destroy(self);
252376
}
377+
378+
pub fn getLlvmType(self: *Union, cunit: *CompilationUnit) llvm.TypeRef {
379+
@panic("TODO");
380+
}
253381
};
382+
254383
pub const Namespace = struct {
255384
base: Type,
256385

@@ -273,6 +402,10 @@ pub const Type = struct {
273402
pub fn destroy(self: *BoundFn, module: *Module) void {
274403
module.a().destroy(self);
275404
}
405+
406+
pub fn getLlvmType(self: *BoundFn, cunit: *CompilationUnit) llvm.TypeRef {
407+
@panic("TODO");
408+
}
276409
};
277410

278411
pub const ArgTuple = struct {
@@ -289,6 +422,10 @@ pub const Type = struct {
289422
pub fn destroy(self: *Opaque, module: *Module) void {
290423
module.a().destroy(self);
291424
}
425+
426+
pub fn getLlvmType(self: *Opaque, cunit: *CompilationUnit) llvm.TypeRef {
427+
@panic("TODO");
428+
}
292429
};
293430

294431
pub const Promise = struct {
@@ -297,5 +434,9 @@ pub const Type = struct {
297434
pub fn destroy(self: *Promise, module: *Module) void {
298435
module.a().destroy(self);
299436
}
437+
438+
pub fn getLlvmType(self: *Promise, cunit: *CompilationUnit) llvm.TypeRef {
439+
@panic("TODO");
440+
}
300441
};
301442
};

‎src-self-hosted/value.zig‎

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,16 @@ const Module = @import("module.zig").Module;
88
pub const Value = struct {
99
id: Id,
1010
typeof: *Type,
11-
ref_count: usize,
11+
ref_count: std.atomic.Int(usize),
1212

13+
/// Thread-safe
1314
pub fn ref(base: *Value) void {
14-
base.ref_count += 1;
15+
_ = base.ref_count.incr();
1516
}
1617

18+
/// Thread-safe
1719
pub fn deref(base: *Value, module: *Module) void {
18-
base.ref_count -= 1;
19-
if (base.ref_count == 0) {
20+
if (base.ref_count.decr() == 1) {
2021
base.typeof.base.deref(module);
2122
switch (base.id) {
2223
Id.Type => @fieldParentPtr(Type, "base", base).destroy(module),
@@ -52,6 +53,10 @@ pub const Value = struct {
5253
pub const Fn = struct {
5354
base: Value,
5455

56+
/// The main external name that is used in the .o file.
57+
/// TODO https://github.com/ziglang/zig/issues/265
58+
symbol_name: std.Buffer,
59+
5560
/// parent should be the top level decls or container decls
5661
fndef_scope: *Scope.FnDef,
5762

@@ -62,16 +67,18 @@ pub const Value = struct {
6267
block_scope: *Scope.Block,
6368

6469
/// Creates a Fn value with 1 ref
65-
pub fn create(module: *Module, fn_type: *Type.Fn, fndef_scope: *Scope.FnDef) !*Fn {
70+
/// Takes ownership of symbol_name
71+
pub fn create(module: *Module, fn_type: *Type.Fn, fndef_scope: *Scope.FnDef, symbol_name: std.Buffer) !*Fn {
6672
const self = try module.a().create(Fn{
6773
.base = Value{
6874
.id = Value.Id.Fn,
6975
.typeof = &fn_type.base,
70-
.ref_count = 1,
76+
.ref_count = std.atomic.Int(usize).init(1),
7177
},
7278
.fndef_scope = fndef_scope,
7379
.child_scope = &fndef_scope.base,
7480
.block_scope = undefined,
81+
.symbol_name = symbol_name,
7582
});
7683
fn_type.base.base.ref();
7784
fndef_scope.fn_val = self;
@@ -81,6 +88,7 @@ pub const Value = struct {
8188

8289
pub fn destroy(self: *Fn, module: *Module) void {
8390
self.fndef_scope.base.deref(module);
91+
self.symbol_name.deinit();
8492
module.a().destroy(self);
8593
}
8694
};

‎std/atomic/int.zig‎

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,26 @@ const AtomicOrder = builtin.AtomicOrder;
44
/// Thread-safe, lock-free integer
55
pub fn Int(comptime T: type) type {
66
return struct {
7-
value: T,
7+
unprotected_value: T,
88

99
pub const Self = this;
1010

1111
pub fn init(init_val: T) Self {
12-
return Self{ .value = init_val };
12+
return Self{ .unprotected_value = init_val };
1313
}
1414

15-
pub fn next(self: *Self) T {
16-
return @atomicRmw(T, &self.value, builtin.AtomicRmwOp.Add, 1, AtomicOrder.SeqCst);
15+
/// Returns previous value
16+
pub fn incr(self: *Self) T {
17+
return @atomicRmw(T, &self.unprotected_value, builtin.AtomicRmwOp.Add, 1, AtomicOrder.SeqCst);
18+
}
19+
20+
/// Returns previous value
21+
pub fn decr(self: *Self) T {
22+
return @atomicRmw(T, &self.unprotected_value, builtin.AtomicRmwOp.Sub, 1, AtomicOrder.SeqCst);
23+
}
24+
25+
pub fn get(self: *Self) T {
26+
return @atomicLoad(T, &self.unprotected_value, AtomicOrder.SeqCst);
1727
}
1828
};
1929
}

‎std/event/loop.zig‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,6 @@ pub const Loop = struct {
101101
errdefer self.deinitOsData();
102102
}
103103

104-
/// must call stop before deinit
105104
pub fn deinit(self: *Loop) void {
106105
self.deinitOsData();
107106
self.allocator.free(self.extra_threads);

0 commit comments

Comments
 (0)
Please sign in to comment.