Merge pull request #22672 from jacobly0/x86_64-rewrite

x86_64: rewrite float conversions
This commit is contained in:
Andrew Kelley 2025-02-01 14:32:43 -08:00 committed by GitHub
commit 963651bbf2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
27 changed files with 14415 additions and 2023 deletions

View File

@ -450,7 +450,7 @@ pub fn build(b: *std.Build) !void {
.skip_non_native = skip_non_native,
.skip_libc = skip_libc,
.use_llvm = use_llvm,
.max_rss = 1 * 1024 * 1024 * 1024,
.max_rss = 1.25 * 1024 * 1024 * 1024,
}));
test_modules_step.dependOn(tests.addModuleTests(b, .{

View File

@ -2114,7 +2114,7 @@ pub const Inst = struct {
ref_start_index = static_len,
_,
pub const static_len = 92;
pub const static_len = 93;
pub fn toRef(i: Index) Inst.Ref {
return @enumFromInt(@intFromEnum(Index.ref_start_index) + @intFromEnum(i));
@ -2215,6 +2215,7 @@ pub const Inst = struct {
vector_4_u64_type,
vector_4_f16_type,
vector_8_f16_type,
vector_2_f32_type,
vector_4_f32_type,
vector_8_f32_type,
vector_2_f64_type,

View File

@ -266,7 +266,8 @@ pub const Inst = struct {
/// Boolean or binary NOT.
/// Uses the `ty_op` field.
not,
/// Reinterpret the memory representation of a value as a different type.
/// Reinterpret the bits of a value as a different type. This is like `@bitCast` but
/// also supports enums and pointers.
/// Uses the `ty_op` field.
bitcast,
/// Uses the `ty_pl` field with payload `Block`. A block runs its body which always ends
@ -517,14 +518,6 @@ pub const Inst = struct {
/// Read a value from a pointer.
/// Uses the `ty_op` field.
load,
/// Converts a pointer to its address. Result type is always `usize`.
/// Pointer type size may be any, including slice.
/// Uses the `un_op` field.
int_from_ptr,
/// Given a boolean, returns 0 or 1.
/// Result type is always `u1`.
/// Uses the `un_op` field.
int_from_bool,
/// Return a value from a function.
/// Result type is always noreturn; no instructions in a block follow this one.
/// Uses the `un_op` field.
@ -1008,6 +1001,7 @@ pub const Inst = struct {
vector_4_u64_type = @intFromEnum(InternPool.Index.vector_4_u64_type),
vector_4_f16_type = @intFromEnum(InternPool.Index.vector_4_f16_type),
vector_8_f16_type = @intFromEnum(InternPool.Index.vector_8_f16_type),
vector_2_f32_type = @intFromEnum(InternPool.Index.vector_2_f32_type),
vector_4_f32_type = @intFromEnum(InternPool.Index.vector_4_f32_type),
vector_8_f32_type = @intFromEnum(InternPool.Index.vector_8_f32_type),
vector_2_f64_type = @intFromEnum(InternPool.Index.vector_2_f64_type),
@ -1542,7 +1536,6 @@ pub fn typeOfIndex(air: *const Air, inst: Air.Inst.Index, ip: *const InternPool)
.c_va_end,
=> return Type.void,
.int_from_ptr,
.slice_len,
.ret_addr,
.frame_addr,
@ -1552,8 +1545,6 @@ pub fn typeOfIndex(air: *const Air, inst: Air.Inst.Index, ip: *const InternPool)
.wasm_memory_grow => return Type.isize,
.wasm_memory_size => return Type.usize,
.int_from_bool => return Type.u1,
.tag_name, .error_name => return Type.slice_const_u8_sentinel_0,
.call, .call_always_tail, .call_never_tail, .call_never_inline => {
@ -1815,8 +1806,6 @@ pub fn mustLower(air: Air, inst: Air.Inst.Index, ip: *const InternPool) bool {
.is_non_err_ptr,
.bool_and,
.bool_or,
.int_from_ptr,
.int_from_bool,
.fptrunc,
.fpext,
.intcast,

View File

@ -208,8 +208,6 @@ fn checkBody(air: Air, body: []const Air.Inst.Index, zcu: *Zcu) bool {
.is_non_err,
.is_err_ptr,
.is_non_err_ptr,
.int_from_ptr,
.int_from_bool,
.ret,
.ret_safe,
.ret_load,

View File

@ -4593,6 +4593,7 @@ pub const Index = enum(u32) {
vector_4_u64_type,
vector_4_f16_type,
vector_8_f16_type,
vector_2_f32_type,
vector_4_f32_type,
vector_8_f32_type,
vector_2_f64_type,
@ -5124,6 +5125,8 @@ pub const static_keys = [_]Key{
.{ .vector_type = .{ .len = 4, .child = .f16_type } },
// @Vector(8, f16)
.{ .vector_type = .{ .len = 8, .child = .f16_type } },
// @Vector(2, f32)
.{ .vector_type = .{ .len = 2, .child = .f32_type } },
// @Vector(4, f32)
.{ .vector_type = .{ .len = 4, .child = .f32_type } },
// @Vector(8, f32)
@ -11778,6 +11781,7 @@ pub fn typeOf(ip: *const InternPool, index: Index) Index {
.vector_4_u64_type,
.vector_4_f16_type,
.vector_8_f16_type,
.vector_2_f32_type,
.vector_4_f32_type,
.vector_8_f32_type,
.vector_2_f64_type,
@ -12117,6 +12121,7 @@ pub fn zigTypeTag(ip: *const InternPool, index: Index) std.builtin.TypeId {
.vector_4_u64_type,
.vector_4_f16_type,
.vector_8_f16_type,
.vector_2_f32_type,
.vector_4_f32_type,
.vector_8_f32_type,
.vector_2_f64_type,

View File

@ -402,8 +402,6 @@ pub fn categorizeOperand(
.is_non_err,
.is_err_ptr,
.is_non_err_ptr,
.int_from_ptr,
.int_from_bool,
.is_named_enum_value,
.tag_name,
.error_name,
@ -1028,8 +1026,6 @@ fn analyzeInst(
.is_non_err,
.is_err_ptr,
.is_non_err_ptr,
.int_from_ptr,
.int_from_bool,
.is_named_enum_value,
.tag_name,
.error_name,

View File

@ -130,8 +130,6 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void {
.is_non_err,
.is_err_ptr,
.is_non_err_ptr,
.int_from_ptr,
.int_from_bool,
.is_named_enum_value,
.tag_name,
.error_name,

View File

@ -10038,6 +10038,8 @@ fn zirIntFromPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!
};
return sema.failWithOwnedErrorMsg(block, msg);
}
const len = if (is_vector) operand_ty.vectorLen(zcu) else undefined;
const dest_ty: Type = if (is_vector) try pt.vectorType(.{ .child = .usize_type, .len = len }) else .usize;
if (try sema.resolveValueIntable(operand)) |operand_val| ct: {
if (!is_vector) {
if (operand_val.isUndef(zcu)) {
@ -10048,8 +10050,6 @@ fn zirIntFromPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!
(try operand_val.toUnsignedIntSema(pt)),
)).toIntern());
}
const len = operand_ty.vectorLen(zcu);
const dest_ty = try pt.vectorType(.{ .child = .usize_type, .len = len });
const new_elems = try sema.arena.alloc(InternPool.Index, len);
for (new_elems, 0..) |*new_elem, i| {
const ptr_val = try operand_val.elemValue(pt, i);
@ -10073,16 +10073,14 @@ fn zirIntFromPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!
}
try sema.requireRuntimeBlock(block, block.nodeOffset(inst_data.src_node), ptr_src);
try sema.validateRuntimeValue(block, ptr_src, operand);
if (!is_vector) {
return block.addUnOp(.int_from_ptr, operand);
if (!is_vector or zcu.backendSupportsFeature(.all_vector_instructions)) {
return block.addBitCast(dest_ty, operand);
}
const len = operand_ty.vectorLen(zcu);
const dest_ty = try pt.vectorType(.{ .child = .usize_type, .len = len });
const new_elems = try sema.arena.alloc(Air.Inst.Ref, len);
for (new_elems, 0..) |*new_elem, i| {
const idx_ref = try pt.intRef(Type.usize, i);
const old_elem = try block.addBinOp(.array_elem_val, operand, idx_ref);
new_elem.* = try block.addUnOp(.int_from_ptr, old_elem);
new_elem.* = try block.addBitCast(.usize, old_elem);
}
return block.addAggregateInit(dest_ty, new_elems);
}
@ -10569,7 +10567,7 @@ fn zirFloatCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
if (dst_bits >= src_bits) {
return sema.coerce(block, dest_ty, operand, operand_src);
}
if (!is_vector) {
if (!is_vector or zcu.backendSupportsFeature(.all_vector_instructions)) {
return block.addTyOp(.fptrunc, dest_ty, operand);
}
const vec_len = operand_ty.vectorLen(zcu);
@ -14746,7 +14744,7 @@ fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
});
const many_ty = slice_ty.slicePtrFieldType(zcu);
const many_alloc = try block.addTyOp(.bitcast, many_ty, mutable_alloc);
const many_alloc = try block.addBitCast(many_ty, mutable_alloc);
// lhs_dest_slice = dest[0..lhs.len]
const slice_ty_ref = Air.internedToRef(slice_ty.toIntern());
@ -14796,7 +14794,7 @@ fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
try sema.storePtr2(block, src, elem_ptr, src, init, lhs_src, .store);
}
return block.addTyOp(.bitcast, constant_alloc_ty, mutable_alloc);
return block.addBitCast(constant_alloc_ty, mutable_alloc);
}
var elem_i: u32 = 0;
@ -14829,7 +14827,7 @@ fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
try sema.storePtr2(block, src, elem_ptr, src, init, lhs_src, .store);
}
return block.addTyOp(.bitcast, constant_alloc_ty, mutable_alloc);
return block.addBitCast(constant_alloc_ty, mutable_alloc);
}
const element_refs = try sema.arena.alloc(Air.Inst.Ref, result_len);
@ -16596,8 +16594,8 @@ fn analyzeArithmetic(
};
try sema.requireRuntimeBlock(block, src, runtime_src);
const lhs_int = try block.addUnOp(.int_from_ptr, lhs);
const rhs_int = try block.addUnOp(.int_from_ptr, rhs);
const lhs_int = try block.addBitCast(.usize, lhs);
const rhs_int = try block.addBitCast(.usize, rhs);
const address = try block.addBinOp(.sub_wrap, lhs_int, rhs_int);
return try block.addBinOp(.div_exact, address, try pt.intRef(Type.usize, elem_size));
}
@ -21215,14 +21213,14 @@ fn zirIntFromBool(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
if (operand_scalar_ty.toIntern() != .bool_type) {
return sema.fail(block, src, "expected 'bool', found '{}'", .{operand_scalar_ty.zigTypeTag(zcu)});
}
const len = if (is_vector) operand_ty.vectorLen(zcu) else undefined;
const dest_ty: Type = if (is_vector) try pt.vectorType(.{ .child = .u1_type, .len = len }) else .u1;
if (try sema.resolveValue(operand)) |val| {
if (!is_vector) {
if (val.isUndef(zcu)) return pt.undefRef(Type.u1);
if (val.toBool()) return Air.internedToRef((try pt.intValue(Type.u1, 1)).toIntern());
return Air.internedToRef((try pt.intValue(Type.u1, 0)).toIntern());
}
const len = operand_ty.vectorLen(zcu);
const dest_ty = try pt.vectorType(.{ .child = .u1_type, .len = len });
if (val.isUndef(zcu)) return pt.undefRef(dest_ty);
const new_elems = try sema.arena.alloc(InternPool.Index, len);
for (new_elems, 0..) |*new_elem, i| {
@ -21240,16 +21238,14 @@ fn zirIntFromBool(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
.storage = .{ .elems = new_elems },
} }));
}
if (!is_vector) {
return block.addUnOp(.int_from_bool, operand);
if (!is_vector or zcu.backendSupportsFeature(.all_vector_instructions)) {
return block.addBitCast(dest_ty, operand);
}
const len = operand_ty.vectorLen(zcu);
const dest_ty = try pt.vectorType(.{ .child = .u1_type, .len = len });
const new_elems = try sema.arena.alloc(Air.Inst.Ref, len);
for (new_elems, 0..) |*new_elem, i| {
const idx_ref = try pt.intRef(Type.usize, i);
const old_elem = try block.addBinOp(.array_elem_val, operand, idx_ref);
new_elem.* = try block.addUnOp(.int_from_bool, old_elem);
new_elem.* = try block.addBitCast(.u1, old_elem);
}
return block.addAggregateInit(dest_ty, new_elems);
}
@ -22842,14 +22838,27 @@ fn zirIntFromFloat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro
.storage = .{ .repeated_elem = (try pt.intValue(dest_scalar_ty, 0)).toIntern() },
} }));
}
if (!is_vector) {
if (!is_vector or zcu.backendSupportsFeature(.all_vector_instructions)) {
const result = try block.addTyOp(if (block.float_mode == .optimized) .int_from_float_optimized else .int_from_float, dest_ty, operand);
if (block.wantSafety()) {
const back = try block.addTyOp(.float_from_int, operand_ty, result);
const diff = try block.addBinOp(.sub, operand, back);
const ok_pos = try block.addBinOp(if (block.float_mode == .optimized) .cmp_lt_optimized else .cmp_lt, diff, Air.internedToRef((try pt.floatValue(operand_ty, 1.0)).toIntern()));
const ok_neg = try block.addBinOp(if (block.float_mode == .optimized) .cmp_gt_optimized else .cmp_gt, diff, Air.internedToRef((try pt.floatValue(operand_ty, -1.0)).toIntern()));
const ok = try block.addBinOp(.bool_and, ok_pos, ok_neg);
const diff = try block.addBinOp(if (block.float_mode == .optimized) .sub_optimized else .sub, operand, back);
const ok = if (is_vector) ok: {
const ok_pos = try block.addCmpVector(diff, Air.internedToRef((try sema.splat(operand_ty, try pt.floatValue(operand_scalar_ty, 1.0))).toIntern()), .lt);
const ok_neg = try block.addCmpVector(diff, Air.internedToRef((try sema.splat(operand_ty, try pt.floatValue(operand_scalar_ty, -1.0))).toIntern()), .gt);
const ok = try block.addBinOp(.bit_and, ok_pos, ok_neg);
break :ok try block.addInst(.{
.tag = .reduce,
.data = .{ .reduce = .{
.operand = ok,
.operation = .And,
} },
});
} else ok: {
const ok_pos = try block.addBinOp(if (block.float_mode == .optimized) .cmp_lt_optimized else .cmp_lt, diff, Air.internedToRef((try pt.floatValue(operand_ty, 1.0)).toIntern()));
const ok_neg = try block.addBinOp(if (block.float_mode == .optimized) .cmp_gt_optimized else .cmp_gt, diff, Air.internedToRef((try pt.floatValue(operand_ty, -1.0)).toIntern()));
break :ok try block.addBinOp(.bool_and, ok_pos, ok_neg);
};
try sema.addSafetyCheck(block, src, ok, .integer_part_out_of_bounds);
}
return result;
@ -22901,7 +22910,7 @@ fn zirFloatFromInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro
}
try sema.requireRuntimeBlock(block, src, operand_src);
if (!is_vector) {
if (!is_vector or zcu.backendSupportsFeature(.all_vector_instructions)) {
return block.addTyOp(.float_from_int, dest_ty, operand);
}
const len = operand_ty.vectorLen(zcu);
@ -22980,17 +22989,37 @@ fn zirPtrFromInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!
});
}
try sema.requireRuntimeBlock(block, src, operand_src);
if (!is_vector) {
if (!is_vector or zcu.backendSupportsFeature(.all_vector_instructions)) {
if (block.wantSafety() and (try elem_ty.hasRuntimeBitsSema(pt) or elem_ty.zigTypeTag(zcu) == .@"fn")) {
if (!ptr_ty.isAllowzeroPtr(zcu)) {
const is_non_zero = try block.addBinOp(.cmp_neq, operand_coerced, .zero_usize);
const is_non_zero = if (is_vector) all_non_zero: {
const zero_usize = Air.internedToRef((try sema.splat(operand_ty, .zero_usize)).toIntern());
const is_non_zero = try block.addCmpVector(operand_coerced, zero_usize, .neq);
break :all_non_zero try block.addInst(.{
.tag = .reduce,
.data = .{ .reduce = .{
.operand = is_non_zero,
.operation = .And,
} },
});
} else try block.addBinOp(.cmp_neq, operand_coerced, .zero_usize);
try sema.addSafetyCheck(block, src, is_non_zero, .cast_to_null);
}
if (ptr_align.compare(.gt, .@"1")) {
const align_bytes_minus_1 = ptr_align.toByteUnits().? - 1;
const align_minus_1 = Air.internedToRef((try pt.intValue(Type.usize, align_bytes_minus_1)).toIntern());
const align_minus_1 = Air.internedToRef((try sema.splat(operand_ty, try pt.intValue(Type.usize, align_bytes_minus_1))).toIntern());
const remainder = try block.addBinOp(.bit_and, operand_coerced, align_minus_1);
const is_aligned = try block.addBinOp(.cmp_eq, remainder, .zero_usize);
const is_aligned = if (is_vector) all_aligned: {
const splat_zero_usize = Air.internedToRef((try sema.splat(operand_ty, .zero_usize)).toIntern());
const is_aligned = try block.addCmpVector(remainder, splat_zero_usize, .eq);
break :all_aligned try block.addInst(.{
.tag = .reduce,
.data = .{ .reduce = .{
.operand = is_aligned,
.operation = .And,
} },
});
} else try block.addBinOp(.cmp_eq, remainder, .zero_usize);
try sema.addSafetyCheck(block, src, is_aligned, .incorrect_alignment);
}
}
@ -23543,7 +23572,11 @@ fn ptrCastFull(
if (block.wantSafety() and operand_ty.ptrAllowsZero(zcu) and !dest_ty.ptrAllowsZero(zcu) and
(try Type.fromInterned(dest_info.child).hasRuntimeBitsSema(pt) or Type.fromInterned(dest_info.child).zigTypeTag(zcu) == .@"fn"))
{
const ptr_int = try block.addUnOp(.int_from_ptr, ptr);
const actual_ptr = if (src_info.flags.size == .slice)
try sema.analyzeSlicePtr(block, src, ptr, operand_ty)
else
ptr;
const ptr_int = try block.addBitCast(.usize, actual_ptr);
const is_non_zero = try block.addBinOp(.cmp_neq, ptr_int, .zero_usize);
const ok = if (src_info.flags.size == .slice and dest_info.flags.size == .slice) ok: {
const len = try sema.analyzeSliceLen(block, operand_src, ptr);
@ -23559,7 +23592,11 @@ fn ptrCastFull(
{
const align_bytes_minus_1 = dest_align.toByteUnits().? - 1;
const align_minus_1 = Air.internedToRef((try pt.intValue(Type.usize, align_bytes_minus_1)).toIntern());
const ptr_int = try block.addUnOp(.int_from_ptr, ptr);
const actual_ptr = if (src_info.flags.size == .slice)
try sema.analyzeSlicePtr(block, src, ptr, operand_ty)
else
ptr;
const ptr_int = try block.addBitCast(.usize, actual_ptr);
const remainder = try block.addBinOp(.bit_and, ptr_int, align_minus_1);
const is_aligned = try block.addBinOp(.cmp_eq, remainder, .zero_usize);
const ok = if (src_info.flags.size == .slice and dest_info.flags.size == .slice) ok: {
@ -31407,7 +31444,7 @@ fn coerceCompatiblePtrs(
try sema.analyzeSlicePtr(block, inst_src, inst, inst_ty)
else
inst;
const ptr_int = try block.addUnOp(.int_from_ptr, actual_ptr);
const ptr_int = try block.addBitCast(.usize, actual_ptr);
const is_non_zero = try block.addBinOp(.cmp_neq, ptr_int, .zero_usize);
const ok = if (inst_ty.isSlice(zcu)) ok: {
const len = try sema.analyzeSliceLen(block, inst_src, inst);
@ -36700,6 +36737,7 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {
.vector_4_u64_type,
.vector_4_f16_type,
.vector_8_f16_type,
.vector_2_f32_type,
.vector_4_f32_type,
.vector_8_f32_type,
.vector_2_f64_type,

View File

@ -4216,6 +4216,7 @@ pub const vector_2_u64: Type = .{ .ip_index = .vector_2_u64_type };
pub const vector_4_u64: Type = .{ .ip_index = .vector_4_u64_type };
pub const vector_4_f16: Type = .{ .ip_index = .vector_4_f16_type };
pub const vector_8_f16: Type = .{ .ip_index = .vector_8_f16_type };
pub const vector_2_f32: Type = .{ .ip_index = .vector_2_f32_type };
pub const vector_4_f32: Type = .{ .ip_index = .vector_4_f32_type };
pub const vector_8_f32: Type = .{ .ip_index = .vector_8_f32_type };
pub const vector_2_f64: Type = .{ .ip_index = .vector_2_f64_type };

View File

@ -3336,6 +3336,15 @@ pub const Feature = enum {
safety_checked_instructions,
/// If the backend supports running from another thread.
separate_thread,
/// If the backend supports the following AIR instructions with vector types:
/// * `Air.Inst.Tag.bit_and`
/// * `Air.Inst.Tag.bit_or`
/// * `Air.Inst.Tag.bitcast`
/// * `Air.Inst.Tag.float_from_int`
/// * `Air.Inst.Tag.fptrunc`
/// * `Air.Inst.Tag.int_from_float`
/// If not supported, Sema will scalarize the operation.
all_vector_instructions,
};
pub fn backendSupportsFeature(zcu: *const Zcu, comptime feature: Feature) bool {

View File

@ -734,7 +734,6 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
.fpext => try self.airFpext(inst),
.intcast => try self.airIntCast(inst),
.trunc => try self.airTrunc(inst),
.int_from_bool => try self.airIntFromBool(inst),
.is_non_null => try self.airIsNonNull(inst),
.is_non_null_ptr => try self.airIsNonNullPtr(inst),
.is_null => try self.airIsNull(inst),
@ -746,7 +745,6 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
.load => try self.airLoad(inst),
.loop => try self.airLoop(inst),
.not => try self.airNot(inst),
.int_from_ptr => try self.airIntFromPtr(inst),
.ret => try self.airRet(inst),
.ret_safe => try self.airRet(inst), // TODO
.ret_load => try self.airRetLoad(inst),
@ -1294,13 +1292,6 @@ fn airTrunc(self: *Self, inst: Air.Inst.Index) InnerError!void {
return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
}
fn airIntFromBool(self: *Self, inst: Air.Inst.Index) InnerError!void {
const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
const operand = try self.resolveInst(un_op);
const result: MCValue = if (self.liveness.isUnused(inst)) .dead else operand;
return self.finishAir(inst, result, .{ un_op, .none, .none });
}
fn airNot(self: *Self, inst: Air.Inst.Index) InnerError!void {
const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
const pt = self.pt;
@ -5906,12 +5897,6 @@ fn genSetStackArgument(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) I
}
}
fn airIntFromPtr(self: *Self, inst: Air.Inst.Index) InnerError!void {
const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
const result = try self.resolveInst(un_op);
return self.finishAir(inst, result, .{ un_op, .none, .none });
}
fn airBitCast(self: *Self, inst: Air.Inst.Index) InnerError!void {
const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
const result = if (self.liveness.isUnused(inst)) .dead else result: {

View File

@ -723,7 +723,6 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
.fpext => try self.airFpext(inst),
.intcast => try self.airIntCast(inst),
.trunc => try self.airTrunc(inst),
.int_from_bool => try self.airIntFromBool(inst),
.is_non_null => try self.airIsNonNull(inst),
.is_non_null_ptr => try self.airIsNonNullPtr(inst),
.is_null => try self.airIsNull(inst),
@ -735,7 +734,6 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
.load => try self.airLoad(inst),
.loop => try self.airLoop(inst),
.not => try self.airNot(inst),
.int_from_ptr => try self.airIntFromPtr(inst),
.ret => try self.airRet(inst),
.ret_safe => try self.airRet(inst), // TODO
.ret_load => try self.airRetLoad(inst),
@ -1258,13 +1256,6 @@ fn airTrunc(self: *Self, inst: Air.Inst.Index) !void {
return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
}
fn airIntFromBool(self: *Self, inst: Air.Inst.Index) !void {
const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
const operand = try self.resolveInst(un_op);
const result: MCValue = if (self.liveness.isUnused(inst)) .dead else operand;
return self.finishAir(inst, result, .{ un_op, .none, .none });
}
fn airNot(self: *Self, inst: Air.Inst.Index) !void {
const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
const pt = self.pt;
@ -5874,12 +5865,6 @@ fn genSetStackArgument(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) I
}
}
fn airIntFromPtr(self: *Self, inst: Air.Inst.Index) !void {
const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
const result = try self.resolveInst(un_op);
return self.finishAir(inst, result, .{ un_op, .none, .none });
}
fn airBitCast(self: *Self, inst: Air.Inst.Index) !void {
const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
const result = if (self.liveness.isUnused(inst)) .dead else result: {

View File

@ -1557,7 +1557,6 @@ fn genBody(func: *Func, body: []const Air.Inst.Index) InnerError!void {
.fpext => try func.airFpext(inst),
.intcast => try func.airIntCast(inst),
.trunc => try func.airTrunc(inst),
.int_from_bool => try func.airIntFromBool(inst),
.is_non_null => try func.airIsNonNull(inst),
.is_non_null_ptr => try func.airIsNonNullPtr(inst),
.is_null => try func.airIsNull(inst),
@ -1569,7 +1568,6 @@ fn genBody(func: *Func, body: []const Air.Inst.Index) InnerError!void {
.load => try func.airLoad(inst),
.loop => try func.airLoop(inst),
.not => try func.airNot(inst),
.int_from_ptr => try func.airIntFromPtr(inst),
.ret => try func.airRet(inst, false),
.ret_safe => try func.airRet(inst, true),
.ret_load => try func.airRetLoad(inst),
@ -2299,13 +2297,6 @@ fn airTrunc(func: *Func, inst: Air.Inst.Index) !void {
return func.finishAir(inst, operand, .{ ty_op.operand, .none, .none });
}
fn airIntFromBool(func: *Func, inst: Air.Inst.Index) !void {
const un_op = func.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
const operand = try func.resolveInst(un_op);
const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else operand;
return func.finishAir(inst, result, .{ un_op, .none, .none });
}
fn airNot(func: *Func, inst: Air.Inst.Index) !void {
const ty_op = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else result: {
@ -7262,21 +7253,6 @@ fn genSetMem(
}
}
fn airIntFromPtr(func: *Func, inst: Air.Inst.Index) !void {
const un_op = func.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
const result = result: {
const src_mcv = try func.resolveInst(un_op);
const src_ty = func.typeOfIndex(inst);
if (func.reuseOperand(inst, un_op, 0, src_mcv)) break :result src_mcv;
const dst_mcv = try func.allocRegOrMem(src_ty, inst, true);
const dst_ty = func.typeOfIndex(inst);
try func.genCopy(dst_ty, dst_mcv, src_mcv);
break :result dst_mcv;
};
return func.finishAir(inst, result, .{ un_op, .none, .none });
}
fn airBitCast(func: *Func, inst: Air.Inst.Index) !void {
const pt = func.pt;
const zcu = pt.zcu;
@ -7285,8 +7261,9 @@ fn airBitCast(func: *Func, inst: Air.Inst.Index) !void {
const result = if (func.liveness.isUnused(inst)) .unreach else result: {
const src_mcv = try func.resolveInst(ty_op.operand);
const dst_ty = func.typeOfIndex(inst);
const src_ty = func.typeOf(ty_op.operand);
if (src_ty.toIntern() == .bool_type) break :result src_mcv;
const dst_ty = func.typeOfIndex(inst);
const src_lock = if (src_mcv.getReg()) |reg| func.register_manager.lockReg(reg) else null;
defer if (src_lock) |lock| func.register_manager.unlockReg(lock);

View File

@ -577,7 +577,6 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
.fpext => @panic("TODO try self.airFpext(inst)"),
.intcast => try self.airIntCast(inst),
.trunc => try self.airTrunc(inst),
.int_from_bool => try self.airIntFromBool(inst),
.is_non_null => try self.airIsNonNull(inst),
.is_non_null_ptr => @panic("TODO try self.airIsNonNullPtr(inst)"),
.is_null => try self.airIsNull(inst),
@ -589,7 +588,6 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
.load => try self.airLoad(inst),
.loop => try self.airLoop(inst),
.not => try self.airNot(inst),
.int_from_ptr => try self.airIntFromPtr(inst),
.ret => try self.airRet(inst),
.ret_safe => try self.airRet(inst), // TODO
.ret_load => try self.airRetLoad(inst),
@ -1077,13 +1075,6 @@ fn airBinOp(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void {
return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
}
fn airIntFromBool(self: *Self, inst: Air.Inst.Index) !void {
const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
const operand = try self.resolveInst(un_op);
const result: MCValue = if (self.liveness.isUnused(inst)) .dead else operand;
return self.finishAir(inst, result, .{ un_op, .none, .none });
}
fn airPtrArithmetic(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void {
const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;
@ -2230,12 +2221,6 @@ fn airPtrSlicePtrPtr(self: *Self, inst: Air.Inst.Index) !void {
return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
}
fn airIntFromPtr(self: *Self, inst: Air.Inst.Index) !void {
const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
const result = try self.resolveInst(un_op);
return self.finishAir(inst, result, .{ un_op, .none, .none });
}
fn airRem(self: *Self, inst: Air.Inst.Index) !void {
const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
const lhs = try self.resolveInst(bin_op.lhs);

View File

@ -1926,7 +1926,6 @@ fn genInst(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
.br => cg.airBr(inst),
.repeat => cg.airRepeat(inst),
.switch_dispatch => return cg.fail("TODO implement `switch_dispatch`", .{}),
.int_from_bool => cg.airIntFromBool(inst),
.cond_br => cg.airCondBr(inst),
.intcast => cg.airIntcast(inst),
.fptrunc => cg.airFptrunc(inst),
@ -1972,7 +1971,6 @@ fn genInst(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
.ptr_sub => cg.airPtrBinOp(inst, .sub),
.ptr_elem_ptr => cg.airPtrElemPtr(inst),
.ptr_elem_val => cg.airPtrElemVal(inst),
.int_from_ptr => cg.airIntFromPtr(inst),
.ret => cg.airRet(inst),
.ret_safe => cg.airRet(inst), // TODO
.ret_ptr => cg.airRetPtr(inst),
@ -3777,7 +3775,11 @@ fn airBitcast(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
break :result try cg.wrapOperand(operand, wanted_ty);
}
break :result cg.reuseOperand(ty_op.operand, operand);
break :result switch (operand) {
// for stack offset, return a pointer to this offset.
.stack_offset => try cg.buildPointerOffset(operand, 0, .new),
else => cg.reuseOperand(ty_op.operand, operand),
};
};
return cg.finishAir(inst, result, &.{ty_op.operand});
}
@ -4637,14 +4639,6 @@ fn trunc(cg: *CodeGen, operand: WValue, wanted_ty: Type, given_ty: Type) InnerEr
return result;
}
fn airIntFromBool(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
const un_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
const operand = try cg.resolveInst(un_op);
const result = cg.reuseOperand(un_op, operand);
return cg.finishAir(inst, result, &.{un_op});
}
fn airArrayToSlice(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
const zcu = cg.pt.zcu;
const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
@ -4668,21 +4662,6 @@ fn airArrayToSlice(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
return cg.finishAir(inst, slice_local, &.{ty_op.operand});
}
fn airIntFromPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
const zcu = cg.pt.zcu;
const un_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
const operand = try cg.resolveInst(un_op);
const ptr_ty = cg.typeOf(un_op);
const result = if (ptr_ty.isSlice(zcu))
try cg.slicePtr(operand)
else switch (operand) {
// for stack offset, return a pointer to this offset.
.stack_offset => try cg.buildPointerOffset(operand, 0, .new),
else => cg.reuseOperand(un_op, operand),
};
return cg.finishAir(inst, result, &.{un_op});
}
fn airPtrElemVal(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
const zcu = cg.pt.zcu;
const bin_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;

File diff suppressed because it is too large Load Diff

View File

@ -3325,7 +3325,6 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail,
.bitcast => try airBitcast(f, inst),
.intcast => try airIntCast(f, inst),
.trunc => try airTrunc(f, inst),
.int_from_bool => try airIntFromBool(f, inst),
.load => try airLoad(f, inst),
.store => try airStore(f, inst, false),
.store_safe => try airStore(f, inst, true),
@ -3371,8 +3370,6 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail,
.fpext,
=> try airFloatCast(f, inst),
.int_from_ptr => try airIntFromPtr(f, inst),
.atomic_store_unordered => try airAtomicStore(f, inst, toMemoryOrder(.unordered)),
.atomic_store_monotonic => try airAtomicStore(f, inst, toMemoryOrder(.monotonic)),
.atomic_store_release => try airAtomicStore(f, inst, toMemoryOrder(.release)),
@ -3983,21 +3980,6 @@ fn airTrunc(f: *Function, inst: Air.Inst.Index) !CValue {
return local;
}
fn airIntFromBool(f: *Function, inst: Air.Inst.Index) !CValue {
const un_op = f.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
const operand = try f.resolveInst(un_op);
try reap(f, inst, &.{un_op});
const writer = f.object.writer();
const inst_ty = f.typeOfIndex(inst);
const local = try f.allocLocal(inst, inst_ty);
const a = try Assignment.start(f, writer, try f.ctypeFromType(inst_ty, .complete));
try f.writeCValue(writer, local, .Other);
try a.assign(f, writer);
try f.writeCValue(writer, operand, .Other);
try a.end(f, writer);
return local;
}
fn airStore(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue {
const pt = f.object.dg.pt;
const zcu = pt.zcu;
@ -4970,7 +4952,7 @@ fn bitcast(f: *Function, dest_ty: Type, operand: CValue, operand_ty: Type) !CVal
src_info.bits == dest_info.bits) return operand;
}
if (dest_ty.isPtrAtRuntime(zcu) and operand_ty.isPtrAtRuntime(zcu)) {
if (dest_ty.isPtrAtRuntime(zcu) or operand_ty.isPtrAtRuntime(zcu)) {
const local = try f.allocLocal(null, dest_ty);
try f.writeCValue(writer, local, .Other);
try writer.writeAll(" = (");
@ -6455,30 +6437,6 @@ fn airFloatCast(f: *Function, inst: Air.Inst.Index) !CValue {
return local;
}
fn airIntFromPtr(f: *Function, inst: Air.Inst.Index) !CValue {
const pt = f.object.dg.pt;
const zcu = pt.zcu;
const un_op = f.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
const operand = try f.resolveInst(un_op);
const operand_ty = f.typeOf(un_op);
try reap(f, inst, &.{un_op});
const inst_ty = f.typeOfIndex(inst);
const writer = f.object.writer();
const local = try f.allocLocal(inst, inst_ty);
try f.writeCValue(writer, local, .Other);
try writer.writeAll(" = (");
try f.renderType(writer, inst_ty);
try writer.writeByte(')');
if (operand_ty.isSlice(zcu))
try f.writeCValueMember(writer, operand, .{ .identifier = "ptr" })
else
try f.writeCValue(writer, operand, .Other);
try writer.writeAll(";\n");
return local;
}
fn airUnBuiltinCall(
f: *Function,
inst: Air.Inst.Index,

View File

@ -1707,6 +1707,21 @@ pub const Pool = struct {
};
return pool.fromFields(allocator, .@"struct", &fields, kind);
},
.vector_2_f32_type => {
const vector_ctype = try pool.getVector(allocator, .{
.elem_ctype = .f32,
.len = 2,
});
if (!kind.isParameter()) return vector_ctype;
var fields = [_]Info.Field{
.{
.name = .{ .index = .array },
.ctype = vector_ctype,
.alignas = AlignAs.fromAbiAlignment(Type.f32.abiAlignment(zcu)),
},
};
return pool.fromFields(allocator, .@"struct", &fields, kind);
},
.vector_4_f32_type => {
const vector_ctype = try pool.getVector(allocator, .{
.elem_ctype = .f32,

View File

@ -5154,7 +5154,6 @@ pub const FuncGen = struct {
.ret_ptr => try self.airRetPtr(inst),
.arg => try self.airArg(inst),
.bitcast => try self.airBitCast(inst),
.int_from_bool => try self.airIntFromBool(inst),
.breakpoint => try self.airBreakpoint(inst),
.ret_addr => try self.airRetAddr(inst),
.frame_addr => try self.airFrameAddress(inst),
@ -5167,7 +5166,6 @@ pub const FuncGen = struct {
.trunc => try self.airTrunc(inst),
.fptrunc => try self.airFptrunc(inst),
.fpext => try self.airFpext(inst),
.int_from_ptr => try self.airIntFromPtr(inst),
.load => try self.airLoad(body[i..]),
.not => try self.airNot(inst),
.store => try self.airStore(inst, false),
@ -9435,16 +9433,6 @@ pub const FuncGen = struct {
}
}
fn airIntFromPtr(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
const o = self.ng.object;
const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
const operand = try self.resolveInst(un_op);
const ptr_ty = self.typeOf(un_op);
const operand_ptr = try self.sliceOrArrayPtr(operand, ptr_ty);
const dest_llvm_ty = try o.lowerType(self.typeOfIndex(inst));
return self.wip.cast(.ptrtoint, operand_ptr, dest_llvm_ty, "");
}
fn airBitCast(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
const operand_ty = self.typeOf(ty_op.operand);
@ -9476,6 +9464,10 @@ pub const FuncGen = struct {
return self.wip.cast(.inttoptr, operand, llvm_dest_ty, "");
}
if (operand_ty.isPtrAtRuntime(zcu) and inst_ty.zigTypeTag(zcu) == .int) {
return self.wip.cast(.ptrtoint, operand, llvm_dest_ty, "");
}
if (operand_ty.zigTypeTag(zcu) == .vector and inst_ty.zigTypeTag(zcu) == .array) {
const elem_ty = operand_ty.childType(zcu);
if (!result_is_ref) {
@ -9564,12 +9556,6 @@ pub const FuncGen = struct {
return self.wip.cast(.bitcast, operand, llvm_dest_ty, "");
}
fn airIntFromBool(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
const operand = try self.resolveInst(un_op);
return operand;
}
fn airArg(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
const o = self.ng.object;
const pt = o.pt;

View File

@ -3449,10 +3449,8 @@ const NavGen = struct {
.bitcast => try self.airBitCast(inst),
.intcast, .trunc => try self.airIntCast(inst),
.int_from_ptr => try self.airIntFromPtr(inst),
.float_from_int => try self.airFloatFromInt(inst),
.int_from_float => try self.airIntFromFloat(inst),
.int_from_bool => try self.airIntFromBool(inst),
.fpext, .fptrunc => try self.airFloatCast(inst),
.not => try self.airNot(inst),
@ -4706,9 +4704,14 @@ const NavGen = struct {
fn airBitCast(self: *NavGen, inst: Air.Inst.Index) !?IdRef {
const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
const operand_id = try self.resolve(ty_op.operand);
const operand_ty = self.typeOf(ty_op.operand);
const result_ty = self.typeOfIndex(inst);
if (operand_ty.toIntern() == .bool_type) {
const operand = try self.temporary(ty_op.operand);
const result = try self.intFromBool(operand);
return try result.materialize(self);
}
const operand_id = try self.resolve(ty_op.operand);
return try self.bitCast(result_ty, operand_ty, operand_id);
}
@ -4749,12 +4752,6 @@ const NavGen = struct {
return result_id;
}
fn airIntFromPtr(self: *NavGen, inst: Air.Inst.Index) !?IdRef {
const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
const operand_id = try self.resolve(un_op);
return try self.intFromPtr(operand_id);
}
fn airFloatFromInt(self: *NavGen, inst: Air.Inst.Index) !?IdRef {
const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
const operand_ty = self.typeOf(ty_op.operand);
@ -4808,13 +4805,6 @@ const NavGen = struct {
return result_id;
}
fn airIntFromBool(self: *NavGen, inst: Air.Inst.Index) !?IdRef {
const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
const operand = try self.temporary(un_op);
const result = try self.intFromBool(operand);
return try result.materialize(self);
}
fn airFloatCast(self: *NavGen, inst: Air.Inst.Index) !?IdRef {
const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
const operand_id = try self.resolve(ty_op.operand);

View File

@ -172,8 +172,6 @@ const Writer = struct {
.is_non_err,
.is_err_ptr,
.is_non_err_ptr,
.int_from_ptr,
.int_from_bool,
.ret,
.ret_safe,
.ret_load,

View File

@ -745,5 +745,8 @@ pub inline fn backendSupportsFeature(backend: std.builtin.CompilerBackend, compt
.stage2_llvm => false,
else => true,
},
.all_vector_instructions => switch (backend) {
else => false,
},
};
}

View File

@ -203,8 +203,8 @@ test "@min/@max notices vector bounds" {
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_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;
var x: @Vector(2, u16) = .{ 140, 40 };
const y: @Vector(2, u64) = .{ 5, 100 };
@ -257,8 +257,8 @@ test "@min/@max notices bounds from vector 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_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;
var x: @Vector(2, u16) = .{ 30, 67 };
var y: @Vector(2, u32) = .{ 20, 500 };
@ -301,8 +301,7 @@ test "@min/@max notices bounds from vector types when element of comptime-known
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_x86_64 and
!comptime std.Target.x86.featureSetHas(builtin.cpu.features, .sse4_1)) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;
var x: @Vector(2, u32) = .{ 1_000_000, 12345 };
_ = &x;

File diff suppressed because it is too large Load Diff

View File

@ -15,6 +15,6 @@ pub export fn entry() void {
// error
//
// :7:25: error: unable to resolve comptime value
// :7:25: note: initializer of comptime-only struct 'tmp.S.foo__anon_463.C' must be comptime-known
// :7:25: note: initializer of comptime-only struct 'tmp.S.foo__anon_464.C' must be comptime-known
// :4:16: note: struct requires comptime because of this field
// :4:16: note: types are not available at runtime

View File

@ -16,5 +16,5 @@ pub export fn entry2() void {
//
// :3:6: error: no field or member function named 'copy' in '[]const u8'
// :9:8: error: no field or member function named 'bar' in '@TypeOf(.{})'
// :12:18: error: no field or member function named 'bar' in 'tmp.entry2__struct_467'
// :12:18: error: no field or member function named 'bar' in 'tmp.entry2__struct_468'
// :12:6: note: struct declared here

View File

@ -6,6 +6,6 @@ export fn foo() void {
// error
//
// :4:16: error: expected type 'tmp.T', found 'tmp.foo__struct_456'
// :4:16: error: expected type 'tmp.T', found 'tmp.foo__struct_457'
// :3:16: note: struct declared here
// :1:11: note: struct declared here