authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-06-26 02:25:09-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-06-26 02:30:14-04:00
log130c7fd23b9f23aa5afad2eb1744ffab9e193715
treeb39e5cf093a901c7713009d4c4448e0702d4ead7
parente820678ca1c1a66b561e760fb6aae4df4babf8ba

self-hosted: working towards conditional branching test case

New features: * Functions can have parameters in semantic analysis. Codegen is not implemented yet. * Support for i8, i16, i32, i64, u8, u16, u32, u64 primitive identifiers. * New ZIR instructions: arg, block, and breakvoid Implementation details: * Move Module.Body to ir.Body * Scope.Block gains a parent field and an optional Label field * Fix bug in integer type equality comparison. Here's the test case I'm working towards: ``` @void = primitive(void) @i32 = primitive(i32) @fnty = fntype([@i32, @i32], @void) @0 = str("entry") @1 = export(@0, "entry") @entry = fn(@fnty, { %0 = arg(0) %1 = arg(1) %2 = add(%0, %1) %3 = int(7) %4 = block("if", { %neq = cmp(%2, neq, %3) %5 = condbr(%neq, { %6 = unreachable() }, { %7 = breakvoid("if") }) }) %11 = returnvoid() }) ``` $ ./zig-cache/bin/zig build-obj test.zir test.zir:9:12: error: TODO implement function parameters for Arch.x86_64 That's where I left off.

6 files changed, 841 insertions(+), 96 deletions(-)

src-self-hosted/Module.zig+204-46
......@@ -15,6 +15,7 @@ const ir = @import("ir.zig");
1515const zir = @import("zir.zig");
1616const Module = @This();
1717const Inst = ir.Inst;
18const Body = ir.Body;
1819const ast = std.zig.ast;
1920const trace = @import("tracy.zig").trace;
2021
......@@ -649,11 +650,19 @@ pub const Scope = struct {
649650 pub const Block = struct {
650651 pub const base_tag: Tag = .block;
651652 base: Scope = Scope{ .tag = base_tag },
653 parent: ?*Block,
652654 func: ?*Fn,
653655 decl: *Decl,
654656 instructions: ArrayListUnmanaged(*Inst),
655657 /// Points to the arena allocator of DeclAnalysis
656658 arena: *Allocator,
659 label: ?Label = null,
660
661 pub const Label = struct {
662 name: []const u8,
663 results: ArrayListUnmanaged(*Inst),
664 block_inst: *Inst.Block,
665 };
657666 };
658667
659668 /// This is a temporary structure, references to it are valid only
......@@ -676,10 +685,6 @@ pub const Scope = struct {
676685 };
677686};
678687
679pub const Body = struct {
680 instructions: []*Inst,
681};
682
683688pub const AllErrors = struct {
684689 arena: std.heap.ArenaAllocator.State,
685690 list: []const Message,
......@@ -1139,13 +1144,16 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {
11391144
11401145 const body_node = fn_proto.body_node orelse
11411146 return self.failTok(&fn_type_scope.base, fn_proto.fn_token, "TODO implement extern functions", .{});
1142 if (fn_proto.params_len != 0) {
1143 return self.failTok(
1144 &fn_type_scope.base,
1145 fn_proto.params()[0].name_token.?,
1146 "TODO implement function parameters",
1147 .{},
1148 );
1147
1148 const param_decls = fn_proto.params();
1149 const param_types = try fn_type_scope.arena.allocator.alloc(*zir.Inst, param_decls.len);
1150 for (param_decls) |param_decl, i| {
1151 const param_type_node = switch (param_decl.param_type) {
1152 .var_type => |node| return self.failNode(&fn_type_scope.base, node, "TODO implement anytype parameter", .{}),
1153 .var_args => |tok| return self.failTok(&fn_type_scope.base, tok, "TODO implement var args", .{}),
1154 .type_expr => |node| node,
1155 };
1156 param_types[i] = try self.astGenExpr(&fn_type_scope.base, param_type_node);
11491157 }
11501158 if (fn_proto.lib_name) |lib_name| {
11511159 return self.failNode(&fn_type_scope.base, lib_name, "TODO implement function library name", .{});
......@@ -1174,7 +1182,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {
11741182 const fn_src = tree.token_locs[fn_proto.fn_token].start;
11751183 const fn_type_inst = try self.addZIRInst(&fn_type_scope.base, fn_src, zir.Inst.FnType, .{
11761184 .return_type = return_type_inst,
1177 .param_types = &[0]*zir.Inst{},
1185 .param_types = param_types,
11781186 }, .{});
11791187 _ = try self.addZIRInst(&fn_type_scope.base, fn_src, zir.Inst.Return, .{ .operand = fn_type_inst }, .{});
11801188
......@@ -1184,6 +1192,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {
11841192 const decl_arena_state = try decl_arena.allocator.create(std.heap.ArenaAllocator.State);
11851193
11861194 var block_scope: Scope.Block = .{
1195 .parent = null,
11871196 .func = null,
11881197 .decl = decl,
11891198 .instructions = .{},
......@@ -1302,10 +1311,25 @@ fn astGenExpr(self: *Module, scope: *Scope, ast_node: *ast.Node) InnerError!*zir
13021311 .Call => return self.astGenCall(scope, @fieldParentPtr(ast.Node.Call, "base", ast_node)),
13031312 .Unreachable => return self.astGenUnreachable(scope, @fieldParentPtr(ast.Node.Unreachable, "base", ast_node)),
13041313 .ControlFlowExpression => return self.astGenControlFlowExpression(scope, @fieldParentPtr(ast.Node.ControlFlowExpression, "base", ast_node)),
1314 .If => return self.astGenIf(scope, @fieldParentPtr(ast.Node.If, "base", ast_node)),
13051315 else => return self.failNode(scope, ast_node, "TODO implement astGenExpr for {}", .{@tagName(ast_node.id)}),
13061316 }
13071317}
13081318
1319fn astGenIf(self: *Module, scope: *Scope, if_node: *ast.Node.If) InnerError!*zir.Inst {
1320 if (if_node.payload) |payload| {
1321 return self.failNode(scope, payload, "TODO implement astGenIf for optionals", .{});
1322 }
1323 if (if_node.@"else") |else_node| {
1324 if (else_node.payload) |payload| {
1325 return self.failNode(scope, payload, "TODO implement astGenIf for error unions", .{});
1326 }
1327 }
1328 const cond = try self.astGenExpr(scope, if_node.condition);
1329 const body = try self.astGenExpr(scope, if_node.condition);
1330 return self.failNode(scope, if_node.condition, "TODO implement astGenIf", .{});
1331}
1332
13091333fn astGenControlFlowExpression(
13101334 self: *Module,
13111335 scope: *Scope,
......@@ -1351,7 +1375,18 @@ fn astGenIdent(self: *Module, scope: *Scope, ident: *ast.Node.Identifier) InnerE
13511375 ),
13521376 error.InvalidCharacter => break :integer,
13531377 };
1354 return self.failNode(scope, &ident.base, "TODO implement arbitrary integer bitwidth types", .{});
1378 const val = switch (bit_count) {
1379 8 => if (is_signed) Value.initTag(.i8_type) else Value.initTag(.u8_type),
1380 16 => if (is_signed) Value.initTag(.i16_type) else Value.initTag(.u16_type),
1381 32 => if (is_signed) Value.initTag(.i32_type) else Value.initTag(.u32_type),
1382 64 => if (is_signed) Value.initTag(.i64_type) else Value.initTag(.u64_type),
1383 else => return self.failNode(scope, &ident.base, "TODO implement arbitrary integer bitwidth types", .{}),
1384 };
1385 const src = tree.token_locs[ident.token].start;
1386 return self.addZIRInstConst(scope, src, .{
1387 .ty = Type.initTag(.type),
1388 .val = val,
1389 });
13551390 }
13561391 }
13571392
......@@ -1494,16 +1529,18 @@ fn astGenBuiltinCall(self: *Module, scope: *Scope, call: *ast.Node.BuiltinCall)
14941529
14951530fn astGenCall(self: *Module, scope: *Scope, call: *ast.Node.Call) InnerError!*zir.Inst {
14961531 const tree = scope.tree();
1532 const lhs = try self.astGenExpr(scope, call.lhs);
14971533
1498 if (call.params_len != 0) {
1499 return self.failNode(scope, &call.base, "TODO implement fn calls with parameters", .{});
1534 const param_nodes = call.params();
1535 const args = try scope.cast(Scope.GenZIR).?.arena.allocator.alloc(*zir.Inst, param_nodes.len);
1536 for (param_nodes) |param_node, i| {
1537 args[i] = try self.astGenExpr(scope, param_node);
15001538 }
1501 const lhs = try self.astGenExpr(scope, call.lhs);
15021539
15031540 const src = tree.token_locs[call.lhs.firstToken()].start;
15041541 return self.addZIRInst(scope, src, zir.Inst.Call, .{
15051542 .func = lhs,
1506 .args = &[0]*zir.Inst{},
1543 .args = args,
15071544 }, .{});
15081545}
15091546
......@@ -1871,6 +1908,7 @@ fn analyzeFnBody(self: *Module, decl: *Decl, func: *Fn) !void {
18711908 var arena = decl.typed_value.most_recent.arena.?.promote(self.allocator);
18721909 defer decl.typed_value.most_recent.arena.?.* = arena.state;
18731910 var inner_block: Scope.Block = .{
1911 .parent = null,
18741912 .func = func,
18751913 .decl = decl,
18761914 .instructions = .{},
......@@ -2323,7 +2361,10 @@ fn analyzeInstConst(self: *Module, scope: *Scope, const_inst: *zir.Inst.Const) I
23232361
23242362fn analyzeInst(self: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!*Inst {
23252363 switch (old_inst.tag) {
2364 .arg => return self.analyzeInstArg(scope, old_inst.cast(zir.Inst.Arg).?),
2365 .block => return self.analyzeInstBlock(scope, old_inst.cast(zir.Inst.Block).?),
23262366 .breakpoint => return self.analyzeInstBreakpoint(scope, old_inst.cast(zir.Inst.Breakpoint).?),
2367 .breakvoid => return self.analyzeInstBreakVoid(scope, old_inst.cast(zir.Inst.BreakVoid).?),
23272368 .call => return self.analyzeInstCall(scope, old_inst.cast(zir.Inst.Call).?),
23282369 .compileerror => return self.analyzeInstCompileError(scope, old_inst.cast(zir.Inst.CompileError).?),
23292370 .@"const" => return self.analyzeInstConst(scope, old_inst.cast(zir.Inst.Const).?),
......@@ -2436,11 +2477,105 @@ fn analyzeInstCompileError(self: *Module, scope: *Scope, inst: *zir.Inst.Compile
24362477 return self.fail(scope, inst.base.src, "{}", .{inst.positionals.msg});
24372478}
24382479
2480fn analyzeInstArg(self: *Module, scope: *Scope, inst: *zir.Inst.Arg) InnerError!*Inst {
2481 const b = try self.requireRuntimeBlock(scope, inst.base.src);
2482 const fn_ty = b.func.?.owner_decl.typed_value.most_recent.typed_value.ty;
2483 const param_count = fn_ty.fnParamLen();
2484 if (inst.positionals.index >= param_count) {
2485 return self.fail(scope, inst.base.src, "parameter index {} outside list of length {}", .{
2486 inst.positionals.index,
2487 param_count,
2488 });
2489 }
2490 const param_type = fn_ty.fnParamType(inst.positionals.index);
2491 return self.addNewInstArgs(b, inst.base.src, param_type, Inst.Arg, .{
2492 .index = inst.positionals.index,
2493 });
2494}
2495
2496fn analyzeInstBlock(self: *Module, scope: *Scope, inst: *zir.Inst.Block) InnerError!*Inst {
2497 const parent_block = scope.cast(Scope.Block).?;
2498
2499 // Reserve space for a Block instruction so that generated Break instructions can
2500 // point to it, even if it doesn't end up getting used because the code ends up being
2501 // comptime evaluated.
2502 const block_inst = try parent_block.arena.create(Inst.Block);
2503 block_inst.* = .{
2504 .base = .{
2505 .tag = Inst.Block.base_tag,
2506 .ty = undefined, // Set after analysis.
2507 .src = inst.base.src,
2508 },
2509 .args = undefined,
2510 };
2511
2512 var child_block: Scope.Block = .{
2513 .parent = parent_block,
2514 .func = parent_block.func,
2515 .decl = parent_block.decl,
2516 .instructions = .{},
2517 .arena = parent_block.arena,
2518 // TODO @as here is working around a miscompilation compiler bug :(
2519 .label = @as(?Scope.Block.Label, Scope.Block.Label{
2520 .name = inst.positionals.label,
2521 .results = .{},
2522 .block_inst = block_inst,
2523 }),
2524 };
2525 const label = &child_block.label.?;
2526
2527 defer child_block.instructions.deinit(self.allocator);
2528 defer label.results.deinit(self.allocator);
2529
2530 try self.analyzeBody(&child_block.base, inst.positionals.body);
2531
2532 // Blocks must terminate with noreturn instruction.
2533 assert(child_block.instructions.items.len != 0);
2534 assert(child_block.instructions.items[child_block.instructions.items.len - 1].tag.isNoReturn());
2535
2536 if (label.results.items.len <= 1) {
2537 // No need to add the Block instruction; we can add the instructions to the parent block directly.
2538 // Blocks are terminated with a noreturn instruction which we do not want to include.
2539 const instrs = child_block.instructions.items;
2540 try parent_block.instructions.appendSlice(self.allocator, instrs[0 .. instrs.len - 1]);
2541 if (label.results.items.len == 1) {
2542 return label.results.items[0];
2543 } else {
2544 return self.constNoReturn(scope, inst.base.src);
2545 }
2546 }
2547
2548 // Need to set the type and emit the Block instruction. This allows machine code generation
2549 // to emit a jump instruction to after the block when it encounters the break.
2550 try parent_block.instructions.append(self.allocator, &block_inst.base);
2551 block_inst.base.ty = try self.resolvePeerTypes(scope, label.results.items);
2552 block_inst.args.body = .{ .instructions = try parent_block.arena.dupe(*Inst, child_block.instructions.items) };
2553 return &block_inst.base;
2554}
2555
24392556fn analyzeInstBreakpoint(self: *Module, scope: *Scope, inst: *zir.Inst.Breakpoint) InnerError!*Inst {
24402557 const b = try self.requireRuntimeBlock(scope, inst.base.src);
24412558 return self.addNewInstArgs(b, inst.base.src, Type.initTag(.void), Inst.Breakpoint, {});
24422559}
24432560
2561fn analyzeInstBreakVoid(self: *Module, scope: *Scope, inst: *zir.Inst.BreakVoid) InnerError!*Inst {
2562 const label_name = inst.positionals.label;
2563 const void_inst = try self.constVoid(scope, inst.base.src);
2564
2565 var opt_block = scope.cast(Scope.Block);
2566 while (opt_block) |block| {
2567 if (block.label) |*label| {
2568 if (mem.eql(u8, label.name, label_name)) {
2569 try label.results.append(self.allocator, void_inst);
2570 return self.constNoReturn(scope, inst.base.src);
2571 }
2572 }
2573 opt_block = block.parent;
2574 } else {
2575 return self.fail(scope, inst.base.src, "use of undeclared label '{}'", .{label_name});
2576 }
2577}
2578
24442579fn analyzeInstDeclRefStr(self: *Module, scope: *Scope, inst: *zir.Inst.DeclRefStr) InnerError!*Inst {
24452580 const decl_name = try self.resolveConstString(scope, inst.positionals.name);
24462581 return self.analyzeDeclRefByName(scope, inst.base.src, decl_name);
......@@ -2602,35 +2737,38 @@ fn analyzeInstFn(self: *Module, scope: *Scope, fn_inst: *zir.Inst.Fn) InnerError
26022737fn analyzeInstFnType(self: *Module, scope: *Scope, fntype: *zir.Inst.FnType) InnerError!*Inst {
26032738 const return_type = try self.resolveType(scope, fntype.positionals.return_type);
26042739
2605 if (return_type.zigTypeTag() == .NoReturn and
2606 fntype.positionals.param_types.len == 0 and
2607 fntype.kw_args.cc == .Unspecified)
2608 {
2609 return self.constType(scope, fntype.base.src, Type.initTag(.fn_noreturn_no_args));
2610 }
2740 // Hot path for some common function types.
2741 if (fntype.positionals.param_types.len == 0) {
2742 if (return_type.zigTypeTag() == .NoReturn and fntype.kw_args.cc == .Unspecified) {
2743 return self.constType(scope, fntype.base.src, Type.initTag(.fn_noreturn_no_args));
2744 }
26112745
2612 if (return_type.zigTypeTag() == .Void and
2613 fntype.positionals.param_types.len == 0 and
2614 fntype.kw_args.cc == .Unspecified)
2615 {
2616 return self.constType(scope, fntype.base.src, Type.initTag(.fn_void_no_args));
2617 }
2746 if (return_type.zigTypeTag() == .Void and fntype.kw_args.cc == .Unspecified) {
2747 return self.constType(scope, fntype.base.src, Type.initTag(.fn_void_no_args));
2748 }
26182749
2619 if (return_type.zigTypeTag() == .NoReturn and
2620 fntype.positionals.param_types.len == 0 and
2621 fntype.kw_args.cc == .Naked)
2622 {
2623 return self.constType(scope, fntype.base.src, Type.initTag(.fn_naked_noreturn_no_args));
2750 if (return_type.zigTypeTag() == .NoReturn and fntype.kw_args.cc == .Naked) {
2751 return self.constType(scope, fntype.base.src, Type.initTag(.fn_naked_noreturn_no_args));
2752 }
2753
2754 if (return_type.zigTypeTag() == .Void and fntype.kw_args.cc == .C) {
2755 return self.constType(scope, fntype.base.src, Type.initTag(.fn_ccc_void_no_args));
2756 }
26242757 }
26252758
2626 if (return_type.zigTypeTag() == .Void and
2627 fntype.positionals.param_types.len == 0 and
2628 fntype.kw_args.cc == .C)
2629 {
2630 return self.constType(scope, fntype.base.src, Type.initTag(.fn_ccc_void_no_args));
2759 const arena = scope.arena();
2760 const param_types = try arena.alloc(Type, fntype.positionals.param_types.len);
2761 for (fntype.positionals.param_types) |param_type, i| {
2762 param_types[i] = try self.resolveType(scope, param_type);
26312763 }
26322764
2633 return self.fail(scope, fntype.base.src, "TODO implement fntype instruction more", .{});
2765 const payload = try arena.create(Type.Payload.Function);
2766 payload.* = .{
2767 .cc = fntype.kw_args.cc,
2768 .return_type = return_type,
2769 .param_types = param_types,
2770 };
2771 return self.constType(scope, fntype.base.src, Type.initPayload(&payload.base));
26342772}
26352773
26362774fn analyzeInstPrimitive(self: *Module, scope: *Scope, primitive: *zir.Inst.Primitive) InnerError!*Inst {
......@@ -2757,10 +2895,17 @@ fn analyzeInstElemPtr(self: *Module, scope: *Scope, inst: *zir.Inst.ElemPtr) Inn
27572895}
27582896
27592897fn analyzeInstAdd(self: *Module, scope: *Scope, inst: *zir.Inst.Add) InnerError!*Inst {
2898 const tracy = trace(@src());
2899 defer tracy.end();
2900
27602901 const lhs = try self.resolveInst(scope, inst.positionals.lhs);
27612902 const rhs = try self.resolveInst(scope, inst.positionals.rhs);
27622903
27632904 if (lhs.ty.zigTypeTag() == .Int and rhs.ty.zigTypeTag() == .Int) {
2905 if (!lhs.ty.eql(rhs.ty)) {
2906 return self.fail(scope, inst.base.src, "TODO implement peer type resolution", .{});
2907 }
2908
27642909 if (lhs.value()) |lhs_val| {
27652910 if (rhs.value()) |rhs_val| {
27662911 // TODO is this a performance issue? maybe we should try the operation without
......@@ -2777,10 +2922,6 @@ fn analyzeInstAdd(self: *Module, scope: *Scope, inst: *zir.Inst.Add) InnerError!
27772922 result_bigint.add(lhs_bigint, rhs_bigint);
27782923 const result_limbs = result_bigint.limbs[0..result_bigint.len];
27792924
2780 if (!lhs.ty.eql(rhs.ty)) {
2781 return self.fail(scope, inst.base.src, "TODO implement peer type resolution", .{});
2782 }
2783
27842925 const val_payload = if (result_bigint.positive) blk: {
27852926 const val_payload = try scope.arena().create(Value.Payload.IntBigPositive);
27862927 val_payload.* = .{ .limbs = result_limbs };
......@@ -2797,6 +2938,12 @@ fn analyzeInstAdd(self: *Module, scope: *Scope, inst: *zir.Inst.Add) InnerError!
27972938 });
27982939 }
27992940 }
2941
2942 const b = try self.requireRuntimeBlock(scope, inst.base.src);
2943 return self.addNewInstArgs(b, inst.base.src, lhs.ty, Inst.Add, .{
2944 .lhs = lhs,
2945 .rhs = rhs,
2946 });
28002947 }
28012948
28022949 return self.fail(scope, inst.base.src, "TODO implement more analyze add", .{});
......@@ -2936,6 +3083,7 @@ fn analyzeInstCondBr(self: *Module, scope: *Scope, inst: *zir.Inst.CondBr) Inner
29363083 const parent_block = try self.requireRuntimeBlock(scope, inst.base.src);
29373084
29383085 var true_block: Scope.Block = .{
3086 .parent = parent_block,
29393087 .func = parent_block.func,
29403088 .decl = parent_block.decl,
29413089 .instructions = .{},
......@@ -2945,6 +3093,7 @@ fn analyzeInstCondBr(self: *Module, scope: *Scope, inst: *zir.Inst.CondBr) Inner
29453093 try self.analyzeBody(&true_block.base, inst.positionals.true_body);
29463094
29473095 var false_block: Scope.Block = .{
3096 .parent = parent_block,
29483097 .func = parent_block.func,
29493098 .decl = parent_block.decl,
29503099 .instructions = .{},
......@@ -3178,7 +3327,7 @@ fn cmpNumeric(
31783327 const casted_lhs = try self.coerce(scope, dest_type, lhs);
31793328 const casted_rhs = try self.coerce(scope, dest_type, lhs);
31803329
3181 return self.addNewInstArgs(b, src, dest_type, Inst.Cmp, .{
3330 return self.addNewInstArgs(b, src, Type.initTag(.bool), Inst.Cmp, .{
31823331 .lhs = casted_lhs,
31833332 .rhs = casted_rhs,
31843333 .op = op,
......@@ -3197,6 +3346,12 @@ fn makeIntType(self: *Module, scope: *Scope, signed: bool, bits: u16) !Type {
31973346 }
31983347}
31993348
3349fn resolvePeerTypes(self: *Module, scope: *Scope, instructions: []*Inst) !Type {
3350 if (instructions.len == 0)
3351 return Type.initTag(.noreturn);
3352 return self.fail(scope, instructions[0].src, "TODO peer type resolution", .{});
3353}
3354
32003355fn coerce(self: *Module, scope: *Scope, dest_type: Type, inst: *Inst) !*Inst {
32013356 // If the types are the same, we can return the operand.
32023357 if (dest_type.eql(inst.ty))
......@@ -3238,7 +3393,10 @@ fn coerce(self: *Module, scope: *Scope, dest_type: Type, inst: *Inst) !*Inst {
32383393 if (inst.value()) |val| {
32393394 return self.constInst(scope, inst.src, .{ .ty = dest_type, .val = val });
32403395 } else {
3241 return self.fail(scope, inst.src, "TODO implement runtime integer widening", .{});
3396 return self.fail(scope, inst.src, "TODO implement runtime integer widening ({} to {})", .{
3397 inst.ty,
3398 dest_type,
3399 });
32423400 }
32433401 } else {
32443402 return self.fail(scope, inst.src, "TODO implement more int widening {} to {}", .{ inst.ty, dest_type });
src-self-hosted/codegen.zig+22
......@@ -174,6 +174,9 @@ const Function = struct {
174174
175175 fn genFuncInst(self: *Function, inst: *ir.Inst) !MCValue {
176176 switch (inst.tag) {
177 .add => return self.genAdd(inst.cast(ir.Inst.Add).?),
178 .arg => return self.genArg(inst.src),
179 .block => return self.genBlock(inst.cast(ir.Inst.Block).?),
177180 .breakpoint => return self.genBreakpoint(inst.src),
178181 .call => return self.genCall(inst.cast(ir.Inst.Call).?),
179182 .unreach => return MCValue{ .unreach = {} },
......@@ -190,6 +193,19 @@ const Function = struct {
190193 }
191194 }
192195
196 fn genAdd(self: *Function, inst: *ir.Inst.Add) !MCValue {
197 switch (self.target.cpu.arch) {
198 else => return self.fail(inst.base.src, "TODO implement add for {}", .{self.target.cpu.arch}),
199 }
200 }
201
202 fn genArg(self: *Function, src: usize) !MCValue {
203 switch (self.target.cpu.arch) {
204 else => return self.fail(src, "TODO implement function parameters for {}", .{self.target.cpu.arch}),
205 }
206 return .none;
207 }
208
193209 fn genBreakpoint(self: *Function, src: usize) !MCValue {
194210 switch (self.target.cpu.arch) {
195211 .i386, .x86_64 => {
......@@ -302,6 +318,12 @@ const Function = struct {
302318 }
303319 }
304320
321 fn genBlock(self: *Function, inst: *ir.Inst.Block) !MCValue {
322 switch (self.target.cpu.arch) {
323 else => return self.fail(inst.base.src, "TODO implement codegen Block for {}", .{self.target.cpu.arch}),
324 }
325 }
326
305327 fn genAsm(self: *Function, inst: *ir.Inst.Assembly) !MCValue {
306328 // TODO convert to inline function
307329 switch (self.target.cpu.arch) {
src-self-hosted/ir.zig+63-2
......@@ -15,8 +15,11 @@ pub const Inst = struct {
1515 src: usize,
1616
1717 pub const Tag = enum {
18 add,
19 arg,
1820 assembly,
1921 bitcast,
22 block,
2023 breakpoint,
2124 call,
2225 cmp,
......@@ -28,6 +31,33 @@ pub const Inst = struct {
2831 ret,
2932 retvoid,
3033 unreach,
34
35 /// Returns whether the instruction is one of the control flow "noreturn" types.
36 /// Function calls do not count. When ZIR is generated, the compiler automatically
37 /// emits an `Unreach` after a function call with the `noreturn` return type.
38 pub fn isNoReturn(tag: Tag) bool {
39 return switch (tag) {
40 .add,
41 .arg,
42 .assembly,
43 .bitcast,
44 .block,
45 .breakpoint,
46 .cmp,
47 .constant,
48 .isnonnull,
49 .isnull,
50 .ptrtoint,
51 .call,
52 => false,
53
54 .condbr,
55 .ret,
56 .retvoid,
57 .unreach,
58 => true,
59 };
60 }
3161 };
3262
3363 pub fn cast(base: *Inst, comptime T: type) ?*T {
......@@ -50,6 +80,25 @@ pub const Inst = struct {
5080 return inst.val;
5181 }
5282
83 pub const Add = struct {
84 pub const base_tag = Tag.add;
85 base: Inst,
86
87 args: struct {
88 lhs: *Inst,
89 rhs: *Inst,
90 },
91 };
92
93 pub const Arg = struct {
94 pub const base_tag = Tag.arg;
95 base: Inst,
96
97 args: struct {
98 index: usize,
99 },
100 };
101
53102 pub const Assembly = struct {
54103 pub const base_tag = Tag.assembly;
55104 base: Inst,
......@@ -73,6 +122,14 @@ pub const Inst = struct {
73122 },
74123 };
75124
125 pub const Block = struct {
126 pub const base_tag = Tag.block;
127 base: Inst,
128 args: struct {
129 body: Body,
130 },
131 };
132
76133 pub const Breakpoint = struct {
77134 pub const base_tag = Tag.breakpoint;
78135 base: Inst,
......@@ -105,8 +162,8 @@ pub const Inst = struct {
105162 base: Inst,
106163 args: struct {
107164 condition: *Inst,
108 true_body: Module.Body,
109 false_body: Module.Body,
165 true_body: Body,
166 false_body: Body,
110167 },
111168 };
112169
......@@ -164,3 +221,7 @@ pub const Inst = struct {
164221 args: void,
165222 };
166223};
224
225pub const Body = struct {
226 instructions: []*Inst,
227};
src-self-hosted/type.zig+323-17
......@@ -21,8 +21,14 @@ pub const Type = extern union {
2121 switch (self.tag()) {
2222 .u8,
2323 .i8,
24 .isize,
24 .u16,
25 .i16,
26 .u32,
27 .i32,
28 .u64,
29 .i64,
2530 .usize,
31 .isize,
2632 .c_short,
2733 .c_ushort,
2834 .c_int,
......@@ -57,6 +63,7 @@ pub const Type = extern union {
5763 .fn_void_no_args => return .Fn,
5864 .fn_naked_noreturn_no_args => return .Fn,
5965 .fn_ccc_void_no_args => return .Fn,
66 .function => return .Fn,
6067
6168 .array, .array_u8_sentinel_0 => return .Array,
6269 .single_const_pointer => return .Pointer,
......@@ -126,10 +133,14 @@ pub const Type = extern union {
126133 @panic("TODO implement more pointer Type equality comparison");
127134 },
128135 .Int => {
129 if (a.tag() != b.tag()) {
130 // Detect that e.g. u64 != usize, even if the bits match on a particular target.
136 // Detect that e.g. u64 != usize, even if the bits match on a particular target.
137 const a_is_named_int = a.isNamedInt();
138 const b_is_named_int = b.isNamedInt();
139 if (a_is_named_int != b_is_named_int)
131140 return false;
132 }
141 if (a_is_named_int)
142 return a.tag() == b.tag();
143 // Remaining cases are arbitrary sized integers.
133144 // The target will not be branched upon, because we handled target-dependent cases above.
134145 const info_a = a.intInfo(@as(Target, undefined));
135146 const info_b = b.intInfo(@as(Target, undefined));
......@@ -176,8 +187,14 @@ pub const Type = extern union {
176187 } else switch (self.ptr_otherwise.tag) {
177188 .u8,
178189 .i8,
179 .isize,
190 .u16,
191 .i16,
192 .u32,
193 .i32,
194 .u64,
195 .i64,
180196 .usize,
197 .isize,
181198 .c_short,
182199 .c_ushort,
183200 .c_int,
......@@ -231,6 +248,21 @@ pub const Type = extern union {
231248 },
232249 .int_signed => return self.copyPayloadShallow(allocator, Payload.IntSigned),
233250 .int_unsigned => return self.copyPayloadShallow(allocator, Payload.IntUnsigned),
251 .function => {
252 const payload = @fieldParentPtr(Payload.Function, "base", self.ptr_otherwise);
253 const new_payload = try allocator.create(Payload.Function);
254 const param_types = try allocator.alloc(Type, payload.param_types.len);
255 for (payload.param_types) |param_type, i| {
256 param_types[i] = try param_type.copy(allocator);
257 }
258 new_payload.* = .{
259 .base = payload.base,
260 .return_type = try payload.return_type.copy(allocator),
261 .param_types = param_types,
262 .cc = payload.cc,
263 };
264 return Type{ .ptr_otherwise = &new_payload.base };
265 },
234266 }
235267 }
236268
......@@ -246,7 +278,7 @@ pub const Type = extern union {
246278 comptime fmt: []const u8,
247279 options: std.fmt.FormatOptions,
248280 out_stream: var,
249 ) !void {
281 ) @TypeOf(out_stream).Error!void {
250282 comptime assert(fmt.len == 0);
251283 var ty = self;
252284 while (true) {
......@@ -254,8 +286,14 @@ pub const Type = extern union {
254286 switch (t) {
255287 .u8,
256288 .i8,
257 .isize,
289 .u16,
290 .i16,
291 .u32,
292 .i32,
293 .u64,
294 .i64,
258295 .usize,
296 .isize,
259297 .c_short,
260298 .c_ushort,
261299 .c_int,
......@@ -288,6 +326,16 @@ pub const Type = extern union {
288326 .fn_naked_noreturn_no_args => return out_stream.writeAll("fn() callconv(.Naked) noreturn"),
289327 .fn_ccc_void_no_args => return out_stream.writeAll("fn() callconv(.C) void"),
290328 .single_const_pointer_to_comptime_int => return out_stream.writeAll("*const comptime_int"),
329 .function => {
330 const payload = @fieldParentPtr(Payload.Function, "base", ty.ptr_otherwise);
331 try out_stream.writeAll("fn(");
332 for (payload.param_types) |param_type, i| {
333 if (i != 0) try out_stream.writeAll(", ");
334 try param_type.format("", .{}, out_stream);
335 }
336 try out_stream.writeAll(") ");
337 try payload.return_type.format("", .{}, out_stream);
338 },
291339
292340 .array_u8_sentinel_0 => {
293341 const payload = @fieldParentPtr(Payload.Array_u8_Sentinel0, "base", ty.ptr_otherwise);
......@@ -322,8 +370,14 @@ pub const Type = extern union {
322370 switch (self.tag()) {
323371 .u8 => return Value.initTag(.u8_type),
324372 .i8 => return Value.initTag(.i8_type),
325 .isize => return Value.initTag(.isize_type),
373 .u16 => return Value.initTag(.u16_type),
374 .i16 => return Value.initTag(.i16_type),
375 .u32 => return Value.initTag(.u32_type),
376 .i32 => return Value.initTag(.i32_type),
377 .u64 => return Value.initTag(.u64_type),
378 .i64 => return Value.initTag(.i64_type),
326379 .usize => return Value.initTag(.usize_type),
380 .isize => return Value.initTag(.isize_type),
327381 .c_short => return Value.initTag(.c_short_type),
328382 .c_ushort => return Value.initTag(.c_ushort_type),
329383 .c_int => return Value.initTag(.c_int_type),
......@@ -365,8 +419,14 @@ pub const Type = extern union {
365419 return switch (self.tag()) {
366420 .u8,
367421 .i8,
368 .isize,
422 .u16,
423 .i16,
424 .u32,
425 .i32,
426 .u64,
427 .i64,
369428 .usize,
429 .isize,
370430 .c_short,
371431 .c_ushort,
372432 .c_int,
......@@ -386,6 +446,7 @@ pub const Type = extern union {
386446 .fn_void_no_args,
387447 .fn_naked_noreturn_no_args,
388448 .fn_ccc_void_no_args,
449 .function,
389450 .single_const_pointer_to_comptime_int,
390451 .const_slice_u8,
391452 .array_u8_sentinel_0,
......@@ -417,9 +478,14 @@ pub const Type = extern union {
417478 .fn_void_no_args, // represents machine code; not a pointer
418479 .fn_naked_noreturn_no_args, // represents machine code; not a pointer
419480 .fn_ccc_void_no_args, // represents machine code; not a pointer
481 .function, // represents machine code; not a pointer
420482 .array_u8_sentinel_0,
421483 => return 1,
422484
485 .i16, .u16 => return 2,
486 .i32, .u32 => return 4,
487 .i64, .u64 => return 8,
488
423489 .isize,
424490 .usize,
425491 .single_const_pointer_to_comptime_int,
......@@ -473,8 +539,14 @@ pub const Type = extern union {
473539 return switch (self.tag()) {
474540 .u8,
475541 .i8,
476 .isize,
542 .u16,
543 .i16,
544 .u32,
545 .i32,
546 .u64,
547 .i64,
477548 .usize,
549 .isize,
478550 .c_short,
479551 .c_ushort,
480552 .c_int,
......@@ -505,6 +577,7 @@ pub const Type = extern union {
505577 .fn_void_no_args,
506578 .fn_naked_noreturn_no_args,
507579 .fn_ccc_void_no_args,
580 .function,
508581 .int_unsigned,
509582 .int_signed,
510583 => false,
......@@ -519,8 +592,14 @@ pub const Type = extern union {
519592 return switch (self.tag()) {
520593 .u8,
521594 .i8,
522 .isize,
595 .u16,
596 .i16,
597 .u32,
598 .i32,
599 .u64,
600 .i64,
523601 .usize,
602 .isize,
524603 .c_short,
525604 .c_ushort,
526605 .c_int,
......@@ -552,6 +631,7 @@ pub const Type = extern union {
552631 .fn_void_no_args,
553632 .fn_naked_noreturn_no_args,
554633 .fn_ccc_void_no_args,
634 .function,
555635 .int_unsigned,
556636 .int_signed,
557637 => false,
......@@ -565,8 +645,14 @@ pub const Type = extern union {
565645 return switch (self.tag()) {
566646 .u8,
567647 .i8,
568 .isize,
648 .u16,
649 .i16,
650 .u32,
651 .i32,
652 .u64,
653 .i64,
569654 .usize,
655 .isize,
570656 .c_short,
571657 .c_ushort,
572658 .c_int,
......@@ -596,6 +682,7 @@ pub const Type = extern union {
596682 .fn_void_no_args,
597683 .fn_naked_noreturn_no_args,
598684 .fn_ccc_void_no_args,
685 .function,
599686 .int_unsigned,
600687 .int_signed,
601688 => unreachable,
......@@ -612,8 +699,14 @@ pub const Type = extern union {
612699 return switch (self.tag()) {
613700 .u8,
614701 .i8,
615 .isize,
702 .u16,
703 .i16,
704 .u32,
705 .i32,
706 .u64,
707 .i64,
616708 .usize,
709 .isize,
617710 .c_short,
618711 .c_ushort,
619712 .c_int,
......@@ -641,6 +734,7 @@ pub const Type = extern union {
641734 .fn_void_no_args,
642735 .fn_naked_noreturn_no_args,
643736 .fn_ccc_void_no_args,
737 .function,
644738 .int_unsigned,
645739 .int_signed,
646740 => unreachable,
......@@ -657,8 +751,14 @@ pub const Type = extern union {
657751 return switch (self.tag()) {
658752 .u8,
659753 .i8,
660 .isize,
754 .u16,
755 .i16,
756 .u32,
757 .i32,
758 .u64,
759 .i64,
661760 .usize,
761 .isize,
662762 .c_short,
663763 .c_ushort,
664764 .c_int,
......@@ -686,6 +786,7 @@ pub const Type = extern union {
686786 .fn_void_no_args,
687787 .fn_naked_noreturn_no_args,
688788 .fn_ccc_void_no_args,
789 .function,
689790 .single_const_pointer,
690791 .single_const_pointer_to_comptime_int,
691792 .const_slice_u8,
......@@ -703,8 +804,14 @@ pub const Type = extern union {
703804 return switch (self.tag()) {
704805 .u8,
705806 .i8,
706 .isize,
807 .u16,
808 .i16,
809 .u32,
810 .i32,
811 .u64,
812 .i64,
707813 .usize,
814 .isize,
708815 .c_short,
709816 .c_ushort,
710817 .c_int,
......@@ -732,6 +839,7 @@ pub const Type = extern union {
732839 .fn_void_no_args,
733840 .fn_naked_noreturn_no_args,
734841 .fn_ccc_void_no_args,
842 .function,
735843 .single_const_pointer,
736844 .single_const_pointer_to_comptime_int,
737845 .const_slice_u8,
......@@ -766,6 +874,7 @@ pub const Type = extern union {
766874 .fn_void_no_args,
767875 .fn_naked_noreturn_no_args,
768876 .fn_ccc_void_no_args,
877 .function,
769878 .array,
770879 .single_const_pointer,
771880 .single_const_pointer_to_comptime_int,
......@@ -778,6 +887,9 @@ pub const Type = extern union {
778887 .c_uint,
779888 .c_ulong,
780889 .c_ulonglong,
890 .u16,
891 .u32,
892 .u64,
781893 => false,
782894
783895 .int_signed,
......@@ -787,11 +899,14 @@ pub const Type = extern union {
787899 .c_int,
788900 .c_long,
789901 .c_longlong,
902 .i16,
903 .i32,
904 .i64,
790905 => true,
791906 };
792907 }
793908
794 /// Asserts the type is a fixed-width integer.
909 /// Asserts the type is an integer.
795910 pub fn intInfo(self: Type, target: Target) struct { signed: bool, bits: u16 } {
796911 return switch (self.tag()) {
797912 .f16,
......@@ -813,6 +928,7 @@ pub const Type = extern union {
813928 .fn_void_no_args,
814929 .fn_naked_noreturn_no_args,
815930 .fn_ccc_void_no_args,
931 .function,
816932 .array,
817933 .single_const_pointer,
818934 .single_const_pointer_to_comptime_int,
......@@ -824,6 +940,12 @@ pub const Type = extern union {
824940 .int_signed => .{ .signed = true, .bits = self.cast(Payload.IntSigned).?.bits },
825941 .u8 => .{ .signed = false, .bits = 8 },
826942 .i8 => .{ .signed = true, .bits = 8 },
943 .u16 => .{ .signed = false, .bits = 16 },
944 .i16 => .{ .signed = true, .bits = 16 },
945 .u32 => .{ .signed = false, .bits = 32 },
946 .i32 => .{ .signed = true, .bits = 32 },
947 .u64 => .{ .signed = false, .bits = 64 },
948 .i64 => .{ .signed = true, .bits = 64 },
827949 .usize => .{ .signed = false, .bits = target.cpu.arch.ptrBitWidth() },
828950 .isize => .{ .signed = true, .bits = target.cpu.arch.ptrBitWidth() },
829951 .c_short => .{ .signed = true, .bits = CType.short.sizeInBits(target) },
......@@ -837,6 +959,59 @@ pub const Type = extern union {
837959 };
838960 }
839961
962 pub fn isNamedInt(self: Type) bool {
963 return switch (self.tag()) {
964 .f16,
965 .f32,
966 .f64,
967 .f128,
968 .c_longdouble,
969 .c_void,
970 .bool,
971 .void,
972 .type,
973 .anyerror,
974 .comptime_int,
975 .comptime_float,
976 .noreturn,
977 .@"null",
978 .@"undefined",
979 .fn_noreturn_no_args,
980 .fn_void_no_args,
981 .fn_naked_noreturn_no_args,
982 .fn_ccc_void_no_args,
983 .function,
984 .array,
985 .single_const_pointer,
986 .single_const_pointer_to_comptime_int,
987 .array_u8_sentinel_0,
988 .const_slice_u8,
989 .int_unsigned,
990 .int_signed,
991 .u8,
992 .i8,
993 .u16,
994 .i16,
995 .u32,
996 .i32,
997 .u64,
998 .i64,
999 => false,
1000
1001 .usize,
1002 .isize,
1003 .c_short,
1004 .c_ushort,
1005 .c_int,
1006 .c_uint,
1007 .c_long,
1008 .c_ulong,
1009 .c_longlong,
1010 .c_ulonglong,
1011 => true,
1012 };
1013 }
1014
8401015 pub fn isFloat(self: Type) bool {
8411016 return switch (self.tag()) {
8421017 .f16,
......@@ -870,6 +1045,7 @@ pub const Type = extern union {
8701045 .fn_void_no_args => 0,
8711046 .fn_naked_noreturn_no_args => 0,
8721047 .fn_ccc_void_no_args => 0,
1048 .function => @fieldParentPtr(Payload.Function, "base", self.ptr_otherwise).param_types.len,
8731049
8741050 .f16,
8751051 .f32,
......@@ -893,6 +1069,12 @@ pub const Type = extern union {
8931069 .const_slice_u8,
8941070 .u8,
8951071 .i8,
1072 .u16,
1073 .i16,
1074 .u32,
1075 .i32,
1076 .u64,
1077 .i64,
8961078 .usize,
8971079 .isize,
8981080 .c_short,
......@@ -917,6 +1099,10 @@ pub const Type = extern union {
9171099 .fn_void_no_args => return,
9181100 .fn_naked_noreturn_no_args => return,
9191101 .fn_ccc_void_no_args => return,
1102 .function => {
1103 const payload = @fieldParentPtr(Payload.Function, "base", self.ptr_otherwise);
1104 std.mem.copy(Type, types, payload.param_types);
1105 },
9201106
9211107 .f16,
9221108 .f32,
......@@ -940,6 +1126,68 @@ pub const Type = extern union {
9401126 .const_slice_u8,
9411127 .u8,
9421128 .i8,
1129 .u16,
1130 .i16,
1131 .u32,
1132 .i32,
1133 .u64,
1134 .i64,
1135 .usize,
1136 .isize,
1137 .c_short,
1138 .c_ushort,
1139 .c_int,
1140 .c_uint,
1141 .c_long,
1142 .c_ulong,
1143 .c_longlong,
1144 .c_ulonglong,
1145 .int_unsigned,
1146 .int_signed,
1147 => unreachable,
1148 }
1149 }
1150
1151 /// Asserts the type is a function.
1152 pub fn fnParamType(self: Type, index: usize) Type {
1153 switch (self.tag()) {
1154 .function => {
1155 const payload = @fieldParentPtr(Payload.Function, "base", self.ptr_otherwise);
1156 return payload.param_types[index];
1157 },
1158
1159 .fn_noreturn_no_args,
1160 .fn_void_no_args,
1161 .fn_naked_noreturn_no_args,
1162 .fn_ccc_void_no_args,
1163 .f16,
1164 .f32,
1165 .f64,
1166 .f128,
1167 .c_longdouble,
1168 .c_void,
1169 .bool,
1170 .void,
1171 .type,
1172 .anyerror,
1173 .comptime_int,
1174 .comptime_float,
1175 .noreturn,
1176 .@"null",
1177 .@"undefined",
1178 .array,
1179 .single_const_pointer,
1180 .single_const_pointer_to_comptime_int,
1181 .array_u8_sentinel_0,
1182 .const_slice_u8,
1183 .u8,
1184 .i8,
1185 .u16,
1186 .i16,
1187 .u32,
1188 .i32,
1189 .u64,
1190 .i64,
9431191 .usize,
9441192 .isize,
9451193 .c_short,
......@@ -966,6 +1214,8 @@ pub const Type = extern union {
9661214 .fn_ccc_void_no_args,
9671215 => Type.initTag(.void),
9681216
1217 .function => @fieldParentPtr(Payload.Function, "base", self.ptr_otherwise).return_type,
1218
9691219 .f16,
9701220 .f32,
9711221 .f64,
......@@ -988,6 +1238,12 @@ pub const Type = extern union {
9881238 .const_slice_u8,
9891239 .u8,
9901240 .i8,
1241 .u16,
1242 .i16,
1243 .u32,
1244 .i32,
1245 .u64,
1246 .i64,
9911247 .usize,
9921248 .isize,
9931249 .c_short,
......@@ -1011,6 +1267,7 @@ pub const Type = extern union {
10111267 .fn_void_no_args => .Unspecified,
10121268 .fn_naked_noreturn_no_args => .Naked,
10131269 .fn_ccc_void_no_args => .C,
1270 .function => @fieldParentPtr(Payload.Function, "base", self.ptr_otherwise).cc,
10141271
10151272 .f16,
10161273 .f32,
......@@ -1034,6 +1291,12 @@ pub const Type = extern union {
10341291 .const_slice_u8,
10351292 .u8,
10361293 .i8,
1294 .u16,
1295 .i16,
1296 .u32,
1297 .i32,
1298 .u64,
1299 .i64,
10371300 .usize,
10381301 .isize,
10391302 .c_short,
......@@ -1057,6 +1320,7 @@ pub const Type = extern union {
10571320 .fn_void_no_args => false,
10581321 .fn_naked_noreturn_no_args => false,
10591322 .fn_ccc_void_no_args => false,
1323 .function => false,
10601324
10611325 .f16,
10621326 .f32,
......@@ -1080,6 +1344,12 @@ pub const Type = extern union {
10801344 .const_slice_u8,
10811345 .u8,
10821346 .i8,
1347 .u16,
1348 .i16,
1349 .u32,
1350 .i32,
1351 .u64,
1352 .i64,
10831353 .usize,
10841354 .isize,
10851355 .c_short,
......@@ -1107,6 +1377,12 @@ pub const Type = extern union {
11071377 .comptime_float,
11081378 .u8,
11091379 .i8,
1380 .u16,
1381 .i16,
1382 .u32,
1383 .i32,
1384 .u64,
1385 .i64,
11101386 .usize,
11111387 .isize,
11121388 .c_short,
......@@ -1133,6 +1409,7 @@ pub const Type = extern union {
11331409 .fn_void_no_args,
11341410 .fn_naked_noreturn_no_args,
11351411 .fn_ccc_void_no_args,
1412 .function,
11361413 .array,
11371414 .single_const_pointer,
11381415 .single_const_pointer_to_comptime_int,
......@@ -1154,6 +1431,12 @@ pub const Type = extern union {
11541431 .comptime_float,
11551432 .u8,
11561433 .i8,
1434 .u16,
1435 .i16,
1436 .u32,
1437 .i32,
1438 .u64,
1439 .i64,
11571440 .usize,
11581441 .isize,
11591442 .c_short,
......@@ -1171,6 +1454,7 @@ pub const Type = extern union {
11711454 .fn_void_no_args,
11721455 .fn_naked_noreturn_no_args,
11731456 .fn_ccc_void_no_args,
1457 .function,
11741458 .single_const_pointer_to_comptime_int,
11751459 .array_u8_sentinel_0,
11761460 .const_slice_u8,
......@@ -1211,6 +1495,12 @@ pub const Type = extern union {
12111495 .comptime_float,
12121496 .u8,
12131497 .i8,
1498 .u16,
1499 .i16,
1500 .u32,
1501 .i32,
1502 .u64,
1503 .i64,
12141504 .usize,
12151505 .isize,
12161506 .c_short,
......@@ -1228,6 +1518,7 @@ pub const Type = extern union {
12281518 .fn_void_no_args,
12291519 .fn_naked_noreturn_no_args,
12301520 .fn_ccc_void_no_args,
1521 .function,
12311522 .single_const_pointer_to_comptime_int,
12321523 .array_u8_sentinel_0,
12331524 .const_slice_u8,
......@@ -1254,8 +1545,14 @@ pub const Type = extern union {
12541545 // The first section of this enum are tags that require no payload.
12551546 u8,
12561547 i8,
1257 isize,
1548 u16,
1549 i16,
1550 u32,
1551 i32,
1552 u64,
1553 i64,
12581554 usize,
1555 isize,
12591556 c_short,
12601557 c_ushort,
12611558 c_int,
......@@ -1292,6 +1589,7 @@ pub const Type = extern union {
12921589 single_const_pointer,
12931590 int_signed,
12941591 int_unsigned,
1592 function,
12951593
12961594 pub const last_no_payload_tag = Tag.const_slice_u8;
12971595 pub const no_payload_count = @enumToInt(last_no_payload_tag) + 1;
......@@ -1330,6 +1628,14 @@ pub const Type = extern union {
13301628
13311629 bits: u16,
13321630 };
1631
1632 pub const Function = struct {
1633 base: Payload = Payload{ .tag = .function },
1634
1635 param_types: []Type,
1636 return_type: Type,
1637 cc: std.builtin.CallingConvention,
1638 };
13331639 };
13341640};
13351641
src-self-hosted/value.zig+90-12
......@@ -23,8 +23,14 @@ pub const Value = extern union {
2323 // The first section of this enum are tags that require no payload.
2424 u8_type,
2525 i8_type,
26 isize_type,
26 u16_type,
27 i16_type,
28 u32_type,
29 i32_type,
30 u64_type,
31 i64_type,
2732 usize_type,
33 isize_type,
2834 c_short_type,
2935 c_ushort_type,
3036 c_int_type,
......@@ -114,8 +120,14 @@ pub const Value = extern union {
114120 } else switch (self.ptr_otherwise.tag) {
115121 .u8_type,
116122 .i8_type,
117 .isize_type,
123 .u16_type,
124 .i16_type,
125 .u32_type,
126 .i32_type,
127 .u64_type,
128 .i64_type,
118129 .usize_type,
130 .isize_type,
119131 .c_short_type,
120132 .c_ushort_type,
121133 .c_int_type,
......@@ -222,6 +234,12 @@ pub const Value = extern union {
222234 while (true) switch (val.tag()) {
223235 .u8_type => return out_stream.writeAll("u8"),
224236 .i8_type => return out_stream.writeAll("i8"),
237 .u16_type => return out_stream.writeAll("u16"),
238 .i16_type => return out_stream.writeAll("i16"),
239 .u32_type => return out_stream.writeAll("u32"),
240 .i32_type => return out_stream.writeAll("i32"),
241 .u64_type => return out_stream.writeAll("u64"),
242 .i64_type => return out_stream.writeAll("i64"),
225243 .isize_type => return out_stream.writeAll("isize"),
226244 .usize_type => return out_stream.writeAll("usize"),
227245 .c_short_type => return out_stream.writeAll("c_short"),
......@@ -308,8 +326,14 @@ pub const Value = extern union {
308326
309327 .u8_type => Type.initTag(.u8),
310328 .i8_type => Type.initTag(.i8),
311 .isize_type => Type.initTag(.isize),
329 .u16_type => Type.initTag(.u16),
330 .i16_type => Type.initTag(.i16),
331 .u32_type => Type.initTag(.u32),
332 .i32_type => Type.initTag(.i32),
333 .u64_type => Type.initTag(.u64),
334 .i64_type => Type.initTag(.i64),
312335 .usize_type => Type.initTag(.usize),
336 .isize_type => Type.initTag(.isize),
313337 .c_short_type => Type.initTag(.c_short),
314338 .c_ushort_type => Type.initTag(.c_ushort),
315339 .c_int_type => Type.initTag(.c_int),
......@@ -366,8 +390,14 @@ pub const Value = extern union {
366390 .ty,
367391 .u8_type,
368392 .i8_type,
369 .isize_type,
393 .u16_type,
394 .i16_type,
395 .u32_type,
396 .i32_type,
397 .u64_type,
398 .i64_type,
370399 .usize_type,
400 .isize_type,
371401 .c_short_type,
372402 .c_ushort_type,
373403 .c_int_type,
......@@ -426,8 +456,14 @@ pub const Value = extern union {
426456 .ty,
427457 .u8_type,
428458 .i8_type,
429 .isize_type,
459 .u16_type,
460 .i16_type,
461 .u32_type,
462 .i32_type,
463 .u64_type,
464 .i64_type,
430465 .usize_type,
466 .isize_type,
431467 .c_short_type,
432468 .c_ushort_type,
433469 .c_int_type,
......@@ -487,8 +523,14 @@ pub const Value = extern union {
487523 .ty,
488524 .u8_type,
489525 .i8_type,
490 .isize_type,
526 .u16_type,
527 .i16_type,
528 .u32_type,
529 .i32_type,
530 .u64_type,
531 .i64_type,
491532 .usize_type,
533 .isize_type,
492534 .c_short_type,
493535 .c_ushort_type,
494536 .c_int_type,
......@@ -553,8 +595,14 @@ pub const Value = extern union {
553595 .ty,
554596 .u8_type,
555597 .i8_type,
556 .isize_type,
598 .u16_type,
599 .i16_type,
600 .u32_type,
601 .i32_type,
602 .u64_type,
603 .i64_type,
557604 .usize_type,
605 .isize_type,
558606 .c_short_type,
559607 .c_ushort_type,
560608 .c_int_type,
......@@ -648,8 +696,14 @@ pub const Value = extern union {
648696 .ty,
649697 .u8_type,
650698 .i8_type,
651 .isize_type,
699 .u16_type,
700 .i16_type,
701 .u32_type,
702 .i32_type,
703 .u64_type,
704 .i64_type,
652705 .usize_type,
706 .isize_type,
653707 .c_short_type,
654708 .c_ushort_type,
655709 .c_int_type,
......@@ -705,8 +759,14 @@ pub const Value = extern union {
705759 .ty,
706760 .u8_type,
707761 .i8_type,
708 .isize_type,
762 .u16_type,
763 .i16_type,
764 .u32_type,
765 .i32_type,
766 .u64_type,
767 .i64_type,
709768 .usize_type,
769 .isize_type,
710770 .c_short_type,
711771 .c_ushort_type,
712772 .c_int_type,
......@@ -807,8 +867,14 @@ pub const Value = extern union {
807867 .ty,
808868 .u8_type,
809869 .i8_type,
810 .isize_type,
870 .u16_type,
871 .i16_type,
872 .u32_type,
873 .i32_type,
874 .u64_type,
875 .i64_type,
811876 .usize_type,
877 .isize_type,
812878 .c_short_type,
813879 .c_ushort_type,
814880 .c_int_type,
......@@ -870,8 +936,14 @@ pub const Value = extern union {
870936 .ty,
871937 .u8_type,
872938 .i8_type,
873 .isize_type,
939 .u16_type,
940 .i16_type,
941 .u32_type,
942 .i32_type,
943 .u64_type,
944 .i64_type,
874945 .usize_type,
946 .isize_type,
875947 .c_short_type,
876948 .c_ushort_type,
877949 .c_int_type,
......@@ -950,8 +1022,14 @@ pub const Value = extern union {
9501022 .ty,
9511023 .u8_type,
9521024 .i8_type,
953 .isize_type,
1025 .u16_type,
1026 .i16_type,
1027 .u32_type,
1028 .i32_type,
1029 .u64_type,
1030 .i64_type,
9541031 .usize_type,
1032 .isize_type,
9551033 .c_short_type,
9561034 .c_ushort_type,
9571035 .c_int_type,
src-self-hosted/zir.zig+139-19
......@@ -34,7 +34,13 @@ pub const Inst = struct {
3434
3535 /// These names are used directly as the instruction names in the text format.
3636 pub const Tag = enum {
37 /// Function parameter value.
38 arg,
39 /// A labeled block of code, which can return a value.
40 block,
3741 breakpoint,
42 /// Same as `break` but without an operand; the operand is assumed to be the void value.
43 breakvoid,
3844 call,
3945 compileerror,
4046 /// Special case, has no textual representation.
......@@ -75,7 +81,10 @@ pub const Inst = struct {
7581
7682 pub fn TagToType(tag: Tag) type {
7783 return switch (tag) {
84 .arg => Arg,
85 .block => Block,
7886 .breakpoint => Breakpoint,
87 .breakvoid => BreakVoid,
7988 .call => Call,
8089 .declref => DeclRef,
8190 .declref_str => DeclRefStr,
......@@ -115,6 +124,27 @@ pub const Inst = struct {
115124 return @fieldParentPtr(T, "base", base);
116125 }
117126
127 pub const Arg = struct {
128 pub const base_tag = Tag.arg;
129 base: Inst,
130
131 positionals: struct {
132 index: usize,
133 },
134 kw_args: struct {},
135 };
136
137 pub const Block = struct {
138 pub const base_tag = Tag.block;
139 base: Inst,
140
141 positionals: struct {
142 label: []const u8,
143 body: Module.Body,
144 },
145 kw_args: struct {},
146 };
147
118148 pub const Breakpoint = struct {
119149 pub const base_tag = Tag.breakpoint;
120150 base: Inst,
......@@ -123,6 +153,16 @@ pub const Inst = struct {
123153 kw_args: struct {},
124154 };
125155
156 pub const BreakVoid = struct {
157 pub const base_tag = Tag.breakvoid;
158 base: Inst,
159
160 positionals: struct {
161 label: []const u8,
162 },
163 kw_args: struct {},
164 };
165
126166 pub const Call = struct {
127167 pub const base_tag = Tag.call;
128168 base: Inst,
......@@ -347,6 +387,14 @@ pub const Inst = struct {
347387 kw_args: struct {},
348388
349389 pub const Builtin = enum {
390 i8,
391 u8,
392 i16,
393 u16,
394 i32,
395 u32,
396 i64,
397 u64,
350398 isize,
351399 usize,
352400 c_short,
......@@ -378,6 +426,14 @@ pub const Inst = struct {
378426
379427 pub fn toTypedValue(self: Builtin) TypedValue {
380428 return switch (self) {
429 .i8 => .{ .ty = Type.initTag(.type), .val = Value.initTag(.i8_type) },
430 .u8 => .{ .ty = Type.initTag(.type), .val = Value.initTag(.u8_type) },
431 .i16 => .{ .ty = Type.initTag(.type), .val = Value.initTag(.i16_type) },
432 .u16 => .{ .ty = Type.initTag(.type), .val = Value.initTag(.u16_type) },
433 .i32 => .{ .ty = Type.initTag(.type), .val = Value.initTag(.i32_type) },
434 .u32 => .{ .ty = Type.initTag(.type), .val = Value.initTag(.u32_type) },
435 .i64 => .{ .ty = Type.initTag(.type), .val = Value.initTag(.i64_type) },
436 .u64 => .{ .ty = Type.initTag(.type), .val = Value.initTag(.u64_type) },
381437 .isize => .{ .ty = Type.initTag(.type), .val = Value.initTag(.isize_type) },
382438 .usize => .{ .ty = Type.initTag(.type), .val = Value.initTag(.usize_type) },
383439 .c_short => .{ .ty = Type.initTag(.type), .val = Value.initTag(.c_short_type) },
......@@ -591,7 +647,10 @@ pub const Module = struct {
591647 ) @TypeOf(stream).Error!void {
592648 // TODO I tried implementing this with an inline for loop and hit a compiler bug
593649 switch (inst.tag) {
650 .arg => return self.writeInstToStreamGeneric(stream, .arg, inst, inst_table),
651 .block => return self.writeInstToStreamGeneric(stream, .block, inst, inst_table),
594652 .breakpoint => return self.writeInstToStreamGeneric(stream, .breakpoint, inst, inst_table),
653 .breakvoid => return self.writeInstToStreamGeneric(stream, .breakvoid, inst, inst_table),
595654 .call => return self.writeInstToStreamGeneric(stream, .call, inst, inst_table),
596655 .declref => return self.writeInstToStreamGeneric(stream, .declref, inst, inst_table),
597656 .declref_str => return self.writeInstToStreamGeneric(stream, .declref_str, inst, inst_table),
......@@ -691,7 +750,7 @@ pub const Module = struct {
691750 },
692751 bool => return stream.writeByte("01"[@boolToInt(param)]),
693752 []u8, []const u8 => return std.zig.renderStringLiteral(param, stream),
694 BigIntConst => return stream.print("{}", .{param}),
753 BigIntConst, usize => return stream.print("{}", .{param}),
695754 TypedValue => unreachable, // this is a special case
696755 *IrModule.Decl => unreachable, // this is a special case
697756 else => |T| @compileError("unimplemented: rendering parameter of type " ++ @typeName(T)),
......@@ -718,7 +777,7 @@ pub const Module = struct {
718777};
719778
720779pub fn parse(allocator: *Allocator, source: [:0]const u8) Allocator.Error!Module {
721 var global_name_map = std.StringHashMap(usize).init(allocator);
780 var global_name_map = std.StringHashMap(*Inst).init(allocator);
722781 defer global_name_map.deinit();
723782
724783 var parser: Parser = .{
......@@ -752,22 +811,24 @@ const Parser = struct {
752811 i: usize,
753812 source: [:0]const u8,
754813 decls: std.ArrayListUnmanaged(*Decl),
755 global_name_map: *std.StringHashMap(usize),
814 global_name_map: *std.StringHashMap(*Inst),
756815 error_msg: ?ErrorMsg = null,
757816 unnamed_index: usize,
758817
759818 const Body = struct {
760819 instructions: std.ArrayList(*Inst),
761 name_map: std.StringHashMap(usize),
820 name_map: *std.StringHashMap(*Inst),
762821 };
763822
764 fn parseBody(self: *Parser) !Module.Body {
823 fn parseBody(self: *Parser, body_ctx: ?*Body) !Module.Body {
824 var name_map = std.StringHashMap(*Inst).init(self.allocator);
825 defer name_map.deinit();
826
765827 var body_context = Body{
766828 .instructions = std.ArrayList(*Inst).init(self.allocator),
767 .name_map = std.StringHashMap(usize).init(self.allocator),
829 .name_map = if (body_ctx) |bctx| bctx.name_map else &name_map,
768830 };
769831 defer body_context.instructions.deinit();
770 defer body_context.name_map.deinit();
771832
772833 try requireEatBytes(self, "{");
773834 skipSpace(self);
......@@ -782,7 +843,7 @@ const Parser = struct {
782843 skipSpace(self);
783844 const decl = try parseInstruction(self, &body_context, ident);
784845 const ident_index = body_context.instructions.items.len;
785 if (try body_context.name_map.put(ident, ident_index)) |_| {
846 if (try body_context.name_map.put(ident, decl.inst)) |_| {
786847 return self.fail("redefinition of identifier '{}'", .{ident});
787848 }
788849 try body_context.instructions.append(decl.inst);
......@@ -866,12 +927,12 @@ const Parser = struct {
866927 skipSpace(self);
867928 try requireEatBytes(self, "=");
868929 skipSpace(self);
869 const inst = try parseInstruction(self, null, ident);
930 const decl = try parseInstruction(self, null, ident);
870931 const ident_index = self.decls.items.len;
871 if (try self.global_name_map.put(ident, ident_index)) |_| {
932 if (try self.global_name_map.put(ident, decl.inst)) |_| {
872933 return self.fail("redefinition of identifier '{}'", .{ident});
873934 }
874 try self.decls.append(self.allocator, inst);
935 try self.decls.append(self.allocator, decl);
875936 },
876937 ' ', '\n' => self.i += 1,
877938 0 => break,
......@@ -1032,7 +1093,7 @@ const Parser = struct {
10321093 };
10331094 }
10341095 switch (T) {
1035 Module.Body => return parseBody(self),
1096 Module.Body => return parseBody(self, body_ctx),
10361097 bool => {
10371098 const bool_value = switch (self.source[self.i]) {
10381099 '0' => false,
......@@ -1060,6 +1121,10 @@ const Parser = struct {
10601121 *Inst => return parseParameterInst(self, body_ctx),
10611122 []u8, []const u8 => return self.parseStringLiteral(),
10621123 BigIntConst => return self.parseIntegerLiteral(),
1124 usize => {
1125 const big_int = try self.parseIntegerLiteral();
1126 return big_int.to(usize) catch |err| return self.fail("integer literal: {}", .{@errorName(err)});
1127 },
10631128 TypedValue => return self.fail("'const' is a special instruction; not legal in ZIR text", .{}),
10641129 *IrModule.Decl => return self.fail("'declval_in_module' is a special instruction; not legal in ZIR text", .{}),
10651130 else => @compileError("Unimplemented: ir parseParameterGeneric for type " ++ @typeName(T)),
......@@ -1075,7 +1140,7 @@ const Parser = struct {
10751140 };
10761141 const map = if (local_ref)
10771142 if (body_ctx) |bc|
1078 &bc.name_map
1143 bc.name_map
10791144 else
10801145 return self.fail("referencing a % instruction in global scope", .{})
10811146 else
......@@ -1107,11 +1172,7 @@ const Parser = struct {
11071172 return &declval.base;
11081173 }
11091174 };
1110 if (local_ref) {
1111 return body_ctx.?.instructions.items[kv.value];
1112 } else {
1113 return self.decls.items[kv.value].inst;
1114 }
1175 return kv.value;
11151176 }
11161177
11171178 fn generateName(self: *Parser) ![]u8 {
......@@ -1456,7 +1517,7 @@ const EmitZIR = struct {
14561517
14571518 fn emitBody(
14581519 self: *EmitZIR,
1459 body: IrModule.Body,
1520 body: ir.Body,
14601521 inst_table: *std.AutoHashMap(*ir.Inst, *Inst),
14611522 instructions: *std.ArrayList(*Inst),
14621523 ) Allocator.Error!void {
......@@ -1466,6 +1527,57 @@ const EmitZIR = struct {
14661527 };
14671528 for (body.instructions) |inst| {
14681529 const new_inst = switch (inst.tag) {
1530 .add => blk: {
1531 const old_inst = inst.cast(ir.Inst.Add).?;
1532 const new_inst = try self.arena.allocator.create(Inst.Add);
1533 new_inst.* = .{
1534 .base = .{
1535 .src = inst.src,
1536 .tag = Inst.Add.base_tag,
1537 },
1538 .positionals = .{
1539 .lhs = try self.resolveInst(new_body, old_inst.args.lhs),
1540 .rhs = try self.resolveInst(new_body, old_inst.args.rhs),
1541 },
1542 .kw_args = .{},
1543 };
1544 break :blk &new_inst.base;
1545 },
1546 .arg => blk: {
1547 const old_inst = inst.cast(ir.Inst.Arg).?;
1548 const new_inst = try self.arena.allocator.create(Inst.Arg);
1549 new_inst.* = .{
1550 .base = .{
1551 .src = inst.src,
1552 .tag = Inst.Arg.base_tag,
1553 },
1554 .positionals = .{ .index = old_inst.args.index },
1555 .kw_args = .{},
1556 };
1557 break :blk &new_inst.base;
1558 },
1559 .block => blk: {
1560 const old_inst = inst.cast(ir.Inst.Block).?;
1561 const new_inst = try self.arena.allocator.create(Inst.Block);
1562
1563 var block_body = std.ArrayList(*Inst).init(self.allocator);
1564 defer block_body.deinit();
1565
1566 try self.emitBody(old_inst.args.body, inst_table, &block_body);
1567
1568 new_inst.* = .{
1569 .base = .{
1570 .src = inst.src,
1571 .tag = Inst.Block.base_tag,
1572 },
1573 .positionals = .{
1574 .label = try self.autoName(),
1575 .body = .{ .instructions = block_body.toOwnedSlice() },
1576 },
1577 .kw_args = .{},
1578 };
1579 break :blk &new_inst.base;
1580 },
14691581 .breakpoint => try self.emitTrivial(inst.src, Inst.Breakpoint),
14701582 .call => blk: {
14711583 const old_inst = inst.cast(ir.Inst.Call).?;
......@@ -1660,6 +1772,14 @@ const EmitZIR = struct {
16601772
16611773 fn emitType(self: *EmitZIR, src: usize, ty: Type) Allocator.Error!*Decl {
16621774 switch (ty.tag()) {
1775 .i8 => return self.emitPrimitive(src, .i8),
1776 .u8 => return self.emitPrimitive(src, .u8),
1777 .i16 => return self.emitPrimitive(src, .i16),
1778 .u16 => return self.emitPrimitive(src, .u16),
1779 .i32 => return self.emitPrimitive(src, .i32),
1780 .u32 => return self.emitPrimitive(src, .u32),
1781 .i64 => return self.emitPrimitive(src, .i64),
1782 .u64 => return self.emitPrimitive(src, .u64),
16631783 .isize => return self.emitPrimitive(src, .isize),
16641784 .usize => return self.emitPrimitive(src, .usize),
16651785 .c_short => return self.emitPrimitive(src, .c_short),