authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-07-22 23:27:58-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-07-22 23:28:53-04:00
log93e78ee72259b98840f63db0ad87fdddb071e384
treeb8d0481cf68d4d87fc12be637597e591597d9fe2
parent58c5f94a99a78346286065bbf390e4c30be1b707

self-hosted can compile libc hello world


15 files changed, 1358 insertions(+), 184 deletions(-)

CMakeLists.txt+1
...@@ -624,6 +624,7 @@ set(ZIG_STD_FILES...@@ -624,6 +624,7 @@ set(ZIG_STD_FILES
624 "zig/ast.zig"624 "zig/ast.zig"
625 "zig/index.zig"625 "zig/index.zig"
626 "zig/parse.zig"626 "zig/parse.zig"
627 "zig/parse_string_literal.zig"
627 "zig/render.zig"628 "zig/render.zig"
628 "zig/tokenizer.zig"629 "zig/tokenizer.zig"
629)630)
src-self-hosted/codegen.zig+4-2
...@@ -78,6 +78,7 @@ pub async fn renderToLlvm(comp: *Compilation, fn_val: *Value.Fn, code: *ir.Code)...@@ -78,6 +78,7 @@ pub async fn renderToLlvm(comp: *Compilation, fn_val: *Value.Fn, code: *ir.Code)
78 .dibuilder = dibuilder,78 .dibuilder = dibuilder,
79 .context = context,79 .context = context,
80 .lock = event.Lock.init(comp.loop),80 .lock = event.Lock.init(comp.loop),
81 .arena = &code.arena.allocator,
81 };82 };
8283
83 try renderToLlvmModule(&ofile, fn_val, code);84 try renderToLlvmModule(&ofile, fn_val, code);
...@@ -139,6 +140,7 @@ pub const ObjectFile = struct {...@@ -139,6 +140,7 @@ pub const ObjectFile = struct {
139 dibuilder: *llvm.DIBuilder,140 dibuilder: *llvm.DIBuilder,
140 context: llvm.ContextRef,141 context: llvm.ContextRef,
141 lock: event.Lock,142 lock: event.Lock,
143 arena: *std.mem.Allocator,
142144
143 fn gpa(self: *ObjectFile) *std.mem.Allocator {145 fn gpa(self: *ObjectFile) *std.mem.Allocator {
144 return self.comp.gpa();146 return self.comp.gpa();
...@@ -147,7 +149,7 @@ pub const ObjectFile = struct {...@@ -147,7 +149,7 @@ pub const ObjectFile = struct {
147149
148pub fn renderToLlvmModule(ofile: *ObjectFile, fn_val: *Value.Fn, code: *ir.Code) !void {150pub fn renderToLlvmModule(ofile: *ObjectFile, fn_val: *Value.Fn, code: *ir.Code) !void {
149 // TODO audit more of codegen.cpp:fn_llvm_value and port more logic151 // TODO audit more of codegen.cpp:fn_llvm_value and port more logic
150 const llvm_fn_type = try fn_val.base.typeof.getLlvmType(ofile);152 const llvm_fn_type = try fn_val.base.typ.getLlvmType(ofile.arena, ofile.context);
151 const llvm_fn = llvm.AddFunction(153 const llvm_fn = llvm.AddFunction(
152 ofile.module,154 ofile.module,
153 fn_val.symbol_name.ptr(),155 fn_val.symbol_name.ptr(),
...@@ -165,7 +167,7 @@ pub fn renderToLlvmModule(ofile: *ObjectFile, fn_val: *Value.Fn, code: *ir.Code)...@@ -165,7 +167,7 @@ pub fn renderToLlvmModule(ofile: *ObjectFile, fn_val: *Value.Fn, code: *ir.Code)
165 // try addLLVMFnAttrInt(ofile, llvm_fn, "alignstack", align_stack);167 // try addLLVMFnAttrInt(ofile, llvm_fn, "alignstack", align_stack);
166 //}168 //}
167169
168 const fn_type = fn_val.base.typeof.cast(Type.Fn).?;170 const fn_type = fn_val.base.typ.cast(Type.Fn).?;
169171
170 try addLLVMFnAttr(ofile, llvm_fn, "nounwind");172 try addLLVMFnAttr(ofile, llvm_fn, "nounwind");
171 //add_uwtable_attr(g, fn_table_entry->llvm_value);173 //add_uwtable_attr(g, fn_table_entry->llvm_value);
src-self-hosted/compilation.zig+141-44
...@@ -194,6 +194,7 @@ pub const Compilation = struct {...@@ -194,6 +194,7 @@ pub const Compilation = struct {
194 bool_type: *Type.Bool,194 bool_type: *Type.Bool,
195 noreturn_type: *Type.NoReturn,195 noreturn_type: *Type.NoReturn,
196 comptime_int_type: *Type.ComptimeInt,196 comptime_int_type: *Type.ComptimeInt,
197 u8_type: *Type.Int,
197198
198 void_value: *Value.Void,199 void_value: *Value.Void,
199 true_value: *Value.Bool,200 true_value: *Value.Bool,
...@@ -203,6 +204,7 @@ pub const Compilation = struct {...@@ -203,6 +204,7 @@ pub const Compilation = struct {
203 target_machine: llvm.TargetMachineRef,204 target_machine: llvm.TargetMachineRef,
204 target_data_ref: llvm.TargetDataRef,205 target_data_ref: llvm.TargetDataRef,
205 target_layout_str: [*]u8,206 target_layout_str: [*]u8,
207 target_ptr_bits: u32,
206208
207 /// for allocating things which have the same lifetime as this Compilation209 /// for allocating things which have the same lifetime as this Compilation
208 arena_allocator: std.heap.ArenaAllocator,210 arena_allocator: std.heap.ArenaAllocator,
...@@ -223,10 +225,14 @@ pub const Compilation = struct {...@@ -223,10 +225,14 @@ pub const Compilation = struct {
223 primitive_type_table: TypeTable,225 primitive_type_table: TypeTable,
224226
225 int_type_table: event.Locked(IntTypeTable),227 int_type_table: event.Locked(IntTypeTable),
228 array_type_table: event.Locked(ArrayTypeTable),
229 ptr_type_table: event.Locked(PtrTypeTable),
226230
227 c_int_types: [CInt.list.len]*Type.Int,231 c_int_types: [CInt.list.len]*Type.Int,
228232
229 const IntTypeTable = std.HashMap(*const Type.Int.Key, *Type.Int, Type.Int.Key.hash, Type.Int.Key.eql);233 const IntTypeTable = std.HashMap(*const Type.Int.Key, *Type.Int, Type.Int.Key.hash, Type.Int.Key.eql);
234 const ArrayTypeTable = std.HashMap(*const Type.Array.Key, *Type.Array, Type.Array.Key.hash, Type.Array.Key.eql);
235 const PtrTypeTable = std.HashMap(*const Type.Pointer.Key, *Type.Pointer, Type.Pointer.Key.hash, Type.Pointer.Key.eql);
230 const TypeTable = std.HashMap([]const u8, *Type, mem.hash_slice_u8, mem.eql_slice_u8);236 const TypeTable = std.HashMap([]const u8, *Type, mem.hash_slice_u8, mem.eql_slice_u8);
231237
232 const CompileErrList = std.ArrayList(*errmsg.Msg);238 const CompileErrList = std.ArrayList(*errmsg.Msg);
...@@ -383,6 +389,8 @@ pub const Compilation = struct {...@@ -383,6 +389,8 @@ pub const Compilation = struct {
383 .deinit_group = event.Group(void).init(loop),389 .deinit_group = event.Group(void).init(loop),
384 .compile_errors = event.Locked(CompileErrList).init(loop, CompileErrList.init(loop.allocator)),390 .compile_errors = event.Locked(CompileErrList).init(loop, CompileErrList.init(loop.allocator)),
385 .int_type_table = event.Locked(IntTypeTable).init(loop, IntTypeTable.init(loop.allocator)),391 .int_type_table = event.Locked(IntTypeTable).init(loop, IntTypeTable.init(loop.allocator)),
392 .array_type_table = event.Locked(ArrayTypeTable).init(loop, ArrayTypeTable.init(loop.allocator)),
393 .ptr_type_table = event.Locked(PtrTypeTable).init(loop, PtrTypeTable.init(loop.allocator)),
386 .c_int_types = undefined,394 .c_int_types = undefined,
387395
388 .meta_type = undefined,396 .meta_type = undefined,
...@@ -394,10 +402,12 @@ pub const Compilation = struct {...@@ -394,10 +402,12 @@ pub const Compilation = struct {
394 .noreturn_type = undefined,402 .noreturn_type = undefined,
395 .noreturn_value = undefined,403 .noreturn_value = undefined,
396 .comptime_int_type = undefined,404 .comptime_int_type = undefined,
405 .u8_type = undefined,
397406
398 .target_machine = undefined,407 .target_machine = undefined,
399 .target_data_ref = undefined,408 .target_data_ref = undefined,
400 .target_layout_str = undefined,409 .target_layout_str = undefined,
410 .target_ptr_bits = target.getArchPtrBitWidth(),
401411
402 .root_package = undefined,412 .root_package = undefined,
403 .std_package = undefined,413 .std_package = undefined,
...@@ -409,6 +419,8 @@ pub const Compilation = struct {...@@ -409,6 +419,8 @@ pub const Compilation = struct {
409 });419 });
410 errdefer {420 errdefer {
411 comp.int_type_table.private_data.deinit();421 comp.int_type_table.private_data.deinit();
422 comp.array_type_table.private_data.deinit();
423 comp.ptr_type_table.private_data.deinit();
412 comp.arena_allocator.deinit();424 comp.arena_allocator.deinit();
413 comp.loop.allocator.destroy(comp);425 comp.loop.allocator.destroy(comp);
414 }426 }
...@@ -517,15 +529,16 @@ pub const Compilation = struct {...@@ -517,15 +529,16 @@ pub const Compilation = struct {
517 .name = "type",529 .name = "type",
518 .base = Value{530 .base = Value{
519 .id = Value.Id.Type,531 .id = Value.Id.Type,
520 .typeof = undefined,532 .typ = undefined,
521 .ref_count = std.atomic.Int(usize).init(3), // 3 because it references itself twice533 .ref_count = std.atomic.Int(usize).init(3), // 3 because it references itself twice
522 },534 },
523 .id = builtin.TypeId.Type,535 .id = builtin.TypeId.Type,
536 .abi_alignment = Type.AbiAlignment.init(comp.loop),
524 },537 },
525 .value = undefined,538 .value = undefined,
526 });539 });
527 comp.meta_type.value = &comp.meta_type.base;540 comp.meta_type.value = &comp.meta_type.base;
528 comp.meta_type.base.base.typeof = &comp.meta_type.base;541 comp.meta_type.base.base.typ = &comp.meta_type.base;
529 assert((try comp.primitive_type_table.put(comp.meta_type.base.name, &comp.meta_type.base)) == null);542 assert((try comp.primitive_type_table.put(comp.meta_type.base.name, &comp.meta_type.base)) == null);
530543
531 comp.void_type = try comp.arena().create(Type.Void{544 comp.void_type = try comp.arena().create(Type.Void{
...@@ -533,10 +546,11 @@ pub const Compilation = struct {...@@ -533,10 +546,11 @@ pub const Compilation = struct {
533 .name = "void",546 .name = "void",
534 .base = Value{547 .base = Value{
535 .id = Value.Id.Type,548 .id = Value.Id.Type,
536 .typeof = &Type.MetaType.get(comp).base,549 .typ = &Type.MetaType.get(comp).base,
537 .ref_count = std.atomic.Int(usize).init(1),550 .ref_count = std.atomic.Int(usize).init(1),
538 },551 },
539 .id = builtin.TypeId.Void,552 .id = builtin.TypeId.Void,
553 .abi_alignment = Type.AbiAlignment.init(comp.loop),
540 },554 },
541 });555 });
542 assert((try comp.primitive_type_table.put(comp.void_type.base.name, &comp.void_type.base)) == null);556 assert((try comp.primitive_type_table.put(comp.void_type.base.name, &comp.void_type.base)) == null);
...@@ -546,10 +560,11 @@ pub const Compilation = struct {...@@ -546,10 +560,11 @@ pub const Compilation = struct {
546 .name = "noreturn",560 .name = "noreturn",
547 .base = Value{561 .base = Value{
548 .id = Value.Id.Type,562 .id = Value.Id.Type,
549 .typeof = &Type.MetaType.get(comp).base,563 .typ = &Type.MetaType.get(comp).base,
550 .ref_count = std.atomic.Int(usize).init(1),564 .ref_count = std.atomic.Int(usize).init(1),
551 },565 },
552 .id = builtin.TypeId.NoReturn,566 .id = builtin.TypeId.NoReturn,
567 .abi_alignment = Type.AbiAlignment.init(comp.loop),
553 },568 },
554 });569 });
555 assert((try comp.primitive_type_table.put(comp.noreturn_type.base.name, &comp.noreturn_type.base)) == null);570 assert((try comp.primitive_type_table.put(comp.noreturn_type.base.name, &comp.noreturn_type.base)) == null);
...@@ -559,10 +574,11 @@ pub const Compilation = struct {...@@ -559,10 +574,11 @@ pub const Compilation = struct {
559 .name = "comptime_int",574 .name = "comptime_int",
560 .base = Value{575 .base = Value{
561 .id = Value.Id.Type,576 .id = Value.Id.Type,
562 .typeof = &Type.MetaType.get(comp).base,577 .typ = &Type.MetaType.get(comp).base,
563 .ref_count = std.atomic.Int(usize).init(1),578 .ref_count = std.atomic.Int(usize).init(1),
564 },579 },
565 .id = builtin.TypeId.ComptimeInt,580 .id = builtin.TypeId.ComptimeInt,
581 .abi_alignment = Type.AbiAlignment.init(comp.loop),
566 },582 },
567 });583 });
568 assert((try comp.primitive_type_table.put(comp.comptime_int_type.base.name, &comp.comptime_int_type.base)) == null);584 assert((try comp.primitive_type_table.put(comp.comptime_int_type.base.name, &comp.comptime_int_type.base)) == null);
...@@ -572,10 +588,11 @@ pub const Compilation = struct {...@@ -572,10 +588,11 @@ pub const Compilation = struct {
572 .name = "bool",588 .name = "bool",
573 .base = Value{589 .base = Value{
574 .id = Value.Id.Type,590 .id = Value.Id.Type,
575 .typeof = &Type.MetaType.get(comp).base,591 .typ = &Type.MetaType.get(comp).base,
576 .ref_count = std.atomic.Int(usize).init(1),592 .ref_count = std.atomic.Int(usize).init(1),
577 },593 },
578 .id = builtin.TypeId.Bool,594 .id = builtin.TypeId.Bool,
595 .abi_alignment = Type.AbiAlignment.init(comp.loop),
579 },596 },
580 });597 });
581 assert((try comp.primitive_type_table.put(comp.bool_type.base.name, &comp.bool_type.base)) == null);598 assert((try comp.primitive_type_table.put(comp.bool_type.base.name, &comp.bool_type.base)) == null);
...@@ -583,7 +600,7 @@ pub const Compilation = struct {...@@ -583,7 +600,7 @@ pub const Compilation = struct {
583 comp.void_value = try comp.arena().create(Value.Void{600 comp.void_value = try comp.arena().create(Value.Void{
584 .base = Value{601 .base = Value{
585 .id = Value.Id.Void,602 .id = Value.Id.Void,
586 .typeof = &Type.Void.get(comp).base,603 .typ = &Type.Void.get(comp).base,
587 .ref_count = std.atomic.Int(usize).init(1),604 .ref_count = std.atomic.Int(usize).init(1),
588 },605 },
589 });606 });
...@@ -591,7 +608,7 @@ pub const Compilation = struct {...@@ -591,7 +608,7 @@ pub const Compilation = struct {
591 comp.true_value = try comp.arena().create(Value.Bool{608 comp.true_value = try comp.arena().create(Value.Bool{
592 .base = Value{609 .base = Value{
593 .id = Value.Id.Bool,610 .id = Value.Id.Bool,
594 .typeof = &Type.Bool.get(comp).base,611 .typ = &Type.Bool.get(comp).base,
595 .ref_count = std.atomic.Int(usize).init(1),612 .ref_count = std.atomic.Int(usize).init(1),
596 },613 },
597 .x = true,614 .x = true,
...@@ -600,7 +617,7 @@ pub const Compilation = struct {...@@ -600,7 +617,7 @@ pub const Compilation = struct {
600 comp.false_value = try comp.arena().create(Value.Bool{617 comp.false_value = try comp.arena().create(Value.Bool{
601 .base = Value{618 .base = Value{
602 .id = Value.Id.Bool,619 .id = Value.Id.Bool,
603 .typeof = &Type.Bool.get(comp).base,620 .typ = &Type.Bool.get(comp).base,
604 .ref_count = std.atomic.Int(usize).init(1),621 .ref_count = std.atomic.Int(usize).init(1),
605 },622 },
606 .x = false,623 .x = false,
...@@ -609,7 +626,7 @@ pub const Compilation = struct {...@@ -609,7 +626,7 @@ pub const Compilation = struct {
609 comp.noreturn_value = try comp.arena().create(Value.NoReturn{626 comp.noreturn_value = try comp.arena().create(Value.NoReturn{
610 .base = Value{627 .base = Value{
611 .id = Value.Id.NoReturn,628 .id = Value.Id.NoReturn,
612 .typeof = &Type.NoReturn.get(comp).base,629 .typ = &Type.NoReturn.get(comp).base,
613 .ref_count = std.atomic.Int(usize).init(1),630 .ref_count = std.atomic.Int(usize).init(1),
614 },631 },
615 });632 });
...@@ -620,10 +637,11 @@ pub const Compilation = struct {...@@ -620,10 +637,11 @@ pub const Compilation = struct {
620 .name = cint.zig_name,637 .name = cint.zig_name,
621 .base = Value{638 .base = Value{
622 .id = Value.Id.Type,639 .id = Value.Id.Type,
623 .typeof = &Type.MetaType.get(comp).base,640 .typ = &Type.MetaType.get(comp).base,
624 .ref_count = std.atomic.Int(usize).init(1),641 .ref_count = std.atomic.Int(usize).init(1),
625 },642 },
626 .id = builtin.TypeId.Int,643 .id = builtin.TypeId.Int,
644 .abi_alignment = Type.AbiAlignment.init(comp.loop),
627 },645 },
628 .key = Type.Int.Key{646 .key = Type.Int.Key{
629 .is_signed = cint.is_signed,647 .is_signed = cint.is_signed,
...@@ -634,6 +652,24 @@ pub const Compilation = struct {...@@ -634,6 +652,24 @@ pub const Compilation = struct {
634 comp.c_int_types[i] = c_int_type;652 comp.c_int_types[i] = c_int_type;
635 assert((try comp.primitive_type_table.put(cint.zig_name, &c_int_type.base)) == null);653 assert((try comp.primitive_type_table.put(cint.zig_name, &c_int_type.base)) == null);
636 }654 }
655 comp.u8_type = try comp.arena().create(Type.Int{
656 .base = Type{
657 .name = "u8",
658 .base = Value{
659 .id = Value.Id.Type,
660 .typ = &Type.MetaType.get(comp).base,
661 .ref_count = std.atomic.Int(usize).init(1),
662 },
663 .id = builtin.TypeId.Int,
664 .abi_alignment = Type.AbiAlignment.init(comp.loop),
665 },
666 .key = Type.Int.Key{
667 .is_signed = false,
668 .bit_count = 8,
669 },
670 .garbage_node = undefined,
671 });
672 assert((try comp.primitive_type_table.put(comp.u8_type.base.name, &comp.u8_type.base)) == null);
637 }673 }
638674
639 /// This function can safely use async/await, because it manages Compilation's lifetime,675 /// This function can safely use async/await, because it manages Compilation's lifetime,
...@@ -750,7 +786,7 @@ pub const Compilation = struct {...@@ -750,7 +786,7 @@ pub const Compilation = struct {
750 ast.Node.Id.Comptime => {786 ast.Node.Id.Comptime => {
751 const comptime_node = @fieldParentPtr(ast.Node.Comptime, "base", decl);787 const comptime_node = @fieldParentPtr(ast.Node.Comptime, "base", decl);
752788
753 try decl_group.call(addCompTimeBlock, self, &decls.base, comptime_node);789 try self.prelink_group.call(addCompTimeBlock, self, &decls.base, comptime_node);
754 },790 },
755 ast.Node.Id.VarDecl => @panic("TODO"),791 ast.Node.Id.VarDecl => @panic("TODO"),
756 ast.Node.Id.FnProto => {792 ast.Node.Id.FnProto => {
...@@ -770,7 +806,6 @@ pub const Compilation = struct {...@@ -770,7 +806,6 @@ pub const Compilation = struct {
770 .name = name,806 .name = name,
771 .visib = parseVisibToken(tree, fn_proto.visib_token),807 .visib = parseVisibToken(tree, fn_proto.visib_token),
772 .resolution = event.Future(BuildError!void).init(self.loop),808 .resolution = event.Future(BuildError!void).init(self.loop),
773 .resolution_in_progress = 0,
774 .parent_scope = &decls.base,809 .parent_scope = &decls.base,
775 },810 },
776 .value = Decl.Fn.Val{ .Unresolved = {} },811 .value = Decl.Fn.Val{ .Unresolved = {} },
...@@ -778,16 +813,22 @@ pub const Compilation = struct {...@@ -778,16 +813,22 @@ pub const Compilation = struct {
778 });813 });
779 errdefer self.gpa().destroy(fn_decl);814 errdefer self.gpa().destroy(fn_decl);
780815
781 try decl_group.call(addTopLevelDecl, self, &fn_decl.base);816 try decl_group.call(addTopLevelDecl, self, decls, &fn_decl.base);
782 },817 },
783 ast.Node.Id.TestDecl => @panic("TODO"),818 ast.Node.Id.TestDecl => @panic("TODO"),
784 else => unreachable,819 else => unreachable,
785 }820 }
786 }821 }
787 try await (async decl_group.wait() catch unreachable);822 try await (async decl_group.wait() catch unreachable);
823
824 // Now other code can rely on the decls scope having a complete list of names.
825 decls.name_future.resolve();
788 }826 }
789827
790 try await (async self.prelink_group.wait() catch unreachable);828 (await (async self.prelink_group.wait() catch unreachable)) catch |err| switch (err) {
829 error.SemanticAnalysisFailed => {},
830 else => return err,
831 };
791832
792 const any_prelink_errors = blk: {833 const any_prelink_errors = blk: {
793 const compile_errors = await (async self.compile_errors.acquire() catch unreachable);834 const compile_errors = await (async self.compile_errors.acquire() catch unreachable);
...@@ -857,14 +898,31 @@ pub const Compilation = struct {...@@ -857,14 +898,31 @@ pub const Compilation = struct {
857 analyzed_code.destroy(comp.gpa());898 analyzed_code.destroy(comp.gpa());
858 }899 }
859900
860 async fn addTopLevelDecl(self: *Compilation, decl: *Decl) !void {901 async fn addTopLevelDecl(self: *Compilation, decls: *Scope.Decls, decl: *Decl) !void {
861 const tree = &decl.findRootScope().tree;902 const tree = &decl.findRootScope().tree;
862 const is_export = decl.isExported(tree);903 const is_export = decl.isExported(tree);
863904
905 var add_to_table_resolved = false;
906 const add_to_table = async self.addDeclToTable(decls, decl) catch unreachable;
907 errdefer if (!add_to_table_resolved) cancel add_to_table; // TODO https://github.com/ziglang/zig/issues/1261
908
864 if (is_export) {909 if (is_export) {
865 try self.prelink_group.call(verifyUniqueSymbol, self, decl);910 try self.prelink_group.call(verifyUniqueSymbol, self, decl);
866 try self.prelink_group.call(resolveDecl, self, decl);911 try self.prelink_group.call(resolveDecl, self, decl);
867 }912 }
913
914 add_to_table_resolved = true;
915 try await add_to_table;
916 }
917
918 async fn addDeclToTable(self: *Compilation, decls: *Scope.Decls, decl: *Decl) !void {
919 const held = await (async decls.table.acquire() catch unreachable);
920 defer held.release();
921
922 if (try held.value.put(decl.name, decl)) |other_decl| {
923 try self.addCompileError(decls.base.findRoot(), decl.getSpan(), "redefinition of '{}'", decl.name);
924 // TODO note: other definition here
925 }
868 }926 }
869927
870 fn addCompileError(self: *Compilation, root: *Scope.Root, span: Span, comptime fmt: []const u8, args: ...) !void {928 fn addCompileError(self: *Compilation, root: *Scope.Root, span: Span, comptime fmt: []const u8, args: ...) !void {
...@@ -1043,6 +1101,15 @@ pub const Compilation = struct {...@@ -1043,6 +1101,15 @@ pub const Compilation = struct {
10431101
1044 return result_val.cast(Type).?;1102 return result_val.cast(Type).?;
1045 }1103 }
1104
1105 /// This declaration has been blessed as going into the final code generation.
1106 pub async fn resolveDecl(comp: *Compilation, decl: *Decl) !void {
1107 if (await (async decl.resolution.start() catch unreachable)) |ptr| return ptr.*;
1108
1109 decl.resolution.data = try await (async generateDecl(comp, decl) catch unreachable);
1110 decl.resolution.resolve();
1111 return decl.resolution.data;
1112 }
1046};1113};
10471114
1048fn printError(comptime format: []const u8, args: ...) !void {1115fn printError(comptime format: []const u8, args: ...) !void {
...@@ -1062,20 +1129,6 @@ fn parseVisibToken(tree: *ast.Tree, optional_token_index: ?ast.TokenIndex) Visib...@@ -1062,20 +1129,6 @@ fn parseVisibToken(tree: *ast.Tree, optional_token_index: ?ast.TokenIndex) Visib
1062 }1129 }
1063}1130}
10641131
1065/// This declaration has been blessed as going into the final code generation.
1066pub async fn resolveDecl(comp: *Compilation, decl: *Decl) !void {
1067 if (await (async decl.resolution.start() catch unreachable)) |ptr| return ptr.*;
1068
1069 decl.resolution.data = (await (async generateDecl(comp, decl) catch unreachable)) catch |err| switch (err) {
1070 // This poison value should not cause the errdefers to run. It simply means
1071 // that comp.compile_errors is populated.
1072 error.SemanticAnalysisFailed => {},
1073 else => err,
1074 };
1075 decl.resolution.resolve();
1076 return decl.resolution.data;
1077}
1078
1079/// The function that actually does the generation.1132/// The function that actually does the generation.
1080async fn generateDecl(comp: *Compilation, decl: *Decl) !void {1133async fn generateDecl(comp: *Compilation, decl: *Decl) !void {
1081 switch (decl.id) {1134 switch (decl.id) {
...@@ -1089,34 +1142,27 @@ async fn generateDecl(comp: *Compilation, decl: *Decl) !void {...@@ -1089,34 +1142,27 @@ async fn generateDecl(comp: *Compilation, decl: *Decl) !void {
1089}1142}
10901143
1091async fn generateDeclFn(comp: *Compilation, fn_decl: *Decl.Fn) !void {1144async fn generateDeclFn(comp: *Compilation, fn_decl: *Decl.Fn) !void {
1092 const body_node = fn_decl.fn_proto.body_node orelse @panic("TODO extern fn proto decl");1145 const body_node = fn_decl.fn_proto.body_node orelse return await (async generateDeclFnProto(comp, fn_decl) catch unreachable);
10931146
1094 const fndef_scope = try Scope.FnDef.create(comp, fn_decl.base.parent_scope);1147 const fndef_scope = try Scope.FnDef.create(comp, fn_decl.base.parent_scope);
1095 defer fndef_scope.base.deref(comp);1148 defer fndef_scope.base.deref(comp);
10961149
1097 const return_type_node = switch (fn_decl.fn_proto.return_type) {1150 const fn_type = try await (async analyzeFnType(comp, fn_decl.base.parent_scope, fn_decl.fn_proto) catch unreachable);
1098 ast.Node.FnProto.ReturnType.Explicit => |n| n,
1099 ast.Node.FnProto.ReturnType.InferErrorSet => |n| n,
1100 };
1101 const return_type = try await (async comp.analyzeTypeExpr(&fndef_scope.base, return_type_node) catch unreachable);
1102 return_type.base.deref(comp);
1103
1104 const is_var_args = false;
1105 const params = ([*]Type.Fn.Param)(undefined)[0..0];
1106 const fn_type = try Type.Fn.create(comp, return_type, params, is_var_args);
1107 defer fn_type.base.base.deref(comp);1151 defer fn_type.base.base.deref(comp);
11081152
1109 var symbol_name = try std.Buffer.init(comp.gpa(), fn_decl.base.name);1153 var symbol_name = try std.Buffer.init(comp.gpa(), fn_decl.base.name);
1110 errdefer symbol_name.deinit();1154 var symbol_name_consumed = false;
1155 errdefer if (!symbol_name_consumed) symbol_name.deinit();
11111156
1112 // The Decl.Fn owns the initial 1 reference count1157 // The Decl.Fn owns the initial 1 reference count
1113 const fn_val = try Value.Fn.create(comp, fn_type, fndef_scope, symbol_name);1158 const fn_val = try Value.Fn.create(comp, fn_type, fndef_scope, symbol_name);
1114 fn_decl.value = Decl.Fn.Val{ .Ok = fn_val };1159 fn_decl.value = Decl.Fn.Val{ .Fn = fn_val };
1160 symbol_name_consumed = true;
11151161
1116 const analyzed_code = try await (async comp.genAndAnalyzeCode(1162 const analyzed_code = try await (async comp.genAndAnalyzeCode(
1117 &fndef_scope.base,1163 &fndef_scope.base,
1118 body_node,1164 body_node,
1119 return_type,1165 fn_type.return_type,
1120 ) catch unreachable);1166 ) catch unreachable);
1121 errdefer analyzed_code.destroy(comp.gpa());1167 errdefer analyzed_code.destroy(comp.gpa());
11221168
...@@ -1141,3 +1187,54 @@ async fn addFnToLinkSet(comp: *Compilation, fn_val: *Value.Fn) void {...@@ -1141,3 +1187,54 @@ async fn addFnToLinkSet(comp: *Compilation, fn_val: *Value.Fn) void {
1141fn getZigDir(allocator: *mem.Allocator) ![]u8 {1187fn getZigDir(allocator: *mem.Allocator) ![]u8 {
1142 return os.getAppDataDir(allocator, "zig");1188 return os.getAppDataDir(allocator, "zig");
1143}1189}
1190
1191async fn analyzeFnType(comp: *Compilation, scope: *Scope, fn_proto: *ast.Node.FnProto) !*Type.Fn {
1192 const return_type_node = switch (fn_proto.return_type) {
1193 ast.Node.FnProto.ReturnType.Explicit => |n| n,
1194 ast.Node.FnProto.ReturnType.InferErrorSet => |n| n,
1195 };
1196 const return_type = try await (async comp.analyzeTypeExpr(scope, return_type_node) catch unreachable);
1197 return_type.base.deref(comp);
1198
1199 var params = ArrayList(Type.Fn.Param).init(comp.gpa());
1200 var params_consumed = false;
1201 defer if (params_consumed) {
1202 for (params.toSliceConst()) |param| {
1203 param.typ.base.deref(comp);
1204 }
1205 params.deinit();
1206 };
1207
1208 const is_var_args = false;
1209 {
1210 var it = fn_proto.params.iterator(0);
1211 while (it.next()) |param_node_ptr| {
1212 const param_node = param_node_ptr.*.cast(ast.Node.ParamDecl).?;
1213 const param_type = try await (async comp.analyzeTypeExpr(scope, param_node.type_node) catch unreachable);
1214 errdefer param_type.base.deref(comp);
1215 try params.append(Type.Fn.Param{
1216 .typ = param_type,
1217 .is_noalias = param_node.noalias_token != null,
1218 });
1219 }
1220 }
1221 const fn_type = try Type.Fn.create(comp, return_type, params.toOwnedSlice(), is_var_args);
1222 params_consumed = true;
1223 errdefer fn_type.base.base.deref(comp);
1224
1225 return fn_type;
1226}
1227
1228async fn generateDeclFnProto(comp: *Compilation, fn_decl: *Decl.Fn) !void {
1229 const fn_type = try await (async analyzeFnType(comp, fn_decl.base.parent_scope, fn_decl.fn_proto) catch unreachable);
1230 defer fn_type.base.base.deref(comp);
1231
1232 var symbol_name = try std.Buffer.init(comp.gpa(), fn_decl.base.name);
1233 var symbol_name_consumed = false;
1234 defer if (!symbol_name_consumed) symbol_name.deinit();
1235
1236 // The Decl.Fn owns the initial 1 reference count
1237 const fn_proto_val = try Value.FnProto.create(comp, fn_type, symbol_name);
1238 fn_decl.value = Decl.Fn.Val{ .FnProto = fn_proto_val };
1239 symbol_name_consumed = true;
1240}
src-self-hosted/decl.zig+4-4
...@@ -15,7 +15,6 @@ pub const Decl = struct {...@@ -15,7 +15,6 @@ pub const Decl = struct {
15 name: []const u8,15 name: []const u8,
16 visib: Visib,16 visib: Visib,
17 resolution: event.Future(Compilation.BuildError!void),17 resolution: event.Future(Compilation.BuildError!void),
18 resolution_in_progress: u8,
19 parent_scope: *Scope,18 parent_scope: *Scope,
2019
21 pub const Table = std.HashMap([]const u8, *Decl, mem.hash_slice_u8, mem.eql_slice_u8);20 pub const Table = std.HashMap([]const u8, *Decl, mem.hash_slice_u8, mem.eql_slice_u8);
...@@ -63,12 +62,13 @@ pub const Decl = struct {...@@ -63,12 +62,13 @@ pub const Decl = struct {
63 pub const Fn = struct {62 pub const Fn = struct {
64 base: Decl,63 base: Decl,
65 value: Val,64 value: Val,
66 fn_proto: *const ast.Node.FnProto,65 fn_proto: *ast.Node.FnProto,
6766
68 // TODO https://github.com/ziglang/zig/issues/683 and then make this anonymous67 // TODO https://github.com/ziglang/zig/issues/683 and then make this anonymous
69 pub const Val = union {68 pub const Val = union(enum) {
70 Unresolved: void,69 Unresolved: void,
71 Ok: *Value.Fn,70 Fn: *Value.Fn,
71 FnProto: *Value.FnProto,
72 };72 };
7373
74 pub fn externLibName(self: Fn, tree: *ast.Tree) ?[]const u8 {74 pub fn externLibName(self: Fn, tree: *ast.Tree) ?[]const u8 {
src-self-hosted/errmsg.zig+8-1
...@@ -16,11 +16,18 @@ pub const Span = struct {...@@ -16,11 +16,18 @@ pub const Span = struct {
16 last: ast.TokenIndex,16 last: ast.TokenIndex,
1717
18 pub fn token(i: TokenIndex) Span {18 pub fn token(i: TokenIndex) Span {
19 return Span {19 return Span{
20 .first = i,20 .first = i,
21 .last = i,21 .last = i,
22 };22 };
23 }23 }
24
25 pub fn node(n: *ast.Node) Span {
26 return Span{
27 .first = n.firstToken(),
28 .last = n.lastToken(),
29 };
30 }
24};31};
2532
26pub const Msg = struct {33pub const Msg = struct {
src-self-hosted/ir.zig+492-52
...@@ -11,6 +11,7 @@ const Token = std.zig.Token;...@@ -11,6 +11,7 @@ const Token = std.zig.Token;
11const Span = @import("errmsg.zig").Span;11const Span = @import("errmsg.zig").Span;
12const llvm = @import("llvm.zig");12const llvm = @import("llvm.zig");
13const ObjectFile = @import("codegen.zig").ObjectFile;13const ObjectFile = @import("codegen.zig").ObjectFile;
14const Decl = @import("decl.zig").Decl;
1415
15pub const LVal = enum {16pub const LVal = enum {
16 None,17 None,
...@@ -30,10 +31,10 @@ pub const IrVal = union(enum) {...@@ -30,10 +31,10 @@ pub const IrVal = union(enum) {
3031
31 pub fn dump(self: IrVal) void {32 pub fn dump(self: IrVal) void {
32 switch (self) {33 switch (self) {
33 IrVal.Unknown => typeof.dump(),34 IrVal.Unknown => std.debug.warn("Unknown"),
34 IrVal.KnownType => |typeof| {35 IrVal.KnownType => |typ| {
35 std.debug.warn("KnownType(");36 std.debug.warn("KnownType(");
36 typeof.dump();37 typ.dump();
37 std.debug.warn(")");38 std.debug.warn(")");
38 },39 },
39 IrVal.KnownValue => |value| {40 IrVal.KnownValue => |value| {
...@@ -108,21 +109,29 @@ pub const Inst = struct {...@@ -108,21 +109,29 @@ pub const Inst = struct {
108 unreachable;109 unreachable;
109 }110 }
110111
111 pub fn analyze(base: *Inst, ira: *Analyze) Analyze.Error!*Inst {112 pub async fn analyze(base: *Inst, ira: *Analyze) Analyze.Error!*Inst {
112 comptime var i = 0;113 switch (base.id) {
113 inline while (i < @memberCount(Id)) : (i += 1) {114 Id.Return => return @fieldParentPtr(Return, "base", base).analyze(ira),
114 if (base.id == @field(Id, @memberName(Id, i))) {115 Id.Const => return @fieldParentPtr(Const, "base", base).analyze(ira),
115 const T = @field(Inst, @memberName(Id, i));116 Id.Call => return @fieldParentPtr(Call, "base", base).analyze(ira),
116 return @fieldParentPtr(T, "base", base).analyze(ira);117 Id.DeclRef => return await (async @fieldParentPtr(DeclRef, "base", base).analyze(ira) catch unreachable),
117 }118 Id.Ref => return await (async @fieldParentPtr(Ref, "base", base).analyze(ira) catch unreachable),
119 Id.DeclVar => return @fieldParentPtr(DeclVar, "base", base).analyze(ira),
120 Id.CheckVoidStmt => return @fieldParentPtr(CheckVoidStmt, "base", base).analyze(ira),
121 Id.Phi => return @fieldParentPtr(Phi, "base", base).analyze(ira),
122 Id.Br => return @fieldParentPtr(Br, "base", base).analyze(ira),
123 Id.AddImplicitReturnType => return @fieldParentPtr(AddImplicitReturnType, "base", base).analyze(ira),
124 Id.PtrType => return await (async @fieldParentPtr(PtrType, "base", base).analyze(ira) catch unreachable),
118 }125 }
119 unreachable;
120 }126 }
121127
122 pub fn render(base: *Inst, ofile: *ObjectFile, fn_val: *Value.Fn) (error{OutOfMemory}!?llvm.ValueRef) {128 pub fn render(base: *Inst, ofile: *ObjectFile, fn_val: *Value.Fn) (error{OutOfMemory}!?llvm.ValueRef) {
123 switch (base.id) {129 switch (base.id) {
124 Id.Return => return @fieldParentPtr(Return, "base", base).render(ofile, fn_val),130 Id.Return => return @fieldParentPtr(Return, "base", base).render(ofile, fn_val),
125 Id.Const => return @fieldParentPtr(Const, "base", base).render(ofile, fn_val),131 Id.Const => return @fieldParentPtr(Const, "base", base).render(ofile, fn_val),
132 Id.Call => return @fieldParentPtr(Call, "base", base).render(ofile, fn_val),
133 Id.DeclRef => unreachable,
134 Id.PtrType => unreachable,
126 Id.Ref => @panic("TODO"),135 Id.Ref => @panic("TODO"),
127 Id.DeclVar => @panic("TODO"),136 Id.DeclVar => @panic("TODO"),
128 Id.CheckVoidStmt => @panic("TODO"),137 Id.CheckVoidStmt => @panic("TODO"),
...@@ -135,7 +144,7 @@ pub const Inst = struct {...@@ -135,7 +144,7 @@ pub const Inst = struct {
135 fn ref(base: *Inst, builder: *Builder) void {144 fn ref(base: *Inst, builder: *Builder) void {
136 base.ref_count += 1;145 base.ref_count += 1;
137 if (base.owner_bb != builder.current_basic_block and !base.isCompTime()) {146 if (base.owner_bb != builder.current_basic_block and !base.isCompTime()) {
138 base.owner_bb.ref();147 base.owner_bb.ref(builder);
139 }148 }
140 }149 }
141150
...@@ -155,11 +164,51 @@ pub const Inst = struct {...@@ -155,11 +164,51 @@ pub const Inst = struct {
155 }164 }
156 }165 }
157166
167 fn getConstVal(self: *Inst, ira: *Analyze) !*Value {
168 if (self.isCompTime()) {
169 return self.val.KnownValue;
170 } else {
171 try ira.addCompileError(self.span, "unable to evaluate constant expression");
172 return error.SemanticAnalysisFailed;
173 }
174 }
175
176 fn getAsConstType(param: *Inst, ira: *Analyze) !*Type {
177 const meta_type = Type.MetaType.get(ira.irb.comp);
178 meta_type.base.base.deref(ira.irb.comp);
179
180 const inst = try param.getAsParam();
181 const casted = try ira.implicitCast(inst, &meta_type.base);
182 const val = try casted.getConstVal(ira);
183 return val.cast(Value.Type).?;
184 }
185
186 fn getAsConstAlign(param: *Inst, ira: *Analyze) !u32 {
187 return error.Unimplemented;
188 //const align_type = Type.Int.get_align(ira.irb.comp);
189 //align_type.base.base.deref(ira.irb.comp);
190
191 //const inst = try param.getAsParam();
192 //const casted = try ira.implicitCast(inst, align_type);
193 //const val = try casted.getConstVal(ira);
194
195 //uint32_t align_bytes = bigint_as_unsigned(&const_val->data.x_bigint);
196 //if (align_bytes == 0) {
197 // ir_add_error(ira, value, buf_sprintf("alignment must be >= 1"));
198 // return false;
199 //}
200
201 //if (!is_power_of_2(align_bytes)) {
202 // ir_add_error(ira, value, buf_sprintf("alignment value %" PRIu32 " is not a power of 2", align_bytes));
203 // return false;
204 //}
205 }
206
158 /// asserts that the type is known207 /// asserts that the type is known
159 fn getKnownType(self: *Inst) *Type {208 fn getKnownType(self: *Inst) *Type {
160 switch (self.val) {209 switch (self.val) {
161 IrVal.KnownType => |typeof| return typeof,210 IrVal.KnownType => |typ| return typ,
162 IrVal.KnownValue => |value| return value.typeof,211 IrVal.KnownValue => |value| return value.typ,
163 IrVal.Unknown => unreachable,212 IrVal.Unknown => unreachable,
164 }213 }
165 }214 }
...@@ -171,8 +220,8 @@ pub const Inst = struct {...@@ -171,8 +220,8 @@ pub const Inst = struct {
171 pub fn isNoReturn(base: *const Inst) bool {220 pub fn isNoReturn(base: *const Inst) bool {
172 switch (base.val) {221 switch (base.val) {
173 IrVal.Unknown => return false,222 IrVal.Unknown => return false,
174 IrVal.KnownValue => |x| return x.typeof.id == Type.Id.NoReturn,223 IrVal.KnownValue => |x| return x.typ.id == Type.Id.NoReturn,
175 IrVal.KnownType => |typeof| return typeof.id == Type.Id.NoReturn,224 IrVal.KnownType => |typ| return typ.id == Type.Id.NoReturn,
176 }225 }
177 }226 }
178227
...@@ -196,6 +245,85 @@ pub const Inst = struct {...@@ -196,6 +245,85 @@ pub const Inst = struct {
196 Phi,245 Phi,
197 Br,246 Br,
198 AddImplicitReturnType,247 AddImplicitReturnType,
248 Call,
249 DeclRef,
250 PtrType,
251 };
252
253 pub const Call = struct {
254 base: Inst,
255 params: Params,
256
257 const Params = struct {
258 fn_ref: *Inst,
259 args: []*Inst,
260 };
261
262 const ir_val_init = IrVal.Init.Unknown;
263
264 pub fn dump(self: *const Call) void {
265 std.debug.warn("#{}(", self.params.fn_ref.debug_id);
266 for (self.params.args) |arg| {
267 std.debug.warn("#{},", arg.debug_id);
268 }
269 std.debug.warn(")");
270 }
271
272 pub fn hasSideEffects(self: *const Call) bool {
273 return true;
274 }
275
276 pub fn analyze(self: *const Call, ira: *Analyze) !*Inst {
277 const fn_ref = try self.params.fn_ref.getAsParam();
278 const fn_ref_type = fn_ref.getKnownType();
279 const fn_type = fn_ref_type.cast(Type.Fn) orelse {
280 try ira.addCompileError(fn_ref.span, "type '{}' not a function", fn_ref_type.name);
281 return error.SemanticAnalysisFailed;
282 };
283
284 if (fn_type.params.len != self.params.args.len) {
285 try ira.addCompileError(
286 self.base.span,
287 "expected {} arguments, found {}",
288 fn_type.params.len,
289 self.params.args.len,
290 );
291 return error.SemanticAnalysisFailed;
292 }
293
294 const args = try ira.irb.arena().alloc(*Inst, self.params.args.len);
295 for (self.params.args) |arg, i| {
296 args[i] = try arg.getAsParam();
297 }
298 const new_inst = try ira.irb.build(Call, self.base.scope, self.base.span, Params{
299 .fn_ref = fn_ref,
300 .args = args,
301 });
302 new_inst.val = IrVal{ .KnownType = fn_type.return_type };
303 return new_inst;
304 }
305
306 pub fn render(self: *Call, ofile: *ObjectFile, fn_val: *Value.Fn) !?llvm.ValueRef {
307 const fn_ref = self.params.fn_ref.llvm_value.?;
308
309 const args = try ofile.arena.alloc(llvm.ValueRef, self.params.args.len);
310 for (self.params.args) |arg, i| {
311 args[i] = arg.llvm_value.?;
312 }
313
314 const llvm_cc = llvm.CCallConv;
315 const fn_inline = llvm.FnInline.Auto;
316
317 return llvm.BuildCall(
318 ofile.builder,
319 fn_ref,
320 args.ptr,
321 @intCast(c_uint, args.len),
322 llvm_cc,
323 fn_inline,
324 c"",
325 ) orelse error.OutOfMemory;
326 }
199 };327 };
200328
201 pub const Const = struct {329 pub const Const = struct {
...@@ -254,14 +382,14 @@ pub const Inst = struct {...@@ -254,14 +382,14 @@ pub const Inst = struct {
254 return ira.irb.build(Return, self.base.scope, self.base.span, Params{ .return_value = casted_value });382 return ira.irb.build(Return, self.base.scope, self.base.span, Params{ .return_value = casted_value });
255 }383 }
256384
257 pub fn render(self: *Return, ofile: *ObjectFile, fn_val: *Value.Fn) ?llvm.ValueRef {385 pub fn render(self: *Return, ofile: *ObjectFile, fn_val: *Value.Fn) !?llvm.ValueRef {
258 const value = self.params.return_value.llvm_value;386 const value = self.params.return_value.llvm_value;
259 const return_type = self.params.return_value.getKnownType();387 const return_type = self.params.return_value.getKnownType();
260388
261 if (return_type.handleIsPtr()) {389 if (return_type.handleIsPtr()) {
262 @panic("TODO");390 @panic("TODO");
263 } else {391 } else {
264 _ = llvm.BuildRet(ofile.builder, value);392 _ = llvm.BuildRet(ofile.builder, value) orelse return error.OutOfMemory;
265 }393 }
266 return null;394 return null;
267 }395 }
...@@ -285,7 +413,7 @@ pub const Inst = struct {...@@ -285,7 +413,7 @@ pub const Inst = struct {
285 return false;413 return false;
286 }414 }
287415
288 pub fn analyze(self: *const Ref, ira: *Analyze) !*Inst {416 pub async fn analyze(self: *const Ref, ira: *Analyze) !*Inst {
289 const target = try self.params.target.getAsParam();417 const target = try self.params.target.getAsParam();
290418
291 if (ira.getCompTimeValOrNullUndefOk(target)) |val| {419 if (ira.getCompTimeValOrNullUndefOk(target)) |val| {
...@@ -294,7 +422,6 @@ pub const Inst = struct {...@@ -294,7 +422,6 @@ pub const Inst = struct {
294 Value.Ptr.Mut.CompTimeConst,422 Value.Ptr.Mut.CompTimeConst,
295 self.params.mut,423 self.params.mut,
296 self.params.volatility,424 self.params.volatility,
297 val.typeof.getAbiAlignment(ira.irb.comp),
298 );425 );
299 }426 }
300427
...@@ -304,14 +431,13 @@ pub const Inst = struct {...@@ -304,14 +431,13 @@ pub const Inst = struct {
304 .volatility = self.params.volatility,431 .volatility = self.params.volatility,
305 });432 });
306 const elem_type = target.getKnownType();433 const elem_type = target.getKnownType();
307 const ptr_type = Type.Pointer.get(434 const ptr_type = try await (async Type.Pointer.get(ira.irb.comp, Type.Pointer.Key{
308 ira.irb.comp,435 .child_type = elem_type,
309 elem_type,436 .mut = self.params.mut,
310 self.params.mut,437 .vol = self.params.volatility,
311 self.params.volatility,438 .size = Type.Pointer.Size.One,
312 Type.Pointer.Size.One,439 .alignment = Type.Pointer.Align.Abi,
313 elem_type.getAbiAlignment(ira.irb.comp),440 }) catch unreachable);
314 );
315 // TODO: potentially set the hint that this is a stack pointer. But it might not be - this441 // TODO: potentially set the hint that this is a stack pointer. But it might not be - this
316 // could be a ref of a global, for example442 // could be a ref of a global, for example
317 new_inst.val = IrVal{ .KnownType = &ptr_type.base };443 new_inst.val = IrVal{ .KnownType = &ptr_type.base };
...@@ -320,6 +446,97 @@ pub const Inst = struct {...@@ -320,6 +446,97 @@ pub const Inst = struct {
320 }446 }
321 };447 };
322448
449 pub const DeclRef = struct {
450 base: Inst,
451 params: Params,
452
453 const Params = struct {
454 decl: *Decl,
455 lval: LVal,
456 };
457
458 const ir_val_init = IrVal.Init.Unknown;
459
460 pub fn dump(inst: *const DeclRef) void {}
461
462 pub fn hasSideEffects(inst: *const DeclRef) bool {
463 return false;
464 }
465
466 pub async fn analyze(self: *const DeclRef, ira: *Analyze) !*Inst {
467 (await (async ira.irb.comp.resolveDecl(self.params.decl) catch unreachable)) catch |err| switch (err) {
468 error.OutOfMemory => return error.OutOfMemory,
469 else => return error.SemanticAnalysisFailed,
470 };
471 switch (self.params.decl.id) {
472 Decl.Id.CompTime => unreachable,
473 Decl.Id.Var => return error.Unimplemented,
474 Decl.Id.Fn => {
475 const fn_decl = @fieldParentPtr(Decl.Fn, "base", self.params.decl);
476 const decl_val = switch (fn_decl.value) {
477 Decl.Fn.Val.Unresolved => unreachable,
478 Decl.Fn.Val.Fn => |fn_val| &fn_val.base,
479 Decl.Fn.Val.FnProto => |fn_proto| &fn_proto.base,
480 };
481 switch (self.params.lval) {
482 LVal.None => {
483 return ira.irb.buildConstValue(self.base.scope, self.base.span, decl_val);
484 },
485 LVal.Ptr => return error.Unimplemented,
486 }
487 },
488 }
489 }
490 };
491
492 pub const PtrType = struct {
493 base: Inst,
494 params: Params,
495
496 const Params = struct {
497 child_type: *Inst,
498 mut: Type.Pointer.Mut,
499 vol: Type.Pointer.Vol,
500 size: Type.Pointer.Size,
501 alignment: ?*Inst,
502 };
503
504 const ir_val_init = IrVal.Init.Unknown;
505
506 pub fn dump(inst: *const PtrType) void {}
507
508 pub fn hasSideEffects(inst: *const PtrType) bool {
509 return false;
510 }
511
512 pub async fn analyze(self: *const PtrType, ira: *Analyze) !*Inst {
513 const child_type = try self.params.child_type.getAsConstType(ira);
514 // if (child_type->id == TypeTableEntryIdUnreachable) {
515 // ir_add_error(ira, &instruction->base, buf_sprintf("pointer to noreturn not allowed"));
516 // return ira->codegen->builtin_types.entry_invalid;
517 // } else if (child_type->id == TypeTableEntryIdOpaque && instruction->ptr_len == PtrLenUnknown) {
518 // ir_add_error(ira, &instruction->base, buf_sprintf("unknown-length pointer to opaque"));
519 // return ira->codegen->builtin_types.entry_invalid;
520 // }
521 const alignment = if (self.params.alignment) |align_inst| blk: {
522 const amt = try align_inst.getAsConstAlign(ira);
523 break :blk Type.Pointer.Align{ .Override = amt };
524 } else blk: {
525 break :blk Type.Pointer.Align{ .Abi = {} };
526 };
527 const ptr_type = try await (async Type.Pointer.get(ira.irb.comp, Type.Pointer.Key{
528 .child_type = child_type,
529 .mut = self.params.mut,
530 .vol = self.params.vol,
531 .size = self.params.size,
532 .alignment = alignment,
533 }) catch unreachable);
534 ptr_type.base.base.deref(ira.irb.comp);
535
536 return ira.irb.buildConstValue(self.base.scope, self.base.span, &ptr_type.base.base);
537 }
538 };
539
323 pub const DeclVar = struct {540 pub const DeclVar = struct {
324 base: Inst,541 base: Inst,
325 params: Params,542 params: Params,
...@@ -351,14 +568,21 @@ pub const Inst = struct {...@@ -351,14 +568,21 @@ pub const Inst = struct {
351568
352 const ir_val_init = IrVal.Init.Unknown;569 const ir_val_init = IrVal.Init.Unknown;
353570
354 pub fn dump(inst: *const CheckVoidStmt) void {}571 pub fn dump(self: *const CheckVoidStmt) void {
572 std.debug.warn("#{}", self.params.target.debug_id);
573 }
355574
356 pub fn hasSideEffects(inst: *const CheckVoidStmt) bool {575 pub fn hasSideEffects(inst: *const CheckVoidStmt) bool {
357 return true;576 return true;
358 }577 }
359578
360 pub fn analyze(self: *const CheckVoidStmt, ira: *Analyze) !*Inst {579 pub fn analyze(self: *const CheckVoidStmt, ira: *Analyze) !*Inst {
361 return error.Unimplemented; // TODO580 const target = try self.params.target.getAsParam();
581 if (target.getKnownType().id != Type.Id.Void) {
582 try ira.addCompileError(self.base.span, "expression value is ignored");
583 return error.SemanticAnalysisFailed;
584 }
585 return ira.irb.buildConstVoid(self.base.scope, self.base.span, true);
362 }586 }
363 };587 };
364588
...@@ -583,7 +807,7 @@ pub const BasicBlock = struct {...@@ -583,7 +807,7 @@ pub const BasicBlock = struct {
583 /// the basic block that this one derives from in analysis807 /// the basic block that this one derives from in analysis
584 parent: ?*BasicBlock,808 parent: ?*BasicBlock,
585809
586 pub fn ref(self: *BasicBlock) void {810 pub fn ref(self: *BasicBlock, builder: *Builder) void {
587 self.ref_count += 1;811 self.ref_count += 1;
588 }812 }
589813
...@@ -724,8 +948,42 @@ pub const Builder = struct {...@@ -724,8 +948,42 @@ pub const Builder = struct {
724 ast.Node.Id.VarDecl => return error.Unimplemented,948 ast.Node.Id.VarDecl => return error.Unimplemented,
725 ast.Node.Id.Defer => return error.Unimplemented,949 ast.Node.Id.Defer => return error.Unimplemented,
726 ast.Node.Id.InfixOp => return error.Unimplemented,950 ast.Node.Id.InfixOp => return error.Unimplemented,
727 ast.Node.Id.PrefixOp => return error.Unimplemented,951 ast.Node.Id.PrefixOp => {
728 ast.Node.Id.SuffixOp => return error.Unimplemented,952 const prefix_op = @fieldParentPtr(ast.Node.PrefixOp, "base", node);
953 switch (prefix_op.op) {
954 ast.Node.PrefixOp.Op.AddressOf => return error.Unimplemented,
955 ast.Node.PrefixOp.Op.ArrayType => |n| return error.Unimplemented,
956 ast.Node.PrefixOp.Op.Await => return error.Unimplemented,
957 ast.Node.PrefixOp.Op.BitNot => return error.Unimplemented,
958 ast.Node.PrefixOp.Op.BoolNot => return error.Unimplemented,
959 ast.Node.PrefixOp.Op.Cancel => return error.Unimplemented,
960 ast.Node.PrefixOp.Op.OptionalType => return error.Unimplemented,
961 ast.Node.PrefixOp.Op.Negation => return error.Unimplemented,
962 ast.Node.PrefixOp.Op.NegationWrap => return error.Unimplemented,
963 ast.Node.PrefixOp.Op.Resume => return error.Unimplemented,
964 ast.Node.PrefixOp.Op.PtrType => |ptr_info| {
965 const inst = try await (async irb.genPtrType(prefix_op, ptr_info, scope) catch unreachable);
966 return irb.lvalWrap(scope, inst, lval);
967 },
968 ast.Node.PrefixOp.Op.SliceType => |ptr_info| return error.Unimplemented,
969 ast.Node.PrefixOp.Op.Try => return error.Unimplemented,
970 }
971 },
972 ast.Node.Id.SuffixOp => {
973 const suffix_op = @fieldParentPtr(ast.Node.SuffixOp, "base", node);
974 switch (suffix_op.op) {
975 @TagType(ast.Node.SuffixOp.Op).Call => |*call| {
976 const inst = try await (async irb.genCall(suffix_op, call, scope) catch unreachable);
977 return irb.lvalWrap(scope, inst, lval);
978 },
979 @TagType(ast.Node.SuffixOp.Op).ArrayAccess => |n| return error.Unimplemented,
980 @TagType(ast.Node.SuffixOp.Op).Slice => |slice| return error.Unimplemented,
981 @TagType(ast.Node.SuffixOp.Op).ArrayInitializer => |init_list| return error.Unimplemented,
982 @TagType(ast.Node.SuffixOp.Op).StructInitializer => |init_list| return error.Unimplemented,
983 @TagType(ast.Node.SuffixOp.Op).Deref => return error.Unimplemented,
984 @TagType(ast.Node.SuffixOp.Op).UnwrapOptional => return error.Unimplemented,
985 }
986 },
729 ast.Node.Id.Switch => return error.Unimplemented,987 ast.Node.Id.Switch => return error.Unimplemented,
730 ast.Node.Id.While => return error.Unimplemented,988 ast.Node.Id.While => return error.Unimplemented,
731 ast.Node.Id.For => return error.Unimplemented,989 ast.Node.Id.For => return error.Unimplemented,
...@@ -744,7 +1002,11 @@ pub const Builder = struct {...@@ -744,7 +1002,11 @@ pub const Builder = struct {
744 return irb.lvalWrap(scope, try irb.genIntLit(int_lit, scope), lval);1002 return irb.lvalWrap(scope, try irb.genIntLit(int_lit, scope), lval);
745 },1003 },
746 ast.Node.Id.FloatLiteral => return error.Unimplemented,1004 ast.Node.Id.FloatLiteral => return error.Unimplemented,
747 ast.Node.Id.StringLiteral => return error.Unimplemented,1005 ast.Node.Id.StringLiteral => {
1006 const str_lit = @fieldParentPtr(ast.Node.StringLiteral, "base", node);
1007 const inst = try await (async irb.genStrLit(str_lit, scope) catch unreachable);
1008 return irb.lvalWrap(scope, inst, lval);
1009 },
748 ast.Node.Id.MultilineStringLiteral => return error.Unimplemented,1010 ast.Node.Id.MultilineStringLiteral => return error.Unimplemented,
749 ast.Node.Id.CharLiteral => return error.Unimplemented,1011 ast.Node.Id.CharLiteral => return error.Unimplemented,
750 ast.Node.Id.BoolLiteral => return error.Unimplemented,1012 ast.Node.Id.BoolLiteral => return error.Unimplemented,
...@@ -789,6 +1051,99 @@ pub const Builder = struct {...@@ -789,6 +1051,99 @@ pub const Builder = struct {
789 }1051 }
790 }1052 }
7911053
1054 async fn genCall(irb: *Builder, suffix_op: *ast.Node.SuffixOp, call: *ast.Node.SuffixOp.Op.Call, scope: *Scope) !*Inst {
1055 const fn_ref = try await (async irb.genNode(suffix_op.lhs, scope, LVal.None) catch unreachable);
1056
1057 const args = try irb.arena().alloc(*Inst, call.params.len);
1058 var it = call.params.iterator(0);
1059 var i: usize = 0;
1060 while (it.next()) |arg_node_ptr| : (i += 1) {
1061 args[i] = try await (async irb.genNode(arg_node_ptr.*, scope, LVal.None) catch unreachable);
1062 }
1063
1064 //bool is_async = node->data.fn_call_expr.is_async;
1065 //IrInstruction *async_allocator = nullptr;
1066 //if (is_async) {
1067 // if (node->data.fn_call_expr.async_allocator) {
1068 // async_allocator = ir_gen_node(irb, node->data.fn_call_expr.async_allocator, scope);
1069 // if (async_allocator == irb->codegen->invalid_instruction)
1070 // return async_allocator;
1071 // }
1072 //}
1073
1074 return irb.build(Inst.Call, scope, Span.token(suffix_op.rtoken), Inst.Call.Params{
1075 .fn_ref = fn_ref,
1076 .args = args,
1077 });
1078 //IrInstruction *fn_call = ir_build_call(irb, scope, node, nullptr, fn_ref, arg_count, args, false, FnInlineAuto, is_async, async_allocator, nullptr);
1079 //return ir_lval_wrap(irb, scope, fn_call, lval);
1080 }
1081
1082 async fn genPtrType(
1083 irb: *Builder,
1084 prefix_op: *ast.Node.PrefixOp,
1085 ptr_info: ast.Node.PrefixOp.PtrInfo,
1086 scope: *Scope,
1087 ) !*Inst {
1088 // TODO port more logic
1089
1090 //assert(node->type == NodeTypePointerType);
1091 //PtrLen ptr_len = (node->data.pointer_type.star_token->id == TokenIdStar ||
1092 // node->data.pointer_type.star_token->id == TokenIdStarStar) ? PtrLenSingle : PtrLenUnknown;
1093 //bool is_const = node->data.pointer_type.is_const;
1094 //bool is_volatile = node->data.pointer_type.is_volatile;
1095 //AstNode *expr_node = node->data.pointer_type.op_expr;
1096 //AstNode *align_expr = node->data.pointer_type.align_expr;
1097
1098 //IrInstruction *align_value;
1099 //if (align_expr != nullptr) {
1100 // align_value = ir_gen_node(irb, align_expr, scope);
1101 // if (align_value == irb->codegen->invalid_instruction)
1102 // return align_value;
1103 //} else {
1104 // align_value = nullptr;
1105 //}
1106 const child_type = try await (async irb.genNode(prefix_op.rhs, scope, LVal.None) catch unreachable);
1107
1108 //uint32_t bit_offset_start = 0;
1109 //if (node->data.pointer_type.bit_offset_start != nullptr) {
1110 // if (!bigint_fits_in_bits(node->data.pointer_type.bit_offset_start, 32, false)) {
1111 // Buf *val_buf = buf_alloc();
1112 // bigint_append_buf(val_buf, node->data.pointer_type.bit_offset_start, 10);
1113 // exec_add_error_node(irb->codegen, irb->exec, node,
1114 // buf_sprintf("value %s too large for u32 bit offset", buf_ptr(val_buf)));
1115 // return irb->codegen->invalid_instruction;
1116 // }
1117 // bit_offset_start = bigint_as_unsigned(node->data.pointer_type.bit_offset_start);
1118 //}
1119
1120 //uint32_t bit_offset_end = 0;
1121 //if (node->data.pointer_type.bit_offset_end != nullptr) {
1122 // if (!bigint_fits_in_bits(node->data.pointer_type.bit_offset_end, 32, false)) {
1123 // Buf *val_buf = buf_alloc();
1124 // bigint_append_buf(val_buf, node->data.pointer_type.bit_offset_end, 10);
1125 // exec_add_error_node(irb->codegen, irb->exec, node,
1126 // buf_sprintf("value %s too large for u32 bit offset", buf_ptr(val_buf)));
1127 // return irb->codegen->invalid_instruction;
1128 // }
1129 // bit_offset_end = bigint_as_unsigned(node->data.pointer_type.bit_offset_end);
1130 //}
1131
1132 //if ((bit_offset_start != 0 || bit_offset_end != 0) && bit_offset_start >= bit_offset_end) {
1133 // exec_add_error_node(irb->codegen, irb->exec, node,
1134 // buf_sprintf("bit offset start must be less than bit offset end"));
1135 // return irb->codegen->invalid_instruction;
1136 //}
1137
1138 return irb.build(Inst.PtrType, scope, Span.node(&prefix_op.base), Inst.PtrType.Params{
1139 .child_type = child_type,
1140 .mut = Type.Pointer.Mut.Mut,
1141 .vol = Type.Pointer.Vol.Non,
1142 .size = Type.Pointer.Size.Many,
1143 .alignment = null,
1144 });
1145 }
1146
792 fn isCompTime(irb: *Builder, target_scope: *Scope) bool {1147 fn isCompTime(irb: *Builder, target_scope: *Scope) bool {
793 if (irb.is_comptime)1148 if (irb.is_comptime)
794 return true;1149 return true;
...@@ -847,6 +1202,56 @@ pub const Builder = struct {...@@ -847,6 +1202,56 @@ pub const Builder = struct {
847 return inst;1202 return inst;
848 }1203 }
8491204
1205 pub async fn genStrLit(irb: *Builder, str_lit: *ast.Node.StringLiteral, scope: *Scope) !*Inst {
1206 const str_token = irb.root_scope.tree.tokenSlice(str_lit.token);
1207 const src_span = Span.token(str_lit.token);
1208
1209 var bad_index: usize = undefined;
1210 var buf = std.zig.parseStringLiteral(irb.comp.gpa(), str_token, &bad_index) catch |err| switch (err) {
1211 error.OutOfMemory => return error.OutOfMemory,
1212 error.InvalidCharacter => {
1213 try irb.comp.addCompileError(
1214 irb.root_scope,
1215 src_span,
1216 "invalid character in string literal: '{c}'",
1217 str_token[bad_index],
1218 );
1219 return error.SemanticAnalysisFailed;
1220 },
1221 };
1222 var buf_cleaned = false;
1223 errdefer if (!buf_cleaned) irb.comp.gpa().free(buf);
1224
1225 if (str_token[0] == 'c') {
1226 // first we add a null
1227 buf = try irb.comp.gpa().realloc(u8, buf, buf.len + 1);
1228 buf[buf.len - 1] = 0;
1229
1230 // next make an array value
1231 const array_val = try await (async Value.Array.createOwnedBuffer(irb.comp, buf) catch unreachable);
1232 buf_cleaned = true;
1233 defer array_val.base.deref(irb.comp);
1234
1235 // then make a pointer value pointing at the first element
1236 const ptr_val = try await (async Value.Ptr.createArrayElemPtr(
1237 irb.comp,
1238 array_val,
1239 Type.Pointer.Mut.Const,
1240 Type.Pointer.Size.Many,
1241 0,
1242 ) catch unreachable);
1243 defer ptr_val.base.deref(irb.comp);
1244
1245 return irb.buildConstValue(scope, src_span, &ptr_val.base);
1246 } else {
1247 const array_val = try await (async Value.Array.createOwnedBuffer(irb.comp, buf) catch unreachable);
1248 buf_cleaned = true;
1249 defer array_val.base.deref(irb.comp);
1250
1251 return irb.buildConstValue(scope, src_span, &array_val.base);
1252 }
1253 }
1254
850 pub async fn genBlock(irb: *Builder, block: *ast.Node.Block, parent_scope: *Scope) !*Inst {1255 pub async fn genBlock(irb: *Builder, block: *ast.Node.Block, parent_scope: *Scope) !*Inst {
851 const block_scope = try Scope.Block.create(irb.comp, parent_scope);1256 const block_scope = try Scope.Block.create(irb.comp, parent_scope);
8521257
...@@ -911,7 +1316,10 @@ pub const Builder = struct {...@@ -911,7 +1316,10 @@ pub const Builder = struct {
911 _ = irb.build(1316 _ = irb.build(
912 Inst.CheckVoidStmt,1317 Inst.CheckVoidStmt,
913 child_scope,1318 child_scope,
914 statement_value.span,1319 Span{
1320 .first = statement_node.firstToken(),
1321 .last = statement_node.lastToken(),
1322 },
915 Inst.CheckVoidStmt.Params{ .target = statement_value },1323 Inst.CheckVoidStmt.Params{ .target = statement_value },
916 );1324 );
917 }1325 }
...@@ -1068,6 +1476,8 @@ pub const Builder = struct {...@@ -1068,6 +1476,8 @@ pub const Builder = struct {
1068 if (result) |primitive_type| {1476 if (result) |primitive_type| {
1069 defer primitive_type.base.deref(irb.comp);1477 defer primitive_type.base.deref(irb.comp);
1070 switch (lval) {1478 switch (lval) {
1479 // if (lval == LValPtr) {
1480 // return ir_build_ref(irb, scope, node, value, false, false);
1071 LVal.Ptr => return error.Unimplemented,1481 LVal.Ptr => return error.Unimplemented,
1072 LVal.None => return irb.buildConstValue(scope, src_span, &primitive_type.base),1482 LVal.None => return irb.buildConstValue(scope, src_span, &primitive_type.base),
1073 }1483 }
...@@ -1079,15 +1489,6 @@ pub const Builder = struct {...@@ -1079,15 +1489,6 @@ pub const Builder = struct {
1079 },1489 },
1080 error.OutOfMemory => return error.OutOfMemory,1490 error.OutOfMemory => return error.OutOfMemory,
1081 }1491 }
1082 //TypeTableEntry *primitive_type = get_primitive_type(irb->codegen, variable_name);
1083 //if (primitive_type != nullptr) {
1084 // IrInstruction *value = ir_build_const_type(irb, scope, node, primitive_type);
1085 // if (lval == LValPtr) {
1086 // return ir_build_ref(irb, scope, node, value, false, false);
1087 // } else {
1088 // return value;
1089 // }
1090 //}
10911492
1092 //VariableTableEntry *var = find_variable(irb->codegen, scope, variable_name);1493 //VariableTableEntry *var = find_variable(irb->codegen, scope, variable_name);
1093 //if (var) {1494 //if (var) {
...@@ -1098,9 +1499,12 @@ pub const Builder = struct {...@@ -1098,9 +1499,12 @@ pub const Builder = struct {
1098 // return ir_build_load_ptr(irb, scope, node, var_ptr);1499 // return ir_build_load_ptr(irb, scope, node, var_ptr);
1099 //}1500 //}
11001501
1101 //Tld *tld = find_decl(irb->codegen, scope, variable_name);1502 if (await (async irb.findDecl(scope, name) catch unreachable)) |decl| {
1102 //if (tld)1503 return irb.build(Inst.DeclRef, scope, src_span, Inst.DeclRef.Params{
1103 // return ir_build_decl_ref(irb, scope, node, tld, lval);1504 .decl = decl,
1505 .lval = lval,
1506 });
1507 }
11041508
1105 //if (node->owner->any_imports_failed) {1509 //if (node->owner->any_imports_failed) {
1106 // // skip the error message since we had a failing import in this file1510 // // skip the error message since we had a failing import in this file
...@@ -1251,8 +1655,26 @@ pub const Builder = struct {...@@ -1251,8 +1655,26 @@ pub const Builder = struct {
1251 const FieldType = comptime @typeOf(@field(I.Params(undefined), @memberName(I.Params, i)));1655 const FieldType = comptime @typeOf(@field(I.Params(undefined), @memberName(I.Params, i)));
1252 switch (FieldType) {1656 switch (FieldType) {
1253 *Inst => @field(inst.params, @memberName(I.Params, i)).ref(self),1657 *Inst => @field(inst.params, @memberName(I.Params, i)).ref(self),
1658 *BasicBlock => @field(inst.params, @memberName(I.Params, i)).ref(self),
1254 ?*Inst => if (@field(inst.params, @memberName(I.Params, i))) |other| other.ref(self),1659 ?*Inst => if (@field(inst.params, @memberName(I.Params, i))) |other| other.ref(self),
1255 else => {},1660 []*Inst => {
1661 // TODO https://github.com/ziglang/zig/issues/1269
1662 for (@field(inst.params, @memberName(I.Params, i))) |other|
1663 other.ref(self);
1664 },
1665 []*BasicBlock => {
1666 // TODO https://github.com/ziglang/zig/issues/1269
1667 for (@field(inst.params, @memberName(I.Params, i))) |other|
1668 other.ref(self);
1669 },
1670 Type.Pointer.Mut,
1671 Type.Pointer.Vol,
1672 Type.Pointer.Size,
1673 LVal,
1674 *Decl,
1675 => {},
1676 // it's ok to add more types here, just make sure any instructions are ref'd appropriately
1677 else => @compileError("unrecognized type in Params: " ++ @typeName(FieldType)),
1256 }1678 }
1257 }1679 }
12581680
...@@ -1348,6 +1770,24 @@ pub const Builder = struct {...@@ -1348,6 +1770,24 @@ pub const Builder = struct {
1348 // is_comptime);1770 // is_comptime);
1349 //// the above blocks are rendered by ir_gen after the rest of codegen1771 //// the above blocks are rendered by ir_gen after the rest of codegen
1350 }1772 }
1773
1774 async fn findDecl(irb: *Builder, scope: *Scope, name: []const u8) ?*Decl {
1775 var s = scope;
1776 while (true) {
1777 switch (s.id) {
1778 Scope.Id.Decls => {
1779 const decls = @fieldParentPtr(Scope.Decls, "base", s);
1780 const table = await (async decls.getTableReadOnly() catch unreachable);
1781 if (table.get(name)) |entry| {
1782 return entry.value;
1783 }
1784 },
1785 Scope.Id.Root => return null,
1786 else => {},
1787 }
1788 s = s.parent.?;
1789 }
1790 }
1351};1791};
13521792
1353const Analyze = struct {1793const Analyze = struct {
...@@ -1930,7 +2370,6 @@ const Analyze = struct {...@@ -1930,7 +2370,6 @@ const Analyze = struct {
1930 ptr_mut: Value.Ptr.Mut,2370 ptr_mut: Value.Ptr.Mut,
1931 mut: Type.Pointer.Mut,2371 mut: Type.Pointer.Mut,
1932 volatility: Type.Pointer.Vol,2372 volatility: Type.Pointer.Vol,
1933 ptr_align: u32,
1934 ) Analyze.Error!*Inst {2373 ) Analyze.Error!*Inst {
1935 return error.Unimplemented;2374 return error.Unimplemented;
1936 }2375 }
...@@ -1945,7 +2384,7 @@ pub async fn gen(...@@ -1945,7 +2384,7 @@ pub async fn gen(
1945 errdefer irb.abort();2384 errdefer irb.abort();
19462385
1947 const entry_block = try irb.createBasicBlock(scope, c"Entry");2386 const entry_block = try irb.createBasicBlock(scope, c"Entry");
1948 entry_block.ref(); // Entry block gets a reference because we enter it to begin.2387 entry_block.ref(&irb); // Entry block gets a reference because we enter it to begin.
1949 try irb.setCursorAtEndAndAppendBlock(entry_block);2388 try irb.setCursorAtEndAndAppendBlock(entry_block);
19502389
1951 const result = try await (async irb.genNode(body_node, scope, LVal.None) catch unreachable);2390 const result = try await (async irb.genNode(body_node, scope, LVal.None) catch unreachable);
...@@ -1965,7 +2404,7 @@ pub async fn analyze(comp: *Compilation, old_code: *Code, expected_type: ?*Type)...@@ -1965,7 +2404,7 @@ pub async fn analyze(comp: *Compilation, old_code: *Code, expected_type: ?*Type)
1965 errdefer ira.abort();2404 errdefer ira.abort();
19662405
1967 const new_entry_bb = try ira.getNewBasicBlock(old_entry_bb, null);2406 const new_entry_bb = try ira.getNewBasicBlock(old_entry_bb, null);
1968 new_entry_bb.ref();2407 new_entry_bb.ref(&ira.irb);
19692408
1970 ira.irb.current_basic_block = new_entry_bb;2409 ira.irb.current_basic_block = new_entry_bb;
19712410
...@@ -1979,7 +2418,8 @@ pub async fn analyze(comp: *Compilation, old_code: *Code, expected_type: ?*Type)...@@ -1979,7 +2418,8 @@ pub async fn analyze(comp: *Compilation, old_code: *Code, expected_type: ?*Type)
1979 continue;2418 continue;
1980 }2419 }
19812420
1982 const return_inst = try old_instruction.analyze(&ira);2421 const return_inst = try await (async old_instruction.analyze(&ira) catch unreachable);
2422 assert(return_inst.val != IrVal.Unknown); // at least the type should be known at this point
1983 return_inst.linkToParent(old_instruction);2423 return_inst.linkToParent(old_instruction);
1984 // Note: if we ever modify the above to handle error.CompileError by continuing analysis,2424 // Note: if we ever modify the above to handle error.CompileError by continuing analysis,
1985 // then here we want to check if ira.isCompTime() and return early if true2425 // then here we want to check if ira.isCompTime() and return early if true
src-self-hosted/llvm.zig+37-1
...@@ -23,12 +23,17 @@ pub const TargetMachineRef = removeNullability(c.LLVMTargetMachineRef);...@@ -23,12 +23,17 @@ pub const TargetMachineRef = removeNullability(c.LLVMTargetMachineRef);
23pub const TargetDataRef = removeNullability(c.LLVMTargetDataRef);23pub const TargetDataRef = removeNullability(c.LLVMTargetDataRef);
24pub const DIBuilder = c.ZigLLVMDIBuilder;24pub const DIBuilder = c.ZigLLVMDIBuilder;
2525
26pub const ABIAlignmentOfType = c.LLVMABIAlignmentOfType;
26pub const AddAttributeAtIndex = c.LLVMAddAttributeAtIndex;27pub const AddAttributeAtIndex = c.LLVMAddAttributeAtIndex;
27pub const AddFunction = c.LLVMAddFunction;28pub const AddFunction = c.LLVMAddFunction;
29pub const AddGlobal = c.LLVMAddGlobal;
28pub const AddModuleCodeViewFlag = c.ZigLLVMAddModuleCodeViewFlag;30pub const AddModuleCodeViewFlag = c.ZigLLVMAddModuleCodeViewFlag;
29pub const AddModuleDebugInfoFlag = c.ZigLLVMAddModuleDebugInfoFlag;31pub const AddModuleDebugInfoFlag = c.ZigLLVMAddModuleDebugInfoFlag;
32pub const ArrayType = c.LLVMArrayType;
30pub const ClearCurrentDebugLocation = c.ZigLLVMClearCurrentDebugLocation;33pub const ClearCurrentDebugLocation = c.ZigLLVMClearCurrentDebugLocation;
31pub const ConstAllOnes = c.LLVMConstAllOnes;34pub const ConstAllOnes = c.LLVMConstAllOnes;
35pub const ConstArray = c.LLVMConstArray;
36pub const ConstBitCast = c.LLVMConstBitCast;
32pub const ConstInt = c.LLVMConstInt;37pub const ConstInt = c.LLVMConstInt;
33pub const ConstIntOfArbitraryPrecision = c.LLVMConstIntOfArbitraryPrecision;38pub const ConstIntOfArbitraryPrecision = c.LLVMConstIntOfArbitraryPrecision;
34pub const ConstNeg = c.LLVMConstNeg;39pub const ConstNeg = c.LLVMConstNeg;
...@@ -59,6 +64,7 @@ pub const GetEnumAttributeKindForName = c.LLVMGetEnumAttributeKindForName;...@@ -59,6 +64,7 @@ pub const GetEnumAttributeKindForName = c.LLVMGetEnumAttributeKindForName;
59pub const GetHostCPUName = c.ZigLLVMGetHostCPUName;64pub const GetHostCPUName = c.ZigLLVMGetHostCPUName;
60pub const GetMDKindIDInContext = c.LLVMGetMDKindIDInContext;65pub const GetMDKindIDInContext = c.LLVMGetMDKindIDInContext;
61pub const GetNativeFeatures = c.ZigLLVMGetNativeFeatures;66pub const GetNativeFeatures = c.ZigLLVMGetNativeFeatures;
67pub const GetUndef = c.LLVMGetUndef;
62pub const HalfTypeInContext = c.LLVMHalfTypeInContext;68pub const HalfTypeInContext = c.LLVMHalfTypeInContext;
63pub const InitializeAllAsmParsers = c.LLVMInitializeAllAsmParsers;69pub const InitializeAllAsmParsers = c.LLVMInitializeAllAsmParsers;
64pub const InitializeAllAsmPrinters = c.LLVMInitializeAllAsmPrinters;70pub const InitializeAllAsmPrinters = c.LLVMInitializeAllAsmPrinters;
...@@ -81,14 +87,24 @@ pub const MDStringInContext = c.LLVMMDStringInContext;...@@ -81,14 +87,24 @@ pub const MDStringInContext = c.LLVMMDStringInContext;
81pub const MetadataTypeInContext = c.LLVMMetadataTypeInContext;87pub const MetadataTypeInContext = c.LLVMMetadataTypeInContext;
82pub const ModuleCreateWithNameInContext = c.LLVMModuleCreateWithNameInContext;88pub const ModuleCreateWithNameInContext = c.LLVMModuleCreateWithNameInContext;
83pub const PPCFP128TypeInContext = c.LLVMPPCFP128TypeInContext;89pub const PPCFP128TypeInContext = c.LLVMPPCFP128TypeInContext;
90pub const PointerType = c.LLVMPointerType;
91pub const SetAlignment = c.LLVMSetAlignment;
84pub const SetDataLayout = c.LLVMSetDataLayout;92pub const SetDataLayout = c.LLVMSetDataLayout;
93pub const SetGlobalConstant = c.LLVMSetGlobalConstant;
94pub const SetInitializer = c.LLVMSetInitializer;
95pub const SetLinkage = c.LLVMSetLinkage;
85pub const SetTarget = c.LLVMSetTarget;96pub const SetTarget = c.LLVMSetTarget;
97pub const SetUnnamedAddr = c.LLVMSetUnnamedAddr;
86pub const StructTypeInContext = c.LLVMStructTypeInContext;98pub const StructTypeInContext = c.LLVMStructTypeInContext;
87pub const TokenTypeInContext = c.LLVMTokenTypeInContext;99pub const TokenTypeInContext = c.LLVMTokenTypeInContext;
100pub const TypeOf = c.LLVMTypeOf;
88pub const VoidTypeInContext = c.LLVMVoidTypeInContext;101pub const VoidTypeInContext = c.LLVMVoidTypeInContext;
89pub const X86FP80TypeInContext = c.LLVMX86FP80TypeInContext;102pub const X86FP80TypeInContext = c.LLVMX86FP80TypeInContext;
90pub const X86MMXTypeInContext = c.LLVMX86MMXTypeInContext;103pub const X86MMXTypeInContext = c.LLVMX86MMXTypeInContext;
91104
105pub const ConstInBoundsGEP = LLVMConstInBoundsGEP;
106pub extern fn LLVMConstInBoundsGEP(ConstantVal: ValueRef, ConstantIndices: [*]ValueRef, NumIndices: c_uint) ?ValueRef;
107
92pub const GetTargetFromTriple = LLVMGetTargetFromTriple;108pub const GetTargetFromTriple = LLVMGetTargetFromTriple;
93extern fn LLVMGetTargetFromTriple(Triple: [*]const u8, T: *TargetRef, ErrorMessage: ?*[*]u8) Bool;109extern fn LLVMGetTargetFromTriple(Triple: [*]const u8, T: *TargetRef, ErrorMessage: ?*[*]u8) Bool;
94110
...@@ -145,13 +161,28 @@ pub const EmitBinary = EmitOutputType.ZigLLVM_EmitBinary;...@@ -145,13 +161,28 @@ pub const EmitBinary = EmitOutputType.ZigLLVM_EmitBinary;
145pub const EmitLLVMIr = EmitOutputType.ZigLLVM_EmitLLVMIr;161pub const EmitLLVMIr = EmitOutputType.ZigLLVM_EmitLLVMIr;
146pub const EmitOutputType = c.ZigLLVM_EmitOutputType;162pub const EmitOutputType = c.ZigLLVM_EmitOutputType;
147163
164pub const CCallConv = c.LLVMCCallConv;
165pub const FastCallConv = c.LLVMFastCallConv;
166pub const ColdCallConv = c.LLVMColdCallConv;
167pub const WebKitJSCallConv = c.LLVMWebKitJSCallConv;
168pub const AnyRegCallConv = c.LLVMAnyRegCallConv;
169pub const X86StdcallCallConv = c.LLVMX86StdcallCallConv;
170pub const X86FastcallCallConv = c.LLVMX86FastcallCallConv;
171pub const CallConv = c.LLVMCallConv;
172
173pub const FnInline = extern enum {
174 Auto,
175 Always,
176 Never,
177};
178
148fn removeNullability(comptime T: type) type {179fn removeNullability(comptime T: type) type {
149 comptime assert(@typeId(T) == builtin.TypeId.Optional);180 comptime assert(@typeId(T) == builtin.TypeId.Optional);
150 return T.Child;181 return T.Child;
151}182}
152183
153pub const BuildRet = LLVMBuildRet;184pub const BuildRet = LLVMBuildRet;
154extern fn LLVMBuildRet(arg0: BuilderRef, V: ?ValueRef) ValueRef;185extern fn LLVMBuildRet(arg0: BuilderRef, V: ?ValueRef) ?ValueRef;
155186
156pub const TargetMachineEmitToFile = ZigLLVMTargetMachineEmitToFile;187pub const TargetMachineEmitToFile = ZigLLVMTargetMachineEmitToFile;
157extern fn ZigLLVMTargetMachineEmitToFile(188extern fn ZigLLVMTargetMachineEmitToFile(
...@@ -163,3 +194,8 @@ extern fn ZigLLVMTargetMachineEmitToFile(...@@ -163,3 +194,8 @@ extern fn ZigLLVMTargetMachineEmitToFile(
163 is_debug: bool,194 is_debug: bool,
164 is_small: bool,195 is_small: bool,
165) bool;196) bool;
197
198pub const BuildCall = ZigLLVMBuildCall;
199extern fn ZigLLVMBuildCall(B: BuilderRef, Fn: ValueRef, Args: [*]ValueRef, NumArgs: c_uint, CC: c_uint, fn_inline: FnInline, Name: [*]const u8) ?ValueRef;
200
201pub const PrivateLinkage = c.LLVMLinkage.LLVMPrivateLinkage;
src-self-hosted/scope.zig+17-8
...@@ -9,6 +9,7 @@ const Value = @import("value.zig").Value;...@@ -9,6 +9,7 @@ const Value = @import("value.zig").Value;
9const ir = @import("ir.zig");9const ir = @import("ir.zig");
10const Span = @import("errmsg.zig").Span;10const Span = @import("errmsg.zig").Span;
11const assert = std.debug.assert;11const assert = std.debug.assert;
12const event = std.event;
1213
13pub const Scope = struct {14pub const Scope = struct {
14 id: Id,15 id: Id,
...@@ -123,7 +124,15 @@ pub const Scope = struct {...@@ -123,7 +124,15 @@ pub const Scope = struct {
123124
124 pub const Decls = struct {125 pub const Decls = struct {
125 base: Scope,126 base: Scope,
126 table: Decl.Table,127
128 /// The lock must be respected for writing. However once name_future resolves,
129 /// readers can freely access it.
130 table: event.Locked(Decl.Table),
131
132 /// Once this future is resolved, the table is complete and available for unlocked
133 /// read-only access. It does not mean all the decls are resolved; it means only that
134 /// the table has all the names. Each decl in the table has its own resolution state.
135 name_future: event.Future(void),
127136
128 /// Creates a Decls scope with 1 reference137 /// Creates a Decls scope with 1 reference
129 pub fn create(comp: *Compilation, parent: *Scope) !*Decls {138 pub fn create(comp: *Compilation, parent: *Scope) !*Decls {
...@@ -133,15 +142,10 @@ pub const Scope = struct {...@@ -133,15 +142,10 @@ pub const Scope = struct {
133 .parent = parent,142 .parent = parent,
134 .ref_count = 1,143 .ref_count = 1,
135 },144 },
136 .table = undefined,145 .table = event.Locked(Decl.Table).init(comp.loop, Decl.Table.init(comp.gpa())),
146 .name_future = event.Future(void).init(comp.loop),
137 });147 });
138 errdefer comp.gpa().destroy(self);
139
140 self.table = Decl.Table.init(comp.gpa());
141 errdefer self.table.deinit();
142
143 parent.ref();148 parent.ref();
144
145 return self;149 return self;
146 }150 }
147151
...@@ -149,6 +153,11 @@ pub const Scope = struct {...@@ -149,6 +153,11 @@ pub const Scope = struct {
149 self.table.deinit();153 self.table.deinit();
150 comp.gpa().destroy(self);154 comp.gpa().destroy(self);
151 }155 }
156
157 pub async fn getTableReadOnly(self: *Decls) *Decl.Table {
158 _ = await (async self.name_future.get() catch unreachable);
159 return &self.table.private_data;
160 }
152 };161 };
153162
154 pub const Block = struct {163 pub const Block = struct {
src-self-hosted/test.zig+1
...@@ -14,6 +14,7 @@ test "compile errors" {...@@ -14,6 +14,7 @@ test "compile errors" {
14 defer ctx.deinit();14 defer ctx.deinit();
1515
16 try @import("../test/stage2/compile_errors.zig").addCases(&ctx);16 try @import("../test/stage2/compile_errors.zig").addCases(&ctx);
17 //try @import("../test/stage2/compare_output.zig").addCases(&ctx);
1718
18 try ctx.run();19 try ctx.run();
19}20}
src-self-hosted/type.zig+306-58
...@@ -4,12 +4,17 @@ const Scope = @import("scope.zig").Scope;...@@ -4,12 +4,17 @@ const Scope = @import("scope.zig").Scope;
4const Compilation = @import("compilation.zig").Compilation;4const Compilation = @import("compilation.zig").Compilation;
5const Value = @import("value.zig").Value;5const Value = @import("value.zig").Value;
6const llvm = @import("llvm.zig");6const llvm = @import("llvm.zig");
7const ObjectFile = @import("codegen.zig").ObjectFile;7const event = std.event;
8const Allocator = std.mem.Allocator;
9const assert = std.debug.assert;
810
9pub const Type = struct {11pub const Type = struct {
10 base: Value,12 base: Value,
11 id: Id,13 id: Id,
12 name: []const u8,14 name: []const u8,
15 abi_alignment: AbiAlignment,
16
17 pub const AbiAlignment = event.Future(error{OutOfMemory}!u32);
1318
14 pub const Id = builtin.TypeId;19 pub const Id = builtin.TypeId;
1520
...@@ -43,33 +48,37 @@ pub const Type = struct {...@@ -43,33 +48,37 @@ pub const Type = struct {
43 }48 }
44 }49 }
4550
46 pub fn getLlvmType(base: *Type, ofile: *ObjectFile) (error{OutOfMemory}!llvm.TypeRef) {51 pub fn getLlvmType(
52 base: *Type,
53 allocator: *Allocator,
54 llvm_context: llvm.ContextRef,
55 ) (error{OutOfMemory}!llvm.TypeRef) {
47 switch (base.id) {56 switch (base.id) {
48 Id.Struct => return @fieldParentPtr(Struct, "base", base).getLlvmType(ofile),57 Id.Struct => return @fieldParentPtr(Struct, "base", base).getLlvmType(allocator, llvm_context),
49 Id.Fn => return @fieldParentPtr(Fn, "base", base).getLlvmType(ofile),58 Id.Fn => return @fieldParentPtr(Fn, "base", base).getLlvmType(allocator, llvm_context),
50 Id.Type => unreachable,59 Id.Type => unreachable,
51 Id.Void => unreachable,60 Id.Void => unreachable,
52 Id.Bool => return @fieldParentPtr(Bool, "base", base).getLlvmType(ofile),61 Id.Bool => return @fieldParentPtr(Bool, "base", base).getLlvmType(allocator, llvm_context),
53 Id.NoReturn => unreachable,62 Id.NoReturn => unreachable,
54 Id.Int => return @fieldParentPtr(Int, "base", base).getLlvmType(ofile),63 Id.Int => return @fieldParentPtr(Int, "base", base).getLlvmType(allocator, llvm_context),
55 Id.Float => return @fieldParentPtr(Float, "base", base).getLlvmType(ofile),64 Id.Float => return @fieldParentPtr(Float, "base", base).getLlvmType(allocator, llvm_context),
56 Id.Pointer => return @fieldParentPtr(Pointer, "base", base).getLlvmType(ofile),65 Id.Pointer => return @fieldParentPtr(Pointer, "base", base).getLlvmType(allocator, llvm_context),
57 Id.Array => return @fieldParentPtr(Array, "base", base).getLlvmType(ofile),66 Id.Array => return @fieldParentPtr(Array, "base", base).getLlvmType(allocator, llvm_context),
58 Id.ComptimeFloat => unreachable,67 Id.ComptimeFloat => unreachable,
59 Id.ComptimeInt => unreachable,68 Id.ComptimeInt => unreachable,
60 Id.Undefined => unreachable,69 Id.Undefined => unreachable,
61 Id.Null => unreachable,70 Id.Null => unreachable,
62 Id.Optional => return @fieldParentPtr(Optional, "base", base).getLlvmType(ofile),71 Id.Optional => return @fieldParentPtr(Optional, "base", base).getLlvmType(allocator, llvm_context),
63 Id.ErrorUnion => return @fieldParentPtr(ErrorUnion, "base", base).getLlvmType(ofile),72 Id.ErrorUnion => return @fieldParentPtr(ErrorUnion, "base", base).getLlvmType(allocator, llvm_context),
64 Id.ErrorSet => return @fieldParentPtr(ErrorSet, "base", base).getLlvmType(ofile),73 Id.ErrorSet => return @fieldParentPtr(ErrorSet, "base", base).getLlvmType(allocator, llvm_context),
65 Id.Enum => return @fieldParentPtr(Enum, "base", base).getLlvmType(ofile),74 Id.Enum => return @fieldParentPtr(Enum, "base", base).getLlvmType(allocator, llvm_context),
66 Id.Union => return @fieldParentPtr(Union, "base", base).getLlvmType(ofile),75 Id.Union => return @fieldParentPtr(Union, "base", base).getLlvmType(allocator, llvm_context),
67 Id.Namespace => unreachable,76 Id.Namespace => unreachable,
68 Id.Block => unreachable,77 Id.Block => unreachable,
69 Id.BoundFn => return @fieldParentPtr(BoundFn, "base", base).getLlvmType(ofile),78 Id.BoundFn => return @fieldParentPtr(BoundFn, "base", base).getLlvmType(allocator, llvm_context),
70 Id.ArgTuple => unreachable,79 Id.ArgTuple => unreachable,
71 Id.Opaque => return @fieldParentPtr(Opaque, "base", base).getLlvmType(ofile),80 Id.Opaque => return @fieldParentPtr(Opaque, "base", base).getLlvmType(allocator, llvm_context),
72 Id.Promise => return @fieldParentPtr(Promise, "base", base).getLlvmType(ofile),81 Id.Promise => return @fieldParentPtr(Promise, "base", base).getLlvmType(allocator, llvm_context),
73 }82 }
74 }83 }
7584
...@@ -156,16 +165,45 @@ pub const Type = struct {...@@ -156,16 +165,45 @@ pub const Type = struct {
156 base.* = Type{165 base.* = Type{
157 .base = Value{166 .base = Value{
158 .id = Value.Id.Type,167 .id = Value.Id.Type,
159 .typeof = &MetaType.get(comp).base,168 .typ = &MetaType.get(comp).base,
160 .ref_count = std.atomic.Int(usize).init(1),169 .ref_count = std.atomic.Int(usize).init(1),
161 },170 },
162 .id = id,171 .id = id,
163 .name = name,172 .name = name,
173 .abi_alignment = AbiAlignment.init(comp.loop),
164 };174 };
165 }175 }
166176
167 pub fn getAbiAlignment(base: *Type, comp: *Compilation) u32 {177 /// If you happen to have an llvm context handy, use getAbiAlignmentInContext instead.
168 @panic("TODO getAbiAlignment");178 /// Otherwise, this one will grab one from the pool and then release it.
179 pub async fn getAbiAlignment(base: *Type, comp: *Compilation) !u32 {
180 if (await (async base.abi_alignment.start() catch unreachable)) |ptr| return ptr.*;
181
182 {
183 const held = try comp.event_loop_local.getAnyLlvmContext();
184 defer held.release(comp.event_loop_local);
185
186 const llvm_context = held.node.data;
187
188 base.abi_alignment.data = await (async base.resolveAbiAlignment(comp, llvm_context) catch unreachable);
189 }
190 base.abi_alignment.resolve();
191 return base.abi_alignment.data;
192 }
193
194 /// If you have an llvm conext handy, you can use it here.
195 pub async fn getAbiAlignmentInContext(base: *Type, comp: *Compilation, llvm_context: llvm.ContextRef) !u32 {
196 if (await (async base.abi_alignment.start() catch unreachable)) |ptr| return ptr.*;
197
198 base.abi_alignment.data = await (async base.resolveAbiAlignment(comp, llvm_context) catch unreachable);
199 base.abi_alignment.resolve();
200 return base.abi_alignment.data;
201 }
202
203 /// Lower level function that does the work. See getAbiAlignment.
204 async fn resolveAbiAlignment(base: *Type, comp: *Compilation, llvm_context: llvm.ContextRef) !u32 {
205 const llvm_type = try base.getLlvmType(comp.gpa(), llvm_context);
206 return @intCast(u32, llvm.ABIAlignmentOfType(comp.target_data_ref, llvm_type));
169 }207 }
170208
171 pub const Struct = struct {209 pub const Struct = struct {
...@@ -176,7 +214,7 @@ pub const Type = struct {...@@ -176,7 +214,7 @@ pub const Type = struct {
176 comp.gpa().destroy(self);214 comp.gpa().destroy(self);
177 }215 }
178216
179 pub fn getLlvmType(self: *Struct, ofile: *ObjectFile) llvm.TypeRef {217 pub fn getLlvmType(self: *Struct, allocator: *Allocator, llvm_context: llvm.ContextRef) llvm.TypeRef {
180 @panic("TODO");218 @panic("TODO");
181 }219 }
182 };220 };
...@@ -189,7 +227,7 @@ pub const Type = struct {...@@ -189,7 +227,7 @@ pub const Type = struct {
189227
190 pub const Param = struct {228 pub const Param = struct {
191 is_noalias: bool,229 is_noalias: bool,
192 typeof: *Type,230 typ: *Type,
193 };231 };
194232
195 pub fn create(comp: *Compilation, return_type: *Type, params: []Param, is_var_args: bool) !*Fn {233 pub fn create(comp: *Compilation, return_type: *Type, params: []Param, is_var_args: bool) !*Fn {
...@@ -205,7 +243,7 @@ pub const Type = struct {...@@ -205,7 +243,7 @@ pub const Type = struct {
205243
206 result.return_type.base.ref();244 result.return_type.base.ref();
207 for (result.params) |param| {245 for (result.params) |param| {
208 param.typeof.base.ref();246 param.typ.base.ref();
209 }247 }
210 return result;248 return result;
211 }249 }
...@@ -213,20 +251,20 @@ pub const Type = struct {...@@ -213,20 +251,20 @@ pub const Type = struct {
213 pub fn destroy(self: *Fn, comp: *Compilation) void {251 pub fn destroy(self: *Fn, comp: *Compilation) void {
214 self.return_type.base.deref(comp);252 self.return_type.base.deref(comp);
215 for (self.params) |param| {253 for (self.params) |param| {
216 param.typeof.base.deref(comp);254 param.typ.base.deref(comp);
217 }255 }
218 comp.gpa().destroy(self);256 comp.gpa().destroy(self);
219 }257 }
220258
221 pub fn getLlvmType(self: *Fn, ofile: *ObjectFile) !llvm.TypeRef {259 pub fn getLlvmType(self: *Fn, allocator: *Allocator, llvm_context: llvm.ContextRef) !llvm.TypeRef {
222 const llvm_return_type = switch (self.return_type.id) {260 const llvm_return_type = switch (self.return_type.id) {
223 Type.Id.Void => llvm.VoidTypeInContext(ofile.context) orelse return error.OutOfMemory,261 Type.Id.Void => llvm.VoidTypeInContext(llvm_context) orelse return error.OutOfMemory,
224 else => try self.return_type.getLlvmType(ofile),262 else => try self.return_type.getLlvmType(allocator, llvm_context),
225 };263 };
226 const llvm_param_types = try ofile.gpa().alloc(llvm.TypeRef, self.params.len);264 const llvm_param_types = try allocator.alloc(llvm.TypeRef, self.params.len);
227 defer ofile.gpa().free(llvm_param_types);265 defer allocator.free(llvm_param_types);
228 for (llvm_param_types) |*llvm_param_type, i| {266 for (llvm_param_types) |*llvm_param_type, i| {
229 llvm_param_type.* = try self.params[i].typeof.getLlvmType(ofile);267 llvm_param_type.* = try self.params[i].typ.getLlvmType(allocator, llvm_context);
230 }268 }
231269
232 return llvm.FunctionType(270 return llvm.FunctionType(
...@@ -280,7 +318,7 @@ pub const Type = struct {...@@ -280,7 +318,7 @@ pub const Type = struct {
280 comp.gpa().destroy(self);318 comp.gpa().destroy(self);
281 }319 }
282320
283 pub fn getLlvmType(self: *Bool, ofile: *ObjectFile) llvm.TypeRef {321 pub fn getLlvmType(self: *Bool, allocator: *Allocator, llvm_context: llvm.ContextRef) llvm.TypeRef {
284 @panic("TODO");322 @panic("TODO");
285 }323 }
286 };324 };
...@@ -318,6 +356,11 @@ pub const Type = struct {...@@ -318,6 +356,11 @@ pub const Type = struct {
318 }356 }
319 };357 };
320358
359 pub fn get_u8(comp: *Compilation) *Int {
360 comp.u8_type.base.base.ref();
361 return comp.u8_type;
362 }
363
321 pub async fn get(comp: *Compilation, key: Key) !*Int {364 pub async fn get(comp: *Compilation, key: Key) !*Int {
322 {365 {
323 const held = await (async comp.int_type_table.acquire() catch unreachable);366 const held = await (async comp.int_type_table.acquire() catch unreachable);
...@@ -371,8 +414,8 @@ pub const Type = struct {...@@ -371,8 +414,8 @@ pub const Type = struct {
371 comp.gpa().destroy(self);414 comp.gpa().destroy(self);
372 }415 }
373416
374 pub fn getLlvmType(self: *Int, ofile: *ObjectFile) !llvm.TypeRef {417 pub fn getLlvmType(self: *Int, allocator: *Allocator, llvm_context: llvm.ContextRef) !llvm.TypeRef {
375 return llvm.IntTypeInContext(ofile.context, self.key.bit_count) orelse return error.OutOfMemory;418 return llvm.IntTypeInContext(llvm_context, self.key.bit_count) orelse return error.OutOfMemory;
376 }419 }
377 };420 };
378421
...@@ -383,56 +426,236 @@ pub const Type = struct {...@@ -383,56 +426,236 @@ pub const Type = struct {
383 comp.gpa().destroy(self);426 comp.gpa().destroy(self);
384 }427 }
385428
386 pub fn getLlvmType(self: *Float, ofile: *ObjectFile) llvm.TypeRef {429 pub fn getLlvmType(self: *Float, allocator: *Allocator, llvm_context: llvm.ContextRef) llvm.TypeRef {
387 @panic("TODO");430 @panic("TODO");
388 }431 }
389 };432 };
390 pub const Pointer = struct {433 pub const Pointer = struct {
391 base: Type,434 base: Type,
392 mut: Mut,435 key: Key,
393 vol: Vol,436 garbage_node: std.atomic.Stack(*Pointer).Node,
394 size: Size,437
395 alignment: u32,438 pub const Key = struct {
439 child_type: *Type,
440 mut: Mut,
441 vol: Vol,
442 size: Size,
443 alignment: Align,
444
445 pub fn hash(self: *const Key) u32 {
446 const align_hash = switch (self.alignment) {
447 Align.Abi => 0xf201c090,
448 Align.Override => |x| x,
449 };
450 return hash_usize(@ptrToInt(self.child_type)) *%
451 hash_enum(self.mut) *%
452 hash_enum(self.vol) *%
453 hash_enum(self.size) *%
454 align_hash;
455 }
456
457 pub fn eql(self: *const Key, other: *const Key) bool {
458 if (self.child_type != other.child_type or
459 self.mut != other.mut or
460 self.vol != other.vol or
461 self.size != other.size or
462 @TagType(Align)(self.alignment) != @TagType(Align)(other.alignment))
463 {
464 return false;
465 }
466 switch (self.alignment) {
467 Align.Abi => return true,
468 Align.Override => |x| return x == other.alignment.Override,
469 }
470 }
471 };
396472
397 pub const Mut = enum {473 pub const Mut = enum {
398 Mut,474 Mut,
399 Const,475 Const,
400 };476 };
477
401 pub const Vol = enum {478 pub const Vol = enum {
402 Non,479 Non,
403 Volatile,480 Volatile,
404 };481 };
482
483 pub const Align = union(enum) {
484 Abi,
485 Override: u32,
486 };
487
405 pub const Size = builtin.TypeInfo.Pointer.Size;488 pub const Size = builtin.TypeInfo.Pointer.Size;
406489
407 pub fn destroy(self: *Pointer, comp: *Compilation) void {490 pub fn destroy(self: *Pointer, comp: *Compilation) void {
491 self.garbage_node = std.atomic.Stack(*Pointer).Node{
492 .data = self,
493 .next = undefined,
494 };
495 comp.registerGarbage(Pointer, &self.garbage_node);
496 }
497
498 pub async fn gcDestroy(self: *Pointer, comp: *Compilation) void {
499 {
500 const held = await (async comp.ptr_type_table.acquire() catch unreachable);
501 defer held.release();
502
503 _ = held.value.remove(&self.key).?;
504 }
505 self.key.child_type.base.deref(comp);
408 comp.gpa().destroy(self);506 comp.gpa().destroy(self);
409 }507 }
410508
411 pub fn get(509 pub async fn getAlignAsInt(self: *Pointer, comp: *Compilation) u32 {
510 switch (self.key.alignment) {
511 Align.Abi => return await (async self.key.child_type.getAbiAlignment(comp) catch unreachable),
512 Align.Override => |alignment| return alignment,
513 }
514 }
515
516 pub async fn get(
412 comp: *Compilation,517 comp: *Compilation,
413 elem_type: *Type,518 key: Key,
414 mut: Mut,519 ) !*Pointer {
415 vol: Vol,520 var normal_key = key;
416 size: Size,521 switch (key.alignment) {
417 alignment: u32,522 Align.Abi => {},
418 ) *Pointer {523 Align.Override => |alignment| {
419 @panic("TODO get pointer");524 const abi_align = try await (async key.child_type.getAbiAlignment(comp) catch unreachable);
525 if (abi_align == alignment) {
526 normal_key.alignment = Align.Abi;
527 }
528 },
529 }
530 {
531 const held = await (async comp.ptr_type_table.acquire() catch unreachable);
532 defer held.release();
533
534 if (held.value.get(&normal_key)) |entry| {
535 entry.value.base.base.ref();
536 return entry.value;
537 }
538 }
539
540 const self = try comp.gpa().create(Pointer{
541 .base = undefined,
542 .key = normal_key,
543 .garbage_node = undefined,
544 });
545 errdefer comp.gpa().destroy(self);
546
547 const size_str = switch (self.key.size) {
548 Size.One => "*",
549 Size.Many => "[*]",
550 Size.Slice => "[]",
551 };
552 const mut_str = switch (self.key.mut) {
553 Mut.Const => "const ",
554 Mut.Mut => "",
555 };
556 const vol_str = switch (self.key.vol) {
557 Vol.Volatile => "volatile ",
558 Vol.Non => "",
559 };
560 const name = switch (self.key.alignment) {
561 Align.Abi => try std.fmt.allocPrint(
562 comp.gpa(),
563 "{}{}{}{}",
564 size_str,
565 mut_str,
566 vol_str,
567 self.key.child_type.name,
568 ),
569 Align.Override => |alignment| try std.fmt.allocPrint(
570 comp.gpa(),
571 "{}align<{}> {}{}{}",
572 size_str,
573 alignment,
574 mut_str,
575 vol_str,
576 self.key.child_type.name,
577 ),
578 };
579 errdefer comp.gpa().free(name);
580
581 self.base.init(comp, Id.Pointer, name);
582
583 {
584 const held = await (async comp.ptr_type_table.acquire() catch unreachable);
585 defer held.release();
586
587 _ = try held.value.put(&self.key, self);
588 }
589 return self;
420 }590 }
421591
422 pub fn getLlvmType(self: *Pointer, ofile: *ObjectFile) llvm.TypeRef {592 pub fn getLlvmType(self: *Pointer, allocator: *Allocator, llvm_context: llvm.ContextRef) !llvm.TypeRef {
423 @panic("TODO");593 const elem_llvm_type = try self.key.child_type.getLlvmType(allocator, llvm_context);
594 return llvm.PointerType(elem_llvm_type, 0) orelse return error.OutOfMemory;
424 }595 }
425 };596 };
426597
427 pub const Array = struct {598 pub const Array = struct {
428 base: Type,599 base: Type,
600 key: Key,
601 garbage_node: std.atomic.Stack(*Array).Node,
602
603 pub const Key = struct {
604 elem_type: *Type,
605 len: usize,
606
607 pub fn hash(self: *const Key) u32 {
608 return hash_usize(@ptrToInt(self.elem_type)) *% hash_usize(self.len);
609 }
610
611 pub fn eql(self: *const Key, other: *const Key) bool {
612 return self.elem_type == other.elem_type and self.len == other.len;
613 }
614 };
429615
430 pub fn destroy(self: *Array, comp: *Compilation) void {616 pub fn destroy(self: *Array, comp: *Compilation) void {
617 self.key.elem_type.base.deref(comp);
431 comp.gpa().destroy(self);618 comp.gpa().destroy(self);
432 }619 }
433620
434 pub fn getLlvmType(self: *Array, ofile: *ObjectFile) llvm.TypeRef {621 pub async fn get(comp: *Compilation, key: Key) !*Array {
435 @panic("TODO");622 key.elem_type.base.ref();
623 errdefer key.elem_type.base.deref(comp);
624
625 {
626 const held = await (async comp.array_type_table.acquire() catch unreachable);
627 defer held.release();
628
629 if (held.value.get(&key)) |entry| {
630 entry.value.base.base.ref();
631 return entry.value;
632 }
633 }
634
635 const self = try comp.gpa().create(Array{
636 .base = undefined,
637 .key = key,
638 .garbage_node = undefined,
639 });
640 errdefer comp.gpa().destroy(self);
641
642 const name = try std.fmt.allocPrint(comp.gpa(), "[{}]{}", key.len, key.elem_type.name);
643 errdefer comp.gpa().free(name);
644
645 self.base.init(comp, Id.Array, name);
646
647 {
648 const held = await (async comp.array_type_table.acquire() catch unreachable);
649 defer held.release();
650
651 _ = try held.value.put(&self.key, self);
652 }
653 return self;
654 }
655
656 pub fn getLlvmType(self: *Array, allocator: *Allocator, llvm_context: llvm.ContextRef) !llvm.TypeRef {
657 const elem_llvm_type = try self.key.elem_type.getLlvmType(allocator, llvm_context);
658 return llvm.ArrayType(elem_llvm_type, @intCast(c_uint, self.key.len)) orelse return error.OutOfMemory;
436 }659 }
437 };660 };
438661
...@@ -481,7 +704,7 @@ pub const Type = struct {...@@ -481,7 +704,7 @@ pub const Type = struct {
481 comp.gpa().destroy(self);704 comp.gpa().destroy(self);
482 }705 }
483706
484 pub fn getLlvmType(self: *Optional, ofile: *ObjectFile) llvm.TypeRef {707 pub fn getLlvmType(self: *Optional, allocator: *Allocator, llvm_context: llvm.ContextRef) llvm.TypeRef {
485 @panic("TODO");708 @panic("TODO");
486 }709 }
487 };710 };
...@@ -493,7 +716,7 @@ pub const Type = struct {...@@ -493,7 +716,7 @@ pub const Type = struct {
493 comp.gpa().destroy(self);716 comp.gpa().destroy(self);
494 }717 }
495718
496 pub fn getLlvmType(self: *ErrorUnion, ofile: *ObjectFile) llvm.TypeRef {719 pub fn getLlvmType(self: *ErrorUnion, allocator: *Allocator, llvm_context: llvm.ContextRef) llvm.TypeRef {
497 @panic("TODO");720 @panic("TODO");
498 }721 }
499 };722 };
...@@ -505,7 +728,7 @@ pub const Type = struct {...@@ -505,7 +728,7 @@ pub const Type = struct {
505 comp.gpa().destroy(self);728 comp.gpa().destroy(self);
506 }729 }
507730
508 pub fn getLlvmType(self: *ErrorSet, ofile: *ObjectFile) llvm.TypeRef {731 pub fn getLlvmType(self: *ErrorSet, allocator: *Allocator, llvm_context: llvm.ContextRef) llvm.TypeRef {
509 @panic("TODO");732 @panic("TODO");
510 }733 }
511 };734 };
...@@ -517,7 +740,7 @@ pub const Type = struct {...@@ -517,7 +740,7 @@ pub const Type = struct {
517 comp.gpa().destroy(self);740 comp.gpa().destroy(self);
518 }741 }
519742
520 pub fn getLlvmType(self: *Enum, ofile: *ObjectFile) llvm.TypeRef {743 pub fn getLlvmType(self: *Enum, allocator: *Allocator, llvm_context: llvm.ContextRef) llvm.TypeRef {
521 @panic("TODO");744 @panic("TODO");
522 }745 }
523 };746 };
...@@ -529,7 +752,7 @@ pub const Type = struct {...@@ -529,7 +752,7 @@ pub const Type = struct {
529 comp.gpa().destroy(self);752 comp.gpa().destroy(self);
530 }753 }
531754
532 pub fn getLlvmType(self: *Union, ofile: *ObjectFile) llvm.TypeRef {755 pub fn getLlvmType(self: *Union, allocator: *Allocator, llvm_context: llvm.ContextRef) llvm.TypeRef {
533 @panic("TODO");756 @panic("TODO");
534 }757 }
535 };758 };
...@@ -557,7 +780,7 @@ pub const Type = struct {...@@ -557,7 +780,7 @@ pub const Type = struct {
557 comp.gpa().destroy(self);780 comp.gpa().destroy(self);
558 }781 }
559782
560 pub fn getLlvmType(self: *BoundFn, ofile: *ObjectFile) llvm.TypeRef {783 pub fn getLlvmType(self: *BoundFn, allocator: *Allocator, llvm_context: llvm.ContextRef) llvm.TypeRef {
561 @panic("TODO");784 @panic("TODO");
562 }785 }
563 };786 };
...@@ -577,7 +800,7 @@ pub const Type = struct {...@@ -577,7 +800,7 @@ pub const Type = struct {
577 comp.gpa().destroy(self);800 comp.gpa().destroy(self);
578 }801 }
579802
580 pub fn getLlvmType(self: *Opaque, ofile: *ObjectFile) llvm.TypeRef {803 pub fn getLlvmType(self: *Opaque, allocator: *Allocator, llvm_context: llvm.ContextRef) llvm.TypeRef {
581 @panic("TODO");804 @panic("TODO");
582 }805 }
583 };806 };
...@@ -589,8 +812,33 @@ pub const Type = struct {...@@ -589,8 +812,33 @@ pub const Type = struct {
589 comp.gpa().destroy(self);812 comp.gpa().destroy(self);
590 }813 }
591814
592 pub fn getLlvmType(self: *Promise, ofile: *ObjectFile) llvm.TypeRef {815 pub fn getLlvmType(self: *Promise, allocator: *Allocator, llvm_context: llvm.ContextRef) llvm.TypeRef {
593 @panic("TODO");816 @panic("TODO");
594 }817 }
595 };818 };
596};819};
820
821fn hash_usize(x: usize) u32 {
822 return switch (@sizeOf(usize)) {
823 4 => x,
824 8 => @truncate(u32, x *% 0xad44ee2d8e3fc13d),
825 else => @compileError("implement this hash function"),
826 };
827}
828
829fn hash_enum(x: var) u32 {
830 const rands = []u32{
831 0x85ebf64f,
832 0x3fcb3211,
833 0x240a4e8e,
834 0x40bb0e3c,
835 0x78be45af,
836 0x1ca98e37,
837 0xec56053a,
838 0x906adc48,
839 0xd4fe9763,
840 0x54c80dac,
841 };
842 comptime assert(@memberCount(@typeOf(x)) < rands.len);
843 return rands[@enumToInt(x)];
844}
src-self-hosted/value.zig+266-14
...@@ -11,7 +11,7 @@ const assert = std.debug.assert;...@@ -11,7 +11,7 @@ const assert = std.debug.assert;
11/// If there is only 1 ref then write need not copy11/// If there is only 1 ref then write need not copy
12pub const Value = struct {12pub const Value = struct {
13 id: Id,13 id: Id,
14 typeof: *Type,14 typ: *Type,
15 ref_count: std.atomic.Int(usize),15 ref_count: std.atomic.Int(usize),
1616
17 /// Thread-safe17 /// Thread-safe
...@@ -22,23 +22,25 @@ pub const Value = struct {...@@ -22,23 +22,25 @@ pub const Value = struct {
22 /// Thread-safe22 /// Thread-safe
23 pub fn deref(base: *Value, comp: *Compilation) void {23 pub fn deref(base: *Value, comp: *Compilation) void {
24 if (base.ref_count.decr() == 1) {24 if (base.ref_count.decr() == 1) {
25 base.typeof.base.deref(comp);25 base.typ.base.deref(comp);
26 switch (base.id) {26 switch (base.id) {
27 Id.Type => @fieldParentPtr(Type, "base", base).destroy(comp),27 Id.Type => @fieldParentPtr(Type, "base", base).destroy(comp),
28 Id.Fn => @fieldParentPtr(Fn, "base", base).destroy(comp),28 Id.Fn => @fieldParentPtr(Fn, "base", base).destroy(comp),
29 Id.FnProto => @fieldParentPtr(FnProto, "base", base).destroy(comp),
29 Id.Void => @fieldParentPtr(Void, "base", base).destroy(comp),30 Id.Void => @fieldParentPtr(Void, "base", base).destroy(comp),
30 Id.Bool => @fieldParentPtr(Bool, "base", base).destroy(comp),31 Id.Bool => @fieldParentPtr(Bool, "base", base).destroy(comp),
31 Id.NoReturn => @fieldParentPtr(NoReturn, "base", base).destroy(comp),32 Id.NoReturn => @fieldParentPtr(NoReturn, "base", base).destroy(comp),
32 Id.Ptr => @fieldParentPtr(Ptr, "base", base).destroy(comp),33 Id.Ptr => @fieldParentPtr(Ptr, "base", base).destroy(comp),
33 Id.Int => @fieldParentPtr(Int, "base", base).destroy(comp),34 Id.Int => @fieldParentPtr(Int, "base", base).destroy(comp),
35 Id.Array => @fieldParentPtr(Array, "base", base).destroy(comp),
34 }36 }
35 }37 }
36 }38 }
3739
38 pub fn setType(base: *Value, new_type: *Type, comp: *Compilation) void {40 pub fn setType(base: *Value, new_type: *Type, comp: *Compilation) void {
39 base.typeof.base.deref(comp);41 base.typ.base.deref(comp);
40 new_type.base.ref();42 new_type.base.ref();
41 base.typeof = new_type;43 base.typ = new_type;
42 }44 }
4345
44 pub fn getRef(base: *Value) *Value {46 pub fn getRef(base: *Value) *Value {
...@@ -59,11 +61,13 @@ pub const Value = struct {...@@ -59,11 +61,13 @@ pub const Value = struct {
59 switch (base.id) {61 switch (base.id) {
60 Id.Type => unreachable,62 Id.Type => unreachable,
61 Id.Fn => @panic("TODO"),63 Id.Fn => @panic("TODO"),
64 Id.FnProto => return @fieldParentPtr(FnProto, "base", base).getLlvmConst(ofile),
62 Id.Void => return null,65 Id.Void => return null,
63 Id.Bool => return @fieldParentPtr(Bool, "base", base).getLlvmConst(ofile),66 Id.Bool => return @fieldParentPtr(Bool, "base", base).getLlvmConst(ofile),
64 Id.NoReturn => unreachable,67 Id.NoReturn => unreachable,
65 Id.Ptr => @panic("TODO"),68 Id.Ptr => return @fieldParentPtr(Ptr, "base", base).getLlvmConst(ofile),
66 Id.Int => return @fieldParentPtr(Int, "base", base).getLlvmConst(ofile),69 Id.Int => return @fieldParentPtr(Int, "base", base).getLlvmConst(ofile),
70 Id.Array => return @fieldParentPtr(Array, "base", base).getLlvmConst(ofile),
67 }71 }
68 }72 }
6973
...@@ -81,26 +85,87 @@ pub const Value = struct {...@@ -81,26 +85,87 @@ pub const Value = struct {
81 switch (base.id) {85 switch (base.id) {
82 Id.Type => unreachable,86 Id.Type => unreachable,
83 Id.Fn => unreachable,87 Id.Fn => unreachable,
88 Id.FnProto => unreachable,
84 Id.Void => unreachable,89 Id.Void => unreachable,
85 Id.Bool => unreachable,90 Id.Bool => unreachable,
86 Id.NoReturn => unreachable,91 Id.NoReturn => unreachable,
87 Id.Ptr => unreachable,92 Id.Ptr => unreachable,
93 Id.Array => unreachable,
88 Id.Int => return &(try @fieldParentPtr(Int, "base", base).copy(comp)).base,94 Id.Int => return &(try @fieldParentPtr(Int, "base", base).copy(comp)).base,
89 }95 }
90 }96 }
9197
98 pub const Parent = union(enum) {
99 None,
100 BaseStruct: BaseStruct,
101 BaseArray: BaseArray,
102 BaseUnion: *Value,
103 BaseScalar: *Value,
104
105 pub const BaseStruct = struct {
106 val: *Value,
107 field_index: usize,
108 };
109
110 pub const BaseArray = struct {
111 val: *Value,
112 elem_index: usize,
113 };
114 };
115
92 pub const Id = enum {116 pub const Id = enum {
93 Type,117 Type,
94 Fn,118 Fn,
95 Void,119 Void,
96 Bool,120 Bool,
97 NoReturn,121 NoReturn,
122 Array,
98 Ptr,123 Ptr,
99 Int,124 Int,
125 FnProto,
100 };126 };
101127
102 pub const Type = @import("type.zig").Type;128 pub const Type = @import("type.zig").Type;
103129
130 pub const FnProto = struct {
131 base: Value,
132
133 /// The main external name that is used in the .o file.
134 /// TODO https://github.com/ziglang/zig/issues/265
135 symbol_name: Buffer,
136
137 pub fn create(comp: *Compilation, fn_type: *Type.Fn, symbol_name: Buffer) !*FnProto {
138 const self = try comp.gpa().create(FnProto{
139 .base = Value{
140 .id = Value.Id.FnProto,
141 .typ = &fn_type.base,
142 .ref_count = std.atomic.Int(usize).init(1),
143 },
144 .symbol_name = symbol_name,
145 });
146 fn_type.base.base.ref();
147 return self;
148 }
149
150 pub fn destroy(self: *FnProto, comp: *Compilation) void {
151 self.symbol_name.deinit();
152 comp.gpa().destroy(self);
153 }
154
155 pub fn getLlvmConst(self: *FnProto, ofile: *ObjectFile) !?llvm.ValueRef {
156 const llvm_fn_type = try self.base.typ.getLlvmType(ofile.arena, ofile.context);
157 const llvm_fn = llvm.AddFunction(
158 ofile.module,
159 self.symbol_name.ptr(),
160 llvm_fn_type,
161 ) orelse return error.OutOfMemory;
162
163 // TODO port more logic from codegen.cpp:fn_llvm_value
164
165 return llvm_fn;
166 }
167 };
168
104 pub const Fn = struct {169 pub const Fn = struct {
105 base: Value,170 base: Value,
106171
...@@ -135,7 +200,7 @@ pub const Value = struct {...@@ -135,7 +200,7 @@ pub const Value = struct {
135 const self = try comp.gpa().create(Fn{200 const self = try comp.gpa().create(Fn{
136 .base = Value{201 .base = Value{
137 .id = Value.Id.Fn,202 .id = Value.Id.Fn,
138 .typeof = &fn_type.base,203 .typ = &fn_type.base,
139 .ref_count = std.atomic.Int(usize).init(1),204 .ref_count = std.atomic.Int(usize).init(1),
140 },205 },
141 .fndef_scope = fndef_scope,206 .fndef_scope = fndef_scope,
...@@ -224,6 +289,8 @@ pub const Value = struct {...@@ -224,6 +289,8 @@ pub const Value = struct {
224289
225 pub const Ptr = struct {290 pub const Ptr = struct {
226 base: Value,291 base: Value,
292 special: Special,
293 mut: Mut,
227294
228 pub const Mut = enum {295 pub const Mut = enum {
229 CompTimeConst,296 CompTimeConst,
...@@ -231,25 +298,210 @@ pub const Value = struct {...@@ -231,25 +298,210 @@ pub const Value = struct {
231 RunTime,298 RunTime,
232 };299 };
233300
301 pub const Special = union(enum) {
302 Scalar: *Value,
303 BaseArray: BaseArray,
304 BaseStruct: BaseStruct,
305 HardCodedAddr: u64,
306 Discard,
307 };
308
309 pub const BaseArray = struct {
310 val: *Value,
311 elem_index: usize,
312 };
313
314 pub const BaseStruct = struct {
315 val: *Value,
316 field_index: usize,
317 };
318
319 pub async fn createArrayElemPtr(
320 comp: *Compilation,
321 array_val: *Array,
322 mut: Type.Pointer.Mut,
323 size: Type.Pointer.Size,
324 elem_index: usize,
325 ) !*Ptr {
326 array_val.base.ref();
327 errdefer array_val.base.deref(comp);
328
329 const elem_type = array_val.base.typ.cast(Type.Array).?.key.elem_type;
330 const ptr_type = try await (async Type.Pointer.get(comp, Type.Pointer.Key{
331 .child_type = elem_type,
332 .mut = mut,
333 .vol = Type.Pointer.Vol.Non,
334 .size = size,
335 .alignment = Type.Pointer.Align.Abi,
336 }) catch unreachable);
337 var ptr_type_consumed = false;
338 errdefer if (!ptr_type_consumed) ptr_type.base.base.deref(comp);
339
340 const self = try comp.gpa().create(Value.Ptr{
341 .base = Value{
342 .id = Value.Id.Ptr,
343 .typ = &ptr_type.base,
344 .ref_count = std.atomic.Int(usize).init(1),
345 },
346 .special = Special{
347 .BaseArray = BaseArray{
348 .val = &array_val.base,
349 .elem_index = 0,
350 },
351 },
352 .mut = Mut.CompTimeConst,
353 });
354 ptr_type_consumed = true;
355 errdefer comp.gpa().destroy(self);
356
357 return self;
358 }
359
234 pub fn destroy(self: *Ptr, comp: *Compilation) void {360 pub fn destroy(self: *Ptr, comp: *Compilation) void {
235 comp.gpa().destroy(self);361 comp.gpa().destroy(self);
236 }362 }
363
364 pub fn getLlvmConst(self: *Ptr, ofile: *ObjectFile) !?llvm.ValueRef {
365 const llvm_type = self.base.typ.getLlvmType(ofile.arena, ofile.context);
366 // TODO carefully port the logic from codegen.cpp:gen_const_val_ptr
367 switch (self.special) {
368 Special.Scalar => |scalar| @panic("TODO"),
369 Special.BaseArray => |base_array| {
370 // TODO put this in one .o file only, and after that, generate extern references to it
371 const array_llvm_value = (try base_array.val.getLlvmConst(ofile)).?;
372 const ptr_bit_count = ofile.comp.target_ptr_bits;
373 const usize_llvm_type = llvm.IntTypeInContext(ofile.context, ptr_bit_count) orelse return error.OutOfMemory;
374 const indices = []llvm.ValueRef{
375 llvm.ConstNull(usize_llvm_type) orelse return error.OutOfMemory,
376 llvm.ConstInt(usize_llvm_type, base_array.elem_index, 0) orelse return error.OutOfMemory,
377 };
378 return llvm.ConstInBoundsGEP(
379 array_llvm_value,
380 &indices,
381 @intCast(c_uint, indices.len),
382 ) orelse return error.OutOfMemory;
383 },
384 Special.BaseStruct => |base_struct| @panic("TODO"),
385 Special.HardCodedAddr => |addr| @panic("TODO"),
386 Special.Discard => unreachable,
387 }
388 }
389 };
390
391 pub const Array = struct {
392 base: Value,
393 special: Special,
394
395 pub const Special = union(enum) {
396 Undefined,
397 OwnedBuffer: []u8,
398 Explicit: Data,
399 };
400
401 pub const Data = struct {
402 parent: Parent,
403 elements: []*Value,
404 };
405
406 /// Takes ownership of buffer
407 pub async fn createOwnedBuffer(comp: *Compilation, buffer: []u8) !*Array {
408 const u8_type = Type.Int.get_u8(comp);
409 defer u8_type.base.base.deref(comp);
410
411 const array_type = try await (async Type.Array.get(comp, Type.Array.Key{
412 .elem_type = &u8_type.base,
413 .len = buffer.len,
414 }) catch unreachable);
415 errdefer array_type.base.base.deref(comp);
416
417 const self = try comp.gpa().create(Value.Array{
418 .base = Value{
419 .id = Value.Id.Array,
420 .typ = &array_type.base,
421 .ref_count = std.atomic.Int(usize).init(1),
422 },
423 .special = Special{ .OwnedBuffer = buffer },
424 });
425 errdefer comp.gpa().destroy(self);
426
427 return self;
428 }
429
430 pub fn destroy(self: *Array, comp: *Compilation) void {
431 switch (self.special) {
432 Special.Undefined => {},
433 Special.OwnedBuffer => |buf| {
434 comp.gpa().free(buf);
435 },
436 Special.Explicit => {},
437 }
438 comp.gpa().destroy(self);
439 }
440
441 pub fn getLlvmConst(self: *Array, ofile: *ObjectFile) !?llvm.ValueRef {
442 switch (self.special) {
443 Special.Undefined => {
444 const llvm_type = try self.base.typ.getLlvmType(ofile.arena, ofile.context);
445 return llvm.GetUndef(llvm_type);
446 },
447 Special.OwnedBuffer => |buf| {
448 const dont_null_terminate = 1;
449 const llvm_str_init = llvm.ConstStringInContext(
450 ofile.context,
451 buf.ptr,
452 @intCast(c_uint, buf.len),
453 dont_null_terminate,
454 ) orelse return error.OutOfMemory;
455 const str_init_type = llvm.TypeOf(llvm_str_init);
456 const global = llvm.AddGlobal(ofile.module, str_init_type, c"") orelse return error.OutOfMemory;
457 llvm.SetInitializer(global, llvm_str_init);
458 llvm.SetLinkage(global, llvm.PrivateLinkage);
459 llvm.SetGlobalConstant(global, 1);
460 llvm.SetUnnamedAddr(global, 1);
461 llvm.SetAlignment(global, llvm.ABIAlignmentOfType(ofile.comp.target_data_ref, str_init_type));
462 return global;
463 },
464 Special.Explicit => @panic("TODO"),
465 }
466
467 //{
468 // uint64_t len = type_entry->data.array.len;
469 // if (const_val->data.x_array.special == ConstArraySpecialUndef) {
470 // return LLVMGetUndef(type_entry->type_ref);
471 // }
472
473 // LLVMValueRef *values = allocate<LLVMValueRef>(len);
474 // LLVMTypeRef element_type_ref = type_entry->data.array.child_type->type_ref;
475 // bool make_unnamed_struct = false;
476 // for (uint64_t i = 0; i < len; i += 1) {
477 // ConstExprValue *elem_value = &const_val->data.x_array.s_none.elements[i];
478 // LLVMValueRef val = gen_const_val(g, elem_value, "");
479 // values[i] = val;
480 // make_unnamed_struct = make_unnamed_struct || is_llvm_value_unnamed_type(elem_value->type, val);
481 // }
482 // if (make_unnamed_struct) {
483 // return LLVMConstStruct(values, len, true);
484 // } else {
485 // return LLVMConstArray(element_type_ref, values, (unsigned)len);
486 // }
487 //}
488 }
237 };489 };
238490
239 pub const Int = struct {491 pub const Int = struct {
240 base: Value,492 base: Value,
241 big_int: std.math.big.Int,493 big_int: std.math.big.Int,
242494
243 pub fn createFromString(comp: *Compilation, typeof: *Type, base: u8, value: []const u8) !*Int {495 pub fn createFromString(comp: *Compilation, typ: *Type, base: u8, value: []const u8) !*Int {
244 const self = try comp.gpa().create(Value.Int{496 const self = try comp.gpa().create(Value.Int{
245 .base = Value{497 .base = Value{
246 .id = Value.Id.Int,498 .id = Value.Id.Int,
247 .typeof = typeof,499 .typ = typ,
248 .ref_count = std.atomic.Int(usize).init(1),500 .ref_count = std.atomic.Int(usize).init(1),
249 },501 },
250 .big_int = undefined,502 .big_int = undefined,
251 });503 });
252 typeof.base.ref();504 typ.base.ref();
253 errdefer comp.gpa().destroy(self);505 errdefer comp.gpa().destroy(self);
254506
255 self.big_int = try std.math.big.Int.init(comp.gpa());507 self.big_int = try std.math.big.Int.init(comp.gpa());
...@@ -261,9 +513,9 @@ pub const Value = struct {...@@ -261,9 +513,9 @@ pub const Value = struct {
261 }513 }
262514
263 pub fn getLlvmConst(self: *Int, ofile: *ObjectFile) !?llvm.ValueRef {515 pub fn getLlvmConst(self: *Int, ofile: *ObjectFile) !?llvm.ValueRef {
264 switch (self.base.typeof.id) {516 switch (self.base.typ.id) {
265 Type.Id.Int => {517 Type.Id.Int => {
266 const type_ref = try self.base.typeof.getLlvmType(ofile);518 const type_ref = try self.base.typ.getLlvmType(ofile.arena, ofile.context);
267 if (self.big_int.len == 0) {519 if (self.big_int.len == 0) {
268 return llvm.ConstNull(type_ref);520 return llvm.ConstNull(type_ref);
269 }521 }
...@@ -286,13 +538,13 @@ pub const Value = struct {...@@ -286,13 +538,13 @@ pub const Value = struct {
286 }538 }
287539
288 pub fn copy(old: *Int, comp: *Compilation) !*Int {540 pub fn copy(old: *Int, comp: *Compilation) !*Int {
289 old.base.typeof.base.ref();541 old.base.typ.base.ref();
290 errdefer old.base.typeof.base.deref(comp);542 errdefer old.base.typ.base.deref(comp);
291543
292 const new = try comp.gpa().create(Value.Int{544 const new = try comp.gpa().create(Value.Int{
293 .base = Value{545 .base = Value{
294 .id = Value.Id.Int,546 .id = Value.Id.Int,
295 .typeof = old.base.typeof,547 .typ = old.base.typ,
296 .ref_count = std.atomic.Int(usize).init(1),548 .ref_count = std.atomic.Int(usize).init(1),
297 },549 },
298 .big_int = undefined,550 .big_int = undefined,
std/event/group.zig+1
...@@ -76,6 +76,7 @@ pub fn Group(comptime ReturnType: type) type {...@@ -76,6 +76,7 @@ pub fn Group(comptime ReturnType: type) type {
7676
77 /// Wait for all the calls and promises of the group to complete.77 /// Wait for all the calls and promises of the group to complete.
78 /// Thread-safe.78 /// Thread-safe.
79 /// Safe to call any number of times.
79 pub async fn wait(self: *Self) ReturnType {80 pub async fn wait(self: *Self) ReturnType {
80 // TODO catch unreachable because the allocation can be grouped with81 // TODO catch unreachable because the allocation can be grouped with
81 // the coro frame allocation82 // the coro frame allocation
std/zig/index.zig+3
...@@ -2,6 +2,7 @@ const tokenizer = @import("tokenizer.zig");...@@ -2,6 +2,7 @@ const tokenizer = @import("tokenizer.zig");
2pub const Token = tokenizer.Token;2pub const Token = tokenizer.Token;
3pub const Tokenizer = tokenizer.Tokenizer;3pub const Tokenizer = tokenizer.Tokenizer;
4pub const parse = @import("parse.zig").parse;4pub const parse = @import("parse.zig").parse;
5pub const parseStringLiteral = @import("parse_string_literal.zig").parseStringLiteral;
5pub const render = @import("render.zig").render;6pub const render = @import("render.zig").render;
6pub const ast = @import("ast.zig");7pub const ast = @import("ast.zig");
78
...@@ -10,4 +11,6 @@ test "std.zig tests" {...@@ -10,4 +11,6 @@ test "std.zig tests" {
10 _ = @import("parse.zig");11 _ = @import("parse.zig");
11 _ = @import("render.zig");12 _ = @import("render.zig");
12 _ = @import("tokenizer.zig");13 _ = @import("tokenizer.zig");
14 _ = @import("parse_string_literal.zig");
13}15}
16
std/zig/parse_string_literal.zig created+76
...@@ -0,0 +1,76 @@
1const std = @import("../index.zig");
2const assert = std.debug.assert;
3
4const State = enum {
5 Start,
6 Backslash,
7};
8
9pub const ParseStringLiteralError = error{
10 OutOfMemory,
11
12 /// When this is returned, index will be the position of the character.
13 InvalidCharacter,
14};
15
16/// caller owns returned memory
17pub fn parseStringLiteral(
18 allocator: *std.mem.Allocator,
19 bytes: []const u8,
20 bad_index: *usize, // populated if error.InvalidCharacter is returned
21) ParseStringLiteralError![]u8 {
22 const first_index = if (bytes[0] == 'c') usize(2) else usize(1);
23 assert(bytes[bytes.len - 1] == '"');
24
25 var list = std.ArrayList(u8).init(allocator);
26 errdefer list.deinit();
27
28 const slice = bytes[first_index..];
29 try list.ensureCapacity(slice.len - 1);
30
31 var state = State.Start;
32 for (slice) |b, index| {
33 switch (state) {
34 State.Start => switch (b) {
35 '\\' => state = State.Backslash,
36 '\n' => {
37 bad_index.* = index;
38 return error.InvalidCharacter;
39 },
40 '"' => return list.toOwnedSlice(),
41 else => try list.append(b),
42 },
43 State.Backslash => switch (b) {
44 'x' => @panic("TODO"),
45 'u' => @panic("TODO"),
46 'U' => @panic("TODO"),
47 'n' => {
48 try list.append('\n');
49 state = State.Start;
50 },
51 'r' => {
52 try list.append('\r');
53 state = State.Start;
54 },
55 '\\' => {
56 try list.append('\\');
57 state = State.Start;
58 },
59 't' => {
60 try list.append('\t');
61 state = State.Start;
62 },
63 '"' => {
64 try list.append('"');
65 state = State.Start;
66 },
67 else => {
68 bad_index.* = index;
69 return error.InvalidCharacter;
70 },
71 },
72 else => unreachable,
73 }
74 }
75 unreachable;
76}
std/zig/tokenizer.zig+1
...@@ -73,6 +73,7 @@ pub const Token = struct {...@@ -73,6 +73,7 @@ pub const Token = struct {
73 return null;73 return null;
74 }74 }
7575
76 /// TODO remove this enum
76 const StrLitKind = enum {77 const StrLitKind = enum {
77 Normal,78 Normal,
78 C,79 C,