authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-10-26 00:30:17+03:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-10-27 21:08:25-04:00
logd03c47bf85b17f7727d2f1fe5bd497b311c9eba7
treefc2008e0adbee552fd72215614eefe7e111dbf5d
parent398a3aae40bc03f6b7c6cd86d78a4cde125f2811

Sema: use `runtime_value` instead of creating allocs


12 files changed, 126 insertions(+), 52 deletions(-)

src/Sema.zig+43-33
......@@ -1827,6 +1827,22 @@ fn resolveMaybeUndefValAllowVariables(
18271827 block: *Block,
18281828 src: LazySrcLoc,
18291829 inst: Air.Inst.Ref,
1830) CompileError!?Value {
1831 var make_runtime = false;
1832 if (try sema.resolveMaybeUndefValAllowVariablesMaybeRuntime(block, src, inst, &make_runtime)) |val| {
1833 if (make_runtime) return null;
1834 return val;
1835 }
1836 return null;
1837}
1838
1839/// Returns all Value tags including `variable`, `undef` and `runtime_value`.
1840fn resolveMaybeUndefValAllowVariablesMaybeRuntime(
1841 sema: *Sema,
1842 block: *Block,
1843 src: LazySrcLoc,
1844 inst: Air.Inst.Ref,
1845 make_runtime: *bool,
18301846) CompileError!?Value {
18311847 // First section of indexes correspond to a set number of constant values.
18321848 var i: usize = @enumToInt(inst);
......@@ -1843,7 +1859,7 @@ fn resolveMaybeUndefValAllowVariables(
18431859 .constant => {
18441860 const ty_pl = sema.air_instructions.items(.data)[i].ty_pl;
18451861 const val = sema.air_values.items[ty_pl.payload];
1846 if (val.tag() == .runtime_int) return null;
1862 if (val.tag() == .runtime_value) make_runtime.* = true;
18471863 return val;
18481864 },
18491865 .const_ty => {
......@@ -3896,6 +3912,7 @@ fn validateUnionInit(
38963912 var first_block_index = block.instructions.items.len;
38973913 var block_index = block.instructions.items.len - 1;
38983914 var init_val: ?Value = null;
3915 var make_runtime = false;
38993916 while (block_index > 0) : (block_index -= 1) {
39003917 const store_inst = block.instructions.items[block_index];
39013918 if (store_inst == field_ptr_air_inst) break;
......@@ -3920,7 +3937,7 @@ fn validateUnionInit(
39203937 } else {
39213938 first_block_index = @min(first_block_index, block_index);
39223939 }
3923 init_val = try sema.resolveMaybeUndefValAllowVariables(block, init_src, bin_op.rhs);
3940 init_val = try sema.resolveMaybeUndefValAllowVariablesMaybeRuntime(block, init_src, bin_op.rhs, &make_runtime);
39243941 break;
39253942 }
39263943
......@@ -3933,10 +3950,11 @@ fn validateUnionInit(
39333950 // instead a single `store` to the result ptr with a comptime union value.
39343951 block.instructions.shrinkRetainingCapacity(first_block_index);
39353952
3936 const union_val = try Value.Tag.@"union".create(sema.arena, .{
3953 var union_val = try Value.Tag.@"union".create(sema.arena, .{
39373954 .tag = tag_val,
39383955 .val = val,
39393956 });
3957 if (make_runtime) union_val = try Value.Tag.runtime_value.create(sema.arena, union_val);
39403958 const union_init = try sema.addConstant(union_ty, union_val);
39413959 try sema.storePtr2(block, init_src, union_ptr, init_src, union_init, init_src, .store);
39423960 return;
......@@ -4054,6 +4072,7 @@ fn validateStructInit(
40544072
40554073 var struct_is_comptime = true;
40564074 var first_block_index = block.instructions.items.len;
4075 var make_runtime = false;
40574076
40584077 const air_tags = sema.air_instructions.items(.tag);
40594078 const air_datas = sema.air_instructions.items(.data);
......@@ -4130,7 +4149,7 @@ fn validateStructInit(
41304149 } else {
41314150 first_block_index = @min(first_block_index, block_index);
41324151 }
4133 if (try sema.resolveMaybeUndefValAllowVariables(block, field_src, bin_op.rhs)) |val| {
4152 if (try sema.resolveMaybeUndefValAllowVariablesMaybeRuntime(block, field_src, bin_op.rhs, &make_runtime)) |val| {
41344153 field_values[i] = val;
41354154 } else {
41364155 struct_is_comptime = false;
......@@ -4185,7 +4204,8 @@ fn validateStructInit(
41854204 // instead a single `store` to the struct_ptr with a comptime struct value.
41864205
41874206 block.instructions.shrinkRetainingCapacity(first_block_index);
4188 const struct_val = try Value.Tag.aggregate.create(sema.arena, field_values);
4207 var struct_val = try Value.Tag.aggregate.create(sema.arena, field_values);
4208 if (make_runtime) struct_val = try Value.Tag.runtime_value.create(sema.arena, struct_val);
41894209 const struct_init = try sema.addConstant(struct_ty, struct_val);
41904210 try sema.storePtr2(block, init_src, struct_ptr, init_src, struct_init, init_src, .store);
41914211 return;
......@@ -4265,6 +4285,7 @@ fn zirValidateArrayInit(
42654285
42664286 var array_is_comptime = true;
42674287 var first_block_index = block.instructions.items.len;
4288 var make_runtime = false;
42684289
42694290 // Collect the comptime element values in case the array literal ends up
42704291 // being comptime-known.
......@@ -4326,7 +4347,7 @@ fn zirValidateArrayInit(
43264347 array_is_comptime = false;
43274348 continue;
43284349 }
4329 if (try sema.resolveMaybeUndefValAllowVariables(block, elem_src, bin_op.rhs)) |val| {
4350 if (try sema.resolveMaybeUndefValAllowVariablesMaybeRuntime(block, elem_src, bin_op.rhs, &make_runtime)) |val| {
43304351 element_vals[i] = val;
43314352 } else {
43324353 array_is_comptime = false;
......@@ -4352,7 +4373,7 @@ fn zirValidateArrayInit(
43524373 array_is_comptime = false;
43534374 continue;
43544375 }
4355 if (try sema.resolveMaybeUndefValAllowVariables(block, elem_src, bin_op.rhs)) |val| {
4376 if (try sema.resolveMaybeUndefValAllowVariablesMaybeRuntime(block, elem_src, bin_op.rhs, &make_runtime)) |val| {
43564377 element_vals[i] = val;
43574378 } else {
43584379 array_is_comptime = false;
......@@ -4383,7 +4404,8 @@ fn zirValidateArrayInit(
43834404
43844405 block.instructions.shrinkRetainingCapacity(first_block_index);
43854406
4386 const array_val = try Value.Tag.aggregate.create(sema.arena, element_vals);
4407 var array_val = try Value.Tag.aggregate.create(sema.arena, element_vals);
4408 if (make_runtime) array_val = try Value.Tag.runtime_value.create(sema.arena, array_val);
43874409 const array_init = try sema.addConstant(array_ty, array_val);
43884410 try sema.storePtr2(block, init_src, array_ptr, init_src, array_init, init_src, .store);
43894411 }
......@@ -6635,20 +6657,14 @@ fn analyzeInlineCallArg(
66356657 .ty = param_ty,
66366658 .val = arg_val,
66376659 };
6638 } else if (((try sema.resolveMaybeUndefVal(arg_block, arg_src, casted_arg)) == null) or
6639 try sema.typeRequiresComptime(param_ty) or zir_tags[inst] == .param_comptime)
6640 {
6660 } else if (zir_tags[inst] == .param_comptime or try sema.typeRequiresComptime(param_ty)) {
66416661 try sema.inst_map.putNoClobber(sema.gpa, inst, casted_arg);
6642 } else {
6662 } else if (try sema.resolveMaybeUndefVal(arg_block, arg_src, casted_arg)) |val| {
66436663 // We have a comptime value but we need a runtime value to preserve inlining semantics,
6644 const ptr_type = try Type.ptr(sema.arena, sema.mod, .{
6645 .pointee_type = param_ty,
6646 .@"addrspace" = target_util.defaultAddressSpace(sema.mod.getTarget(), .local),
6647 });
6648 const alloc = try arg_block.addTy(.alloc, ptr_type);
6649 _ = try arg_block.addBinOp(.store, alloc, casted_arg);
6650 const loaded = try arg_block.addTyOp(.load, param_ty, alloc);
6651 try sema.inst_map.putNoClobber(sema.gpa, inst, loaded);
6664 const wrapped = try sema.addConstant(param_ty, try Value.Tag.runtime_value.create(sema.arena, val));
6665 try sema.inst_map.putNoClobber(sema.gpa, inst, wrapped);
6666 } else {
6667 try sema.inst_map.putNoClobber(sema.gpa, inst, casted_arg);
66526668 }
66536669
66546670 arg_i.* += 1;
......@@ -6685,20 +6701,14 @@ fn analyzeInlineCallArg(
66856701 .ty = sema.typeOf(uncasted_arg),
66866702 .val = arg_val,
66876703 };
6688 } else if ((try sema.resolveMaybeUndefVal(arg_block, arg_src, uncasted_arg)) == null or
6689 try sema.typeRequiresComptime(param_ty) or zir_tags[inst] == .param_anytype_comptime)
6690 {
6704 } else if (zir_tags[inst] == .param_anytype_comptime or try sema.typeRequiresComptime(param_ty)) {
66916705 try sema.inst_map.putNoClobber(sema.gpa, inst, uncasted_arg);
6692 } else {
6706 } else if (try sema.resolveMaybeUndefVal(arg_block, arg_src, uncasted_arg)) |val| {
66936707 // We have a comptime value but we need a runtime value to preserve inlining semantics,
6694 const ptr_type = try Type.ptr(sema.arena, sema.mod, .{
6695 .pointee_type = param_ty,
6696 .@"addrspace" = target_util.defaultAddressSpace(sema.mod.getTarget(), .local),
6697 });
6698 const alloc = try arg_block.addTy(.alloc, ptr_type);
6699 _ = try arg_block.addBinOp(.store, alloc, uncasted_arg);
6700 const loaded = try arg_block.addTyOp(.load, param_ty, alloc);
6701 try sema.inst_map.putNoClobber(sema.gpa, inst, loaded);
6708 const wrapped = try sema.addConstant(param_ty, try Value.Tag.runtime_value.create(sema.arena, val));
6709 try sema.inst_map.putNoClobber(sema.gpa, inst, wrapped);
6710 } else {
6711 try sema.inst_map.putNoClobber(sema.gpa, inst, uncasted_arg);
67026712 }
67036713
67046714 arg_i.* += 1;
......@@ -14826,7 +14836,7 @@ fn zirBuiltinSrc(
1482614836 // fn_name: [:0]const u8,
1482714837 field_values[1] = func_name_val;
1482814838 // line: u32
14829 field_values[2] = try Value.Tag.runtime_int.create(sema.arena, extra.line + 1);
14839 field_values[2] = try Value.Tag.runtime_value.create(sema.arena, try Value.Tag.int_u64.create(sema.arena, extra.line + 1));
1483014840 // column: u32,
1483114841 field_values[3] = try Value.Tag.int_u64.create(sema.arena, extra.column + 1);
1483214842
src/TypedValue.zig+1-1
......@@ -477,6 +477,6 @@ pub fn print(
477477 },
478478 .generic_poison_type => return writer.writeAll("(generic poison type)"),
479479 .generic_poison => return writer.writeAll("(generic poison)"),
480 .runtime_int => return writer.writeAll("[runtime value]"),
480 .runtime_value => return writer.writeAll("[runtime value]"),
481481 };
482482}
src/arch/aarch64/CodeGen.zig+5-1
......@@ -5401,7 +5401,11 @@ fn lowerUnnamedConst(self: *Self, tv: TypedValue) InnerError!MCValue {
54015401 }
54025402}
54035403
5404fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {
5404fn genTypedValue(self: *Self, arg_tv: TypedValue) InnerError!MCValue {
5405 var typed_value = arg_tv;
5406 if (typed_value.val.castTag(.runtime_value)) |rt| {
5407 typed_value.val = rt.data;
5408 }
54055409 log.debug("genTypedValue: ty = {}, val = {}", .{ typed_value.ty.fmtDebug(), typed_value.val.fmtDebug() });
54065410 if (typed_value.val.isUndef())
54075411 return MCValue{ .undef = {} };
src/arch/arm/CodeGen.zig+5-1
......@@ -6047,7 +6047,11 @@ fn lowerUnnamedConst(self: *Self, tv: TypedValue) InnerError!MCValue {
60476047 }
60486048}
60496049
6050fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {
6050fn genTypedValue(self: *Self, arg_tv: TypedValue) InnerError!MCValue {
6051 var typed_value = arg_tv;
6052 if (typed_value.val.castTag(.runtime_value)) |rt| {
6053 typed_value.val = rt.data;
6054 }
60516055 log.debug("genTypedValue: ty = {}, val = {}", .{ typed_value.ty.fmtDebug(), typed_value.val.fmtDebug() });
60526056 if (typed_value.val.isUndef())
60536057 return MCValue{ .undef = {} };
src/arch/wasm/CodeGen.zig+5-1
......@@ -2582,7 +2582,11 @@ fn toTwosComplement(value: anytype, bits: u7) std.meta.Int(.unsigned, @typeInfo(
25822582 return @intCast(WantedT, result);
25832583}
25842584
2585fn lowerConstant(func: *CodeGen, val: Value, ty: Type) InnerError!WValue {
2585fn lowerConstant(func: *CodeGen, arg_val: Value, ty: Type) InnerError!WValue {
2586 var val = arg_val;
2587 if (val.castTag(.runtime_value)) |rt| {
2588 val = rt.data;
2589 }
25862590 if (val.isUndefDeep()) return func.emitUndefined(ty);
25872591 if (val.castTag(.decl_ref)) |decl_ref| {
25882592 const decl_index = decl_ref.data;
src/arch/x86_64/CodeGen.zig+5-1
......@@ -6960,7 +6960,11 @@ fn lowerUnnamedConst(self: *Self, tv: TypedValue) InnerError!MCValue {
69606960 }
69616961}
69626962
6963fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {
6963fn genTypedValue(self: *Self, arg_tv: TypedValue) InnerError!MCValue {
6964 var typed_value = arg_tv;
6965 if (typed_value.val.castTag(.runtime_value)) |rt| {
6966 typed_value.val = rt.data;
6967 }
69646968 log.debug("genTypedValue: ty = {}, val = {}", .{ typed_value.ty.fmtDebug(), typed_value.val.fmtDebug() });
69656969 if (typed_value.val.isUndef())
69666970 return MCValue{ .undef = {} };
src/codegen.zig+6-1
......@@ -149,7 +149,7 @@ fn writeFloat(comptime F: type, f: F, target: Target, endian: std.builtin.Endian
149149pub fn generateSymbol(
150150 bin_file: *link.File,
151151 src_loc: Module.SrcLoc,
152 typed_value: TypedValue,
152 arg_tv: TypedValue,
153153 code: *std.ArrayList(u8),
154154 debug_output: DebugInfoOutput,
155155 reloc_info: RelocInfo,
......@@ -157,6 +157,11 @@ pub fn generateSymbol(
157157 const tracy = trace(@src());
158158 defer tracy.end();
159159
160 var typed_value = arg_tv;
161 if (arg_tv.val.castTag(.runtime_value)) |rt| {
162 typed_value.val = rt.data;
163 }
164
160165 const target = bin_file.options.target;
161166 const endian = target.cpu.arch.endian();
162167
src/codegen/c.zig+5-1
......@@ -555,9 +555,13 @@ pub const DeclGen = struct {
555555 dg: *DeclGen,
556556 writer: anytype,
557557 ty: Type,
558 val: Value,
558 arg_val: Value,
559559 location: ValueRenderLocation,
560560 ) error{ OutOfMemory, AnalysisFail }!void {
561 var val = arg_val;
562 if (val.castTag(.runtime_value)) |rt| {
563 val = rt.data;
564 }
561565 const target = dg.module.getTarget();
562566 if (val.isUndefDeep()) {
563567 switch (ty.zigTypeTag()) {
src/codegen/llvm.zig+5-1
......@@ -3187,7 +3187,11 @@ pub const DeclGen = struct {
31873187 return llvm_elem_ty;
31883188 }
31893189
3190 fn lowerValue(dg: *DeclGen, tv: TypedValue) Error!*llvm.Value {
3190 fn lowerValue(dg: *DeclGen, arg_tv: TypedValue) Error!*llvm.Value {
3191 var tv = arg_tv;
3192 if (tv.val.castTag(.runtime_value)) |rt| {
3193 tv.val = rt.data;
3194 }
31913195 if (tv.val.isUndef()) {
31923196 const llvm_type = try dg.lowerType(tv.ty);
31933197 return llvm_type.getUndef();
src/value.zig+8-11
......@@ -111,10 +111,12 @@ pub const Value = extern union {
111111 int_i64,
112112 int_big_positive,
113113 int_big_negative,
114 runtime_int,
115114 function,
116115 extern_fn,
117116 variable,
117 /// A wrapper for values which are comptime-known but should
118 /// semantically be runtime-known.
119 runtime_value,
118120 /// Represents a pointer to a Decl.
119121 /// When machine codegen backend sees this, it must set the Decl's `alive` field to true.
120122 decl_ref,
......@@ -282,6 +284,7 @@ pub const Value = extern union {
282284 .eu_payload,
283285 .opt_payload,
284286 .empty_array_sentinel,
287 .runtime_value,
285288 => Payload.SubValue,
286289
287290 .eu_payload_ptr,
......@@ -305,7 +308,6 @@ pub const Value = extern union {
305308 .int_type => Payload.IntType,
306309 .int_u64 => Payload.U64,
307310 .int_i64 => Payload.I64,
308 .runtime_int => Payload.U64,
309311 .function => Payload.Function,
310312 .variable => Payload.Variable,
311313 .decl_ref_mut => Payload.DeclRefMut,
......@@ -485,7 +487,6 @@ pub const Value = extern union {
485487 },
486488 .int_type => return self.copyPayloadShallow(arena, Payload.IntType),
487489 .int_u64 => return self.copyPayloadShallow(arena, Payload.U64),
488 .runtime_int => return self.copyPayloadShallow(arena, Payload.U64),
489490 .int_i64 => return self.copyPayloadShallow(arena, Payload.I64),
490491 .int_big_positive, .int_big_negative => {
491492 const old_payload = self.cast(Payload.BigInt).?;
......@@ -567,6 +568,7 @@ pub const Value = extern union {
567568 .eu_payload,
568569 .opt_payload,
569570 .empty_array_sentinel,
571 .runtime_value,
570572 => {
571573 const payload = self.cast(Payload.SubValue).?;
572574 const new_payload = try arena.create(Payload.SubValue);
......@@ -765,7 +767,7 @@ pub const Value = extern union {
765767 .int_i64 => return std.fmt.formatIntValue(val.castTag(.int_i64).?.data, "", options, out_stream),
766768 .int_big_positive => return out_stream.print("{}", .{val.castTag(.int_big_positive).?.asBigInt()}),
767769 .int_big_negative => return out_stream.print("{}", .{val.castTag(.int_big_negative).?.asBigInt()}),
768 .runtime_int => return out_stream.writeAll("[runtime value]"),
770 .runtime_value => return out_stream.writeAll("[runtime value]"),
769771 .function => return out_stream.print("(function decl={d})", .{val.castTag(.function).?.data.owner_decl}),
770772 .extern_fn => return out_stream.writeAll("(extern function)"),
771773 .variable => return out_stream.writeAll("(variable)"),
......@@ -1081,8 +1083,6 @@ pub const Value = extern union {
10811083 .int_big_positive => return val.castTag(.int_big_positive).?.asBigInt(),
10821084 .int_big_negative => return val.castTag(.int_big_negative).?.asBigInt(),
10831085
1084 .runtime_int => return BigIntMutable.init(&space.limbs, val.castTag(.runtime_int).?.data).toConst(),
1085
10861086 .undef => unreachable,
10871087
10881088 .lazy_align => {
......@@ -1138,8 +1138,6 @@ pub const Value = extern union {
11381138 .int_big_positive => return val.castTag(.int_big_positive).?.asBigInt().to(u64) catch null,
11391139 .int_big_negative => return val.castTag(.int_big_negative).?.asBigInt().to(u64) catch null,
11401140
1141 .runtime_int => return val.castTag(.runtime_int).?.data,
1142
11431141 .undef => unreachable,
11441142
11451143 .lazy_align => {
......@@ -2357,6 +2355,8 @@ pub const Value = extern union {
23572355 const zig_ty_tag = ty.zigTypeTag();
23582356 std.hash.autoHash(hasher, zig_ty_tag);
23592357 if (val.isUndef()) return;
2358 // The value is runtime-known and shouldn't affect the hash.
2359 if (val.tag() == .runtime_value) return;
23602360
23612361 switch (zig_ty_tag) {
23622362 .BoundFn => unreachable, // TODO remove this from the language
......@@ -2632,9 +2632,6 @@ pub const Value = extern union {
26322632 .lazy_size,
26332633 => return hashInt(ptr_val, hasher, target),
26342634
2635 // The value is runtime-known and shouldn't affect the hash.
2636 .runtime_int => {},
2637
26382635 else => unreachable,
26392636 }
26402637 }
test/behavior/bugs/13164.zig+1
......@@ -10,6 +10,7 @@ inline fn setLimits(min: ?u32, max: ?u32) !void {
1010test {
1111 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1212 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
13 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
1314
1415 var x: u32 = 42;
1516 try setLimits(x, null);
test/behavior/vector.zig+37
......@@ -1135,3 +1135,40 @@ test "array of vectors is copied" {
11351135 points2[0..points.len].* = points;
11361136 try std.testing.expectEqual(points2[6], Vec3{ -345, -311, 381 });
11371137}
1138
1139test "byte vector initialized in inline function" {
1140 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1141 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
1142 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
1143 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1144 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1145
1146 const S = struct {
1147 inline fn boolx4(e0: bool, e1: bool, e2: bool, e3: bool) @Vector(4, bool) {
1148 return .{ e0, e1, e2, e3 };
1149 }
1150
1151 fn all(vb: @Vector(4, bool)) bool {
1152 return @reduce(.And, vb);
1153 }
1154 };
1155
1156 try expect(S.all(S.boolx4(true, true, true, true)));
1157}
1158
1159test "byte vector initialized in inline function" {
1160 // TODO https://github.com/ziglang/zig/issues/13279
1161 if (true) return error.SkipZigTest;
1162
1163 const S = struct {
1164 fn boolx4(e0: bool, e1: bool, e2: bool, e3: bool) @Vector(4, bool) {
1165 return .{ e0, e1, e2, e3 };
1166 }
1167
1168 fn all(vb: @Vector(4, bool)) bool {
1169 return @reduce(.And, vb);
1170 }
1171 };
1172
1173 try expect(S.all(S.boolx4(true, true, true, true)));
1174}