From f0e66ac4d0e6347bf1b5a00b309fafb5da84191b Mon Sep 17 00:00:00 2001 From: Cody Tapscott Date: Fri, 21 Oct 2022 19:20:58 -0700 Subject: std.Target: Remove `longDoubleIs` This function is redundant with CType.sizeInBits(), and until the previous commit they disagreed about the correct long double type for several targets. Although they're all synced up now, it's much simpler just to have a single source of truth. --- src/codegen/llvm.zig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/codegen') diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index b0d1588007..68e969f9e7 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -10615,8 +10615,8 @@ fn backendSupportsF128(target: std.Target) bool { fn intrinsicsAllowed(scalar_ty: Type, target: std.Target) bool { return switch (scalar_ty.tag()) { .f16 => backendSupportsF16(target), - .f80 => target.longDoubleIs(f80) and backendSupportsF80(target), - .f128 => target.longDoubleIs(f128) and backendSupportsF128(target), + .f80 => (CType.longdouble.sizeInBits(target) == 80) and backendSupportsF80(target), + .f128 => (CType.longdouble.sizeInBits(target) == 128) and backendSupportsF128(target), else => true, }; } -- cgit v1.2.3 From dd437ae39948031dc04836f245c8b77d459a428a Mon Sep 17 00:00:00 2001 From: Veikka Tuominen Date: Mon, 24 Oct 2022 14:41:22 +0300 Subject: stage2: optimize size of optional slices --- src/codegen/c.zig | 14 +++++++++----- src/codegen/llvm.zig | 10 ++++++++-- src/type.zig | 46 ++++++++-------------------------------------- test/behavior/cast.zig | 4 ++++ test/behavior/optional.zig | 16 ++++++++++++++++ 5 files changed, 45 insertions(+), 45 deletions(-) (limited to 'src/codegen') diff --git a/src/codegen/c.zig b/src/codegen/c.zig index d6584d75ae..5f6f2fd6d5 100644 --- a/src/codegen/c.zig +++ b/src/codegen/c.zig @@ -726,7 +726,11 @@ pub const DeclGen = struct { } if (ty.optionalReprIsPayload()) { - return dg.renderValue(writer, payload_ty, val, location); + if (val.castTag(.opt_payload)) |payload| { + return dg.renderValue(writer, payload_ty, payload.data, location); + } else { + return dg.renderValue(writer, payload_ty, val, location); + } } try writer.writeByte('('); @@ -3263,11 +3267,9 @@ fn airIsNull( try f.writeCValue(writer, operand); const ty = f.air.typeOf(un_op); + const opt_ty = if (deref_suffix[0] != 0) ty.childType() else ty; var opt_buf: Type.Payload.ElemType = undefined; - const payload_ty = if (deref_suffix[0] != 0) - ty.childType().optionalChild(&opt_buf) - else - ty.optionalChild(&opt_buf); + const payload_ty = opt_ty.optionalChild(&opt_buf); if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { try writer.print("){s} {s} true;\n", .{ deref_suffix, operator }); @@ -3276,6 +3278,8 @@ fn airIsNull( try writer.print("){s} {s} NULL;\n", .{ deref_suffix, operator }); } else if (payload_ty.zigTypeTag() == .ErrorSet) { try writer.print("){s} {s} 0;\n", .{ deref_suffix, operator }); + } else if (payload_ty.isSlice() and opt_ty.optionalReprIsPayload()) { + try writer.print("){s}.ptr {s} NULL;\n", .{ deref_suffix, operator }); } else { try writer.print("){s}.is_null {s} true;\n", .{ deref_suffix, operator }); } diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index ffc19cb6f6..d4a94d1308 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -6316,18 +6316,24 @@ pub const FuncGen = struct { const operand_ty = self.air.typeOf(un_op); const optional_ty = if (operand_is_ptr) operand_ty.childType() else operand_ty; const optional_llvm_ty = try self.dg.lowerType(optional_ty); + var buf: Type.Payload.ElemType = undefined; + const payload_ty = optional_ty.optionalChild(&buf); if (optional_ty.optionalReprIsPayload()) { const loaded = if (operand_is_ptr) self.builder.buildLoad(optional_llvm_ty, operand, "") else operand; + if (payload_ty.isSlice()) { + const slice_ptr = self.builder.buildExtractValue(loaded, 0, ""); + var slice_buf: Type.SlicePtrFieldTypeBuffer = undefined; + const ptr_ty = try self.dg.lowerType(payload_ty.slicePtrFieldType(&slice_buf)); + return self.builder.buildICmp(pred, slice_ptr, ptr_ty.constNull(), ""); + } return self.builder.buildICmp(pred, loaded, optional_llvm_ty.constNull(), ""); } comptime assert(optional_layout_version == 3); - var buf: Type.Payload.ElemType = undefined; - const payload_ty = optional_ty.optionalChild(&buf); if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { const loaded = if (operand_is_ptr) self.builder.buildLoad(optional_llvm_ty, operand, "") diff --git a/src/type.zig b/src/type.zig index a2f0bb9e8f..8904b3178d 100644 --- a/src/type.zig +++ b/src/type.zig @@ -3469,20 +3469,8 @@ pub const Type = extern union { if (!child_type.hasRuntimeBits()) return AbiSizeAdvanced{ .scalar = 1 }; - switch (child_type.zigTypeTag()) { - .Pointer => { - const ptr_info = child_type.ptrInfo().data; - const has_null = switch (ptr_info.size) { - .Slice, .C => true, - else => ptr_info.@"allowzero", - }; - if (!has_null) { - const ptr_size_bytes = @divExact(target.cpu.arch.ptrBitWidth(), 8); - return AbiSizeAdvanced{ .scalar = ptr_size_bytes }; - } - }, - .ErrorSet => return abiSizeAdvanced(Type.anyerror, target, strat), - else => {}, + if (ty.optionalReprIsPayload()) { + return abiSizeAdvanced(child_type, target, strat); } const payload_size = switch (try child_type.abiSizeAdvanced(target, strat)) { @@ -3747,28 +3735,10 @@ pub const Type = extern union { .int_signed, .int_unsigned => return ty.cast(Payload.Bits).?.data, - .optional => { - var buf: Payload.ElemType = undefined; - const child_type = ty.optionalChild(&buf); - if (!child_type.hasRuntimeBits()) return 8; - - if (child_type.zigTypeTag() == .Pointer and !child_type.isCPtr() and !child_type.isSlice()) - return target.cpu.arch.ptrBitWidth(); - - // Optional types are represented as a struct with the child type as the first - // field and a boolean as the second. Since the child type's abi alignment is - // guaranteed to be >= that of bool's (1 byte) the added size is exactly equal - // to the child type's ABI alignment. - const child_bit_size = try bitSizeAdvanced(child_type, target, sema_kit); - return child_bit_size + 1; - }, - - .error_union => { - const payload = ty.castTag(.error_union).?.data; - if (!payload.payload.hasRuntimeBits()) { - return payload.error_set.bitSizeAdvanced(target, sema_kit); - } - @panic("TODO bitSize error union"); + .optional, .error_union => { + // Optionals and error unions are not packed so their bitsize + // includes padding bits. + return (try abiSizeAdvanced(ty, target, if (sema_kit) |sk| .{ .sema_kit = sk } else .eager)).scalar * 8; }, .atomic_order, @@ -4045,8 +4015,8 @@ pub const Type = extern union { .Pointer => { const info = child_ty.ptrInfo().data; switch (info.size) { - .Slice, .C => return false, - .Many, .One => return !info.@"allowzero", + .C => return false, + .Slice, .Many, .One => return !info.@"allowzero", } }, .ErrorSet => return true, diff --git a/test/behavior/cast.zig b/test/behavior/cast.zig index 9a02e74853..cb76f86820 100644 --- a/test/behavior/cast.zig +++ b/test/behavior/cast.zig @@ -1170,6 +1170,7 @@ test "implicitly cast from [N]T to ?[]const T" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO try expect(mem.eql(u8, castToOptionalSlice().?, "hi")); comptime try expect(mem.eql(u8, castToOptionalSlice().?, "hi")); @@ -1256,6 +1257,7 @@ test "*const [N]null u8 to ?[]const u8" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO const S = struct { fn doTheTest() !void { @@ -1394,6 +1396,8 @@ test "cast i8 fn call peers to i32 result" { test "cast compatible optional types" { 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_c) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO var a: ?[:0]const u8 = null; var b: ?[]const u8 = a; diff --git a/test/behavior/optional.zig b/test/behavior/optional.zig index eb693147e6..9c9211f777 100644 --- a/test/behavior/optional.zig +++ b/test/behavior/optional.zig @@ -3,6 +3,7 @@ const std = @import("std"); const testing = std.testing; const expect = testing.expect; const expectEqual = testing.expectEqual; +const expectEqualStrings = std.testing.expectEqualStrings; test "passing an optional integer as a parameter" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; @@ -428,3 +429,18 @@ test "alignment of wrapping an optional payload" { }; try expect(S.foo().?.x == 1234); } + +test "Optional slice size is optimized" { + if (builtin.zig_backend == .stage1) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; + + try expect(@sizeOf(?[]u8) == @sizeOf([]u8)); + var a: ?[]const u8 = null; + try expect(a == null); + a = "hello"; + try expectEqualStrings(a.?, "hello"); +} -- cgit v1.2.3 From 78a7bb108ad9f7bf59061675bcae8947d65afc3a Mon Sep 17 00:00:00 2001 From: Veikka Tuominen Date: Mon, 24 Oct 2022 14:46:14 +0300 Subject: llvm: handle namespace like packed structs Closes #13159 Closes #13188 --- src/codegen/llvm.zig | 2 +- test/behavior.zig | 1 + test/behavior/bugs/13159.zig | 14 ++++++++++++++ 3 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 test/behavior/bugs/13159.zig (limited to 'src/codegen') diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index d4a94d1308..18b89eef78 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -1916,7 +1916,7 @@ pub const Object = struct { if (ty.castTag(.@"struct")) |payload| { const struct_obj = payload.data; - if (struct_obj.layout == .Packed) { + if (struct_obj.layout == .Packed and struct_obj.haveFieldTypes()) { const info = struct_obj.backing_int_ty.intInfo(target); const dwarf_encoding: c_uint = switch (info.signedness) { .signed => DW.ATE.signed, diff --git a/test/behavior.zig b/test/behavior.zig index 2f5d752087..442b27c09f 100644 --- a/test/behavior.zig +++ b/test/behavior.zig @@ -109,6 +109,7 @@ test { _ = @import("behavior/bugs/13128.zig"); _ = @import("behavior/bugs/13164.zig"); _ = @import("behavior/bugs/13171.zig"); + _ = @import("behavior/bugs/13159.zig"); _ = @import("behavior/byteswap.zig"); _ = @import("behavior/byval_arg_var.zig"); _ = @import("behavior/call.zig"); diff --git a/test/behavior/bugs/13159.zig b/test/behavior/bugs/13159.zig new file mode 100644 index 0000000000..6119c498a9 --- /dev/null +++ b/test/behavior/bugs/13159.zig @@ -0,0 +1,14 @@ +const std = @import("std"); +const expect = std.testing.expect; + +const Bar = packed struct { + const Baz = enum { + fizz, + buzz, + }; +}; + +test { + var foo = Bar.Baz.fizz; + try expect(foo == .fizz); +} -- cgit v1.2.3 From 595ccecd88d82874e7f677ee1809c04fc29424ff Mon Sep 17 00:00:00 2001 From: Veikka Tuominen Date: Tue, 25 Oct 2022 16:10:09 +0300 Subject: llvm: do not return undefined pointers from array_to_slice --- src/codegen/llvm.zig | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'src/codegen') diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index 18b89eef78..2eb95dc5e3 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -5434,10 +5434,11 @@ pub const FuncGen = struct { const llvm_usize = try self.dg.lowerType(Type.usize); const len = llvm_usize.constInt(array_ty.arrayLen(), .False); const slice_llvm_ty = try self.dg.lowerType(self.air.typeOfIndex(inst)); + const operand = try self.resolveInst(ty_op.operand); if (!array_ty.hasRuntimeBitsIgnoreComptime()) { - return self.builder.buildInsertValue(slice_llvm_ty.getUndef(), len, 1, ""); + const partial = self.builder.buildInsertValue(slice_llvm_ty.getUndef(), operand, 0, ""); + return self.builder.buildInsertValue(partial, len, 1, ""); } - const operand = try self.resolveInst(ty_op.operand); const indices: [2]*llvm.Value = .{ llvm_usize.constNull(), llvm_usize.constNull(), }; -- cgit v1.2.3 From f3a3fb3d880528e8b6404648c605ed092ef1412c Mon Sep 17 00:00:00 2001 From: Veikka Tuominen Date: Thu, 27 Oct 2022 00:23:43 +0300 Subject: llvm: pass optional slices like regular slices --- src/codegen/llvm.zig | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) (limited to 'src/codegen') diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index 2eb95dc5e3..2660b19bf3 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -1027,7 +1027,9 @@ pub const Object = struct { dg.addArgAttr(llvm_func, llvm_arg_i, "noalias"); } } - dg.addArgAttr(llvm_func, llvm_arg_i, "nonnull"); + if (param_ty.zigTypeTag() != .Optional) { + dg.addArgAttr(llvm_func, llvm_arg_i, "nonnull"); + } if (!ptr_info.mutable) { dg.addArgAttr(llvm_func, llvm_arg_i, "readonly"); } @@ -3117,7 +3119,11 @@ pub const DeclGen = struct { .slice => { const param_ty = fn_info.param_types[it.zig_index - 1]; var buf: Type.SlicePtrFieldTypeBuffer = undefined; - const ptr_ty = param_ty.slicePtrFieldType(&buf); + var opt_buf: Type.Payload.ElemType = undefined; + const ptr_ty = if (param_ty.zigTypeTag() == .Optional) + param_ty.optionalChild(&opt_buf).slicePtrFieldType(&buf) + else + param_ty.slicePtrFieldType(&buf); const ptr_llvm_ty = try dg.lowerType(ptr_ty); const len_llvm_ty = try dg.lowerType(Type.usize); @@ -10358,7 +10364,8 @@ const ParamTypeIterator = struct { .Unspecified, .Inline => { it.zig_index += 1; it.llvm_index += 1; - if (ty.isSlice()) { + var buf: Type.Payload.ElemType = undefined; + if (ty.isSlice() or (ty.zigTypeTag() == .Optional and ty.optionalChild(&buf).isSlice())) { return .slice; } else if (isByRef(ty)) { return .byref; -- cgit v1.2.3 From d03c47bf85b17f7727d2f1fe5bd497b311c9eba7 Mon Sep 17 00:00:00 2001 From: Veikka Tuominen Date: Wed, 26 Oct 2022 00:30:17 +0300 Subject: Sema: use `runtime_value` instead of creating allocs --- src/Sema.zig | 76 +++++++++++++++++++++++++------------------- src/TypedValue.zig | 2 +- src/arch/aarch64/CodeGen.zig | 6 +++- src/arch/arm/CodeGen.zig | 6 +++- src/arch/wasm/CodeGen.zig | 6 +++- src/arch/x86_64/CodeGen.zig | 6 +++- src/codegen.zig | 7 +++- src/codegen/c.zig | 6 +++- src/codegen/llvm.zig | 6 +++- src/value.zig | 19 +++++------ test/behavior/bugs/13164.zig | 1 + test/behavior/vector.zig | 37 +++++++++++++++++++++ 12 files changed, 126 insertions(+), 52 deletions(-) (limited to 'src/codegen') diff --git a/src/Sema.zig b/src/Sema.zig index 4c2f72034e..931e06724b 100644 --- a/src/Sema.zig +++ b/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); diff --git a/src/TypedValue.zig b/src/TypedValue.zig index ba32e55f1e..619fb003f9 100644 --- a/src/TypedValue.zig +++ b/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]"), }; } diff --git a/src/arch/aarch64/CodeGen.zig b/src/arch/aarch64/CodeGen.zig index eb8ca8e8f1..3bb5bbe0d3 100644 --- a/src/arch/aarch64/CodeGen.zig +++ b/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 = {} }; diff --git a/src/arch/arm/CodeGen.zig b/src/arch/arm/CodeGen.zig index 1ebc348fc2..67cf899dc3 100644 --- a/src/arch/arm/CodeGen.zig +++ b/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 = {} }; diff --git a/src/arch/wasm/CodeGen.zig b/src/arch/wasm/CodeGen.zig index 538fcb13c1..69d5e38f65 100644 --- a/src/arch/wasm/CodeGen.zig +++ b/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; diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig index 5f793aaeb9..965a34251c 100644 --- a/src/arch/x86_64/CodeGen.zig +++ b/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 = {} }; diff --git a/src/codegen.zig b/src/codegen.zig index e7f927a2d6..757bd23b38 100644 --- a/src/codegen.zig +++ b/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(); diff --git a/src/codegen/c.zig b/src/codegen/c.zig index d6584d75ae..d0f76f0390 100644 --- a/src/codegen/c.zig +++ b/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()) { diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index ffc19cb6f6..938770629f 100644 --- a/src/codegen/llvm.zig +++ b/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(); diff --git a/src/value.zig b/src/value.zig index d24c5a1c17..28601c1723 100644 --- a/src/value.zig +++ b/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, } } diff --git a/test/behavior/bugs/13164.zig b/test/behavior/bugs/13164.zig index ee9fe1c120..37f5bdf805 100644 --- a/test/behavior/bugs/13164.zig +++ b/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); diff --git a/test/behavior/vector.zig b/test/behavior/vector.zig index 80fa2021d8..22e12d0808 100644 --- a/test/behavior/vector.zig +++ b/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))); +} -- cgit v1.2.3