authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-12-01 17:38:11-05:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-12-01 17:38:11-05:00
log4071b22454eb991beefe9f789911a6ba473ce5a4
tree8bc6fd9eb6814a726223b1cb2e8cbf1dc2757cee
parent6e52f36d46f6dbcd4be6295fea6d54868399c12f
parent6ded2d2adb806845b79f1c5039ab76fdb890a225
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #13715 from Vexu/cbe

cbe bug fixes and improvements

21 files changed, 409 insertions(+), 275 deletions(-)

lib/compiler_rt/atomics.zig+1-1
......@@ -453,7 +453,7 @@ fn __atomic_fetch_nand_8(ptr: *u64, val: u64, model: i32) callconv(.C) u64 {
453453}
454454
455455comptime {
456 if (supports_atomic_ops) {
456 if (supports_atomic_ops and builtin.object_format != .c) {
457457 @export(__atomic_load, .{ .name = "__atomic_load", .linkage = linkage });
458458 @export(__atomic_store, .{ .name = "__atomic_store", .linkage = linkage });
459459 @export(__atomic_exchange, .{ .name = "__atomic_exchange", .linkage = linkage });
lib/compiler_rt/memcpy.zig+4-1
......@@ -1,8 +1,11 @@
11const std = @import("std");
22const common = @import("./common.zig");
3const builtin = @import("builtin");
34
45comptime {
5 @export(memcpy, .{ .name = "memcpy", .linkage = common.linkage });
6 if (builtin.object_format != .c) {
7 @export(memcpy, .{ .name = "memcpy", .linkage = common.linkage });
8 }
69}
710
811pub fn memcpy(noalias dest: ?[*]u8, noalias src: ?[*]const u8, len: usize) callconv(.C) ?[*]u8 {
lib/compiler_rt/memset.zig+5-2
......@@ -1,9 +1,12 @@
11const std = @import("std");
22const common = @import("./common.zig");
3const builtin = @import("builtin");
34
45comptime {
5 @export(memset, .{ .name = "memset", .linkage = common.linkage });
6 @export(__memset, .{ .name = "__memset", .linkage = common.linkage });
6 if (builtin.object_format != .c) {
7 @export(memset, .{ .name = "memset", .linkage = common.linkage });
8 @export(__memset, .{ .name = "__memset", .linkage = common.linkage });
9 }
710}
811
912pub fn memset(dest: ?[*]u8, c: u8, len: usize) callconv(.C) ?[*]u8 {
src/AstGen.zig+10-3
......@@ -8551,11 +8551,18 @@ fn shiftOp(
85518551 rhs_node: Ast.Node.Index,
85528552 tag: Zir.Inst.Tag,
85538553) InnerError!Zir.Inst.Ref {
8554 var line = gz.astgen.source_line - gz.decl_line;
8555 var column = gz.astgen.source_column;
85548556 const lhs = try expr(gz, scope, .{ .rl = .none }, lhs_node);
85558557
8556 maybeAdvanceSourceCursorToMainToken(gz, node);
8557 const line = gz.astgen.source_line - gz.decl_line;
8558 const column = gz.astgen.source_column;
8558 switch (gz.astgen.tree.nodes.items(.tag)[node]) {
8559 .shl, .shr => {
8560 maybeAdvanceSourceCursorToMainToken(gz, node);
8561 line = gz.astgen.source_line - gz.decl_line;
8562 column = gz.astgen.source_column;
8563 },
8564 else => {},
8565 }
85598566
85608567 const log2_int_type = try gz.addUnNode(.typeof_log2_int_type, lhs, lhs_node);
85618568 const rhs = try expr(gz, scope, .{ .rl = .{ .ty = log2_int_type }, .ctx = .shift_op }, rhs_node);
src/Sema.zig+2-2
......@@ -3645,7 +3645,7 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com
36453645 const final_elem_ty = try decl.ty.copy(sema.arena);
36463646 const final_ptr_ty = try Type.ptr(sema.arena, sema.mod, .{
36473647 .pointee_type = final_elem_ty,
3648 .mutable = var_is_mut,
3648 .mutable = true,
36493649 .@"align" = iac.data.alignment,
36503650 .@"addrspace" = target_util.defaultAddressSpace(target, .local),
36513651 });
......@@ -3669,7 +3669,7 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com
36693669
36703670 const final_ptr_ty = try Type.ptr(sema.arena, sema.mod, .{
36713671 .pointee_type = final_elem_ty,
3672 .mutable = var_is_mut,
3672 .mutable = true,
36733673 .@"align" = inferred_alloc.data.alignment,
36743674 .@"addrspace" = target_util.defaultAddressSpace(target, .local),
36753675 });
src/codegen/c.zig+353-252
......@@ -50,6 +50,8 @@ pub const CValue = union(enum) {
5050 /// Render these bytes literally.
5151 /// TODO make this a [*:0]const u8 to save memory
5252 bytes: []const u8,
53 /// Index of an instruction that should later be rendered inline.
54 inline_index: Air.Inst.Index,
5355};
5456
5557const BlockData = struct {
......@@ -79,6 +81,7 @@ const ValueRenderLocation = enum {
7981 FunctionArgument,
8082 Initializer,
8183 Other,
84 condition,
8285};
8386
8487const BuiltinInfo = enum {
......@@ -278,6 +281,19 @@ pub const Function = struct {
278281 return result;
279282 }
280283
284 fn resolveInstNoInline(f: *Function, inst: Air.Inst.Ref) !CValue {
285 const operand = try f.resolveInst(inst);
286 if (operand != .inline_index) return operand;
287
288 const inst_ty = f.air.typeOf(inst);
289 const writer = f.object.writer();
290 const local = try f.allocLocal(inst_ty, .Const);
291 try writer.writeAll(" = ");
292 try f.writeCValueInline(operand.inline_index);
293 try writer.writeAll(";\n");
294 return local;
295 }
296
281297 fn wantSafety(f: *Function) bool {
282298 return switch (f.object.dg.module.optimizeMode()) {
283299 .Debug, .ReleaseSafe => true,
......@@ -313,10 +329,95 @@ pub const Function = struct {
313329 .constant => |inst| {
314330 const ty = f.air.typeOf(inst);
315331 const val = f.air.value(inst).?;
316 return f.object.dg.renderValue(w, ty, val, location);
332 try f.object.dg.renderValue(w, ty, val, location);
333 },
334 .undef => |ty| try f.object.dg.renderValue(w, ty, Value.undef, location),
335 .inline_index => |node| {
336 if (location != .condition) try w.writeByte('(');
337 try f.writeCValueInline(node);
338 if (location != .condition) try w.writeByte(')');
317339 },
318 .undef => |ty| return f.object.dg.renderValue(w, ty, Value.undef, location),
319 else => return f.object.dg.writeCValue(w, c_value),
340 else => try f.object.dg.writeCValue(w, c_value),
341 }
342 }
343
344 const E = error{ OutOfMemory, AnalysisFail };
345
346 fn writeCValueInline(f: *Function, inst: Air.Inst.Index) E!void {
347 switch (f.air.instructions.items(.tag)[inst]) {
348 // zig fmt: off
349 // TODO use a different strategy for add, sub, mul, div
350 // that communicates to the optimizer that wrapping is UB.
351 .add => try airBinOp(f, inst, "+", "add", .None),
352 .sub => try airBinOp(f, inst, "-", "sub", .None),
353 .mul => try airBinOp(f, inst, "*", "mul", .None),
354
355 .div_float => try airBinBuiltinCall(f, inst, "div", .None),
356
357 .div_trunc, .div_exact => try airBinOp(f, inst, "/", "div_trunc", .None),
358 .rem => {
359 const bin_op = f.air.instructions.items(.data)[inst].bin_op;
360 const lhs_ty = f.air.typeOf(bin_op.lhs);
361 // For binary operations @TypeOf(lhs)==@TypeOf(rhs),
362 // so we only check one.
363 if (lhs_ty.isInt())
364 try airBinOp(f, inst, "%", "rem", .None)
365 else
366 try airBinFloatOp(f, inst, "fmod");
367 },
368 .div_floor => try airBinBuiltinCall(f, inst, "div_floor", .None),
369 .mod => try airBinBuiltinCall(f, inst, "mod", .None),
370
371 .addwrap => try airBinBuiltinCall(f, inst, "addw", .Bits),
372 .subwrap => try airBinBuiltinCall(f, inst, "subw", .Bits),
373 .mulwrap => try airBinBuiltinCall(f, inst, "mulw", .Bits),
374
375 .add_sat => try airBinBuiltinCall(f, inst, "adds", .Bits),
376 .sub_sat => try airBinBuiltinCall(f, inst, "subs", .Bits),
377 .mul_sat => try airBinBuiltinCall(f, inst, "muls", .Bits),
378 .shl_sat => try airBinBuiltinCall(f, inst, "shls", .Bits),
379
380 .min => try airMinMax(f, inst, '<', "fmin"),
381 .max => try airMinMax(f, inst, '>', "fmax"),
382
383 .cmp_gt => try airCmpOp(f, inst, ">", "gt"),
384 .cmp_gte => try airCmpOp(f, inst, ">=", "ge"),
385 .cmp_lt => try airCmpOp(f, inst, "<", "lt"),
386 .cmp_lte => try airCmpOp(f, inst, "<=", "le"),
387
388 .cmp_eq => try airEquality(f, inst, "((", "==", "eq"),
389 .cmp_neq => try airEquality(f, inst, "!((", "!=", "ne"),
390
391 .bool_and, .bit_and => try airBinOp(f, inst, "&", "and", .None),
392 .bool_or, .bit_or => try airBinOp(f, inst, "|", "or", .None),
393 .xor => try airBinOp(f, inst, "^", "xor", .None),
394 .shr, .shr_exact => try airBinBuiltinCall(f, inst, "shr", .None),
395 .shl, => try airBinBuiltinCall(f, inst, "shlw", .Bits),
396 .shl_exact => try airBinOp(f, inst, "<<", "shl", .None),
397 .not => try airNot (f, inst),
398
399 .is_err => try airIsErr(f, inst, false, "!="),
400 .is_non_err => try airIsErr(f, inst, false, "=="),
401 .is_err_ptr => try airIsErr(f, inst, true, "!="),
402 .is_non_err_ptr => try airIsErr(f, inst, true, "=="),
403
404 .is_null => try airIsNull(f, inst, "==", false),
405 .is_non_null => try airIsNull(f, inst, "!=", false),
406 .is_null_ptr => try airIsNull(f, inst, "==", true),
407 .is_non_null_ptr => try airIsNull(f, inst, "!=", true),
408
409 .get_union_tag => try airGetUnionTag(f, inst),
410 .clz => try airUnBuiltinCall(f, inst, "clz", .Bits),
411 .ctz => try airUnBuiltinCall(f, inst, "ctz", .Bits),
412 .popcount => try airUnBuiltinCall(f, inst, "popcount", .Bits),
413 .byte_swap => try airUnBuiltinCall(f, inst, "byte_swap", .Bits),
414 .bit_reverse => try airUnBuiltinCall(f, inst, "bit_reverse", .Bits),
415 .tag_name => try airTagName(f, inst),
416 .error_name => try airErrorName(f, inst),
417
418 .ptrtoint => try airPtrToInt(f, inst),
419 else => unreachable,
420 // zig fmt: on
320421 }
321422 }
322423
......@@ -342,6 +443,7 @@ pub const Function = struct {
342443 try w.writeByte('.');
343444 return f.writeCValue(w, member, .Other);
344445 },
446 .inline_index => unreachable, // Use resolveInstNoInline
345447 else => return f.object.dg.writeCValueMember(w, c_value, member),
346448 }
347449 }
......@@ -542,9 +644,14 @@ pub const DeclGen = struct {
542644 return dg.renderParentPtr(writer, field_ptr.container_ptr, host_ty);
543645 },
544646 },
545 .Union => FieldInfo{
546 .name = container_ty.unionFields().keys()[index],
547 .ty = container_ty.unionFields().values()[index].ty,
647 .Union => switch (container_ty.containerLayout()) {
648 .Auto, .Extern => FieldInfo{
649 .name = container_ty.unionFields().keys()[index],
650 .ty = container_ty.unionFields().values()[index].ty,
651 },
652 .Packed => {
653 return dg.renderParentPtr(writer, field_ptr.container_ptr, ptr_ty);
654 },
548655 },
549656 .Pointer => field_info: {
550657 assert(container_ty.isSlice());
......@@ -1165,6 +1272,27 @@ pub const DeclGen = struct {
11651272 try writer.writeByte(')');
11661273 }
11671274
1275 const index = ty.unionTagFieldIndex(union_obj.tag, dg.module).?;
1276 const field_ty = ty.unionFields().values()[index].ty;
1277 const field_name = ty.unionFields().keys()[index];
1278 if (ty.containerLayout() == .Packed) {
1279 if (field_ty.hasRuntimeBits()) {
1280 if (field_ty.isPtrAtRuntime()) {
1281 try writer.writeByte('(');
1282 try dg.renderTypecast(writer, ty);
1283 try writer.writeByte(')');
1284 } else if (field_ty.zigTypeTag() == .Float) {
1285 try writer.writeByte('(');
1286 try dg.renderTypecast(writer, ty);
1287 try writer.writeByte(')');
1288 }
1289 try dg.renderValue(writer, field_ty, union_obj.val, .Initializer);
1290 } else {
1291 try writer.writeAll("0");
1292 }
1293 return;
1294 }
1295
11681296 try writer.writeByte('{');
11691297 if (ty.unionTagTypeSafety()) |tag_ty| {
11701298 const layout = ty.unionGetLayout(target);
......@@ -1176,9 +1304,6 @@ pub const DeclGen = struct {
11761304 try writer.writeAll(".payload = {");
11771305 }
11781306
1179 const index = ty.unionTagFieldIndex(union_obj.tag, dg.module).?;
1180 const field_ty = ty.unionFields().values()[index].ty;
1181 const field_name = ty.unionFields().keys()[index];
11821307 var it = ty.unionFields().iterator();
11831308 if (field_ty.hasRuntimeBits()) {
11841309 try writer.print(".{ } = ", .{fmtIdent(field_name)});
......@@ -1445,7 +1570,7 @@ pub const DeclGen = struct {
14451570 if (field_id == 0) try buffer.appendSlice(" char empty_tuple;\n");
14461571 }
14471572 const name_begin = buffer.items.len + "} ".len;
1448 try buffer.writer().print("}} zig_T_{};\n", .{typeToCIdentifier(t, dg.module)});
1573 try buffer.writer().print("}} zig_T_{}_{d};\n", .{ typeToCIdentifier(t, dg.module), @truncate(u16, t.hash(dg.module)) });
14491574 const name_end = buffer.items.len - ";\n".len;
14501575
14511576 const rendered = try buffer.toOwnedSlice();
......@@ -1794,9 +1919,17 @@ pub const DeclGen = struct {
17941919
17951920 return w.writeAll(name);
17961921 },
1797 .Struct, .Union => |tag| if (tag == .Struct and t.containerLayout() == .Packed)
1798 try dg.renderType(w, t.castTag(.@"struct").?.data.backing_int_ty, kind)
1799 else if (t.isSimpleTupleOrAnonStruct()) {
1922 .Struct, .Union => |tag| if (t.containerLayout() == .Packed) {
1923 if (t.castTag(.@"struct")) |struct_obj| {
1924 try dg.renderType(w, struct_obj.data.backing_int_ty, kind);
1925 } else {
1926 var buf: Type.Payload.Bits = .{
1927 .base = .{ .tag = .int_unsigned },
1928 .data = @intCast(u16, t.bitSize(target)),
1929 };
1930 try dg.renderType(w, Type.initPayload(&buf.base), kind);
1931 }
1932 } else if (t.isSimpleTupleOrAnonStruct()) {
18001933 const ExpectedContents = struct { types: [8]Type, values: [8]Value };
18011934 var stack align(@alignOf(ExpectedContents)) =
18021935 std.heap.stackFallback(@sizeOf(ExpectedContents), dg.gpa);
......@@ -1961,7 +2094,7 @@ pub const DeclGen = struct {
19612094 try buffer.appendSlice("static ");
19622095 try dg.renderType(bw, name_slice_ty, .Complete);
19632096 const name_begin = buffer.items.len + " ".len;
1964 try bw.print(" zig_tagName_{}(", .{typeToCIdentifier(enum_ty, dg.module)});
2097 try bw.print(" zig_tagName_{}_{d}(", .{ typeToCIdentifier(enum_ty, dg.module), @enumToInt(enum_ty.getOwnerDecl()) });
19652098 const name_end = buffer.items.len - "(".len;
19662099 try dg.renderTypeAndName(bw, enum_ty, .{ .identifier = "tag" }, .Const, 0, .Complete);
19672100 try buffer.appendSlice(") {\n switch (tag) {\n");
......@@ -2041,7 +2174,7 @@ pub const DeclGen = struct {
20412174
20422175 fn writeCValue(dg: *DeclGen, w: anytype, c_value: CValue) !void {
20432176 switch (c_value) {
2044 .none => unreachable,
2177 .none, .inline_index => unreachable,
20452178 .local => |i| return w.print("t{d}", .{i}),
20462179 .local_ref => |i| return w.print("&t{d}", .{i}),
20472180 .constant => unreachable,
......@@ -2060,7 +2193,7 @@ pub const DeclGen = struct {
20602193
20612194 fn writeCValueDeref(dg: *DeclGen, w: anytype, c_value: CValue) !void {
20622195 switch (c_value) {
2063 .none => unreachable,
2196 .none, .inline_index => unreachable,
20642197 .local => |i| return w.print("(*t{d})", .{i}),
20652198 .local_ref => |i| return w.print("t{d}", .{i}),
20662199 .constant => unreachable,
......@@ -2090,7 +2223,7 @@ pub const DeclGen = struct {
20902223
20912224 fn writeCValueDerefMember(dg: *DeclGen, writer: anytype, c_value: CValue, member: CValue) !void {
20922225 switch (c_value) {
2093 .none, .constant, .field, .undef => unreachable,
2226 .none, .constant, .field, .undef, .inline_index => unreachable,
20942227 .local, .arg, .decl, .identifier, .bytes => {
20952228 try dg.writeCValue(writer, c_value);
20962229 try writer.writeAll("->");
......@@ -2111,11 +2244,16 @@ pub const DeclGen = struct {
21112244 return writer.writeAll(exports.items[0].options.name);
21122245 } else if (decl.isExtern()) {
21132246 return writer.writeAll(mem.sliceTo(decl.name, 0));
2247 } else if (dg.module.test_functions.get(decl_index)) |_| {
2248 const gpa = dg.gpa;
2249 const name = try decl.getFullyQualifiedName(dg.module);
2250 defer gpa.free(name);
2251 return writer.print("{}_{d}", .{ fmtIdent(name), @enumToInt(decl_index) });
21142252 } else {
21152253 const gpa = dg.gpa;
21162254 const name = try decl.getFullyQualifiedName(dg.module);
21172255 defer gpa.free(name);
2118 return writer.print("{ }", .{fmtIdent(name)});
2256 return writer.print("{}", .{fmtIdent(name)});
21192257 }
21202258 }
21212259
......@@ -2401,37 +2539,26 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO
24012539 .ptr_add => try airPtrAddSub(f, inst, '+'),
24022540 .ptr_sub => try airPtrAddSub(f, inst, '-'),
24032541
2404 // TODO use a different strategy for add, sub, mul, div
2405 // that communicates to the optimizer that wrapping is UB.
2406 .add => try airBinOp(f, inst, "+", "add", .None),
2407 .sub => try airBinOp(f, inst, "-", "sub", .None),
2408 .mul => try airBinOp(f, inst, "*", "mul", .None),
2542 .add => CValue{ .inline_index = inst },
2543 .sub => CValue{ .inline_index = inst },
2544 .mul => CValue{ .inline_index = inst },
24092545
24102546 .neg => try airFloatNeg(f, inst),
2411 .div_float => try airBinBuiltinCall(f, inst, "div", .None),
2547 .div_float => CValue{ .inline_index = inst },
24122548
2413 .div_trunc, .div_exact => try airBinOp(f, inst, "/", "div_trunc", .None),
2414 .rem => blk: {
2415 const bin_op = f.air.instructions.items(.data)[inst].bin_op;
2416 const lhs_ty = f.air.typeOf(bin_op.lhs);
2417 // For binary operations @TypeOf(lhs)==@TypeOf(rhs),
2418 // so we only check one.
2419 break :blk if (lhs_ty.isInt())
2420 try airBinOp(f, inst, "%", "rem", .None)
2421 else
2422 try airBinFloatOp(f, inst, "fmod");
2423 },
2424 .div_floor => try airBinBuiltinCall(f, inst, "div_floor", .None),
2425 .mod => try airBinBuiltinCall(f, inst, "mod", .None),
2549 .div_trunc, .div_exact => CValue{ .inline_index = inst },
2550 .rem => CValue{ .inline_index = inst },
2551 .div_floor => CValue{ .inline_index = inst },
2552 .mod => CValue{ .inline_index = inst },
24262553
2427 .addwrap => try airBinBuiltinCall(f, inst, "addw", .Bits),
2428 .subwrap => try airBinBuiltinCall(f, inst, "subw", .Bits),
2429 .mulwrap => try airBinBuiltinCall(f, inst, "mulw", .Bits),
2554 .addwrap => CValue{ .inline_index = inst },
2555 .subwrap => CValue{ .inline_index = inst },
2556 .mulwrap => CValue{ .inline_index = inst },
24302557
2431 .add_sat => try airBinBuiltinCall(f, inst, "adds", .Bits),
2432 .sub_sat => try airBinBuiltinCall(f, inst, "subs", .Bits),
2433 .mul_sat => try airBinBuiltinCall(f, inst, "muls", .Bits),
2434 .shl_sat => try airBinBuiltinCall(f, inst, "shls", .Bits),
2558 .add_sat => CValue{ .inline_index = inst },
2559 .sub_sat => CValue{ .inline_index = inst },
2560 .mul_sat => CValue{ .inline_index = inst },
2561 .shl_sat => CValue{ .inline_index = inst },
24352562
24362563 .sqrt,
24372564 .sin,
......@@ -2456,45 +2583,45 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO
24562583 .mul_with_overflow => try airOverflow(f, inst, "mul", .Bits),
24572584 .shl_with_overflow => try airOverflow(f, inst, "shl", .Bits),
24582585
2459 .min => try airMinMax(f, inst, '<', "fmin"),
2460 .max => try airMinMax(f, inst, '>', "fmax"),
2586 .min => CValue{ .inline_index = inst },
2587 .max => CValue{ .inline_index = inst },
24612588
24622589 .slice => try airSlice(f, inst),
24632590
2464 .cmp_gt => try airCmpOp(f, inst, ">", "gt"),
2465 .cmp_gte => try airCmpOp(f, inst, ">=", "ge"),
2466 .cmp_lt => try airCmpOp(f, inst, "<", "lt"),
2467 .cmp_lte => try airCmpOp(f, inst, "<=", "le"),
2591 .cmp_gt => CValue{ .inline_index = inst },
2592 .cmp_gte => CValue{ .inline_index = inst },
2593 .cmp_lt => CValue{ .inline_index = inst },
2594 .cmp_lte => CValue{ .inline_index = inst },
24682595
2469 .cmp_eq => try airEquality(f, inst, "((", "==", "eq"),
2470 .cmp_neq => try airEquality(f, inst, "!((", "!=", "ne"),
2596 .cmp_eq => CValue{ .inline_index = inst },
2597 .cmp_neq => CValue{ .inline_index = inst },
24712598
24722599 .cmp_vector => return f.fail("TODO: C backend: implement cmp_vector", .{}),
24732600 .cmp_lt_errors_len => try airCmpLtErrorsLen(f, inst),
24742601
24752602 // bool_and and bool_or are non-short-circuit operations
2476 .bool_and, .bit_and => try airBinOp(f, inst, "&", "and", .None),
2477 .bool_or, .bit_or => try airBinOp(f, inst, "|", "or", .None),
2478 .xor => try airBinOp(f, inst, "^", "xor", .None),
2479 .shr, .shr_exact => try airBinBuiltinCall(f, inst, "shr", .None),
2480 .shl, => try airBinBuiltinCall(f, inst, "shlw", .Bits),
2481 .shl_exact => try airBinOp(f, inst, "<<", "shl", .None),
2482 .not => try airNot (f, inst),
2603 .bool_and, .bit_and => CValue{ .inline_index = inst },
2604 .bool_or, .bit_or => CValue{ .inline_index = inst },
2605 .xor => CValue{ .inline_index = inst },
2606 .shr, .shr_exact => CValue{ .inline_index = inst },
2607 .shl, => CValue{ .inline_index = inst },
2608 .shl_exact => CValue{ .inline_index = inst },
2609 .not => CValue{ .inline_index = inst },
24832610
24842611 .optional_payload => try airOptionalPayload(f, inst),
24852612 .optional_payload_ptr => try airOptionalPayloadPtr(f, inst),
24862613 .optional_payload_ptr_set => try airOptionalPayloadPtrSet(f, inst),
24872614 .wrap_optional => try airWrapOptional(f, inst),
24882615
2489 .is_err => try airIsErr(f, inst, false, "!="),
2490 .is_non_err => try airIsErr(f, inst, false, "=="),
2491 .is_err_ptr => try airIsErr(f, inst, true, "!="),
2492 .is_non_err_ptr => try airIsErr(f, inst, true, "=="),
2616 .is_err => CValue{ .inline_index = inst },
2617 .is_non_err => CValue{ .inline_index = inst },
2618 .is_err_ptr => CValue{ .inline_index = inst },
2619 .is_non_err_ptr => CValue{ .inline_index = inst },
24932620
2494 .is_null => try airIsNull(f, inst, "==", false),
2495 .is_non_null => try airIsNull(f, inst, "!=", false),
2496 .is_null_ptr => try airIsNull(f, inst, "==", true),
2497 .is_non_null_ptr => try airIsNull(f, inst, "!=", true),
2621 .is_null => CValue{ .inline_index = inst },
2622 .is_non_null => CValue{ .inline_index = inst },
2623 .is_null_ptr => CValue{ .inline_index = inst },
2624 .is_non_null_ptr => CValue{ .inline_index = inst },
24982625
24992626 .alloc => try airAlloc(f, inst),
25002627 .ret_ptr => try airRetPtr(f, inst),
......@@ -2522,14 +2649,14 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO
25222649 .memset => try airMemset(f, inst),
25232650 .memcpy => try airMemcpy(f, inst),
25242651 .set_union_tag => try airSetUnionTag(f, inst),
2525 .get_union_tag => try airGetUnionTag(f, inst),
2526 .clz => try airUnBuiltinCall(f, inst, "clz", .Bits),
2527 .ctz => try airUnBuiltinCall(f, inst, "ctz", .Bits),
2528 .popcount => try airUnBuiltinCall(f, inst, "popcount", .Bits),
2529 .byte_swap => try airUnBuiltinCall(f, inst, "byte_swap", .Bits),
2530 .bit_reverse => try airUnBuiltinCall(f, inst, "bit_reverse", .Bits),
2531 .tag_name => try airTagName(f, inst),
2532 .error_name => try airErrorName(f, inst),
2652 .get_union_tag => CValue{ .inline_index = inst },
2653 .clz => CValue{ .inline_index = inst },
2654 .ctz => CValue{ .inline_index = inst },
2655 .popcount => CValue{ .inline_index = inst },
2656 .byte_swap => CValue{ .inline_index = inst },
2657 .bit_reverse => CValue{ .inline_index = inst },
2658 .tag_name => CValue{ .inline_index = inst },
2659 .error_name => CValue{ .inline_index = inst },
25332660 .splat => try airSplat(f, inst),
25342661 .select => try airSelect(f, inst),
25352662 .shuffle => try airShuffle(f, inst),
......@@ -2565,7 +2692,7 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO
25652692 .fpext,
25662693 => try airFloatCast(f, inst),
25672694
2568 .ptrtoint => try airPtrToInt(f, inst),
2695 .ptrtoint => CValue{ .inline_index = inst },
25692696
25702697 .atomic_store_unordered => try airAtomicStore(f, inst, toMemoryOrder(.Unordered)),
25712698 .atomic_store_monotonic => try airAtomicStore(f, inst, toMemoryOrder(.Monotonic)),
......@@ -2649,7 +2776,7 @@ fn airSliceField(f: *Function, inst: Air.Inst.Index, is_ptr: bool, field_name: [
26492776
26502777 const inst_ty = f.air.typeOfIndex(inst);
26512778 const ty_op = f.air.instructions.items(.data)[inst].ty_op;
2652 const operand = try f.resolveInst(ty_op.operand);
2779 const operand = try f.resolveInstNoInline(ty_op.operand);
26532780 const writer = f.object.writer();
26542781 const local = try f.allocLocal(inst_ty, .Const);
26552782 try writer.writeAll(" = ");
......@@ -3224,25 +3351,21 @@ fn airOverflow(f: *Function, inst: Air.Inst.Index, operation: []const u8, info:
32243351 return local;
32253352}
32263353
3227fn airNot(f: *Function, inst: Air.Inst.Index) !CValue {
3228 if (f.liveness.isUnused(inst)) return CValue.none;
3229
3354fn airNot(f: *Function, inst: Air.Inst.Index) !void {
32303355 const ty_op = f.air.instructions.items(.data)[inst].ty_op;
32313356 const op = try f.resolveInst(ty_op.operand);
32323357
32333358 const writer = f.object.writer();
32343359 const inst_ty = f.air.typeOfIndex(inst);
3235 const local = try f.allocLocal(inst_ty, .Const);
32363360
32373361 const target = f.object.dg.module.getTarget();
32383362 if (inst_ty.bitSize(target) > 64) {}
32393363
3240 try writer.writeAll(" = ");
3364 try writer.writeByte('(');
3365 try f.renderTypecast(writer, inst_ty);
3366 try writer.writeByte(')');
32413367 try writer.writeByte(if (inst_ty.tag() == .bool) '!' else '~');
32423368 try f.writeCValue(writer, op, .Other);
3243 try writer.writeAll(";\n");
3244
3245 return local;
32463369}
32473370
32483371fn airBinOp(
......@@ -3251,62 +3374,54 @@ fn airBinOp(
32513374 operator: []const u8,
32523375 operation: []const u8,
32533376 info: BuiltinInfo,
3254) !CValue {
3255 if (f.liveness.isUnused(inst)) return CValue.none;
3256
3377) !void {
32573378 const bin_op = f.air.instructions.items(.data)[inst].bin_op;
32583379
32593380 const operand_ty = f.air.typeOf(bin_op.lhs);
32603381 const target = f.object.dg.module.getTarget();
32613382 if ((operand_ty.isInt() and operand_ty.bitSize(target) > 64) or operand_ty.isRuntimeFloat())
3262 return try airBinBuiltinCall(f, inst, operation, info);
3383 return airBinBuiltinCall(f, inst, operation, info);
32633384
32643385 const inst_ty = f.air.typeOfIndex(inst);
32653386 const lhs = try f.resolveInst(bin_op.lhs);
32663387 const rhs = try f.resolveInst(bin_op.rhs);
32673388
32683389 const writer = f.object.writer();
3269 const local = try f.allocLocal(inst_ty, .Const);
3270
3271 try writer.writeAll(" = ");
3390 try writer.writeByte('(');
3391 try f.renderTypecast(writer, inst_ty);
3392 try writer.writeAll(")(");
32723393 try f.writeCValue(writer, lhs, .Other);
32733394 try writer.writeByte(' ');
32743395 try writer.writeAll(operator);
32753396 try writer.writeByte(' ');
32763397 try f.writeCValue(writer, rhs, .Other);
3277 try writer.writeAll(";\n");
3278
3279 return local;
3398 try writer.writeByte(')');
32803399}
32813400
3282fn airCmpOp(f: *Function, inst: Air.Inst.Index, operator: []const u8, operation: []const u8) !CValue {
3283 if (f.liveness.isUnused(inst)) return CValue.none;
3284
3401fn airCmpOp(
3402 f: *Function,
3403 inst: Air.Inst.Index,
3404 operator: []const u8,
3405 operation: []const u8,
3406) !void {
32853407 const bin_op = f.air.instructions.items(.data)[inst].bin_op;
32863408
32873409 const operand_ty = f.air.typeOf(bin_op.lhs);
32883410 const target = f.object.dg.module.getTarget();
32893411 if (operand_ty.isInt() and operand_ty.bitSize(target) > 64)
3290 return try airCmpBuiltinCall(f, inst, operator, "cmp");
3412 return airCmpBuiltinCall(f, inst, operator, "cmp");
32913413 if (operand_ty.isRuntimeFloat())
3292 return try airCmpBuiltinCall(f, inst, operator, operation);
3414 return airCmpBuiltinCall(f, inst, operator, operation);
32933415
3294 const inst_ty = f.air.typeOfIndex(inst);
32953416 const lhs = try f.resolveInst(bin_op.lhs);
32963417 const rhs = try f.resolveInst(bin_op.rhs);
32973418
32983419 const writer = f.object.writer();
3299 const local = try f.allocLocal(inst_ty, .Const);
3300
3301 try writer.writeAll(" = ");
33023420 try f.writeCValue(writer, lhs, .Other);
33033421 try writer.writeByte(' ');
33043422 try writer.writeAll(operator);
33053423 try writer.writeByte(' ');
33063424 try f.writeCValue(writer, rhs, .Other);
3307 try writer.writeAll(";\n");
3308
3309 return local;
33103425}
33113426
33123427fn airEquality(
......@@ -3315,27 +3430,20 @@ fn airEquality(
33153430 negate_prefix: []const u8,
33163431 operator: []const u8,
33173432 operation: []const u8,
3318) !CValue {
3319 if (f.liveness.isUnused(inst)) return CValue.none;
3320
3433) !void {
33213434 const bin_op = f.air.instructions.items(.data)[inst].bin_op;
33223435
33233436 const operand_ty = f.air.typeOf(bin_op.lhs);
33243437 const target = f.object.dg.module.getTarget();
33253438 if (operand_ty.isInt() and operand_ty.bitSize(target) > 64)
3326 return try airCmpBuiltinCall(f, inst, operator, "cmp");
3439 return airCmpBuiltinCall(f, inst, operator, "cmp");
33273440 if (operand_ty.isRuntimeFloat())
3328 return try airCmpBuiltinCall(f, inst, operator, operation);
3441 return airCmpBuiltinCall(f, inst, operator, operation);
33293442
33303443 const lhs = try f.resolveInst(bin_op.lhs);
33313444 const rhs = try f.resolveInst(bin_op.rhs);
33323445
33333446 const writer = f.object.writer();
3334 const inst_ty = f.air.typeOfIndex(inst);
3335 const local = try f.allocLocal(inst_ty, .Const);
3336
3337 try writer.writeAll(" = ");
3338
33393447 if (operand_ty.zigTypeTag() == .Optional and !operand_ty.isPtrLikeOptional()) {
33403448 // (A && B) || (C && (A == B))
33413449 // A = lhs.is_null ; B = rhs.is_null ; C = rhs.payload == lhs.payload
......@@ -3352,9 +3460,8 @@ fn airEquality(
33523460 try f.writeCValue(writer, lhs, .Other);
33533461 try writer.writeAll(".is_null == ");
33543462 try f.writeCValue(writer, rhs, .Other);
3355 try writer.writeAll(".is_null));\n");
3356
3357 return local;
3463 try writer.writeAll(".is_null))");
3464 return;
33583465 }
33593466
33603467 try f.writeCValue(writer, lhs, .Other);
......@@ -3362,9 +3469,6 @@ fn airEquality(
33623469 try writer.writeAll(operator);
33633470 try writer.writeByte(' ');
33643471 try f.writeCValue(writer, rhs, .Other);
3365 try writer.writeAll(";\n");
3366
3367 return local;
33683472}
33693473
33703474fn airCmpLtErrorsLen(f: *Function, inst: Air.Inst.Index) !CValue {
......@@ -3418,26 +3522,23 @@ fn airPtrAddSub(f: *Function, inst: Air.Inst.Index, operator: u8) !CValue {
34183522 return local;
34193523}
34203524
3421fn airMinMax(f: *Function, inst: Air.Inst.Index, operator: u8, operation: []const u8) !CValue {
3422 if (f.liveness.isUnused(inst)) return CValue.none;
3423
3525fn airMinMax(f: *Function, inst: Air.Inst.Index, operator: u8, operation: []const u8) !void {
34243526 const bin_op = f.air.instructions.items(.data)[inst].bin_op;
34253527
34263528 const inst_ty = f.air.typeOfIndex(inst);
34273529 const target = f.object.dg.module.getTarget();
34283530 if (inst_ty.isInt() and inst_ty.bitSize(target) > 64)
3429 return try airBinBuiltinCall(f, inst, operation[1..], .None);
3531 return airBinBuiltinCall(f, inst, operation[1..], .None);
34303532 if (inst_ty.isRuntimeFloat())
3431 return try airBinFloatOp(f, inst, operation);
3533 return airBinFloatOp(f, inst, operation);
34323534
34333535 const lhs = try f.resolveInst(bin_op.lhs);
34343536 const rhs = try f.resolveInst(bin_op.rhs);
34353537
34363538 const writer = f.object.writer();
3437 const local = try f.allocLocal(inst_ty, .Const);
34383539
34393540 // (lhs <> rhs) ? lhs : rhs
3440 try writer.writeAll(" = (");
3541 try writer.writeAll("(");
34413542 try f.writeCValue(writer, lhs, .Other);
34423543 try writer.writeByte(' ');
34433544 try writer.writeByte(operator);
......@@ -3447,9 +3548,6 @@ fn airMinMax(f: *Function, inst: Air.Inst.Index, operator: u8, operation: []cons
34473548 try f.writeCValue(writer, lhs, .Other);
34483549 try writer.writeAll(" : ");
34493550 try f.writeCValue(writer, rhs, .Other);
3450 try writer.writeAll(";\n");
3451
3452 return local;
34533551}
34543552
34553553fn airSlice(f: *Function, inst: Air.Inst.Index) !CValue {
......@@ -3759,46 +3857,62 @@ fn airBr(f: *Function, inst: Air.Inst.Index) !CValue {
37593857}
37603858
37613859fn airBitcast(f: *Function, inst: Air.Inst.Index) !CValue {
3762 const inst_ty = f.air.typeOfIndex(inst);
3860 const src_ty = f.air.typeOfIndex(inst);
37633861 // No IgnoreComptime until Sema stops giving us garbage Air.
37643862 // https://github.com/ziglang/zig/issues/13410
3765 if (f.liveness.isUnused(inst) or !inst_ty.hasRuntimeBits()) return CValue.none;
3863 if (f.liveness.isUnused(inst) or !src_ty.hasRuntimeBits()) return CValue.none;
37663864
37673865 const ty_op = f.air.instructions.items(.data)[inst].ty_op;
3768 const operand = try f.resolveInst(ty_op.operand);
3866 const operand = try f.resolveInstNoInline(ty_op.operand);
3867 const dest_ty = f.air.typeOf(ty_op.operand);
3868 const target = f.object.dg.module.getTarget();
3869
3870 if (dest_ty.isAbiInt() and src_ty.isAbiInt()) {
3871 const src_info = src_ty.intInfo(target);
3872 const dest_info = dest_ty.intInfo(target);
3873 if (std.meta.eql(src_info, dest_info)) {
3874 return operand;
3875 }
3876 }
37693877
37703878 const writer = f.object.writer();
3771 if (inst_ty.isPtrAtRuntime() and
3772 f.air.typeOf(ty_op.operand).isPtrAtRuntime())
3773 {
3774 const local = try f.allocLocal(inst_ty, .Const);
3879 if (src_ty.isPtrAtRuntime() and dest_ty.isPtrAtRuntime()) {
3880 const local = try f.allocLocal(src_ty, .Const);
37753881 try writer.writeAll(" = (");
3776 try f.renderTypecast(writer, inst_ty);
3882 try f.renderTypecast(writer, src_ty);
37773883 try writer.writeByte(')');
37783884 try f.writeCValue(writer, operand, .Other);
37793885 try writer.writeAll(";\n");
37803886 return local;
37813887 }
37823888
3783 const local = try f.allocLocal(inst_ty, .Mut);
3889 const local = try f.allocLocal(src_ty, .Mut);
37843890 try writer.writeAll(";\n");
37853891
3892 const operand_lval = if (operand == .constant) blk: {
3893 const operand_local = try f.allocLocal(dest_ty, .Const);
3894 try writer.writeAll(" = ");
3895 try f.writeCValue(writer, operand, .Initializer);
3896 try writer.writeAll(";\n");
3897 break :blk operand_local;
3898 } else operand;
3899
37863900 try writer.writeAll("memcpy(&");
37873901 try f.writeCValue(writer, local, .Other);
37883902 try writer.writeAll(", &");
3789 try f.writeCValue(writer, operand, .Other);
3903 try f.writeCValue(writer, operand_lval, .Other);
37903904 try writer.writeAll(", sizeof(");
3791 try f.renderTypecast(writer, inst_ty);
3905 try f.renderTypecast(writer, src_ty);
37923906 try writer.writeAll("));\n");
37933907
37943908 // Ensure padding bits have the expected value.
3795 if (inst_ty.isAbiInt()) {
3909 if (src_ty.isAbiInt()) {
37963910 try f.writeCValue(writer, local, .Other);
37973911 try writer.writeAll(" = zig_wrap_");
3798 try f.object.dg.renderTypeForBuiltinFnName(writer, inst_ty);
3912 try f.object.dg.renderTypeForBuiltinFnName(writer, src_ty);
37993913 try writer.writeByte('(');
38003914 try f.writeCValue(writer, local, .Other);
3801 try f.object.dg.renderBuiltinInfo(writer, inst_ty, .Bits);
3915 try f.object.dg.renderBuiltinInfo(writer, src_ty, .Bits);
38023916 try writer.writeAll(");\n");
38033917 }
38043918
......@@ -3855,7 +3969,7 @@ fn airLoop(f: *Function, inst: Air.Inst.Index) !CValue {
38553969 const body = f.air.extra[loop.end..][0..loop.data.body_len];
38563970 const writer = f.object.writer();
38573971 try writer.writeAll("while (");
3858 try f.object.dg.renderValue(writer, Type.bool, Value.true, .Other);
3972 try f.object.dg.renderValue(writer, Type.bool, Value.true, .condition);
38593973 try writer.writeAll(") ");
38603974 try genBody(f, body);
38613975 try writer.writeByte('\n');
......@@ -3871,7 +3985,7 @@ fn airCondBr(f: *Function, inst: Air.Inst.Index) !CValue {
38713985 const writer = f.object.writer();
38723986
38733987 try writer.writeAll("if (");
3874 try f.writeCValue(writer, cond, .Other);
3988 try f.writeCValue(writer, cond, .condition);
38753989 try writer.writeAll(") ");
38763990 try genBody(f, then_body);
38773991 try writer.writeAll(" else ");
......@@ -3889,10 +4003,14 @@ fn airSwitchBr(f: *Function, inst: Air.Inst.Index) !CValue {
38894003 const writer = f.object.writer();
38904004
38914005 try writer.writeAll("switch (");
3892 if (condition_ty.tag() == .bool) {
4006 if (condition_ty.zigTypeTag() == .Bool) {
38934007 try writer.writeByte('(');
38944008 try f.renderTypecast(writer, Type.u1);
38954009 try writer.writeByte(')');
4010 } else if (condition_ty.isPtrAtRuntime()) {
4011 try writer.writeByte('(');
4012 try f.renderTypecast(writer, Type.usize);
4013 try writer.writeByte(')');
38964014 }
38974015 try f.writeCValue(writer, condition, .Other);
38984016 try writer.writeAll(") {");
......@@ -3909,6 +4027,11 @@ fn airSwitchBr(f: *Function, inst: Air.Inst.Index) !CValue {
39094027 for (items) |item| {
39104028 try f.object.indent_writer.insertNewline();
39114029 try writer.writeAll("case ");
4030 if (condition_ty.isPtrAtRuntime()) {
4031 try writer.writeByte('(');
4032 try f.renderTypecast(writer, Type.usize);
4033 try writer.writeByte(')');
4034 }
39124035 try f.object.dg.renderValue(writer, condition_ty, f.air.value(item).?, .Other);
39134036 try writer.writeAll(": ");
39144037 }
......@@ -4055,6 +4178,8 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
40554178 if (is_reg) {
40564179 try f.writeCValue(writer, .{ .local = locals_index }, .Other);
40574180 locals_index += 1;
4181 } else if (output == .none) {
4182 try f.writeCValue(writer, local, .FunctionArgument);
40584183 } else {
40594184 try f.writeCValueDeref(writer, try f.resolveInst(output));
40604185 }
......@@ -4131,16 +4256,11 @@ fn airIsNull(
41314256 inst: Air.Inst.Index,
41324257 operator: []const u8,
41334258 is_ptr: bool,
4134) !CValue {
4135 if (f.liveness.isUnused(inst))
4136 return CValue.none;
4137
4259) !void {
41384260 const un_op = f.air.instructions.items(.data)[inst].un_op;
41394261 const writer = f.object.writer();
41404262 const operand = try f.resolveInst(un_op);
41414263
4142 const local = try f.allocLocal(Type.initTag(.bool), .Const);
4143 try writer.writeAll(" = ");
41444264 try if (is_ptr) f.writeCValueDeref(writer, operand) else f.writeCValue(writer, operand, .Other);
41454265
41464266 const operand_ty = f.air.typeOf(un_op);
......@@ -4168,8 +4288,6 @@ fn airIsNull(
41684288 try writer.writeAll(operator);
41694289 try writer.writeByte(' ');
41704290 try f.object.dg.renderValue(writer, rhs.ty, rhs.val, .Other);
4171 try writer.writeAll(";\n");
4172 return local;
41734291}
41744292
41754293fn airOptionalPayload(f: *Function, inst: Air.Inst.Index) !CValue {
......@@ -4358,6 +4476,10 @@ fn structFieldPtr(f: *Function, inst: Air.Inst.Index, struct_ptr_ty: Type, struc
43584476 u8_ptr_pl.data.pointee_type = Type.u8;
43594477 const u8_ptr_ty = Type.initPayload(&u8_ptr_pl.base);
43604478
4479 if (!std.mem.isAligned(byte_offset, field_ptr_ty.ptrAlignment(target))) {
4480 return f.fail("TODO: CBE: unaligned packed struct field pointer", .{});
4481 }
4482
43614483 try writer.writeAll("&((");
43624484 try f.renderTypecast(writer, u8_ptr_ty);
43634485 try writer.writeByte(')');
......@@ -4366,7 +4488,11 @@ fn structFieldPtr(f: *Function, inst: Air.Inst.Index, struct_ptr_ty: Type, struc
43664488 return local;
43674489 } else @as(CValue, CValue.none), // this @as is needed because of a stage1 bug
43684490 },
4369 .@"union", .union_safety_tagged, .union_tagged => .{
4491 .@"union", .union_safety_tagged, .union_tagged => if (struct_ty.containerLayout() == .Packed) {
4492 try f.writeCValue(writer, struct_ptr, .Other);
4493 try writer.writeAll(";\n");
4494 return local;
4495 } else .{
43704496 .identifier = struct_ty.unionFields().keys()[index],
43714497 },
43724498 .tuple, .anon_struct => field_name: {
......@@ -4480,7 +4606,26 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {
44804606 return local;
44814607 },
44824608 },
4483 .@"union", .union_safety_tagged, .union_tagged => .{
4609 .@"union", .union_safety_tagged, .union_tagged => if (struct_ty.containerLayout() == .Packed) {
4610 const operand_lval = if (struct_byval == .constant) blk: {
4611 const operand_local = try f.allocLocal(struct_ty, .Const);
4612 try writer.writeAll(" = ");
4613 try f.writeCValue(writer, struct_byval, .Initializer);
4614 try writer.writeAll(";\n");
4615 break :blk operand_local;
4616 } else struct_byval;
4617
4618 const local = try f.allocLocal(inst_ty, .Mut);
4619 try writer.writeAll(";\n");
4620 try writer.writeAll("memcpy(&");
4621 try f.writeCValue(writer, local, .FunctionArgument);
4622 try writer.writeAll(", &");
4623 try f.writeCValue(writer, operand_lval, .FunctionArgument);
4624 try writer.writeAll(", sizeof(");
4625 try f.renderTypecast(writer, inst_ty);
4626 try writer.writeAll("));\n");
4627 return local;
4628 } else .{
44844629 .identifier = struct_ty.unionFields().keys()[extra.field_index],
44854630 },
44864631 .tuple, .anon_struct => blk: {
......@@ -4558,7 +4703,18 @@ fn airUnwrapErrUnionPay(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValu
45584703 const operand_is_ptr = operand_ty.zigTypeTag() == .Pointer;
45594704 const error_union_ty = if (operand_is_ptr) operand_ty.childType() else operand_ty;
45604705
4561 if (!error_union_ty.errorUnionPayload().hasRuntimeBits()) return CValue.none;
4706 if (!error_union_ty.errorUnionPayload().hasRuntimeBits()) {
4707 if (!is_ptr) return CValue.none;
4708
4709 const local = try f.allocLocal(inst_ty, .Const);
4710 const w = f.object.writer();
4711 try w.writeAll(" = (");
4712 try f.renderTypecast(w, inst_ty);
4713 try w.writeByte(')');
4714 try f.writeCValue(w, operand, .Initializer);
4715 try w.writeAll(";\n");
4716 return local;
4717 }
45624718
45634719 const writer = f.object.writer();
45644720 const local = try f.allocLocal(inst_ty, .Const);
......@@ -4701,21 +4857,15 @@ fn airWrapErrUnionPay(f: *Function, inst: Air.Inst.Index) !CValue {
47014857 return local;
47024858}
47034859
4704fn airIsErr(f: *Function, inst: Air.Inst.Index, is_ptr: bool, operator: []const u8) !CValue {
4705 if (f.liveness.isUnused(inst))
4706 return CValue.none;
4707
4860fn airIsErr(f: *Function, inst: Air.Inst.Index, is_ptr: bool, operator: []const u8) !void {
47084861 const un_op = f.air.instructions.items(.data)[inst].un_op;
47094862 const writer = f.object.writer();
47104863 const operand = try f.resolveInst(un_op);
47114864 const operand_ty = f.air.typeOf(un_op);
4712 const local = try f.allocLocal(Type.initTag(.bool), .Const);
47134865 const err_union_ty = if (is_ptr) operand_ty.childType() else operand_ty;
47144866 const payload_ty = err_union_ty.errorUnionPayload();
47154867 const error_ty = err_union_ty.errorUnionSet();
47164868
4717 try writer.writeAll(" = ");
4718
47194869 if (!error_ty.errorSetIsEmpty())
47204870 if (payload_ty.hasRuntimeBits())
47214871 if (is_ptr)
......@@ -4730,8 +4880,6 @@ fn airIsErr(f: *Function, inst: Air.Inst.Index, is_ptr: bool, operator: []const
47304880 try writer.writeAll(operator);
47314881 try writer.writeByte(' ');
47324882 try f.object.dg.renderValue(writer, error_ty, Value.zero, .Other);
4733 try writer.writeAll(";\n");
4734 return local;
47354883}
47364884
47374885fn airArrayToSlice(f: *Function, inst: Air.Inst.Index) !CValue {
......@@ -4805,21 +4953,16 @@ fn airFloatCast(f: *Function, inst: Air.Inst.Index) !CValue {
48054953 return local;
48064954}
48074955
4808fn airPtrToInt(f: *Function, inst: Air.Inst.Index) !CValue {
4809 if (f.liveness.isUnused(inst)) return CValue.none;
4810
4956fn airPtrToInt(f: *Function, inst: Air.Inst.Index) !void {
48114957 const inst_ty = f.air.typeOfIndex(inst);
4812 const local = try f.allocLocal(inst_ty, .Const);
48134958 const un_op = f.air.instructions.items(.data)[inst].un_op;
48144959 const writer = f.object.writer();
48154960 const operand = try f.resolveInst(un_op);
48164961
4817 try writer.writeAll(" = (");
4962 try writer.writeAll("(");
48184963 try f.renderTypecast(writer, inst_ty);
48194964 try writer.writeByte(')');
48204965 try f.writeCValue(writer, operand, .Other);
4821 try writer.writeAll(";\n");
4822 return local;
48234966}
48244967
48254968fn airUnBuiltinCall(
......@@ -4827,24 +4970,19 @@ fn airUnBuiltinCall(
48274970 inst: Air.Inst.Index,
48284971 operation: []const u8,
48294972 info: BuiltinInfo,
4830) !CValue {
4831 if (f.liveness.isUnused(inst)) return CValue.none;
4832
4833 const inst_ty = f.air.typeOfIndex(inst);
4973) !void {
48344974 const operand = f.air.instructions.items(.data)[inst].ty_op.operand;
48354975 const operand_ty = f.air.typeOf(operand);
48364976
4837 const local = try f.allocLocal(inst_ty, .Const);
48384977 const writer = f.object.writer();
4839 try writer.writeAll(" = zig_");
4978 try writer.writeAll("zig_");
48404979 try writer.writeAll(operation);
48414980 try writer.writeByte('_');
48424981 try f.object.dg.renderTypeForBuiltinFnName(writer, operand_ty);
48434982 try writer.writeByte('(');
48444983 try f.writeCValue(writer, try f.resolveInst(operand), .FunctionArgument);
48454984 try f.object.dg.renderBuiltinInfo(writer, operand_ty, info);
4846 try writer.writeAll(");\n");
4847 return local;
4985 try writer.writeAll(")");
48484986}
48494987
48504988fn airBinBuiltinCall(
......@@ -4852,16 +4990,12 @@ fn airBinBuiltinCall(
48524990 inst: Air.Inst.Index,
48534991 operation: []const u8,
48544992 info: BuiltinInfo,
4855) !CValue {
4856 if (f.liveness.isUnused(inst)) return CValue.none;
4857
4858 const inst_ty = f.air.typeOfIndex(inst);
4993) !void {
48594994 const bin_op = f.air.instructions.items(.data)[inst].bin_op;
48604995 const operand_ty = f.air.typeOf(bin_op.lhs);
48614996
4862 const local = try f.allocLocal(inst_ty, .Const);
48634997 const writer = f.object.writer();
4864 try writer.writeAll(" = zig_");
4998 try writer.writeAll("zig_");
48654999 try writer.writeAll(operation);
48665000 try writer.writeByte('_');
48675001 try f.object.dg.renderTypeForBuiltinFnName(writer, operand_ty);
......@@ -4870,8 +5004,7 @@ fn airBinBuiltinCall(
48705004 try writer.writeAll(", ");
48715005 try f.writeCValue(writer, try f.resolveInst(bin_op.rhs), .FunctionArgument);
48725006 try f.object.dg.renderBuiltinInfo(writer, operand_ty, info);
4873 try writer.writeAll(");\n");
4874 return local;
5007 try writer.writeAll(")");
48755008}
48765009
48775010fn airCmpBuiltinCall(
......@@ -4879,16 +5012,12 @@ fn airCmpBuiltinCall(
48795012 inst: Air.Inst.Index,
48805013 operator: []const u8,
48815014 operation: []const u8,
4882) !CValue {
4883 if (f.liveness.isUnused(inst)) return CValue.none;
4884
4885 const inst_ty = f.air.typeOfIndex(inst);
5015) !void {
48865016 const bin_op = f.air.instructions.items(.data)[inst].bin_op;
48875017 const operand_ty = f.air.typeOf(bin_op.lhs);
48885018
4889 const local = try f.allocLocal(inst_ty, .Const);
48905019 const writer = f.object.writer();
4891 try writer.writeAll(" = zig_");
5020 try writer.writeAll("zig_");
48925021 try writer.writeAll(operation);
48935022 try writer.writeByte('_');
48945023 try f.object.dg.renderTypeForBuiltinFnName(writer, operand_ty);
......@@ -4896,8 +5025,7 @@ fn airCmpBuiltinCall(
48965025 try f.writeCValue(writer, try f.resolveInst(bin_op.lhs), .FunctionArgument);
48975026 try writer.writeAll(", ");
48985027 try f.writeCValue(writer, try f.resolveInst(bin_op.rhs), .FunctionArgument);
4899 try writer.print(") {s} {};\n", .{ operator, try f.fmtIntLiteral(Type.initTag(.i32), Value.zero) });
4900 return local;
5028 try writer.print(") {s} {}", .{ operator, try f.fmtIntLiteral(Type.initTag(.i32), Value.zero) });
49015029}
49025030
49035031fn airCmpxchg(f: *Function, inst: Air.Inst.Index, flavor: [*:0]const u8) !CValue {
......@@ -5127,12 +5255,7 @@ fn airSetUnionTag(f: *Function, inst: Air.Inst.Index) !CValue {
51275255 return CValue.none;
51285256}
51295257
5130fn airGetUnionTag(f: *Function, inst: Air.Inst.Index) !CValue {
5131 if (f.liveness.isUnused(inst))
5132 return CValue.none;
5133
5134 const inst_ty = f.air.typeOfIndex(inst);
5135 const local = try f.allocLocal(inst_ty, .Const);
5258fn airGetUnionTag(f: *Function, inst: Air.Inst.Index) !void {
51365259 const ty_op = f.air.instructions.items(.data)[inst].ty_op;
51375260 const un_ty = f.air.typeOf(ty_op.operand);
51385261 const writer = f.object.writer();
......@@ -5140,44 +5263,31 @@ fn airGetUnionTag(f: *Function, inst: Air.Inst.Index) !CValue {
51405263
51415264 const target = f.object.dg.module.getTarget();
51425265 const layout = un_ty.unionGetLayout(target);
5143 if (layout.tag_size == 0) return CValue.none;
5266 assert(layout.tag_size != 0);
51445267
5145 try writer.writeAll(" = ");
51465268 try f.writeCValue(writer, operand, .Other);
5147 try writer.writeAll(".tag;\n");
5148 return local;
5269 try writer.writeAll(".tag");
51495270}
51505271
5151fn airTagName(f: *Function, inst: Air.Inst.Index) !CValue {
5152 if (f.liveness.isUnused(inst)) return CValue.none;
5153
5272fn airTagName(f: *Function, inst: Air.Inst.Index) !void {
51545273 const un_op = f.air.instructions.items(.data)[inst].un_op;
5155 const inst_ty = f.air.typeOfIndex(inst);
51565274 const enum_ty = f.air.typeOf(un_op);
51575275 const operand = try f.resolveInst(un_op);
51585276
51595277 const writer = f.object.writer();
5160 const local = try f.allocLocal(inst_ty, .Const);
5161 try writer.print(" = {s}(", .{try f.object.dg.getTagNameFn(enum_ty)});
5278 try writer.print("{s}(", .{try f.object.dg.getTagNameFn(enum_ty)});
51625279 try f.writeCValue(writer, operand, .Other);
5163 try writer.writeAll(");\n");
5164
5165 return local;
5280 try writer.writeAll(")");
51665281}
51675282
5168fn airErrorName(f: *Function, inst: Air.Inst.Index) !CValue {
5169 if (f.liveness.isUnused(inst)) return CValue.none;
5170
5283fn airErrorName(f: *Function, inst: Air.Inst.Index) !void {
51715284 const un_op = f.air.instructions.items(.data)[inst].un_op;
51725285 const writer = f.object.writer();
5173 const inst_ty = f.air.typeOfIndex(inst);
51745286 const operand = try f.resolveInst(un_op);
5175 const local = try f.allocLocal(inst_ty, .Const);
51765287
5177 try writer.writeAll(" = zig_errorName[");
5288 try writer.writeAll("zig_errorName[");
51785289 try f.writeCValue(writer, operand, .Other);
5179 try writer.writeAll("];\n");
5180 return local;
5290 try writer.writeAll("]");
51815291}
51825292
51835293fn airSplat(f: *Function, inst: Air.Inst.Index) !CValue {
......@@ -5198,30 +5308,12 @@ fn airSplat(f: *Function, inst: Air.Inst.Index) !CValue {
51985308fn airSelect(f: *Function, inst: Air.Inst.Index) !CValue {
51995309 if (f.liveness.isUnused(inst)) return CValue.none;
52005310
5201 const inst_ty = f.air.typeOfIndex(inst);
5202 const ty_pl = f.air.instructions.items(.data)[inst].ty_pl;
5203
5204 const writer = f.object.writer();
5205 const local = try f.allocLocal(inst_ty, .Const);
5206 try writer.writeAll(" = ");
5207
5208 _ = local;
5209 _ = ty_pl;
52105311 return f.fail("TODO: C backend: implement airSelect", .{});
52115312}
52125313
52135314fn airShuffle(f: *Function, inst: Air.Inst.Index) !CValue {
52145315 if (f.liveness.isUnused(inst)) return CValue.none;
52155316
5216 const inst_ty = f.air.typeOfIndex(inst);
5217 const ty_op = f.air.instructions.items(.data)[inst].ty_op;
5218 const operand = try f.resolveInst(ty_op.operand);
5219 const writer = f.object.writer();
5220 const local = try f.allocLocal(inst_ty, .Const);
5221 try writer.writeAll(" = ");
5222
5223 _ = operand;
5224 _ = local;
52255317 return f.fail("TODO: C backend: implement airShuffle", .{});
52265318}
52275319
......@@ -5532,6 +5624,13 @@ fn airUnionInit(f: *Function, inst: Air.Inst.Index) !CValue {
55325624
55335625 const writer = f.object.writer();
55345626 const local = try f.allocLocal(union_ty, .Const);
5627 if (union_obj.layout == .Packed) {
5628 try writer.writeAll(" = ");
5629 try f.writeCValue(writer, payload, .Initializer);
5630 try writer.writeAll(";\n");
5631 return local;
5632 }
5633
55355634 try writer.writeAll(" = {");
55365635 if (union_ty.unionTagTypeSafety()) |tag_ty| {
55375636 const layout = union_ty.unionGetLayout(target);
......@@ -5645,15 +5744,18 @@ fn airUnFloatOp(f: *Function, inst: Air.Inst.Index, operation: []const u8) !CVal
56455744 return local;
56465745}
56475746
5648fn airBinFloatOp(f: *Function, inst: Air.Inst.Index, operation: []const u8) !CValue {
5649 if (f.liveness.isUnused(inst)) return CValue.none;
5747fn airBinFloatOp(
5748 f: *Function,
5749 inst: Air.Inst.Index,
5750 operation: []const u8,
5751) !void {
56505752 const bin_op = f.air.instructions.items(.data)[inst].bin_op;
56515753 const writer = f.object.writer();
56525754 const inst_ty = f.air.typeOfIndex(inst);
56535755 const lhs = try f.resolveInst(bin_op.lhs);
56545756 const rhs = try f.resolveInst(bin_op.rhs);
5655 const local = try f.allocLocal(inst_ty, .Const);
5656 try writer.writeAll(" = zig_libc_name_");
5757
5758 try writer.writeAll("zig_libc_name_");
56575759 try f.object.dg.renderTypeForBuiltinFnName(writer, inst_ty);
56585760 try writer.writeByte('(');
56595761 try writer.writeAll(operation);
......@@ -5661,8 +5763,7 @@ fn airBinFloatOp(f: *Function, inst: Air.Inst.Index, operation: []const u8) !CVa
56615763 try f.writeCValue(writer, lhs, .FunctionArgument);
56625764 try writer.writeAll(", ");
56635765 try f.writeCValue(writer, rhs, .FunctionArgument);
5664 try writer.writeAll(");\n");
5665 return local;
5766 try writer.writeAll(")");
56665767}
56675768
56685769fn airMulAdd(f: *Function, inst: Air.Inst.Index) !CValue {
src/value.zig+6
......@@ -2895,6 +2895,12 @@ pub const Value = extern union {
28952895 return val;
28962896 },
28972897
2898 .opt_payload_ptr => return val.castTag(.opt_payload_ptr).?.data.container_ptr.elemValueAdvanced(mod, index, arena, buffer),
2899 .eu_payload_ptr => return val.castTag(.eu_payload_ptr).?.data.container_ptr.elemValueAdvanced(mod, index, arena, buffer),
2900
2901 .opt_payload => return val.castTag(.opt_payload).?.data.elemValueAdvanced(mod, index, arena, buffer),
2902 .eu_payload => return val.castTag(.eu_payload).?.data.elemValueAdvanced(mod, index, arena, buffer),
2903
28982904 else => unreachable,
28992905 }
29002906 }
test/behavior.zig+1
......@@ -117,6 +117,7 @@ test {
117117 _ = @import("behavior/bugs/13285.zig");
118118 _ = @import("behavior/bugs/13435.zig");
119119 _ = @import("behavior/bugs/13664.zig");
120 _ = @import("behavior/bugs/13714.zig");
120121 _ = @import("behavior/byteswap.zig");
121122 _ = @import("behavior/byval_arg_var.zig");
122123 _ = @import("behavior/call.zig");
test/behavior/basic.zig+1-1
......@@ -739,7 +739,6 @@ test "thread local variable" {
739739}
740740
741741test "result location is optional inside error union" {
742 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
743742 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
744743 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
745744
......@@ -771,6 +770,7 @@ threadlocal var buffer: [11]u8 = undefined;
771770
772771test "auto created variables have correct alignment" {
773772 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
773 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
774774
775775 const S = struct {
776776 fn foo(str: [*]const u8) u32 {
test/behavior/bugs/13064.zig-1
......@@ -5,7 +5,6 @@ const expect = std.testing.expect;
55test {
66 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
77 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
8 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
98
109 var x: [10][10]u32 = undefined;
1110
test/behavior/bugs/13065.zig-1
......@@ -10,7 +10,6 @@ const U = union(enum) {
1010test {
1111 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1212 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
13 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
1413
1514 var x = U{ .array = undefined };
1615
test/behavior/bugs/13069.zig-1
......@@ -6,7 +6,6 @@ test {
66 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
77 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
88 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
9 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
109
1110 var opt_x: ?[3]f32 = [_]f32{0.0} ** 3;
1211
test/behavior/bugs/13714.zig created+4
......@@ -0,0 +1,4 @@
1comptime {
2 var image: [1]u8 = undefined;
3 _ = @shlExact(@as(u16, image[0]), 8);
4}
test/behavior/enum.zig-1
......@@ -1101,7 +1101,6 @@ test "enum literal in array literal" {
11011101}
11021102
11031103test "tag name functions are unique" {
1104 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
11051104 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
11061105 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
11071106 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
test/behavior/floatop.zig-2
......@@ -798,7 +798,6 @@ test "comptime fixed-width float non-zero divided by zero produces signed Inf" {
798798 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
799799 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
800800 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
801 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
802801
803802 inline for (.{ f16, f32, f64, f80, f128 }) |F| {
804803 const pos = @as(F, 1) / @as(F, 0);
......@@ -897,7 +896,6 @@ test "nan negation f80" {
897896 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
898897 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
899898 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
900 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
901899
902900 const nan_comptime = comptime math.nan(f80);
903901 const neg_nan_comptime = -nan_comptime;
test/behavior/if.zig-1
......@@ -133,7 +133,6 @@ test "if-else expression with runtime condition result location is inferred opti
133133 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
134134 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
135135 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
136 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
137136
138137 const A = struct { b: u64, c: u64 };
139138 var d: bool = true;
test/behavior/math.zig-3
......@@ -315,8 +315,6 @@ test "comptime_int multi-limb partial shift right" {
315315}
316316
317317test "xor" {
318 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
319
320318 try test_xor();
321319 comptime try test_xor();
322320}
......@@ -572,7 +570,6 @@ fn testShrTrunc(x: u16) !void {
572570}
573571
574572test "f128" {
575 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
576573 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
577574 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
578575 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
test/behavior/optional.zig-1
......@@ -342,7 +342,6 @@ test "optional pointer to zero bit optional payload" {
342342}
343343
344344test "optional pointer to zero bit error union payload" {
345 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
346345 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
347346 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
348347 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
test/behavior/switch.zig-1
......@@ -548,7 +548,6 @@ test "switch prongs with cases with identical payload types" {
548548}
549549
550550test "switch on pointer type" {
551 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
552551 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
553552 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
554553
test/behavior/type.zig+22
......@@ -535,3 +535,25 @@ test "Type.Fn" {
535535 try std.testing.expectEqual(T, fn_type);
536536 }
537537}
538
539test "reified struct field name from optional payload" {
540 comptime {
541 const m_name: ?[1]u8 = "a".*;
542 if (m_name) |*name| {
543 const T = @Type(.{ .Struct = .{
544 .layout = .Auto,
545 .fields = &.{.{
546 .name = name,
547 .field_type = u8,
548 .default_value = null,
549 .is_comptime = false,
550 .alignment = 1,
551 }},
552 .decls = &.{},
553 .is_tuple = false,
554 } });
555 var t: T = .{ .a = 123 };
556 try std.testing.expect(t.a == 123);
557 }
558 }
559}
test/behavior/union.zig-1
......@@ -1376,7 +1376,6 @@ test "union field ptr - zero sized field" {
13761376
13771377test "packed union in packed struct" {
13781378 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
1379 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
13801379 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
13811380 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
13821381 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO