diff --git a/src/Compilation.zig b/src/Compilation.zig index 11c8303fac..cd3db84ec2 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -1457,11 +1457,12 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor .complete, .codegen_failure_retryable => { const module = self.bin_file.options.module.?; - if (decl.typed_value.most_recent.typed_value.val.cast(Value.Payload.Function)) |payload| { - switch (payload.func.analysis) { - .queued => module.analyzeFnBody(decl, payload.func) catch |err| switch (err) { + if (decl.typed_value.most_recent.typed_value.val.castTag(.function)) |payload| { + const func = payload.data; + switch (func.analysis) { + .queued => module.analyzeFnBody(decl, func) catch |err| switch (err) { error.AnalysisFail => { - assert(payload.func.analysis != .in_progress); + assert(func.analysis != .in_progress); continue; }, error.OutOfMemory => return error.OutOfMemory, @@ -1475,7 +1476,7 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor var decl_arena = decl.typed_value.most_recent.arena.?.promote(module.gpa); defer decl.typed_value.most_recent.arena.?.* = decl_arena.state; log.debug("analyze liveness of {}\n", .{decl.name}); - try liveness.analyze(module.gpa, &decl_arena.allocator, payload.func.analysis.success); + try liveness.analyze(module.gpa, &decl_arena.allocator, func.analysis.success); } assert(decl.typed_value.most_recent.typed_value.ty.hasCodeGenBits()); diff --git a/src/Module.zig b/src/Module.zig index 3e937fe49b..ca0718c3d5 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -1092,16 +1092,12 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { tvm.deinit(self.gpa); } - const value_payload = try decl_arena.allocator.create(Value.Payload.ExternFn); - value_payload.* = .{ .decl = decl }; + const fn_val = try Value.Tag.extern_fn.create(&decl_arena.allocator, decl); decl_arena_state.* = decl_arena.state; decl.typed_value = .{ .most_recent = .{ - .typed_value = .{ - .ty = fn_type, - .val = Value.initPayload(&value_payload.base), - }, + .typed_value = .{ .ty = fn_type, .val = fn_val }, .arena = decl_arena_state, }, }; @@ -1187,7 +1183,10 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { .analysis = .{ .queued = fn_zir }, .owner_decl = decl, }; - fn_payload.* = .{ .func = new_func }; + fn_payload.* = .{ + .base = .{ .tag = .function }, + .data = new_func, + }; var prev_type_has_bits = false; var type_changed = true; @@ -1375,7 +1374,6 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { } const new_variable = try decl_arena.allocator.create(Var); - const var_payload = try decl_arena.allocator.create(Value.Payload.Variable); new_variable.* = .{ .owner_decl = decl, .init = var_info.val orelse undefined, @@ -1383,14 +1381,14 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { .is_mutable = is_mutable, .is_threadlocal = is_threadlocal, }; - var_payload.* = .{ .variable = new_variable }; + const var_val = try Value.Tag.variable.create(&decl_arena.allocator, new_variable); decl_arena_state.* = decl_arena.state; decl.typed_value = .{ .most_recent = .{ .typed_value = .{ .ty = var_info.ty, - .val = Value.initPayload(&var_payload.base), + .val = var_val, }, .arena = decl_arena_state, }, @@ -2232,52 +2230,43 @@ pub fn constBool(self: *Module, scope: *Scope, src: usize, v: bool) !*Inst { } pub fn constIntUnsigned(self: *Module, scope: *Scope, src: usize, ty: Type, int: u64) !*Inst { - const int_payload = try scope.arena().create(Value.Payload.Int_u64); - int_payload.* = .{ .int = int }; - return self.constInst(scope, src, .{ .ty = ty, - .val = Value.initPayload(&int_payload.base), + .val = try Value.Tag.int_u64.create(scope.arena(), int), }); } pub fn constIntSigned(self: *Module, scope: *Scope, src: usize, ty: Type, int: i64) !*Inst { - const int_payload = try scope.arena().create(Value.Payload.Int_i64); - int_payload.* = .{ .int = int }; - return self.constInst(scope, src, .{ .ty = ty, - .val = Value.initPayload(&int_payload.base), + .val = try Value.Tag.int_i64.create(scope.arena(), int), }); } pub fn constIntBig(self: *Module, scope: *Scope, src: usize, ty: Type, big_int: BigIntConst) !*Inst { - const val_payload = if (big_int.positive) blk: { + if (big_int.positive) { if (big_int.to(u64)) |x| { return self.constIntUnsigned(scope, src, ty, x); } else |err| switch (err) { error.NegativeIntoUnsigned => unreachable, error.TargetTooSmall => {}, // handled below } - const big_int_payload = try scope.arena().create(Value.Payload.IntBigPositive); - big_int_payload.* = .{ .limbs = big_int.limbs }; - break :blk &big_int_payload.base; - } else blk: { + return self.constInst(scope, src, .{ + .ty = ty, + .val = try Value.Tag.int_big_positive.create(scope.arena(), big_int.limbs), + }); + } else { if (big_int.to(i64)) |x| { return self.constIntSigned(scope, src, ty, x); } else |err| switch (err) { error.NegativeIntoUnsigned => unreachable, error.TargetTooSmall => {}, // handled below } - const big_int_payload = try scope.arena().create(Value.Payload.IntBigNegative); - big_int_payload.* = .{ .limbs = big_int.limbs }; - break :blk &big_int_payload.base; - }; - - return self.constInst(scope, src, .{ - .ty = ty, - .val = Value.initPayload(val_payload), - }); + return self.constInst(scope, src, .{ + .ty = ty, + .val = try Value.Tag.int_big_negative.create(scope.arena(), big_int.limbs), + }); + } } pub fn createAnonymousDecl( @@ -2346,26 +2335,20 @@ pub fn analyzeDeclRef(self: *Module, scope: *Scope, src: usize, decl: *Decl) Inn if (decl_tv.val.tag() == .variable) { return self.analyzeVarRef(scope, src, decl_tv); } - const ty = try self.simplePtrType(scope, src, decl_tv.ty, false, .One); - const val_payload = try scope.arena().create(Value.Payload.DeclRef); - val_payload.* = .{ .decl = decl }; - return self.constInst(scope, src, .{ - .ty = ty, - .val = Value.initPayload(&val_payload.base), + .ty = try self.simplePtrType(scope, src, decl_tv.ty, false, .One), + .val = try Value.Tag.decl_ref.create(scope.arena(), decl), }); } fn analyzeVarRef(self: *Module, scope: *Scope, src: usize, tv: TypedValue) InnerError!*Inst { - const variable = tv.val.cast(Value.Payload.Variable).?.variable; + const variable = tv.val.castTag(.variable).?.data; const ty = try self.simplePtrType(scope, src, tv.ty, variable.is_mutable, .One); if (!variable.is_mutable and !variable.is_extern) { - const val_payload = try scope.arena().create(Value.Payload.RefVal); - val_payload.* = .{ .val = variable.init }; return self.constInst(scope, src, .{ .ty = ty, - .val = Value.initPayload(&val_payload.base), + .val = try Value.Tag.ref_val.create(scope.arena(), variable.init), }); } @@ -3107,17 +3090,11 @@ pub fn intAdd(allocator: *Allocator, lhs: Value, rhs: Value) !Value { result_bigint.add(lhs_bigint, rhs_bigint); const result_limbs = result_bigint.limbs[0..result_bigint.len]; - const val_payload = if (result_bigint.positive) blk: { - const val_payload = try allocator.create(Value.Payload.IntBigPositive); - val_payload.* = .{ .limbs = result_limbs }; - break :blk &val_payload.base; - } else blk: { - const val_payload = try allocator.create(Value.Payload.IntBigNegative); - val_payload.* = .{ .limbs = result_limbs }; - break :blk &val_payload.base; - }; - - return Value.initPayload(val_payload); + if (result_bigint.positive) { + return Value.Tag.int_big_positive.create(allocator, result_limbs); + } else { + return Value.Tag.int_big_negative.create(allocator, result_limbs); + } } pub fn intSub(allocator: *Allocator, lhs: Value, rhs: Value) !Value { @@ -3135,85 +3112,81 @@ pub fn intSub(allocator: *Allocator, lhs: Value, rhs: Value) !Value { result_bigint.sub(lhs_bigint, rhs_bigint); const result_limbs = result_bigint.limbs[0..result_bigint.len]; - const val_payload = if (result_bigint.positive) blk: { - const val_payload = try allocator.create(Value.Payload.IntBigPositive); - val_payload.* = .{ .limbs = result_limbs }; - break :blk &val_payload.base; - } else blk: { - const val_payload = try allocator.create(Value.Payload.IntBigNegative); - val_payload.* = .{ .limbs = result_limbs }; - break :blk &val_payload.base; - }; - - return Value.initPayload(val_payload); + if (result_bigint.positive) { + return Value.Tag.int_big_positive.create(allocator, result_limbs); + } else { + return Value.Tag.int_big_negative.create(allocator, result_limbs); + } } -pub fn floatAdd(self: *Module, scope: *Scope, float_type: Type, src: usize, lhs: Value, rhs: Value) !Value { - var bit_count = switch (float_type.tag()) { - .comptime_float => 128, - else => float_type.floatBits(self.getTarget()), - }; - - const allocator = scope.arena(); - const val_payload = switch (bit_count) { - 16 => { - return self.fail(scope, src, "TODO Implement addition for soft floats", .{}); +pub fn floatAdd( + self: *Module, + scope: *Scope, + float_type: Type, + src: usize, + lhs: Value, + rhs: Value, +) !Value { + const arena = scope.arena(); + switch (float_type.tag()) { + .f16 => { + @panic("TODO add __trunctfhf2 to compiler-rt"); + //const lhs_val = lhs.toFloat(f16); + //const rhs_val = rhs.toFloat(f16); + //return Value.Tag.float_16.create(arena, lhs_val + rhs_val); }, - 32 => blk: { + .f32 => { const lhs_val = lhs.toFloat(f32); const rhs_val = rhs.toFloat(f32); - const val_payload = try allocator.create(Value.Payload.Float_32); - val_payload.* = .{ .val = lhs_val + rhs_val }; - break :blk &val_payload.base; + return Value.Tag.float_32.create(arena, lhs_val + rhs_val); }, - 64 => blk: { + .f64 => { const lhs_val = lhs.toFloat(f64); const rhs_val = rhs.toFloat(f64); - const val_payload = try allocator.create(Value.Payload.Float_64); - val_payload.* = .{ .val = lhs_val + rhs_val }; - break :blk &val_payload.base; + return Value.Tag.float_64.create(arena, lhs_val + rhs_val); }, - 128 => { - return self.fail(scope, src, "TODO Implement addition for big floats", .{}); + .f128, .comptime_float, .c_longdouble => { + const lhs_val = lhs.toFloat(f128); + const rhs_val = rhs.toFloat(f128); + return Value.Tag.float_128.create(arena, lhs_val + rhs_val); }, else => unreachable, - }; - - return Value.initPayload(val_payload); + } } -pub fn floatSub(self: *Module, scope: *Scope, float_type: Type, src: usize, lhs: Value, rhs: Value) !Value { - var bit_count = switch (float_type.tag()) { - .comptime_float => 128, - else => float_type.floatBits(self.getTarget()), - }; - - const allocator = scope.arena(); - const val_payload = switch (bit_count) { - 16 => { - return self.fail(scope, src, "TODO Implement substraction for soft floats", .{}); +pub fn floatSub( + self: *Module, + scope: *Scope, + float_type: Type, + src: usize, + lhs: Value, + rhs: Value, +) !Value { + const arena = scope.arena(); + switch (float_type.tag()) { + .f16 => { + @panic("TODO add __trunctfhf2 to compiler-rt"); + //const lhs_val = lhs.toFloat(f16); + //const rhs_val = rhs.toFloat(f16); + //return Value.Tag.float_16.create(arena, lhs_val - rhs_val); }, - 32 => blk: { + .f32 => { const lhs_val = lhs.toFloat(f32); const rhs_val = rhs.toFloat(f32); - const val_payload = try allocator.create(Value.Payload.Float_32); - val_payload.* = .{ .val = lhs_val - rhs_val }; - break :blk &val_payload.base; + return Value.Tag.float_32.create(arena, lhs_val - rhs_val); }, - 64 => blk: { + .f64 => { const lhs_val = lhs.toFloat(f64); const rhs_val = rhs.toFloat(f64); - const val_payload = try allocator.create(Value.Payload.Float_64); - val_payload.* = .{ .val = lhs_val - rhs_val }; - break :blk &val_payload.base; + return Value.Tag.float_64.create(arena, lhs_val - rhs_val); }, - 128 => { - return self.fail(scope, src, "TODO Implement substraction for big floats", .{}); + .f128, .comptime_float, .c_longdouble => { + const lhs_val = lhs.toFloat(f128); + const rhs_val = rhs.toFloat(f128); + return Value.Tag.float_128.create(arena, lhs_val - rhs_val); }, else => unreachable, - }; - - return Value.initPayload(val_payload); + } } pub fn simplePtrType(self: *Module, scope: *Scope, src: usize, elem_ty: Type, mutable: bool, size: std.builtin.TypeInfo.Pointer.Size) Allocator.Error!Type { diff --git a/src/astgen.zig b/src/astgen.zig index 1fc8a0d19e..c5261c4073 100644 --- a/src/astgen.zig +++ b/src/astgen.zig @@ -1956,13 +1956,13 @@ fn identifier(mod: *Module, scope: *Scope, rl: ResultLoc, ident: *ast.Node.OneTo 32 => if (is_signed) Value.initTag(.i32_type) else Value.initTag(.u32_type), 64 => if (is_signed) Value.initTag(.i64_type) else Value.initTag(.u64_type), else => { - const int_type_payload = try scope.arena().create(Value.Payload.IntType); - int_type_payload.* = .{ .signed = is_signed, .bits = bit_count }; - const result = try addZIRInstConst(mod, scope, src, .{ + return rlWrap(mod, scope, rl, try addZIRInstConst(mod, scope, src, .{ .ty = Type.initTag(.type), - .val = Value.initPayload(&int_type_payload.base), - }); - return rlWrap(mod, scope, rl, result); + .val = try Value.Tag.int_type.create(scope.arena(), .{ + .signed = is_signed, + .bits = bit_count, + }), + })); }, }; const result = try addZIRInstConst(mod, scope, src, .{ @@ -2062,11 +2062,9 @@ fn charLiteral(mod: *Module, scope: *Scope, node: *ast.Node.OneToken) !*zir.Inst }, }; - const int_payload = try scope.arena().create(Value.Payload.Int_u64); - int_payload.* = .{ .int = value }; return addZIRInstConst(mod, scope, src, .{ .ty = Type.initTag(.comptime_int), - .val = Value.initPayload(&int_payload.base), + .val = try Value.Tag.int_u64.create(scope.arena(), value), }); } @@ -2089,12 +2087,10 @@ fn integerLiteral(mod: *Module, scope: *Scope, int_lit: *ast.Node.OneToken) Inne prefixed_bytes[2..]; if (std.fmt.parseInt(u64, bytes, base)) |small_int| { - const int_payload = try arena.create(Value.Payload.Int_u64); - int_payload.* = .{ .int = small_int }; const src = tree.token_locs[int_lit.token].start; return addZIRInstConst(mod, scope, src, .{ .ty = Type.initTag(.comptime_int), - .val = Value.initPayload(&int_payload.base), + .val = try Value.Tag.int_u64.create(arena, small_int), }); } else |err| { return mod.failTok(scope, int_lit.token, "TODO implement int literals that don't fit in a u64", .{}); @@ -2109,15 +2105,13 @@ fn floatLiteral(mod: *Module, scope: *Scope, float_lit: *ast.Node.OneToken) Inne return mod.failTok(scope, float_lit.token, "TODO hex floats", .{}); } - const val = std.fmt.parseFloat(f128, bytes) catch |e| switch (e) { + const float_number = std.fmt.parseFloat(f128, bytes) catch |e| switch (e) { error.InvalidCharacter => unreachable, // validated by tokenizer }; - const float_payload = try arena.create(Value.Payload.Float_128); - float_payload.* = .{ .val = val }; const src = tree.token_locs[float_lit.token].start; return addZIRInstConst(mod, scope, src, .{ .ty = Type.initTag(.comptime_float), - .val = Value.initPayload(&float_payload.base), + .val = try Value.Tag.float_128.create(arena, float_number), }); } diff --git a/src/codegen.zig b/src/codegen.zig index d98a87a440..f978115ebc 100644 --- a/src/codegen.zig +++ b/src/codegen.zig @@ -137,7 +137,7 @@ pub fn generateSymbol( }, .Array => { // TODO populate .debug_info for the array - if (typed_value.val.cast(Value.Payload.Bytes)) |payload| { + if (typed_value.val.castTag(.bytes)) |payload| { if (typed_value.ty.sentinel()) |sentinel| { try code.ensureCapacity(code.items.len + payload.data.len + 1); code.appendSliceAssumeCapacity(payload.data); @@ -168,8 +168,8 @@ pub fn generateSymbol( }, .Pointer => { // TODO populate .debug_info for the pointer - if (typed_value.val.cast(Value.Payload.DeclRef)) |payload| { - const decl = payload.decl; + if (typed_value.val.castTag(.decl_ref)) |payload| { + const decl = payload.data; if (decl.analysis != .complete) return error.AnalysisFail; // TODO handle the dependency of this symbol on the decl's vaddr. // If the decl changes vaddr, then this symbol needs to get regenerated. @@ -432,7 +432,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { @panic("Attempted to compile for architecture that was disabled by build configuration"); } - const module_fn = typed_value.val.cast(Value.Payload.Function).?.func; + const module_fn = typed_value.val.castTag(.function).?.data; const fn_type = module_fn.owner_decl.typed_value.most_recent.typed_value.ty; @@ -1579,9 +1579,9 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { } } - if (inst.func.cast(ir.Inst.Constant)) |func_inst| { - if (func_inst.val.cast(Value.Payload.Function)) |func_val| { - const func = func_val.func; + if (inst.func.value()) |func_value| { + if (func_value.castTag(.function)) |func_payload| { + const func = func_payload.data; const ptr_bits = self.target.cpu.arch.ptrBitWidth(); const ptr_bytes: u64 = @divExact(ptr_bits, 8); @@ -1607,9 +1607,9 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { .riscv64 => { if (info.args.len > 0) return self.fail(inst.base.src, "TODO implement fn args for {}", .{self.target.cpu.arch}); - if (inst.func.cast(ir.Inst.Constant)) |func_inst| { - if (func_inst.val.cast(Value.Payload.Function)) |func_val| { - const func = func_val.func; + if (inst.func.value()) |func_value| { + if (func_value.castTag(.function)) |func_payload| { + const func = func_payload.data; const ptr_bits = self.target.cpu.arch.ptrBitWidth(); const ptr_bytes: u64 = @divExact(ptr_bits, 8); @@ -1631,12 +1631,12 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { } }, .spu_2 => { - if (inst.func.cast(ir.Inst.Constant)) |func_inst| { + if (inst.func.value()) |func_value| { if (info.args.len != 0) { return self.fail(inst.base.src, "TODO implement call with more than 0 parameters", .{}); } - if (func_inst.val.cast(Value.Payload.Function)) |func_val| { - const func = func_val.func; + if (func_value.castTag(.function)) |func_payload| { + const func = func_payload.data; const got_addr = if (self.bin_file.cast(link.File.Elf)) |elf_file| blk: { const got = &elf_file.program_headers.items[elf_file.phdr_got_index.?]; break :blk @intCast(u16, got.p_vaddr + func.owner_decl.link.elf.offset_table_index * 2); @@ -1705,9 +1705,9 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { } } - if (inst.func.cast(ir.Inst.Constant)) |func_inst| { - if (func_inst.val.cast(Value.Payload.Function)) |func_val| { - const func = func_val.func; + if (inst.func.value()) |func_value| { + if (func_value.castTag(.function)) |func_payload| { + const func = func_payload.data; const ptr_bits = self.target.cpu.arch.ptrBitWidth(); const ptr_bytes: u64 = @divExact(ptr_bits, 8); const got_addr = if (self.bin_file.cast(link.File.Elf)) |elf_file| blk: { @@ -1766,9 +1766,9 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { } } - if (inst.func.cast(ir.Inst.Constant)) |func_inst| { - if (func_inst.val.cast(Value.Payload.Function)) |func_val| { - const func = func_val.func; + if (inst.func.value()) |func_value| { + if (func_value.castTag(.function)) |func_payload| { + const func = func_payload.data; const ptr_bits = self.target.cpu.arch.ptrBitWidth(); const ptr_bytes: u64 = @divExact(ptr_bits, 8); const got_addr = if (self.bin_file.cast(link.File.Elf)) |elf_file| blk: { @@ -1825,9 +1825,9 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { } } - if (inst.func.cast(ir.Inst.Constant)) |func_inst| { - if (func_inst.val.cast(Value.Payload.Function)) |func_val| { - const func = func_val.func; + if (inst.func.value()) |func_value| { + if (func_value.castTag(.function)) |func_payload| { + const func = func_payload.data; const text_segment = &macho_file.load_commands.items[macho_file.text_segment_cmd_index.?].Segment; const got = &text_segment.sections.items[macho_file.got_section_index.?]; const got_addr = got.addr + func.owner_decl.link.macho.offset_table_index * @sizeOf(u64); @@ -3223,20 +3223,20 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { const ptr_bytes: u64 = @divExact(ptr_bits, 8); switch (typed_value.ty.zigTypeTag()) { .Pointer => { - if (typed_value.val.cast(Value.Payload.DeclRef)) |payload| { + if (typed_value.val.castTag(.decl_ref)) |payload| { if (self.bin_file.cast(link.File.Elf)) |elf_file| { - const decl = payload.decl; + const decl = payload.data; const got = &elf_file.program_headers.items[elf_file.phdr_got_index.?]; const got_addr = got.p_vaddr + decl.link.elf.offset_table_index * ptr_bytes; return MCValue{ .memory = got_addr }; } else if (self.bin_file.cast(link.File.MachO)) |macho_file| { - const decl = payload.decl; + const decl = payload.data; const text_segment = &macho_file.load_commands.items[macho_file.text_segment_cmd_index.?].Segment; const got = &text_segment.sections.items[macho_file.got_section_index.?]; const got_addr = got.addr + decl.link.macho.offset_table_index * ptr_bytes; return MCValue{ .memory = got_addr }; } else if (self.bin_file.cast(link.File.Coff)) |coff_file| { - const decl = payload.decl; + const decl = payload.data; const got_addr = coff_file.offset_table_virtual_address + decl.link.coff.offset_table_index * ptr_bytes; return MCValue{ .memory = got_addr }; } else { diff --git a/src/codegen/c.zig b/src/codegen/c.zig index 828061fac6..7cd4479bd9 100644 --- a/src/codegen/c.zig +++ b/src/codegen/c.zig @@ -138,25 +138,25 @@ fn renderValue( .undef, .zero => try writer.writeAll("0"), .one => try writer.writeAll("1"), .decl_ref => { - const decl_ref_payload = val.cast(Value.Payload.DeclRef).?; + const decl = val.castTag(.decl_ref).?.data; // Determine if we must pointer cast. - const decl_tv = decl_ref_payload.decl.typed_value.most_recent.typed_value; + const decl_tv = decl.typed_value.most_recent.typed_value; if (t.eql(decl_tv.ty)) { - try writer.print("&{s}", .{decl_ref_payload.decl.name}); + try writer.print("&{s}", .{decl.name}); } else { try writer.writeAll("("); try renderType(ctx, writer, t); - try writer.print(")&{s}", .{decl_ref_payload.decl.name}); + try writer.print(")&{s}", .{decl.name}); } }, .function => { - const payload = val.cast(Value.Payload.Function).?; - try writer.print("{s}", .{payload.func.owner_decl.name}); + const func = val.castTag(.function).?.data; + try writer.print("{s}", .{func.owner_decl.name}); }, .extern_fn => { - const payload = val.cast(Value.Payload.ExternFn).?; - try writer.print("{s}", .{payload.decl.name}); + const decl = val.castTag(.extern_fn).?.data; + try writer.print("{s}", .{decl.name}); }, else => |e| return ctx.fail( ctx.decl.src(), @@ -169,7 +169,7 @@ fn renderValue( switch (val.tag()) { .undef, .empty_struct_value, .empty_array => try writer.writeAll("{}"), .bytes => { - const bytes = val.cast(Value.Payload.Bytes).?.data; + const bytes = val.castTag(.bytes).?.data; // TODO: make our own C string escape instead of using {Z} try writer.print("\"{Z}\"", .{bytes}); }, @@ -209,7 +209,7 @@ fn renderFunctionSignature( switch (tv.val.tag()) { .extern_fn => break :blk true, .function => { - const func = tv.val.cast(Value.Payload.Function).?.func; + const func = tv.val.castTag(.function).?.data; break :blk ctx.module.decl_exports.contains(func.owner_decl); }, else => unreachable, @@ -268,13 +268,13 @@ pub fn generate(file: *C, module: *Module, decl: *Decl) !void { ctx.deinit(); } - if (tv.val.cast(Value.Payload.Function)) |func_payload| { + if (tv.val.castTag(.function)) |func_payload| { const writer = file.main.writer(); try renderFunctionSignature(&ctx, writer, decl); try writer.writeAll(" {"); - const func: *Module.Fn = func_payload.func; + const func: *Module.Fn = func_payload.data; const instructions = func.analysis.success.instructions; if (instructions.len > 0) { try writer.writeAll("\n"); @@ -480,10 +480,10 @@ fn genCall(ctx: *Context, file: *C, inst: *Inst.Call) !?[]u8 { const writer = file.main.writer(); const header = file.header.buf.writer(); if (inst.func.castTag(.constant)) |func_inst| { - const fn_decl = if (func_inst.val.cast(Value.Payload.ExternFn)) |extern_fn| - extern_fn.decl - else if (func_inst.val.cast(Value.Payload.Function)) |func_val| - func_val.func.owner_decl + const fn_decl = if (func_inst.val.castTag(.extern_fn)) |extern_fn| + extern_fn.data + else if (func_inst.val.castTag(.function)) |func_payload| + func_payload.data.owner_decl else unreachable; @@ -513,8 +513,8 @@ fn genCall(ctx: *Context, file: *C, inst: *Inst.Call) !?[]u8 { if (i > 0) { try writer.writeAll(", "); } - if (arg.cast(Inst.Constant)) |con| { - try renderValue(ctx, writer, arg.ty, con.val); + if (arg.value()) |val| { + try renderValue(ctx, writer, arg.ty, val); } else { const val = try ctx.resolveInst(arg); try writer.print("{}", .{val}); diff --git a/src/codegen/wasm.zig b/src/codegen/wasm.zig index 7297ea1d54..c7ad59f5d1 100644 --- a/src/codegen/wasm.zig +++ b/src/codegen/wasm.zig @@ -62,7 +62,7 @@ pub fn genCode(buf: *ArrayList(u8), decl: *Decl) !void { // Write instructions // TODO: check for and handle death of instructions const tv = decl.typed_value.most_recent.typed_value; - const mod_fn = tv.val.cast(Value.Payload.Function).?.func; + const mod_fn = tv.val.castTag(.function).?.data; for (mod_fn.analysis.success.instructions) |inst| try genInst(buf, decl, inst); // Write 'end' opcode @@ -125,8 +125,8 @@ fn genRet(buf: *ArrayList(u8), decl: *Decl, inst: *Inst.UnOp) !void { fn genCall(buf: *ArrayList(u8), decl: *Decl, inst: *Inst.Call) !void { const func_inst = inst.func.castTag(.constant).?; - const func_val = func_inst.val.cast(Value.Payload.Function).?; - const target = func_val.func.owner_decl; + const func = func_inst.val.castTag(.function).?.data; + const target = func.owner_decl; const target_ty = target.typed_value.most_recent.typed_value.ty; if (inst.args.len != 0) return error.TODOImplementMoreWasmCodegen; diff --git a/src/link/Elf.zig b/src/link/Elf.zig index 25b883f8c6..4b2b95fc72 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -2183,7 +2183,7 @@ pub fn updateDecl(self: *Elf, module: *Module, decl: *Module.Decl) !void { for (zir_dumps) |fn_name| { if (mem.eql(u8, mem.spanZ(decl.name), fn_name)) { std.debug.print("\n{}\n", .{decl.name}); - typed_value.val.cast(Value.Payload.Function).?.func.dump(module.*); + typed_value.val.castTag(.function).?.data.dump(module.*); } } } diff --git a/src/llvm_backend.zig b/src/llvm_backend.zig index 77aa4d3bd5..294e6f5400 100644 --- a/src/llvm_backend.zig +++ b/src/llvm_backend.zig @@ -280,7 +280,7 @@ pub const LLVMIRModule = struct { fn gen(self: *LLVMIRModule, module: *Module, typed_value: TypedValue, src: usize) !void { switch (typed_value.ty.zigTypeTag()) { .Fn => { - const func = typed_value.val.cast(Value.Payload.Function).?.func; + const func = typed_value.val.castTag(.function).?.data; const llvm_func = try self.resolveLLVMFunction(func); @@ -314,9 +314,9 @@ pub const LLVMIRModule = struct { } fn genCall(self: *LLVMIRModule, inst: *Inst.Call) !void { - if (inst.func.cast(Inst.Constant)) |func_inst| { - if (func_inst.val.cast(Value.Payload.Function)) |func_val| { - const func = func_val.func; + if (inst.func.value()) |func_value| { + if (func_value.castTag(.function)) |func_payload| { + const func = func_payload.data; const zig_fn_type = func.owner_decl.typed_value.most_recent.typed_value.ty; const llvm_fn = try self.resolveLLVMFunction(func); diff --git a/src/type.zig b/src/type.zig index ce237f89c7..9d834a19f2 100644 --- a/src/type.zig +++ b/src/type.zig @@ -733,11 +733,7 @@ pub const Type = extern union { .single_const_pointer_to_comptime_int => return Value.initTag(.single_const_pointer_to_comptime_int_type), .const_slice_u8 => return Value.initTag(.const_slice_u8_type), .enum_literal => return Value.initTag(.enum_literal_type), - else => { - const ty_payload = try allocator.create(Value.Payload.Ty); - ty_payload.* = .{ .ty = self }; - return Value.initPayload(&ty_payload.base); - }, + else => return Value.Tag.ty.create(allocator, self), } } @@ -2951,11 +2947,8 @@ pub const Type = extern union { } if ((info.bits - 1) <= std.math.maxInt(u6)) { - const payload = try arena.allocator.create(Value.Payload.Int_i64); - payload.* = .{ - .int = -(@as(i64, 1) << @truncate(u6, info.bits - 1)), - }; - return Value.initPayload(&payload.base); + const n: i64 = -(@as(i64, 1) << @truncate(u6, info.bits - 1)); + return Value.Tag.int_i64.create(&arena.allocator, n); } var res = try std.math.big.int.Managed.initSet(&arena.allocator, 1); @@ -2964,13 +2957,9 @@ pub const Type = extern union { const res_const = res.toConst(); if (res_const.positive) { - const val_payload = try arena.allocator.create(Value.Payload.IntBigPositive); - val_payload.* = .{ .limbs = res_const.limbs }; - return Value.initPayload(&val_payload.base); + return Value.Tag.int_big_positive.create(&arena.allocator, res_const.limbs); } else { - const val_payload = try arena.allocator.create(Value.Payload.IntBigNegative); - val_payload.* = .{ .limbs = res_const.limbs }; - return Value.initPayload(&val_payload.base); + return Value.Tag.int_big_negative.create(&arena.allocator, res_const.limbs); } } @@ -2980,17 +2969,11 @@ pub const Type = extern union { const info = self.intInfo(target); if (info.signedness == .signed and (info.bits - 1) <= std.math.maxInt(u6)) { - const payload = try arena.allocator.create(Value.Payload.Int_i64); - payload.* = .{ - .int = (@as(i64, 1) << @truncate(u6, info.bits - 1)) - 1, - }; - return Value.initPayload(&payload.base); + const n: i64 = (@as(i64, 1) << @truncate(u6, info.bits - 1)) - 1; + return Value.Tag.int_i64.create(&arena.allocator, n); } else if (info.signedness == .signed and info.bits <= std.math.maxInt(u6)) { - const payload = try arena.allocator.create(Value.Payload.Int_u64); - payload.* = .{ - .int = (@as(u64, 1) << @truncate(u6, info.bits)) - 1, - }; - return Value.initPayload(&payload.base); + const n: u64 = (@as(u64, 1) << @truncate(u6, info.bits)) - 1; + return Value.Tag.int_u64.create(&arena.allocator, n); } var res = try std.math.big.int.Managed.initSet(&arena.allocator, 1); @@ -3003,13 +2986,9 @@ pub const Type = extern union { const res_const = res.toConst(); if (res_const.positive) { - const val_payload = try arena.allocator.create(Value.Payload.IntBigPositive); - val_payload.* = .{ .limbs = res_const.limbs }; - return Value.initPayload(&val_payload.base); + return Value.Tag.int_big_positive.create(&arena.allocator, res_const.limbs); } else { - const val_payload = try arena.allocator.create(Value.Payload.IntBigNegative); - val_payload.* = .{ .limbs = res_const.limbs }; - return Value.initPayload(&val_payload.base); + return Value.Tag.int_big_negative.create(&arena.allocator, res_const.limbs); } } diff --git a/src/value.zig b/src/value.zig index f26c8d8772..91b21511d4 100644 --- a/src/value.zig +++ b/src/value.zig @@ -84,11 +84,16 @@ pub const Value = extern union { function, extern_fn, variable, + /// Represents a pointer to another immutable value. ref_val, + /// Represents a pointer to a decl, not the value of the decl. decl_ref, elem_ptr, + /// A slice of u8 whose memory is managed externally. bytes, - repeated, // the value is a value repeated some number of times + /// This value is repeated some number of times. The amount of times to repeat + /// is stored externally. + repeated, float_16, float_32, float_64, @@ -99,6 +104,106 @@ pub const Value = extern union { pub const last_no_payload_tag = Tag.bool_false; pub const no_payload_count = @enumToInt(last_no_payload_tag) + 1; + + pub fn Type(comptime t: Tag) type { + return switch (t) { + .u8_type, + .i8_type, + .u16_type, + .i16_type, + .u32_type, + .i32_type, + .u64_type, + .i64_type, + .usize_type, + .isize_type, + .c_short_type, + .c_ushort_type, + .c_int_type, + .c_uint_type, + .c_long_type, + .c_ulong_type, + .c_longlong_type, + .c_ulonglong_type, + .c_longdouble_type, + .f16_type, + .f32_type, + .f64_type, + .f128_type, + .c_void_type, + .bool_type, + .void_type, + .type_type, + .anyerror_type, + .comptime_int_type, + .comptime_float_type, + .noreturn_type, + .null_type, + .undefined_type, + .fn_noreturn_no_args_type, + .fn_void_no_args_type, + .fn_naked_noreturn_no_args_type, + .fn_ccc_void_no_args_type, + .single_const_pointer_to_comptime_int_type, + .const_slice_u8_type, + .enum_literal_type, + .anyframe_type, + .undef, + .zero, + .one, + .void_value, + .unreachable_value, + .empty_struct_value, + .empty_array, + .null_value, + .bool_true, + .bool_false, + => @compileError("Value Tag " ++ @tagName(t) ++ " has no payload"), + + .int_big_positive, + .int_big_negative, + => Payload.BigInt, + + .extern_fn, + .decl_ref, + => Payload.Decl, + + .ref_val, + .repeated, + => Payload.SubValue, + + .bytes, + .enum_literal, + => Payload.Bytes, + + .ty => Payload.Ty, + .int_type => Payload.IntType, + .int_u64 => Payload.U64, + .int_i64 => Payload.I64, + .function => Payload.Function, + .variable => Payload.Variable, + .elem_ptr => Payload.ElemPtr, + .float_16 => Payload.Float_16, + .float_32 => Payload.Float_32, + .float_64 => Payload.Float_64, + .float_128 => Payload.Float_128, + .error_set => Payload.ErrorSet, + .@"error" => Payload.Error, + }; + } + + pub fn create(comptime t: Tag, ally: *Allocator, data: Data(t)) error{OutOfMemory}!Value { + const ptr = try ally.create(t.Type()); + ptr.* = .{ + .base = .{ .tag = t }, + .data = data, + }; + return Value{ .ptr_otherwise = &ptr.base }; + } + + pub fn Data(comptime t: Tag) type { + return std.meta.fieldInfo(t.Type(), "data").field_type; + } }; pub fn initTag(small_tag: Tag) Value { @@ -119,15 +224,36 @@ pub const Value = extern union { } } + /// Prefer `castTag` to this. pub fn cast(self: Value, comptime T: type) ?*T { + if (@hasField(T, "base_tag")) { + return base.castTag(T.base_tag); + } + if (self.tag_if_small_enough < Tag.no_payload_count) { + return null; + } + inline for (@typeInfo(Tag).Enum.fields) |field| { + if (field.value < Tag.no_payload_count) + continue; + const t = @intToEnum(Tag, field.value); + if (self.ptr_otherwise.tag == t) { + if (T == t.Type()) { + return @fieldParentPtr(T, "base", self.ptr_otherwise); + } + return null; + } + } + unreachable; + } + + pub fn castTag(self: Value, comptime t: Tag) ?*t.Type() { if (self.tag_if_small_enough < Tag.no_payload_count) return null; - const expected_tag = std.meta.fieldInfo(T, "base").default_value.?.tag; - if (self.ptr_otherwise.tag != expected_tag) - return null; + if (self.ptr_otherwise.tag == t) + return @fieldParentPtr(t.Type(), "base", self.ptr_otherwise); - return @fieldParentPtr(T, "base", self.ptr_otherwise); + return null; } pub fn copy(self: Value, allocator: *Allocator) error{OutOfMemory}!Value { @@ -188,17 +314,17 @@ pub const Value = extern union { => unreachable, .ty => { - const payload = @fieldParentPtr(Payload.Ty, "base", self.ptr_otherwise); + const payload = self.castTag(.ty).?; const new_payload = try allocator.create(Payload.Ty); new_payload.* = .{ .base = payload.base, - .ty = try payload.ty.copy(allocator), + .data = try payload.data.copy(allocator), }; return Value{ .ptr_otherwise = &new_payload.base }; }, .int_type => return self.copyPayloadShallow(allocator, Payload.IntType), - .int_u64 => return self.copyPayloadShallow(allocator, Payload.Int_u64), - .int_i64 => return self.copyPayloadShallow(allocator, Payload.Int_i64), + .int_u64 => return self.copyPayloadShallow(allocator, Payload.U64), + .int_i64 => return self.copyPayloadShallow(allocator, Payload.I64), .int_big_positive => { @panic("TODO implement copying of big ints"); }, @@ -206,35 +332,37 @@ pub const Value = extern union { @panic("TODO implement copying of big ints"); }, .function => return self.copyPayloadShallow(allocator, Payload.Function), - .extern_fn => return self.copyPayloadShallow(allocator, Payload.ExternFn), + .extern_fn => return self.copyPayloadShallow(allocator, Payload.Decl), .variable => return self.copyPayloadShallow(allocator, Payload.Variable), .ref_val => { - const payload = @fieldParentPtr(Payload.RefVal, "base", self.ptr_otherwise); - const new_payload = try allocator.create(Payload.RefVal); + const payload = self.castTag(.ref_val).?; + const new_payload = try allocator.create(Payload.SubValue); new_payload.* = .{ .base = payload.base, - .val = try payload.val.copy(allocator), + .data = try payload.data.copy(allocator), }; return Value{ .ptr_otherwise = &new_payload.base }; }, - .decl_ref => return self.copyPayloadShallow(allocator, Payload.DeclRef), + .decl_ref => return self.copyPayloadShallow(allocator, Payload.Decl), .elem_ptr => { - const payload = @fieldParentPtr(Payload.ElemPtr, "base", self.ptr_otherwise); + const payload = self.castTag(.elem_ptr).?; const new_payload = try allocator.create(Payload.ElemPtr); new_payload.* = .{ .base = payload.base, - .array_ptr = try payload.array_ptr.copy(allocator), - .index = payload.index, + .data = .{ + .array_ptr = try payload.data.array_ptr.copy(allocator), + .index = payload.data.index, + }, }; return Value{ .ptr_otherwise = &new_payload.base }; }, .bytes => return self.copyPayloadShallow(allocator, Payload.Bytes), .repeated => { - const payload = @fieldParentPtr(Payload.Repeated, "base", self.ptr_otherwise); - const new_payload = try allocator.create(Payload.Repeated); + const payload = self.castTag(.repeated).?; + const new_payload = try allocator.create(Payload.SubValue); new_payload.* = .{ .base = payload.base, - .val = try payload.val.copy(allocator), + .data = try payload.data.copy(allocator), }; return Value{ .ptr_otherwise = &new_payload.base }; }, @@ -243,7 +371,7 @@ pub const Value = extern union { .float_64 => return self.copyPayloadShallow(allocator, Payload.Float_64), .float_128 => return self.copyPayloadShallow(allocator, Payload.Float_128), .enum_literal => { - const payload = @fieldParentPtr(Payload.Bytes, "base", self.ptr_otherwise); + const payload = self.castTag(.enum_literal).?; const new_payload = try allocator.create(Payload.Bytes); new_payload.* = .{ .base = payload.base, @@ -259,7 +387,7 @@ pub const Value = extern union { } fn copyPayloadShallow(self: Value, allocator: *Allocator, comptime T: type) error{OutOfMemory}!Value { - const payload = @fieldParentPtr(T, "base", self.ptr_otherwise); + const payload = self.cast(T).?; const new_payload = try allocator.create(T); new_payload.* = payload.*; return Value{ .ptr_otherwise = &new_payload.base }; @@ -326,45 +454,45 @@ pub const Value = extern union { .unreachable_value => return out_stream.writeAll("unreachable"), .bool_true => return out_stream.writeAll("true"), .bool_false => return out_stream.writeAll("false"), - .ty => return val.cast(Payload.Ty).?.ty.format("", options, out_stream), + .ty => return val.castTag(.ty).?.data.format("", options, out_stream), .int_type => { - const int_type = val.cast(Payload.IntType).?; + const int_type = val.castTag(.int_type).?.data; return out_stream.print("{}{}", .{ if (int_type.signed) "s" else "u", int_type.bits, }); }, - .int_u64 => return std.fmt.formatIntValue(val.cast(Payload.Int_u64).?.int, "", options, out_stream), - .int_i64 => return std.fmt.formatIntValue(val.cast(Payload.Int_i64).?.int, "", options, out_stream), - .int_big_positive => return out_stream.print("{}", .{val.cast(Payload.IntBigPositive).?.asBigInt()}), - .int_big_negative => return out_stream.print("{}", .{val.cast(Payload.IntBigNegative).?.asBigInt()}), + .int_u64 => return std.fmt.formatIntValue(val.castTag(.int_u64).?.data, "", options, out_stream), + .int_i64 => return std.fmt.formatIntValue(val.castTag(.int_i64).?.data, "", options, out_stream), + .int_big_positive => return out_stream.print("{}", .{val.castTag(.int_big_positive).?.asBigInt()}), + .int_big_negative => return out_stream.print("{}", .{val.castTag(.int_big_negative).?.asBigInt()}), .function => return out_stream.writeAll("(function)"), .extern_fn => return out_stream.writeAll("(extern function)"), .variable => return out_stream.writeAll("(variable)"), .ref_val => { - const ref_val = val.cast(Payload.RefVal).?; + const ref_val = val.castTag(.ref_val).?.data; try out_stream.writeAll("&const "); - val = ref_val.val; + val = ref_val; }, .decl_ref => return out_stream.writeAll("(decl ref)"), .elem_ptr => { - const elem_ptr = val.cast(Payload.ElemPtr).?; + const elem_ptr = val.castTag(.elem_ptr).?.data; try out_stream.print("&[{}] ", .{elem_ptr.index}); val = elem_ptr.array_ptr; }, .empty_array => return out_stream.writeAll(".{}"), - .enum_literal => return out_stream.print(".{z}", .{self.cast(Payload.Bytes).?.data}), - .bytes => return out_stream.print("\"{Z}\"", .{self.cast(Payload.Bytes).?.data}), + .enum_literal => return out_stream.print(".{z}", .{self.castTag(.enum_literal).?.data}), + .bytes => return out_stream.print("\"{Z}\"", .{self.castTag(.bytes).?.data}), .repeated => { try out_stream.writeAll("(repeated) "); - val = val.cast(Payload.Repeated).?.val; + val = val.castTag(.repeated).?.data; }, - .float_16 => return out_stream.print("{}", .{val.cast(Payload.Float_16).?.val}), - .float_32 => return out_stream.print("{}", .{val.cast(Payload.Float_32).?.val}), - .float_64 => return out_stream.print("{}", .{val.cast(Payload.Float_64).?.val}), - .float_128 => return out_stream.print("{}", .{val.cast(Payload.Float_128).?.val}), + .float_16 => return out_stream.print("{}", .{val.castTag(.float_16).?.data}), + .float_32 => return out_stream.print("{}", .{val.castTag(.float_32).?.data}), + .float_64 => return out_stream.print("{}", .{val.castTag(.float_64).?.data}), + .float_128 => return out_stream.print("{}", .{val.castTag(.float_128).?.data}), .error_set => { - const error_set = val.cast(Payload.ErrorSet).?; + const error_set = val.castTag(.error_set).?.data; try out_stream.writeAll("error{"); var it = error_set.fields.iterator(); while (it.next()) |entry| { @@ -372,21 +500,24 @@ pub const Value = extern union { } return out_stream.writeAll("}"); }, - .@"error" => return out_stream.print("error.{}", .{val.cast(Payload.Error).?.name}), + .@"error" => return out_stream.print("error.{}", .{val.castTag(.@"error").?.data.name}), }; } /// Asserts that the value is representable as an array of bytes. /// Copies the value into a freshly allocated slice of memory, which is owned by the caller. pub fn toAllocatedBytes(self: Value, allocator: *Allocator) ![]u8 { - if (self.cast(Payload.Bytes)) |bytes| { - return std.mem.dupe(allocator, u8, bytes.data); + if (self.castTag(.bytes)) |payload| { + return std.mem.dupe(allocator, u8, payload.data); } - if (self.cast(Payload.Repeated)) |repeated| { + if (self.castTag(.enum_literal)) |payload| { + return std.mem.dupe(allocator, u8, payload.data); + } + if (self.castTag(.repeated)) |payload| { @panic("TODO implement toAllocatedBytes for this Value tag"); } - if (self.cast(Payload.DeclRef)) |declref| { - const val = try declref.decl.value(); + if (self.castTag(.decl_ref)) |payload| { + const val = try payload.data.value(); return val.toAllocatedBytes(allocator); } unreachable; @@ -395,7 +526,7 @@ pub const Value = extern union { /// Asserts that the value is representable as a type. pub fn toType(self: Value, allocator: *Allocator) !Type { return switch (self.tag()) { - .ty => self.cast(Payload.Ty).?.ty, + .ty => self.castTag(.ty).?.data, .u8_type => Type.initTag(.u8), .i8_type => Type.initTag(.i8), .u16_type => Type.initTag(.u16), @@ -439,7 +570,7 @@ pub const Value = extern union { .anyframe_type => Type.initTag(.@"anyframe"), .int_type => { - const payload = self.cast(Payload.IntType).?; + const payload = self.castTag(.int_type).?.data; const new = try allocator.create(Type.Payload.Bits); new.* = .{ .base = .{ @@ -450,7 +581,7 @@ pub const Value = extern union { return Type.initPayload(&new.base); }, .error_set => { - const payload = self.cast(Payload.ErrorSet).?; + const payload = self.castTag(.error_set).?.data; return Type.Tag.error_set.create(allocator, payload.decl); }, @@ -564,10 +695,10 @@ pub const Value = extern union { .bool_true, => return BigIntMutable.init(&space.limbs, 1).toConst(), - .int_u64 => return BigIntMutable.init(&space.limbs, self.cast(Payload.Int_u64).?.int).toConst(), - .int_i64 => return BigIntMutable.init(&space.limbs, self.cast(Payload.Int_i64).?.int).toConst(), - .int_big_positive => return self.cast(Payload.IntBigPositive).?.asBigInt(), - .int_big_negative => return self.cast(Payload.IntBigNegative).?.asBigInt(), + .int_u64 => return BigIntMutable.init(&space.limbs, self.castTag(.int_u64).?.data).toConst(), + .int_i64 => return BigIntMutable.init(&space.limbs, self.castTag(.int_i64).?.data).toConst(), + .int_big_positive => return self.castTag(.int_big_positive).?.asBigInt(), + .int_big_negative => return self.castTag(.int_big_negative).?.asBigInt(), } } @@ -649,10 +780,10 @@ pub const Value = extern union { .bool_true, => return 1, - .int_u64 => return self.cast(Payload.Int_u64).?.int, - .int_i64 => return @intCast(u64, self.cast(Payload.Int_i64).?.int), - .int_big_positive => return self.cast(Payload.IntBigPositive).?.asBigInt().to(u64) catch unreachable, - .int_big_negative => return self.cast(Payload.IntBigNegative).?.asBigInt().to(u64) catch unreachable, + .int_u64 => return self.castTag(.int_u64).?.data, + .int_i64 => return @intCast(u64, self.castTag(.int_i64).?.data), + .int_big_positive => return self.castTag(.int_big_positive).?.asBigInt().to(u64) catch unreachable, + .int_big_negative => return self.castTag(.int_big_negative).?.asBigInt().to(u64) catch unreachable, } } @@ -734,10 +865,10 @@ pub const Value = extern union { .bool_true, => return 1, - .int_u64 => return @intCast(i64, self.cast(Payload.Int_u64).?.int), - .int_i64 => return self.cast(Payload.Int_i64).?.int, - .int_big_positive => return self.cast(Payload.IntBigPositive).?.asBigInt().to(i64) catch unreachable, - .int_big_negative => return self.cast(Payload.IntBigNegative).?.asBigInt().to(i64) catch unreachable, + .int_u64 => return @intCast(i64, self.castTag(.int_u64).?.data), + .int_i64 => return self.castTag(.int_i64).?.data, + .int_big_positive => return self.castTag(.int_big_positive).?.asBigInt().to(i64) catch unreachable, + .int_big_negative => return self.castTag(.int_big_negative).?.asBigInt().to(i64) catch unreachable, } } @@ -753,14 +884,14 @@ pub const Value = extern union { pub fn toFloat(self: Value, comptime T: type) T { return switch (self.tag()) { .float_16 => @panic("TODO soft float"), - .float_32 => @floatCast(T, self.cast(Payload.Float_32).?.val), - .float_64 => @floatCast(T, self.cast(Payload.Float_64).?.val), - .float_128 => @floatCast(T, self.cast(Payload.Float_128).?.val), + .float_32 => @floatCast(T, self.castTag(.float_32).?.data), + .float_64 => @floatCast(T, self.castTag(.float_64).?.data), + .float_128 => @floatCast(T, self.castTag(.float_128).?.data), .zero => 0, .one => 1, - .int_u64 => @intToFloat(T, self.cast(Payload.Int_u64).?.int), - .int_i64 => @intToFloat(T, self.cast(Payload.Int_i64).?.int), + .int_u64 => @intToFloat(T, self.castTag(.int_u64).?.data), + .int_i64 => @intToFloat(T, self.castTag(.int_i64).?.data), .int_big_positive, .int_big_negative => @panic("big int to f128"), else => unreachable, @@ -846,15 +977,15 @@ pub const Value = extern union { => return 1, .int_u64 => { - const x = self.cast(Payload.Int_u64).?.int; + const x = self.castTag(.int_u64).?.data; if (x == 0) return 0; return @intCast(usize, std.math.log2(x) + 1); }, .int_i64 => { @panic("TODO implement i64 intBitCountTwosComp"); }, - .int_big_positive => return self.cast(Payload.IntBigPositive).?.asBigInt().bitCountTwosComp(), - .int_big_negative => return self.cast(Payload.IntBigNegative).?.asBigInt().bitCountTwosComp(), + .int_big_positive => return self.castTag(.int_big_positive).?.asBigInt().bitCountTwosComp(), + .int_big_negative => return self.castTag(.int_big_negative).?.asBigInt().bitCountTwosComp(), } } @@ -943,7 +1074,7 @@ pub const Value = extern union { .int_u64 => switch (ty.zigTypeTag()) { .Int => { - const x = self.cast(Payload.Int_u64).?.int; + const x = self.castTag(.int_u64).?.data; if (x == 0) return true; const info = ty.intInfo(target); const needed_bits = std.math.log2(x) + 1 + @boolToInt(info.signedness == .signed); @@ -954,7 +1085,7 @@ pub const Value = extern union { }, .int_i64 => switch (ty.zigTypeTag()) { .Int => { - const x = self.cast(Payload.Int_i64).?.int; + const x = self.castTag(.int_i64).?.data; if (x == 0) return true; const info = ty.intInfo(target); if (info.signedness == .unsigned and x < 0) @@ -967,7 +1098,7 @@ pub const Value = extern union { .int_big_positive => switch (ty.zigTypeTag()) { .Int => { const info = ty.intInfo(target); - return self.cast(Payload.IntBigPositive).?.asBigInt().fitsInTwosComp(info.signedness, info.bits); + return self.castTag(.int_big_positive).?.asBigInt().fitsInTwosComp(info.signedness, info.bits); }, .ComptimeInt => return true, else => unreachable, @@ -975,7 +1106,7 @@ pub const Value = extern union { .int_big_negative => switch (ty.zigTypeTag()) { .Int => { const info = ty.intInfo(target); - return self.cast(Payload.IntBigNegative).?.asBigInt().fitsInTwosComp(info.signedness, info.bits); + return self.castTag(.int_big_negative).?.asBigInt().fitsInTwosComp(info.signedness, info.bits); }, .ComptimeInt => return true, else => unreachable, @@ -986,42 +1117,28 @@ pub const Value = extern union { /// Converts an integer or a float to a float. /// Returns `error.Overflow` if the value does not fit in the new type. pub fn floatCast(self: Value, allocator: *Allocator, ty: Type, target: Target) !Value { - const dest_bit_count = switch (ty.tag()) { - .comptime_float => 128, - else => ty.floatBits(target), - }; - switch (dest_bit_count) { - 16, 32, 64, 128 => {}, - else => std.debug.panic("TODO float cast bit count {}\n", .{dest_bit_count}), - } - if (ty.isInt()) { - @panic("TODO int to float"); - } - - switch (dest_bit_count) { - 16 => { - @panic("TODO soft float"); - // var res_payload = Value.Payload.Float_16{.val = self.toFloat(f16)}; - // if (!self.eql(Value.initPayload(&res_payload.base))) - // return error.Overflow; - // return Value.initPayload(&res_payload.base).copy(allocator); + switch (ty.tag()) { + .f16 => { + @panic("TODO add __trunctfhf2 to compiler-rt"); + //const res = try Value.Tag.float_16.create(allocator, self.toFloat(f16)); + //if (!self.eql(res)) + // return error.Overflow; + //return res; }, - 32 => { - var res_payload = Value.Payload.Float_32{ .val = self.toFloat(f32) }; - if (!self.eql(Value.initPayload(&res_payload.base))) + .f32 => { + const res = try Value.Tag.float_32.create(allocator, self.toFloat(f32)); + if (!self.eql(res)) return error.Overflow; - return Value.initPayload(&res_payload.base).copy(allocator); + return res; }, - 64 => { - var res_payload = Value.Payload.Float_64{ .val = self.toFloat(f64) }; - if (!self.eql(Value.initPayload(&res_payload.base))) + .f64 => { + const res = try Value.Tag.float_64.create(allocator, self.toFloat(f64)); + if (!self.eql(res)) return error.Overflow; - return Value.initPayload(&res_payload.base).copy(allocator); + return res; }, - 128 => { - const float_payload = try allocator.create(Value.Payload.Float_128); - float_payload.* = .{ .val = self.toFloat(f128) }; - return Value.initPayload(&float_payload.base); + .f128, .comptime_float, .c_longdouble => { + return Value.Tag.float_128.create(allocator, self.toFloat(f128)); }, else => unreachable, } @@ -1102,10 +1219,10 @@ pub const Value = extern union { .one, => false, - .float_16 => @rem(self.cast(Payload.Float_16).?.val, 1) != 0, - .float_32 => @rem(self.cast(Payload.Float_32).?.val, 1) != 0, - .float_64 => @rem(self.cast(Payload.Float_64).?.val, 1) != 0, - // .float_128 => @rem(self.cast(Payload.Float_128).?.val, 1) != 0, + .float_16 => @rem(self.castTag(.float_16).?.data, 1) != 0, + .float_32 => @rem(self.castTag(.float_32).?.data, 1) != 0, + .float_64 => @rem(self.castTag(.float_64).?.data, 1) != 0, + // .float_128 => @rem(self.castTag(.float_128).?.data, 1) != 0, .float_128 => @panic("TODO lld: error: undefined symbol: fmodl"), }; } @@ -1182,15 +1299,15 @@ pub const Value = extern union { .bool_true, => .gt, - .int_u64 => std.math.order(lhs.cast(Payload.Int_u64).?.int, 0), - .int_i64 => std.math.order(lhs.cast(Payload.Int_i64).?.int, 0), - .int_big_positive => lhs.cast(Payload.IntBigPositive).?.asBigInt().orderAgainstScalar(0), - .int_big_negative => lhs.cast(Payload.IntBigNegative).?.asBigInt().orderAgainstScalar(0), + .int_u64 => std.math.order(lhs.castTag(.int_u64).?.data, 0), + .int_i64 => std.math.order(lhs.castTag(.int_i64).?.data, 0), + .int_big_positive => lhs.castTag(.int_big_positive).?.asBigInt().orderAgainstScalar(0), + .int_big_negative => lhs.castTag(.int_big_negative).?.asBigInt().orderAgainstScalar(0), - .float_16 => std.math.order(lhs.cast(Payload.Float_16).?.val, 0), - .float_32 => std.math.order(lhs.cast(Payload.Float_32).?.val, 0), - .float_64 => std.math.order(lhs.cast(Payload.Float_64).?.val, 0), - .float_128 => std.math.order(lhs.cast(Payload.Float_128).?.val, 0), + .float_16 => std.math.order(lhs.castTag(.float_16).?.data, 0), + .float_32 => std.math.order(lhs.castTag(.float_32).?.data, 0), + .float_64 => std.math.order(lhs.castTag(.float_64).?.data, 0), + .float_128 => std.math.order(lhs.castTag(.float_128).?.data, 0), }; } @@ -1208,10 +1325,10 @@ pub const Value = extern union { if (lhs_float and rhs_float) { if (lhs_tag == rhs_tag) { return switch (lhs.tag()) { - .float_16 => return std.math.order(lhs.cast(Payload.Float_16).?.val, rhs.cast(Payload.Float_16).?.val), - .float_32 => return std.math.order(lhs.cast(Payload.Float_32).?.val, rhs.cast(Payload.Float_32).?.val), - .float_64 => return std.math.order(lhs.cast(Payload.Float_64).?.val, rhs.cast(Payload.Float_64).?.val), - .float_128 => return std.math.order(lhs.cast(Payload.Float_128).?.val, rhs.cast(Payload.Float_128).?.val), + .float_16 => return std.math.order(lhs.castTag(.float_16).?.data, rhs.castTag(.float_16).?.data), + .float_32 => return std.math.order(lhs.castTag(.float_32).?.data, rhs.castTag(.float_32).?.data), + .float_64 => return std.math.order(lhs.castTag(.float_64).?.data, rhs.castTag(.float_64).?.data), + .float_128 => return std.math.order(lhs.castTag(.float_128).?.data, rhs.castTag(.float_128).?.data), else => unreachable, }; } @@ -1244,8 +1361,8 @@ pub const Value = extern union { if (a.tag() == .void_value or a.tag() == .null_value) { return true; } else if (a.tag() == .enum_literal) { - const a_name = @fieldParentPtr(Payload.Bytes, "base", a.ptr_otherwise).data; - const b_name = @fieldParentPtr(Payload.Bytes, "base", b.ptr_otherwise).data; + const a_name = a.castTag(.enum_literal).?.data; + const b_name = b.castTag(.enum_literal).?.data; return std.mem.eql(u8, a_name, b_name); } } @@ -1313,11 +1430,11 @@ pub const Value = extern union { }, .error_set => { // Payload.decl should be same for all instances of the type. - const payload = @fieldParentPtr(Payload.ErrorSet, "base", self.ptr_otherwise); + const payload = self.castTag(.error_set).?.data; std.hash.autoHash(&hasher, payload.decl); }, .int_type => { - const payload = self.cast(Payload.IntType).?; + const payload = self.castTag(.int_type).?.data; var int_payload = Type.Payload.Bits{ .base = .{ .tag = if (payload.signed) .int_signed else .int_unsigned, @@ -1341,25 +1458,29 @@ pub const Value = extern union { .one, .bool_true => std.hash.autoHash(&hasher, @as(u64, 1)), .float_16, .float_32, .float_64, .float_128 => {}, - .enum_literal, .bytes => { - const payload = @fieldParentPtr(Payload.Bytes, "base", self.ptr_otherwise); + .enum_literal => { + const payload = self.castTag(.enum_literal).?; + hasher.update(payload.data); + }, + .bytes => { + const payload = self.castTag(.bytes).?; hasher.update(payload.data); }, .int_u64 => { - const payload = @fieldParentPtr(Payload.Int_u64, "base", self.ptr_otherwise); - std.hash.autoHash(&hasher, payload.int); + const payload = self.castTag(.int_u64).?; + std.hash.autoHash(&hasher, payload.data); }, .int_i64 => { - const payload = @fieldParentPtr(Payload.Int_i64, "base", self.ptr_otherwise); - std.hash.autoHash(&hasher, payload.int); + const payload = self.castTag(.int_i64).?; + std.hash.autoHash(&hasher, payload.data); }, .repeated => { - const payload = @fieldParentPtr(Payload.Repeated, "base", self.ptr_otherwise); - std.hash.autoHash(&hasher, payload.val.hash()); + const payload = self.castTag(.repeated).?; + std.hash.autoHash(&hasher, payload.data.hash()); }, .ref_val => { - const payload = @fieldParentPtr(Payload.RefVal, "base", self.ptr_otherwise); - std.hash.autoHash(&hasher, payload.val.hash()); + const payload = self.castTag(.ref_val).?; + std.hash.autoHash(&hasher, payload.data.hash()); }, .int_big_positive, .int_big_negative => { var space: BigIntSpace = undefined; @@ -1379,28 +1500,28 @@ pub const Value = extern union { } }, .elem_ptr => { - const payload = @fieldParentPtr(Payload.ElemPtr, "base", self.ptr_otherwise); + const payload = self.castTag(.elem_ptr).?.data; std.hash.autoHash(&hasher, payload.array_ptr.hash()); std.hash.autoHash(&hasher, payload.index); }, .decl_ref => { - const payload = @fieldParentPtr(Payload.DeclRef, "base", self.ptr_otherwise); - std.hash.autoHash(&hasher, payload.decl); + const decl = self.castTag(.decl_ref).?.data; + std.hash.autoHash(&hasher, decl); }, .function => { - const payload = @fieldParentPtr(Payload.Function, "base", self.ptr_otherwise); - std.hash.autoHash(&hasher, payload.func); + const func = self.castTag(.function).?.data; + std.hash.autoHash(&hasher, func); }, .extern_fn => { - const payload = @fieldParentPtr(Payload.ExternFn, "base", self.ptr_otherwise); - std.hash.autoHash(&hasher, payload.decl); + const decl = self.castTag(.extern_fn).?.data; + std.hash.autoHash(&hasher, decl); }, .variable => { - const payload = @fieldParentPtr(Payload.Variable, "base", self.ptr_otherwise); - std.hash.autoHash(&hasher, payload.variable); + const variable = self.castTag(.variable).?.data; + std.hash.autoHash(&hasher, variable); }, .@"error" => { - const payload = @fieldParentPtr(Payload.Error, "base", self.ptr_otherwise); + const payload = self.castTag(.@"error").?.data; hasher.update(payload.name); std.hash.autoHash(&hasher, payload.value); }, @@ -1483,10 +1604,10 @@ pub const Value = extern union { .empty_struct_value, => unreachable, - .ref_val => self.cast(Payload.RefVal).?.val, - .decl_ref => self.cast(Payload.DeclRef).?.decl.value(), + .ref_val => self.castTag(.ref_val).?.data, + .decl_ref => self.castTag(.decl_ref).?.data.value(), .elem_ptr => { - const elem_ptr = self.cast(Payload.ElemPtr).?; + const elem_ptr = self.castTag(.elem_ptr).?.data; const array_val = try elem_ptr.array_ptr.pointerDeref(allocator); return array_val.elemValue(allocator, elem_ptr.index); }, @@ -1570,26 +1691,26 @@ pub const Value = extern union { .empty_array => unreachable, // out of bounds array index - .bytes => { - const int_payload = try allocator.create(Payload.Int_u64); - int_payload.* = .{ .int = self.cast(Payload.Bytes).?.data[index] }; - return Value.initPayload(&int_payload.base); - }, + .bytes => return Tag.int_u64.create(allocator, self.castTag(.bytes).?.data[index]), // No matter the index; all the elements are the same! - .repeated => return self.cast(Payload.Repeated).?.val, + .repeated => return self.castTag(.repeated).?.data, } } /// Returns a pointer to the element value at the index. pub fn elemPtr(self: Value, allocator: *Allocator, index: usize) !Value { - const payload = try allocator.create(Payload.ElemPtr); - if (self.cast(Payload.ElemPtr)) |elem_ptr| { - payload.* = .{ .array_ptr = elem_ptr.array_ptr, .index = elem_ptr.index + index }; - } else { - payload.* = .{ .array_ptr = self, .index = index }; + if (self.castTag(.elem_ptr)) |elem_ptr| { + return Tag.elem_ptr.create(allocator, .{ + .array_ptr = elem_ptr.data.array_ptr, + .index = elem_ptr.data.index + index, + }); } - return Value.initPayload(&payload.base); + + return Tag.elem_ptr.create(allocator, .{ + .array_ptr = self, + .index = index, + }); } pub fn isUndef(self: Value) bool { @@ -1776,131 +1897,128 @@ pub const Value = extern union { pub const Payload = struct { tag: Tag, - pub const Int_u64 = struct { - base: Payload = Payload{ .tag = .int_u64 }, - int: u64, + pub const U64 = struct { + base: Payload, + data: u64, }; - pub const Int_i64 = struct { - base: Payload = Payload{ .tag = .int_i64 }, - int: i64, + pub const I64 = struct { + base: Payload, + data: i64, }; - pub const IntBigPositive = struct { - base: Payload = Payload{ .tag = .int_big_positive }, - limbs: []const std.math.big.Limb, + pub const BigInt = struct { + base: Payload, + data: []const std.math.big.Limb, - pub fn asBigInt(self: IntBigPositive) BigIntConst { - return BigIntConst{ .limbs = self.limbs, .positive = true }; - } - }; - - pub const IntBigNegative = struct { - base: Payload = Payload{ .tag = .int_big_negative }, - limbs: []const std.math.big.Limb, - - pub fn asBigInt(self: IntBigNegative) BigIntConst { - return BigIntConst{ .limbs = self.limbs, .positive = false }; + pub fn asBigInt(self: BigInt) BigIntConst { + const positive = switch (self.base.tag) { + .int_big_positive => true, + .int_big_negative => false, + else => unreachable, + }; + return BigIntConst{ .limbs = self.data, .positive = positive }; } }; pub const Function = struct { - base: Payload = Payload{ .tag = .function }, - func: *Module.Fn, + base: Payload, + data: *Module.Fn, }; - pub const ExternFn = struct { - base: Payload = Payload{ .tag = .extern_fn }, - decl: *Module.Decl, + pub const Decl = struct { + base: Payload, + data: *Module.Decl, }; pub const Variable = struct { - base: Payload = Payload{ .tag = .variable }, - variable: *Module.Var, + base: Payload, + data: *Module.Var, }; - pub const ArraySentinel0_u8_Type = struct { - base: Payload = Payload{ .tag = .array_sentinel_0_u8_type }, - len: u64, - }; - - /// Represents a pointer to another immutable value. - pub const RefVal = struct { - base: Payload = Payload{ .tag = .ref_val }, - val: Value, - }; - - /// Represents a pointer to a decl, not the value of the decl. - pub const DeclRef = struct { - base: Payload = Payload{ .tag = .decl_ref }, - decl: *Module.Decl, + pub const SubValue = struct { + base: Payload, + data: Value, }; pub const ElemPtr = struct { - base: Payload = Payload{ .tag = .elem_ptr }, - array_ptr: Value, - index: usize, + pub const base_tag = Tag.elem_ptr; + + base: Payload = Payload{ .tag = base_tag }, + data: struct { + array_ptr: Value, + index: usize, + }, }; pub const Bytes = struct { - base: Payload = Payload{ .tag = .bytes }, + base: Payload, data: []const u8, }; pub const Ty = struct { - base: Payload = Payload{ .tag = .ty }, - ty: Type, + base: Payload, + data: Type, }; pub const IntType = struct { - base: Payload = Payload{ .tag = .int_type }, - bits: u16, - signed: bool, - }; + pub const base_tag = Tag.int_type; - pub const Repeated = struct { - base: Payload = Payload{ .tag = .ty }, - /// This value is repeated some number of times. The amount of times to repeat - /// is stored externally. - val: Value, + base: Payload = Payload{ .tag = base_tag }, + data: struct { + bits: u16, + signed: bool, + }, }; pub const Float_16 = struct { - base: Payload = .{ .tag = .float_16 }, - val: f16, + pub const base_tag = Tag.float_16; + + base: Payload = .{ .tag = base_tag }, + data: f16, }; pub const Float_32 = struct { - base: Payload = .{ .tag = .float_32 }, - val: f32, + pub const base_tag = Tag.float_32; + + base: Payload = .{ .tag = base_tag }, + data: f32, }; pub const Float_64 = struct { - base: Payload = .{ .tag = .float_64 }, - val: f64, + pub const base_tag = Tag.float_64; + + base: Payload = .{ .tag = base_tag }, + data: f64, }; pub const Float_128 = struct { - base: Payload = .{ .tag = .float_128 }, - val: f128, + pub const base_tag = Tag.float_128; + + base: Payload = .{ .tag = base_tag }, + data: f128, }; pub const ErrorSet = struct { - base: Payload = .{ .tag = .error_set }, + pub const base_tag = Tag.error_set; - // TODO revisit this when we have the concept of the error tag type - fields: std.StringHashMapUnmanaged(u16), - decl: *Module.Decl, + base: Payload = .{ .tag = base_tag }, + data: struct { + // TODO revisit this when we have the concept of the error tag type + fields: std.StringHashMapUnmanaged(u16), + decl: *Module.Decl, + }, }; pub const Error = struct { base: Payload = .{ .tag = .@"error" }, - - // TODO revisit this when we have the concept of the error tag type - /// `name` is owned by `Module` and will be valid for the entire - /// duration of the compilation. - name: []const u8, - value: u16, + data: struct { + // TODO revisit this when we have the concept of the error tag type + /// `name` is owned by `Module` and will be valid for the entire + /// duration of the compilation. + name: []const u8, + value: u16, + }, }; }; @@ -1914,15 +2032,24 @@ pub const Value = extern union { test "hash same value different representation" { const zero_1 = Value.initTag(.zero); - var payload_1 = Value.Payload.Int_u64{ .int = 0 }; + var payload_1 = Value.Payload.U64{ + .base = .{ .tag = .int_u64 }, + .data = 0, + }; const zero_2 = Value.initPayload(&payload_1.base); std.testing.expectEqual(zero_1.hash(), zero_2.hash()); - var payload_2 = Value.Payload.Int_i64{ .int = 0 }; + var payload_2 = Value.Payload.I64{ + .base = .{ .tag = .int_i64 }, + .data = 0, + }; const zero_3 = Value.initPayload(&payload_2.base); std.testing.expectEqual(zero_2.hash(), zero_3.hash()); - var payload_3 = Value.Payload.IntBigNegative{ .limbs = &[_]std.math.big.Limb{0} }; + var payload_3 = Value.Payload.BigInt{ + .base = .{ .tag = .int_big_negative }, + .data = &[_]std.math.big.Limb{0}, + }; const zero_4 = Value.initPayload(&payload_3.base); std.testing.expectEqual(zero_3.hash(), zero_4.hash()); } diff --git a/src/zir.zig b/src/zir.zig index bd9ab2c538..21bd4f8435 100644 --- a/src/zir.zig +++ b/src/zir.zig @@ -1990,15 +1990,15 @@ const EmitZIR = struct { fn resolveInst(self: *EmitZIR, new_body: ZirBody, inst: *ir.Inst) !*Inst { if (inst.cast(ir.Inst.Constant)) |const_inst| { - const new_inst = if (const_inst.val.cast(Value.Payload.Function)) |func_pl| blk: { - const owner_decl = func_pl.func.owner_decl; + const new_inst = if (const_inst.val.castTag(.function)) |func_pl| blk: { + const owner_decl = func_pl.data.owner_decl; break :blk try self.emitDeclVal(inst.src, mem.spanZ(owner_decl.name)); - } else if (const_inst.val.cast(Value.Payload.DeclRef)) |declref| blk: { - const decl_ref = try self.emitDeclRef(inst.src, declref.decl); + } else if (const_inst.val.castTag(.decl_ref)) |declref| blk: { + const decl_ref = try self.emitDeclRef(inst.src, declref.data); try new_body.instructions.append(decl_ref); break :blk decl_ref; - } else if (const_inst.val.cast(Value.Payload.Variable)) |var_pl| blk: { - const owner_decl = var_pl.variable.owner_decl; + } else if (const_inst.val.castTag(.variable)) |var_pl| blk: { + const owner_decl = var_pl.data.owner_decl; break :blk try self.emitDeclVal(inst.src, mem.spanZ(owner_decl.name)); } else blk: { break :blk (try self.emitTypedValue(inst.src, .{ .ty = inst.ty, .val = const_inst.val })).inst; @@ -2150,13 +2150,13 @@ const EmitZIR = struct { fn emitTypedValue(self: *EmitZIR, src: usize, typed_value: TypedValue) Allocator.Error!*Decl { const allocator = &self.arena.allocator; - if (typed_value.val.cast(Value.Payload.DeclRef)) |decl_ref| { - const decl = decl_ref.decl; + if (typed_value.val.castTag(.decl_ref)) |decl_ref| { + const decl = decl_ref.data; return try self.emitUnnamedDecl(try self.emitDeclRef(src, decl)); - } else if (typed_value.val.cast(Value.Payload.Variable)) |variable| { + } else if (typed_value.val.castTag(.variable)) |variable| { return self.emitTypedValue(src, .{ .ty = typed_value.ty, - .val = variable.variable.init, + .val = variable.data.init, }); } if (typed_value.val.isUndef()) { @@ -2215,7 +2215,7 @@ const EmitZIR = struct { return self.emitType(src, ty); }, .Fn => { - const module_fn = typed_value.val.cast(Value.Payload.Function).?.func; + const module_fn = typed_value.val.castTag(.function).?.data; return self.emitFn(module_fn, src, typed_value.ty); }, .Array => { @@ -2248,7 +2248,7 @@ const EmitZIR = struct { else return self.emitPrimitive(src, .@"false"), .EnumLiteral => { - const enum_literal = @fieldParentPtr(Value.Payload.Bytes, "base", typed_value.val.ptr_otherwise); + const enum_literal = typed_value.val.castTag(.enum_literal).?; const inst = try self.arena.allocator.create(Inst.Str); inst.* = .{ .base = .{ @@ -2748,9 +2748,8 @@ const EmitZIR = struct { .signed => .@"true", .unsigned => .@"false", }); - const bits_payload = try self.arena.allocator.create(Value.Payload.Int_u64); - bits_payload.* = .{ .int = info.bits }; - const bits = try self.emitComptimeIntVal(src, Value.initPayload(&bits_payload.base)); + const bits_val = try Value.Tag.int_u64.create(&self.arena.allocator, info.bits); + const bits = try self.emitComptimeIntVal(src, bits_val); const inttype_inst = try self.arena.allocator.create(Inst.IntType); inttype_inst.* = .{ .base = .{ @@ -2800,7 +2799,10 @@ const EmitZIR = struct { return self.emitUnnamedDecl(&inst.base); }, .Array => { - var len_pl = Value.Payload.Int_u64{ .int = ty.arrayLen() }; + var len_pl = Value.Payload.U64{ + .base = .{ .tag = .int_u64 }, + .data = ty.arrayLen(), + }; const len = Value.initPayload(&len_pl.base); const inst = if (ty.sentinel()) |sentinel| blk: { diff --git a/src/zir_sema.zig b/src/zir_sema.zig index 8960f3ba4d..2e3cced839 100644 --- a/src/zir_sema.zig +++ b/src/zir_sema.zig @@ -364,12 +364,9 @@ fn analyzeInstRef(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError! const ptr_type = try mod.simplePtrType(scope, inst.base.src, operand.ty, false, .One); if (operand.value()) |val| { - const ref_payload = try scope.arena().create(Value.Payload.RefVal); - ref_payload.* = .{ .val = val }; - return mod.constInst(scope, inst.base.src, .{ .ty = ptr_type, - .val = Value.initPayload(&ref_payload.base), + .val = try Value.Tag.ref_val.create(scope.arena(), val), }); } @@ -480,12 +477,9 @@ fn analyzeInstStr(mod: *Module, scope: *Scope, str_inst: *zir.Inst.Str) InnerErr errdefer new_decl_arena.deinit(); const arena_bytes = try new_decl_arena.allocator.dupe(u8, str_inst.positionals.bytes); - const bytes_payload = try scope.arena().create(Value.Payload.Bytes); - bytes_payload.* = .{ .data = arena_bytes }; - const new_decl = try mod.createAnonymousDecl(scope, &new_decl_arena, .{ .ty = try Type.Tag.array_u8_sentinel_0.create(scope.arena(), arena_bytes.len), - .val = Value.initPayload(&bytes_payload.base), + .val = try Value.Tag.bytes.create(scope.arena(), arena_bytes), }); return mod.analyzeDeclRef(scope, str_inst.base.src, new_decl); } @@ -779,11 +773,9 @@ fn analyzeInstFn(mod: *Module, scope: *Scope, fn_inst: *zir.Inst.Fn) InnerError! .analysis = .{ .queued = fn_zir }, .owner_decl = scope.decl().?, }; - const fn_payload = try scope.arena().create(Value.Payload.Function); - fn_payload.* = .{ .func = new_func }; return mod.constInst(scope, fn_inst.base.src, .{ .ty = fn_type, - .val = Value.initPayload(&fn_payload.base), + .val = try Value.Tag.function.create(scope.arena(), new_func), }); } @@ -838,14 +830,17 @@ fn analyzeInstErrorSet(mod: *Module, scope: *Scope, inst: *zir.Inst.ErrorSet) In const payload = try scope.arena().create(Value.Payload.ErrorSet); payload.* = .{ - .fields = .{}, - .decl = undefined, // populated below + .base = .{ .tag = .error_set }, + .data = .{ + .fields = .{}, + .decl = undefined, // populated below + }, }; - try payload.fields.ensureCapacity(&new_decl_arena.allocator, @intCast(u32, inst.positionals.fields.len)); + try payload.data.fields.ensureCapacity(&new_decl_arena.allocator, @intCast(u32, inst.positionals.fields.len)); for (inst.positionals.fields) |field_name| { const entry = try mod.getErrorValue(field_name); - if (payload.fields.fetchPutAssumeCapacity(entry.key, entry.value)) |prev| { + if (payload.data.fields.fetchPutAssumeCapacity(entry.key, entry.value)) |prev| { return mod.fail(scope, inst.base.src, "duplicate error: '{}'", .{field_name}); } } @@ -854,7 +849,7 @@ fn analyzeInstErrorSet(mod: *Module, scope: *Scope, inst: *zir.Inst.ErrorSet) In .ty = Type.initTag(.type), .val = Value.initPayload(&payload.base), }); - payload.decl = new_decl; + payload.data.decl = new_decl; return mod.analyzeDeclRef(scope, inst.base.src, new_decl); } @@ -863,14 +858,10 @@ fn analyzeInstMergeErrorSets(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) } fn analyzeInstEnumLiteral(mod: *Module, scope: *Scope, inst: *zir.Inst.EnumLiteral) InnerError!*Inst { - const payload = try scope.arena().create(Value.Payload.Bytes); - payload.* = .{ - .base = .{ .tag = .enum_literal }, - .data = try scope.arena().dupe(u8, inst.positionals.name), - }; + const duped_name = try scope.arena().dupe(u8, inst.positionals.name); return mod.constInst(scope, inst.base.src, .{ .ty = Type.initTag(.enum_literal), - .val = Value.initPayload(&payload.base), + .val = try Value.Tag.enum_literal.create(scope.arena(), duped_name), }); } @@ -989,15 +980,12 @@ fn analyzeInstFieldPtr(mod: *Module, scope: *Scope, fieldptr: *zir.Inst.FieldPtr switch (elem_ty.zigTypeTag()) { .Array => { if (mem.eql(u8, field_name, "len")) { - const len_payload = try scope.arena().create(Value.Payload.Int_u64); - len_payload.* = .{ .int = elem_ty.arrayLen() }; - - const ref_payload = try scope.arena().create(Value.Payload.RefVal); - ref_payload.* = .{ .val = Value.initPayload(&len_payload.base) }; - return mod.constInst(scope, fieldptr.base.src, .{ .ty = Type.initTag(.single_const_pointer_to_comptime_int), - .val = Value.initPayload(&ref_payload.base), + .val = try Value.Tag.ref_val.create( + scope.arena(), + try Value.Tag.int_u64.create(scope.arena(), elem_ty.arrayLen()), + ), }); } else { return mod.fail( @@ -1013,15 +1001,12 @@ fn analyzeInstFieldPtr(mod: *Module, scope: *Scope, fieldptr: *zir.Inst.FieldPtr switch (ptr_child.zigTypeTag()) { .Array => { if (mem.eql(u8, field_name, "len")) { - const len_payload = try scope.arena().create(Value.Payload.Int_u64); - len_payload.* = .{ .int = ptr_child.arrayLen() }; - - const ref_payload = try scope.arena().create(Value.Payload.RefVal); - ref_payload.* = .{ .val = Value.initPayload(&len_payload.base) }; - return mod.constInst(scope, fieldptr.base.src, .{ .ty = Type.initTag(.single_const_pointer_to_comptime_int), - .val = Value.initPayload(&ref_payload.base), + .val = try Value.Tag.ref_val.create( + scope.arena(), + try Value.Tag.int_u64.create(scope.arena(), ptr_child.arrayLen()), + ), }); } else { return mod.fail( @@ -1043,21 +1028,12 @@ fn analyzeInstFieldPtr(mod: *Module, scope: *Scope, fieldptr: *zir.Inst.FieldPtr switch (child_type.zigTypeTag()) { .ErrorSet => { // TODO resolve inferred error sets - const entry = if (val.cast(Value.Payload.ErrorSet)) |payload| - (payload.fields.getEntry(field_name) orelse + const entry = if (val.castTag(.error_set)) |payload| + (payload.data.fields.getEntry(field_name) orelse return mod.fail(scope, fieldptr.base.src, "no error named '{}' in '{}'", .{ field_name, child_type })).* else try mod.getErrorValue(field_name); - const error_payload = try scope.arena().create(Value.Payload.Error); - error_payload.* = .{ - .name = entry.key, - .value = entry.value, - }; - - const ref_payload = try scope.arena().create(Value.Payload.RefVal); - ref_payload.* = .{ .val = Value.initPayload(&error_payload.base) }; - const result_type = if (child_type.tag() == .anyerror) try Type.Tag.error_set_single.create(scope.arena(), entry.key) else @@ -1065,7 +1041,13 @@ fn analyzeInstFieldPtr(mod: *Module, scope: *Scope, fieldptr: *zir.Inst.FieldPtr return mod.constInst(scope, fieldptr.base.src, .{ .ty = try mod.simplePtrType(scope, fieldptr.base.src, result_type, false, .One), - .val = Value.initPayload(&ref_payload.base), + .val = try Value.Tag.ref_val.create( + scope.arena(), + try Value.Tag.@"error".create(scope.arena(), .{ + .name = entry.key, + .value = entry.value, + }), + ), }); }, .Struct => {