aboutsummaryrefslogtreecommitdiff
path: root/src/value.zig
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2020-12-31 01:54:02 -0700
committerAndrew Kelley <andrew@ziglang.org>2020-12-31 01:54:02 -0700
commita46d24af1cf2885991c67bf39a2e639891c16121 (patch)
treed4f3c81b798cbae420819434c810a52b6817a85b /src/value.zig
parent3f7d9b5fc19e4081236b3b63aebbc80e1b17f5b5 (diff)
downloadzig-a46d24af1cf2885991c67bf39a2e639891c16121.tar.gz
zig-a46d24af1cf2885991c67bf39a2e639891c16121.zip
stage2: inferred local variables
This patch introduces the following new things: Types: - inferred_alloc - This is a special value that tracks a set of types that have been stored to an inferred allocation. It does not support most of the normal type queries. However it does respond to `isConstPtr`, `ptrSize`, `zigTypeTag`, etc. - The payload for this type simply points to the corresponding Value payload. Values: - inferred_alloc - This is a special value that tracks a set of types that have been stored to an inferred allocation. It does not support any of the normal value queries. ZIR instructions: - store_to_inferred_ptr, - Same as `store` but the type of the value being stored will be used to infer the pointer type. - resolve_inferred_alloc - Each `store_to_inferred_ptr` puts the type of the stored value into a set, and then `resolve_inferred_alloc` triggers peer type resolution on the set. The operand is a `alloc_inferred` or `alloc_inferred_mut` instruction, which is the allocation that needs to have its type inferred. Changes to the C backend: * Implements the bitcast instruction. If the source and dest types are both pointers, uses a cast, otherwise uses memcpy. * Tests are run with -Wno-declaration-after-statement. Someday we can conform to this but not today. In ZIR form it looks like this: ```zir fn_body main { // unanalyzed %0 = dbg_stmt() =>%1 = alloc_inferred() %2 = declval_in_module(Decl(add)) %3 = deref(%2) %4 = param_type(%3, 0) %5 = const(TypedValue{ .ty = comptime_int, .val = 1}) %6 = as(%4, %5) %7 = param_type(%3, 1) %8 = const(TypedValue{ .ty = comptime_int, .val = 2}) %9 = as(%7, %8) %10 = call(%3, [%6, %9], modifier=auto) =>%11 = store_to_inferred_ptr(%1, %10) =>%12 = resolve_inferred_alloc(%1) %13 = dbg_stmt() %14 = ret_type() %15 = const(TypedValue{ .ty = comptime_int, .val = 3}) %16 = sub(%10, %15) %17 = as(%14, %16) %18 = return(%17) } // fn_body main ``` I have not played around with very many test cases yet. Some interesting ones that I want to look at before merging: ```zig var x = blk: { var y = foo(); y.a = 1; break :blk y; }; ``` In the above test case, x and y are supposed to alias. ```zig var x = if (bar()) blk: { var y = foo(); y.a = 1; break :blk y; } else blk: { var z = baz(); z.b = 1; break :blk z; }; ``` In the above test case, x, y, and z are supposed to alias. I also haven't tested with `var` instead of `const` yet.
Diffstat (limited to 'src/value.zig')
-rw-r--r--src/value.zig36
1 files changed, 36 insertions, 0 deletions
diff --git a/src/value.zig b/src/value.zig
index 91b21511d4..4450099069 100644
--- a/src/value.zig
+++ b/src/value.zig
@@ -7,6 +7,7 @@ const BigIntMutable = std.math.big.int.Mutable;
const Target = std.Target;
const Allocator = std.mem.Allocator;
const Module = @import("Module.zig");
+const ir = @import("ir.zig");
/// This is the raw data, with no bookkeeping, no memory awareness,
/// no de-duplication, and no type system awareness.
@@ -101,6 +102,9 @@ pub const Value = extern union {
enum_literal,
error_set,
@"error",
+ /// This is a special value that tracks a set of types that have been stored
+ /// to an inferred allocation. It does not support any of the normal value queries.
+ inferred_alloc,
pub const last_no_payload_tag = Tag.bool_false;
pub const no_payload_count = @enumToInt(last_no_payload_tag) + 1;
@@ -189,6 +193,7 @@ pub const Value = extern union {
.float_128 => Payload.Float_128,
.error_set => Payload.ErrorSet,
.@"error" => Payload.Error,
+ .inferred_alloc => Payload.InferredAlloc,
};
}
@@ -383,6 +388,8 @@ pub const Value = extern union {
// memory is managed by the declaration
.error_set => return self.copyPayloadShallow(allocator, Payload.ErrorSet),
+
+ .inferred_alloc => unreachable,
}
}
@@ -501,6 +508,7 @@ pub const Value = extern union {
return out_stream.writeAll("}");
},
.@"error" => return out_stream.print("error.{}", .{val.castTag(.@"error").?.data.name}),
+ .inferred_alloc => return out_stream.writeAll("(inferred allocation value)"),
};
}
@@ -613,6 +621,7 @@ pub const Value = extern union {
.enum_literal,
.@"error",
.empty_struct_value,
+ .inferred_alloc,
=> unreachable,
};
}
@@ -683,6 +692,7 @@ pub const Value = extern union {
.error_set,
.@"error",
.empty_struct_value,
+ .inferred_alloc,
=> unreachable,
.undef => unreachable,
@@ -768,6 +778,7 @@ pub const Value = extern union {
.error_set,
.@"error",
.empty_struct_value,
+ .inferred_alloc,
=> unreachable,
.undef => unreachable,
@@ -853,6 +864,7 @@ pub const Value = extern union {
.error_set,
.@"error",
.empty_struct_value,
+ .inferred_alloc,
=> unreachable,
.undef => unreachable,
@@ -966,6 +978,7 @@ pub const Value = extern union {
.error_set,
.@"error",
.empty_struct_value,
+ .inferred_alloc,
=> unreachable,
.zero,
@@ -1055,6 +1068,7 @@ pub const Value = extern union {
.error_set,
.@"error",
.empty_struct_value,
+ .inferred_alloc,
=> unreachable,
.zero,
@@ -1213,6 +1227,7 @@ pub const Value = extern union {
.error_set,
.@"error",
.empty_struct_value,
+ .inferred_alloc,
=> unreachable,
.zero,
@@ -1289,6 +1304,7 @@ pub const Value = extern union {
.error_set,
.@"error",
.empty_struct_value,
+ .inferred_alloc,
=> unreachable,
.zero,
@@ -1525,6 +1541,8 @@ pub const Value = extern union {
hasher.update(payload.name);
std.hash.autoHash(&hasher, payload.value);
},
+
+ .inferred_alloc => unreachable,
}
return hasher.final();
}
@@ -1602,6 +1620,7 @@ pub const Value = extern union {
.error_set,
.@"error",
.empty_struct_value,
+ .inferred_alloc,
=> unreachable,
.ref_val => self.castTag(.ref_val).?.data,
@@ -1687,6 +1706,7 @@ pub const Value = extern union {
.error_set,
.@"error",
.empty_struct_value,
+ .inferred_alloc,
=> unreachable,
.empty_array => unreachable, // out of bounds array index
@@ -1793,6 +1813,7 @@ pub const Value = extern union {
.undef => unreachable,
.unreachable_value => unreachable,
+ .inferred_alloc => unreachable,
.null_value => true,
};
}
@@ -1801,6 +1822,7 @@ pub const Value = extern union {
pub fn isFloat(self: Value) bool {
return switch (self.tag()) {
.undef => unreachable,
+ .inferred_alloc => unreachable,
.float_16,
.float_32,
@@ -1890,6 +1912,7 @@ pub const Value = extern union {
.undef => unreachable,
.unreachable_value => unreachable,
+ .inferred_alloc => unreachable,
};
}
@@ -2020,6 +2043,19 @@ pub const Value = extern union {
value: u16,
},
};
+
+ pub const InferredAlloc = struct {
+ pub const base_tag = Tag.inferred_alloc;
+
+ base: Payload = .{ .tag = base_tag },
+ data: struct {
+ /// The value stored in the inferred allocation. This will go into
+ /// peer type resolution. This is stored in a separate list so that
+ /// the items are contiguous in memory and thus can be passed to
+ /// `Module.resolvePeerTypes`.
+ stored_inst_list: std.ArrayListUnmanaged(*ir.Inst) = .{},
+ },
+ };
};
/// Big enough to fit any non-BigInt value