From 2ae72c6f091716a4c1a30928dc1a49c9a1ed312a Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 3 May 2021 20:05:29 -0700 Subject: [PATCH] Sema: implement ExportOptions support in `@export` Also fix switch blocks not emitting their AIR code. --- BRANCH_TODO | 2 - lib/std/start.zig | 2 +- src/Module.zig | 4 ++ src/Sema.zig | 129 ++++++++++++++++++++++++++-------------------- src/value.zig | 9 ++++ 5 files changed, 87 insertions(+), 59 deletions(-) diff --git a/BRANCH_TODO b/BRANCH_TODO index d96b1fc6fe44fb3972e8a76c606ee0869bd80653..e64354dcbc83709ceb4b8d872de4dcf95c853140 100644 --- a/BRANCH_TODO +++ b/BRANCH_TODO @@ -1,5 +1,3 @@ - * implement lazy struct field resolution; don't resolve struct fields until - they are needed. * AstGen threadlocal * extern "foo" for vars and for functions * namespace decls table can't reference ZIR memory because it can get modified on updates diff --git a/lib/std/start.zig b/lib/std/start.zig index 68fcd1955d9178ac742561a6c1c6f522965faeb2..d34c7365a95d0cf8a68712ad142798e3f6b0c3af 100644 --- a/lib/std/start.zig +++ b/lib/std/start.zig @@ -83,7 +83,7 @@ fn _start2() callconv(.Naked) noreturn { exit2(0); } -fn exit2(code: u8) noreturn { +fn exit2(code: usize) noreturn { switch (builtin.stage2_arch) { .x86_64 => { asm volatile ("syscall" diff --git a/src/Module.zig b/src/Module.zig index 16a6ff6acfea423d886b944ae105d793049cb391..6d6443076cc373ca7b26b750d240df0d9adb9649 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -3273,6 +3273,10 @@ pub fn analyzeExport( const owner_decl = scope.ownerDecl().?; + log.debug("exporting Decl '{s}' as symbol '{s}' from Decl '{s}'", .{ + exported_decl.name, borrowed_symbol_name, owner_decl.name, + }); + new_export.* = .{ .options = .{ .name = symbol_name }, .src = src, diff --git a/src/Sema.zig b/src/Sema.zig index 049b289cb8b136bff2afbbcd0df6d0d9b3241792..87f2f475ffbf78e7dffec2511c17ee8aaf69d021 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -1617,6 +1617,18 @@ fn zirBlock(sema: *Sema, parent_block: *Scope.Block, inst: Zir.Inst.Index) Inner return sema.analyzeBlockBody(parent_block, src, &child_block, merges); } +fn resolveBlockBody( + sema: *Sema, + parent_block: *Scope.Block, + src: LazySrcLoc, + child_block: *Scope.Block, + body: []const Zir.Inst.Index, + merges: *Scope.Block.Merges, +) InnerError!*Inst { + _ = try sema.analyzeBody(child_block, body); + return sema.analyzeBlockBody(parent_block, src, child_block, merges); +} + fn analyzeBlockBody( sema: *Sema, parent_block: *Scope.Block, @@ -1711,11 +1723,23 @@ fn zirExport(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError! const decl_name = sema.code.nullTerminatedString(extra.decl_name); const decl = try sema.lookupIdentifier(block, lhs_src, decl_name); const options = try sema.resolveInstConst(block, rhs_src, extra.options); + const struct_obj = options.ty.castTag(.@"struct").?.data; + const fields = options.val.castTag(.@"struct").?.data[0..struct_obj.fields.count()]; + const name_index = struct_obj.fields.getIndex("name").?; + const linkage_index = struct_obj.fields.getIndex("linkage").?; + const section_index = struct_obj.fields.getIndex("section").?; + const export_name = try fields[name_index].toAllocatedBytes(sema.arena); + const linkage = fields[linkage_index].toEnum( + struct_obj.fields.items()[linkage_index].value.ty, + std.builtin.GlobalLinkage, + ); - // TODO respect the name, linkage, and section options. Until then we export - // as the decl name. - _ = options; - const export_name = mem.spanZ(decl.name); + if (linkage != .Strong) { + return sema.mod.fail(&block.base, src, "TODO: implement exporting with non-strong linkage", .{}); + } + if (!fields[section_index].isNull()) { + return sema.mod.fail(&block.base, src, "TODO: implement exporting with linksection", .{}); + } try sema.mod.analyzeExport(&block.base, src, export_name, decl); } @@ -3600,7 +3624,39 @@ fn analyzeSwitch( }), } - if (try sema.resolveDefinedValue(block, src, operand)) |operand_val| { + const block_inst = try sema.arena.create(Inst.Block); + block_inst.* = .{ + .base = .{ + .tag = Inst.Block.base_tag, + .ty = undefined, // Set after analysis. + .src = src, + }, + .body = undefined, + }; + + var child_block: Scope.Block = .{ + .parent = block, + .sema = sema, + .src_decl = block.src_decl, + .instructions = .{}, + // TODO @as here is working around a stage1 miscompilation bug :( + .label = @as(?Scope.Block.Label, Scope.Block.Label{ + .zir_block = switch_inst, + .merges = .{ + .results = .{}, + .br_list = .{}, + .block_inst = block_inst, + }, + }), + .inlining = block.inlining, + .is_comptime = block.is_comptime, + }; + const merges = &child_block.label.?.merges; + defer child_block.instructions.deinit(gpa); + defer merges.results.deinit(gpa); + defer merges.br_list.deinit(gpa); + + if (try sema.resolveDefinedValue(&child_block, src, operand)) |operand_val| { var extra_index: usize = special.end; { var scalar_i: usize = 0; @@ -3614,9 +3670,9 @@ fn analyzeSwitch( // Validation above ensured these will succeed. const item = sema.resolveInst(item_ref) catch unreachable; - const item_val = sema.resolveConstValue(block, .unneeded, item) catch unreachable; + const item_val = sema.resolveConstValue(&child_block, .unneeded, item) catch unreachable; if (operand_val.eql(item_val)) { - return sema.resolveBody(block, body); + return sema.resolveBlockBody(block, src, &child_block, body, merges); } } } @@ -3636,9 +3692,9 @@ fn analyzeSwitch( for (items) |item_ref| { // Validation above ensured these will succeed. const item = sema.resolveInst(item_ref) catch unreachable; - const item_val = sema.resolveConstValue(block, item.src, item) catch unreachable; + const item_val = sema.resolveConstValue(&child_block, item.src, item) catch unreachable; if (operand_val.eql(item_val)) { - return sema.resolveBody(block, body); + return sema.resolveBlockBody(block, src, &child_block, body, merges); } } @@ -3650,59 +3706,27 @@ fn analyzeSwitch( extra_index += 1; // Validation above ensured these will succeed. - const first_tv = sema.resolveInstConst(block, .unneeded, item_first) catch unreachable; - const last_tv = sema.resolveInstConst(block, .unneeded, item_last) catch unreachable; + const first_tv = sema.resolveInstConst(&child_block, .unneeded, item_first) catch unreachable; + const last_tv = sema.resolveInstConst(&child_block, .unneeded, item_last) catch unreachable; if (Value.compare(operand_val, .gte, first_tv.val) and Value.compare(operand_val, .lte, last_tv.val)) { - return sema.resolveBody(block, body); + return sema.resolveBlockBody(block, src, &child_block, body, merges); } } extra_index += body_len; } } - return sema.resolveBody(block, special.body); + return sema.resolveBlockBody(block, src, &child_block, special.body, merges); } if (scalar_cases_len + multi_cases_len == 0) { - return sema.resolveBody(block, special.body); + return sema.resolveBlockBody(block, src, &child_block, special.body, merges); } try sema.requireRuntimeBlock(block, src); - const block_inst = try sema.arena.create(Inst.Block); - block_inst.* = .{ - .base = .{ - .tag = Inst.Block.base_tag, - .ty = undefined, // Set after analysis. - .src = src, - }, - .body = undefined, - }; - - var child_block: Scope.Block = .{ - .parent = block, - .sema = sema, - .src_decl = block.src_decl, - .instructions = .{}, - // TODO @as here is working around a stage1 miscompilation bug :( - .label = @as(?Scope.Block.Label, Scope.Block.Label{ - .zir_block = switch_inst, - .merges = .{ - .results = .{}, - .br_list = .{}, - .block_inst = block_inst, - }, - }), - .inlining = block.inlining, - .is_comptime = block.is_comptime, - }; - const merges = &child_block.label.?.merges; - defer child_block.instructions.deinit(gpa); - defer merges.results.deinit(gpa); - defer merges.br_list.deinit(gpa); - // TODO when reworking AIR memory layout make multi cases get generated as cases, // not as part of the "else" block. const cases = try sema.arena.alloc(Inst.SwitchBr.Case, scalar_cases_len); @@ -4614,7 +4638,8 @@ fn zirTypeInfo(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerErro } fn zirTypeof(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { - const inst_data = sema.code.instructions.items(.data)[inst].un_node; + const zir_datas = sema.code.instructions.items(.data); + const inst_data = zir_datas[inst].un_node; const src = inst_data.src(); const operand = try sema.resolveInst(inst_data.operand); return sema.mod.constType(sema.arena, src, operand.ty); @@ -5555,15 +5580,7 @@ fn zirFuncExtended( const cc_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); extra_index += 1; const cc_tv = try sema.resolveInstConst(block, cc_src, cc_ref); - // TODO this needs to resolve other kinds of Value tags rather than - // assuming the tag will be .enum_field_index. - const cc_field_index = cc_tv.val.castTag(.enum_field_index).?.data; - // TODO should `@intToEnum` do this `@intCast` for you? - const cc = @intToEnum( - std.builtin.CallingConvention, - @intCast(@typeInfo(std.builtin.CallingConvention).Enum.tag_type, cc_field_index), - ); - break :blk cc; + break :blk cc_tv.val.toEnum(cc_tv.ty, std.builtin.CallingConvention); } else .Unspecified; const align_val: Value = if (small.has_align) blk: { diff --git a/src/value.zig b/src/value.zig index 4a547c883687be50f9f4fe9732a0d7227ac0a319..e6ce65a9f489d0805834985c14c374b01c5359a8 100644 --- a/src/value.zig +++ b/src/value.zig @@ -715,6 +715,15 @@ pub const Value = extern union { }; } + /// Asserts the type is an enum type. + pub fn toEnum(val: Value, enum_ty: Type, comptime E: type) E { + // TODO this needs to resolve other kinds of Value tags rather than + // assuming the tag will be .enum_field_index. + const field_index = val.castTag(.enum_field_index).?.data; + // TODO should `@intToEnum` do this `@intCast` for you? + return @intToEnum(E, @intCast(@typeInfo(E).Enum.tag_type, field_index)); + } + /// Asserts the value is an integer. pub fn toBigInt(self: Value, space: *BigIntSpace) BigIntConst { switch (self.tag()) { -- 2.54.0