| author | |
| committer | |
| log | a5c6e51f03ab164e64b1a1d8370071dd1e670458 |
| tree | f803ff576a680391288ce944117d3fc999ef133b |
| parent | ed174b7386cb5a6f2008cb6a25c3ff684645d847 |
* AIR no longer has a `variables` array. Instead of the `varptr`
instruction, Sema emits a constant with a `decl_ref`.
* AIR no longer has a `ref` instruction. There is no longer any
instruction that takes a value and returns a pointer to it. If this
is desired, Sema must either create an anynomous Decl and return a
constant `decl_ref`, or in the case of a runtime value, emit an
`alloc` instruction, `store` the value to it, and then return the
`alloc`.
* The `ref_val` Value Tag is eliminated. `decl_ref` should be used
instead. Also added is `eu_payload_ptr` which points to the payload
of an error union, given an error union pointer.
In general, Sema should avoid calling `analyzeRef` if it can be helped.
For example in the case of field_val and elem_val, there should never be
a reason to create a temporary (alloc or decl). Recent previous commits
made progress along that front.
There is a new abstraction in Sema, which looks like this:
var anon_decl = try block.startAnonDecl();
defer anon_decl.deinit();
// here 'anon_decl.arena()` may be used
const decl = try anon_decl.finish(ty, val);
// decl is typically now used with `decl_ref`.
This pattern is used to upgrade `ref_val` usages to `decl_ref` usages.
Additional improvements:
* Sema: fix source location resolution for calling convention
expression.
* Sema: properly report "unable to resolve comptime value" for loads of
global variables. There is now a set of functions which can be
called if the callee wants to obtain the Value even if the tag is
`variable` (indicating comptime-known address but runtime-known value).
* Sema: `coerce` resolves builtin types before checking equality.
* Sema: fix `u1_type` missing from `addType`, making this type have a
slightly more efficient representation in AIR.
* LLVM backend: fix `genTypedValue` for tags `decl_ref` and `variable`
to properly do an LLVMConstBitCast.
* Remove unused parameter from `Value.toEnum`.
After this commit, some test cases are no longer passing. This is due to
the more principled approach to comptime references causing more
anonymous decls to get sent to the linker for codegen. However, in all
these cases the decls are not actually referenced by the runtime machine
code. A future commit in this branch will implement garbage collection
of decls so that unused decls do not get sent to the linker for codegen.
This will make the tests go back to passing.13 files changed, 246 insertions(+), 278 deletions(-)
src/Air.zig-14| ... | @@ -15,7 +15,6 @@ instructions: std.MultiArrayList(Inst).Slice, | ... | @@ -15,7 +15,6 @@ instructions: std.MultiArrayList(Inst).Slice, |
| 15 | /// The first few indexes are reserved. See `ExtraIndex` for the values. | 15 | /// The first few indexes are reserved. See `ExtraIndex` for the values. |
| 16 | extra: []const u32, | 16 | extra: []const u32, |
| 17 | values: []const Value, | 17 | values: []const Value, |
| 18 | variables: []const *Module.Var, | ||
| 19 | 18 | ||
| 20 | pub const ExtraIndex = enum(u32) { | 19 | pub const ExtraIndex = enum(u32) { |
| 21 | /// Payload index of the main `Block` in the `extra` array. | 20 | /// Payload index of the main `Block` in the `extra` array. |
| ... | @@ -193,20 +192,10 @@ pub const Inst = struct { | ... | @@ -193,20 +192,10 @@ pub const Inst = struct { |
| 193 | /// Result type is always `u1`. | 192 | /// Result type is always `u1`. |
| 194 | /// Uses the `un_op` field. | 193 | /// Uses the `un_op` field. |
| 195 | bool_to_int, | 194 | bool_to_int, |
| 196 | /// Stores a value onto the stack and returns a pointer to it. | ||
| 197 | /// TODO audit where this AIR instruction is emitted, maybe it should instead be emitting | ||
| 198 | /// alloca instruction and storing to the alloca. | ||
| 199 | /// Uses the `ty_op` field. | ||
| 200 | ref, | ||
| 201 | /// Return a value from a function. | 195 | /// Return a value from a function. |
| 202 | /// Result type is always noreturn; no instructions in a block follow this one. | 196 | /// Result type is always noreturn; no instructions in a block follow this one. |
| 203 | /// Uses the `un_op` field. | 197 | /// Uses the `un_op` field. |
| 204 | ret, | 198 | ret, |
| 205 | /// Returns a pointer to a global variable. | ||
| 206 | /// Uses the `ty_pl` field. Index is into the `variables` array. | ||
| 207 | /// TODO this can be modeled simply as a constant with a decl ref and then | ||
| 208 | /// the variables array can be removed from Air. | ||
| 209 | varptr, | ||
| 210 | /// Write a value to a pointer. LHS is pointer, RHS is value. | 199 | /// Write a value to a pointer. LHS is pointer, RHS is value. |
| 211 | /// Result type is always void. | 200 | /// Result type is always void. |
| 212 | /// Uses the `bin_op` field. | 201 | /// Uses the `bin_op` field. |
| ... | @@ -454,7 +443,6 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type { | ... | @@ -454,7 +443,6 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type { |
| 454 | .assembly, | 443 | .assembly, |
| 455 | .block, | 444 | .block, |
| 456 | .constant, | 445 | .constant, |
| 457 | .varptr, | ||
| 458 | .struct_field_ptr, | 446 | .struct_field_ptr, |
| 459 | .struct_field_val, | 447 | .struct_field_val, |
| 460 | => return air.getRefType(datas[inst].ty_pl.ty), | 448 | => return air.getRefType(datas[inst].ty_pl.ty), |
| ... | @@ -462,7 +450,6 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type { | ... | @@ -462,7 +450,6 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type { |
| 462 | .not, | 450 | .not, |
| 463 | .bitcast, | 451 | .bitcast, |
| 464 | .load, | 452 | .load, |
| 465 | .ref, | ||
| 466 | .floatcast, | 453 | .floatcast, |
| 467 | .intcast, | 454 | .intcast, |
| 468 | .optional_payload, | 455 | .optional_payload, |
| ... | @@ -550,7 +537,6 @@ pub fn deinit(air: *Air, gpa: *std.mem.Allocator) void { | ... | @@ -550,7 +537,6 @@ pub fn deinit(air: *Air, gpa: *std.mem.Allocator) void { |
| 550 | air.instructions.deinit(gpa); | 537 | air.instructions.deinit(gpa); |
| 551 | gpa.free(air.extra); | 538 | gpa.free(air.extra); |
| 552 | gpa.free(air.values); | 539 | gpa.free(air.values); |
| 553 | gpa.free(air.variables); | ||
| 554 | air.* = undefined; | 540 | air.* = undefined; |
| 555 | } | 541 | } |
| 556 | 542 |
src/Liveness.zig-2| ... | @@ -256,14 +256,12 @@ fn analyzeInst( | ... | @@ -256,14 +256,12 @@ fn analyzeInst( |
| 256 | .const_ty, | 256 | .const_ty, |
| 257 | .breakpoint, | 257 | .breakpoint, |
| 258 | .dbg_stmt, | 258 | .dbg_stmt, |
| 259 | .varptr, | ||
| 260 | .unreach, | 259 | .unreach, |
| 261 | => return trackOperands(a, new_set, inst, main_tomb, .{ .none, .none, .none }), | 260 | => return trackOperands(a, new_set, inst, main_tomb, .{ .none, .none, .none }), |
| 262 | 261 | ||
| 263 | .not, | 262 | .not, |
| 264 | .bitcast, | 263 | .bitcast, |
| 265 | .load, | 264 | .load, |
| 266 | .ref, | ||
| 267 | .floatcast, | 265 | .floatcast, |
| 268 | .intcast, | 266 | .intcast, |
| 269 | .optional_payload, | 267 | .optional_payload, |
src/Module.zig+45-2| ... | @@ -1324,6 +1324,42 @@ pub const Scope = struct { | ... | @@ -1324,6 +1324,42 @@ pub const Scope = struct { |
| 1324 | block.instructions.appendAssumeCapacity(result_index); | 1324 | block.instructions.appendAssumeCapacity(result_index); |
| 1325 | return result_index; | 1325 | return result_index; |
| 1326 | } | 1326 | } |
| 1327 | |||
| 1328 | pub fn startAnonDecl(block: *Block) !WipAnonDecl { | ||
| 1329 | return WipAnonDecl{ | ||
| 1330 | .block = block, | ||
| 1331 | .new_decl_arena = std.heap.ArenaAllocator.init(block.sema.gpa), | ||
| 1332 | .finished = false, | ||
| 1333 | }; | ||
| 1334 | } | ||
| 1335 | |||
| 1336 | pub const WipAnonDecl = struct { | ||
| 1337 | block: *Scope.Block, | ||
| 1338 | new_decl_arena: std.heap.ArenaAllocator, | ||
| 1339 | finished: bool, | ||
| 1340 | |||
| 1341 | pub fn arena(wad: *WipAnonDecl) *Allocator { | ||
| 1342 | return &wad.new_decl_arena.allocator; | ||
| 1343 | } | ||
| 1344 | |||
| 1345 | pub fn deinit(wad: *WipAnonDecl) void { | ||
| 1346 | if (!wad.finished) { | ||
| 1347 | wad.new_decl_arena.deinit(); | ||
| 1348 | } | ||
| 1349 | wad.* = undefined; | ||
| 1350 | } | ||
| 1351 | |||
| 1352 | pub fn finish(wad: *WipAnonDecl, ty: Type, val: Value) !*Decl { | ||
| 1353 | const new_decl = try wad.block.sema.mod.createAnonymousDecl(&wad.block.base, .{ | ||
| 1354 | .ty = ty, | ||
| 1355 | .val = val, | ||
| 1356 | }); | ||
| 1357 | errdefer wad.block.sema.mod.deleteAnonDecl(&wad.block.base, new_decl); | ||
| 1358 | try new_decl.finalizeNewArena(&wad.new_decl_arena); | ||
| 1359 | wad.finished = true; | ||
| 1360 | return new_decl; | ||
| 1361 | } | ||
| 1362 | }; | ||
| 1327 | }; | 1363 | }; |
| 1328 | }; | 1364 | }; |
| 1329 | 1365 | ||
| ... | @@ -1700,6 +1736,7 @@ pub const SrcLoc = struct { | ... | @@ -1700,6 +1736,7 @@ pub const SrcLoc = struct { |
| 1700 | 1736 | ||
| 1701 | .node_offset_fn_type_cc => |node_off| { | 1737 | .node_offset_fn_type_cc => |node_off| { |
| 1702 | const tree = try src_loc.file_scope.getTree(gpa); | 1738 | const tree = try src_loc.file_scope.getTree(gpa); |
| 1739 | const node_datas = tree.nodes.items(.data); | ||
| 1703 | const node_tags = tree.nodes.items(.tag); | 1740 | const node_tags = tree.nodes.items(.tag); |
| 1704 | const node = src_loc.declRelativeToNodeIndex(node_off); | 1741 | const node = src_loc.declRelativeToNodeIndex(node_off); |
| 1705 | var params: [1]ast.Node.Index = undefined; | 1742 | var params: [1]ast.Node.Index = undefined; |
| ... | @@ -1708,6 +1745,13 @@ pub const SrcLoc = struct { | ... | @@ -1708,6 +1745,13 @@ pub const SrcLoc = struct { |
| 1708 | .fn_proto_multi => tree.fnProtoMulti(node), | 1745 | .fn_proto_multi => tree.fnProtoMulti(node), |
| 1709 | .fn_proto_one => tree.fnProtoOne(&params, node), | 1746 | .fn_proto_one => tree.fnProtoOne(&params, node), |
| 1710 | .fn_proto => tree.fnProto(node), | 1747 | .fn_proto => tree.fnProto(node), |
| 1748 | .fn_decl => switch (node_tags[node_datas[node].lhs]) { | ||
| 1749 | .fn_proto_simple => tree.fnProtoSimple(&params, node_datas[node].lhs), | ||
| 1750 | .fn_proto_multi => tree.fnProtoMulti(node_datas[node].lhs), | ||
| 1751 | .fn_proto_one => tree.fnProtoOne(&params, node_datas[node].lhs), | ||
| 1752 | .fn_proto => tree.fnProto(node_datas[node].lhs), | ||
| 1753 | else => unreachable, | ||
| 1754 | }, | ||
| 1711 | else => unreachable, | 1755 | else => unreachable, |
| 1712 | }; | 1756 | }; |
| 1713 | const main_tokens = tree.nodes.items(.main_token); | 1757 | const main_tokens = tree.nodes.items(.main_token); |
| ... | @@ -2935,7 +2979,7 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool { | ... | @@ -2935,7 +2979,7 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool { |
| 2935 | const break_index = try sema.analyzeBody(&block_scope, body); | 2979 | const break_index = try sema.analyzeBody(&block_scope, body); |
| 2936 | const result_ref = zir_datas[break_index].@"break".operand; | 2980 | const result_ref = zir_datas[break_index].@"break".operand; |
| 2937 | const src: LazySrcLoc = .{ .node_offset = 0 }; | 2981 | const src: LazySrcLoc = .{ .node_offset = 0 }; |
| 2938 | const decl_tv = try sema.resolveInstConst(&block_scope, src, result_ref); | 2982 | const decl_tv = try sema.resolveInstValue(&block_scope, src, result_ref); |
| 2939 | const align_val = blk: { | 2983 | const align_val = blk: { |
| 2940 | const align_ref = decl.zirAlignRef(); | 2984 | const align_ref = decl.zirAlignRef(); |
| 2941 | if (align_ref == .none) break :blk Value.initTag(.null_value); | 2985 | if (align_ref == .none) break :blk Value.initTag(.null_value); |
| ... | @@ -3603,7 +3647,6 @@ pub fn analyzeFnBody(mod: *Module, decl: *Decl, func: *Fn) SemaError!Air { | ... | @@ -3603,7 +3647,6 @@ pub fn analyzeFnBody(mod: *Module, decl: *Decl, func: *Fn) SemaError!Air { |
| 3603 | .instructions = sema.air_instructions.toOwnedSlice(), | 3647 | .instructions = sema.air_instructions.toOwnedSlice(), |
| 3604 | .extra = sema.air_extra.toOwnedSlice(gpa), | 3648 | .extra = sema.air_extra.toOwnedSlice(gpa), |
| 3605 | .values = sema.air_values.toOwnedSlice(gpa), | 3649 | .values = sema.air_values.toOwnedSlice(gpa), |
| 3606 | .variables = sema.air_variables.toOwnedSlice(gpa), | ||
| 3607 | }; | 3650 | }; |
| 3608 | } | 3651 | } |
| 3609 | 3652 |
src/Sema.zig+130-61| ... | @@ -14,7 +14,6 @@ code: Zir, | ... | @@ -14,7 +14,6 @@ code: Zir, |
| 14 | air_instructions: std.MultiArrayList(Air.Inst) = .{}, | 14 | air_instructions: std.MultiArrayList(Air.Inst) = .{}, |
| 15 | air_extra: std.ArrayListUnmanaged(u32) = .{}, | 15 | air_extra: std.ArrayListUnmanaged(u32) = .{}, |
| 16 | air_values: std.ArrayListUnmanaged(Value) = .{}, | 16 | air_values: std.ArrayListUnmanaged(Value) = .{}, |
| 17 | air_variables: std.ArrayListUnmanaged(*Module.Var) = .{}, | ||
| 18 | /// Maps ZIR to AIR. | 17 | /// Maps ZIR to AIR. |
| 19 | inst_map: InstMap = .{}, | 18 | inst_map: InstMap = .{}, |
| 20 | /// When analyzing an inline function call, owner_decl is the Decl of the caller | 19 | /// When analyzing an inline function call, owner_decl is the Decl of the caller |
| ... | @@ -76,7 +75,6 @@ pub fn deinit(sema: *Sema) void { | ... | @@ -76,7 +75,6 @@ pub fn deinit(sema: *Sema) void { |
| 76 | sema.air_instructions.deinit(gpa); | 75 | sema.air_instructions.deinit(gpa); |
| 77 | sema.air_extra.deinit(gpa); | 76 | sema.air_extra.deinit(gpa); |
| 78 | sema.air_values.deinit(gpa); | 77 | sema.air_values.deinit(gpa); |
| 79 | sema.air_variables.deinit(gpa); | ||
| 80 | sema.inst_map.deinit(gpa); | 78 | sema.inst_map.deinit(gpa); |
| 81 | sema.decl_val_table.deinit(gpa); | 79 | sema.decl_val_table.deinit(gpa); |
| 82 | sema.* = undefined; | 80 | sema.* = undefined; |
| ... | @@ -639,16 +637,40 @@ fn analyzeAsType( | ... | @@ -639,16 +637,40 @@ fn analyzeAsType( |
| 639 | return val.toType(sema.arena); | 637 | return val.toType(sema.arena); |
| 640 | } | 638 | } |
| 641 | 639 | ||
| 640 | /// May return Value Tags: `variable`, `undef`. | ||
| 641 | /// See `resolveConstValue` for an alternative. | ||
| 642 | fn resolveValue( | ||
| 643 | sema: *Sema, | ||
| 644 | block: *Scope.Block, | ||
| 645 | src: LazySrcLoc, | ||
| 646 | air_ref: Air.Inst.Ref, | ||
| 647 | ) CompileError!Value { | ||
| 648 | if (try sema.resolveMaybeUndefValAllowVariables(block, src, air_ref)) |val| { | ||
| 649 | return val; | ||
| 650 | } | ||
| 651 | return sema.failWithNeededComptime(block, src); | ||
| 652 | } | ||
| 653 | |||
| 654 | /// Will not return Value Tags: `variable`, `undef`. Instead they will emit compile errors. | ||
| 655 | /// See `resolveValue` for an alternative. | ||
| 642 | fn resolveConstValue( | 656 | fn resolveConstValue( |
| 643 | sema: *Sema, | 657 | sema: *Sema, |
| 644 | block: *Scope.Block, | 658 | block: *Scope.Block, |
| 645 | src: LazySrcLoc, | 659 | src: LazySrcLoc, |
| 646 | air_ref: Air.Inst.Ref, | 660 | air_ref: Air.Inst.Ref, |
| 647 | ) CompileError!Value { | 661 | ) CompileError!Value { |
| 648 | return (try sema.resolveDefinedValue(block, src, air_ref)) orelse | 662 | if (try sema.resolveMaybeUndefValAllowVariables(block, src, air_ref)) |val| { |
| 649 | return sema.failWithNeededComptime(block, src); | 663 | switch (val.tag()) { |
| 664 | .undef => return sema.failWithUseOfUndef(block, src), | ||
| 665 | .variable => return sema.failWithNeededComptime(block, src), | ||
| 666 | else => return val, | ||
| 667 | } | ||
| 668 | } | ||
| 669 | return sema.failWithNeededComptime(block, src); | ||
| 650 | } | 670 | } |
| 651 | 671 | ||
| 672 | /// Value Tag `variable` causes this function to return `null`. | ||
| 673 | /// Value Tag `undef` causes this function to return a compile error. | ||
| 652 | fn resolveDefinedValue( | 674 | fn resolveDefinedValue( |
| 653 | sema: *Sema, | 675 | sema: *Sema, |
| 654 | block: *Scope.Block, | 676 | block: *Scope.Block, |
| ... | @@ -664,11 +686,27 @@ fn resolveDefinedValue( | ... | @@ -664,11 +686,27 @@ fn resolveDefinedValue( |
| 664 | return null; | 686 | return null; |
| 665 | } | 687 | } |
| 666 | 688 | ||
| 689 | /// Value Tag `variable` causes this function to return `null`. | ||
| 690 | /// Value Tag `undef` causes this function to return the Value. | ||
| 667 | fn resolveMaybeUndefVal( | 691 | fn resolveMaybeUndefVal( |
| 668 | sema: *Sema, | 692 | sema: *Sema, |
| 669 | block: *Scope.Block, | 693 | block: *Scope.Block, |
| 670 | src: LazySrcLoc, | 694 | src: LazySrcLoc, |
| 671 | inst: Air.Inst.Ref, | 695 | inst: Air.Inst.Ref, |
| 696 | ) CompileError!?Value { | ||
| 697 | const val = (try sema.resolveMaybeUndefValAllowVariables(block, src, inst)) orelse return null; | ||
| 698 | if (val.tag() == .variable) { | ||
| 699 | return sema.failWithNeededComptime(block, src); | ||
| 700 | } | ||
| 701 | return val; | ||
| 702 | } | ||
| 703 | |||
| 704 | /// Returns all Value tags including `variable` and `undef`. | ||
| 705 | fn resolveMaybeUndefValAllowVariables( | ||
| 706 | sema: *Sema, | ||
| 707 | block: *Scope.Block, | ||
| 708 | src: LazySrcLoc, | ||
| 709 | inst: Air.Inst.Ref, | ||
| 672 | ) CompileError!?Value { | 710 | ) CompileError!?Value { |
| 673 | // First section of indexes correspond to a set number of constant values. | 711 | // First section of indexes correspond to a set number of constant values. |
| 674 | var i: usize = @enumToInt(inst); | 712 | var i: usize = @enumToInt(inst); |
| ... | @@ -734,6 +772,8 @@ fn resolveInt( | ... | @@ -734,6 +772,8 @@ fn resolveInt( |
| 734 | return val.toUnsignedInt(); | 772 | return val.toUnsignedInt(); |
| 735 | } | 773 | } |
| 736 | 774 | ||
| 775 | // Returns a compile error if the value has tag `variable`. See `resolveInstValue` for | ||
| 776 | // a function that does not. | ||
| 737 | pub fn resolveInstConst( | 777 | pub fn resolveInstConst( |
| 738 | sema: *Sema, | 778 | sema: *Sema, |
| 739 | block: *Scope.Block, | 779 | block: *Scope.Block, |
| ... | @@ -748,6 +788,22 @@ pub fn resolveInstConst( | ... | @@ -748,6 +788,22 @@ pub fn resolveInstConst( |
| 748 | }; | 788 | }; |
| 749 | } | 789 | } |
| 750 | 790 | ||
| 791 | // Value Tag may be `undef` or `variable`. | ||
| 792 | // See `resolveInstConst` for an alternative. | ||
| 793 | pub fn resolveInstValue( | ||
| 794 | sema: *Sema, | ||
| 795 | block: *Scope.Block, | ||
| 796 | src: LazySrcLoc, | ||
| 797 | zir_ref: Zir.Inst.Ref, | ||
| 798 | ) CompileError!TypedValue { | ||
| 799 | const air_ref = sema.resolveInst(zir_ref); | ||
| 800 | const val = try sema.resolveValue(block, src, air_ref); | ||
| 801 | return TypedValue{ | ||
| 802 | .ty = sema.typeOf(air_ref), | ||
| 803 | .val = val, | ||
| 804 | }; | ||
| 805 | } | ||
| 806 | |||
| 751 | fn zirBitcastResultPtr(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | 807 | fn zirBitcastResultPtr(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 752 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | 808 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 753 | const src = inst_data.src(); | 809 | const src = inst_data.src(); |
| ... | @@ -1707,7 +1763,7 @@ fn zirStr(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!A | ... | @@ -1707,7 +1763,7 @@ fn zirStr(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!A |
| 1707 | }); | 1763 | }); |
| 1708 | errdefer sema.mod.deleteAnonDecl(&block.base, new_decl); | 1764 | errdefer sema.mod.deleteAnonDecl(&block.base, new_decl); |
| 1709 | try new_decl.finalizeNewArena(&new_decl_arena); | 1765 | try new_decl.finalizeNewArena(&new_decl_arena); |
| 1710 | return sema.analyzeDeclRef(block, .unneeded, new_decl); | 1766 | return sema.analyzeDeclRef(new_decl); |
| 1711 | } | 1767 | } |
| 1712 | 1768 | ||
| 1713 | fn zirInt(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | 1769 | fn zirInt(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| ... | @@ -2090,10 +2146,7 @@ fn zirExport(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileErro | ... | @@ -2090,10 +2146,7 @@ fn zirExport(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileErro |
| 2090 | const linkage_index = struct_obj.fields.getIndex("linkage").?; | 2146 | const linkage_index = struct_obj.fields.getIndex("linkage").?; |
| 2091 | const section_index = struct_obj.fields.getIndex("section").?; | 2147 | const section_index = struct_obj.fields.getIndex("section").?; |
| 2092 | const export_name = try fields[name_index].toAllocatedBytes(sema.arena); | 2148 | const export_name = try fields[name_index].toAllocatedBytes(sema.arena); |
| 2093 | const linkage = fields[linkage_index].toEnum( | 2149 | const linkage = fields[linkage_index].toEnum(std.builtin.GlobalLinkage); |
| 2094 | struct_obj.fields.values()[linkage_index].ty, | ||
| 2095 | std.builtin.GlobalLinkage, | ||
| 2096 | ); | ||
| 2097 | 2150 | ||
| 2098 | if (linkage != .Strong) { | 2151 | if (linkage != .Strong) { |
| 2099 | return sema.mod.fail(&block.base, src, "TODO: implement exporting with non-strong linkage", .{}); | 2152 | return sema.mod.fail(&block.base, src, "TODO: implement exporting with non-strong linkage", .{}); |
| ... | @@ -2194,7 +2247,7 @@ fn zirDeclRef(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileErr | ... | @@ -2194,7 +2247,7 @@ fn zirDeclRef(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileErr |
| 2194 | const src = inst_data.src(); | 2247 | const src = inst_data.src(); |
| 2195 | const decl_name = inst_data.get(sema.code); | 2248 | const decl_name = inst_data.get(sema.code); |
| 2196 | const decl = try sema.lookupIdentifier(block, src, decl_name); | 2249 | const decl = try sema.lookupIdentifier(block, src, decl_name); |
| 2197 | return sema.analyzeDeclRef(block, src, decl); | 2250 | return sema.analyzeDeclRef(decl); |
| 2198 | } | 2251 | } |
| 2199 | 2252 | ||
| 2200 | fn zirDeclVal(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | 2253 | fn zirDeclVal(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| ... | @@ -2978,14 +3031,9 @@ fn zirErrUnionPayloadPtr( | ... | @@ -2978,14 +3031,9 @@ fn zirErrUnionPayloadPtr( |
| 2978 | if (val.getError()) |name| { | 3031 | if (val.getError()) |name| { |
| 2979 | return sema.mod.fail(&block.base, src, "caught unexpected error '{s}'", .{name}); | 3032 | return sema.mod.fail(&block.base, src, "caught unexpected error '{s}'", .{name}); |
| 2980 | } | 3033 | } |
| 2981 | const data = val.castTag(.error_union).?.data; | ||
| 2982 | // The same Value represents the pointer to the error union and the payload. | ||
| 2983 | return sema.addConstant( | 3034 | return sema.addConstant( |
| 2984 | operand_pointer_ty, | 3035 | operand_pointer_ty, |
| 2985 | try Value.Tag.ref_val.create( | 3036 | try Value.Tag.eu_payload_ptr.create(sema.arena, pointer_val), |
| 2986 | sema.arena, | ||
| 2987 | data, | ||
| 2988 | ), | ||
| 2989 | ); | 3037 | ); |
| 2990 | } | 3038 | } |
| 2991 | 3039 | ||
| ... | @@ -6296,7 +6344,7 @@ fn zirFuncExtended( | ... | @@ -6296,7 +6344,7 @@ fn zirFuncExtended( |
| 6296 | const cc_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); | 6344 | const cc_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); |
| 6297 | extra_index += 1; | 6345 | extra_index += 1; |
| 6298 | const cc_tv = try sema.resolveInstConst(block, cc_src, cc_ref); | 6346 | const cc_tv = try sema.resolveInstConst(block, cc_src, cc_ref); |
| 6299 | break :blk cc_tv.val.toEnum(cc_tv.ty, std.builtin.CallingConvention); | 6347 | break :blk cc_tv.val.toEnum(std.builtin.CallingConvention); |
| 6300 | } else .Unspecified; | 6348 | } else .Unspecified; |
| 6301 | 6349 | ||
| 6302 | const align_val: Value = if (small.has_align) blk: { | 6350 | const align_val: Value = if (small.has_align) blk: { |
| ... | @@ -6554,7 +6602,7 @@ fn safetyPanic( | ... | @@ -6554,7 +6602,7 @@ fn safetyPanic( |
| 6554 | }); | 6602 | }); |
| 6555 | errdefer sema.mod.deleteAnonDecl(&block.base, new_decl); | 6603 | errdefer sema.mod.deleteAnonDecl(&block.base, new_decl); |
| 6556 | try new_decl.finalizeNewArena(&new_decl_arena); | 6604 | try new_decl.finalizeNewArena(&new_decl_arena); |
| 6557 | break :msg_inst try sema.analyzeDeclRef(block, .unneeded, new_decl); | 6605 | break :msg_inst try sema.analyzeDeclRef(new_decl); |
| 6558 | }; | 6606 | }; |
| 6559 | 6607 | ||
| 6560 | const casted_msg_inst = try sema.coerce(block, Type.initTag(.const_slice_u8), msg_inst, src); | 6608 | const casted_msg_inst = try sema.coerce(block, Type.initTag(.const_slice_u8), msg_inst, src); |
| ... | @@ -6761,11 +6809,16 @@ fn fieldPtr( | ... | @@ -6761,11 +6809,16 @@ fn fieldPtr( |
| 6761 | switch (object_ty.zigTypeTag()) { | 6809 | switch (object_ty.zigTypeTag()) { |
| 6762 | .Array => { | 6810 | .Array => { |
| 6763 | if (mem.eql(u8, field_name, "len")) { | 6811 | if (mem.eql(u8, field_name, "len")) { |
| 6812 | var anon_decl = try block.startAnonDecl(); | ||
| 6813 | defer anon_decl.deinit(); | ||
| 6764 | return sema.addConstant( | 6814 | return sema.addConstant( |
| 6765 | Type.initTag(.single_const_pointer_to_comptime_int), | 6815 | Type.initTag(.single_const_pointer_to_comptime_int), |
| 6766 | try Value.Tag.ref_val.create( | 6816 | try Value.Tag.decl_ref.create( |
| 6767 | arena, | 6817 | arena, |
| 6768 | try Value.Tag.int_u64.create(arena, object_ty.arrayLen()), | 6818 | try anon_decl.finish( |
| 6819 | Type.initTag(.comptime_int), | ||
| 6820 | try Value.Tag.int_u64.create(anon_decl.arena(), object_ty.arrayLen()), | ||
| 6821 | ), | ||
| 6769 | ), | 6822 | ), |
| 6770 | ); | 6823 | ); |
| 6771 | } else { | 6824 | } else { |
| ... | @@ -6780,18 +6833,25 @@ fn fieldPtr( | ... | @@ -6780,18 +6833,25 @@ fn fieldPtr( |
| 6780 | .Pointer => { | 6833 | .Pointer => { |
| 6781 | const ptr_child = object_ty.elemType(); | 6834 | const ptr_child = object_ty.elemType(); |
| 6782 | if (ptr_child.isSlice()) { | 6835 | if (ptr_child.isSlice()) { |
| 6836 | // Here for the ptr and len fields what we need to do is the situation | ||
| 6837 | // when a temporary has its address taken, e.g. `&a[c..d].len`. | ||
| 6838 | // This value may be known at compile-time or runtime. In the former | ||
| 6839 | // case, it should create an anonymous Decl and return a decl_ref to it. | ||
| 6840 | // In the latter case, it should add an `alloc` instruction, store | ||
| 6841 | // the runtime value to it, and then return the `alloc`. | ||
| 6842 | // In both cases the pointer should be const. | ||
| 6783 | if (mem.eql(u8, field_name, "ptr")) { | 6843 | if (mem.eql(u8, field_name, "ptr")) { |
| 6784 | return mod.fail( | 6844 | return mod.fail( |
| 6785 | &block.base, | 6845 | &block.base, |
| 6786 | field_name_src, | 6846 | field_name_src, |
| 6787 | "cannot obtain reference to pointer field of slice '{}'", | 6847 | "TODO: implement reference to 'ptr' field of slice '{}'", |
| 6788 | .{object_ty}, | 6848 | .{object_ty}, |
| 6789 | ); | 6849 | ); |
| 6790 | } else if (mem.eql(u8, field_name, "len")) { | 6850 | } else if (mem.eql(u8, field_name, "len")) { |
| 6791 | return mod.fail( | 6851 | return mod.fail( |
| 6792 | &block.base, | 6852 | &block.base, |
| 6793 | field_name_src, | 6853 | field_name_src, |
| 6794 | "cannot obtain reference to length field of slice '{}'", | 6854 | "TODO: implement reference to 'len' field of slice '{}'", |
| 6795 | .{object_ty}, | 6855 | .{object_ty}, |
| 6796 | ); | 6856 | ); |
| 6797 | } else { | 6857 | } else { |
| ... | @@ -6805,11 +6865,16 @@ fn fieldPtr( | ... | @@ -6805,11 +6865,16 @@ fn fieldPtr( |
| 6805 | } else switch (ptr_child.zigTypeTag()) { | 6865 | } else switch (ptr_child.zigTypeTag()) { |
| 6806 | .Array => { | 6866 | .Array => { |
| 6807 | if (mem.eql(u8, field_name, "len")) { | 6867 | if (mem.eql(u8, field_name, "len")) { |
| 6868 | var anon_decl = try block.startAnonDecl(); | ||
| 6869 | defer anon_decl.deinit(); | ||
| 6808 | return sema.addConstant( | 6870 | return sema.addConstant( |
| 6809 | Type.initTag(.single_const_pointer_to_comptime_int), | 6871 | Type.initTag(.single_const_pointer_to_comptime_int), |
| 6810 | try Value.Tag.ref_val.create( | 6872 | try Value.Tag.decl_ref.create( |
| 6811 | arena, | 6873 | arena, |
| 6812 | try Value.Tag.int_u64.create(arena, ptr_child.arrayLen()), | 6874 | try anon_decl.finish( |
| 6875 | Type.initTag(.comptime_int), | ||
| 6876 | try Value.Tag.int_u64.create(anon_decl.arena(), ptr_child.arrayLen()), | ||
| 6877 | ), | ||
| 6813 | ), | 6878 | ), |
| 6814 | ); | 6879 | ); |
| 6815 | } else { | 6880 | } else { |
| ... | @@ -6848,13 +6913,16 @@ fn fieldPtr( | ... | @@ -6848,13 +6913,16 @@ fn fieldPtr( |
| 6848 | }); | 6913 | }); |
| 6849 | } else (try mod.getErrorValue(field_name)).key; | 6914 | } else (try mod.getErrorValue(field_name)).key; |
| 6850 | 6915 | ||
| 6916 | var anon_decl = try block.startAnonDecl(); | ||
| 6917 | defer anon_decl.deinit(); | ||
| 6851 | return sema.addConstant( | 6918 | return sema.addConstant( |
| 6852 | try Module.simplePtrType(arena, child_type, false, .One), | 6919 | try Module.simplePtrType(arena, child_type, false, .One), |
| 6853 | try Value.Tag.ref_val.create( | 6920 | try Value.Tag.decl_ref.create( |
| 6854 | arena, | 6921 | arena, |
| 6855 | try Value.Tag.@"error".create(arena, .{ | 6922 | try anon_decl.finish( |
| 6856 | .name = name, | 6923 | child_type, |
| 6857 | }), | 6924 | try Value.Tag.@"error".create(anon_decl.arena(), .{ .name = name }), |
| 6925 | ), | ||
| 6858 | ), | 6926 | ), |
| 6859 | ); | 6927 | ); |
| 6860 | }, | 6928 | }, |
| ... | @@ -6901,10 +6969,17 @@ fn fieldPtr( | ... | @@ -6901,10 +6969,17 @@ fn fieldPtr( |
| 6901 | return mod.failWithOwnedErrorMsg(&block.base, msg); | 6969 | return mod.failWithOwnedErrorMsg(&block.base, msg); |
| 6902 | }; | 6970 | }; |
| 6903 | const field_index_u32 = @intCast(u32, field_index); | 6971 | const field_index_u32 = @intCast(u32, field_index); |
| 6904 | const enum_val = try Value.Tag.enum_field_index.create(arena, field_index_u32); | 6972 | var anon_decl = try block.startAnonDecl(); |
| 6973 | defer anon_decl.deinit(); | ||
| 6905 | return sema.addConstant( | 6974 | return sema.addConstant( |
| 6906 | try Module.simplePtrType(arena, child_type, false, .One), | 6975 | try Module.simplePtrType(arena, child_type, false, .One), |
| 6907 | try Value.Tag.ref_val.create(arena, enum_val), | 6976 | try Value.Tag.decl_ref.create( |
| 6977 | arena, | ||
| 6978 | try anon_decl.finish( | ||
| 6979 | child_type, | ||
| 6980 | try Value.Tag.enum_field_index.create(anon_decl.arena(), field_index_u32), | ||
| 6981 | ), | ||
| 6982 | ), | ||
| 6908 | ); | 6983 | ); |
| 6909 | }, | 6984 | }, |
| 6910 | else => return mod.fail(&block.base, src, "type '{}' has no members", .{child_type}), | 6985 | else => return mod.fail(&block.base, src, "type '{}' has no members", .{child_type}), |
| ... | @@ -6951,7 +7026,7 @@ fn namespaceLookupRef( | ... | @@ -6951,7 +7026,7 @@ fn namespaceLookupRef( |
| 6951 | decl_name: []const u8, | 7026 | decl_name: []const u8, |
| 6952 | ) CompileError!?Air.Inst.Ref { | 7027 | ) CompileError!?Air.Inst.Ref { |
| 6953 | const decl = (try sema.namespaceLookup(block, src, namespace, decl_name)) orelse return null; | 7028 | const decl = (try sema.namespaceLookup(block, src, namespace, decl_name)) orelse return null; |
| 6954 | return try sema.analyzeDeclRef(block, src, decl); | 7029 | return try sema.analyzeDeclRef(decl); |
| 6955 | } | 7030 | } |
| 6956 | 7031 | ||
| 6957 | fn structFieldPtr( | 7032 | fn structFieldPtr( |
| ... | @@ -7207,13 +7282,15 @@ fn elemPtrArray( | ... | @@ -7207,13 +7282,15 @@ fn elemPtrArray( |
| 7207 | fn coerce( | 7282 | fn coerce( |
| 7208 | sema: *Sema, | 7283 | sema: *Sema, |
| 7209 | block: *Scope.Block, | 7284 | block: *Scope.Block, |
| 7210 | dest_type: Type, | 7285 | dest_type_unresolved: Type, |
| 7211 | inst: Air.Inst.Ref, | 7286 | inst: Air.Inst.Ref, |
| 7212 | inst_src: LazySrcLoc, | 7287 | inst_src: LazySrcLoc, |
| 7213 | ) CompileError!Air.Inst.Ref { | 7288 | ) CompileError!Air.Inst.Ref { |
| 7214 | if (dest_type.tag() == .var_args_param) { | 7289 | if (dest_type_unresolved.tag() == .var_args_param) { |
| 7215 | return sema.coerceVarArgParam(block, inst, inst_src); | 7290 | return sema.coerceVarArgParam(block, inst, inst_src); |
| 7216 | } | 7291 | } |
| 7292 | const dest_type_src = inst_src; // TODO better source location | ||
| 7293 | const dest_type = try sema.resolveTypeFields(block, dest_type_src, dest_type_unresolved); | ||
| 7217 | 7294 | ||
| 7218 | const inst_ty = sema.typeOf(inst); | 7295 | const inst_ty = sema.typeOf(inst); |
| 7219 | // If the types are the same, we can return the operand. | 7296 | // If the types are the same, we can return the operand. |
| ... | @@ -7554,17 +7631,17 @@ fn analyzeDeclVal( | ... | @@ -7554,17 +7631,17 @@ fn analyzeDeclVal( |
| 7554 | if (sema.decl_val_table.get(decl)) |result| { | 7631 | if (sema.decl_val_table.get(decl)) |result| { |
| 7555 | return result; | 7632 | return result; |
| 7556 | } | 7633 | } |
| 7557 | const decl_ref = try sema.analyzeDeclRef(block, src, decl); | 7634 | const decl_ref = try sema.analyzeDeclRef(decl); |
| 7558 | const result = try sema.analyzeLoad(block, src, decl_ref, src); | 7635 | const result = try sema.analyzeLoad(block, src, decl_ref, src); |
| 7559 | if (Air.refToIndex(result)) |index| { | 7636 | if (Air.refToIndex(result)) |index| { |
| 7560 | if (sema.air_instructions.items(.tag)[index] == .constant) { | 7637 | if (sema.air_instructions.items(.tag)[index] == .constant) { |
| 7561 | sema.decl_val_table.put(sema.gpa, decl, result) catch {}; | 7638 | try sema.decl_val_table.put(sema.gpa, decl, result); |
| 7562 | } | 7639 | } |
| 7563 | } | 7640 | } |
| 7564 | return result; | 7641 | return result; |
| 7565 | } | 7642 | } |
| 7566 | 7643 | ||
| 7567 | fn analyzeDeclRef(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, decl: *Decl) CompileError!Air.Inst.Ref { | 7644 | fn analyzeDeclRef(sema: *Sema, decl: *Decl) CompileError!Air.Inst.Ref { |
| 7568 | try sema.mod.declareDeclDependency(sema.owner_decl, decl); | 7645 | try sema.mod.declareDeclDependency(sema.owner_decl, decl); |
| 7569 | sema.mod.ensureDeclAnalyzed(decl) catch |err| { | 7646 | sema.mod.ensureDeclAnalyzed(decl) catch |err| { |
| 7570 | if (sema.func) |func| { | 7647 | if (sema.func) |func| { |
| ... | @@ -7576,8 +7653,10 @@ fn analyzeDeclRef(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, decl: *Decl | ... | @@ -7576,8 +7653,10 @@ fn analyzeDeclRef(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, decl: *Decl |
| 7576 | }; | 7653 | }; |
| 7577 | 7654 | ||
| 7578 | const decl_tv = try decl.typedValue(); | 7655 | const decl_tv = try decl.typedValue(); |
| 7579 | if (decl_tv.val.tag() == .variable) { | 7656 | if (decl_tv.val.castTag(.variable)) |payload| { |
| 7580 | return sema.analyzeVarRef(block, src, decl_tv); | 7657 | const variable = payload.data; |
| 7658 | const ty = try Module.simplePtrType(sema.arena, decl_tv.ty, variable.is_mutable, .One); | ||
| 7659 | return sema.addConstant(ty, try Value.Tag.decl_ref.create(sema.arena, decl)); | ||
| 7581 | } | 7660 | } |
| 7582 | return sema.addConstant( | 7661 | return sema.addConstant( |
| 7583 | try Module.simplePtrType(sema.arena, decl_tv.ty, false, .One), | 7662 | try Module.simplePtrType(sema.arena, decl_tv.ty, false, .One), |
| ... | @@ -7585,26 +7664,6 @@ fn analyzeDeclRef(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, decl: *Decl | ... | @@ -7585,26 +7664,6 @@ fn analyzeDeclRef(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, decl: *Decl |
| 7585 | ); | 7664 | ); |
| 7586 | } | 7665 | } |
| 7587 | 7666 | ||
| 7588 | fn analyzeVarRef(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, tv: TypedValue) CompileError!Air.Inst.Ref { | ||
| 7589 | const variable = tv.val.castTag(.variable).?.data; | ||
| 7590 | |||
| 7591 | const ty = try Module.simplePtrType(sema.arena, tv.ty, variable.is_mutable, .One); | ||
| 7592 | if (!variable.is_mutable and !variable.is_extern) { | ||
| 7593 | return sema.addConstant(ty, try Value.Tag.ref_val.create(sema.arena, variable.init)); | ||
| 7594 | } | ||
| 7595 | |||
| 7596 | const gpa = sema.gpa; | ||
| 7597 | try sema.requireRuntimeBlock(block, src); | ||
| 7598 | try sema.air_variables.append(gpa, variable); | ||
| 7599 | return block.addInst(.{ | ||
| 7600 | .tag = .varptr, | ||
| 7601 | .data = .{ .ty_pl = .{ | ||
| 7602 | .ty = try sema.addType(ty), | ||
| 7603 | .payload = @intCast(u32, sema.air_variables.items.len - 1), | ||
| 7604 | } }, | ||
| 7605 | }); | ||
| 7606 | } | ||
| 7607 | |||
| 7608 | fn analyzeRef( | 7667 | fn analyzeRef( |
| 7609 | sema: *Sema, | 7668 | sema: *Sema, |
| 7610 | block: *Scope.Block, | 7669 | block: *Scope.Block, |
| ... | @@ -7615,11 +7674,21 @@ fn analyzeRef( | ... | @@ -7615,11 +7674,21 @@ fn analyzeRef( |
| 7615 | const ptr_type = try Module.simplePtrType(sema.arena, operand_ty, false, .One); | 7674 | const ptr_type = try Module.simplePtrType(sema.arena, operand_ty, false, .One); |
| 7616 | 7675 | ||
| 7617 | if (try sema.resolveMaybeUndefVal(block, src, operand)) |val| { | 7676 | if (try sema.resolveMaybeUndefVal(block, src, operand)) |val| { |
| 7618 | return sema.addConstant(ptr_type, try Value.Tag.ref_val.create(sema.arena, val)); | 7677 | var anon_decl = try block.startAnonDecl(); |
| 7678 | defer anon_decl.deinit(); | ||
| 7679 | return sema.addConstant( | ||
| 7680 | ptr_type, | ||
| 7681 | try Value.Tag.decl_ref.create( | ||
| 7682 | sema.arena, | ||
| 7683 | try anon_decl.finish(operand_ty, try val.copy(anon_decl.arena())), | ||
| 7684 | ), | ||
| 7685 | ); | ||
| 7619 | } | 7686 | } |
| 7620 | 7687 | ||
| 7621 | try sema.requireRuntimeBlock(block, src); | 7688 | try sema.requireRuntimeBlock(block, src); |
| 7622 | return block.addTyOp(.ref, ptr_type, operand); | 7689 | const alloc = try block.addTy(.alloc, ptr_type); |
| 7690 | try sema.storePtr(block, src, alloc, operand); | ||
| 7691 | return alloc; | ||
| 7623 | } | 7692 | } |
| 7624 | 7693 | ||
| 7625 | fn analyzeLoad( | 7694 | fn analyzeLoad( |
| ... | @@ -8447,12 +8516,12 @@ fn getTmpAir(sema: Sema) Air { | ... | @@ -8447,12 +8516,12 @@ fn getTmpAir(sema: Sema) Air { |
| 8447 | .instructions = sema.air_instructions.slice(), | 8516 | .instructions = sema.air_instructions.slice(), |
| 8448 | .extra = sema.air_extra.items, | 8517 | .extra = sema.air_extra.items, |
| 8449 | .values = sema.air_values.items, | 8518 | .values = sema.air_values.items, |
| 8450 | .variables = sema.air_variables.items, | ||
| 8451 | }; | 8519 | }; |
| 8452 | } | 8520 | } |
| 8453 | 8521 | ||
| 8454 | pub fn addType(sema: *Sema, ty: Type) !Air.Inst.Ref { | 8522 | pub fn addType(sema: *Sema, ty: Type) !Air.Inst.Ref { |
| 8455 | switch (ty.tag()) { | 8523 | switch (ty.tag()) { |
| 8524 | .u1 => return .u1_type, | ||
| 8456 | .u8 => return .u8_type, | 8525 | .u8 => return .u8_type, |
| 8457 | .i8 => return .i8_type, | 8526 | .i8 => return .i8_type, |
| 8458 | .u16 => return .u16_type, | 8527 | .u16 => return .u16_type, |
src/codegen.zig-41| ... | @@ -848,13 +848,11 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -848,13 +848,11 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 848 | .loop => try self.airLoop(inst), | 848 | .loop => try self.airLoop(inst), |
| 849 | .not => try self.airNot(inst), | 849 | .not => try self.airNot(inst), |
| 850 | .ptrtoint => try self.airPtrToInt(inst), | 850 | .ptrtoint => try self.airPtrToInt(inst), |
| 851 | .ref => try self.airRef(inst), | ||
| 852 | .ret => try self.airRet(inst), | 851 | .ret => try self.airRet(inst), |
| 853 | .store => try self.airStore(inst), | 852 | .store => try self.airStore(inst), |
| 854 | .struct_field_ptr=> try self.airStructFieldPtr(inst), | 853 | .struct_field_ptr=> try self.airStructFieldPtr(inst), |
| 855 | .struct_field_val=> try self.airStructFieldVal(inst), | 854 | .struct_field_val=> try self.airStructFieldVal(inst), |
| 856 | .switch_br => try self.airSwitch(inst), | 855 | .switch_br => try self.airSwitch(inst), |
| 857 | .varptr => try self.airVarPtr(inst), | ||
| 858 | .slice_ptr => try self.airSlicePtr(inst), | 856 | .slice_ptr => try self.airSlicePtr(inst), |
| 859 | .slice_len => try self.airSliceLen(inst), | 857 | .slice_len => try self.airSliceLen(inst), |
| 860 | 858 | ||
| ... | @@ -1340,13 +1338,6 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -1340,13 +1338,6 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 1340 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); | 1338 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 1341 | } | 1339 | } |
| 1342 | 1340 | ||
| 1343 | fn airVarPtr(self: *Self, inst: Air.Inst.Index) !void { | ||
| 1344 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else switch (arch) { | ||
| 1345 | else => return self.fail("TODO implement varptr for {}", .{self.target.cpu.arch}), | ||
| 1346 | }; | ||
| 1347 | return self.finishAir(inst, result, .{ .none, .none, .none }); | ||
| 1348 | } | ||
| 1349 | |||
| 1350 | fn airSlicePtr(self: *Self, inst: Air.Inst.Index) !void { | 1341 | fn airSlicePtr(self: *Self, inst: Air.Inst.Index) !void { |
| 1351 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 1342 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 1352 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else switch (arch) { | 1343 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else switch (arch) { |
| ... | @@ -2833,38 +2824,6 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -2833,38 +2824,6 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 2833 | return bt.finishAir(result); | 2824 | return bt.finishAir(result); |
| 2834 | } | 2825 | } |
| 2835 | 2826 | ||
| 2836 | fn airRef(self: *Self, inst: Air.Inst.Index) !void { | ||
| 2837 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | ||
| 2838 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { | ||
| 2839 | const operand_ty = self.air.typeOf(ty_op.operand); | ||
| 2840 | const operand = try self.resolveInst(ty_op.operand); | ||
| 2841 | switch (operand) { | ||
| 2842 | .unreach => unreachable, | ||
| 2843 | .dead => unreachable, | ||
| 2844 | .none => break :result MCValue{ .none = {} }, | ||
| 2845 | |||
| 2846 | .immediate, | ||
| 2847 | .register, | ||
| 2848 | .ptr_stack_offset, | ||
| 2849 | .ptr_embedded_in_code, | ||
| 2850 | .compare_flags_unsigned, | ||
| 2851 | .compare_flags_signed, | ||
| 2852 | => { | ||
| 2853 | const stack_offset = try self.allocMemPtr(inst); | ||
| 2854 | try self.genSetStack(operand_ty, stack_offset, operand); | ||
| 2855 | break :result MCValue{ .ptr_stack_offset = stack_offset }; | ||
| 2856 | }, | ||
| 2857 | |||
| 2858 | .stack_offset => |offset| break :result MCValue{ .ptr_stack_offset = offset }, | ||
| 2859 | .embedded_in_code => |offset| break :result MCValue{ .ptr_embedded_in_code = offset }, | ||
| 2860 | .memory => |vaddr| break :result MCValue{ .immediate = vaddr }, | ||
| 2861 | |||
| 2862 | .undef => return self.fail("TODO implement ref on an undefined value", .{}), | ||
| 2863 | } | ||
| 2864 | }; | ||
| 2865 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); | ||
| 2866 | } | ||
| 2867 | |||
| 2868 | fn ret(self: *Self, mcv: MCValue) !void { | 2827 | fn ret(self: *Self, mcv: MCValue) !void { |
| 2869 | const ret_ty = self.fn_type.fnReturnType(); | 2828 | const ret_ty = self.fn_type.fnReturnType(); |
| 2870 | try self.setRegOrMem(ret_ty, self.ret_mcv, mcv); | 2829 | try self.setRegOrMem(ret_ty, self.ret_mcv, mcv); |
src/codegen/c.zig+1-40| ... | @@ -283,22 +283,7 @@ pub const DeclGen = struct { | ... | @@ -283,22 +283,7 @@ pub const DeclGen = struct { |
| 283 | }, | 283 | }, |
| 284 | else => switch (t.ptrSize()) { | 284 | else => switch (t.ptrSize()) { |
| 285 | .Slice => unreachable, | 285 | .Slice => unreachable, |
| 286 | .Many => { | 286 | .Many => unreachable, |
| 287 | if (val.castTag(.ref_val)) |ref_val_payload| { | ||
| 288 | const sub_val = ref_val_payload.data; | ||
| 289 | if (sub_val.castTag(.bytes)) |bytes_payload| { | ||
| 290 | const bytes = bytes_payload.data; | ||
| 291 | try writer.writeByte('('); | ||
| 292 | try dg.renderType(writer, t); | ||
| 293 | // TODO: make our own C string escape instead of using std.zig.fmtEscapes | ||
| 294 | try writer.print(")\"{}\"", .{std.zig.fmtEscapes(bytes)}); | ||
| 295 | } else { | ||
| 296 | unreachable; | ||
| 297 | } | ||
| 298 | } else { | ||
| 299 | unreachable; | ||
| 300 | } | ||
| 301 | }, | ||
| 302 | .One => { | 287 | .One => { |
| 303 | var arena = std.heap.ArenaAllocator.init(dg.module.gpa); | 288 | var arena = std.heap.ArenaAllocator.init(dg.module.gpa); |
| 304 | defer arena.deinit(); | 289 | defer arena.deinit(); |
| ... | @@ -934,10 +919,8 @@ fn genBody(o: *Object, body: []const Air.Inst.Index) error{ AnalysisFail, OutOfM | ... | @@ -934,10 +919,8 @@ fn genBody(o: *Object, body: []const Air.Inst.Index) error{ AnalysisFail, OutOfM |
| 934 | .br => try airBr(o, inst), | 919 | .br => try airBr(o, inst), |
| 935 | .switch_br => try airSwitchBr(o, inst), | 920 | .switch_br => try airSwitchBr(o, inst), |
| 936 | .wrap_optional => try airWrapOptional(o, inst), | 921 | .wrap_optional => try airWrapOptional(o, inst), |
| 937 | .ref => try airRef(o, inst), | ||
| 938 | .struct_field_ptr => try airStructFieldPtr(o, inst), | 922 | .struct_field_ptr => try airStructFieldPtr(o, inst), |
| 939 | .struct_field_val => try airStructFieldVal(o, inst), | 923 | .struct_field_val => try airStructFieldVal(o, inst), |
| 940 | .varptr => try airVarPtr(o, inst), | ||
| 941 | .slice_ptr => try airSliceField(o, inst, ".ptr;\n"), | 924 | .slice_ptr => try airSliceField(o, inst, ".ptr;\n"), |
| 942 | .slice_len => try airSliceField(o, inst, ".len;\n"), | 925 | .slice_len => try airSliceField(o, inst, ".len;\n"), |
| 943 | 926 | ||
| ... | @@ -996,12 +979,6 @@ fn airSliceElemVal(o: *Object, inst: Air.Inst.Index, prefix: []const u8) !CValue | ... | @@ -996,12 +979,6 @@ fn airSliceElemVal(o: *Object, inst: Air.Inst.Index, prefix: []const u8) !CValue |
| 996 | return local; | 979 | return local; |
| 997 | } | 980 | } |
| 998 | 981 | ||
| 999 | fn airVarPtr(o: *Object, inst: Air.Inst.Index) !CValue { | ||
| 1000 | const ty_pl = o.air.instructions.items(.data)[inst].ty_pl; | ||
| 1001 | const variable = o.air.variables[ty_pl.payload]; | ||
| 1002 | return CValue{ .decl_ref = variable.owner_decl }; | ||
| 1003 | } | ||
| 1004 | |||
| 1005 | fn airAlloc(o: *Object, inst: Air.Inst.Index) !CValue { | 982 | fn airAlloc(o: *Object, inst: Air.Inst.Index) !CValue { |
| 1006 | const writer = o.writer(); | 983 | const writer = o.writer(); |
| 1007 | const inst_ty = o.air.typeOfIndex(inst); | 984 | const inst_ty = o.air.typeOfIndex(inst); |
| ... | @@ -1653,22 +1630,6 @@ fn airOptionalPayload(o: *Object, inst: Air.Inst.Index) !CValue { | ... | @@ -1653,22 +1630,6 @@ fn airOptionalPayload(o: *Object, inst: Air.Inst.Index) !CValue { |
| 1653 | return local; | 1630 | return local; |
| 1654 | } | 1631 | } |
| 1655 | 1632 | ||
| 1656 | fn airRef(o: *Object, inst: Air.Inst.Index) !CValue { | ||
| 1657 | if (o.liveness.isUnused(inst)) | ||
| 1658 | return CValue.none; | ||
| 1659 | |||
| 1660 | const ty_op = o.air.instructions.items(.data)[inst].ty_op; | ||
| 1661 | const writer = o.writer(); | ||
| 1662 | const operand = try o.resolveInst(ty_op.operand); | ||
| 1663 | |||
| 1664 | const inst_ty = o.air.typeOfIndex(inst); | ||
| 1665 | const local = try o.allocLocal(inst_ty, .Const); | ||
| 1666 | try writer.writeAll(" = "); | ||
| 1667 | try o.writeCValue(writer, operand); | ||
| 1668 | try writer.writeAll(";\n"); | ||
| 1669 | return local; | ||
| 1670 | } | ||
| 1671 | |||
| 1672 | fn airStructFieldPtr(o: *Object, inst: Air.Inst.Index) !CValue { | 1633 | fn airStructFieldPtr(o: *Object, inst: Air.Inst.Index) !CValue { |
| 1673 | if (o.liveness.isUnused(inst)) | 1634 | if (o.liveness.isUnused(inst)) |
| 1674 | return CValue.none; | 1635 | return CValue.none; |
src/codegen/llvm.zig+3-32| ... | @@ -699,29 +699,12 @@ pub const DeclGen = struct { | ... | @@ -699,29 +699,12 @@ pub const DeclGen = struct { |
| 699 | .decl_ref => { | 699 | .decl_ref => { |
| 700 | const decl = tv.val.castTag(.decl_ref).?.data; | 700 | const decl = tv.val.castTag(.decl_ref).?.data; |
| 701 | const val = try self.resolveGlobalDecl(decl); | 701 | const val = try self.resolveGlobalDecl(decl); |
| 702 | 702 | return val.constBitCast(llvm_type); | |
| 703 | const usize_type = try self.llvmType(Type.initTag(.usize)); | ||
| 704 | |||
| 705 | // TODO: second index should be the index into the memory! | ||
| 706 | var indices: [2]*const llvm.Value = .{ | ||
| 707 | usize_type.constNull(), | ||
| 708 | usize_type.constNull(), | ||
| 709 | }; | ||
| 710 | |||
| 711 | return val.constInBoundsGEP(&indices, indices.len); | ||
| 712 | }, | ||
| 713 | .ref_val => { | ||
| 714 | //const elem_value = tv.val.castTag(.ref_val).?.data; | ||
| 715 | //const elem_type = tv.ty.castPointer().?.data; | ||
| 716 | //const alloca = fg.?.buildAlloca(try self.llvmType(elem_type)); | ||
| 717 | //_ = fg.?.builder.buildStore(try self.genTypedValue(.{ .ty = elem_type, .val = elem_value }, fg), alloca); | ||
| 718 | //return alloca; | ||
| 719 | // TODO eliminate the ref_val Value Tag | ||
| 720 | return self.todo("implement const of pointer tag ref_val", .{}); | ||
| 721 | }, | 703 | }, |
| 722 | .variable => { | 704 | .variable => { |
| 723 | const variable = tv.val.castTag(.variable).?.data; | 705 | const variable = tv.val.castTag(.variable).?.data; |
| 724 | return self.resolveGlobalDecl(variable.owner_decl); | 706 | const val = try self.resolveGlobalDecl(variable.owner_decl); |
| 707 | return val.constBitCast(llvm_type); | ||
| 725 | }, | 708 | }, |
| 726 | .slice => { | 709 | .slice => { |
| 727 | const slice = tv.val.castTag(.slice).?.data; | 710 | const slice = tv.val.castTag(.slice).?.data; |
| ... | @@ -977,7 +960,6 @@ pub const FuncGen = struct { | ... | @@ -977,7 +960,6 @@ pub const FuncGen = struct { |
| 977 | .ret => try self.airRet(inst), | 960 | .ret => try self.airRet(inst), |
| 978 | .store => try self.airStore(inst), | 961 | .store => try self.airStore(inst), |
| 979 | .assembly => try self.airAssembly(inst), | 962 | .assembly => try self.airAssembly(inst), |
| 980 | .varptr => try self.airVarPtr(inst), | ||
| 981 | .slice_ptr => try self.airSliceField(inst, 0), | 963 | .slice_ptr => try self.airSliceField(inst, 0), |
| 982 | .slice_len => try self.airSliceField(inst, 1), | 964 | .slice_len => try self.airSliceField(inst, 1), |
| 983 | 965 | ||
| ... | @@ -1001,7 +983,6 @@ pub const FuncGen = struct { | ... | @@ -1001,7 +983,6 @@ pub const FuncGen = struct { |
| 1001 | 983 | ||
| 1002 | .constant => unreachable, | 984 | .constant => unreachable, |
| 1003 | .const_ty => unreachable, | 985 | .const_ty => unreachable, |
| 1004 | .ref => unreachable, // TODO eradicate this instruction | ||
| 1005 | .unreach => self.airUnreach(inst), | 986 | .unreach => self.airUnreach(inst), |
| 1006 | .dbg_stmt => blk: { | 987 | .dbg_stmt => blk: { |
| 1007 | // TODO: implement debug info | 988 | // TODO: implement debug info |
| ... | @@ -1180,16 +1161,6 @@ pub const FuncGen = struct { | ... | @@ -1180,16 +1161,6 @@ pub const FuncGen = struct { |
| 1180 | return null; | 1161 | return null; |
| 1181 | } | 1162 | } |
| 1182 | 1163 | ||
| 1183 | fn airVarPtr(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value { | ||
| 1184 | if (self.liveness.isUnused(inst)) | ||
| 1185 | return null; | ||
| 1186 | |||
| 1187 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; | ||
| 1188 | const variable = self.air.variables[ty_pl.payload]; | ||
| 1189 | const decl_llvm_value = self.dg.resolveGlobalDecl(variable.owner_decl); | ||
| 1190 | return decl_llvm_value; | ||
| 1191 | } | ||
| 1192 | |||
| 1193 | fn airSliceField(self: *FuncGen, inst: Air.Inst.Index, index: c_uint) !?*const llvm.Value { | 1164 | fn airSliceField(self: *FuncGen, inst: Air.Inst.Index, index: c_uint) !?*const llvm.Value { |
| 1194 | if (self.liveness.isUnused(inst)) | 1165 | if (self.liveness.isUnused(inst)) |
| 1195 | return null; | 1166 | return null; |
src/codegen/llvm/bindings.zig+3| ... | @@ -112,6 +112,9 @@ pub const Value = opaque { | ... | @@ -112,6 +112,9 @@ pub const Value = opaque { |
| 112 | ConstantIndices: [*]const *const Value, | 112 | ConstantIndices: [*]const *const Value, |
| 113 | NumIndices: c_uint, | 113 | NumIndices: c_uint, |
| 114 | ) *const Value; | 114 | ) *const Value; |
| 115 | |||
| 116 | pub const constBitCast = LLVMConstBitCast; | ||
| 117 | extern fn LLVMConstBitCast(ConstantVal: *const Value, ToType: *const Type) *const Value; | ||
| 115 | }; | 118 | }; |
| 116 | 119 | ||
| 117 | pub const Type = opaque { | 120 | pub const Type = opaque { |
src/codegen/wasm.zig+31-28| ... | @@ -754,22 +754,21 @@ pub const Context = struct { | ... | @@ -754,22 +754,21 @@ pub const Context = struct { |
| 754 | } | 754 | } |
| 755 | 755 | ||
| 756 | /// Generates the wasm bytecode for the declaration belonging to `Context` | 756 | /// Generates the wasm bytecode for the declaration belonging to `Context` |
| 757 | pub fn gen(self: *Context, typed_value: TypedValue) InnerError!Result { | 757 | pub fn gen(self: *Context, ty: Type, val: Value) InnerError!Result { |
| 758 | switch (typed_value.ty.zigTypeTag()) { | 758 | switch (ty.zigTypeTag()) { |
| 759 | .Fn => { | 759 | .Fn => { |
| 760 | try self.genFunctype(); | 760 | try self.genFunctype(); |
| 761 | if (typed_value.val.castTag(.extern_fn)) |_| return Result.appended; // don't need code body for extern functions | 761 | if (val.tag() == .extern_fn) { |
| 762 | return Result.appended; // don't need code body for extern functions | ||
| 763 | } | ||
| 762 | return self.fail("TODO implement wasm codegen for function pointers", .{}); | 764 | return self.fail("TODO implement wasm codegen for function pointers", .{}); |
| 763 | }, | 765 | }, |
| 764 | .Array => { | 766 | .Array => { |
| 765 | if (typed_value.val.castTag(.bytes)) |payload| { | 767 | if (val.castTag(.bytes)) |payload| { |
| 766 | if (typed_value.ty.sentinel()) |sentinel| { | 768 | if (ty.sentinel()) |sentinel| { |
| 767 | try self.code.appendSlice(payload.data); | 769 | try self.code.appendSlice(payload.data); |
| 768 | 770 | ||
| 769 | switch (try self.gen(.{ | 771 | switch (try self.gen(ty.elemType(), sentinel)) { |
| 770 | .ty = typed_value.ty.elemType(), | ||
| 771 | .val = sentinel, | ||
| 772 | })) { | ||
| 773 | .appended => return Result.appended, | 772 | .appended => return Result.appended, |
| 774 | .externally_managed => |data| { | 773 | .externally_managed => |data| { |
| 775 | try self.code.appendSlice(data); | 774 | try self.code.appendSlice(data); |
| ... | @@ -781,13 +780,17 @@ pub const Context = struct { | ... | @@ -781,13 +780,17 @@ pub const Context = struct { |
| 781 | } else return self.fail("TODO implement gen for more kinds of arrays", .{}); | 780 | } else return self.fail("TODO implement gen for more kinds of arrays", .{}); |
| 782 | }, | 781 | }, |
| 783 | .Int => { | 782 | .Int => { |
| 784 | const info = typed_value.ty.intInfo(self.target); | 783 | const info = ty.intInfo(self.target); |
| 785 | if (info.bits == 8 and info.signedness == .unsigned) { | 784 | if (info.bits == 8 and info.signedness == .unsigned) { |
| 786 | const int_byte = typed_value.val.toUnsignedInt(); | 785 | const int_byte = val.toUnsignedInt(); |
| 787 | try self.code.append(@intCast(u8, int_byte)); | 786 | try self.code.append(@intCast(u8, int_byte)); |
| 788 | return Result.appended; | 787 | return Result.appended; |
| 789 | } | 788 | } |
| 790 | return self.fail("TODO: Implement codegen for int type: '{}'", .{typed_value.ty}); | 789 | return self.fail("TODO: Implement codegen for int type: '{}'", .{ty}); |
| 790 | }, | ||
| 791 | .Enum => { | ||
| 792 | try self.emitConstant(val, ty); | ||
| 793 | return Result.appended; | ||
| 791 | }, | 794 | }, |
| 792 | else => |tag| return self.fail("TODO: Implement zig type codegen for type: '{s}'", .{tag}), | 795 | else => |tag| return self.fail("TODO: Implement zig type codegen for type: '{s}'", .{tag}), |
| 793 | } | 796 | } |
| ... | @@ -969,7 +972,7 @@ pub const Context = struct { | ... | @@ -969,7 +972,7 @@ pub const Context = struct { |
| 969 | return WValue{ .code_offset = offset }; | 972 | return WValue{ .code_offset = offset }; |
| 970 | } | 973 | } |
| 971 | 974 | ||
| 972 | fn emitConstant(self: *Context, value: Value, ty: Type) InnerError!void { | 975 | fn emitConstant(self: *Context, val: Value, ty: Type) InnerError!void { |
| 973 | const writer = self.code.writer(); | 976 | const writer = self.code.writer(); |
| 974 | switch (ty.zigTypeTag()) { | 977 | switch (ty.zigTypeTag()) { |
| 975 | .Int => { | 978 | .Int => { |
| ... | @@ -982,10 +985,10 @@ pub const Context = struct { | ... | @@ -982,10 +985,10 @@ pub const Context = struct { |
| 982 | const int_info = ty.intInfo(self.target); | 985 | const int_info = ty.intInfo(self.target); |
| 983 | // write constant | 986 | // write constant |
| 984 | switch (int_info.signedness) { | 987 | switch (int_info.signedness) { |
| 985 | .signed => try leb.writeILEB128(writer, value.toSignedInt()), | 988 | .signed => try leb.writeILEB128(writer, val.toSignedInt()), |
| 986 | .unsigned => switch (int_info.bits) { | 989 | .unsigned => switch (int_info.bits) { |
| 987 | 0...32 => try leb.writeILEB128(writer, @bitCast(i32, @intCast(u32, value.toUnsignedInt()))), | 990 | 0...32 => try leb.writeILEB128(writer, @bitCast(i32, @intCast(u32, val.toUnsignedInt()))), |
| 988 | 33...64 => try leb.writeILEB128(writer, @bitCast(i64, value.toUnsignedInt())), | 991 | 33...64 => try leb.writeILEB128(writer, @bitCast(i64, val.toUnsignedInt())), |
| 989 | else => |bits| return self.fail("Wasm TODO: emitConstant for integer with {d} bits", .{bits}), | 992 | else => |bits| return self.fail("Wasm TODO: emitConstant for integer with {d} bits", .{bits}), |
| 990 | }, | 993 | }, |
| 991 | } | 994 | } |
| ... | @@ -994,7 +997,7 @@ pub const Context = struct { | ... | @@ -994,7 +997,7 @@ pub const Context = struct { |
| 994 | // write opcode | 997 | // write opcode |
| 995 | try writer.writeByte(wasm.opcode(.i32_const)); | 998 | try writer.writeByte(wasm.opcode(.i32_const)); |
| 996 | // write constant | 999 | // write constant |
| 997 | try leb.writeILEB128(writer, value.toSignedInt()); | 1000 | try leb.writeILEB128(writer, val.toSignedInt()); |
| 998 | }, | 1001 | }, |
| 999 | .Float => { | 1002 | .Float => { |
| 1000 | // write opcode | 1003 | // write opcode |
| ... | @@ -1005,13 +1008,13 @@ pub const Context = struct { | ... | @@ -1005,13 +1008,13 @@ pub const Context = struct { |
| 1005 | try writer.writeByte(wasm.opcode(opcode)); | 1008 | try writer.writeByte(wasm.opcode(opcode)); |
| 1006 | // write constant | 1009 | // write constant |
| 1007 | switch (ty.floatBits(self.target)) { | 1010 | switch (ty.floatBits(self.target)) { |
| 1008 | 0...32 => try writer.writeIntLittle(u32, @bitCast(u32, value.toFloat(f32))), | 1011 | 0...32 => try writer.writeIntLittle(u32, @bitCast(u32, val.toFloat(f32))), |
| 1009 | 64 => try writer.writeIntLittle(u64, @bitCast(u64, value.toFloat(f64))), | 1012 | 64 => try writer.writeIntLittle(u64, @bitCast(u64, val.toFloat(f64))), |
| 1010 | else => |bits| return self.fail("Wasm TODO: emitConstant for float with {d} bits", .{bits}), | 1013 | else => |bits| return self.fail("Wasm TODO: emitConstant for float with {d} bits", .{bits}), |
| 1011 | } | 1014 | } |
| 1012 | }, | 1015 | }, |
| 1013 | .Pointer => { | 1016 | .Pointer => { |
| 1014 | if (value.castTag(.decl_ref)) |payload| { | 1017 | if (val.castTag(.decl_ref)) |payload| { |
| 1015 | const decl = payload.data; | 1018 | const decl = payload.data; |
| 1016 | 1019 | ||
| 1017 | // offset into the offset table within the 'data' section | 1020 | // offset into the offset table within the 'data' section |
| ... | @@ -1024,11 +1027,11 @@ pub const Context = struct { | ... | @@ -1024,11 +1027,11 @@ pub const Context = struct { |
| 1024 | try writer.writeByte(wasm.opcode(.i32_load)); | 1027 | try writer.writeByte(wasm.opcode(.i32_load)); |
| 1025 | try leb.writeULEB128(writer, @as(u32, 0)); | 1028 | try leb.writeULEB128(writer, @as(u32, 0)); |
| 1026 | try leb.writeULEB128(writer, @as(u32, 0)); | 1029 | try leb.writeULEB128(writer, @as(u32, 0)); |
| 1027 | } else return self.fail("Wasm TODO: emitConstant for other const pointer tag {s}", .{value.tag()}); | 1030 | } else return self.fail("Wasm TODO: emitConstant for other const pointer tag {s}", .{val.tag()}); |
| 1028 | }, | 1031 | }, |
| 1029 | .Void => {}, | 1032 | .Void => {}, |
| 1030 | .Enum => { | 1033 | .Enum => { |
| 1031 | if (value.castTag(.enum_field_index)) |field_index| { | 1034 | if (val.castTag(.enum_field_index)) |field_index| { |
| 1032 | switch (ty.tag()) { | 1035 | switch (ty.tag()) { |
| 1033 | .enum_simple => { | 1036 | .enum_simple => { |
| 1034 | try writer.writeByte(wasm.opcode(.i32_const)); | 1037 | try writer.writeByte(wasm.opcode(.i32_const)); |
| ... | @@ -1049,20 +1052,20 @@ pub const Context = struct { | ... | @@ -1049,20 +1052,20 @@ pub const Context = struct { |
| 1049 | } else { | 1052 | } else { |
| 1050 | var int_tag_buffer: Type.Payload.Bits = undefined; | 1053 | var int_tag_buffer: Type.Payload.Bits = undefined; |
| 1051 | const int_tag_ty = ty.intTagType(&int_tag_buffer); | 1054 | const int_tag_ty = ty.intTagType(&int_tag_buffer); |
| 1052 | try self.emitConstant(value, int_tag_ty); | 1055 | try self.emitConstant(val, int_tag_ty); |
| 1053 | } | 1056 | } |
| 1054 | }, | 1057 | }, |
| 1055 | .ErrorSet => { | 1058 | .ErrorSet => { |
| 1056 | const error_index = self.global_error_set.get(value.getError().?).?; | 1059 | const error_index = self.global_error_set.get(val.getError().?).?; |
| 1057 | try writer.writeByte(wasm.opcode(.i32_const)); | 1060 | try writer.writeByte(wasm.opcode(.i32_const)); |
| 1058 | try leb.writeULEB128(writer, error_index); | 1061 | try leb.writeULEB128(writer, error_index); |
| 1059 | }, | 1062 | }, |
| 1060 | .ErrorUnion => { | 1063 | .ErrorUnion => { |
| 1061 | const data = value.castTag(.error_union).?.data; | 1064 | const data = val.castTag(.error_union).?.data; |
| 1062 | const error_type = ty.errorUnionSet(); | 1065 | const error_type = ty.errorUnionSet(); |
| 1063 | const payload_type = ty.errorUnionPayload(); | 1066 | const payload_type = ty.errorUnionPayload(); |
| 1064 | if (value.getError()) |_| { | 1067 | if (val.getError()) |_| { |
| 1065 | // write the error value | 1068 | // write the error val |
| 1066 | try self.emitConstant(data, error_type); | 1069 | try self.emitConstant(data, error_type); |
| 1067 | 1070 | ||
| 1068 | // no payload, so write a '0' const | 1071 | // no payload, so write a '0' const |
| ... | @@ -1085,7 +1088,7 @@ pub const Context = struct { | ... | @@ -1085,7 +1088,7 @@ pub const Context = struct { |
| 1085 | } | 1088 | } |
| 1086 | 1089 | ||
| 1087 | /// Returns a `Value` as a signed 32 bit value. | 1090 | /// Returns a `Value` as a signed 32 bit value. |
| 1088 | /// It's illegale to provide a value with a type that cannot be represented | 1091 | /// It's illegal to provide a value with a type that cannot be represented |
| 1089 | /// as an integer value. | 1092 | /// as an integer value. |
| 1090 | fn valueAsI32(self: Context, val: Value, ty: Type) i32 { | 1093 | fn valueAsI32(self: Context, val: Value, ty: Type) i32 { |
| 1091 | switch (ty.zigTypeTag()) { | 1094 | switch (ty.zigTypeTag()) { |
src/link/Wasm.zig+1-1| ... | @@ -275,7 +275,7 @@ pub fn updateDecl(self: *Wasm, module: *Module, decl: *Module.Decl) !void { | ... | @@ -275,7 +275,7 @@ pub fn updateDecl(self: *Wasm, module: *Module, decl: *Module.Decl) !void { |
| 275 | defer context.deinit(); | 275 | defer context.deinit(); |
| 276 | 276 | ||
| 277 | // generate the 'code' section for the function declaration | 277 | // generate the 'code' section for the function declaration |
| 278 | const result = context.gen(.{ .ty = decl.ty, .val = decl.val }) catch |err| switch (err) { | 278 | const result = context.gen(decl.ty, decl.val) catch |err| switch (err) { |
| 279 | error.CodegenFail => { | 279 | error.CodegenFail => { |
| 280 | decl.analysis = .codegen_failure; | 280 | decl.analysis = .codegen_failure; |
| 281 | try module.failed_decls.put(module.gpa, decl, context.err_msg); | 281 | try module.failed_decls.put(module.gpa, decl, context.err_msg); |
src/print_air.zig+1-12| ... | @@ -15,12 +15,11 @@ pub fn dump(gpa: *Allocator, air: Air, zir: Zir, liveness: Liveness) void { | ... | @@ -15,12 +15,11 @@ pub fn dump(gpa: *Allocator, air: Air, zir: Zir, liveness: Liveness) void { |
| 15 | (@sizeOf(Air.Inst.Tag) + 8); | 15 | (@sizeOf(Air.Inst.Tag) + 8); |
| 16 | const extra_bytes = air.extra.len * @sizeOf(u32); | 16 | const extra_bytes = air.extra.len * @sizeOf(u32); |
| 17 | const values_bytes = air.values.len * @sizeOf(Value); | 17 | const values_bytes = air.values.len * @sizeOf(Value); |
| 18 | const variables_bytes = air.variables.len * @sizeOf(*Module.Var); | ||
| 19 | const tomb_bytes = liveness.tomb_bits.len * @sizeOf(usize); | 18 | const tomb_bytes = liveness.tomb_bits.len * @sizeOf(usize); |
| 20 | const liveness_extra_bytes = liveness.extra.len * @sizeOf(u32); | 19 | const liveness_extra_bytes = liveness.extra.len * @sizeOf(u32); |
| 21 | const liveness_special_bytes = liveness.special.count() * 8; | 20 | const liveness_special_bytes = liveness.special.count() * 8; |
| 22 | const total_bytes = @sizeOf(Air) + instruction_bytes + extra_bytes + | 21 | const total_bytes = @sizeOf(Air) + instruction_bytes + extra_bytes + |
| 23 | values_bytes * variables_bytes + @sizeOf(Liveness) + liveness_extra_bytes + | 22 | values_bytes + @sizeOf(Liveness) + liveness_extra_bytes + |
| 24 | liveness_special_bytes + tomb_bytes; | 23 | liveness_special_bytes + tomb_bytes; |
| 25 | 24 | ||
| 26 | // zig fmt: off | 25 | // zig fmt: off |
| ... | @@ -29,7 +28,6 @@ pub fn dump(gpa: *Allocator, air: Air, zir: Zir, liveness: Liveness) void { | ... | @@ -29,7 +28,6 @@ pub fn dump(gpa: *Allocator, air: Air, zir: Zir, liveness: Liveness) void { |
| 29 | \\# AIR Instructions: {d} ({}) | 28 | \\# AIR Instructions: {d} ({}) |
| 30 | \\# AIR Extra Data: {d} ({}) | 29 | \\# AIR Extra Data: {d} ({}) |
| 31 | \\# AIR Values Bytes: {d} ({}) | 30 | \\# AIR Values Bytes: {d} ({}) |
| 32 | \\# AIR Variables Bytes: {d} ({}) | ||
| 33 | \\# Liveness tomb_bits: {} | 31 | \\# Liveness tomb_bits: {} |
| 34 | \\# Liveness Extra Data: {d} ({}) | 32 | \\# Liveness Extra Data: {d} ({}) |
| 35 | \\# Liveness special table: {d} ({}) | 33 | \\# Liveness special table: {d} ({}) |
| ... | @@ -39,7 +37,6 @@ pub fn dump(gpa: *Allocator, air: Air, zir: Zir, liveness: Liveness) void { | ... | @@ -39,7 +37,6 @@ pub fn dump(gpa: *Allocator, air: Air, zir: Zir, liveness: Liveness) void { |
| 39 | air.instructions.len, fmtIntSizeBin(instruction_bytes), | 37 | air.instructions.len, fmtIntSizeBin(instruction_bytes), |
| 40 | air.extra.len, fmtIntSizeBin(extra_bytes), | 38 | air.extra.len, fmtIntSizeBin(extra_bytes), |
| 41 | air.values.len, fmtIntSizeBin(values_bytes), | 39 | air.values.len, fmtIntSizeBin(values_bytes), |
| 42 | air.variables.len, fmtIntSizeBin(variables_bytes), | ||
| 43 | fmtIntSizeBin(tomb_bytes), | 40 | fmtIntSizeBin(tomb_bytes), |
| 44 | liveness.extra.len, fmtIntSizeBin(liveness_extra_bytes), | 41 | liveness.extra.len, fmtIntSizeBin(liveness_extra_bytes), |
| 45 | liveness.special.count(), fmtIntSizeBin(liveness_special_bytes), | 42 | liveness.special.count(), fmtIntSizeBin(liveness_special_bytes), |
| ... | @@ -152,7 +149,6 @@ const Writer = struct { | ... | @@ -152,7 +149,6 @@ const Writer = struct { |
| 152 | .not, | 149 | .not, |
| 153 | .bitcast, | 150 | .bitcast, |
| 154 | .load, | 151 | .load, |
| 155 | .ref, | ||
| 156 | .floatcast, | 152 | .floatcast, |
| 157 | .intcast, | 153 | .intcast, |
| 158 | .optional_payload, | 154 | .optional_payload, |
| ... | @@ -174,7 +170,6 @@ const Writer = struct { | ... | @@ -174,7 +170,6 @@ const Writer = struct { |
| 174 | 170 | ||
| 175 | .struct_field_ptr => try w.writeStructField(s, inst), | 171 | .struct_field_ptr => try w.writeStructField(s, inst), |
| 176 | .struct_field_val => try w.writeStructField(s, inst), | 172 | .struct_field_val => try w.writeStructField(s, inst), |
| 177 | .varptr => try w.writeVarPtr(s, inst), | ||
| 178 | .constant => try w.writeConstant(s, inst), | 173 | .constant => try w.writeConstant(s, inst), |
| 179 | .assembly => try w.writeAssembly(s, inst), | 174 | .assembly => try w.writeAssembly(s, inst), |
| 180 | .dbg_stmt => try w.writeDbgStmt(s, inst), | 175 | .dbg_stmt => try w.writeDbgStmt(s, inst), |
| ... | @@ -243,12 +238,6 @@ const Writer = struct { | ... | @@ -243,12 +238,6 @@ const Writer = struct { |
| 243 | try s.print(", {d}", .{extra.data.field_index}); | 238 | try s.print(", {d}", .{extra.data.field_index}); |
| 244 | } | 239 | } |
| 245 | 240 | ||
| 246 | fn writeVarPtr(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void { | ||
| 247 | _ = w; | ||
| 248 | _ = inst; | ||
| 249 | try s.writeAll("TODO"); | ||
| 250 | } | ||
| 251 | |||
| 252 | fn writeConstant(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void { | 241 | fn writeConstant(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void { |
| 253 | const ty_pl = w.air.instructions.items(.data)[inst].ty_pl; | 242 | const ty_pl = w.air.instructions.items(.data)[inst].ty_pl; |
| 254 | const val = w.air.values[ty_pl.payload]; | 243 | const val = w.air.values[ty_pl.payload]; |
src/value.zig+28-43| ... | @@ -100,8 +100,6 @@ pub const Value = extern union { | ... | @@ -100,8 +100,6 @@ pub const Value = extern union { |
| 100 | function, | 100 | function, |
| 101 | extern_fn, | 101 | extern_fn, |
| 102 | variable, | 102 | variable, |
| 103 | /// Represents a pointer to another immutable value. | ||
| 104 | ref_val, | ||
| 105 | /// Represents a comptime variables storage. | 103 | /// Represents a comptime variables storage. |
| 106 | comptime_alloc, | 104 | comptime_alloc, |
| 107 | /// Represents a pointer to a decl, not the value of the decl. | 105 | /// Represents a pointer to a decl, not the value of the decl. |
| ... | @@ -126,6 +124,8 @@ pub const Value = extern union { | ... | @@ -126,6 +124,8 @@ pub const Value = extern union { |
| 126 | enum_field_index, | 124 | enum_field_index, |
| 127 | @"error", | 125 | @"error", |
| 128 | error_union, | 126 | error_union, |
| 127 | /// A pointer to the payload of an error union, based on a pointer to an error union. | ||
| 128 | eu_payload_ptr, | ||
| 129 | /// An instance of a struct. | 129 | /// An instance of a struct. |
| 130 | @"struct", | 130 | @"struct", |
| 131 | /// An instance of a union. | 131 | /// An instance of a union. |
| ... | @@ -214,9 +214,9 @@ pub const Value = extern union { | ... | @@ -214,9 +214,9 @@ pub const Value = extern union { |
| 214 | .decl_ref, | 214 | .decl_ref, |
| 215 | => Payload.Decl, | 215 | => Payload.Decl, |
| 216 | 216 | ||
| 217 | .ref_val, | ||
| 218 | .repeated, | 217 | .repeated, |
| 219 | .error_union, | 218 | .error_union, |
| 219 | .eu_payload_ptr, | ||
| 220 | => Payload.SubValue, | 220 | => Payload.SubValue, |
| 221 | 221 | ||
| 222 | .bytes, | 222 | .bytes, |
| ... | @@ -407,15 +407,6 @@ pub const Value = extern union { | ... | @@ -407,15 +407,6 @@ pub const Value = extern union { |
| 407 | .function => return self.copyPayloadShallow(allocator, Payload.Function), | 407 | .function => return self.copyPayloadShallow(allocator, Payload.Function), |
| 408 | .extern_fn => return self.copyPayloadShallow(allocator, Payload.Decl), | 408 | .extern_fn => return self.copyPayloadShallow(allocator, Payload.Decl), |
| 409 | .variable => return self.copyPayloadShallow(allocator, Payload.Variable), | 409 | .variable => return self.copyPayloadShallow(allocator, Payload.Variable), |
| 410 | .ref_val => { | ||
| 411 | const payload = self.castTag(.ref_val).?; | ||
| 412 | const new_payload = try allocator.create(Payload.SubValue); | ||
| 413 | new_payload.* = .{ | ||
| 414 | .base = payload.base, | ||
| 415 | .data = try payload.data.copy(allocator), | ||
| 416 | }; | ||
| 417 | return Value{ .ptr_otherwise = &new_payload.base }; | ||
| 418 | }, | ||
| 419 | .comptime_alloc => return self.copyPayloadShallow(allocator, Payload.ComptimeAlloc), | 410 | .comptime_alloc => return self.copyPayloadShallow(allocator, Payload.ComptimeAlloc), |
| 420 | .decl_ref => return self.copyPayloadShallow(allocator, Payload.Decl), | 411 | .decl_ref => return self.copyPayloadShallow(allocator, Payload.Decl), |
| 421 | .elem_ptr => { | 412 | .elem_ptr => { |
| ... | @@ -443,8 +434,8 @@ pub const Value = extern union { | ... | @@ -443,8 +434,8 @@ pub const Value = extern union { |
| 443 | return Value{ .ptr_otherwise = &new_payload.base }; | 434 | return Value{ .ptr_otherwise = &new_payload.base }; |
| 444 | }, | 435 | }, |
| 445 | .bytes => return self.copyPayloadShallow(allocator, Payload.Bytes), | 436 | .bytes => return self.copyPayloadShallow(allocator, Payload.Bytes), |
| 446 | .repeated => { | 437 | .repeated, .error_union, .eu_payload_ptr => { |
| 447 | const payload = self.castTag(.repeated).?; | 438 | const payload = self.cast(Payload.SubValue).?; |
| 448 | const new_payload = try allocator.create(Payload.SubValue); | 439 | const new_payload = try allocator.create(Payload.SubValue); |
| 449 | new_payload.* = .{ | 440 | new_payload.* = .{ |
| 450 | .base = payload.base, | 441 | .base = payload.base, |
| ... | @@ -489,15 +480,6 @@ pub const Value = extern union { | ... | @@ -489,15 +480,6 @@ pub const Value = extern union { |
| 489 | }, | 480 | }, |
| 490 | .enum_field_index => return self.copyPayloadShallow(allocator, Payload.U32), | 481 | .enum_field_index => return self.copyPayloadShallow(allocator, Payload.U32), |
| 491 | .@"error" => return self.copyPayloadShallow(allocator, Payload.Error), | 482 | .@"error" => return self.copyPayloadShallow(allocator, Payload.Error), |
| 492 | .error_union => { | ||
| 493 | const payload = self.castTag(.error_union).?; | ||
| 494 | const new_payload = try allocator.create(Payload.SubValue); | ||
| 495 | new_payload.* = .{ | ||
| 496 | .base = payload.base, | ||
| 497 | .data = try payload.data.copy(allocator), | ||
| 498 | }; | ||
| 499 | return Value{ .ptr_otherwise = &new_payload.base }; | ||
| 500 | }, | ||
| 501 | .@"struct" => @panic("TODO can't copy struct value without knowing the type"), | 483 | .@"struct" => @panic("TODO can't copy struct value without knowing the type"), |
| 502 | .@"union" => @panic("TODO can't copy union value without knowing the type"), | 484 | .@"union" => @panic("TODO can't copy union value without knowing the type"), |
| 503 | 485 | ||
| ... | @@ -609,11 +591,6 @@ pub const Value = extern union { | ... | @@ -609,11 +591,6 @@ pub const Value = extern union { |
| 609 | .function => return out_stream.print("(function '{s}')", .{val.castTag(.function).?.data.owner_decl.name}), | 591 | .function => return out_stream.print("(function '{s}')", .{val.castTag(.function).?.data.owner_decl.name}), |
| 610 | .extern_fn => return out_stream.writeAll("(extern function)"), | 592 | .extern_fn => return out_stream.writeAll("(extern function)"), |
| 611 | .variable => return out_stream.writeAll("(variable)"), | 593 | .variable => return out_stream.writeAll("(variable)"), |
| 612 | .ref_val => { | ||
| 613 | const ref_val = val.castTag(.ref_val).?.data; | ||
| 614 | try out_stream.writeAll("&const "); | ||
| 615 | val = ref_val; | ||
| 616 | }, | ||
| 617 | .comptime_alloc => { | 594 | .comptime_alloc => { |
| 618 | const ref_val = val.castTag(.comptime_alloc).?.data.val; | 595 | const ref_val = val.castTag(.comptime_alloc).?.data.val; |
| 619 | try out_stream.writeAll("&"); | 596 | try out_stream.writeAll("&"); |
| ... | @@ -648,6 +625,10 @@ pub const Value = extern union { | ... | @@ -648,6 +625,10 @@ pub const Value = extern union { |
| 648 | // TODO to print this it should be error{ Set, Items }!T(val), but we need the type for that | 625 | // TODO to print this it should be error{ Set, Items }!T(val), but we need the type for that |
| 649 | .error_union => return out_stream.print("error_union_val({})", .{val.castTag(.error_union).?.data}), | 626 | .error_union => return out_stream.print("error_union_val({})", .{val.castTag(.error_union).?.data}), |
| 650 | .inferred_alloc => return out_stream.writeAll("(inferred allocation value)"), | 627 | .inferred_alloc => return out_stream.writeAll("(inferred allocation value)"), |
| 628 | .eu_payload_ptr => { | ||
| 629 | try out_stream.writeAll("(eu_payload_ptr)"); | ||
| 630 | val = val.castTag(.eu_payload_ptr).?.data; | ||
| 631 | }, | ||
| 651 | }; | 632 | }; |
| 652 | } | 633 | } |
| 653 | 634 | ||
| ... | @@ -758,7 +739,6 @@ pub const Value = extern union { | ... | @@ -758,7 +739,6 @@ pub const Value = extern union { |
| 758 | .function, | 739 | .function, |
| 759 | .extern_fn, | 740 | .extern_fn, |
| 760 | .variable, | 741 | .variable, |
| 761 | .ref_val, | ||
| 762 | .comptime_alloc, | 742 | .comptime_alloc, |
| 763 | .decl_ref, | 743 | .decl_ref, |
| 764 | .elem_ptr, | 744 | .elem_ptr, |
| ... | @@ -780,18 +760,21 @@ pub const Value = extern union { | ... | @@ -780,18 +760,21 @@ pub const Value = extern union { |
| 780 | .@"union", | 760 | .@"union", |
| 781 | .inferred_alloc, | 761 | .inferred_alloc, |
| 782 | .abi_align_default, | 762 | .abi_align_default, |
| 763 | .eu_payload_ptr, | ||
| 783 | => unreachable, | 764 | => unreachable, |
| 784 | }; | 765 | }; |
| 785 | } | 766 | } |
| 786 | 767 | ||
| 787 | /// Asserts the type is an enum type. | 768 | /// Asserts the type is an enum type. |
| 788 | pub fn toEnum(val: Value, enum_ty: Type, comptime E: type) E { | 769 | pub fn toEnum(val: Value, comptime E: type) E { |
| 789 | _ = enum_ty; | 770 | switch (val.tag()) { |
| 790 | // TODO this needs to resolve other kinds of Value tags rather than | 771 | .enum_field_index => { |
| 791 | // assuming the tag will be .enum_field_index. | 772 | const field_index = val.castTag(.enum_field_index).?.data; |
| 792 | const field_index = val.castTag(.enum_field_index).?.data; | 773 | // TODO should `@intToEnum` do this `@intCast` for you? |
| 793 | // TODO should `@intToEnum` do this `@intCast` for you? | 774 | return @intToEnum(E, @intCast(@typeInfo(E).Enum.tag_type, field_index)); |
| 794 | return @intToEnum(E, @intCast(@typeInfo(E).Enum.tag_type, field_index)); | 775 | }, |
| 776 | else => unreachable, | ||
| 777 | } | ||
| 795 | } | 778 | } |
| 796 | 779 | ||
| 797 | /// Asserts the value is an integer. | 780 | /// Asserts the value is an integer. |
| ... | @@ -1255,6 +1238,9 @@ pub const Value = extern union { | ... | @@ -1255,6 +1238,9 @@ pub const Value = extern union { |
| 1255 | .slice => { | 1238 | .slice => { |
| 1256 | @panic("TODO Value.hash for slice"); | 1239 | @panic("TODO Value.hash for slice"); |
| 1257 | }, | 1240 | }, |
| 1241 | .eu_payload_ptr => { | ||
| 1242 | @panic("TODO Value.hash for eu_payload_ptr"); | ||
| 1243 | }, | ||
| 1258 | .int_u64 => { | 1244 | .int_u64 => { |
| 1259 | const payload = self.castTag(.int_u64).?; | 1245 | const payload = self.castTag(.int_u64).?; |
| 1260 | std.hash.autoHash(&hasher, payload.data); | 1246 | std.hash.autoHash(&hasher, payload.data); |
| ... | @@ -1263,10 +1249,6 @@ pub const Value = extern union { | ... | @@ -1263,10 +1249,6 @@ pub const Value = extern union { |
| 1263 | const payload = self.castTag(.int_i64).?; | 1249 | const payload = self.castTag(.int_i64).?; |
| 1264 | std.hash.autoHash(&hasher, payload.data); | 1250 | std.hash.autoHash(&hasher, payload.data); |
| 1265 | }, | 1251 | }, |
| 1266 | .ref_val => { | ||
| 1267 | const payload = self.castTag(.ref_val).?; | ||
| 1268 | std.hash.autoHash(&hasher, payload.data.hash()); | ||
| 1269 | }, | ||
| 1270 | .comptime_alloc => { | 1252 | .comptime_alloc => { |
| 1271 | const payload = self.castTag(.comptime_alloc).?; | 1253 | const payload = self.castTag(.comptime_alloc).?; |
| 1272 | std.hash.autoHash(&hasher, payload.data.val.hash()); | 1254 | std.hash.autoHash(&hasher, payload.data.val.hash()); |
| ... | @@ -1367,7 +1349,6 @@ pub const Value = extern union { | ... | @@ -1367,7 +1349,6 @@ pub const Value = extern union { |
| 1367 | pub fn pointerDeref(self: Value, allocator: *Allocator) error{ AnalysisFail, OutOfMemory }!Value { | 1349 | pub fn pointerDeref(self: Value, allocator: *Allocator) error{ AnalysisFail, OutOfMemory }!Value { |
| 1368 | return switch (self.tag()) { | 1350 | return switch (self.tag()) { |
| 1369 | .comptime_alloc => self.castTag(.comptime_alloc).?.data.val, | 1351 | .comptime_alloc => self.castTag(.comptime_alloc).?.data.val, |
| 1370 | .ref_val => self.castTag(.ref_val).?.data, | ||
| 1371 | .decl_ref => self.castTag(.decl_ref).?.data.value(), | 1352 | .decl_ref => self.castTag(.decl_ref).?.data.value(), |
| 1372 | .elem_ptr => { | 1353 | .elem_ptr => { |
| 1373 | const elem_ptr = self.castTag(.elem_ptr).?.data; | 1354 | const elem_ptr = self.castTag(.elem_ptr).?.data; |
| ... | @@ -1379,6 +1360,11 @@ pub const Value = extern union { | ... | @@ -1379,6 +1360,11 @@ pub const Value = extern union { |
| 1379 | const container_val = try field_ptr.container_ptr.pointerDeref(allocator); | 1360 | const container_val = try field_ptr.container_ptr.pointerDeref(allocator); |
| 1380 | return container_val.fieldValue(allocator, field_ptr.field_index); | 1361 | return container_val.fieldValue(allocator, field_ptr.field_index); |
| 1381 | }, | 1362 | }, |
| 1363 | .eu_payload_ptr => { | ||
| 1364 | const err_union_ptr = self.castTag(.eu_payload_ptr).?.data; | ||
| 1365 | const err_union_val = try err_union_ptr.pointerDeref(allocator); | ||
| 1366 | return err_union_val.castTag(.error_union).?.data; | ||
| 1367 | }, | ||
| 1382 | 1368 | ||
| 1383 | else => unreachable, | 1369 | else => unreachable, |
| 1384 | }; | 1370 | }; |
| ... | @@ -1390,7 +1376,6 @@ pub const Value = extern union { | ... | @@ -1390,7 +1376,6 @@ pub const Value = extern union { |
| 1390 | .bytes => val.castTag(.bytes).?.data.len, | 1376 | .bytes => val.castTag(.bytes).?.data.len, |
| 1391 | .array => val.castTag(.array).?.data.len, | 1377 | .array => val.castTag(.array).?.data.len, |
| 1392 | .slice => val.castTag(.slice).?.data.len.toUnsignedInt(), | 1378 | .slice => val.castTag(.slice).?.data.len.toUnsignedInt(), |
| 1393 | .ref_val => sliceLen(val.castTag(.ref_val).?.data), | ||
| 1394 | .decl_ref => { | 1379 | .decl_ref => { |
| 1395 | const decl = val.castTag(.decl_ref).?.data; | 1380 | const decl = val.castTag(.decl_ref).?.data; |
| 1396 | if (decl.ty.zigTypeTag() == .Array) { | 1381 | if (decl.ty.zigTypeTag() == .Array) { |
| ... | @@ -1576,7 +1561,6 @@ pub const Value = extern union { | ... | @@ -1576,7 +1561,6 @@ pub const Value = extern union { |
| 1576 | .int_i64, | 1561 | .int_i64, |
| 1577 | .int_big_positive, | 1562 | .int_big_positive, |
| 1578 | .int_big_negative, | 1563 | .int_big_negative, |
| 1579 | .ref_val, | ||
| 1580 | .comptime_alloc, | 1564 | .comptime_alloc, |
| 1581 | .decl_ref, | 1565 | .decl_ref, |
| 1582 | .elem_ptr, | 1566 | .elem_ptr, |
| ... | @@ -1599,6 +1583,7 @@ pub const Value = extern union { | ... | @@ -1599,6 +1583,7 @@ pub const Value = extern union { |
| 1599 | .@"union", | 1583 | .@"union", |
| 1600 | .null_value, | 1584 | .null_value, |
| 1601 | .abi_align_default, | 1585 | .abi_align_default, |
| 1586 | .eu_payload_ptr, | ||
| 1602 | => false, | 1587 | => false, |
| 1603 | 1588 | ||
| 1604 | .undef => unreachable, | 1589 | .undef => unreachable, |
test/cases.zig+3-2| ... | @@ -1182,10 +1182,11 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -1182,10 +1182,11 @@ pub fn addCases(ctx: *TestContext) !void { |
| 1182 | var case = ctx.obj("extern variable has no type", linux_x64); | 1182 | var case = ctx.obj("extern variable has no type", linux_x64); |
| 1183 | case.addError( | 1183 | case.addError( |
| 1184 | \\comptime { | 1184 | \\comptime { |
| 1185 | \\ _ = foo; | 1185 | \\ const x = foo + foo; |
| 1186 | \\ _ = x; | ||
| 1186 | \\} | 1187 | \\} |
| 1187 | \\extern var foo: i32; | 1188 | \\extern var foo: i32; |
| 1188 | , &[_][]const u8{":2:9: error: unable to resolve comptime value"}); | 1189 | , &[_][]const u8{":2:15: error: unable to resolve comptime value"}); |
| 1189 | case.addError( | 1190 | case.addError( |
| 1190 | \\export fn entry() void { | 1191 | \\export fn entry() void { |
| 1191 | \\ _ = foo; | 1192 | \\ _ = foo; |