From 63ae7899ae6803ba8113ed3176877c864ce889df Mon Sep 17 00:00:00 2001 From: Veikka Tuominen Date: Sun, 27 Nov 2022 16:50:35 +0200 Subject: [PATCH 01/16] cbe: ensure test and tagName function names are unique --- src/codegen/c.zig | 9 +++++++-- test/behavior/basic.zig | 1 - test/behavior/bugs/13064.zig | 1 - test/behavior/bugs/13065.zig | 1 - test/behavior/bugs/13069.zig | 1 - test/behavior/enum.zig | 1 - test/behavior/math.zig | 3 --- 7 files changed, 7 insertions(+), 10 deletions(-) diff --git a/src/codegen/c.zig b/src/codegen/c.zig index 304728b602..0b9a4ef4fc 100644 --- a/src/codegen/c.zig +++ b/src/codegen/c.zig @@ -1961,7 +1961,7 @@ pub const DeclGen = struct { try buffer.appendSlice("static "); try dg.renderType(bw, name_slice_ty, .Complete); const name_begin = buffer.items.len + " ".len; - try bw.print(" zig_tagName_{}(", .{typeToCIdentifier(enum_ty, dg.module)}); + try bw.print(" zig_tagName_{}_{d}(", .{ typeToCIdentifier(enum_ty, dg.module), @enumToInt(enum_ty.getOwnerDecl()) }); const name_end = buffer.items.len - "(".len; try dg.renderTypeAndName(bw, enum_ty, .{ .identifier = "tag" }, .Const, 0, .Complete); try buffer.appendSlice(") {\n switch (tag) {\n"); @@ -2111,11 +2111,16 @@ pub const DeclGen = struct { return writer.writeAll(exports.items[0].options.name); } else if (decl.isExtern()) { return writer.writeAll(mem.sliceTo(decl.name, 0)); + } else if (dg.module.test_functions.get(decl_index)) |_| { + const gpa = dg.gpa; + const name = try decl.getFullyQualifiedName(dg.module); + defer gpa.free(name); + return writer.print("{}_{d}", .{ fmtIdent(name), @enumToInt(decl_index) }); } else { const gpa = dg.gpa; const name = try decl.getFullyQualifiedName(dg.module); defer gpa.free(name); - return writer.print("{ }", .{fmtIdent(name)}); + return writer.print("{}", .{fmtIdent(name)}); } } diff --git a/test/behavior/basic.zig b/test/behavior/basic.zig index 3fc1cda04d..8a815ecb7b 100644 --- a/test/behavior/basic.zig +++ b/test/behavior/basic.zig @@ -739,7 +739,6 @@ test "thread local variable" { } test "result location is optional inside error union" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO diff --git a/test/behavior/bugs/13064.zig b/test/behavior/bugs/13064.zig index 928e9b2aa7..b847276a90 100644 --- a/test/behavior/bugs/13064.zig +++ b/test/behavior/bugs/13064.zig @@ -5,7 +5,6 @@ const expect = std.testing.expect; test { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO var x: [10][10]u32 = undefined; diff --git a/test/behavior/bugs/13065.zig b/test/behavior/bugs/13065.zig index cad1718e0b..c6a0053ac7 100644 --- a/test/behavior/bugs/13065.zig +++ b/test/behavior/bugs/13065.zig @@ -10,7 +10,6 @@ const U = union(enum) { test { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO var x = U{ .array = undefined }; diff --git a/test/behavior/bugs/13069.zig b/test/behavior/bugs/13069.zig index 8872f8a566..48a3184566 100644 --- a/test/behavior/bugs/13069.zig +++ b/test/behavior/bugs/13069.zig @@ -6,7 +6,6 @@ test { if (builtin.zig_backend == .stage2_arm) 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_c) return error.SkipZigTest; // TODO var opt_x: ?[3]f32 = [_]f32{0.0} ** 3; diff --git a/test/behavior/enum.zig b/test/behavior/enum.zig index a6e417f2ae..8432ee0b8d 100644 --- a/test/behavior/enum.zig +++ b/test/behavior/enum.zig @@ -1101,7 +1101,6 @@ test "enum literal in array literal" { } test "tag name functions are unique" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; diff --git a/test/behavior/math.zig b/test/behavior/math.zig index 17a4c5e64b..4b6b882fe5 100644 --- a/test/behavior/math.zig +++ b/test/behavior/math.zig @@ -315,8 +315,6 @@ test "comptime_int multi-limb partial shift right" { } test "xor" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO - try test_xor(); comptime try test_xor(); } @@ -572,7 +570,6 @@ fn testShrTrunc(x: u16) !void { } test "f128" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_wasm) 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 From 8af564801551882346bd785d25f4f7bf5c374b97 Mon Sep 17 00:00:00 2001 From: Veikka Tuominen Date: Sun, 27 Nov 2022 17:15:32 +0200 Subject: [PATCH 02/16] Sema: make inferred allocs always mutable Const allocs don't make any sense, make_ptr_const handles making the pointers not mutable. --- src/Sema.zig | 4 ++-- test/behavior/if.zig | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/Sema.zig b/src/Sema.zig index be44ca6a5f..17cbbd7274 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -3639,7 +3639,7 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com const final_elem_ty = try decl.ty.copy(sema.arena); const final_ptr_ty = try Type.ptr(sema.arena, sema.mod, .{ .pointee_type = final_elem_ty, - .mutable = var_is_mut, + .mutable = true, .@"align" = iac.data.alignment, .@"addrspace" = target_util.defaultAddressSpace(target, .local), }); @@ -3663,7 +3663,7 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com const final_ptr_ty = try Type.ptr(sema.arena, sema.mod, .{ .pointee_type = final_elem_ty, - .mutable = var_is_mut, + .mutable = true, .@"align" = inferred_alloc.data.alignment, .@"addrspace" = target_util.defaultAddressSpace(target, .local), }); diff --git a/test/behavior/if.zig b/test/behavior/if.zig index 8a001a65d4..07b3ddbca6 100644 --- a/test/behavior/if.zig +++ b/test/behavior/if.zig @@ -133,7 +133,6 @@ test "if-else expression with runtime condition result location is inferred opti if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; const A = struct { b: u64, c: u64 }; var d: bool = true; From 6310186d52ae4e7bccf40326a98916695192b543 Mon Sep 17 00:00:00 2001 From: Veikka Tuominen Date: Sun, 27 Nov 2022 17:16:01 +0200 Subject: [PATCH 03/16] cbe: cast pointer switch target to int --- src/codegen/c.zig | 11 ++++++++++- test/behavior/switch.zig | 1 - 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/codegen/c.zig b/src/codegen/c.zig index 0b9a4ef4fc..85f822d514 100644 --- a/src/codegen/c.zig +++ b/src/codegen/c.zig @@ -3894,10 +3894,14 @@ fn airSwitchBr(f: *Function, inst: Air.Inst.Index) !CValue { const writer = f.object.writer(); try writer.writeAll("switch ("); - if (condition_ty.tag() == .bool) { + if (condition_ty.zigTypeTag() == .Bool) { try writer.writeByte('('); try f.renderTypecast(writer, Type.u1); try writer.writeByte(')'); + } else if (condition_ty.isPtrAtRuntime()) { + try writer.writeByte('('); + try f.renderTypecast(writer, Type.usize); + try writer.writeByte(')'); } try f.writeCValue(writer, condition, .Other); try writer.writeAll(") {"); @@ -3914,6 +3918,11 @@ fn airSwitchBr(f: *Function, inst: Air.Inst.Index) !CValue { for (items) |item| { try f.object.indent_writer.insertNewline(); try writer.writeAll("case "); + if (condition_ty.isPtrAtRuntime()) { + try writer.writeByte('('); + try f.renderTypecast(writer, Type.usize); + try writer.writeByte(')'); + } try f.object.dg.renderValue(writer, condition_ty, f.air.value(item).?, .Other); try writer.writeAll(": "); } diff --git a/test/behavior/switch.zig b/test/behavior/switch.zig index 165b1a8037..31298f1745 100644 --- a/test/behavior/switch.zig +++ b/test/behavior/switch.zig @@ -548,7 +548,6 @@ test "switch prongs with cases with identical payload types" { } test "switch on pointer type" { - 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 From 4def9c4a9b384a5980086825bcb849a88438912b Mon Sep 17 00:00:00 2001 From: Veikka Tuominen Date: Sun, 27 Nov 2022 18:47:49 +0200 Subject: [PATCH 04/16] cbe: operand of address of operator must be an lvalue --- src/codegen/c.zig | 10 +++++++++- test/behavior/floatop.zig | 2 -- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/codegen/c.zig b/src/codegen/c.zig index 85f822d514..97b37309b2 100644 --- a/src/codegen/c.zig +++ b/src/codegen/c.zig @@ -3788,10 +3788,18 @@ fn airBitcast(f: *Function, inst: Air.Inst.Index) !CValue { const local = try f.allocLocal(inst_ty, .Mut); try writer.writeAll(";\n"); + const operand_lval = if (operand == .constant) blk: { + const operand_local = try f.allocLocal(f.air.typeOf(ty_op.operand), .Const); + try writer.writeAll(" = "); + try f.writeCValue(writer, operand, .Initializer); + try writer.writeAll(";\n"); + break :blk operand_local; + } else operand; + try writer.writeAll("memcpy(&"); try f.writeCValue(writer, local, .Other); try writer.writeAll(", &"); - try f.writeCValue(writer, operand, .Other); + try f.writeCValue(writer, operand_lval, .Other); try writer.writeAll(", sizeof("); try f.renderTypecast(writer, inst_ty); try writer.writeAll("));\n"); diff --git a/test/behavior/floatop.zig b/test/behavior/floatop.zig index e8f997c988..80b3c0bc74 100644 --- a/test/behavior/floatop.zig +++ b/test/behavior/floatop.zig @@ -798,7 +798,6 @@ test "comptime fixed-width float non-zero divided by zero produces signed Inf" { if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO inline for (.{ f16, f32, f64, f80, f128 }) |F| { const pos = @as(F, 1) / @as(F, 0); @@ -897,7 +896,6 @@ test "nan negation f80" { 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 - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO const nan_comptime = comptime math.nan(f80); const neg_nan_comptime = -nan_comptime; From 1a1a5702abd61bb670b26bfa4a02d0ff7a6cc84b Mon Sep 17 00:00:00 2001 From: Veikka Tuominen Date: Sun, 27 Nov 2022 19:00:47 +0200 Subject: [PATCH 05/16] cbe: correctly handle pointers to zero bit error union payloads --- src/codegen/c.zig | 13 ++++++++++++- test/behavior/optional.zig | 1 - 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/codegen/c.zig b/src/codegen/c.zig index 97b37309b2..6a7ef2c007 100644 --- a/src/codegen/c.zig +++ b/src/codegen/c.zig @@ -4580,7 +4580,18 @@ fn airUnwrapErrUnionPay(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValu const operand_is_ptr = operand_ty.zigTypeTag() == .Pointer; const error_union_ty = if (operand_is_ptr) operand_ty.childType() else operand_ty; - if (!error_union_ty.errorUnionPayload().hasRuntimeBits()) return CValue.none; + if (!error_union_ty.errorUnionPayload().hasRuntimeBits()) { + if (!is_ptr) return CValue.none; + + const local = try f.allocLocal(inst_ty, .Const); + const w = f.object.writer(); + try w.writeAll(" = ("); + try f.renderTypecast(w, inst_ty); + try w.writeByte(')'); + try f.writeCValue(w, operand, .Initializer); + try w.writeAll(";\n"); + return local; + } const writer = f.object.writer(); const local = try f.allocLocal(inst_ty, .Const); diff --git a/test/behavior/optional.zig b/test/behavior/optional.zig index 5bc79ed31c..9058f4e136 100644 --- a/test/behavior/optional.zig +++ b/test/behavior/optional.zig @@ -342,7 +342,6 @@ test "optional pointer to zero bit optional payload" { } test "optional pointer to zero bit error union payload" { - 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_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO From 2dcac348e57a2b071270cd3183d3e4f63af4ca7c Mon Sep 17 00:00:00 2001 From: Veikka Tuominen Date: Sun, 27 Nov 2022 19:21:22 +0200 Subject: [PATCH 06/16] cbe: implement packed unions --- src/codegen/c.zig | 83 +++++++++++++++++++++++++++++++++++------ test/behavior/union.zig | 1 - 2 files changed, 72 insertions(+), 12 deletions(-) diff --git a/src/codegen/c.zig b/src/codegen/c.zig index 6a7ef2c007..7db7f56de6 100644 --- a/src/codegen/c.zig +++ b/src/codegen/c.zig @@ -542,9 +542,14 @@ pub const DeclGen = struct { return dg.renderParentPtr(writer, field_ptr.container_ptr, host_ty); }, }, - .Union => FieldInfo{ - .name = container_ty.unionFields().keys()[index], - .ty = container_ty.unionFields().values()[index].ty, + .Union => switch (container_ty.containerLayout()) { + .Auto, .Extern => FieldInfo{ + .name = container_ty.unionFields().keys()[index], + .ty = container_ty.unionFields().values()[index].ty, + }, + .Packed => { + return dg.renderParentPtr(writer, field_ptr.container_ptr, ptr_ty); + }, }, .Pointer => field_info: { assert(container_ty.isSlice()); @@ -1165,6 +1170,27 @@ pub const DeclGen = struct { try writer.writeByte(')'); } + const index = ty.unionTagFieldIndex(union_obj.tag, dg.module).?; + const field_ty = ty.unionFields().values()[index].ty; + const field_name = ty.unionFields().keys()[index]; + if (ty.containerLayout() == .Packed) { + if (field_ty.hasRuntimeBits()) { + if (field_ty.isPtrAtRuntime()) { + try writer.writeByte('('); + try dg.renderTypecast(writer, ty); + try writer.writeByte(')'); + } else if (field_ty.zigTypeTag() == .Float) { + try writer.writeByte('('); + try dg.renderTypecast(writer, ty); + try writer.writeByte(')'); + } + try dg.renderValue(writer, field_ty, union_obj.val, .Initializer); + } else { + try writer.writeAll("0"); + } + return; + } + try writer.writeByte('{'); if (ty.unionTagTypeSafety()) |tag_ty| { const layout = ty.unionGetLayout(target); @@ -1176,9 +1202,6 @@ pub const DeclGen = struct { try writer.writeAll(".payload = {"); } - const index = ty.unionTagFieldIndex(union_obj.tag, dg.module).?; - const field_ty = ty.unionFields().values()[index].ty; - const field_name = ty.unionFields().keys()[index]; var it = ty.unionFields().iterator(); if (field_ty.hasRuntimeBits()) { try writer.print(".{ } = ", .{fmtIdent(field_name)}); @@ -1794,9 +1817,17 @@ pub const DeclGen = struct { return w.writeAll(name); }, - .Struct, .Union => |tag| if (tag == .Struct and t.containerLayout() == .Packed) - try dg.renderType(w, t.castTag(.@"struct").?.data.backing_int_ty, kind) - else if (t.isSimpleTupleOrAnonStruct()) { + .Struct, .Union => |tag| if (t.containerLayout() == .Packed) { + if (t.castTag(.@"struct")) |struct_obj| { + try dg.renderType(w, struct_obj.data.backing_int_ty, kind); + } else { + var buf: Type.Payload.Bits = .{ + .base = .{ .tag = .int_unsigned }, + .data = @intCast(u16, t.bitSize(target)), + }; + try dg.renderType(w, Type.initPayload(&buf.base), kind); + } + } else if (t.isSimpleTupleOrAnonStruct()) { const ExpectedContents = struct { types: [8]Type, values: [8]Value }; var stack align(@alignOf(ExpectedContents)) = std.heap.stackFallback(@sizeOf(ExpectedContents), dg.gpa); @@ -4388,7 +4419,11 @@ fn structFieldPtr(f: *Function, inst: Air.Inst.Index, struct_ptr_ty: Type, struc return local; } else @as(CValue, CValue.none), // this @as is needed because of a stage1 bug }, - .@"union", .union_safety_tagged, .union_tagged => .{ + .@"union", .union_safety_tagged, .union_tagged => if (struct_ty.containerLayout() == .Packed) { + try f.writeCValue(writer, struct_ptr, .Other); + try writer.writeAll(";\n"); + return local; + } else .{ .identifier = struct_ty.unionFields().keys()[index], }, .tuple, .anon_struct => field_name: { @@ -4502,7 +4537,26 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue { return local; }, }, - .@"union", .union_safety_tagged, .union_tagged => .{ + .@"union", .union_safety_tagged, .union_tagged => if (struct_ty.containerLayout() == .Packed) { + const operand_lval = if (struct_byval == .constant) blk: { + const operand_local = try f.allocLocal(struct_ty, .Const); + try writer.writeAll(" = "); + try f.writeCValue(writer, struct_byval, .Initializer); + try writer.writeAll(";\n"); + break :blk operand_local; + } else struct_byval; + + const local = try f.allocLocal(inst_ty, .Mut); + try writer.writeAll(";\n"); + try writer.writeAll("memcpy(&"); + try f.writeCValue(writer, local, .FunctionArgument); + try writer.writeAll(", &"); + try f.writeCValue(writer, operand_lval, .FunctionArgument); + try writer.writeAll(", sizeof("); + try f.renderTypecast(writer, inst_ty); + try writer.writeAll("));\n"); + return local; + } else .{ .identifier = struct_ty.unionFields().keys()[extra.field_index], }, .tuple, .anon_struct => blk: { @@ -5565,6 +5619,13 @@ fn airUnionInit(f: *Function, inst: Air.Inst.Index) !CValue { const writer = f.object.writer(); const local = try f.allocLocal(union_ty, .Const); + if (union_obj.layout == .Packed) { + try writer.writeAll(" = "); + try f.writeCValue(writer, payload, .Initializer); + try writer.writeAll(";\n"); + return local; + } + try writer.writeAll(" = {"); if (union_ty.unionTagTypeSafety()) |tag_ty| { const layout = union_ty.unionGetLayout(target); diff --git a/test/behavior/union.zig b/test/behavior/union.zig index aaeb586cdf..6e91202776 100644 --- a/test/behavior/union.zig +++ b/test/behavior/union.zig @@ -1376,7 +1376,6 @@ test "union field ptr - zero sized field" { test "packed union in packed struct" { if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO 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_wasm) return error.SkipZigTest; // TODO From a67ea4a4ae6f8392e2cf9672279aa1b2f80dab72 Mon Sep 17 00:00:00 2001 From: Veikka Tuominen Date: Sun, 27 Nov 2022 21:47:41 +0200 Subject: [PATCH 07/16] cbe: include hash in tuple type name Different (simple) tuple types do not necessarily print out as different strings. This is issue would be caused by passing std.fmt.Formatter to std.fmt.format. --- src/codegen/c.zig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/codegen/c.zig b/src/codegen/c.zig index 7db7f56de6..6e96e92529 100644 --- a/src/codegen/c.zig +++ b/src/codegen/c.zig @@ -1468,7 +1468,7 @@ pub const DeclGen = struct { if (field_id == 0) try buffer.appendSlice(" char empty_tuple;\n"); } const name_begin = buffer.items.len + "} ".len; - try buffer.writer().print("}} zig_T_{};\n", .{typeToCIdentifier(t, dg.module)}); + try buffer.writer().print("}} zig_T_{}_{d};\n", .{ typeToCIdentifier(t, dg.module), @truncate(u16, t.hash(dg.module)) }); const name_end = buffer.items.len - ";\n".len; const rendered = try buffer.toOwnedSlice(); From 3281494dc50055dde0415cefb7dec806437741cc Mon Sep 17 00:00:00 2001 From: Veikka Tuominen Date: Mon, 28 Nov 2022 13:04:32 +0200 Subject: [PATCH 08/16] cbe: prevent access of inactive union field in unimplemented instructions --- src/codegen/c.zig | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/src/codegen/c.zig b/src/codegen/c.zig index 6e96e92529..13ff4e7344 100644 --- a/src/codegen/c.zig +++ b/src/codegen/c.zig @@ -5285,30 +5285,12 @@ fn airSplat(f: *Function, inst: Air.Inst.Index) !CValue { fn airSelect(f: *Function, inst: Air.Inst.Index) !CValue { if (f.liveness.isUnused(inst)) return CValue.none; - const inst_ty = f.air.typeOfIndex(inst); - const ty_pl = f.air.instructions.items(.data)[inst].ty_pl; - - const writer = f.object.writer(); - const local = try f.allocLocal(inst_ty, .Const); - try writer.writeAll(" = "); - - _ = local; - _ = ty_pl; return f.fail("TODO: C backend: implement airSelect", .{}); } fn airShuffle(f: *Function, inst: Air.Inst.Index) !CValue { if (f.liveness.isUnused(inst)) return CValue.none; - const inst_ty = f.air.typeOfIndex(inst); - const ty_op = f.air.instructions.items(.data)[inst].ty_op; - const operand = try f.resolveInst(ty_op.operand); - const writer = f.object.writer(); - const local = try f.allocLocal(inst_ty, .Const); - try writer.writeAll(" = "); - - _ = operand; - _ = local; return f.fail("TODO: C backend: implement airShuffle", .{}); } From 7be6f352e395b1fdc5cc7c3c91067cf4e473d753 Mon Sep 17 00:00:00 2001 From: Veikka Tuominen Date: Mon, 28 Nov 2022 13:49:51 +0200 Subject: [PATCH 09/16] cbe: fix asm return values --- src/codegen/c.zig | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/codegen/c.zig b/src/codegen/c.zig index 13ff4e7344..6df3893cbe 100644 --- a/src/codegen/c.zig +++ b/src/codegen/c.zig @@ -4108,6 +4108,8 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue { if (is_reg) { try f.writeCValue(writer, .{ .local = locals_index }, .Other); locals_index += 1; + } else if (output == .none) { + try f.writeCValue(writer, local, .FunctionArgument); } else { try f.writeCValueDeref(writer, try f.resolveInst(output)); } @@ -4411,6 +4413,10 @@ fn structFieldPtr(f: *Function, inst: Air.Inst.Index, struct_ptr_ty: Type, struc u8_ptr_pl.data.pointee_type = Type.u8; const u8_ptr_ty = Type.initPayload(&u8_ptr_pl.base); + if (!std.mem.isAligned(byte_offset, field_ptr_ty.ptrAlignment(target))) { + return f.fail("TODO: CBE: unaligned packed struct field pointer", .{}); + } + try writer.writeAll("&(("); try f.renderTypecast(writer, u8_ptr_ty); try writer.writeByte(')'); From f4afeb3ffd7f968d2c93839dc5a1f2a744e114ff Mon Sep 17 00:00:00 2001 From: Veikka Tuominen Date: Wed, 30 Nov 2022 15:22:34 +0200 Subject: [PATCH 10/16] AstGen: fix incorrect handling of source cursor with shift builtins Closes #13714 --- src/AstGen.zig | 13 ++++++++++--- test/behavior.zig | 1 + test/behavior/bugs/13714.zig | 4 ++++ 3 files changed, 15 insertions(+), 3 deletions(-) create mode 100644 test/behavior/bugs/13714.zig diff --git a/src/AstGen.zig b/src/AstGen.zig index 1a8309ac2b..009d05e5ed 100644 --- a/src/AstGen.zig +++ b/src/AstGen.zig @@ -8551,11 +8551,18 @@ fn shiftOp( rhs_node: Ast.Node.Index, tag: Zir.Inst.Tag, ) InnerError!Zir.Inst.Ref { + var line = gz.astgen.source_line - gz.decl_line; + var column = gz.astgen.source_column; const lhs = try expr(gz, scope, .{ .rl = .none }, lhs_node); - maybeAdvanceSourceCursorToMainToken(gz, node); - const line = gz.astgen.source_line - gz.decl_line; - const column = gz.astgen.source_column; + switch (gz.astgen.tree.nodes.items(.tag)[node]) { + .shl, .shr => { + maybeAdvanceSourceCursorToMainToken(gz, node); + line = gz.astgen.source_line - gz.decl_line; + column = gz.astgen.source_column; + }, + else => {}, + } const log2_int_type = try gz.addUnNode(.typeof_log2_int_type, lhs, lhs_node); const rhs = try expr(gz, scope, .{ .rl = .{ .ty = log2_int_type }, .ctx = .shift_op }, rhs_node); diff --git a/test/behavior.zig b/test/behavior.zig index 04c6d4c13d..4e959fcf7d 100644 --- a/test/behavior.zig +++ b/test/behavior.zig @@ -117,6 +117,7 @@ test { _ = @import("behavior/bugs/13285.zig"); _ = @import("behavior/bugs/13435.zig"); _ = @import("behavior/bugs/13664.zig"); + _ = @import("behavior/bugs/13714.zig"); _ = @import("behavior/byteswap.zig"); _ = @import("behavior/byval_arg_var.zig"); _ = @import("behavior/call.zig"); diff --git a/test/behavior/bugs/13714.zig b/test/behavior/bugs/13714.zig new file mode 100644 index 0000000000..f11dac3676 --- /dev/null +++ b/test/behavior/bugs/13714.zig @@ -0,0 +1,4 @@ +comptime { + var image: [1]u8 = undefined; + _ = @shlExact(@as(u16, image[0]), 8); +} From 15cc83e27ae8a1740d9b7e2ec14044903979a832 Mon Sep 17 00:00:00 2001 From: Veikka Tuominen Date: Wed, 30 Nov 2022 16:11:27 +0200 Subject: [PATCH 11/16] cbe: reduce amount of temporary locals --- src/codegen/c.zig | 282 ++++++++++++++++++++++------------------- test/behavior/math.zig | 2 + 2 files changed, 155 insertions(+), 129 deletions(-) diff --git a/src/codegen/c.zig b/src/codegen/c.zig index 6df3893cbe..9e814df958 100644 --- a/src/codegen/c.zig +++ b/src/codegen/c.zig @@ -50,6 +50,8 @@ pub const CValue = union(enum) { /// Render these bytes literally. /// TODO make this a [*:0]const u8 to save memory bytes: []const u8, + /// Index of an instruction that should later be rendered inline. + inline_index: Air.Inst.Index, }; const BlockData = struct { @@ -79,6 +81,7 @@ const ValueRenderLocation = enum { FunctionArgument, Initializer, Other, + condition, }; const BuiltinInfo = enum { @@ -278,6 +281,19 @@ pub const Function = struct { return result; } + fn resolveInstNoInline(f: *Function, inst: Air.Inst.Ref) !CValue { + const operand = try f.resolveInst(inst); + if (operand != .inline_index) return operand; + + const inst_ty = f.air.typeOf(inst); + const writer = f.object.writer(); + const local = try f.allocLocal(inst_ty, .Const); + try writer.writeAll(" = "); + try f.writeCValueInline(operand.inline_index); + try writer.writeAll(";\n"); + return local; + } + fn wantSafety(f: *Function) bool { return switch (f.object.dg.module.optimizeMode()) { .Debug, .ReleaseSafe => true, @@ -313,10 +329,74 @@ pub const Function = struct { .constant => |inst| { const ty = f.air.typeOf(inst); const val = f.air.value(inst).?; - return f.object.dg.renderValue(w, ty, val, location); + try f.object.dg.renderValue(w, ty, val, location); }, - .undef => |ty| return f.object.dg.renderValue(w, ty, Value.undef, location), - else => return f.object.dg.writeCValue(w, c_value), + .undef => |ty| try f.object.dg.renderValue(w, ty, Value.undef, location), + .inline_index => |node| { + if (location != .condition) try w.writeByte('('); + try f.writeCValueInline(node); + if (location != .condition) try w.writeByte(')'); + }, + else => try f.object.dg.writeCValue(w, c_value), + } + } + + const E = error{ OutOfMemory, AnalysisFail }; + + fn writeCValueInline(f: *Function, inst: Air.Inst.Index) E!void { + switch (f.air.instructions.items(.tag)[inst]) { + // zig fmt: off + // TODO use a different strategy for add, sub, mul, div + // that communicates to the optimizer that wrapping is UB. + .add => try airBinOp(f, inst, "+", "add", .None), + .sub => try airBinOp(f, inst, "-", "sub", .None), + .mul => try airBinOp(f, inst, "*", "mul", .None), + + .div_float => try airBinBuiltinCall(f, inst, "div", .None), + + .div_trunc, .div_exact => try airBinOp(f, inst, "/", "div_trunc", .None), + .rem => { + const bin_op = f.air.instructions.items(.data)[inst].bin_op; + const lhs_ty = f.air.typeOf(bin_op.lhs); + // For binary operations @TypeOf(lhs)==@TypeOf(rhs), + // so we only check one. + if (lhs_ty.isInt()) + try airBinOp(f, inst, "%", "rem", .None) + else + try airBinFloatOp(f, inst, "fmod"); + }, + .div_floor => try airBinBuiltinCall(f, inst, "div_floor", .None), + .mod => try airBinBuiltinCall(f, inst, "mod", .None), + + .addwrap => try airBinBuiltinCall(f, inst, "addw", .Bits), + .subwrap => try airBinBuiltinCall(f, inst, "subw", .Bits), + .mulwrap => try airBinBuiltinCall(f, inst, "mulw", .Bits), + + .add_sat => try airBinBuiltinCall(f, inst, "adds", .Bits), + .sub_sat => try airBinBuiltinCall(f, inst, "subs", .Bits), + .mul_sat => try airBinBuiltinCall(f, inst, "muls", .Bits), + .shl_sat => try airBinBuiltinCall(f, inst, "shls", .Bits), + + .min => try airMinMax(f, inst, '<', "fmin"), + .max => try airMinMax(f, inst, '>', "fmax"), + + .cmp_gt => try airCmpOp(f, inst, ">", "gt"), + .cmp_gte => try airCmpOp(f, inst, ">=", "ge"), + .cmp_lt => try airCmpOp(f, inst, "<", "lt"), + .cmp_lte => try airCmpOp(f, inst, "<=", "le"), + + .cmp_eq => try airEquality(f, inst, "((", "==", "eq"), + .cmp_neq => try airEquality(f, inst, "!((", "!=", "ne"), + + .bool_and, .bit_and => try airBinOp(f, inst, "&", "and", .None), + .bool_or, .bit_or => try airBinOp(f, inst, "|", "or", .None), + .xor => try airBinOp(f, inst, "^", "xor", .None), + .shr, .shr_exact => try airBinBuiltinCall(f, inst, "shr", .None), + .shl, => try airBinBuiltinCall(f, inst, "shlw", .Bits), + .shl_exact => try airBinOp(f, inst, "<<", "shl", .None), + .not => try airNot (f, inst), + else => unreachable, + // zig fmt: on } } @@ -2072,7 +2152,7 @@ pub const DeclGen = struct { fn writeCValue(dg: *DeclGen, w: anytype, c_value: CValue) !void { switch (c_value) { - .none => unreachable, + .none, .inline_index => unreachable, .local => |i| return w.print("t{d}", .{i}), .local_ref => |i| return w.print("&t{d}", .{i}), .constant => unreachable, @@ -2091,7 +2171,7 @@ pub const DeclGen = struct { fn writeCValueDeref(dg: *DeclGen, w: anytype, c_value: CValue) !void { switch (c_value) { - .none => unreachable, + .none, .inline_index => unreachable, .local => |i| return w.print("(*t{d})", .{i}), .local_ref => |i| return w.print("t{d}", .{i}), .constant => unreachable, @@ -2121,7 +2201,7 @@ pub const DeclGen = struct { fn writeCValueDerefMember(dg: *DeclGen, writer: anytype, c_value: CValue, member: CValue) !void { switch (c_value) { - .none, .constant, .field, .undef => unreachable, + .none, .constant, .field, .undef, .inline_index => unreachable, .local, .arg, .decl, .identifier, .bytes => { try dg.writeCValue(writer, c_value); try writer.writeAll("->"); @@ -2437,37 +2517,26 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO .ptr_add => try airPtrAddSub(f, inst, '+'), .ptr_sub => try airPtrAddSub(f, inst, '-'), - // TODO use a different strategy for add, sub, mul, div - // that communicates to the optimizer that wrapping is UB. - .add => try airBinOp(f, inst, "+", "add", .None), - .sub => try airBinOp(f, inst, "-", "sub", .None), - .mul => try airBinOp(f, inst, "*", "mul", .None), + .add => CValue{ .inline_index = inst }, + .sub => CValue{ .inline_index = inst }, + .mul => CValue{ .inline_index = inst }, .neg => try airFloatNeg(f, inst), - .div_float => try airBinBuiltinCall(f, inst, "div", .None), + .div_float => CValue{ .inline_index = inst }, - .div_trunc, .div_exact => try airBinOp(f, inst, "/", "div_trunc", .None), - .rem => blk: { - const bin_op = f.air.instructions.items(.data)[inst].bin_op; - const lhs_ty = f.air.typeOf(bin_op.lhs); - // For binary operations @TypeOf(lhs)==@TypeOf(rhs), - // so we only check one. - break :blk if (lhs_ty.isInt()) - try airBinOp(f, inst, "%", "rem", .None) - else - try airBinFloatOp(f, inst, "fmod"); - }, - .div_floor => try airBinBuiltinCall(f, inst, "div_floor", .None), - .mod => try airBinBuiltinCall(f, inst, "mod", .None), + .div_trunc, .div_exact => CValue{ .inline_index = inst }, + .rem => CValue{ .inline_index = inst }, + .div_floor => CValue{ .inline_index = inst }, + .mod => CValue{ .inline_index = inst }, - .addwrap => try airBinBuiltinCall(f, inst, "addw", .Bits), - .subwrap => try airBinBuiltinCall(f, inst, "subw", .Bits), - .mulwrap => try airBinBuiltinCall(f, inst, "mulw", .Bits), + .addwrap => CValue{ .inline_index = inst }, + .subwrap => CValue{ .inline_index = inst }, + .mulwrap => CValue{ .inline_index = inst }, - .add_sat => try airBinBuiltinCall(f, inst, "adds", .Bits), - .sub_sat => try airBinBuiltinCall(f, inst, "subs", .Bits), - .mul_sat => try airBinBuiltinCall(f, inst, "muls", .Bits), - .shl_sat => try airBinBuiltinCall(f, inst, "shls", .Bits), + .add_sat => CValue{ .inline_index = inst }, + .sub_sat => CValue{ .inline_index = inst }, + .mul_sat => CValue{ .inline_index = inst }, + .shl_sat => CValue{ .inline_index = inst }, .sqrt, .sin, @@ -2492,30 +2561,30 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO .mul_with_overflow => try airOverflow(f, inst, "mul", .Bits), .shl_with_overflow => try airOverflow(f, inst, "shl", .Bits), - .min => try airMinMax(f, inst, '<', "fmin"), - .max => try airMinMax(f, inst, '>', "fmax"), + .min => CValue{ .inline_index = inst }, + .max => CValue{ .inline_index = inst }, .slice => try airSlice(f, inst), - .cmp_gt => try airCmpOp(f, inst, ">", "gt"), - .cmp_gte => try airCmpOp(f, inst, ">=", "ge"), - .cmp_lt => try airCmpOp(f, inst, "<", "lt"), - .cmp_lte => try airCmpOp(f, inst, "<=", "le"), + .cmp_gt => CValue{ .inline_index = inst }, + .cmp_gte => CValue{ .inline_index = inst }, + .cmp_lt => CValue{ .inline_index = inst }, + .cmp_lte => CValue{ .inline_index = inst }, - .cmp_eq => try airEquality(f, inst, "((", "==", "eq"), - .cmp_neq => try airEquality(f, inst, "!((", "!=", "ne"), + .cmp_eq => CValue{ .inline_index = inst }, + .cmp_neq => CValue{ .inline_index = inst }, .cmp_vector => return f.fail("TODO: C backend: implement cmp_vector", .{}), .cmp_lt_errors_len => try airCmpLtErrorsLen(f, inst), // bool_and and bool_or are non-short-circuit operations - .bool_and, .bit_and => try airBinOp(f, inst, "&", "and", .None), - .bool_or, .bit_or => try airBinOp(f, inst, "|", "or", .None), - .xor => try airBinOp(f, inst, "^", "xor", .None), - .shr, .shr_exact => try airBinBuiltinCall(f, inst, "shr", .None), - .shl, => try airBinBuiltinCall(f, inst, "shlw", .Bits), - .shl_exact => try airBinOp(f, inst, "<<", "shl", .None), - .not => try airNot (f, inst), + .bool_and, .bit_and => CValue{ .inline_index = inst }, + .bool_or, .bit_or => CValue{ .inline_index = inst }, + .xor => CValue{ .inline_index = inst }, + .shr, .shr_exact => CValue{ .inline_index = inst }, + .shl, => CValue{ .inline_index = inst }, + .shl_exact => CValue{ .inline_index = inst }, + .not => CValue{ .inline_index = inst }, .optional_payload => try airOptionalPayload(f, inst), .optional_payload_ptr => try airOptionalPayloadPtr(f, inst), @@ -3260,25 +3329,18 @@ fn airOverflow(f: *Function, inst: Air.Inst.Index, operation: []const u8, info: return local; } -fn airNot(f: *Function, inst: Air.Inst.Index) !CValue { - if (f.liveness.isUnused(inst)) return CValue.none; - +fn airNot(f: *Function, inst: Air.Inst.Index) !void { const ty_op = f.air.instructions.items(.data)[inst].ty_op; const op = try f.resolveInst(ty_op.operand); const writer = f.object.writer(); const inst_ty = f.air.typeOfIndex(inst); - const local = try f.allocLocal(inst_ty, .Const); const target = f.object.dg.module.getTarget(); if (inst_ty.bitSize(target) > 64) {} - try writer.writeAll(" = "); try writer.writeByte(if (inst_ty.tag() == .bool) '!' else '~'); try f.writeCValue(writer, op, .Other); - try writer.writeAll(";\n"); - - return local; } fn airBinOp( @@ -3287,62 +3349,49 @@ fn airBinOp( operator: []const u8, operation: []const u8, info: BuiltinInfo, -) !CValue { - if (f.liveness.isUnused(inst)) return CValue.none; - +) !void { const bin_op = f.air.instructions.items(.data)[inst].bin_op; const operand_ty = f.air.typeOf(bin_op.lhs); const target = f.object.dg.module.getTarget(); if ((operand_ty.isInt() and operand_ty.bitSize(target) > 64) or operand_ty.isRuntimeFloat()) - return try airBinBuiltinCall(f, inst, operation, info); + return airBinBuiltinCall(f, inst, operation, info); - const inst_ty = f.air.typeOfIndex(inst); const lhs = try f.resolveInst(bin_op.lhs); const rhs = try f.resolveInst(bin_op.rhs); const writer = f.object.writer(); - const local = try f.allocLocal(inst_ty, .Const); - - try writer.writeAll(" = "); try f.writeCValue(writer, lhs, .Other); try writer.writeByte(' '); try writer.writeAll(operator); try writer.writeByte(' '); try f.writeCValue(writer, rhs, .Other); - try writer.writeAll(";\n"); - - return local; } -fn airCmpOp(f: *Function, inst: Air.Inst.Index, operator: []const u8, operation: []const u8) !CValue { - if (f.liveness.isUnused(inst)) return CValue.none; - +fn airCmpOp( + f: *Function, + inst: Air.Inst.Index, + operator: []const u8, + operation: []const u8, +) !void { const bin_op = f.air.instructions.items(.data)[inst].bin_op; const operand_ty = f.air.typeOf(bin_op.lhs); const target = f.object.dg.module.getTarget(); if (operand_ty.isInt() and operand_ty.bitSize(target) > 64) - return try airCmpBuiltinCall(f, inst, operator, "cmp"); + return airCmpBuiltinCall(f, inst, operator, "cmp"); if (operand_ty.isRuntimeFloat()) - return try airCmpBuiltinCall(f, inst, operator, operation); + return airCmpBuiltinCall(f, inst, operator, operation); - const inst_ty = f.air.typeOfIndex(inst); const lhs = try f.resolveInst(bin_op.lhs); const rhs = try f.resolveInst(bin_op.rhs); const writer = f.object.writer(); - const local = try f.allocLocal(inst_ty, .Const); - - try writer.writeAll(" = "); try f.writeCValue(writer, lhs, .Other); try writer.writeByte(' '); try writer.writeAll(operator); try writer.writeByte(' '); try f.writeCValue(writer, rhs, .Other); - try writer.writeAll(";\n"); - - return local; } fn airEquality( @@ -3351,27 +3400,20 @@ fn airEquality( negate_prefix: []const u8, operator: []const u8, operation: []const u8, -) !CValue { - if (f.liveness.isUnused(inst)) return CValue.none; - +) !void { const bin_op = f.air.instructions.items(.data)[inst].bin_op; const operand_ty = f.air.typeOf(bin_op.lhs); const target = f.object.dg.module.getTarget(); if (operand_ty.isInt() and operand_ty.bitSize(target) > 64) - return try airCmpBuiltinCall(f, inst, operator, "cmp"); + return airCmpBuiltinCall(f, inst, operator, "cmp"); if (operand_ty.isRuntimeFloat()) - return try airCmpBuiltinCall(f, inst, operator, operation); + return airCmpBuiltinCall(f, inst, operator, operation); const lhs = try f.resolveInst(bin_op.lhs); const rhs = try f.resolveInst(bin_op.rhs); const writer = f.object.writer(); - const inst_ty = f.air.typeOfIndex(inst); - const local = try f.allocLocal(inst_ty, .Const); - - try writer.writeAll(" = "); - if (operand_ty.zigTypeTag() == .Optional and !operand_ty.isPtrLikeOptional()) { // (A && B) || (C && (A == B)) // A = lhs.is_null ; B = rhs.is_null ; C = rhs.payload == lhs.payload @@ -3388,9 +3430,8 @@ fn airEquality( try f.writeCValue(writer, lhs, .Other); try writer.writeAll(".is_null == "); try f.writeCValue(writer, rhs, .Other); - try writer.writeAll(".is_null));\n"); - - return local; + try writer.writeAll(".is_null))"); + return; } try f.writeCValue(writer, lhs, .Other); @@ -3398,9 +3439,6 @@ fn airEquality( try writer.writeAll(operator); try writer.writeByte(' '); try f.writeCValue(writer, rhs, .Other); - try writer.writeAll(";\n"); - - return local; } fn airCmpLtErrorsLen(f: *Function, inst: Air.Inst.Index) !CValue { @@ -3454,26 +3492,23 @@ fn airPtrAddSub(f: *Function, inst: Air.Inst.Index, operator: u8) !CValue { return local; } -fn airMinMax(f: *Function, inst: Air.Inst.Index, operator: u8, operation: []const u8) !CValue { - if (f.liveness.isUnused(inst)) return CValue.none; - +fn airMinMax(f: *Function, inst: Air.Inst.Index, operator: u8, operation: []const u8) !void { const bin_op = f.air.instructions.items(.data)[inst].bin_op; const inst_ty = f.air.typeOfIndex(inst); const target = f.object.dg.module.getTarget(); if (inst_ty.isInt() and inst_ty.bitSize(target) > 64) - return try airBinBuiltinCall(f, inst, operation[1..], .None); + return airBinBuiltinCall(f, inst, operation[1..], .None); if (inst_ty.isRuntimeFloat()) - return try airBinFloatOp(f, inst, operation); + return airBinFloatOp(f, inst, operation); const lhs = try f.resolveInst(bin_op.lhs); const rhs = try f.resolveInst(bin_op.rhs); const writer = f.object.writer(); - const local = try f.allocLocal(inst_ty, .Const); // (lhs <> rhs) ? lhs : rhs - try writer.writeAll(" = ("); + try writer.writeAll("("); try f.writeCValue(writer, lhs, .Other); try writer.writeByte(' '); try writer.writeByte(operator); @@ -3483,9 +3518,6 @@ fn airMinMax(f: *Function, inst: Air.Inst.Index, operator: u8, operation: []cons try f.writeCValue(writer, lhs, .Other); try writer.writeAll(" : "); try f.writeCValue(writer, rhs, .Other); - try writer.writeAll(";\n"); - - return local; } fn airSlice(f: *Function, inst: Air.Inst.Index) !CValue { @@ -3801,7 +3833,7 @@ fn airBitcast(f: *Function, inst: Air.Inst.Index) !CValue { if (f.liveness.isUnused(inst) or !inst_ty.hasRuntimeBits()) return CValue.none; const ty_op = f.air.instructions.items(.data)[inst].ty_op; - const operand = try f.resolveInst(ty_op.operand); + const operand = try f.resolveInstNoInline(ty_op.operand); const writer = f.object.writer(); if (inst_ty.isPtrAtRuntime() and @@ -3899,7 +3931,7 @@ fn airLoop(f: *Function, inst: Air.Inst.Index) !CValue { const body = f.air.extra[loop.end..][0..loop.data.body_len]; const writer = f.object.writer(); try writer.writeAll("while ("); - try f.object.dg.renderValue(writer, Type.bool, Value.true, .Other); + try f.object.dg.renderValue(writer, Type.bool, Value.true, .condition); try writer.writeAll(") "); try genBody(f, body); try writer.writeByte('\n'); @@ -3915,7 +3947,7 @@ fn airCondBr(f: *Function, inst: Air.Inst.Index) !CValue { const writer = f.object.writer(); try writer.writeAll("if ("); - try f.writeCValue(writer, cond, .Other); + try f.writeCValue(writer, cond, .condition); try writer.writeAll(") "); try genBody(f, then_body); try writer.writeAll(" else "); @@ -4945,16 +4977,12 @@ fn airBinBuiltinCall( inst: Air.Inst.Index, operation: []const u8, info: BuiltinInfo, -) !CValue { - if (f.liveness.isUnused(inst)) return CValue.none; - - const inst_ty = f.air.typeOfIndex(inst); +) !void { const bin_op = f.air.instructions.items(.data)[inst].bin_op; const operand_ty = f.air.typeOf(bin_op.lhs); - const local = try f.allocLocal(inst_ty, .Const); const writer = f.object.writer(); - try writer.writeAll(" = zig_"); + try writer.writeAll("zig_"); try writer.writeAll(operation); try writer.writeByte('_'); try f.object.dg.renderTypeForBuiltinFnName(writer, operand_ty); @@ -4963,8 +4991,7 @@ fn airBinBuiltinCall( try writer.writeAll(", "); try f.writeCValue(writer, try f.resolveInst(bin_op.rhs), .FunctionArgument); try f.object.dg.renderBuiltinInfo(writer, operand_ty, info); - try writer.writeAll(");\n"); - return local; + try writer.writeAll(")"); } fn airCmpBuiltinCall( @@ -4972,16 +4999,12 @@ fn airCmpBuiltinCall( inst: Air.Inst.Index, operator: []const u8, operation: []const u8, -) !CValue { - if (f.liveness.isUnused(inst)) return CValue.none; - - const inst_ty = f.air.typeOfIndex(inst); +) !void { const bin_op = f.air.instructions.items(.data)[inst].bin_op; const operand_ty = f.air.typeOf(bin_op.lhs); - const local = try f.allocLocal(inst_ty, .Const); const writer = f.object.writer(); - try writer.writeAll(" = zig_"); + try writer.writeAll("zig_"); try writer.writeAll(operation); try writer.writeByte('_'); try f.object.dg.renderTypeForBuiltinFnName(writer, operand_ty); @@ -4989,8 +5012,7 @@ fn airCmpBuiltinCall( try f.writeCValue(writer, try f.resolveInst(bin_op.lhs), .FunctionArgument); try writer.writeAll(", "); try f.writeCValue(writer, try f.resolveInst(bin_op.rhs), .FunctionArgument); - try writer.print(") {s} {};\n", .{ operator, try f.fmtIntLiteral(Type.initTag(.i32), Value.zero) }); - return local; + try writer.print(") {s} {}", .{ operator, try f.fmtIntLiteral(Type.initTag(.i32), Value.zero) }); } fn airCmpxchg(f: *Function, inst: Air.Inst.Index, flavor: [*:0]const u8) !CValue { @@ -5727,15 +5749,18 @@ fn airUnFloatOp(f: *Function, inst: Air.Inst.Index, operation: []const u8) !CVal return local; } -fn airBinFloatOp(f: *Function, inst: Air.Inst.Index, operation: []const u8) !CValue { - if (f.liveness.isUnused(inst)) return CValue.none; +fn airBinFloatOp( + f: *Function, + inst: Air.Inst.Index, + operation: []const u8, +) !void { const bin_op = f.air.instructions.items(.data)[inst].bin_op; const writer = f.object.writer(); const inst_ty = f.air.typeOfIndex(inst); const lhs = try f.resolveInst(bin_op.lhs); const rhs = try f.resolveInst(bin_op.rhs); - const local = try f.allocLocal(inst_ty, .Const); - try writer.writeAll(" = zig_libc_name_"); + + try writer.writeAll("zig_libc_name_"); try f.object.dg.renderTypeForBuiltinFnName(writer, inst_ty); try writer.writeByte('('); try writer.writeAll(operation); @@ -5743,8 +5768,7 @@ fn airBinFloatOp(f: *Function, inst: Air.Inst.Index, operation: []const u8) !CVa try f.writeCValue(writer, lhs, .FunctionArgument); try writer.writeAll(", "); try f.writeCValue(writer, rhs, .FunctionArgument); - try writer.writeAll(");\n"); - return local; + try writer.writeAll(")"); } fn airMulAdd(f: *Function, inst: Air.Inst.Index) !CValue { diff --git a/test/behavior/math.zig b/test/behavior/math.zig index 4b6b882fe5..0ef1bd759f 100644 --- a/test/behavior/math.zig +++ b/test/behavior/math.zig @@ -357,6 +357,8 @@ fn comptimeAdd(comptime a: comptime_int, comptime b: comptime_int) comptime_int } test "binary not" { + if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO + try expect(comptime x: { break :x ~@as(u16, 0b1010101010101010) == 0b0101010101010101; }); From 11ec7109c3d882615c2d220a813100c7f193cc0a Mon Sep 17 00:00:00 2001 From: Veikka Tuominen Date: Wed, 30 Nov 2022 16:29:11 +0200 Subject: [PATCH 12/16] cbe: do not memcpy identical integer types when bitcasting --- src/codegen/c.zig | 42 +++++++++++++++++++++++++++++------------- test/behavior/math.zig | 2 -- 2 files changed, 29 insertions(+), 15 deletions(-) diff --git a/src/codegen/c.zig b/src/codegen/c.zig index 9e814df958..433cef5d9b 100644 --- a/src/codegen/c.zig +++ b/src/codegen/c.zig @@ -3339,6 +3339,9 @@ fn airNot(f: *Function, inst: Air.Inst.Index) !void { const target = f.object.dg.module.getTarget(); if (inst_ty.bitSize(target) > 64) {} + try writer.writeByte('('); + try f.renderTypecast(writer, inst_ty); + try writer.writeByte(')'); try writer.writeByte(if (inst_ty.tag() == .bool) '!' else '~'); try f.writeCValue(writer, op, .Other); } @@ -3357,15 +3360,20 @@ fn airBinOp( if ((operand_ty.isInt() and operand_ty.bitSize(target) > 64) or operand_ty.isRuntimeFloat()) return airBinBuiltinCall(f, inst, operation, info); + const inst_ty = f.air.typeOfIndex(inst); const lhs = try f.resolveInst(bin_op.lhs); const rhs = try f.resolveInst(bin_op.rhs); const writer = f.object.writer(); + try writer.writeByte('('); + try f.renderTypecast(writer, inst_ty); + try writer.writeAll(")("); try f.writeCValue(writer, lhs, .Other); try writer.writeByte(' '); try writer.writeAll(operator); try writer.writeByte(' '); try f.writeCValue(writer, rhs, .Other); + try writer.writeByte(')'); } fn airCmpOp( @@ -3827,32 +3835,40 @@ fn airBr(f: *Function, inst: Air.Inst.Index) !CValue { } fn airBitcast(f: *Function, inst: Air.Inst.Index) !CValue { - const inst_ty = f.air.typeOfIndex(inst); + const src_ty = f.air.typeOfIndex(inst); // No IgnoreComptime until Sema stops giving us garbage Air. // https://github.com/ziglang/zig/issues/13410 - if (f.liveness.isUnused(inst) or !inst_ty.hasRuntimeBits()) return CValue.none; + if (f.liveness.isUnused(inst) or !src_ty.hasRuntimeBits()) return CValue.none; const ty_op = f.air.instructions.items(.data)[inst].ty_op; const operand = try f.resolveInstNoInline(ty_op.operand); + const dest_ty = f.air.typeOf(ty_op.operand); + const target = f.object.dg.module.getTarget(); + + if (dest_ty.isAbiInt() and src_ty.isAbiInt()) { + const src_info = src_ty.intInfo(target); + const dest_info = dest_ty.intInfo(target); + if (std.meta.eql(src_info, dest_info)) { + return operand; + } + } const writer = f.object.writer(); - if (inst_ty.isPtrAtRuntime() and - f.air.typeOf(ty_op.operand).isPtrAtRuntime()) - { - const local = try f.allocLocal(inst_ty, .Const); + if (src_ty.isPtrAtRuntime() and dest_ty.isPtrAtRuntime()) { + const local = try f.allocLocal(src_ty, .Const); try writer.writeAll(" = ("); - try f.renderTypecast(writer, inst_ty); + try f.renderTypecast(writer, src_ty); try writer.writeByte(')'); try f.writeCValue(writer, operand, .Other); try writer.writeAll(";\n"); return local; } - const local = try f.allocLocal(inst_ty, .Mut); + const local = try f.allocLocal(src_ty, .Mut); try writer.writeAll(";\n"); const operand_lval = if (operand == .constant) blk: { - const operand_local = try f.allocLocal(f.air.typeOf(ty_op.operand), .Const); + const operand_local = try f.allocLocal(dest_ty, .Const); try writer.writeAll(" = "); try f.writeCValue(writer, operand, .Initializer); try writer.writeAll(";\n"); @@ -3864,17 +3880,17 @@ fn airBitcast(f: *Function, inst: Air.Inst.Index) !CValue { try writer.writeAll(", &"); try f.writeCValue(writer, operand_lval, .Other); try writer.writeAll(", sizeof("); - try f.renderTypecast(writer, inst_ty); + try f.renderTypecast(writer, src_ty); try writer.writeAll("));\n"); // Ensure padding bits have the expected value. - if (inst_ty.isAbiInt()) { + if (src_ty.isAbiInt()) { try f.writeCValue(writer, local, .Other); try writer.writeAll(" = zig_wrap_"); - try f.object.dg.renderTypeForBuiltinFnName(writer, inst_ty); + try f.object.dg.renderTypeForBuiltinFnName(writer, src_ty); try writer.writeByte('('); try f.writeCValue(writer, local, .Other); - try f.object.dg.renderBuiltinInfo(writer, inst_ty, .Bits); + try f.object.dg.renderBuiltinInfo(writer, src_ty, .Bits); try writer.writeAll(");\n"); } diff --git a/test/behavior/math.zig b/test/behavior/math.zig index 0ef1bd759f..4b6b882fe5 100644 --- a/test/behavior/math.zig +++ b/test/behavior/math.zig @@ -357,8 +357,6 @@ fn comptimeAdd(comptime a: comptime_int, comptime b: comptime_int) comptime_int } test "binary not" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO - try expect(comptime x: { break :x ~@as(u16, 0b1010101010101010) == 0b0101010101010101; }); From f8b779c114a5fcb82f08168912f2300d7027a2fd Mon Sep 17 00:00:00 2001 From: Veikka Tuominen Date: Wed, 30 Nov 2022 17:09:40 +0200 Subject: [PATCH 13/16] cbe: write more instructions inline --- src/codegen/c.zig | 133 +++++++++++++++++++--------------------------- 1 file changed, 56 insertions(+), 77 deletions(-) diff --git a/src/codegen/c.zig b/src/codegen/c.zig index 433cef5d9b..a14154d85f 100644 --- a/src/codegen/c.zig +++ b/src/codegen/c.zig @@ -395,6 +395,27 @@ pub const Function = struct { .shl, => try airBinBuiltinCall(f, inst, "shlw", .Bits), .shl_exact => try airBinOp(f, inst, "<<", "shl", .None), .not => try airNot (f, inst), + + .is_err => try airIsErr(f, inst, false, "!="), + .is_non_err => try airIsErr(f, inst, false, "=="), + .is_err_ptr => try airIsErr(f, inst, true, "!="), + .is_non_err_ptr => try airIsErr(f, inst, true, "=="), + + .is_null => try airIsNull(f, inst, "==", false), + .is_non_null => try airIsNull(f, inst, "!=", false), + .is_null_ptr => try airIsNull(f, inst, "==", true), + .is_non_null_ptr => try airIsNull(f, inst, "!=", true), + + .get_union_tag => try airGetUnionTag(f, inst), + .clz => try airUnBuiltinCall(f, inst, "clz", .Bits), + .ctz => try airUnBuiltinCall(f, inst, "ctz", .Bits), + .popcount => try airUnBuiltinCall(f, inst, "popcount", .Bits), + .byte_swap => try airUnBuiltinCall(f, inst, "byte_swap", .Bits), + .bit_reverse => try airUnBuiltinCall(f, inst, "bit_reverse", .Bits), + .tag_name => try airTagName(f, inst), + .error_name => try airErrorName(f, inst), + + .ptrtoint => try airPtrToInt(f, inst), else => unreachable, // zig fmt: on } @@ -422,6 +443,7 @@ pub const Function = struct { try w.writeByte('.'); return f.writeCValue(w, member, .Other); }, + .inline_index => unreachable, // Use resolveInstNoInline else => return f.object.dg.writeCValueMember(w, c_value, member), } } @@ -2591,15 +2613,15 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO .optional_payload_ptr_set => try airOptionalPayloadPtrSet(f, inst), .wrap_optional => try airWrapOptional(f, inst), - .is_err => try airIsErr(f, inst, false, "!="), - .is_non_err => try airIsErr(f, inst, false, "=="), - .is_err_ptr => try airIsErr(f, inst, true, "!="), - .is_non_err_ptr => try airIsErr(f, inst, true, "=="), + .is_err => CValue{ .inline_index = inst }, + .is_non_err => CValue{ .inline_index = inst }, + .is_err_ptr => CValue{ .inline_index = inst }, + .is_non_err_ptr => CValue{ .inline_index = inst }, - .is_null => try airIsNull(f, inst, "==", false), - .is_non_null => try airIsNull(f, inst, "!=", false), - .is_null_ptr => try airIsNull(f, inst, "==", true), - .is_non_null_ptr => try airIsNull(f, inst, "!=", true), + .is_null => CValue{ .inline_index = inst }, + .is_non_null => CValue{ .inline_index = inst }, + .is_null_ptr => CValue{ .inline_index = inst }, + .is_non_null_ptr => CValue{ .inline_index = inst }, .alloc => try airAlloc(f, inst), .ret_ptr => try airRetPtr(f, inst), @@ -2627,14 +2649,14 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO .memset => try airMemset(f, inst), .memcpy => try airMemcpy(f, inst), .set_union_tag => try airSetUnionTag(f, inst), - .get_union_tag => try airGetUnionTag(f, inst), - .clz => try airUnBuiltinCall(f, inst, "clz", .Bits), - .ctz => try airUnBuiltinCall(f, inst, "ctz", .Bits), - .popcount => try airUnBuiltinCall(f, inst, "popcount", .Bits), - .byte_swap => try airUnBuiltinCall(f, inst, "byte_swap", .Bits), - .bit_reverse => try airUnBuiltinCall(f, inst, "bit_reverse", .Bits), - .tag_name => try airTagName(f, inst), - .error_name => try airErrorName(f, inst), + .get_union_tag => CValue{ .inline_index = inst }, + .clz => CValue{ .inline_index = inst }, + .ctz => CValue{ .inline_index = inst }, + .popcount => CValue{ .inline_index = inst }, + .byte_swap => CValue{ .inline_index = inst }, + .bit_reverse => CValue{ .inline_index = inst }, + .tag_name => CValue{ .inline_index = inst }, + .error_name => CValue{ .inline_index = inst }, .splat => try airSplat(f, inst), .select => try airSelect(f, inst), .shuffle => try airShuffle(f, inst), @@ -2670,7 +2692,7 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO .fpext, => try airFloatCast(f, inst), - .ptrtoint => try airPtrToInt(f, inst), + .ptrtoint => CValue{ .inline_index = inst }, .atomic_store_unordered => try airAtomicStore(f, inst, toMemoryOrder(.Unordered)), .atomic_store_monotonic => try airAtomicStore(f, inst, toMemoryOrder(.Monotonic)), @@ -2754,7 +2776,7 @@ fn airSliceField(f: *Function, inst: Air.Inst.Index, is_ptr: bool, field_name: [ const inst_ty = f.air.typeOfIndex(inst); const ty_op = f.air.instructions.items(.data)[inst].ty_op; - const operand = try f.resolveInst(ty_op.operand); + const operand = try f.resolveInstNoInline(ty_op.operand); const writer = f.object.writer(); const local = try f.allocLocal(inst_ty, .Const); try writer.writeAll(" = "); @@ -4234,16 +4256,11 @@ fn airIsNull( inst: Air.Inst.Index, operator: []const u8, is_ptr: bool, -) !CValue { - if (f.liveness.isUnused(inst)) - return CValue.none; - +) !void { const un_op = f.air.instructions.items(.data)[inst].un_op; const writer = f.object.writer(); const operand = try f.resolveInst(un_op); - const local = try f.allocLocal(Type.initTag(.bool), .Const); - try writer.writeAll(" = "); try if (is_ptr) f.writeCValueDeref(writer, operand) else f.writeCValue(writer, operand, .Other); const operand_ty = f.air.typeOf(un_op); @@ -4271,8 +4288,6 @@ fn airIsNull( try writer.writeAll(operator); try writer.writeByte(' '); try f.object.dg.renderValue(writer, rhs.ty, rhs.val, .Other); - try writer.writeAll(";\n"); - return local; } fn airOptionalPayload(f: *Function, inst: Air.Inst.Index) !CValue { @@ -4842,21 +4857,15 @@ fn airWrapErrUnionPay(f: *Function, inst: Air.Inst.Index) !CValue { return local; } -fn airIsErr(f: *Function, inst: Air.Inst.Index, is_ptr: bool, operator: []const u8) !CValue { - if (f.liveness.isUnused(inst)) - return CValue.none; - +fn airIsErr(f: *Function, inst: Air.Inst.Index, is_ptr: bool, operator: []const u8) !void { const un_op = f.air.instructions.items(.data)[inst].un_op; const writer = f.object.writer(); const operand = try f.resolveInst(un_op); const operand_ty = f.air.typeOf(un_op); - const local = try f.allocLocal(Type.initTag(.bool), .Const); const err_union_ty = if (is_ptr) operand_ty.childType() else operand_ty; const payload_ty = err_union_ty.errorUnionPayload(); const error_ty = err_union_ty.errorUnionSet(); - try writer.writeAll(" = "); - if (!error_ty.errorSetIsEmpty()) if (payload_ty.hasRuntimeBits()) if (is_ptr) @@ -4871,8 +4880,6 @@ fn airIsErr(f: *Function, inst: Air.Inst.Index, is_ptr: bool, operator: []const try writer.writeAll(operator); try writer.writeByte(' '); try f.object.dg.renderValue(writer, error_ty, Value.zero, .Other); - try writer.writeAll(";\n"); - return local; } fn airArrayToSlice(f: *Function, inst: Air.Inst.Index) !CValue { @@ -4946,21 +4953,16 @@ fn airFloatCast(f: *Function, inst: Air.Inst.Index) !CValue { return local; } -fn airPtrToInt(f: *Function, inst: Air.Inst.Index) !CValue { - if (f.liveness.isUnused(inst)) return CValue.none; - +fn airPtrToInt(f: *Function, inst: Air.Inst.Index) !void { const inst_ty = f.air.typeOfIndex(inst); - const local = try f.allocLocal(inst_ty, .Const); const un_op = f.air.instructions.items(.data)[inst].un_op; const writer = f.object.writer(); const operand = try f.resolveInst(un_op); - try writer.writeAll(" = ("); + try writer.writeAll("("); try f.renderTypecast(writer, inst_ty); try writer.writeByte(')'); try f.writeCValue(writer, operand, .Other); - try writer.writeAll(";\n"); - return local; } fn airUnBuiltinCall( @@ -4968,24 +4970,19 @@ fn airUnBuiltinCall( inst: Air.Inst.Index, operation: []const u8, info: BuiltinInfo, -) !CValue { - if (f.liveness.isUnused(inst)) return CValue.none; - - const inst_ty = f.air.typeOfIndex(inst); +) !void { const operand = f.air.instructions.items(.data)[inst].ty_op.operand; const operand_ty = f.air.typeOf(operand); - const local = try f.allocLocal(inst_ty, .Const); const writer = f.object.writer(); - try writer.writeAll(" = zig_"); + try writer.writeAll("zig_"); try writer.writeAll(operation); try writer.writeByte('_'); try f.object.dg.renderTypeForBuiltinFnName(writer, operand_ty); try writer.writeByte('('); try f.writeCValue(writer, try f.resolveInst(operand), .FunctionArgument); try f.object.dg.renderBuiltinInfo(writer, operand_ty, info); - try writer.writeAll(");\n"); - return local; + try writer.writeAll(")"); } fn airBinBuiltinCall( @@ -5258,12 +5255,7 @@ fn airSetUnionTag(f: *Function, inst: Air.Inst.Index) !CValue { return CValue.none; } -fn airGetUnionTag(f: *Function, inst: Air.Inst.Index) !CValue { - if (f.liveness.isUnused(inst)) - return CValue.none; - - const inst_ty = f.air.typeOfIndex(inst); - const local = try f.allocLocal(inst_ty, .Const); +fn airGetUnionTag(f: *Function, inst: Air.Inst.Index) !void { const ty_op = f.air.instructions.items(.data)[inst].ty_op; const un_ty = f.air.typeOf(ty_op.operand); const writer = f.object.writer(); @@ -5271,44 +5263,31 @@ fn airGetUnionTag(f: *Function, inst: Air.Inst.Index) !CValue { const target = f.object.dg.module.getTarget(); const layout = un_ty.unionGetLayout(target); - if (layout.tag_size == 0) return CValue.none; + assert(layout.tag_size != 0); - try writer.writeAll(" = "); try f.writeCValue(writer, operand, .Other); - try writer.writeAll(".tag;\n"); - return local; + try writer.writeAll(".tag"); } -fn airTagName(f: *Function, inst: Air.Inst.Index) !CValue { - if (f.liveness.isUnused(inst)) return CValue.none; - +fn airTagName(f: *Function, inst: Air.Inst.Index) !void { const un_op = f.air.instructions.items(.data)[inst].un_op; - const inst_ty = f.air.typeOfIndex(inst); const enum_ty = f.air.typeOf(un_op); const operand = try f.resolveInst(un_op); const writer = f.object.writer(); - const local = try f.allocLocal(inst_ty, .Const); - try writer.print(" = {s}(", .{try f.object.dg.getTagNameFn(enum_ty)}); + try writer.print("{s}(", .{try f.object.dg.getTagNameFn(enum_ty)}); try f.writeCValue(writer, operand, .Other); - try writer.writeAll(");\n"); - - return local; + try writer.writeAll(")"); } -fn airErrorName(f: *Function, inst: Air.Inst.Index) !CValue { - if (f.liveness.isUnused(inst)) return CValue.none; - +fn airErrorName(f: *Function, inst: Air.Inst.Index) !void { const un_op = f.air.instructions.items(.data)[inst].un_op; const writer = f.object.writer(); - const inst_ty = f.air.typeOfIndex(inst); const operand = try f.resolveInst(un_op); - const local = try f.allocLocal(inst_ty, .Const); - try writer.writeAll(" = zig_errorName["); + try writer.writeAll("zig_errorName["); try f.writeCValue(writer, operand, .Other); - try writer.writeAll("];\n"); - return local; + try writer.writeAll("]"); } fn airSplat(f: *Function, inst: Air.Inst.Index) !CValue { From 98037a02384cdd9fa9c71210fb35d24b82e61f36 Mon Sep 17 00:00:00 2001 From: Veikka Tuominen Date: Wed, 30 Nov 2022 17:20:34 +0200 Subject: [PATCH 14/16] compiler-rt: disable some exports for ofmt=c --- lib/compiler_rt/atomics.zig | 2 +- lib/compiler_rt/memcpy.zig | 5 ++++- lib/compiler_rt/memset.zig | 7 +++++-- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/lib/compiler_rt/atomics.zig b/lib/compiler_rt/atomics.zig index 8f02600564..13ca3a7197 100644 --- a/lib/compiler_rt/atomics.zig +++ b/lib/compiler_rt/atomics.zig @@ -453,7 +453,7 @@ fn __atomic_fetch_nand_8(ptr: *u64, val: u64, model: i32) callconv(.C) u64 { } comptime { - if (supports_atomic_ops) { + if (supports_atomic_ops and builtin.object_format != .c) { @export(__atomic_load, .{ .name = "__atomic_load", .linkage = linkage }); @export(__atomic_store, .{ .name = "__atomic_store", .linkage = linkage }); @export(__atomic_exchange, .{ .name = "__atomic_exchange", .linkage = linkage }); diff --git a/lib/compiler_rt/memcpy.zig b/lib/compiler_rt/memcpy.zig index bbd69edc0c..8f58fe909c 100644 --- a/lib/compiler_rt/memcpy.zig +++ b/lib/compiler_rt/memcpy.zig @@ -1,8 +1,11 @@ const std = @import("std"); const common = @import("./common.zig"); +const builtin = @import("builtin"); comptime { - @export(memcpy, .{ .name = "memcpy", .linkage = common.linkage }); + if (builtin.object_format != .c) { + @export(memcpy, .{ .name = "memcpy", .linkage = common.linkage }); + } } pub fn memcpy(noalias dest: ?[*]u8, noalias src: ?[*]const u8, len: usize) callconv(.C) ?[*]u8 { diff --git a/lib/compiler_rt/memset.zig b/lib/compiler_rt/memset.zig index 1b535fee97..e88e74079a 100644 --- a/lib/compiler_rt/memset.zig +++ b/lib/compiler_rt/memset.zig @@ -1,9 +1,12 @@ const std = @import("std"); const common = @import("./common.zig"); +const builtin = @import("builtin"); comptime { - @export(memset, .{ .name = "memset", .linkage = common.linkage }); - @export(__memset, .{ .name = "__memset", .linkage = common.linkage }); + if (builtin.object_format != .c) { + @export(memset, .{ .name = "memset", .linkage = common.linkage }); + @export(__memset, .{ .name = "__memset", .linkage = common.linkage }); + } } pub fn memset(dest: ?[*]u8, c: u8, len: usize) callconv(.C) ?[*]u8 { From d0edaabf9d5fd4a8a8e43aef38d8970781dd1c86 Mon Sep 17 00:00:00 2001 From: Veikka Tuominen Date: Thu, 1 Dec 2022 11:49:06 +0200 Subject: [PATCH 15/16] Value: fix elemValueAdvanced for optional payloads Closes #13707 --- src/value.zig | 6 ++++++ test/behavior/type.zig | 22 ++++++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/src/value.zig b/src/value.zig index a029be6c7b..be643f65a3 100644 --- a/src/value.zig +++ b/src/value.zig @@ -2895,6 +2895,12 @@ pub const Value = extern union { return val; }, + .opt_payload_ptr => return val.castTag(.opt_payload_ptr).?.data.container_ptr.elemValueAdvanced(mod, index, arena, buffer), + .eu_payload_ptr => return val.castTag(.eu_payload_ptr).?.data.container_ptr.elemValueAdvanced(mod, index, arena, buffer), + + .opt_payload => return val.castTag(.opt_payload).?.data.elemValueAdvanced(mod, index, arena, buffer), + .eu_payload => return val.castTag(.eu_payload).?.data.elemValueAdvanced(mod, index, arena, buffer), + else => unreachable, } } diff --git a/test/behavior/type.zig b/test/behavior/type.zig index 81aeda6171..556a8c990d 100644 --- a/test/behavior/type.zig +++ b/test/behavior/type.zig @@ -535,3 +535,25 @@ test "Type.Fn" { try std.testing.expectEqual(T, fn_type); } } + +test "reified struct field name from optional payload" { + comptime { + const m_name: ?[1]u8 = "a".*; + if (m_name) |*name| { + const T = @Type(.{ .Struct = .{ + .layout = .Auto, + .fields = &.{.{ + .name = name, + .field_type = u8, + .default_value = null, + .is_comptime = false, + .alignment = 1, + }}, + .decls = &.{}, + .is_tuple = false, + } }); + var t: T = .{ .a = 123 }; + try std.testing.expect(t.a == 123); + } + } +} From 6ded2d2adb806845b79f1c5039ab76fdb890a225 Mon Sep 17 00:00:00 2001 From: Veikka Tuominen Date: Thu, 1 Dec 2022 12:18:10 +0200 Subject: [PATCH 16/16] cbe: disable failing behavior test on aarch64 --- test/behavior/basic.zig | 1 + 1 file changed, 1 insertion(+) diff --git a/test/behavior/basic.zig b/test/behavior/basic.zig index 8a815ecb7b..9fd9e03116 100644 --- a/test/behavior/basic.zig +++ b/test/behavior/basic.zig @@ -770,6 +770,7 @@ threadlocal var buffer: [11]u8 = undefined; test "auto created variables have correct alignment" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO const S = struct { fn foo(str: [*]const u8) u32 {