Commit d03c47bf85
Changed files (12)
src
arch
test
behavior
src/arch/aarch64/CodeGen.zig
@@ -5401,7 +5401,11 @@ fn lowerUnnamedConst(self: *Self, tv: TypedValue) InnerError!MCValue {
}
}
-fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {
+fn genTypedValue(self: *Self, arg_tv: TypedValue) InnerError!MCValue {
+ var typed_value = arg_tv;
+ if (typed_value.val.castTag(.runtime_value)) |rt| {
+ typed_value.val = rt.data;
+ }
log.debug("genTypedValue: ty = {}, val = {}", .{ typed_value.ty.fmtDebug(), typed_value.val.fmtDebug() });
if (typed_value.val.isUndef())
return MCValue{ .undef = {} };
src/arch/arm/CodeGen.zig
@@ -6047,7 +6047,11 @@ fn lowerUnnamedConst(self: *Self, tv: TypedValue) InnerError!MCValue {
}
}
-fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {
+fn genTypedValue(self: *Self, arg_tv: TypedValue) InnerError!MCValue {
+ var typed_value = arg_tv;
+ if (typed_value.val.castTag(.runtime_value)) |rt| {
+ typed_value.val = rt.data;
+ }
log.debug("genTypedValue: ty = {}, val = {}", .{ typed_value.ty.fmtDebug(), typed_value.val.fmtDebug() });
if (typed_value.val.isUndef())
return MCValue{ .undef = {} };
src/arch/wasm/CodeGen.zig
@@ -2582,7 +2582,11 @@ fn toTwosComplement(value: anytype, bits: u7) std.meta.Int(.unsigned, @typeInfo(
return @intCast(WantedT, result);
}
-fn lowerConstant(func: *CodeGen, val: Value, ty: Type) InnerError!WValue {
+fn lowerConstant(func: *CodeGen, arg_val: Value, ty: Type) InnerError!WValue {
+ var val = arg_val;
+ if (val.castTag(.runtime_value)) |rt| {
+ val = rt.data;
+ }
if (val.isUndefDeep()) return func.emitUndefined(ty);
if (val.castTag(.decl_ref)) |decl_ref| {
const decl_index = decl_ref.data;
src/arch/x86_64/CodeGen.zig
@@ -6960,7 +6960,11 @@ fn lowerUnnamedConst(self: *Self, tv: TypedValue) InnerError!MCValue {
}
}
-fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {
+fn genTypedValue(self: *Self, arg_tv: TypedValue) InnerError!MCValue {
+ var typed_value = arg_tv;
+ if (typed_value.val.castTag(.runtime_value)) |rt| {
+ typed_value.val = rt.data;
+ }
log.debug("genTypedValue: ty = {}, val = {}", .{ typed_value.ty.fmtDebug(), typed_value.val.fmtDebug() });
if (typed_value.val.isUndef())
return MCValue{ .undef = {} };
src/codegen/c.zig
@@ -555,9 +555,13 @@ pub const DeclGen = struct {
dg: *DeclGen,
writer: anytype,
ty: Type,
- val: Value,
+ arg_val: Value,
location: ValueRenderLocation,
) error{ OutOfMemory, AnalysisFail }!void {
+ var val = arg_val;
+ if (val.castTag(.runtime_value)) |rt| {
+ val = rt.data;
+ }
const target = dg.module.getTarget();
if (val.isUndefDeep()) {
switch (ty.zigTypeTag()) {
src/codegen/llvm.zig
@@ -3187,7 +3187,11 @@ pub const DeclGen = struct {
return llvm_elem_ty;
}
- fn lowerValue(dg: *DeclGen, tv: TypedValue) Error!*llvm.Value {
+ fn lowerValue(dg: *DeclGen, arg_tv: TypedValue) Error!*llvm.Value {
+ var tv = arg_tv;
+ if (tv.val.castTag(.runtime_value)) |rt| {
+ tv.val = rt.data;
+ }
if (tv.val.isUndef()) {
const llvm_type = try dg.lowerType(tv.ty);
return llvm_type.getUndef();
src/codegen.zig
@@ -149,7 +149,7 @@ fn writeFloat(comptime F: type, f: F, target: Target, endian: std.builtin.Endian
pub fn generateSymbol(
bin_file: *link.File,
src_loc: Module.SrcLoc,
- typed_value: TypedValue,
+ arg_tv: TypedValue,
code: *std.ArrayList(u8),
debug_output: DebugInfoOutput,
reloc_info: RelocInfo,
@@ -157,6 +157,11 @@ pub fn generateSymbol(
const tracy = trace(@src());
defer tracy.end();
+ var typed_value = arg_tv;
+ if (arg_tv.val.castTag(.runtime_value)) |rt| {
+ typed_value.val = rt.data;
+ }
+
const target = bin_file.options.target;
const endian = target.cpu.arch.endian();
src/Sema.zig
@@ -1827,6 +1827,22 @@ fn resolveMaybeUndefValAllowVariables(
block: *Block,
src: LazySrcLoc,
inst: Air.Inst.Ref,
+) CompileError!?Value {
+ var make_runtime = false;
+ if (try sema.resolveMaybeUndefValAllowVariablesMaybeRuntime(block, src, inst, &make_runtime)) |val| {
+ if (make_runtime) return null;
+ return val;
+ }
+ return null;
+}
+
+/// Returns all Value tags including `variable`, `undef` and `runtime_value`.
+fn resolveMaybeUndefValAllowVariablesMaybeRuntime(
+ sema: *Sema,
+ block: *Block,
+ src: LazySrcLoc,
+ inst: Air.Inst.Ref,
+ make_runtime: *bool,
) CompileError!?Value {
// First section of indexes correspond to a set number of constant values.
var i: usize = @enumToInt(inst);
@@ -1843,7 +1859,7 @@ fn resolveMaybeUndefValAllowVariables(
.constant => {
const ty_pl = sema.air_instructions.items(.data)[i].ty_pl;
const val = sema.air_values.items[ty_pl.payload];
- if (val.tag() == .runtime_int) return null;
+ if (val.tag() == .runtime_value) make_runtime.* = true;
return val;
},
.const_ty => {
@@ -3896,6 +3912,7 @@ fn validateUnionInit(
var first_block_index = block.instructions.items.len;
var block_index = block.instructions.items.len - 1;
var init_val: ?Value = null;
+ var make_runtime = false;
while (block_index > 0) : (block_index -= 1) {
const store_inst = block.instructions.items[block_index];
if (store_inst == field_ptr_air_inst) break;
@@ -3920,7 +3937,7 @@ fn validateUnionInit(
} else {
first_block_index = @min(first_block_index, block_index);
}
- init_val = try sema.resolveMaybeUndefValAllowVariables(block, init_src, bin_op.rhs);
+ init_val = try sema.resolveMaybeUndefValAllowVariablesMaybeRuntime(block, init_src, bin_op.rhs, &make_runtime);
break;
}
@@ -3933,10 +3950,11 @@ fn validateUnionInit(
// instead a single `store` to the result ptr with a comptime union value.
block.instructions.shrinkRetainingCapacity(first_block_index);
- const union_val = try Value.Tag.@"union".create(sema.arena, .{
+ var union_val = try Value.Tag.@"union".create(sema.arena, .{
.tag = tag_val,
.val = val,
});
+ if (make_runtime) union_val = try Value.Tag.runtime_value.create(sema.arena, union_val);
const union_init = try sema.addConstant(union_ty, union_val);
try sema.storePtr2(block, init_src, union_ptr, init_src, union_init, init_src, .store);
return;
@@ -4054,6 +4072,7 @@ fn validateStructInit(
var struct_is_comptime = true;
var first_block_index = block.instructions.items.len;
+ var make_runtime = false;
const air_tags = sema.air_instructions.items(.tag);
const air_datas = sema.air_instructions.items(.data);
@@ -4130,7 +4149,7 @@ fn validateStructInit(
} else {
first_block_index = @min(first_block_index, block_index);
}
- if (try sema.resolveMaybeUndefValAllowVariables(block, field_src, bin_op.rhs)) |val| {
+ if (try sema.resolveMaybeUndefValAllowVariablesMaybeRuntime(block, field_src, bin_op.rhs, &make_runtime)) |val| {
field_values[i] = val;
} else {
struct_is_comptime = false;
@@ -4185,7 +4204,8 @@ fn validateStructInit(
// instead a single `store` to the struct_ptr with a comptime struct value.
block.instructions.shrinkRetainingCapacity(first_block_index);
- const struct_val = try Value.Tag.aggregate.create(sema.arena, field_values);
+ var struct_val = try Value.Tag.aggregate.create(sema.arena, field_values);
+ if (make_runtime) struct_val = try Value.Tag.runtime_value.create(sema.arena, struct_val);
const struct_init = try sema.addConstant(struct_ty, struct_val);
try sema.storePtr2(block, init_src, struct_ptr, init_src, struct_init, init_src, .store);
return;
@@ -4265,6 +4285,7 @@ fn zirValidateArrayInit(
var array_is_comptime = true;
var first_block_index = block.instructions.items.len;
+ var make_runtime = false;
// Collect the comptime element values in case the array literal ends up
// being comptime-known.
@@ -4326,7 +4347,7 @@ fn zirValidateArrayInit(
array_is_comptime = false;
continue;
}
- if (try sema.resolveMaybeUndefValAllowVariables(block, elem_src, bin_op.rhs)) |val| {
+ if (try sema.resolveMaybeUndefValAllowVariablesMaybeRuntime(block, elem_src, bin_op.rhs, &make_runtime)) |val| {
element_vals[i] = val;
} else {
array_is_comptime = false;
@@ -4352,7 +4373,7 @@ fn zirValidateArrayInit(
array_is_comptime = false;
continue;
}
- if (try sema.resolveMaybeUndefValAllowVariables(block, elem_src, bin_op.rhs)) |val| {
+ if (try sema.resolveMaybeUndefValAllowVariablesMaybeRuntime(block, elem_src, bin_op.rhs, &make_runtime)) |val| {
element_vals[i] = val;
} else {
array_is_comptime = false;
@@ -4383,7 +4404,8 @@ fn zirValidateArrayInit(
block.instructions.shrinkRetainingCapacity(first_block_index);
- const array_val = try Value.Tag.aggregate.create(sema.arena, element_vals);
+ var array_val = try Value.Tag.aggregate.create(sema.arena, element_vals);
+ if (make_runtime) array_val = try Value.Tag.runtime_value.create(sema.arena, array_val);
const array_init = try sema.addConstant(array_ty, array_val);
try sema.storePtr2(block, init_src, array_ptr, init_src, array_init, init_src, .store);
}
@@ -6635,20 +6657,14 @@ fn analyzeInlineCallArg(
.ty = param_ty,
.val = arg_val,
};
- } else if (((try sema.resolveMaybeUndefVal(arg_block, arg_src, casted_arg)) == null) or
- try sema.typeRequiresComptime(param_ty) or zir_tags[inst] == .param_comptime)
- {
+ } else if (zir_tags[inst] == .param_comptime or try sema.typeRequiresComptime(param_ty)) {
try sema.inst_map.putNoClobber(sema.gpa, inst, casted_arg);
- } else {
+ } else if (try sema.resolveMaybeUndefVal(arg_block, arg_src, casted_arg)) |val| {
// We have a comptime value but we need a runtime value to preserve inlining semantics,
- const ptr_type = try Type.ptr(sema.arena, sema.mod, .{
- .pointee_type = param_ty,
- .@"addrspace" = target_util.defaultAddressSpace(sema.mod.getTarget(), .local),
- });
- const alloc = try arg_block.addTy(.alloc, ptr_type);
- _ = try arg_block.addBinOp(.store, alloc, casted_arg);
- const loaded = try arg_block.addTyOp(.load, param_ty, alloc);
- try sema.inst_map.putNoClobber(sema.gpa, inst, loaded);
+ const wrapped = try sema.addConstant(param_ty, try Value.Tag.runtime_value.create(sema.arena, val));
+ try sema.inst_map.putNoClobber(sema.gpa, inst, wrapped);
+ } else {
+ try sema.inst_map.putNoClobber(sema.gpa, inst, casted_arg);
}
arg_i.* += 1;
@@ -6685,20 +6701,14 @@ fn analyzeInlineCallArg(
.ty = sema.typeOf(uncasted_arg),
.val = arg_val,
};
- } else if ((try sema.resolveMaybeUndefVal(arg_block, arg_src, uncasted_arg)) == null or
- try sema.typeRequiresComptime(param_ty) or zir_tags[inst] == .param_anytype_comptime)
- {
+ } else if (zir_tags[inst] == .param_anytype_comptime or try sema.typeRequiresComptime(param_ty)) {
try sema.inst_map.putNoClobber(sema.gpa, inst, uncasted_arg);
- } else {
+ } else if (try sema.resolveMaybeUndefVal(arg_block, arg_src, uncasted_arg)) |val| {
// We have a comptime value but we need a runtime value to preserve inlining semantics,
- const ptr_type = try Type.ptr(sema.arena, sema.mod, .{
- .pointee_type = param_ty,
- .@"addrspace" = target_util.defaultAddressSpace(sema.mod.getTarget(), .local),
- });
- const alloc = try arg_block.addTy(.alloc, ptr_type);
- _ = try arg_block.addBinOp(.store, alloc, uncasted_arg);
- const loaded = try arg_block.addTyOp(.load, param_ty, alloc);
- try sema.inst_map.putNoClobber(sema.gpa, inst, loaded);
+ const wrapped = try sema.addConstant(param_ty, try Value.Tag.runtime_value.create(sema.arena, val));
+ try sema.inst_map.putNoClobber(sema.gpa, inst, wrapped);
+ } else {
+ try sema.inst_map.putNoClobber(sema.gpa, inst, uncasted_arg);
}
arg_i.* += 1;
@@ -14826,7 +14836,7 @@ fn zirBuiltinSrc(
// fn_name: [:0]const u8,
field_values[1] = func_name_val;
// line: u32
- field_values[2] = try Value.Tag.runtime_int.create(sema.arena, extra.line + 1);
+ field_values[2] = try Value.Tag.runtime_value.create(sema.arena, try Value.Tag.int_u64.create(sema.arena, extra.line + 1));
// column: u32,
field_values[3] = try Value.Tag.int_u64.create(sema.arena, extra.column + 1);
src/TypedValue.zig
@@ -477,6 +477,6 @@ pub fn print(
},
.generic_poison_type => return writer.writeAll("(generic poison type)"),
.generic_poison => return writer.writeAll("(generic poison)"),
- .runtime_int => return writer.writeAll("[runtime value]"),
+ .runtime_value => return writer.writeAll("[runtime value]"),
};
}
src/value.zig
@@ -111,10 +111,12 @@ pub const Value = extern union {
int_i64,
int_big_positive,
int_big_negative,
- runtime_int,
function,
extern_fn,
variable,
+ /// A wrapper for values which are comptime-known but should
+ /// semantically be runtime-known.
+ runtime_value,
/// Represents a pointer to a Decl.
/// When machine codegen backend sees this, it must set the Decl's `alive` field to true.
decl_ref,
@@ -282,6 +284,7 @@ pub const Value = extern union {
.eu_payload,
.opt_payload,
.empty_array_sentinel,
+ .runtime_value,
=> Payload.SubValue,
.eu_payload_ptr,
@@ -305,7 +308,6 @@ pub const Value = extern union {
.int_type => Payload.IntType,
.int_u64 => Payload.U64,
.int_i64 => Payload.I64,
- .runtime_int => Payload.U64,
.function => Payload.Function,
.variable => Payload.Variable,
.decl_ref_mut => Payload.DeclRefMut,
@@ -485,7 +487,6 @@ pub const Value = extern union {
},
.int_type => return self.copyPayloadShallow(arena, Payload.IntType),
.int_u64 => return self.copyPayloadShallow(arena, Payload.U64),
- .runtime_int => return self.copyPayloadShallow(arena, Payload.U64),
.int_i64 => return self.copyPayloadShallow(arena, Payload.I64),
.int_big_positive, .int_big_negative => {
const old_payload = self.cast(Payload.BigInt).?;
@@ -567,6 +568,7 @@ pub const Value = extern union {
.eu_payload,
.opt_payload,
.empty_array_sentinel,
+ .runtime_value,
=> {
const payload = self.cast(Payload.SubValue).?;
const new_payload = try arena.create(Payload.SubValue);
@@ -765,7 +767,7 @@ pub const Value = extern union {
.int_i64 => return std.fmt.formatIntValue(val.castTag(.int_i64).?.data, "", options, out_stream),
.int_big_positive => return out_stream.print("{}", .{val.castTag(.int_big_positive).?.asBigInt()}),
.int_big_negative => return out_stream.print("{}", .{val.castTag(.int_big_negative).?.asBigInt()}),
- .runtime_int => return out_stream.writeAll("[runtime value]"),
+ .runtime_value => return out_stream.writeAll("[runtime value]"),
.function => return out_stream.print("(function decl={d})", .{val.castTag(.function).?.data.owner_decl}),
.extern_fn => return out_stream.writeAll("(extern function)"),
.variable => return out_stream.writeAll("(variable)"),
@@ -1081,8 +1083,6 @@ pub const Value = extern union {
.int_big_positive => return val.castTag(.int_big_positive).?.asBigInt(),
.int_big_negative => return val.castTag(.int_big_negative).?.asBigInt(),
- .runtime_int => return BigIntMutable.init(&space.limbs, val.castTag(.runtime_int).?.data).toConst(),
-
.undef => unreachable,
.lazy_align => {
@@ -1138,8 +1138,6 @@ pub const Value = extern union {
.int_big_positive => return val.castTag(.int_big_positive).?.asBigInt().to(u64) catch null,
.int_big_negative => return val.castTag(.int_big_negative).?.asBigInt().to(u64) catch null,
- .runtime_int => return val.castTag(.runtime_int).?.data,
-
.undef => unreachable,
.lazy_align => {
@@ -2357,6 +2355,8 @@ pub const Value = extern union {
const zig_ty_tag = ty.zigTypeTag();
std.hash.autoHash(hasher, zig_ty_tag);
if (val.isUndef()) return;
+ // The value is runtime-known and shouldn't affect the hash.
+ if (val.tag() == .runtime_value) return;
switch (zig_ty_tag) {
.BoundFn => unreachable, // TODO remove this from the language
@@ -2632,9 +2632,6 @@ pub const Value = extern union {
.lazy_size,
=> return hashInt(ptr_val, hasher, target),
- // The value is runtime-known and shouldn't affect the hash.
- .runtime_int => {},
-
else => unreachable,
}
}
test/behavior/bugs/13164.zig
@@ -10,6 +10,7 @@ inline fn setLimits(min: ?u32, max: ?u32) !void {
test {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
var x: u32 = 42;
try setLimits(x, null);
test/behavior/vector.zig
@@ -1135,3 +1135,40 @@ test "array of vectors is copied" {
points2[0..points.len].* = points;
try std.testing.expectEqual(points2[6], Vec3{ -345, -311, 381 });
}
+
+test "byte vector initialized in inline function" {
+ if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
+
+ const S = struct {
+ inline fn boolx4(e0: bool, e1: bool, e2: bool, e3: bool) @Vector(4, bool) {
+ return .{ e0, e1, e2, e3 };
+ }
+
+ fn all(vb: @Vector(4, bool)) bool {
+ return @reduce(.And, vb);
+ }
+ };
+
+ try expect(S.all(S.boolx4(true, true, true, true)));
+}
+
+test "byte vector initialized in inline function" {
+ // TODO https://github.com/ziglang/zig/issues/13279
+ if (true) return error.SkipZigTest;
+
+ const S = struct {
+ fn boolx4(e0: bool, e1: bool, e2: bool, e3: bool) @Vector(4, bool) {
+ return .{ e0, e1, e2, e3 };
+ }
+
+ fn all(vb: @Vector(4, bool)) bool {
+ return @reduce(.And, vb);
+ }
+ };
+
+ try expect(S.all(S.boolx4(true, true, true, true)));
+}