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
624624 "zig/ast.zig"
625625 "zig/index.zig"
626626 "zig/parse.zig"
627 "zig/parse_string_literal.zig"
627628 "zig/render.zig"
628629 "zig/tokenizer.zig"
629630)
src-self-hosted/codegen.zig+4-2
......@@ -78,6 +78,7 @@ pub async fn renderToLlvm(comp: *Compilation, fn_val: *Value.Fn, code: *ir.Code)
7878 .dibuilder = dibuilder,
7979 .context = context,
8080 .lock = event.Lock.init(comp.loop),
81 .arena = &code.arena.allocator,
8182 };
8283
8384 try renderToLlvmModule(&ofile, fn_val, code);
......@@ -139,6 +140,7 @@ pub const ObjectFile = struct {
139140 dibuilder: *llvm.DIBuilder,
140141 context: llvm.ContextRef,
141142 lock: event.Lock,
143 arena: *std.mem.Allocator,
142144
143145 fn gpa(self: *ObjectFile) *std.mem.Allocator {
144146 return self.comp.gpa();
......@@ -147,7 +149,7 @@ pub const ObjectFile = struct {
147149
148150pub fn renderToLlvmModule(ofile: *ObjectFile, fn_val: *Value.Fn, code: *ir.Code) !void {
149151 // 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);
151153 const llvm_fn = llvm.AddFunction(
152154 ofile.module,
153155 fn_val.symbol_name.ptr(),
......@@ -165,7 +167,7 @@ pub fn renderToLlvmModule(ofile: *ObjectFile, fn_val: *Value.Fn, code: *ir.Code)
165167 // try addLLVMFnAttrInt(ofile, llvm_fn, "alignstack", align_stack);
166168 //}
167169
168 const fn_type = fn_val.base.typeof.cast(Type.Fn).?;
170 const fn_type = fn_val.base.typ.cast(Type.Fn).?;
169171
170172 try addLLVMFnAttr(ofile, llvm_fn, "nounwind");
171173 //add_uwtable_attr(g, fn_table_entry->llvm_value);
src-self-hosted/compilation.zig+141-44
......@@ -194,6 +194,7 @@ pub const Compilation = struct {
194194 bool_type: *Type.Bool,
195195 noreturn_type: *Type.NoReturn,
196196 comptime_int_type: *Type.ComptimeInt,
197 u8_type: *Type.Int,
197198
198199 void_value: *Value.Void,
199200 true_value: *Value.Bool,
......@@ -203,6 +204,7 @@ pub const Compilation = struct {
203204 target_machine: llvm.TargetMachineRef,
204205 target_data_ref: llvm.TargetDataRef,
205206 target_layout_str: [*]u8,
207 target_ptr_bits: u32,
206208
207209 /// for allocating things which have the same lifetime as this Compilation
208210 arena_allocator: std.heap.ArenaAllocator,
......@@ -223,10 +225,14 @@ pub const Compilation = struct {
223225 primitive_type_table: TypeTable,
224226
225227 int_type_table: event.Locked(IntTypeTable),
228 array_type_table: event.Locked(ArrayTypeTable),
229 ptr_type_table: event.Locked(PtrTypeTable),
226230
227231 c_int_types: [CInt.list.len]*Type.Int,
228232
229233 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);
230236 const TypeTable = std.HashMap([]const u8, *Type, mem.hash_slice_u8, mem.eql_slice_u8);
231237
232238 const CompileErrList = std.ArrayList(*errmsg.Msg);
......@@ -383,6 +389,8 @@ pub const Compilation = struct {
383389 .deinit_group = event.Group(void).init(loop),
384390 .compile_errors = event.Locked(CompileErrList).init(loop, CompileErrList.init(loop.allocator)),
385391 .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)),
386394 .c_int_types = undefined,
387395
388396 .meta_type = undefined,
......@@ -394,10 +402,12 @@ pub const Compilation = struct {
394402 .noreturn_type = undefined,
395403 .noreturn_value = undefined,
396404 .comptime_int_type = undefined,
405 .u8_type = undefined,
397406
398407 .target_machine = undefined,
399408 .target_data_ref = undefined,
400409 .target_layout_str = undefined,
410 .target_ptr_bits = target.getArchPtrBitWidth(),
401411
402412 .root_package = undefined,
403413 .std_package = undefined,
......@@ -409,6 +419,8 @@ pub const Compilation = struct {
409419 });
410420 errdefer {
411421 comp.int_type_table.private_data.deinit();
422 comp.array_type_table.private_data.deinit();
423 comp.ptr_type_table.private_data.deinit();
412424 comp.arena_allocator.deinit();
413425 comp.loop.allocator.destroy(comp);
414426 }
......@@ -517,15 +529,16 @@ pub const Compilation = struct {
517529 .name = "type",
518530 .base = Value{
519531 .id = Value.Id.Type,
520 .typeof = undefined,
532 .typ = undefined,
521533 .ref_count = std.atomic.Int(usize).init(3), // 3 because it references itself twice
522534 },
523535 .id = builtin.TypeId.Type,
536 .abi_alignment = Type.AbiAlignment.init(comp.loop),
524537 },
525538 .value = undefined,
526539 });
527540 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;
529542 assert((try comp.primitive_type_table.put(comp.meta_type.base.name, &comp.meta_type.base)) == null);
530543
531544 comp.void_type = try comp.arena().create(Type.Void{
......@@ -533,10 +546,11 @@ pub const Compilation = struct {
533546 .name = "void",
534547 .base = Value{
535548 .id = Value.Id.Type,
536 .typeof = &Type.MetaType.get(comp).base,
549 .typ = &Type.MetaType.get(comp).base,
537550 .ref_count = std.atomic.Int(usize).init(1),
538551 },
539552 .id = builtin.TypeId.Void,
553 .abi_alignment = Type.AbiAlignment.init(comp.loop),
540554 },
541555 });
542556 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 {
546560 .name = "noreturn",
547561 .base = Value{
548562 .id = Value.Id.Type,
549 .typeof = &Type.MetaType.get(comp).base,
563 .typ = &Type.MetaType.get(comp).base,
550564 .ref_count = std.atomic.Int(usize).init(1),
551565 },
552566 .id = builtin.TypeId.NoReturn,
567 .abi_alignment = Type.AbiAlignment.init(comp.loop),
553568 },
554569 });
555570 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 {
559574 .name = "comptime_int",
560575 .base = Value{
561576 .id = Value.Id.Type,
562 .typeof = &Type.MetaType.get(comp).base,
577 .typ = &Type.MetaType.get(comp).base,
563578 .ref_count = std.atomic.Int(usize).init(1),
564579 },
565580 .id = builtin.TypeId.ComptimeInt,
581 .abi_alignment = Type.AbiAlignment.init(comp.loop),
566582 },
567583 });
568584 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 {
572588 .name = "bool",
573589 .base = Value{
574590 .id = Value.Id.Type,
575 .typeof = &Type.MetaType.get(comp).base,
591 .typ = &Type.MetaType.get(comp).base,
576592 .ref_count = std.atomic.Int(usize).init(1),
577593 },
578594 .id = builtin.TypeId.Bool,
595 .abi_alignment = Type.AbiAlignment.init(comp.loop),
579596 },
580597 });
581598 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 {
583600 comp.void_value = try comp.arena().create(Value.Void{
584601 .base = Value{
585602 .id = Value.Id.Void,
586 .typeof = &Type.Void.get(comp).base,
603 .typ = &Type.Void.get(comp).base,
587604 .ref_count = std.atomic.Int(usize).init(1),
588605 },
589606 });
......@@ -591,7 +608,7 @@ pub const Compilation = struct {
591608 comp.true_value = try comp.arena().create(Value.Bool{
592609 .base = Value{
593610 .id = Value.Id.Bool,
594 .typeof = &Type.Bool.get(comp).base,
611 .typ = &Type.Bool.get(comp).base,
595612 .ref_count = std.atomic.Int(usize).init(1),
596613 },
597614 .x = true,
......@@ -600,7 +617,7 @@ pub const Compilation = struct {
600617 comp.false_value = try comp.arena().create(Value.Bool{
601618 .base = Value{
602619 .id = Value.Id.Bool,
603 .typeof = &Type.Bool.get(comp).base,
620 .typ = &Type.Bool.get(comp).base,
604621 .ref_count = std.atomic.Int(usize).init(1),
605622 },
606623 .x = false,
......@@ -609,7 +626,7 @@ pub const Compilation = struct {
609626 comp.noreturn_value = try comp.arena().create(Value.NoReturn{
610627 .base = Value{
611628 .id = Value.Id.NoReturn,
612 .typeof = &Type.NoReturn.get(comp).base,
629 .typ = &Type.NoReturn.get(comp).base,
613630 .ref_count = std.atomic.Int(usize).init(1),
614631 },
615632 });
......@@ -620,10 +637,11 @@ pub const Compilation = struct {
620637 .name = cint.zig_name,
621638 .base = Value{
622639 .id = Value.Id.Type,
623 .typeof = &Type.MetaType.get(comp).base,
640 .typ = &Type.MetaType.get(comp).base,
624641 .ref_count = std.atomic.Int(usize).init(1),
625642 },
626643 .id = builtin.TypeId.Int,
644 .abi_alignment = Type.AbiAlignment.init(comp.loop),
627645 },
628646 .key = Type.Int.Key{
629647 .is_signed = cint.is_signed,
......@@ -634,6 +652,24 @@ pub const Compilation = struct {
634652 comp.c_int_types[i] = c_int_type;
635653 assert((try comp.primitive_type_table.put(cint.zig_name, &c_int_type.base)) == null);
636654 }
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);
637673 }
638674
639675 /// This function can safely use async/await, because it manages Compilation's lifetime,
......@@ -750,7 +786,7 @@ pub const Compilation = struct {
750786 ast.Node.Id.Comptime => {
751787 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);
754790 },
755791 ast.Node.Id.VarDecl => @panic("TODO"),
756792 ast.Node.Id.FnProto => {
......@@ -770,7 +806,6 @@ pub const Compilation = struct {
770806 .name = name,
771807 .visib = parseVisibToken(tree, fn_proto.visib_token),
772808 .resolution = event.Future(BuildError!void).init(self.loop),
773 .resolution_in_progress = 0,
774809 .parent_scope = &decls.base,
775810 },
776811 .value = Decl.Fn.Val{ .Unresolved = {} },
......@@ -778,16 +813,22 @@ pub const Compilation = struct {
778813 });
779814 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);
782817 },
783818 ast.Node.Id.TestDecl => @panic("TODO"),
784819 else => unreachable,
785820 }
786821 }
787822 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();
788826 }
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
792833 const any_prelink_errors = blk: {
793834 const compile_errors = await (async self.compile_errors.acquire() catch unreachable);
......@@ -857,14 +898,31 @@ pub const Compilation = struct {
857898 analyzed_code.destroy(comp.gpa());
858899 }
859900
860 async fn addTopLevelDecl(self: *Compilation, decl: *Decl) !void {
901 async fn addTopLevelDecl(self: *Compilation, decls: *Scope.Decls, decl: *Decl) !void {
861902 const tree = &decl.findRootScope().tree;
862903 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
864909 if (is_export) {
865910 try self.prelink_group.call(verifyUniqueSymbol, self, decl);
866911 try self.prelink_group.call(resolveDecl, self, decl);
867912 }
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 }
868926 }
869927
870928 fn addCompileError(self: *Compilation, root: *Scope.Root, span: Span, comptime fmt: []const u8, args: ...) !void {
......@@ -1043,6 +1101,15 @@ pub const Compilation = struct {
10431101
10441102 return result_val.cast(Type).?;
10451103 }
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 }
10461113};
10471114
10481115fn printError(comptime format: []const u8, args: ...) !void {
......@@ -1062,20 +1129,6 @@ fn parseVisibToken(tree: *ast.Tree, optional_token_index: ?ast.TokenIndex) Visib
10621129 }
10631130}
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
10791132/// The function that actually does the generation.
10801133async fn generateDecl(comp: *Compilation, decl: *Decl) !void {
10811134 switch (decl.id) {
......@@ -1089,34 +1142,27 @@ async fn generateDecl(comp: *Compilation, decl: *Decl) !void {
10891142}
10901143
10911144async 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
10941147 const fndef_scope = try Scope.FnDef.create(comp, fn_decl.base.parent_scope);
10951148 defer fndef_scope.base.deref(comp);
10961149
1097 const return_type_node = switch (fn_decl.fn_proto.return_type) {
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);
1150 const fn_type = try await (async analyzeFnType(comp, fn_decl.base.parent_scope, fn_decl.fn_proto) catch unreachable);
11071151 defer fn_type.base.base.deref(comp);
11081152
11091153 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
11121157 // The Decl.Fn owns the initial 1 reference count
11131158 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
11161162 const analyzed_code = try await (async comp.genAndAnalyzeCode(
11171163 &fndef_scope.base,
11181164 body_node,
1119 return_type,
1165 fn_type.return_type,
11201166 ) catch unreachable);
11211167 errdefer analyzed_code.destroy(comp.gpa());
11221168
......@@ -1141,3 +1187,54 @@ async fn addFnToLinkSet(comp: *Compilation, fn_val: *Value.Fn) void {
11411187fn getZigDir(allocator: *mem.Allocator) ![]u8 {
11421188 return os.getAppDataDir(allocator, "zig");
11431189}
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 {
1515 name: []const u8,
1616 visib: Visib,
1717 resolution: event.Future(Compilation.BuildError!void),
18 resolution_in_progress: u8,
1918 parent_scope: *Scope,
2019
2120 pub const Table = std.HashMap([]const u8, *Decl, mem.hash_slice_u8, mem.eql_slice_u8);
......@@ -63,12 +62,13 @@ pub const Decl = struct {
6362 pub const Fn = struct {
6463 base: Decl,
6564 value: Val,
66 fn_proto: *const ast.Node.FnProto,
65 fn_proto: *ast.Node.FnProto,
6766
6867 // TODO https://github.com/ziglang/zig/issues/683 and then make this anonymous
69 pub const Val = union {
68 pub const Val = union(enum) {
7069 Unresolved: void,
71 Ok: *Value.Fn,
70 Fn: *Value.Fn,
71 FnProto: *Value.FnProto,
7272 };
7373
7474 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 {
1616 last: ast.TokenIndex,
1717
1818 pub fn token(i: TokenIndex) Span {
19 return Span {
19 return Span{
2020 .first = i,
2121 .last = i,
2222 };
2323 }
24
25 pub fn node(n: *ast.Node) Span {
26 return Span{
27 .first = n.firstToken(),
28 .last = n.lastToken(),
29 };
30 }
2431};
2532
2633pub const Msg = struct {
src-self-hosted/ir.zig+492-52
......@@ -11,6 +11,7 @@ const Token = std.zig.Token;
1111const Span = @import("errmsg.zig").Span;
1212const llvm = @import("llvm.zig");
1313const ObjectFile = @import("codegen.zig").ObjectFile;
14const Decl = @import("decl.zig").Decl;
1415
1516pub const LVal = enum {
1617 None,
......@@ -30,10 +31,10 @@ pub const IrVal = union(enum) {
3031
3132 pub fn dump(self: IrVal) void {
3233 switch (self) {
33 IrVal.Unknown => typeof.dump(),
34 IrVal.KnownType => |typeof| {
34 IrVal.Unknown => std.debug.warn("Unknown"),
35 IrVal.KnownType => |typ| {
3536 std.debug.warn("KnownType(");
36 typeof.dump();
37 typ.dump();
3738 std.debug.warn(")");
3839 },
3940 IrVal.KnownValue => |value| {
......@@ -108,21 +109,29 @@ pub const Inst = struct {
108109 unreachable;
109110 }
110111
111 pub fn analyze(base: *Inst, ira: *Analyze) Analyze.Error!*Inst {
112 comptime var i = 0;
113 inline while (i < @memberCount(Id)) : (i += 1) {
114 if (base.id == @field(Id, @memberName(Id, i))) {
115 const T = @field(Inst, @memberName(Id, i));
116 return @fieldParentPtr(T, "base", base).analyze(ira);
117 }
112 pub async fn analyze(base: *Inst, ira: *Analyze) Analyze.Error!*Inst {
113 switch (base.id) {
114 Id.Return => return @fieldParentPtr(Return, "base", base).analyze(ira),
115 Id.Const => return @fieldParentPtr(Const, "base", base).analyze(ira),
116 Id.Call => return @fieldParentPtr(Call, "base", base).analyze(ira),
117 Id.DeclRef => return await (async @fieldParentPtr(DeclRef, "base", base).analyze(ira) catch unreachable),
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),
118125 }
119 unreachable;
120126 }
121127
122128 pub fn render(base: *Inst, ofile: *ObjectFile, fn_val: *Value.Fn) (error{OutOfMemory}!?llvm.ValueRef) {
123129 switch (base.id) {
124130 Id.Return => return @fieldParentPtr(Return, "base", base).render(ofile, fn_val),
125131 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,
126135 Id.Ref => @panic("TODO"),
127136 Id.DeclVar => @panic("TODO"),
128137 Id.CheckVoidStmt => @panic("TODO"),
......@@ -135,7 +144,7 @@ pub const Inst = struct {
135144 fn ref(base: *Inst, builder: *Builder) void {
136145 base.ref_count += 1;
137146 if (base.owner_bb != builder.current_basic_block and !base.isCompTime()) {
138 base.owner_bb.ref();
147 base.owner_bb.ref(builder);
139148 }
140149 }
141150
......@@ -155,11 +164,51 @@ pub const Inst = struct {
155164 }
156165 }
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
158207 /// asserts that the type is known
159208 fn getKnownType(self: *Inst) *Type {
160209 switch (self.val) {
161 IrVal.KnownType => |typeof| return typeof,
162 IrVal.KnownValue => |value| return value.typeof,
210 IrVal.KnownType => |typ| return typ,
211 IrVal.KnownValue => |value| return value.typ,
163212 IrVal.Unknown => unreachable,
164213 }
165214 }
......@@ -171,8 +220,8 @@ pub const Inst = struct {
171220 pub fn isNoReturn(base: *const Inst) bool {
172221 switch (base.val) {
173222 IrVal.Unknown => return false,
174 IrVal.KnownValue => |x| return x.typeof.id == Type.Id.NoReturn,
175 IrVal.KnownType => |typeof| return typeof.id == Type.Id.NoReturn,
223 IrVal.KnownValue => |x| return x.typ.id == Type.Id.NoReturn,
224 IrVal.KnownType => |typ| return typ.id == Type.Id.NoReturn,
176225 }
177226 }
178227
......@@ -196,6 +245,85 @@ pub const Inst = struct {
196245 Phi,
197246 Br,
198247 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 }
199327 };
200328
201329 pub const Const = struct {
......@@ -254,14 +382,14 @@ pub const Inst = struct {
254382 return ira.irb.build(Return, self.base.scope, self.base.span, Params{ .return_value = casted_value });
255383 }
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 {
258386 const value = self.params.return_value.llvm_value;
259387 const return_type = self.params.return_value.getKnownType();
260388
261389 if (return_type.handleIsPtr()) {
262390 @panic("TODO");
263391 } else {
264 _ = llvm.BuildRet(ofile.builder, value);
392 _ = llvm.BuildRet(ofile.builder, value) orelse return error.OutOfMemory;
265393 }
266394 return null;
267395 }
......@@ -285,7 +413,7 @@ pub const Inst = struct {
285413 return false;
286414 }
287415
288 pub fn analyze(self: *const Ref, ira: *Analyze) !*Inst {
416 pub async fn analyze(self: *const Ref, ira: *Analyze) !*Inst {
289417 const target = try self.params.target.getAsParam();
290418
291419 if (ira.getCompTimeValOrNullUndefOk(target)) |val| {
......@@ -294,7 +422,6 @@ pub const Inst = struct {
294422 Value.Ptr.Mut.CompTimeConst,
295423 self.params.mut,
296424 self.params.volatility,
297 val.typeof.getAbiAlignment(ira.irb.comp),
298425 );
299426 }
300427
......@@ -304,14 +431,13 @@ pub const Inst = struct {
304431 .volatility = self.params.volatility,
305432 });
306433 const elem_type = target.getKnownType();
307 const ptr_type = Type.Pointer.get(
308 ira.irb.comp,
309 elem_type,
310 self.params.mut,
311 self.params.volatility,
312 Type.Pointer.Size.One,
313 elem_type.getAbiAlignment(ira.irb.comp),
314 );
434 const ptr_type = try await (async Type.Pointer.get(ira.irb.comp, Type.Pointer.Key{
435 .child_type = elem_type,
436 .mut = self.params.mut,
437 .vol = self.params.volatility,
438 .size = Type.Pointer.Size.One,
439 .alignment = Type.Pointer.Align.Abi,
440 }) catch unreachable);
315441 // TODO: potentially set the hint that this is a stack pointer. But it might not be - this
316442 // could be a ref of a global, for example
317443 new_inst.val = IrVal{ .KnownType = &ptr_type.base };
......@@ -320,6 +446,97 @@ pub const Inst = struct {
320446 }
321447 };
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
323540 pub const DeclVar = struct {
324541 base: Inst,
325542 params: Params,
......@@ -351,14 +568,21 @@ pub const Inst = struct {
351568
352569 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
356575 pub fn hasSideEffects(inst: *const CheckVoidStmt) bool {
357576 return true;
358577 }
359578
360579 pub fn analyze(self: *const CheckVoidStmt, ira: *Analyze) !*Inst {
361 return error.Unimplemented; // TODO
580 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);
362586 }
363587 };
364588
......@@ -583,7 +807,7 @@ pub const BasicBlock = struct {
583807 /// the basic block that this one derives from in analysis
584808 parent: ?*BasicBlock,
585809
586 pub fn ref(self: *BasicBlock) void {
810 pub fn ref(self: *BasicBlock, builder: *Builder) void {
587811 self.ref_count += 1;
588812 }
589813
......@@ -724,8 +948,42 @@ pub const Builder = struct {
724948 ast.Node.Id.VarDecl => return error.Unimplemented,
725949 ast.Node.Id.Defer => return error.Unimplemented,
726950 ast.Node.Id.InfixOp => return error.Unimplemented,
727 ast.Node.Id.PrefixOp => return error.Unimplemented,
728 ast.Node.Id.SuffixOp => return error.Unimplemented,
951 ast.Node.Id.PrefixOp => {
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 },
729987 ast.Node.Id.Switch => return error.Unimplemented,
730988 ast.Node.Id.While => return error.Unimplemented,
731989 ast.Node.Id.For => return error.Unimplemented,
......@@ -744,7 +1002,11 @@ pub const Builder = struct {
7441002 return irb.lvalWrap(scope, try irb.genIntLit(int_lit, scope), lval);
7451003 },
7461004 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 },
7481010 ast.Node.Id.MultilineStringLiteral => return error.Unimplemented,
7491011 ast.Node.Id.CharLiteral => return error.Unimplemented,
7501012 ast.Node.Id.BoolLiteral => return error.Unimplemented,
......@@ -789,6 +1051,99 @@ pub const Builder = struct {
7891051 }
7901052 }
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
7921147 fn isCompTime(irb: *Builder, target_scope: *Scope) bool {
7931148 if (irb.is_comptime)
7941149 return true;
......@@ -847,6 +1202,56 @@ pub const Builder = struct {
8471202 return inst;
8481203 }
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
8501255 pub async fn genBlock(irb: *Builder, block: *ast.Node.Block, parent_scope: *Scope) !*Inst {
8511256 const block_scope = try Scope.Block.create(irb.comp, parent_scope);
8521257
......@@ -911,7 +1316,10 @@ pub const Builder = struct {
9111316 _ = irb.build(
9121317 Inst.CheckVoidStmt,
9131318 child_scope,
914 statement_value.span,
1319 Span{
1320 .first = statement_node.firstToken(),
1321 .last = statement_node.lastToken(),
1322 },
9151323 Inst.CheckVoidStmt.Params{ .target = statement_value },
9161324 );
9171325 }
......@@ -1068,6 +1476,8 @@ pub const Builder = struct {
10681476 if (result) |primitive_type| {
10691477 defer primitive_type.base.deref(irb.comp);
10701478 switch (lval) {
1479 // if (lval == LValPtr) {
1480 // return ir_build_ref(irb, scope, node, value, false, false);
10711481 LVal.Ptr => return error.Unimplemented,
10721482 LVal.None => return irb.buildConstValue(scope, src_span, &primitive_type.base),
10731483 }
......@@ -1079,15 +1489,6 @@ pub const Builder = struct {
10791489 },
10801490 error.OutOfMemory => return error.OutOfMemory,
10811491 }
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
10921493 //VariableTableEntry *var = find_variable(irb->codegen, scope, variable_name);
10931494 //if (var) {
......@@ -1098,9 +1499,12 @@ pub const Builder = struct {
10981499 // return ir_build_load_ptr(irb, scope, node, var_ptr);
10991500 //}
11001501
1101 //Tld *tld = find_decl(irb->codegen, scope, variable_name);
1102 //if (tld)
1103 // return ir_build_decl_ref(irb, scope, node, tld, lval);
1502 if (await (async irb.findDecl(scope, name) catch unreachable)) |decl| {
1503 return irb.build(Inst.DeclRef, scope, src_span, Inst.DeclRef.Params{
1504 .decl = decl,
1505 .lval = lval,
1506 });
1507 }
11041508
11051509 //if (node->owner->any_imports_failed) {
11061510 // // skip the error message since we had a failing import in this file
......@@ -1251,8 +1655,26 @@ pub const Builder = struct {
12511655 const FieldType = comptime @typeOf(@field(I.Params(undefined), @memberName(I.Params, i)));
12521656 switch (FieldType) {
12531657 *Inst => @field(inst.params, @memberName(I.Params, i)).ref(self),
1658 *BasicBlock => @field(inst.params, @memberName(I.Params, i)).ref(self),
12541659 ?*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)),
12561678 }
12571679 }
12581680
......@@ -1348,6 +1770,24 @@ pub const Builder = struct {
13481770 // is_comptime);
13491771 //// the above blocks are rendered by ir_gen after the rest of codegen
13501772 }
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 }
13511791};
13521792
13531793const Analyze = struct {
......@@ -1930,7 +2370,6 @@ const Analyze = struct {
19302370 ptr_mut: Value.Ptr.Mut,
19312371 mut: Type.Pointer.Mut,
19322372 volatility: Type.Pointer.Vol,
1933 ptr_align: u32,
19342373 ) Analyze.Error!*Inst {
19352374 return error.Unimplemented;
19362375 }
......@@ -1945,7 +2384,7 @@ pub async fn gen(
19452384 errdefer irb.abort();
19462385
19472386 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.
19492388 try irb.setCursorAtEndAndAppendBlock(entry_block);
19502389
19512390 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)
19652404 errdefer ira.abort();
19662405
19672406 const new_entry_bb = try ira.getNewBasicBlock(old_entry_bb, null);
1968 new_entry_bb.ref();
2407 new_entry_bb.ref(&ira.irb);
19692408
19702409 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)
19792418 continue;
19802419 }
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
19832423 return_inst.linkToParent(old_instruction);
19842424 // Note: if we ever modify the above to handle error.CompileError by continuing analysis,
19852425 // 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);
2323pub const TargetDataRef = removeNullability(c.LLVMTargetDataRef);
2424pub const DIBuilder = c.ZigLLVMDIBuilder;
2525
26pub const ABIAlignmentOfType = c.LLVMABIAlignmentOfType;
2627pub const AddAttributeAtIndex = c.LLVMAddAttributeAtIndex;
2728pub const AddFunction = c.LLVMAddFunction;
29pub const AddGlobal = c.LLVMAddGlobal;
2830pub const AddModuleCodeViewFlag = c.ZigLLVMAddModuleCodeViewFlag;
2931pub const AddModuleDebugInfoFlag = c.ZigLLVMAddModuleDebugInfoFlag;
32pub const ArrayType = c.LLVMArrayType;
3033pub const ClearCurrentDebugLocation = c.ZigLLVMClearCurrentDebugLocation;
3134pub const ConstAllOnes = c.LLVMConstAllOnes;
35pub const ConstArray = c.LLVMConstArray;
36pub const ConstBitCast = c.LLVMConstBitCast;
3237pub const ConstInt = c.LLVMConstInt;
3338pub const ConstIntOfArbitraryPrecision = c.LLVMConstIntOfArbitraryPrecision;
3439pub const ConstNeg = c.LLVMConstNeg;
......@@ -59,6 +64,7 @@ pub const GetEnumAttributeKindForName = c.LLVMGetEnumAttributeKindForName;
5964pub const GetHostCPUName = c.ZigLLVMGetHostCPUName;
6065pub const GetMDKindIDInContext = c.LLVMGetMDKindIDInContext;
6166pub const GetNativeFeatures = c.ZigLLVMGetNativeFeatures;
67pub const GetUndef = c.LLVMGetUndef;
6268pub const HalfTypeInContext = c.LLVMHalfTypeInContext;
6369pub const InitializeAllAsmParsers = c.LLVMInitializeAllAsmParsers;
6470pub const InitializeAllAsmPrinters = c.LLVMInitializeAllAsmPrinters;
......@@ -81,14 +87,24 @@ pub const MDStringInContext = c.LLVMMDStringInContext;
8187pub const MetadataTypeInContext = c.LLVMMetadataTypeInContext;
8288pub const ModuleCreateWithNameInContext = c.LLVMModuleCreateWithNameInContext;
8389pub const PPCFP128TypeInContext = c.LLVMPPCFP128TypeInContext;
90pub const PointerType = c.LLVMPointerType;
91pub const SetAlignment = c.LLVMSetAlignment;
8492pub const SetDataLayout = c.LLVMSetDataLayout;
93pub const SetGlobalConstant = c.LLVMSetGlobalConstant;
94pub const SetInitializer = c.LLVMSetInitializer;
95pub const SetLinkage = c.LLVMSetLinkage;
8596pub const SetTarget = c.LLVMSetTarget;
97pub const SetUnnamedAddr = c.LLVMSetUnnamedAddr;
8698pub const StructTypeInContext = c.LLVMStructTypeInContext;
8799pub const TokenTypeInContext = c.LLVMTokenTypeInContext;
100pub const TypeOf = c.LLVMTypeOf;
88101pub const VoidTypeInContext = c.LLVMVoidTypeInContext;
89102pub const X86FP80TypeInContext = c.LLVMX86FP80TypeInContext;
90103pub const X86MMXTypeInContext = c.LLVMX86MMXTypeInContext;
91104
105pub const ConstInBoundsGEP = LLVMConstInBoundsGEP;
106pub extern fn LLVMConstInBoundsGEP(ConstantVal: ValueRef, ConstantIndices: [*]ValueRef, NumIndices: c_uint) ?ValueRef;
107
92108pub const GetTargetFromTriple = LLVMGetTargetFromTriple;
93109extern fn LLVMGetTargetFromTriple(Triple: [*]const u8, T: *TargetRef, ErrorMessage: ?*[*]u8) Bool;
94110
......@@ -145,13 +161,28 @@ pub const EmitBinary = EmitOutputType.ZigLLVM_EmitBinary;
145161pub const EmitLLVMIr = EmitOutputType.ZigLLVM_EmitLLVMIr;
146162pub 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
148179fn removeNullability(comptime T: type) type {
149180 comptime assert(@typeId(T) == builtin.TypeId.Optional);
150181 return T.Child;
151182}
152183
153184pub const BuildRet = LLVMBuildRet;
154extern fn LLVMBuildRet(arg0: BuilderRef, V: ?ValueRef) ValueRef;
185extern fn LLVMBuildRet(arg0: BuilderRef, V: ?ValueRef) ?ValueRef;
155186
156187pub const TargetMachineEmitToFile = ZigLLVMTargetMachineEmitToFile;
157188extern fn ZigLLVMTargetMachineEmitToFile(
......@@ -163,3 +194,8 @@ extern fn ZigLLVMTargetMachineEmitToFile(
163194 is_debug: bool,
164195 is_small: bool,
165196) 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;
99const ir = @import("ir.zig");
1010const Span = @import("errmsg.zig").Span;
1111const assert = std.debug.assert;
12const event = std.event;
1213
1314pub const Scope = struct {
1415 id: Id,
......@@ -123,7 +124,15 @@ pub const Scope = struct {
123124
124125 pub const Decls = struct {
125126 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
128137 /// Creates a Decls scope with 1 reference
129138 pub fn create(comp: *Compilation, parent: *Scope) !*Decls {
......@@ -133,15 +142,10 @@ pub const Scope = struct {
133142 .parent = parent,
134143 .ref_count = 1,
135144 },
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),
137147 });
138 errdefer comp.gpa().destroy(self);
139
140 self.table = Decl.Table.init(comp.gpa());
141 errdefer self.table.deinit();
142
143148 parent.ref();
144
145149 return self;
146150 }
147151
......@@ -149,6 +153,11 @@ pub const Scope = struct {
149153 self.table.deinit();
150154 comp.gpa().destroy(self);
151155 }
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 }
152161 };
153162
154163 pub const Block = struct {
src-self-hosted/test.zig+1
......@@ -14,6 +14,7 @@ test "compile errors" {
1414 defer ctx.deinit();
1515
1616 try @import("../test/stage2/compile_errors.zig").addCases(&ctx);
17 //try @import("../test/stage2/compare_output.zig").addCases(&ctx);
1718
1819 try ctx.run();
1920}
src-self-hosted/type.zig+306-58
......@@ -4,12 +4,17 @@ const Scope = @import("scope.zig").Scope;
44const Compilation = @import("compilation.zig").Compilation;
55const Value = @import("value.zig").Value;
66const 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
911pub const Type = struct {
1012 base: Value,
1113 id: Id,
1214 name: []const u8,
15 abi_alignment: AbiAlignment,
16
17 pub const AbiAlignment = event.Future(error{OutOfMemory}!u32);
1318
1419 pub const Id = builtin.TypeId;
1520
......@@ -43,33 +48,37 @@ pub const Type = struct {
4348 }
4449 }
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) {
4756 switch (base.id) {
48 Id.Struct => return @fieldParentPtr(Struct, "base", base).getLlvmType(ofile),
49 Id.Fn => return @fieldParentPtr(Fn, "base", base).getLlvmType(ofile),
57 Id.Struct => return @fieldParentPtr(Struct, "base", base).getLlvmType(allocator, llvm_context),
58 Id.Fn => return @fieldParentPtr(Fn, "base", base).getLlvmType(allocator, llvm_context),
5059 Id.Type => unreachable,
5160 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),
5362 Id.NoReturn => unreachable,
54 Id.Int => return @fieldParentPtr(Int, "base", base).getLlvmType(ofile),
55 Id.Float => return @fieldParentPtr(Float, "base", base).getLlvmType(ofile),
56 Id.Pointer => return @fieldParentPtr(Pointer, "base", base).getLlvmType(ofile),
57 Id.Array => return @fieldParentPtr(Array, "base", base).getLlvmType(ofile),
63 Id.Int => return @fieldParentPtr(Int, "base", base).getLlvmType(allocator, llvm_context),
64 Id.Float => return @fieldParentPtr(Float, "base", base).getLlvmType(allocator, llvm_context),
65 Id.Pointer => return @fieldParentPtr(Pointer, "base", base).getLlvmType(allocator, llvm_context),
66 Id.Array => return @fieldParentPtr(Array, "base", base).getLlvmType(allocator, llvm_context),
5867 Id.ComptimeFloat => unreachable,
5968 Id.ComptimeInt => unreachable,
6069 Id.Undefined => unreachable,
6170 Id.Null => unreachable,
62 Id.Optional => return @fieldParentPtr(Optional, "base", base).getLlvmType(ofile),
63 Id.ErrorUnion => return @fieldParentPtr(ErrorUnion, "base", base).getLlvmType(ofile),
64 Id.ErrorSet => return @fieldParentPtr(ErrorSet, "base", base).getLlvmType(ofile),
65 Id.Enum => return @fieldParentPtr(Enum, "base", base).getLlvmType(ofile),
66 Id.Union => return @fieldParentPtr(Union, "base", base).getLlvmType(ofile),
71 Id.Optional => return @fieldParentPtr(Optional, "base", base).getLlvmType(allocator, llvm_context),
72 Id.ErrorUnion => return @fieldParentPtr(ErrorUnion, "base", base).getLlvmType(allocator, llvm_context),
73 Id.ErrorSet => return @fieldParentPtr(ErrorSet, "base", base).getLlvmType(allocator, llvm_context),
74 Id.Enum => return @fieldParentPtr(Enum, "base", base).getLlvmType(allocator, llvm_context),
75 Id.Union => return @fieldParentPtr(Union, "base", base).getLlvmType(allocator, llvm_context),
6776 Id.Namespace => unreachable,
6877 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),
7079 Id.ArgTuple => unreachable,
71 Id.Opaque => return @fieldParentPtr(Opaque, "base", base).getLlvmType(ofile),
72 Id.Promise => return @fieldParentPtr(Promise, "base", base).getLlvmType(ofile),
80 Id.Opaque => return @fieldParentPtr(Opaque, "base", base).getLlvmType(allocator, llvm_context),
81 Id.Promise => return @fieldParentPtr(Promise, "base", base).getLlvmType(allocator, llvm_context),
7382 }
7483 }
7584
......@@ -156,16 +165,45 @@ pub const Type = struct {
156165 base.* = Type{
157166 .base = Value{
158167 .id = Value.Id.Type,
159 .typeof = &MetaType.get(comp).base,
168 .typ = &MetaType.get(comp).base,
160169 .ref_count = std.atomic.Int(usize).init(1),
161170 },
162171 .id = id,
163172 .name = name,
173 .abi_alignment = AbiAlignment.init(comp.loop),
164174 };
165175 }
166176
167 pub fn getAbiAlignment(base: *Type, comp: *Compilation) u32 {
168 @panic("TODO getAbiAlignment");
177 /// If you happen to have an llvm context handy, use getAbiAlignmentInContext instead.
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));
169207 }
170208
171209 pub const Struct = struct {
......@@ -176,7 +214,7 @@ pub const Type = struct {
176214 comp.gpa().destroy(self);
177215 }
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 {
180218 @panic("TODO");
181219 }
182220 };
......@@ -189,7 +227,7 @@ pub const Type = struct {
189227
190228 pub const Param = struct {
191229 is_noalias: bool,
192 typeof: *Type,
230 typ: *Type,
193231 };
194232
195233 pub fn create(comp: *Compilation, return_type: *Type, params: []Param, is_var_args: bool) !*Fn {
......@@ -205,7 +243,7 @@ pub const Type = struct {
205243
206244 result.return_type.base.ref();
207245 for (result.params) |param| {
208 param.typeof.base.ref();
246 param.typ.base.ref();
209247 }
210248 return result;
211249 }
......@@ -213,20 +251,20 @@ pub const Type = struct {
213251 pub fn destroy(self: *Fn, comp: *Compilation) void {
214252 self.return_type.base.deref(comp);
215253 for (self.params) |param| {
216 param.typeof.base.deref(comp);
254 param.typ.base.deref(comp);
217255 }
218256 comp.gpa().destroy(self);
219257 }
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 {
222260 const llvm_return_type = switch (self.return_type.id) {
223 Type.Id.Void => llvm.VoidTypeInContext(ofile.context) orelse return error.OutOfMemory,
224 else => try self.return_type.getLlvmType(ofile),
261 Type.Id.Void => llvm.VoidTypeInContext(llvm_context) orelse return error.OutOfMemory,
262 else => try self.return_type.getLlvmType(allocator, llvm_context),
225263 };
226 const llvm_param_types = try ofile.gpa().alloc(llvm.TypeRef, self.params.len);
227 defer ofile.gpa().free(llvm_param_types);
264 const llvm_param_types = try allocator.alloc(llvm.TypeRef, self.params.len);
265 defer allocator.free(llvm_param_types);
228266 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);
230268 }
231269
232270 return llvm.FunctionType(
......@@ -280,7 +318,7 @@ pub const Type = struct {
280318 comp.gpa().destroy(self);
281319 }
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 {
284322 @panic("TODO");
285323 }
286324 };
......@@ -318,6 +356,11 @@ pub const Type = struct {
318356 }
319357 };
320358
359 pub fn get_u8(comp: *Compilation) *Int {
360 comp.u8_type.base.base.ref();
361 return comp.u8_type;
362 }
363
321364 pub async fn get(comp: *Compilation, key: Key) !*Int {
322365 {
323366 const held = await (async comp.int_type_table.acquire() catch unreachable);
......@@ -371,8 +414,8 @@ pub const Type = struct {
371414 comp.gpa().destroy(self);
372415 }
373416
374 pub fn getLlvmType(self: *Int, ofile: *ObjectFile) !llvm.TypeRef {
375 return llvm.IntTypeInContext(ofile.context, self.key.bit_count) orelse return error.OutOfMemory;
417 pub fn getLlvmType(self: *Int, allocator: *Allocator, llvm_context: llvm.ContextRef) !llvm.TypeRef {
418 return llvm.IntTypeInContext(llvm_context, self.key.bit_count) orelse return error.OutOfMemory;
376419 }
377420 };
378421
......@@ -383,56 +426,236 @@ pub const Type = struct {
383426 comp.gpa().destroy(self);
384427 }
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 {
387430 @panic("TODO");
388431 }
389432 };
390433 pub const Pointer = struct {
391434 base: Type,
392 mut: Mut,
393 vol: Vol,
394 size: Size,
395 alignment: u32,
435 key: Key,
436 garbage_node: std.atomic.Stack(*Pointer).Node,
437
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
397473 pub const Mut = enum {
398474 Mut,
399475 Const,
400476 };
477
401478 pub const Vol = enum {
402479 Non,
403480 Volatile,
404481 };
482
483 pub const Align = union(enum) {
484 Abi,
485 Override: u32,
486 };
487
405488 pub const Size = builtin.TypeInfo.Pointer.Size;
406489
407490 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);
408506 comp.gpa().destroy(self);
409507 }
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(
412517 comp: *Compilation,
413 elem_type: *Type,
414 mut: Mut,
415 vol: Vol,
416 size: Size,
417 alignment: u32,
418 ) *Pointer {
419 @panic("TODO get pointer");
518 key: Key,
519 ) !*Pointer {
520 var normal_key = key;
521 switch (key.alignment) {
522 Align.Abi => {},
523 Align.Override => |alignment| {
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;
420590 }
421591
422 pub fn getLlvmType(self: *Pointer, ofile: *ObjectFile) llvm.TypeRef {
423 @panic("TODO");
592 pub fn getLlvmType(self: *Pointer, allocator: *Allocator, llvm_context: llvm.ContextRef) !llvm.TypeRef {
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;
424595 }
425596 };
426597
427598 pub const Array = struct {
428599 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
430616 pub fn destroy(self: *Array, comp: *Compilation) void {
617 self.key.elem_type.base.deref(comp);
431618 comp.gpa().destroy(self);
432619 }
433620
434 pub fn getLlvmType(self: *Array, ofile: *ObjectFile) llvm.TypeRef {
435 @panic("TODO");
621 pub async fn get(comp: *Compilation, key: Key) !*Array {
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;
436659 }
437660 };
438661
......@@ -481,7 +704,7 @@ pub const Type = struct {
481704 comp.gpa().destroy(self);
482705 }
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 {
485708 @panic("TODO");
486709 }
487710 };
......@@ -493,7 +716,7 @@ pub const Type = struct {
493716 comp.gpa().destroy(self);
494717 }
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 {
497720 @panic("TODO");
498721 }
499722 };
......@@ -505,7 +728,7 @@ pub const Type = struct {
505728 comp.gpa().destroy(self);
506729 }
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 {
509732 @panic("TODO");
510733 }
511734 };
......@@ -517,7 +740,7 @@ pub const Type = struct {
517740 comp.gpa().destroy(self);
518741 }
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 {
521744 @panic("TODO");
522745 }
523746 };
......@@ -529,7 +752,7 @@ pub const Type = struct {
529752 comp.gpa().destroy(self);
530753 }
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 {
533756 @panic("TODO");
534757 }
535758 };
......@@ -557,7 +780,7 @@ pub const Type = struct {
557780 comp.gpa().destroy(self);
558781 }
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 {
561784 @panic("TODO");
562785 }
563786 };
......@@ -577,7 +800,7 @@ pub const Type = struct {
577800 comp.gpa().destroy(self);
578801 }
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 {
581804 @panic("TODO");
582805 }
583806 };
......@@ -589,8 +812,33 @@ pub const Type = struct {
589812 comp.gpa().destroy(self);
590813 }
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 {
593816 @panic("TODO");
594817 }
595818 };
596819};
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;
1111/// If there is only 1 ref then write need not copy
1212pub const Value = struct {
1313 id: Id,
14 typeof: *Type,
14 typ: *Type,
1515 ref_count: std.atomic.Int(usize),
1616
1717 /// Thread-safe
......@@ -22,23 +22,25 @@ pub const Value = struct {
2222 /// Thread-safe
2323 pub fn deref(base: *Value, comp: *Compilation) void {
2424 if (base.ref_count.decr() == 1) {
25 base.typeof.base.deref(comp);
25 base.typ.base.deref(comp);
2626 switch (base.id) {
2727 Id.Type => @fieldParentPtr(Type, "base", base).destroy(comp),
2828 Id.Fn => @fieldParentPtr(Fn, "base", base).destroy(comp),
29 Id.FnProto => @fieldParentPtr(FnProto, "base", base).destroy(comp),
2930 Id.Void => @fieldParentPtr(Void, "base", base).destroy(comp),
3031 Id.Bool => @fieldParentPtr(Bool, "base", base).destroy(comp),
3132 Id.NoReturn => @fieldParentPtr(NoReturn, "base", base).destroy(comp),
3233 Id.Ptr => @fieldParentPtr(Ptr, "base", base).destroy(comp),
3334 Id.Int => @fieldParentPtr(Int, "base", base).destroy(comp),
35 Id.Array => @fieldParentPtr(Array, "base", base).destroy(comp),
3436 }
3537 }
3638 }
3739
3840 pub fn setType(base: *Value, new_type: *Type, comp: *Compilation) void {
39 base.typeof.base.deref(comp);
41 base.typ.base.deref(comp);
4042 new_type.base.ref();
41 base.typeof = new_type;
43 base.typ = new_type;
4244 }
4345
4446 pub fn getRef(base: *Value) *Value {
......@@ -59,11 +61,13 @@ pub const Value = struct {
5961 switch (base.id) {
6062 Id.Type => unreachable,
6163 Id.Fn => @panic("TODO"),
64 Id.FnProto => return @fieldParentPtr(FnProto, "base", base).getLlvmConst(ofile),
6265 Id.Void => return null,
6366 Id.Bool => return @fieldParentPtr(Bool, "base", base).getLlvmConst(ofile),
6467 Id.NoReturn => unreachable,
65 Id.Ptr => @panic("TODO"),
68 Id.Ptr => return @fieldParentPtr(Ptr, "base", base).getLlvmConst(ofile),
6669 Id.Int => return @fieldParentPtr(Int, "base", base).getLlvmConst(ofile),
70 Id.Array => return @fieldParentPtr(Array, "base", base).getLlvmConst(ofile),
6771 }
6872 }
6973
......@@ -81,26 +85,87 @@ pub const Value = struct {
8185 switch (base.id) {
8286 Id.Type => unreachable,
8387 Id.Fn => unreachable,
88 Id.FnProto => unreachable,
8489 Id.Void => unreachable,
8590 Id.Bool => unreachable,
8691 Id.NoReturn => unreachable,
8792 Id.Ptr => unreachable,
93 Id.Array => unreachable,
8894 Id.Int => return &(try @fieldParentPtr(Int, "base", base).copy(comp)).base,
8995 }
9096 }
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
92116 pub const Id = enum {
93117 Type,
94118 Fn,
95119 Void,
96120 Bool,
97121 NoReturn,
122 Array,
98123 Ptr,
99124 Int,
125 FnProto,
100126 };
101127
102128 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
104169 pub const Fn = struct {
105170 base: Value,
106171
......@@ -135,7 +200,7 @@ pub const Value = struct {
135200 const self = try comp.gpa().create(Fn{
136201 .base = Value{
137202 .id = Value.Id.Fn,
138 .typeof = &fn_type.base,
203 .typ = &fn_type.base,
139204 .ref_count = std.atomic.Int(usize).init(1),
140205 },
141206 .fndef_scope = fndef_scope,
......@@ -224,6 +289,8 @@ pub const Value = struct {
224289
225290 pub const Ptr = struct {
226291 base: Value,
292 special: Special,
293 mut: Mut,
227294
228295 pub const Mut = enum {
229296 CompTimeConst,
......@@ -231,25 +298,210 @@ pub const Value = struct {
231298 RunTime,
232299 };
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
234360 pub fn destroy(self: *Ptr, comp: *Compilation) void {
235361 comp.gpa().destroy(self);
236362 }
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 }
237489 };
238490
239491 pub const Int = struct {
240492 base: Value,
241493 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 {
244496 const self = try comp.gpa().create(Value.Int{
245497 .base = Value{
246498 .id = Value.Id.Int,
247 .typeof = typeof,
499 .typ = typ,
248500 .ref_count = std.atomic.Int(usize).init(1),
249501 },
250502 .big_int = undefined,
251503 });
252 typeof.base.ref();
504 typ.base.ref();
253505 errdefer comp.gpa().destroy(self);
254506
255507 self.big_int = try std.math.big.Int.init(comp.gpa());
......@@ -261,9 +513,9 @@ pub const Value = struct {
261513 }
262514
263515 pub fn getLlvmConst(self: *Int, ofile: *ObjectFile) !?llvm.ValueRef {
264 switch (self.base.typeof.id) {
516 switch (self.base.typ.id) {
265517 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);
267519 if (self.big_int.len == 0) {
268520 return llvm.ConstNull(type_ref);
269521 }
......@@ -286,13 +538,13 @@ pub const Value = struct {
286538 }
287539
288540 pub fn copy(old: *Int, comp: *Compilation) !*Int {
289 old.base.typeof.base.ref();
290 errdefer old.base.typeof.base.deref(comp);
541 old.base.typ.base.ref();
542 errdefer old.base.typ.base.deref(comp);
291543
292544 const new = try comp.gpa().create(Value.Int{
293545 .base = Value{
294546 .id = Value.Id.Int,
295 .typeof = old.base.typeof,
547 .typ = old.base.typ,
296548 .ref_count = std.atomic.Int(usize).init(1),
297549 },
298550 .big_int = undefined,
std/event/group.zig+1
......@@ -76,6 +76,7 @@ pub fn Group(comptime ReturnType: type) type {
7676
7777 /// Wait for all the calls and promises of the group to complete.
7878 /// Thread-safe.
79 /// Safe to call any number of times.
7980 pub async fn wait(self: *Self) ReturnType {
8081 // TODO catch unreachable because the allocation can be grouped with
8182 // the coro frame allocation
std/zig/index.zig+3
......@@ -2,6 +2,7 @@ const tokenizer = @import("tokenizer.zig");
22pub const Token = tokenizer.Token;
33pub const Tokenizer = tokenizer.Tokenizer;
44pub const parse = @import("parse.zig").parse;
5pub const parseStringLiteral = @import("parse_string_literal.zig").parseStringLiteral;
56pub const render = @import("render.zig").render;
67pub const ast = @import("ast.zig");
78
......@@ -10,4 +11,6 @@ test "std.zig tests" {
1011 _ = @import("parse.zig");
1112 _ = @import("render.zig");
1213 _ = @import("tokenizer.zig");
14 _ = @import("parse_string_literal.zig");
1315}
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 {
7373 return null;
7474 }
7575
76 /// TODO remove this enum
7677 const StrLitKind = enum {
7778 Normal,
7879 C,