| ... | @@ -18,7 +18,7 @@ const Air = @import("../Air.zig"); | ... | @@ -18,7 +18,7 @@ const Air = @import("../Air.zig"); |
| 18 | const Liveness = @import("../Liveness.zig"); | 18 | const Liveness = @import("../Liveness.zig"); |
| 19 | const CType = @import("../type.zig").CType; | 19 | const CType = @import("../type.zig").CType; |
| 20 | | 20 | |
| 21 | const Mutability = enum { Const, Mut }; | 21 | const Mutability = enum { Const, ConstArgument, Mut }; |
| 22 | const BigInt = std.math.big.int; | 22 | const BigInt = std.math.big.int; |
| 23 | | 23 | |
| 24 | pub const CValue = union(enum) { | 24 | pub const CValue = union(enum) { |
| ... | @@ -254,24 +254,20 @@ pub const Function = struct { | ... | @@ -254,24 +254,20 @@ pub const Function = struct { |
| 254 | | 254 | |
| 255 | const val = f.air.value(inst).?; | 255 | const val = f.air.value(inst).?; |
| 256 | const ty = f.air.typeOf(inst); | 256 | const ty = f.air.typeOf(inst); |
| 257 | switch (ty.zigTypeTag()) { | 257 | |
| 258 | .Array => { | 258 | const result = if (lowersToArray(ty, f.object.dg.module.getTarget())) result: { |
| 259 | const writer = f.object.code_header.writer(); | 259 | const writer = f.object.code_header.writer(); |
| 260 | const decl_c_value = f.allocLocalValue(); | 260 | const decl_c_value = f.allocLocalValue(); |
| 261 | gop.value_ptr.* = decl_c_value; | 261 | try writer.writeAll("static "); |
| 262 | try writer.writeAll("static "); | 262 | try f.object.dg.renderTypeAndName(writer, ty, decl_c_value, .Const, 0, .Complete); |
| 263 | try f.object.dg.renderTypeAndName(writer, ty, decl_c_value, .Const, 0, .Complete); | 263 | try writer.writeAll(" = "); |
| 264 | try writer.writeAll(" = "); | 264 | try f.object.dg.renderValue(writer, ty, val, .Initializer); |
| 265 | try f.object.dg.renderValue(writer, ty, val, .Initializer); | 265 | try writer.writeAll(";\n "); |
| 266 | try writer.writeAll(";\n "); | 266 | break :result decl_c_value; |
| 267 | return decl_c_value; | 267 | } else CValue{ .constant = inst }; |
| 268 | }, | 268 | |
| 269 | else => { | 269 | gop.value_ptr.* = result; |
| 270 | const result = CValue{ .constant = inst }; | 270 | return result; |
| 271 | gop.value_ptr.* = result; | | |
| 272 | return result; | | |
| 273 | }, | | |
| 274 | } | | |
| 275 | } | 271 | } |
| 276 | | 272 | |
| 277 | fn wantSafety(f: *Function) bool { | 273 | fn wantSafety(f: *Function) bool { |
| ... | @@ -374,7 +370,7 @@ pub const Function = struct { | ... | @@ -374,7 +370,7 @@ pub const Function = struct { |
| 374 | | 370 | |
| 375 | fn renderTypeForBuiltinFnName(f: *Function, writer: anytype, ty: Type) !void { | 371 | fn renderTypeForBuiltinFnName(f: *Function, writer: anytype, ty: Type) !void { |
| 376 | const target = f.object.dg.module.getTarget(); | 372 | const target = f.object.dg.module.getTarget(); |
| 377 | const c_bits = if (ty.isInt()) c_bits: { | 373 | const c_bits = if (ty.isAbiInt()) c_bits: { |
| 378 | const int_info = ty.intInfo(target); | 374 | const int_info = ty.intInfo(target); |
| 379 | try writer.writeByte(signAbbrev(int_info.signedness)); | 375 | try writer.writeByte(signAbbrev(int_info.signedness)); |
| 380 | break :c_bits toCIntBits(int_info.bits) orelse | 376 | break :c_bits toCIntBits(int_info.bits) orelse |
| ... | @@ -393,21 +389,21 @@ pub const Function = struct { | ... | @@ -393,21 +389,21 @@ pub const Function = struct { |
| 393 | switch (info) { | 389 | switch (info) { |
| 394 | .None => {}, | 390 | .None => {}, |
| 395 | .Range => { | 391 | .Range => { |
| 396 | var arena = std.heap.ArenaAllocator.init(f.object.dg.module.gpa); | 392 | var arena = std.heap.ArenaAllocator.init(f.object.dg.gpa); |
| 397 | defer arena.deinit(); | 393 | defer arena.deinit(); |
| 398 | | 394 | |
| 399 | const expected_contents = union { u: Value.Payload.U64, i: Value.Payload.I64 }; | 395 | const ExpectedContents = union { u: Value.Payload.U64, i: Value.Payload.I64 }; |
| 400 | var stack align(@alignOf(expected_contents)) = | 396 | var stack align(@alignOf(ExpectedContents)) = |
| 401 | std.heap.stackFallback(@sizeOf(expected_contents), arena.allocator()); | 397 | std.heap.stackFallback(@sizeOf(ExpectedContents), arena.allocator()); |
| 402 | | 398 | |
| 403 | const int_info = ty.intInfo(target); | 399 | const int_info = ty.intInfo(target); |
| 404 | if (int_info.signedness == .signed) { | 400 | if (int_info.signedness == .signed) { |
| 405 | const min_val = try ty.minInt(stack.get(), target); | 401 | const min_val = try ty.minInt(stack.get(), target); |
| 406 | try writer.print(", {x}", .{try f.fmtIntLiteral(ty, min_val)}); | 402 | try writer.print(", {x}", .{try f.object.dg.fmtIntLiteral(ty, min_val)}); |
| 407 | } | 403 | } |
| 408 | | 404 | |
| 409 | const max_val = try ty.maxInt(stack.get(), target); | 405 | const max_val = try ty.maxInt(stack.get(), target); |
| 410 | try writer.print(", {x}", .{try f.fmtIntLiteral(ty, max_val)}); | 406 | try writer.print(", {x}", .{try f.object.dg.fmtIntLiteral(ty, max_val)}); |
| 411 | }, | 407 | }, |
| 412 | .Bits => { | 408 | .Bits => { |
| 413 | var bits_pl = Value.Payload.U64{ | 409 | var bits_pl = Value.Payload.U64{ |
| ... | @@ -415,7 +411,7 @@ pub const Function = struct { | ... | @@ -415,7 +411,7 @@ pub const Function = struct { |
| 415 | .data = ty.bitSize(target), | 411 | .data = ty.bitSize(target), |
| 416 | }; | 412 | }; |
| 417 | const bits_val = Value.initPayload(&bits_pl.base); | 413 | const bits_val = Value.initPayload(&bits_pl.base); |
| 418 | try writer.print(", {}", .{try f.fmtIntLiteral(Type.u8, bits_val)}); | 414 | try writer.print(", {}", .{try f.object.dg.fmtIntLiteral(Type.u8, bits_val)}); |
| 419 | }, | 415 | }, |
| 420 | } | 416 | } |
| 421 | } | 417 | } |
| ... | @@ -471,7 +467,7 @@ pub const DeclGen = struct { | ... | @@ -471,7 +467,7 @@ pub const DeclGen = struct { |
| 471 | @setCold(true); | 467 | @setCold(true); |
| 472 | const src = LazySrcLoc.nodeOffset(0); | 468 | const src = LazySrcLoc.nodeOffset(0); |
| 473 | const src_loc = src.toSrcLoc(dg.decl); | 469 | const src_loc = src.toSrcLoc(dg.decl); |
| 474 | dg.error_msg = try Module.ErrorMsg.create(dg.module.gpa, src_loc, format, args); | 470 | dg.error_msg = try Module.ErrorMsg.create(dg.gpa, src_loc, format, args); |
| 475 | return error.AnalysisFail; | 471 | return error.AnalysisFail; |
| 476 | } | 472 | } |
| 477 | | 473 | |
| ... | @@ -559,14 +555,55 @@ pub const DeclGen = struct { | ... | @@ -559,14 +555,55 @@ pub const DeclGen = struct { |
| 559 | try dg.renderDeclValue(writer, ptr_ty, ptr_val, decl_index); | 555 | try dg.renderDeclValue(writer, ptr_ty, ptr_val, decl_index); |
| 560 | }, | 556 | }, |
| 561 | .field_ptr => { | 557 | .field_ptr => { |
| | 558 | const ptr_info = ptr_ty.ptrInfo(); |
| 562 | const field_ptr = ptr_val.castTag(.field_ptr).?.data; | 559 | const field_ptr = ptr_val.castTag(.field_ptr).?.data; |
| 563 | const container_ty = field_ptr.container_ty; | 560 | const container_ty = field_ptr.container_ty; |
| 564 | const index = field_ptr.field_index; | 561 | const index = field_ptr.field_index; |
| | 562 | |
| | 563 | var container_ptr_ty_pl: Type.Payload.ElemType = .{ |
| | 564 | .base = .{ .tag = .c_mut_pointer }, |
| | 565 | .data = field_ptr.container_ty, |
| | 566 | }; |
| | 567 | const container_ptr_ty = Type.initPayload(&container_ptr_ty_pl.base); |
| | 568 | |
| 565 | const FieldInfo = struct { name: []const u8, ty: Type }; | 569 | const FieldInfo = struct { name: []const u8, ty: Type }; |
| 566 | const field_info: FieldInfo = switch (container_ty.zigTypeTag()) { | 570 | const field_info: FieldInfo = switch (container_ty.zigTypeTag()) { |
| 567 | .Struct => FieldInfo{ | 571 | .Struct => switch (container_ty.containerLayout()) { |
| 568 | .name = container_ty.structFields().keys()[index], | 572 | .Auto, .Extern => FieldInfo{ |
| 569 | .ty = container_ty.structFields().values()[index].ty, | 573 | .name = container_ty.structFields().keys()[index], |
| | 574 | .ty = container_ty.structFields().values()[index].ty, |
| | 575 | }, |
| | 576 | .Packed => if (ptr_info.data.host_size == 0) { |
| | 577 | const target = dg.module.getTarget(); |
| | 578 | |
| | 579 | const byte_offset = container_ty.packedStructFieldByteOffset(index, target); |
| | 580 | var byte_offset_pl = Value.Payload.U64{ |
| | 581 | .base = .{ .tag = .int_u64 }, |
| | 582 | .data = byte_offset, |
| | 583 | }; |
| | 584 | const byte_offset_val = Value.initPayload(&byte_offset_pl.base); |
| | 585 | |
| | 586 | var ptr_u8_pl = ptr_info; |
| | 587 | ptr_u8_pl.data.pointee_type = Type.u8; |
| | 588 | const ptr_u8_ty = Type.initPayload(&ptr_u8_pl.base); |
| | 589 | |
| | 590 | try writer.writeAll("&(("); |
| | 591 | try dg.renderTypecast(writer, ptr_u8_ty); |
| | 592 | try writer.writeByte(')'); |
| | 593 | try dg.renderParentPtr(writer, field_ptr.container_ptr, container_ptr_ty); |
| | 594 | return writer.print(")[{}]", .{try dg.fmtIntLiteral(Type.usize, byte_offset_val)}); |
| | 595 | } else { |
| | 596 | var host_pl = Type.Payload.Bits{ |
| | 597 | .base = .{ .tag = .int_unsigned }, |
| | 598 | .data = ptr_info.data.host_size * 8, |
| | 599 | }; |
| | 600 | const host_ty = Type.initPayload(&host_pl.base); |
| | 601 | |
| | 602 | try writer.writeByte('('); |
| | 603 | try dg.renderTypecast(writer, ptr_ty); |
| | 604 | try writer.writeByte(')'); |
| | 605 | return dg.renderParentPtr(writer, field_ptr.container_ptr, host_ty); |
| | 606 | }, |
| 570 | }, | 607 | }, |
| 571 | .Union => FieldInfo{ | 608 | .Union => FieldInfo{ |
| 572 | .name = container_ty.unionFields().keys()[index], | 609 | .name = container_ty.unionFields().keys()[index], |
| ... | @@ -582,20 +619,16 @@ pub const DeclGen = struct { | ... | @@ -582,20 +619,16 @@ pub const DeclGen = struct { |
| 582 | }, | 619 | }, |
| 583 | else => unreachable, | 620 | else => unreachable, |
| 584 | }; | 621 | }; |
| 585 | var container_ptr_ty_pl: Type.Payload.ElemType = .{ | | |
| 586 | .base = .{ .tag = .c_mut_pointer }, | | |
| 587 | .data = field_ptr.container_ty, | | |
| 588 | }; | | |
| 589 | const container_ptr_ty = Type.initPayload(&container_ptr_ty_pl.base); | | |
| 590 | | 622 | |
| 591 | if (field_info.ty.hasRuntimeBitsIgnoreComptime()) { | 623 | if (field_info.ty.hasRuntimeBitsIgnoreComptime()) { |
| 592 | try writer.writeAll("&("); | 624 | try writer.writeAll("&("); |
| 593 | try dg.renderParentPtr(writer, field_ptr.container_ptr, container_ptr_ty); | 625 | try dg.renderParentPtr(writer, field_ptr.container_ptr, container_ptr_ty); |
| 594 | if (field_ptr.container_ty.tag() == .union_tagged or field_ptr.container_ty.tag() == .union_safety_tagged) { | 626 | try writer.writeAll(")->"); |
| 595 | try writer.print(")->payload.{ }", .{fmtIdent(field_info.name)}); | 627 | switch (field_ptr.container_ty.tag()) { |
| 596 | } else { | 628 | .union_tagged, .union_safety_tagged => try writer.writeAll("payload."), |
| 597 | try writer.print(")->{ }", .{fmtIdent(field_info.name)}); | 629 | else => {}, |
| 598 | } | 630 | } |
| | 631 | try writer.print("{ }", .{fmtIdent(field_info.name)}); |
| 599 | } else { | 632 | } else { |
| 600 | try dg.renderParentPtr(writer, field_ptr.container_ptr, field_info.ty); | 633 | try dg.renderParentPtr(writer, field_ptr.container_ptr, field_info.ty); |
| 601 | } | 634 | } |
| ... | @@ -694,25 +727,28 @@ pub const DeclGen = struct { | ... | @@ -694,25 +727,28 @@ pub const DeclGen = struct { |
| 694 | try dg.renderValue(writer, Type.bool, val, .Initializer); | 727 | try dg.renderValue(writer, Type.bool, val, .Initializer); |
| 695 | return writer.writeAll(" }"); | 728 | return writer.writeAll(" }"); |
| 696 | }, | 729 | }, |
| 697 | .Struct => { | 730 | .Struct => switch (ty.containerLayout()) { |
| 698 | if (location != .Initializer) { | 731 | .Auto, .Extern => { |
| 699 | try writer.writeByte('('); | 732 | if (location != .Initializer) { |
| 700 | try dg.renderTypecast(writer, ty); | 733 | try writer.writeByte('('); |
| 701 | try writer.writeByte(')'); | 734 | try dg.renderTypecast(writer, ty); |
| 702 | } | 735 | try writer.writeByte(')'); |
| | 736 | } |
| 703 | | 737 | |
| 704 | try writer.writeByte('{'); | 738 | try writer.writeByte('{'); |
| 705 | var empty = true; | 739 | var empty = true; |
| 706 | for (ty.structFields().values()) |field| { | 740 | for (ty.structFields().values()) |field| { |
| 707 | if (!field.ty.hasRuntimeBits()) continue; | 741 | if (!field.ty.hasRuntimeBits()) continue; |
| 708 | | 742 | |
| 709 | if (!empty) try writer.writeByte(','); | 743 | if (!empty) try writer.writeByte(','); |
| 710 | try dg.renderValue(writer, field.ty, val, .Initializer); | 744 | try dg.renderValue(writer, field.ty, val, .Initializer); |
| 711 | | 745 | |
| 712 | empty = false; | 746 | empty = false; |
| 713 | } | 747 | } |
| 714 | if (empty) try writer.print("{x}", .{try dg.fmtIntLiteral(Type.u8, Value.undef)}); | 748 | if (empty) try writer.print("{x}", .{try dg.fmtIntLiteral(Type.u8, Value.undef)}); |
| 715 | return writer.writeByte('}'); | 749 | return writer.writeByte('}'); |
| | 750 | }, |
| | 751 | .Packed => return writer.print("{x}", .{try dg.fmtIntLiteral(ty, Value.undef)}), |
| 716 | }, | 752 | }, |
| 717 | .Union => { | 753 | .Union => { |
| 718 | if (location != .Initializer) { | 754 | if (location != .Initializer) { |
| ... | @@ -898,7 +934,7 @@ pub const DeclGen = struct { | ... | @@ -898,7 +934,7 @@ pub const DeclGen = struct { |
| 898 | }, | 934 | }, |
| 899 | else => { | 935 | else => { |
| 900 | // Fall back to generic implementation. | 936 | // Fall back to generic implementation. |
| 901 | var arena = std.heap.ArenaAllocator.init(dg.module.gpa); | 937 | var arena = std.heap.ArenaAllocator.init(dg.gpa); |
| 902 | defer arena.deinit(); | 938 | defer arena.deinit(); |
| 903 | const arena_allocator = arena.allocator(); | 939 | const arena_allocator = arena.allocator(); |
| 904 | | 940 | |
| ... | @@ -1024,28 +1060,63 @@ pub const DeclGen = struct { | ... | @@ -1024,28 +1060,63 @@ pub const DeclGen = struct { |
| 1024 | }, | 1060 | }, |
| 1025 | else => unreachable, | 1061 | else => unreachable, |
| 1026 | }, | 1062 | }, |
| 1027 | .Struct => { | 1063 | .Struct => switch (ty.containerLayout()) { |
| 1028 | const field_vals = val.castTag(.aggregate).?.data; | 1064 | .Auto, .Extern => { |
| | 1065 | const field_vals = val.castTag(.aggregate).?.data; |
| 1029 | | 1066 | |
| 1030 | if (location != .Initializer) { | 1067 | if (location != .Initializer) { |
| 1031 | try writer.writeByte('('); | 1068 | try writer.writeByte('('); |
| 1032 | try dg.renderTypecast(writer, ty); | 1069 | try dg.renderTypecast(writer, ty); |
| 1033 | try writer.writeByte(')'); | 1070 | try writer.writeByte(')'); |
| 1034 | } | 1071 | } |
| 1035 | | 1072 | |
| 1036 | try writer.writeByte('{'); | 1073 | try writer.writeByte('{'); |
| 1037 | var empty = true; | 1074 | var empty = true; |
| 1038 | for (field_vals) |field_val, field_index| { | 1075 | for (field_vals) |field_val, field_index| { |
| 1039 | const field_ty = ty.structFieldType(field_index); | 1076 | const field_ty = ty.structFieldType(field_index); |
| 1040 | if (!field_ty.hasRuntimeBits()) continue; | 1077 | if (!field_ty.hasRuntimeBits()) continue; |
| 1041 | | 1078 | |
| 1042 | if (!empty) try writer.writeByte(','); | 1079 | if (!empty) try writer.writeByte(','); |
| 1043 | try dg.renderValue(writer, field_ty, field_val, .Initializer); | 1080 | try dg.renderValue(writer, field_ty, field_val, .Initializer); |
| 1044 | | 1081 | |
| 1045 | empty = false; | 1082 | empty = false; |
| 1046 | } | 1083 | } |
| 1047 | if (empty) try writer.print("{}", .{try dg.fmtIntLiteral(Type.u8, Value.zero)}); | 1084 | if (empty) try writer.print("{}", .{try dg.fmtIntLiteral(Type.u8, Value.zero)}); |
| 1048 | try writer.writeByte('}'); | 1085 | try writer.writeByte('}'); |
| | 1086 | }, |
| | 1087 | .Packed => { |
| | 1088 | const field_vals = val.castTag(.aggregate).?.data; |
| | 1089 | const int_info = ty.intInfo(target); |
| | 1090 | |
| | 1091 | var bit_offset_ty_pl = Type.Payload.Bits{ |
| | 1092 | .base = .{ .tag = .int_unsigned }, |
| | 1093 | .data = Type.smallestUnsignedBits(int_info.bits - 1), |
| | 1094 | }; |
| | 1095 | const bit_offset_ty = Type.initPayload(&bit_offset_ty_pl.base); |
| | 1096 | |
| | 1097 | var bit_offset_val_pl: Value.Payload.U64 = .{ .base = .{ .tag = .int_u64 }, .data = 0 }; |
| | 1098 | const bit_offset_val = Value.initPayload(&bit_offset_val_pl.base); |
| | 1099 | |
| | 1100 | try writer.writeByte('('); |
| | 1101 | var empty = true; |
| | 1102 | for (field_vals) |field_val, index| { |
| | 1103 | const field_ty = ty.structFieldType(index); |
| | 1104 | if (!field_ty.hasRuntimeBitsIgnoreComptime()) continue; |
| | 1105 | |
| | 1106 | if (!empty) try writer.writeAll(" | "); |
| | 1107 | try writer.writeByte('('); |
| | 1108 | try dg.renderTypecast(writer, ty); |
| | 1109 | try writer.writeByte(')'); |
| | 1110 | try dg.renderValue(writer, field_ty, field_val, .Other); |
| | 1111 | try writer.writeAll(" << "); |
| | 1112 | try dg.renderValue(writer, bit_offset_ty, bit_offset_val, .FunctionArgument); |
| | 1113 | |
| | 1114 | bit_offset_val_pl.data += field_ty.bitSize(target); |
| | 1115 | empty = false; |
| | 1116 | } |
| | 1117 | if (empty) try dg.renderValue(writer, ty, Value.undef, .Initializer); |
| | 1118 | try writer.writeByte(')'); |
| | 1119 | }, |
| 1049 | }, | 1120 | }, |
| 1050 | .Union => { | 1121 | .Union => { |
| 1051 | const union_obj = val.castTag(.@"union").?.data; | 1122 | const union_obj = val.castTag(.@"union").?.data; |
| ... | @@ -1103,11 +1174,12 @@ pub const DeclGen = struct { | ... | @@ -1103,11 +1174,12 @@ pub const DeclGen = struct { |
| 1103 | if (fn_info.cc == .Naked) try w.writeAll("zig_naked "); | 1174 | if (fn_info.cc == .Naked) try w.writeAll("zig_naked "); |
| 1104 | if (dg.decl.val.castTag(.function)) |func_payload| | 1175 | if (dg.decl.val.castTag(.function)) |func_payload| |
| 1105 | if (func_payload.data.is_cold) try w.writeAll("zig_cold "); | 1176 | if (func_payload.data.is_cold) try w.writeAll("zig_cold "); |
| 1106 | const ret_ty = fn_info.return_type; | 1177 | |
| 1107 | try dg.renderType(w, if (ret_ty.tag() == .noreturn or ret_ty.hasRuntimeBitsIgnoreComptime()) | 1178 | const target = dg.module.getTarget(); |
| 1108 | ret_ty | 1179 | var ret_buf: LowerFnRetTyBuffer = undefined; |
| 1109 | else | 1180 | const ret_ty = lowerFnRetTy(fn_info.return_type, &ret_buf, target); |
| 1110 | Type.void, kind); | 1181 | |
| | 1182 | try dg.renderType(w, ret_ty, kind); |
| 1111 | try w.writeByte(' '); | 1183 | try w.writeByte(' '); |
| 1112 | try dg.renderDeclName(w, dg.decl_index); | 1184 | try dg.renderDeclName(w, dg.decl_index); |
| 1113 | try w.writeByte('('); | 1185 | try w.writeByte('('); |
| ... | @@ -1117,7 +1189,7 @@ pub const DeclGen = struct { | ... | @@ -1117,7 +1189,7 @@ pub const DeclGen = struct { |
| 1117 | if (!param_type.hasRuntimeBitsIgnoreComptime()) continue; | 1189 | if (!param_type.hasRuntimeBitsIgnoreComptime()) continue; |
| 1118 | if (index > 0) try w.writeAll(", "); | 1190 | if (index > 0) try w.writeAll(", "); |
| 1119 | const name = CValue{ .arg = index }; | 1191 | const name = CValue{ .arg = index }; |
| 1120 | try dg.renderTypeAndName(w, param_type, name, .Const, 0, kind); | 1192 | try dg.renderTypeAndName(w, param_type, name, .ConstArgument, 0, kind); |
| 1121 | index += 1; | 1193 | index += 1; |
| 1122 | } | 1194 | } |
| 1123 | | 1195 | |
| ... | @@ -1137,10 +1209,13 @@ pub const DeclGen = struct { | ... | @@ -1137,10 +1209,13 @@ pub const DeclGen = struct { |
| 1137 | | 1209 | |
| 1138 | const fn_info = t.fnInfo(); | 1210 | const fn_info = t.fnInfo(); |
| 1139 | | 1211 | |
| | 1212 | const target = dg.module.getTarget(); |
| | 1213 | var ret_buf: LowerFnRetTyBuffer = undefined; |
| | 1214 | const ret_ty = lowerFnRetTy(fn_info.return_type, &ret_buf, target); |
| | 1215 | |
| 1140 | try bw.writeAll("typedef "); | 1216 | try bw.writeAll("typedef "); |
| 1141 | try dg.renderType(bw, fn_info.return_type, .Forward); | 1217 | try dg.renderType(bw, ret_ty, .Forward); |
| 1142 | try bw.writeAll(" (*"); | 1218 | try bw.writeAll(" (*"); |
| 1143 | | | |
| 1144 | const name_begin = buffer.items.len; | 1219 | const name_begin = buffer.items.len; |
| 1145 | try bw.print("zig_F_{}", .{typeToCIdentifier(t, dg.module)}); | 1220 | try bw.print("zig_F_{}", .{typeToCIdentifier(t, dg.module)}); |
| 1146 | const name_end = buffer.items.len; | 1221 | const name_end = buffer.items.len; |
| ... | @@ -1315,8 +1390,12 @@ pub const DeclGen = struct { | ... | @@ -1315,8 +1390,12 @@ pub const DeclGen = struct { |
| 1315 | const val = fields.values[i]; | 1390 | const val = fields.values[i]; |
| 1316 | if (val.tag() != .unreachable_value) continue; | 1391 | if (val.tag() != .unreachable_value) continue; |
| 1317 | | 1392 | |
| 1318 | const field_name = try std.fmt.allocPrint(dg.typedefs.allocator, "field_{d}", .{i}); | 1393 | var field_name_buf: []const u8 = &.{}; |
| 1319 | defer dg.typedefs.allocator.free(field_name); | 1394 | defer dg.typedefs.allocator.free(field_name_buf); |
| | 1395 | const field_name = if (t.isTuple()) field_name: { |
| | 1396 | field_name_buf = try std.fmt.allocPrint(dg.typedefs.allocator, "field_{d}", .{i}); |
| | 1397 | break :field_name field_name_buf; |
| | 1398 | } else t.structFieldName(i); |
| 1320 | | 1399 | |
| 1321 | try buffer.append(' '); | 1400 | try buffer.append(' '); |
| 1322 | try dg.renderTypeAndName(buffer.writer(), field_ty, .{ .identifier = field_name }, .Mut, 0, .Complete); | 1401 | try dg.renderTypeAndName(buffer.writer(), field_ty, .{ .identifier = field_name }, .Mut, 0, .Complete); |
| ... | @@ -1463,7 +1542,10 @@ pub const DeclGen = struct { | ... | @@ -1463,7 +1542,10 @@ pub const DeclGen = struct { |
| 1463 | try bw.print(" zig_A_{}_{d}", .{ typeToCIdentifier(info.elem_type, dg.module), info.len }); | 1542 | try bw.print(" zig_A_{}_{d}", .{ typeToCIdentifier(info.elem_type, dg.module), info.len }); |
| 1464 | const name_end = buffer.items.len; | 1543 | const name_end = buffer.items.len; |
| 1465 | | 1544 | |
| 1466 | try bw.print("[{d}];\n", .{if (info.len > 0) info.len else 1}); | 1545 | const c_len = if (info.len > 0) info.len else 1; |
| | 1546 | var c_len_pl: Value.Payload.U64 = .{ .base = .{ .tag = .int_u64 }, .data = c_len }; |
| | 1547 | const c_len_val = Value.initPayload(&c_len_pl.base); |
| | 1548 | try bw.print("[{}];\n", .{try dg.fmtIntLiteral(Type.usize, c_len_val)}); |
| 1467 | | 1549 | |
| 1468 | const rendered = buffer.toOwnedSlice(); | 1550 | const rendered = buffer.toOwnedSlice(); |
| 1469 | errdefer dg.typedefs.allocator.free(rendered); | 1551 | errdefer dg.typedefs.allocator.free(rendered); |
| ... | @@ -1487,7 +1569,7 @@ pub const DeclGen = struct { | ... | @@ -1487,7 +1569,7 @@ pub const DeclGen = struct { |
| 1487 | try dg.renderTypeAndName(bw, child_type, .{ .identifier = "payload" }, .Mut, 0, .Complete); | 1569 | try dg.renderTypeAndName(bw, child_type, .{ .identifier = "payload" }, .Mut, 0, .Complete); |
| 1488 | try bw.writeAll(";\n "); | 1570 | try bw.writeAll(";\n "); |
| 1489 | try dg.renderTypeAndName(bw, Type.bool, .{ .identifier = "is_null" }, .Mut, 0, .Complete); | 1571 | try dg.renderTypeAndName(bw, Type.bool, .{ .identifier = "is_null" }, .Mut, 0, .Complete); |
| 1490 | try bw.writeAll("; } "); | 1572 | try bw.writeAll(";\n} "); |
| 1491 | const name_begin = buffer.items.len; | 1573 | const name_begin = buffer.items.len; |
| 1492 | try bw.print("zig_Q_{}", .{typeToCIdentifier(child_type, dg.module)}); | 1574 | try bw.print("zig_Q_{}", .{typeToCIdentifier(child_type, dg.module)}); |
| 1493 | const name_end = buffer.items.len; | 1575 | const name_end = buffer.items.len; |
| ... | @@ -1566,18 +1648,29 @@ pub const DeclGen = struct { | ... | @@ -1566,18 +1648,29 @@ pub const DeclGen = struct { |
| 1566 | try w.writeAll("zig_"); | 1648 | try w.writeAll("zig_"); |
| 1567 | try t.print(w, dg.module); | 1649 | try t.print(w, dg.module); |
| 1568 | } else { | 1650 | } else { |
| 1569 | const info = t.intInfo(target); | 1651 | const int_info = t.intInfo(target); |
| 1570 | const c_bits = toCIntBits(info.bits) orelse | 1652 | if (toCIntBits(int_info.bits)) |c_bits| |
| 1571 | return dg.fail("TODO: C backend: implement integer types larger than 128 bits", .{}); | 1653 | return w.print("zig_{c}{d}", .{ signAbbrev(int_info.signedness), c_bits }) |
| 1572 | try w.print("zig_{c}{d}", .{ signAbbrev(info.signedness), c_bits }); | 1654 | else if (loweredArrayInfo(t, target)) |array_info| { |
| | 1655 | assert(array_info.sentinel == null); |
| | 1656 | var array_pl = Type.Payload.Array{ |
| | 1657 | .base = .{ .tag = .array }, |
| | 1658 | .data = .{ .len = array_info.len, .elem_type = array_info.elem_type }, |
| | 1659 | }; |
| | 1660 | const array_ty = Type.initPayload(&array_pl.base); |
| | 1661 | |
| | 1662 | return dg.renderType(w, array_ty, kind); |
| | 1663 | } else return dg.fail("C backend: Unable to lower unnamed integer type {}", .{ |
| | 1664 | t.fmt(dg.module), |
| | 1665 | }); |
| 1573 | } | 1666 | } |
| 1574 | }, | 1667 | }, |
| 1575 | .Pointer => { | 1668 | .Pointer => { |
| 1576 | const child_ty = t.childType(); | 1669 | const ptr_info = t.ptrInfo().data; |
| 1577 | if (t.isSlice()) { | 1670 | if (ptr_info.size == .Slice) { |
| 1578 | var slice_pl = Type.Payload.ElemType{ | 1671 | var slice_pl = Type.Payload.ElemType{ |
| 1579 | .base = .{ .tag = if (t.ptrIsMutable()) .mut_slice else .const_slice }, | 1672 | .base = .{ .tag = if (t.ptrIsMutable()) .mut_slice else .const_slice }, |
| 1580 | .data = child_ty, | 1673 | .data = ptr_info.pointee_type, |
| 1581 | }; | 1674 | }; |
| 1582 | const slice_ty = Type.initPayload(&slice_pl.base); | 1675 | const slice_ty = Type.initPayload(&slice_pl.base); |
| 1583 | | 1676 | |
| ... | @@ -1587,14 +1680,22 @@ pub const DeclGen = struct { | ... | @@ -1587,14 +1680,22 @@ pub const DeclGen = struct { |
| 1587 | return w.writeAll(name); | 1680 | return w.writeAll(name); |
| 1588 | } | 1681 | } |
| 1589 | | 1682 | |
| 1590 | if (child_ty.zigTypeTag() == .Fn) { | 1683 | if (ptr_info.pointee_type.zigTypeTag() == .Fn) { |
| 1591 | const name = dg.getTypedefName(child_ty) orelse | 1684 | const name = dg.getTypedefName(ptr_info.pointee_type) orelse |
| 1592 | try dg.renderPtrToFnTypedef(child_ty); | 1685 | try dg.renderPtrToFnTypedef(ptr_info.pointee_type); |
| 1593 | | 1686 | |
| 1594 | return w.writeAll(name); | 1687 | return w.writeAll(name); |
| 1595 | } | 1688 | } |
| 1596 | | 1689 | |
| 1597 | if (t.isCPtr() and child_ty.eql(Type.u8, dg.module) and | 1690 | if (ptr_info.host_size != 0) { |
| | 1691 | var host_pl = Type.Payload.Bits{ |
| | 1692 | .base = .{ .tag = .int_unsigned }, |
| | 1693 | .data = ptr_info.host_size * 8, |
| | 1694 | }; |
| | 1695 | const host_ty = Type.initPayload(&host_pl.base); |
| | 1696 | |
| | 1697 | try dg.renderType(w, host_ty, .Forward); |
| | 1698 | } else if (t.isCPtr() and ptr_info.pointee_type.eql(Type.u8, dg.module) and |
| 1598 | (dg.decl.val.tag() == .extern_fn or | 1699 | (dg.decl.val.tag() == .extern_fn or |
| 1599 | std.mem.eql(u8, std.mem.span(dg.decl.name), "main"))) | 1700 | std.mem.eql(u8, std.mem.span(dg.decl.name), "main"))) |
| 1600 | { | 1701 | { |
| ... | @@ -1603,9 +1704,9 @@ pub const DeclGen = struct { | ... | @@ -1603,9 +1704,9 @@ pub const DeclGen = struct { |
| 1603 | // u8 and i8 produce unsigned char and signed char respectively, | 1704 | // u8 and i8 produce unsigned char and signed char respectively, |
| 1604 | // which in C are (not very usefully) different than char. | 1705 | // which in C are (not very usefully) different than char. |
| 1605 | try w.writeAll("char"); | 1706 | try w.writeAll("char"); |
| 1606 | } else try dg.renderType(w, switch (child_ty.tag()) { | 1707 | } else try dg.renderType(w, switch (ptr_info.pointee_type.tag()) { |
| 1607 | .anyopaque => Type.void, | 1708 | .anyopaque => Type.void, |
| 1608 | else => child_ty, | 1709 | else => ptr_info.pointee_type, |
| 1609 | }, .Forward); | 1710 | }, .Forward); |
| 1610 | if (t.isConstPtr()) try w.writeAll(" const"); | 1711 | if (t.isConstPtr()) try w.writeAll(" const"); |
| 1611 | if (t.isVolatilePtr()) try w.writeAll(" volatile"); | 1712 | if (t.isVolatilePtr()) try w.writeAll(" volatile"); |
| ... | @@ -1654,7 +1755,9 @@ pub const DeclGen = struct { | ... | @@ -1654,7 +1755,9 @@ pub const DeclGen = struct { |
| 1654 | | 1755 | |
| 1655 | return w.writeAll(name); | 1756 | return w.writeAll(name); |
| 1656 | }, | 1757 | }, |
| 1657 | .Struct, .Union => |tag| if (kind == .Complete or t.isTupleOrAnonStruct()) { | 1758 | .Struct, .Union => |tag| if (tag == .Struct and t.containerLayout() == .Packed) |
| | 1759 | try dg.renderType(w, t.castTag(.@"struct").?.data.backing_int_ty, kind) |
| | 1760 | else if (kind == .Complete or t.isTupleOrAnonStruct()) { |
| 1658 | const name = dg.getTypedefName(t) orelse switch (tag) { | 1761 | const name = dg.getTypedefName(t) orelse switch (tag) { |
| 1659 | .Struct => if (t.isTupleOrAnonStruct()) | 1762 | .Struct => if (t.isTupleOrAnonStruct()) |
| 1660 | try dg.renderTupleTypedef(t) | 1763 | try dg.renderTupleTypedef(t) |
| ... | @@ -1664,7 +1767,7 @@ pub const DeclGen = struct { | ... | @@ -1664,7 +1767,7 @@ pub const DeclGen = struct { |
| 1664 | else => unreachable, | 1767 | else => unreachable, |
| 1665 | }; | 1768 | }; |
| 1666 | | 1769 | |
| 1667 | return w.writeAll(name); | 1770 | try w.writeAll(name); |
| 1668 | } else { | 1771 | } else { |
| 1669 | var ptr_pl = Type.Payload.ElemType{ | 1772 | var ptr_pl = Type.Payload.ElemType{ |
| 1670 | .base = .{ .tag = .single_const_pointer }, | 1773 | .base = .{ .tag = .single_const_pointer }, |
| ... | @@ -1675,7 +1778,7 @@ pub const DeclGen = struct { | ... | @@ -1675,7 +1778,7 @@ pub const DeclGen = struct { |
| 1675 | const name = dg.getTypedefName(ptr_ty) orelse | 1778 | const name = dg.getTypedefName(ptr_ty) orelse |
| 1676 | try dg.renderFwdTypedef(ptr_ty); | 1779 | try dg.renderFwdTypedef(ptr_ty); |
| 1677 | | 1780 | |
| 1678 | return w.writeAll(name); | 1781 | try w.writeAll(name); |
| 1679 | }, | 1782 | }, |
| 1680 | .Enum => { | 1783 | .Enum => { |
| 1681 | // For enums, we simply use the integer tag type. | 1784 | // For enums, we simply use the integer tag type. |
| ... | @@ -1751,24 +1854,32 @@ pub const DeclGen = struct { | ... | @@ -1751,24 +1854,32 @@ pub const DeclGen = struct { |
| 1751 | ) error{ OutOfMemory, AnalysisFail }!void { | 1854 | ) error{ OutOfMemory, AnalysisFail }!void { |
| 1752 | var suffix = std.ArrayList(u8).init(dg.gpa); | 1855 | var suffix = std.ArrayList(u8).init(dg.gpa); |
| 1753 | defer suffix.deinit(); | 1856 | defer suffix.deinit(); |
| | 1857 | const suffix_writer = suffix.writer(); |
| 1754 | | 1858 | |
| 1755 | // Any top-level array types are rendered here as a suffix, which | 1859 | // Any top-level array types are rendered here as a suffix, which |
| 1756 | // avoids creating typedefs for every array type | 1860 | // avoids creating typedefs for every array type |
| | 1861 | const target = dg.module.getTarget(); |
| 1757 | var render_ty = ty; | 1862 | var render_ty = ty; |
| 1758 | while (render_ty.zigTypeTag() == .Array) { | 1863 | var depth: u32 = 0; |
| 1759 | const sentinel_bit = @boolToInt(render_ty.sentinel() != null); | 1864 | while (loweredArrayInfo(render_ty, target)) |array_info| { |
| 1760 | const c_len = render_ty.arrayLen() + sentinel_bit; | 1865 | const c_len = array_info.len + @boolToInt(array_info.sentinel != null); |
| 1761 | try suffix.writer().print("[{d}]", .{c_len}); | 1866 | var c_len_pl: Value.Payload.U64 = .{ .base = .{ .tag = .int_u64 }, .data = c_len }; |
| 1762 | render_ty = render_ty.elemType(); | 1867 | const c_len_val = Value.initPayload(&c_len_pl.base); |
| | 1868 | |
| | 1869 | try suffix_writer.writeByte('['); |
| | 1870 | if (mutability == .ConstArgument and depth == 0) try suffix_writer.writeAll("static const "); |
| | 1871 | try suffix.writer().print("{}]", .{try dg.fmtIntLiteral(Type.usize, c_len_val)}); |
| | 1872 | render_ty = array_info.elem_type; |
| | 1873 | depth += 1; |
| 1763 | } | 1874 | } |
| 1764 | | 1875 | |
| 1765 | if (alignment != 0 and alignment > ty.abiAlignment(dg.module.getTarget())) { | 1876 | if (alignment != 0 and alignment > ty.abiAlignment(target)) { |
| 1766 | try w.print("zig_align({}) ", .{alignment}); | 1877 | try w.print("zig_align({}) ", .{alignment}); |
| 1767 | } | 1878 | } |
| 1768 | try dg.renderType(w, render_ty, kind); | 1879 | try dg.renderType(w, render_ty, kind); |
| 1769 | | 1880 | |
| 1770 | const const_prefix = switch (mutability) { | 1881 | const const_prefix = switch (mutability) { |
| 1771 | .Const => "const ", | 1882 | .Const, .ConstArgument => "const ", |
| 1772 | .Mut => "", | 1883 | .Mut => "", |
| 1773 | }; | 1884 | }; |
| 1774 | try w.print(" {s}", .{const_prefix}); | 1885 | try w.print(" {s}", .{const_prefix}); |
| ... | @@ -1935,7 +2046,7 @@ pub const DeclGen = struct { | ... | @@ -1935,7 +2046,7 @@ pub const DeclGen = struct { |
| 1935 | } else if (decl.isExtern()) { | 2046 | } else if (decl.isExtern()) { |
| 1936 | return writer.writeAll(mem.sliceTo(decl.name, 0)); | 2047 | return writer.writeAll(mem.sliceTo(decl.name, 0)); |
| 1937 | } else { | 2048 | } else { |
| 1938 | const gpa = dg.module.gpa; | 2049 | const gpa = dg.gpa; |
| 1939 | const name = try decl.getFullyQualifiedName(dg.module); | 2050 | const name = try decl.getFullyQualifiedName(dg.module); |
| 1940 | defer gpa.free(name); | 2051 | defer gpa.free(name); |
| 1941 | return writer.print("{ }", .{fmtIdent(name)}); | 2052 | return writer.print("{ }", .{fmtIdent(name)}); |
| ... | @@ -2298,8 +2409,8 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO | ... | @@ -2298,8 +2409,8 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO |
| 2298 | .trunc => try airTrunc(f, inst), | 2409 | .trunc => try airTrunc(f, inst), |
| 2299 | .bool_to_int => try airBoolToInt(f, inst), | 2410 | .bool_to_int => try airBoolToInt(f, inst), |
| 2300 | .load => try airLoad(f, inst), | 2411 | .load => try airLoad(f, inst), |
| 2301 | .ret => try airRet(f, inst), | 2412 | .ret => try airRet(f, inst, false), |
| 2302 | .ret_load => try airRetLoad(f, inst), | 2413 | .ret_load => try airRet(f, inst, true), |
| 2303 | .store => try airStore(f, inst), | 2414 | .store => try airStore(f, inst), |
| 2304 | .loop => try airLoop(f, inst), | 2415 | .loop => try airLoop(f, inst), |
| 2305 | .cond_br => try airCondBr(f, inst), | 2416 | .cond_br => try airCondBr(f, inst), |
| ... | @@ -2588,14 +2699,15 @@ fn airArg(f: *Function) CValue { | ... | @@ -2588,14 +2699,15 @@ fn airArg(f: *Function) CValue { |
| 2588 | | 2699 | |
| 2589 | fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue { | 2700 | fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue { |
| 2590 | const ty_op = f.air.instructions.items(.data)[inst].ty_op; | 2701 | const ty_op = f.air.instructions.items(.data)[inst].ty_op; |
| 2591 | const is_volatile = f.air.typeOf(ty_op.operand).isVolatilePtr(); | 2702 | const ptr_info = f.air.typeOf(ty_op.operand).ptrInfo().data; |
| 2592 | | 2703 | |
| 2593 | const inst_ty = f.air.typeOfIndex(inst); | 2704 | const inst_ty = f.air.typeOfIndex(inst); |
| 2594 | if (!inst_ty.hasRuntimeBitsIgnoreComptime() or | 2705 | if (!inst_ty.hasRuntimeBitsIgnoreComptime() or |
| 2595 | !is_volatile and f.liveness.isUnused(inst)) | 2706 | !ptr_info.@"volatile" and f.liveness.isUnused(inst)) |
| 2596 | return CValue.none; | 2707 | return CValue.none; |
| 2597 | | 2708 | |
| 2598 | const is_array = inst_ty.zigTypeTag() == .Array; | 2709 | const target = f.object.dg.module.getTarget(); |
| | 2710 | const is_array = lowersToArray(inst_ty, target); |
| 2599 | const operand = try f.resolveInst(ty_op.operand); | 2711 | const operand = try f.resolveInst(ty_op.operand); |
| 2600 | const writer = f.object.writer(); | 2712 | const writer = f.object.writer(); |
| 2601 | | 2713 | |
| ... | @@ -2612,26 +2724,88 @@ fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -2612,26 +2724,88 @@ fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue { |
| 2612 | try f.writeCValue(writer, operand, .FunctionArgument); | 2724 | try f.writeCValue(writer, operand, .FunctionArgument); |
| 2613 | try writer.writeAll(", sizeof("); | 2725 | try writer.writeAll(", sizeof("); |
| 2614 | try f.renderTypecast(writer, inst_ty); | 2726 | try f.renderTypecast(writer, inst_ty); |
| 2615 | try writer.writeAll("));\n"); | 2727 | try writer.writeAll("))"); |
| | 2728 | } else if (ptr_info.host_size != 0) { |
| | 2729 | var host_pl = Type.Payload.Bits{ |
| | 2730 | .base = .{ .tag = .int_unsigned }, |
| | 2731 | .data = ptr_info.host_size * 8, |
| | 2732 | }; |
| | 2733 | const host_ty = Type.initPayload(&host_pl.base); |
| | 2734 | |
| | 2735 | var bit_offset_ty_pl = Type.Payload.Bits{ |
| | 2736 | .base = .{ .tag = .int_unsigned }, |
| | 2737 | .data = Type.smallestUnsignedBits(host_pl.data - 1), |
| | 2738 | }; |
| | 2739 | const bit_offset_ty = Type.initPayload(&bit_offset_ty_pl.base); |
| | 2740 | |
| | 2741 | var bit_offset_val_pl: Value.Payload.U64 = .{ |
| | 2742 | .base = .{ .tag = .int_u64 }, |
| | 2743 | .data = ptr_info.bit_offset, |
| | 2744 | }; |
| | 2745 | const bit_offset_val = Value.initPayload(&bit_offset_val_pl.base); |
| | 2746 | |
| | 2747 | var field_pl = Type.Payload.Bits{ |
| | 2748 | .base = .{ .tag = .int_unsigned }, |
| | 2749 | .data = @intCast(u16, inst_ty.bitSize(target)), |
| | 2750 | }; |
| | 2751 | const field_ty = Type.initPayload(&field_pl.base); |
| | 2752 | |
| | 2753 | try writer.writeAll(" = ("); |
| | 2754 | try f.renderTypecast(writer, inst_ty); |
| | 2755 | try writer.writeAll(")zig_wrap_"); |
| | 2756 | try f.renderTypeForBuiltinFnName(writer, field_ty); |
| | 2757 | try writer.writeAll("(("); |
| | 2758 | try f.renderTypecast(writer, field_ty); |
| | 2759 | try writer.writeAll(")zig_shr_"); |
| | 2760 | try f.renderTypeForBuiltinFnName(writer, host_ty); |
| | 2761 | try writer.writeByte('('); |
| | 2762 | try f.writeCValueDeref(writer, operand); |
| | 2763 | try writer.print(", {})", .{try f.fmtIntLiteral(bit_offset_ty, bit_offset_val)}); |
| | 2764 | try f.renderBuiltinInfo(writer, field_ty, .Bits); |
| | 2765 | try writer.writeByte(')'); |
| 2616 | } else { | 2766 | } else { |
| 2617 | try writer.writeAll(" = "); | 2767 | try writer.writeAll(" = "); |
| 2618 | try f.writeCValueDeref(writer, operand); | 2768 | try f.writeCValueDeref(writer, operand); |
| 2619 | try writer.writeAll(";\n"); | | |
| 2620 | } | 2769 | } |
| | 2770 | try writer.writeAll(";\n"); |
| 2621 | return local; | 2771 | return local; |
| 2622 | } | 2772 | } |
| 2623 | | 2773 | |
| 2624 | fn airRet(f: *Function, inst: Air.Inst.Index) !CValue { | 2774 | fn airRet(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValue { |
| 2625 | const un_op = f.air.instructions.items(.data)[inst].un_op; | 2775 | const un_op = f.air.instructions.items(.data)[inst].un_op; |
| 2626 | const writer = f.object.writer(); | 2776 | const writer = f.object.writer(); |
| 2627 | const ret_ty = f.air.typeOf(un_op); | 2777 | const target = f.object.dg.module.getTarget(); |
| 2628 | if (ret_ty.isFnOrHasRuntimeBitsIgnoreComptime()) { | 2778 | const op_ty = f.air.typeOf(un_op); |
| | 2779 | const ret_ty = if (is_ptr) op_ty.childType() else op_ty; |
| | 2780 | var lowered_ret_buf: LowerFnRetTyBuffer = undefined; |
| | 2781 | const lowered_ret_ty = lowerFnRetTy(ret_ty, &lowered_ret_buf, target); |
| | 2782 | |
| | 2783 | if (lowered_ret_ty.hasRuntimeBitsIgnoreComptime()) { |
| | 2784 | var deref = is_ptr; |
| 2629 | const operand = try f.resolveInst(un_op); | 2785 | const operand = try f.resolveInst(un_op); |
| | 2786 | const ret_val = if (lowersToArray(ret_ty, target)) ret_val: { |
| | 2787 | const array_local = try f.allocLocal(lowered_ret_ty, .Mut); |
| | 2788 | try writer.writeAll(";\n"); |
| | 2789 | try writer.writeAll("memcpy("); |
| | 2790 | try f.writeCValueMember(writer, array_local, .{ .identifier = "array" }); |
| | 2791 | try writer.writeAll(", "); |
| | 2792 | if (deref) |
| | 2793 | try f.writeCValueDeref(writer, operand) |
| | 2794 | else |
| | 2795 | try f.writeCValue(writer, operand, .FunctionArgument); |
| | 2796 | deref = false; |
| | 2797 | try writer.writeAll(", sizeof("); |
| | 2798 | try f.renderTypecast(writer, ret_ty); |
| | 2799 | try writer.writeAll("));\n"); |
| | 2800 | break :ret_val array_local; |
| | 2801 | } else operand; |
| | 2802 | |
| 2630 | try writer.writeAll("return "); | 2803 | try writer.writeAll("return "); |
| 2631 | try f.writeCValue(writer, operand, .Other); | 2804 | if (deref) |
| | 2805 | try f.writeCValueDeref(writer, ret_val) |
| | 2806 | else |
| | 2807 | try f.writeCValue(writer, ret_val, .Other); |
| 2632 | try writer.writeAll(";\n"); | 2808 | try writer.writeAll(";\n"); |
| 2633 | } else if (ret_ty.isError()) { | | |
| 2634 | try writer.writeAll("return 0;"); | | |
| 2635 | } else if (f.object.dg.decl.ty.fnCallingConvention() != .Naked) { | 2809 | } else if (f.object.dg.decl.ty.fnCallingConvention() != .Naked) { |
| 2636 | // Not even allowed to return void in a naked function. | 2810 | // Not even allowed to return void in a naked function. |
| 2637 | try writer.writeAll("return;\n"); | 2811 | try writer.writeAll("return;\n"); |
| ... | @@ -2639,24 +2813,6 @@ fn airRet(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -2639,24 +2813,6 @@ fn airRet(f: *Function, inst: Air.Inst.Index) !CValue { |
| 2639 | return CValue.none; | 2813 | return CValue.none; |
| 2640 | } | 2814 | } |
| 2641 | | 2815 | |
| 2642 | fn airRetLoad(f: *Function, inst: Air.Inst.Index) !CValue { | | |
| 2643 | const un_op = f.air.instructions.items(.data)[inst].un_op; | | |
| 2644 | const writer = f.object.writer(); | | |
| 2645 | const ptr_ty = f.air.typeOf(un_op); | | |
| 2646 | const ret_ty = ptr_ty.childType(); | | |
| 2647 | if (ret_ty.isFnOrHasRuntimeBitsIgnoreComptime()) { | | |
| 2648 | const ptr = try f.resolveInst(un_op); | | |
| 2649 | try writer.writeAll("return *"); | | |
| 2650 | try f.writeCValue(writer, ptr, .Other); | | |
| 2651 | try writer.writeAll(";\n"); | | |
| 2652 | } else if (ret_ty.isError()) { | | |
| 2653 | try writer.writeAll("return 0;\n"); | | |
| 2654 | } else { | | |
| 2655 | try writer.writeAll("return;\n"); | | |
| 2656 | } | | |
| 2657 | return CValue.none; | | |
| 2658 | } | | |
| 2659 | | | |
| 2660 | fn airIntCast(f: *Function, inst: Air.Inst.Index) !CValue { | 2816 | fn airIntCast(f: *Function, inst: Air.Inst.Index) !CValue { |
| 2661 | if (f.liveness.isUnused(inst)) | 2817 | if (f.liveness.isUnused(inst)) |
| 2662 | return CValue.none; | 2818 | return CValue.none; |
| ... | @@ -2696,12 +2852,12 @@ fn airTrunc(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -2696,12 +2852,12 @@ fn airTrunc(f: *Function, inst: Air.Inst.Index) !CValue { |
| 2696 | try writer.writeAll(";\n"); | 2852 | try writer.writeAll(";\n"); |
| 2697 | } else switch (dest_int_info.signedness) { | 2853 | } else switch (dest_int_info.signedness) { |
| 2698 | .unsigned => { | 2854 | .unsigned => { |
| 2699 | var arena = std.heap.ArenaAllocator.init(f.object.dg.module.gpa); | 2855 | var arena = std.heap.ArenaAllocator.init(f.object.dg.gpa); |
| 2700 | defer arena.deinit(); | 2856 | defer arena.deinit(); |
| 2701 | | 2857 | |
| 2702 | const expected_contents = union { u: Value.Payload.U64, i: Value.Payload.I64 }; | 2858 | const ExpectedContents = union { u: Value.Payload.U64, i: Value.Payload.I64 }; |
| 2703 | var stack align(@alignOf(expected_contents)) = | 2859 | var stack align(@alignOf(ExpectedContents)) = |
| 2704 | std.heap.stackFallback(@sizeOf(expected_contents), arena.allocator()); | 2860 | std.heap.stackFallback(@sizeOf(ExpectedContents), arena.allocator()); |
| 2705 | | 2861 | |
| 2706 | const mask_val = try inst_ty.maxInt(stack.get(), target); | 2862 | const mask_val = try inst_ty.maxInt(stack.get(), target); |
| 2707 | | 2863 | |
| ... | @@ -2756,10 +2912,11 @@ fn airStoreUndefined(f: *Function, lhs_child_ty: Type, dest_ptr: CValue) !CValue | ... | @@ -2756,10 +2912,11 @@ fn airStoreUndefined(f: *Function, lhs_child_ty: Type, dest_ptr: CValue) !CValue |
| 2756 | fn airStore(f: *Function, inst: Air.Inst.Index) !CValue { | 2912 | fn airStore(f: *Function, inst: Air.Inst.Index) !CValue { |
| 2757 | // *a = b; | 2913 | // *a = b; |
| 2758 | const bin_op = f.air.instructions.items(.data)[inst].bin_op; | 2914 | const bin_op = f.air.instructions.items(.data)[inst].bin_op; |
| 2759 | const lhs_child_ty = f.air.typeOf(bin_op.lhs).childType(); | 2915 | const ptr_info = f.air.typeOf(bin_op.lhs).ptrInfo().data; |
| 2760 | if (!lhs_child_ty.hasRuntimeBitsIgnoreComptime()) return CValue.none; | 2916 | if (!ptr_info.pointee_type.hasRuntimeBitsIgnoreComptime()) return CValue.none; |
| 2761 | | 2917 | |
| 2762 | const dest_ptr = try f.resolveInst(bin_op.lhs); | 2918 | const ptr_val = try f.resolveInst(bin_op.lhs); |
| | 2919 | const src_ty = f.air.typeOf(bin_op.rhs); |
| 2763 | const src_val = try f.resolveInst(bin_op.rhs); | 2920 | const src_val = try f.resolveInst(bin_op.rhs); |
| 2764 | | 2921 | |
| 2765 | // TODO Sema should emit a different instruction when the store should | 2922 | // TODO Sema should emit a different instruction when the store should |
| ... | @@ -2767,20 +2924,20 @@ fn airStore(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -2767,20 +2924,20 @@ fn airStore(f: *Function, inst: Air.Inst.Index) !CValue { |
| 2767 | const src_val_is_undefined = | 2924 | const src_val_is_undefined = |
| 2768 | if (f.air.value(bin_op.rhs)) |v| v.isUndefDeep() else false; | 2925 | if (f.air.value(bin_op.rhs)) |v| v.isUndefDeep() else false; |
| 2769 | if (src_val_is_undefined) | 2926 | if (src_val_is_undefined) |
| 2770 | return try airStoreUndefined(f, lhs_child_ty, dest_ptr); | 2927 | return try airStoreUndefined(f, ptr_info.pointee_type, ptr_val); |
| 2771 | | 2928 | |
| | 2929 | const target = f.object.dg.module.getTarget(); |
| 2772 | const writer = f.object.writer(); | 2930 | const writer = f.object.writer(); |
| 2773 | if (lhs_child_ty.zigTypeTag() == .Array) { | 2931 | if (lowersToArray(ptr_info.pointee_type, target)) { |
| 2774 | // For this memcpy to safely work we need the rhs to have the same | 2932 | // For this memcpy to safely work we need the rhs to have the same |
| 2775 | // underlying type as the lhs (i.e. they must both be arrays of the same underlying type). | 2933 | // underlying type as the lhs (i.e. they must both be arrays of the same underlying type). |
| 2776 | const rhs_type = f.air.typeOf(bin_op.rhs); | 2934 | assert(src_ty.eql(ptr_info.pointee_type, f.object.dg.module)); |
| 2777 | assert(rhs_type.eql(lhs_child_ty, f.object.dg.module)); | | |
| 2778 | | 2935 | |
| 2779 | // If the source is a constant, writeCValue will emit a brace initialization | 2936 | // If the source is a constant, writeCValue will emit a brace initialization |
| 2780 | // so work around this by initializing into new local. | 2937 | // so work around this by initializing into new local. |
| 2781 | // TODO this should be done by manually initializing elements of the dest array | 2938 | // TODO this should be done by manually initializing elements of the dest array |
| 2782 | const array_src = if (src_val == .constant) blk: { | 2939 | const array_src = if (src_val == .constant) blk: { |
| 2783 | const new_local = try f.allocLocal(rhs_type, .Const); | 2940 | const new_local = try f.allocLocal(src_ty, .Const); |
| 2784 | try writer.writeAll(" = "); | 2941 | try writer.writeAll(" = "); |
| 2785 | try f.writeCValue(writer, src_val, .Initializer); | 2942 | try f.writeCValue(writer, src_val, .Initializer); |
| 2786 | try writer.writeAll(";\n"); | 2943 | try writer.writeAll(";\n"); |
| ... | @@ -2789,18 +2946,69 @@ fn airStore(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -2789,18 +2946,69 @@ fn airStore(f: *Function, inst: Air.Inst.Index) !CValue { |
| 2789 | } else src_val; | 2946 | } else src_val; |
| 2790 | | 2947 | |
| 2791 | try writer.writeAll("memcpy("); | 2948 | try writer.writeAll("memcpy("); |
| 2792 | try f.writeCValue(writer, dest_ptr, .FunctionArgument); | 2949 | try f.writeCValue(writer, ptr_val, .FunctionArgument); |
| 2793 | try writer.writeAll(", "); | 2950 | try writer.writeAll(", "); |
| 2794 | try f.writeCValue(writer, array_src, .FunctionArgument); | 2951 | try f.writeCValue(writer, array_src, .FunctionArgument); |
| 2795 | try writer.writeAll(", sizeof("); | 2952 | try writer.writeAll(", sizeof("); |
| 2796 | try f.renderTypecast(writer, lhs_child_ty); | 2953 | try f.renderTypecast(writer, src_ty); |
| 2797 | try writer.writeAll("));\n"); | 2954 | try writer.writeAll("))"); |
| | 2955 | } else if (ptr_info.host_size != 0) { |
| | 2956 | const host_bits = ptr_info.host_size * 8; |
| | 2957 | var host_pl = Type.Payload.Bits{ .base = .{ .tag = .int_unsigned }, .data = host_bits }; |
| | 2958 | const host_ty = Type.initPayload(&host_pl.base); |
| | 2959 | |
| | 2960 | var bit_offset_ty_pl = Type.Payload.Bits{ |
| | 2961 | .base = .{ .tag = .int_unsigned }, |
| | 2962 | .data = Type.smallestUnsignedBits(host_bits - 1), |
| | 2963 | }; |
| | 2964 | const bit_offset_ty = Type.initPayload(&bit_offset_ty_pl.base); |
| | 2965 | |
| | 2966 | var bit_offset_val_pl: Value.Payload.U64 = .{ |
| | 2967 | .base = .{ .tag = .int_u64 }, |
| | 2968 | .data = ptr_info.bit_offset, |
| | 2969 | }; |
| | 2970 | const bit_offset_val = Value.initPayload(&bit_offset_val_pl.base); |
| | 2971 | |
| | 2972 | const src_bits = src_ty.bitSize(target); |
| | 2973 | |
| | 2974 | const Limb = std.math.big.Limb; |
| | 2975 | const ExpectedContents = [BigInt.Managed.default_capacity]Limb; |
| | 2976 | var stack align(@alignOf(ExpectedContents)) = |
| | 2977 | std.heap.stackFallback(@sizeOf(ExpectedContents), f.object.dg.gpa); |
| | 2978 | |
| | 2979 | var mask = try BigInt.Managed.initCapacity(stack.get(), BigInt.calcTwosCompLimbCount(host_bits)); |
| | 2980 | defer mask.deinit(); |
| | 2981 | |
| | 2982 | try mask.setTwosCompIntLimit(.max, .unsigned, @intCast(usize, src_bits)); |
| | 2983 | try mask.shiftLeft(&mask, ptr_info.bit_offset); |
| | 2984 | try mask.bitNotWrap(&mask, .unsigned, host_bits); |
| | 2985 | |
| | 2986 | var mask_pl = Value.Payload.BigInt{ |
| | 2987 | .base = .{ .tag = .int_big_positive }, |
| | 2988 | .data = mask.limbs[0..mask.len()], |
| | 2989 | }; |
| | 2990 | const mask_val = Value.initPayload(&mask_pl.base); |
| | 2991 | |
| | 2992 | try f.writeCValueDeref(writer, ptr_val); |
| | 2993 | try writer.writeAll(" = zig_or_"); |
| | 2994 | try f.renderTypeForBuiltinFnName(writer, host_ty); |
| | 2995 | try writer.writeAll("(zig_and_"); |
| | 2996 | try f.renderTypeForBuiltinFnName(writer, host_ty); |
| | 2997 | try writer.writeByte('('); |
| | 2998 | try f.writeCValueDeref(writer, ptr_val); |
| | 2999 | try writer.print(", {x}), zig_shl_", .{try f.fmtIntLiteral(host_ty, mask_val)}); |
| | 3000 | try f.renderTypeForBuiltinFnName(writer, host_ty); |
| | 3001 | try writer.writeAll("(("); |
| | 3002 | try f.renderTypecast(writer, host_ty); |
| | 3003 | try writer.writeByte(')'); |
| | 3004 | try f.writeCValue(writer, src_val, .Other); |
| | 3005 | try writer.print(", {}))", .{try f.fmtIntLiteral(bit_offset_ty, bit_offset_val)}); |
| 2798 | } else { | 3006 | } else { |
| 2799 | try f.writeCValueDeref(writer, dest_ptr); | 3007 | try f.writeCValueDeref(writer, ptr_val); |
| 2800 | try writer.writeAll(" = "); | 3008 | try writer.writeAll(" = "); |
| 2801 | try f.writeCValue(writer, src_val, .Other); | 3009 | try f.writeCValue(writer, src_val, .Other); |
| 2802 | try writer.writeAll(";\n"); | | |
| 2803 | } | 3010 | } |
| | 3011 | try writer.writeAll(";\n"); |
| 2804 | return CValue.none; | 3012 | return CValue.none; |
| 2805 | } | 3013 | } |
| 2806 | | 3014 | |
| ... | @@ -2959,7 +3167,9 @@ fn airEquality( | ... | @@ -2959,7 +3167,9 @@ fn airEquality( |
| 2959 | } | 3167 | } |
| 2960 | | 3168 | |
| 2961 | try f.writeCValue(writer, lhs, .Other); | 3169 | try f.writeCValue(writer, lhs, .Other); |
| | 3170 | try writer.writeByte(' '); |
| 2962 | try writer.writeAll(eq_op_str); | 3171 | try writer.writeAll(eq_op_str); |
| | 3172 | try writer.writeByte(' '); |
| 2963 | try f.writeCValue(writer, rhs, .Other); | 3173 | try f.writeCValue(writer, rhs, .Other); |
| 2964 | try writer.writeAll(";\n"); | 3174 | try writer.writeAll(";\n"); |
| 2965 | | 3175 | |
| ... | @@ -3079,17 +3289,22 @@ fn airCall( | ... | @@ -3079,17 +3289,22 @@ fn airCall( |
| 3079 | }; | 3289 | }; |
| 3080 | const writer = f.object.writer(); | 3290 | const writer = f.object.writer(); |
| 3081 | | 3291 | |
| 3082 | const result_local: CValue = r: { | 3292 | const target = f.object.dg.module.getTarget(); |
| 3083 | if (!loweredFnRetTyHasBits(fn_ty)) { | 3293 | const ret_ty = fn_ty.fnReturnType(); |
| 3084 | break :r .none; | 3294 | var lowered_ret_buf: LowerFnRetTyBuffer = undefined; |
| 3085 | } else if (f.liveness.isUnused(inst)) { | 3295 | const lowered_ret_ty = lowerFnRetTy(ret_ty, &lowered_ret_buf, target); |
| 3086 | try writer.print("(void)", .{}); | 3296 | |
| 3087 | break :r .none; | 3297 | const result_local: CValue = if (!lowered_ret_ty.hasRuntimeBitsIgnoreComptime()) |
| 3088 | } else { | 3298 | .none |
| 3089 | const local = try f.allocLocal(fn_ty.fnReturnType(), .Const); | 3299 | else if (f.liveness.isUnused(inst)) r: { |
| 3090 | try writer.writeAll(" = "); | 3300 | try writer.writeByte('('); |
| 3091 | break :r local; | 3301 | try f.renderTypecast(writer, Type.void); |
| 3092 | } | 3302 | try writer.writeByte(')'); |
| | 3303 | break :r .none; |
| | 3304 | } else r: { |
| | 3305 | const local = try f.allocLocal(lowered_ret_ty, .Const); |
| | 3306 | try writer.writeAll(" = "); |
| | 3307 | break :r local; |
| 3093 | }; | 3308 | }; |
| 3094 | | 3309 | |
| 3095 | var is_extern = false; | 3310 | var is_extern = false; |
| ... | @@ -3138,7 +3353,19 @@ fn airCall( | ... | @@ -3138,7 +3353,19 @@ fn airCall( |
| 3138 | args_written += 1; | 3353 | args_written += 1; |
| 3139 | } | 3354 | } |
| 3140 | try writer.writeAll(");\n"); | 3355 | try writer.writeAll(");\n"); |
| 3141 | return result_local; | 3356 | |
| | 3357 | if (result_local == .none or !lowersToArray(ret_ty, target)) return result_local; |
| | 3358 | |
| | 3359 | const array_local = try f.allocLocal(ret_ty, .Mut); |
| | 3360 | try writer.writeAll(";\n"); |
| | 3361 | try writer.writeAll("memcpy("); |
| | 3362 | try f.writeCValue(writer, array_local, .FunctionArgument); |
| | 3363 | try writer.writeAll(", "); |
| | 3364 | try f.writeCValueMember(writer, result_local, .{ .identifier = "array" }); |
| | 3365 | try writer.writeAll(", sizeof("); |
| | 3366 | try f.renderTypecast(writer, ret_ty); |
| | 3367 | try writer.writeAll("));\n"); |
| | 3368 | return array_local; |
| 3142 | } | 3369 | } |
| 3143 | | 3370 | |
| 3144 | fn airDbgStmt(f: *Function, inst: Air.Inst.Index) !CValue { | 3371 | fn airDbgStmt(f: *Function, inst: Air.Inst.Index) !CValue { |
| ... | @@ -3263,7 +3490,8 @@ fn lowerTry( | ... | @@ -3263,7 +3490,8 @@ fn lowerTry( |
| 3263 | } | 3490 | } |
| 3264 | } | 3491 | } |
| 3265 | | 3492 | |
| 3266 | const is_array = payload_ty.zigTypeTag() == .Array; | 3493 | const target = f.object.dg.module.getTarget(); |
| | 3494 | const is_array = lowersToArray(payload_ty, target); |
| 3267 | const local = try f.allocLocal(result_ty, if (is_array) .Mut else .Const); | 3495 | const local = try f.allocLocal(result_ty, if (is_array) .Mut else .Const); |
| 3268 | if (is_array) { | 3496 | if (is_array) { |
| 3269 | try writer.writeAll(";\n"); | 3497 | try writer.writeAll(";\n"); |
| ... | @@ -3814,51 +4042,74 @@ fn airFieldParentPtr(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -3814,51 +4042,74 @@ fn airFieldParentPtr(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3814 | | 4042 | |
| 3815 | fn structFieldPtr(f: *Function, inst: Air.Inst.Index, struct_ptr_ty: Type, struct_ptr: CValue, index: u32) !CValue { | 4043 | fn structFieldPtr(f: *Function, inst: Air.Inst.Index, struct_ptr_ty: Type, struct_ptr: CValue, index: u32) !CValue { |
| 3816 | const writer = f.object.writer(); | 4044 | const writer = f.object.writer(); |
| | 4045 | const field_ptr_ty = f.air.typeOfIndex(inst); |
| | 4046 | const field_ptr_info = field_ptr_ty.ptrInfo(); |
| 3817 | const struct_ty = struct_ptr_ty.elemType(); | 4047 | const struct_ty = struct_ptr_ty.elemType(); |
| 3818 | var field_name: []const u8 = undefined; | 4048 | const field_ty = struct_ty.structFieldType(index); |
| 3819 | var field_val_ty: Type = undefined; | | |
| 3820 | | 4049 | |
| 3821 | var field_name_buf: []const u8 = ""; | 4050 | // Ensure complete type definition is visible before accessing fields. |
| | 4051 | try f.renderType(std.io.null_writer, struct_ty); |
| | 4052 | |
| | 4053 | const local = try f.allocLocal(field_ptr_ty, .Const); |
| | 4054 | try writer.writeAll(" = ("); |
| | 4055 | try f.renderTypecast(writer, field_ptr_ty); |
| | 4056 | try writer.writeByte(')'); |
| | 4057 | |
| | 4058 | const extra_name: ?[]const u8 = switch (struct_ty.tag()) { |
| | 4059 | .union_tagged, .union_safety_tagged => "payload", |
| | 4060 | else => null, |
| | 4061 | }; |
| | 4062 | |
| | 4063 | var field_name_buf: []const u8 = &.{}; |
| 3822 | defer f.object.dg.gpa.free(field_name_buf); | 4064 | defer f.object.dg.gpa.free(field_name_buf); |
| 3823 | switch (struct_ty.tag()) { | 4065 | const field_name: ?[]const u8 = switch (struct_ty.tag()) { |
| 3824 | .@"struct" => { | 4066 | .@"struct" => switch (struct_ty.containerLayout()) { |
| 3825 | const fields = struct_ty.structFields(); | 4067 | .Auto, .Extern => struct_ty.structFieldName(index), |
| 3826 | field_name = fields.keys()[index]; | 4068 | .Packed => if (field_ptr_info.data.host_size == 0) { |
| 3827 | field_val_ty = fields.values()[index].ty; | 4069 | const target = f.object.dg.module.getTarget(); |
| 3828 | }, | 4070 | |
| 3829 | .@"union", .union_safety_tagged, .union_tagged => { | 4071 | const byte_offset = struct_ty.packedStructFieldByteOffset(index, target); |
| 3830 | const fields = struct_ty.unionFields(); | 4072 | var byte_offset_pl = Value.Payload.U64{ |
| 3831 | field_name = fields.keys()[index]; | 4073 | .base = .{ .tag = .int_u64 }, |
| 3832 | field_val_ty = fields.values()[index].ty; | 4074 | .data = byte_offset, |
| | 4075 | }; |
| | 4076 | const byte_offset_val = Value.initPayload(&byte_offset_pl.base); |
| | 4077 | |
| | 4078 | var ptr_u8_pl = field_ptr_info; |
| | 4079 | ptr_u8_pl.data.pointee_type = Type.u8; |
| | 4080 | const ptr_u8_ty = Type.initPayload(&ptr_u8_pl.base); |
| | 4081 | |
| | 4082 | try writer.writeAll("&(("); |
| | 4083 | try f.renderTypecast(writer, ptr_u8_ty); |
| | 4084 | try writer.writeByte(')'); |
| | 4085 | try f.writeCValue(writer, struct_ptr, .Other); |
| | 4086 | try writer.print(")[{}];\n", .{try f.fmtIntLiteral(Type.usize, byte_offset_val)}); |
| | 4087 | return local; |
| | 4088 | } else null, |
| 3833 | }, | 4089 | }, |
| 3834 | .tuple, .anon_struct => { | 4090 | .@"union", .union_safety_tagged, .union_tagged => struct_ty.unionFields().keys()[index], |
| | 4091 | .tuple, .anon_struct => |tag| field_name: { |
| 3835 | const tuple = struct_ty.tupleFields(); | 4092 | const tuple = struct_ty.tupleFields(); |
| 3836 | if (tuple.values[index].tag() != .unreachable_value) return CValue.none; | 4093 | if (tuple.values[index].tag() != .unreachable_value) return CValue.none; |
| 3837 | | 4094 | |
| | 4095 | if (tag == .anon_struct) break :field_name struct_ty.structFieldName(index); |
| | 4096 | |
| 3838 | field_name_buf = try std.fmt.allocPrint(f.object.dg.gpa, "field_{d}", .{index}); | 4097 | field_name_buf = try std.fmt.allocPrint(f.object.dg.gpa, "field_{d}", .{index}); |
| 3839 | field_name = field_name_buf; | 4098 | break :field_name field_name_buf; |
| 3840 | field_val_ty = tuple.types[index]; | | |
| 3841 | }, | 4099 | }, |
| 3842 | else => unreachable, | 4100 | else => unreachable, |
| 3843 | } | 4101 | }; |
| 3844 | const payload = if (struct_ty.tag() == .union_tagged or struct_ty.tag() == .union_safety_tagged) "payload." else ""; | | |
| 3845 | | | |
| 3846 | // Ensure complete type definition is visible before accessing fields. | | |
| 3847 | try f.renderType(std.io.null_writer, struct_ty); | | |
| 3848 | | 4102 | |
| 3849 | const inst_ty = f.air.typeOfIndex(inst); | 4103 | if (field_ty.hasRuntimeBitsIgnoreComptime()) { |
| 3850 | const local = try f.allocLocal(inst_ty, .Const); | 4104 | try writer.writeByte('&'); |
| 3851 | if (field_val_ty.hasRuntimeBitsIgnoreComptime()) { | 4105 | if (extra_name orelse field_name) |name| |
| 3852 | try writer.writeAll(" = &"); | 4106 | try f.writeCValueDerefMember(writer, struct_ptr, .{ .identifier = name }) |
| 3853 | try f.writeCValueDeref(writer, struct_ptr); | 4107 | else |
| 3854 | try writer.print(".{s}{ };\n", .{ payload, fmtIdent(field_name) }); | 4108 | try f.writeCValueDeref(writer, struct_ptr); |
| 3855 | } else { | 4109 | if (extra_name) |_| if (field_name) |name| |
| 3856 | try writer.writeAll(" = ("); | 4110 | try writer.print(".{ }", .{fmtIdent(name)}); |
| 3857 | try f.renderTypecast(writer, inst_ty); | 4111 | } else try f.writeCValue(writer, struct_ptr, .Other); |
| 3858 | try writer.writeByte(')'); | 4112 | try writer.writeAll(";\n"); |
| 3859 | try f.writeCValue(writer, struct_ptr, .Other); | | |
| 3860 | try writer.writeAll(";\n"); | | |
| 3861 | } | | |
| 3862 | return local; | 4113 | return local; |
| 3863 | } | 4114 | } |
| 3864 | | 4115 | |
| ... | @@ -3868,18 +4119,84 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -3868,18 +4119,84 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3868 | | 4119 | |
| 3869 | const ty_pl = f.air.instructions.items(.data)[inst].ty_pl; | 4120 | const ty_pl = f.air.instructions.items(.data)[inst].ty_pl; |
| 3870 | const extra = f.air.extraData(Air.StructField, ty_pl.payload).data; | 4121 | const extra = f.air.extraData(Air.StructField, ty_pl.payload).data; |
| 3871 | const writer = f.object.writer(); | 4122 | const inst_ty = f.air.typeOfIndex(inst); |
| | 4123 | const target = f.object.dg.module.getTarget(); |
| 3872 | const struct_byval = try f.resolveInst(extra.struct_operand); | 4124 | const struct_byval = try f.resolveInst(extra.struct_operand); |
| 3873 | const struct_ty = f.air.typeOf(extra.struct_operand); | 4125 | const struct_ty = f.air.typeOf(extra.struct_operand); |
| | 4126 | const writer = f.object.writer(); |
| | 4127 | |
| | 4128 | // Ensure complete type definition is visible before accessing fields. |
| | 4129 | try f.renderType(std.io.null_writer, struct_ty); |
| | 4130 | |
| 3874 | var field_name_buf: []const u8 = ""; | 4131 | var field_name_buf: []const u8 = ""; |
| 3875 | defer f.object.dg.gpa.free(field_name_buf); | 4132 | defer f.object.dg.gpa.free(field_name_buf); |
| 3876 | const field_name = switch (struct_ty.tag()) { | 4133 | const field_name = switch (struct_ty.tag()) { |
| 3877 | .@"struct" => struct_ty.structFields().keys()[extra.field_index], | 4134 | .@"struct" => switch (struct_ty.containerLayout()) { |
| | 4135 | .Auto, .Extern => struct_ty.structFieldName(extra.field_index), |
| | 4136 | .Packed => { |
| | 4137 | const struct_obj = struct_ty.castTag(.@"struct").?.data; |
| | 4138 | const int_info = struct_ty.intInfo(target); |
| | 4139 | |
| | 4140 | var bit_offset_ty_pl = Type.Payload.Bits{ |
| | 4141 | .base = .{ .tag = .int_unsigned }, |
| | 4142 | .data = Type.smallestUnsignedBits(int_info.bits - 1), |
| | 4143 | }; |
| | 4144 | const bit_offset_ty = Type.initPayload(&bit_offset_ty_pl.base); |
| | 4145 | |
| | 4146 | var bit_offset_val_pl: Value.Payload.U64 = .{ |
| | 4147 | .base = .{ .tag = .int_u64 }, |
| | 4148 | .data = struct_obj.packedFieldBitOffset(target, extra.field_index), |
| | 4149 | }; |
| | 4150 | const bit_offset_val = Value.initPayload(&bit_offset_val_pl.base); |
| | 4151 | |
| | 4152 | const field_int_signedness = if (inst_ty.isAbiInt()) |
| | 4153 | inst_ty.intInfo(target).signedness |
| | 4154 | else |
| | 4155 | .unsigned; |
| | 4156 | var field_int_pl = Type.Payload.Bits{ |
| | 4157 | .base = .{ .tag = switch (field_int_signedness) { |
| | 4158 | .unsigned => .int_unsigned, |
| | 4159 | .signed => .int_signed, |
| | 4160 | } }, |
| | 4161 | .data = @intCast(u16, inst_ty.bitSize(target)), |
| | 4162 | }; |
| | 4163 | const field_int_ty = Type.initPayload(&field_int_pl.base); |
| | 4164 | |
| | 4165 | const temp_local = try f.allocLocal(field_int_ty, .Const); |
| | 4166 | try writer.writeAll(" = zig_wrap_"); |
| | 4167 | try f.renderTypeForBuiltinFnName(writer, field_int_ty); |
| | 4168 | try writer.writeAll("(("); |
| | 4169 | try f.renderTypecast(writer, field_int_ty); |
| | 4170 | try writer.writeAll(")zig_shr_"); |
| | 4171 | try f.renderTypeForBuiltinFnName(writer, struct_ty); |
| | 4172 | try writer.writeByte('('); |
| | 4173 | try f.writeCValue(writer, struct_byval, .Other); |
| | 4174 | try writer.writeAll(", "); |
| | 4175 | try f.object.dg.renderValue(writer, bit_offset_ty, bit_offset_val, .FunctionArgument); |
| | 4176 | try writer.writeByte(')'); |
| | 4177 | try f.renderBuiltinInfo(writer, field_int_ty, .Bits); |
| | 4178 | try writer.writeAll(");\n"); |
| | 4179 | if (inst_ty.eql(field_int_ty, f.object.dg.module)) return temp_local; |
| | 4180 | |
| | 4181 | const local = try f.allocLocal(inst_ty, .Mut); |
| | 4182 | try writer.writeAll(";\n"); |
| | 4183 | try writer.writeAll("memcpy("); |
| | 4184 | try f.writeCValue(writer, .{ .local_ref = local.local }, .FunctionArgument); |
| | 4185 | try writer.writeAll(", "); |
| | 4186 | try f.writeCValue(writer, .{ .local_ref = temp_local.local }, .FunctionArgument); |
| | 4187 | try writer.writeAll(", sizeof("); |
| | 4188 | try f.renderTypecast(writer, inst_ty); |
| | 4189 | try writer.writeAll("));\n"); |
| | 4190 | return local; |
| | 4191 | }, |
| | 4192 | }, |
| 3878 | .@"union", .union_safety_tagged, .union_tagged => struct_ty.unionFields().keys()[extra.field_index], | 4193 | .@"union", .union_safety_tagged, .union_tagged => struct_ty.unionFields().keys()[extra.field_index], |
| 3879 | .tuple, .anon_struct => blk: { | 4194 | .tuple, .anon_struct => |tag| blk: { |
| 3880 | const tuple = struct_ty.tupleFields(); | 4195 | const tuple = struct_ty.tupleFields(); |
| 3881 | if (tuple.values[extra.field_index].tag() != .unreachable_value) return CValue.none; | 4196 | if (tuple.values[extra.field_index].tag() != .unreachable_value) return CValue.none; |
| 3882 | | 4197 | |
| | 4198 | if (tag == .anon_struct) break :blk struct_ty.structFieldName(extra.field_index); |
| | 4199 | |
| 3883 | field_name_buf = try std.fmt.allocPrint(f.object.dg.gpa, "field_{d}", .{extra.field_index}); | 4200 | field_name_buf = try std.fmt.allocPrint(f.object.dg.gpa, "field_{d}", .{extra.field_index}); |
| 3884 | break :blk field_name_buf; | 4201 | break :blk field_name_buf; |
| 3885 | }, | 4202 | }, |
| ... | @@ -3887,13 +4204,8 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -3887,13 +4204,8 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3887 | }; | 4204 | }; |
| 3888 | const payload = if (struct_ty.tag() == .union_tagged or struct_ty.tag() == .union_safety_tagged) "payload." else ""; | 4205 | const payload = if (struct_ty.tag() == .union_tagged or struct_ty.tag() == .union_safety_tagged) "payload." else ""; |
| 3889 | | 4206 | |
| 3890 | // Ensure complete type definition is visible before accessing fields. | 4207 | const is_array = lowersToArray(inst_ty, target); |
| 3891 | try f.renderType(std.io.null_writer, struct_ty); | | |
| 3892 | | | |
| 3893 | const inst_ty = f.air.typeOfIndex(inst); | | |
| 3894 | const is_array = inst_ty.zigTypeTag() == .Array; | | |
| 3895 | const local = try f.allocLocal(inst_ty, if (is_array) .Mut else .Const); | 4208 | const local = try f.allocLocal(inst_ty, if (is_array) .Mut else .Const); |
| 3896 | | | |
| 3897 | if (is_array) { | 4209 | if (is_array) { |
| 3898 | try writer.writeAll(";\n"); | 4210 | try writer.writeAll(";\n"); |
| 3899 | try writer.writeAll("memcpy("); | 4211 | try writer.writeAll("memcpy("); |
| ... | @@ -4067,7 +4379,8 @@ fn airWrapErrUnionPay(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -4067,7 +4379,8 @@ fn airWrapErrUnionPay(f: *Function, inst: Air.Inst.Index) !CValue { |
| 4067 | const inst_ty = f.air.typeOfIndex(inst); | 4379 | const inst_ty = f.air.typeOfIndex(inst); |
| 4068 | const payload_ty = inst_ty.errorUnionPayload(); | 4380 | const payload_ty = inst_ty.errorUnionPayload(); |
| 4069 | const error_ty = inst_ty.errorUnionSet(); | 4381 | const error_ty = inst_ty.errorUnionSet(); |
| 4070 | const is_array = payload_ty.zigTypeTag() == .Array; | 4382 | const target = f.object.dg.module.getTarget(); |
| | 4383 | const is_array = lowersToArray(payload_ty, target); |
| 4071 | const local = try f.allocLocal(inst_ty, if (is_array) .Mut else .Const); | 4384 | const local = try f.allocLocal(inst_ty, if (is_array) .Mut else .Const); |
| 4072 | try writer.writeAll(" = { .payload = "); | 4385 | try writer.writeAll(" = { .payload = "); |
| 4073 | try f.writeCValue(writer, if (is_array) CValue{ .undef = payload_ty } else operand, .Initializer); | 4386 | try f.writeCValue(writer, if (is_array) CValue{ .undef = payload_ty } else operand, .Initializer); |
| ... | @@ -4141,7 +4454,7 @@ fn airArrayToSlice(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -4141,7 +4454,7 @@ fn airArrayToSlice(f: *Function, inst: Air.Inst.Index) !CValue { |
| 4141 | } else { | 4454 | } else { |
| 4142 | try writer.writeAll("&("); | 4455 | try writer.writeAll("&("); |
| 4143 | try f.writeCValueDeref(writer, operand); | 4456 | try f.writeCValueDeref(writer, operand); |
| 4144 | try writer.writeAll(")[0]"); | 4457 | try writer.print(")[{}]", .{try f.fmtIntLiteral(Type.usize, Value.zero)}); |
| 4145 | } | 4458 | } |
| 4146 | | 4459 | |
| 4147 | var len_pl: Value.Payload.U64 = .{ .base = .{ .tag = .int_u64 }, .data = array_len }; | 4460 | var len_pl: Value.Payload.U64 = .{ .base = .{ .tag = .int_u64 }, .data = array_len }; |
| ... | @@ -4571,16 +4884,18 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -4571,16 +4884,18 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue { |
| 4571 | const ty_pl = f.air.instructions.items(.data)[inst].ty_pl; | 4884 | const ty_pl = f.air.instructions.items(.data)[inst].ty_pl; |
| 4572 | const len = @intCast(usize, inst_ty.arrayLen()); | 4885 | const len = @intCast(usize, inst_ty.arrayLen()); |
| 4573 | const elements = @ptrCast([]const Air.Inst.Ref, f.air.extra[ty_pl.payload..][0..len]); | 4886 | const elements = @ptrCast([]const Air.Inst.Ref, f.air.extra[ty_pl.payload..][0..len]); |
| | 4887 | const target = f.object.dg.module.getTarget(); |
| 4574 | const mutability: Mutability = for (elements) |element| { | 4888 | const mutability: Mutability = for (elements) |element| { |
| 4575 | if (f.air.typeOf(element).zigTypeTag() == .Array) break .Mut; | 4889 | if (lowersToArray(f.air.typeOf(element), target)) break .Mut; |
| 4576 | } else .Const; | 4890 | } else .Const; |
| 4577 | | 4891 | |
| 4578 | const writer = f.object.writer(); | 4892 | const writer = f.object.writer(); |
| 4579 | const local = try f.allocLocal(inst_ty, mutability); | 4893 | const local = try f.allocLocal(inst_ty, mutability); |
| 4580 | try writer.writeAll(" = {"); | 4894 | try writer.writeAll(" = "); |
| 4581 | switch (inst_ty.zigTypeTag()) { | 4895 | switch (inst_ty.zigTypeTag()) { |
| 4582 | .Array => { | 4896 | .Array => { |
| 4583 | const elem_ty = inst_ty.childType(); | 4897 | const elem_ty = inst_ty.childType(); |
| | 4898 | try writer.writeByte('{'); |
| 4584 | var empty = true; | 4899 | var empty = true; |
| 4585 | for (elements) |element| { | 4900 | for (elements) |element| { |
| 4586 | if (!empty) try writer.writeAll(", "); | 4901 | if (!empty) try writer.writeAll(", "); |
| ... | @@ -4595,49 +4910,99 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -4595,49 +4910,99 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue { |
| 4595 | if (empty) try writer.print("{}", .{try f.fmtIntLiteral(Type.u8, Value.zero)}); | 4910 | if (empty) try writer.print("{}", .{try f.fmtIntLiteral(Type.u8, Value.zero)}); |
| 4596 | try writer.writeAll("};\n"); | 4911 | try writer.writeAll("};\n"); |
| 4597 | }, | 4912 | }, |
| 4598 | .Struct => { | 4913 | .Struct => switch (inst_ty.containerLayout()) { |
| 4599 | var empty = true; | 4914 | .Auto, .Extern => { |
| 4600 | for (elements) |element, index| { | 4915 | try writer.writeByte('{'); |
| 4601 | if (inst_ty.structFieldValueComptime(index)) |_| continue; | 4916 | var empty = true; |
| | 4917 | for (elements) |element, index| { |
| | 4918 | if (inst_ty.structFieldValueComptime(index)) |_| continue; |
| 4602 | | 4919 | |
| 4603 | if (!empty) try writer.writeAll(", "); | 4920 | if (!empty) try writer.writeAll(", "); |
| 4604 | if (!inst_ty.isTupleOrAnonStruct()) { | 4921 | if (!inst_ty.isTupleOrAnonStruct()) { |
| 4605 | try writer.print(".{ } = ", .{fmtIdent(inst_ty.structFieldName(index))}); | 4922 | try writer.print(".{ } = ", .{fmtIdent(inst_ty.structFieldName(index))}); |
| | 4923 | } |
| | 4924 | |
| | 4925 | const element_ty = f.air.typeOf(element); |
| | 4926 | try f.writeCValue(writer, switch (element_ty.zigTypeTag()) { |
| | 4927 | .Array => CValue{ .undef = element_ty }, |
| | 4928 | else => try f.resolveInst(element), |
| | 4929 | }, .Initializer); |
| | 4930 | empty = false; |
| | 4931 | } |
| | 4932 | if (empty) try writer.print("{}", .{try f.fmtIntLiteral(Type.u8, Value.zero)}); |
| | 4933 | try writer.writeAll("};\n"); |
| | 4934 | |
| | 4935 | for (elements) |element, index| { |
| | 4936 | if (inst_ty.structFieldValueComptime(index)) |_| continue; |
| | 4937 | |
| | 4938 | const element_ty = f.air.typeOf(element); |
| | 4939 | if (element_ty.zigTypeTag() != .Array) continue; |
| | 4940 | |
| | 4941 | var field_name_buf: []u8 = &.{}; |
| | 4942 | defer f.object.dg.gpa.free(field_name_buf); |
| | 4943 | const field_name = if (inst_ty.isTuple()) field_name: { |
| | 4944 | field_name_buf = try std.fmt.allocPrint(f.object.dg.gpa, "field_{d}", .{index}); |
| | 4945 | break :field_name field_name_buf; |
| | 4946 | } else inst_ty.structFieldName(index); |
| | 4947 | |
| | 4948 | try writer.writeAll(";\n"); |
| | 4949 | try writer.writeAll("memcpy("); |
| | 4950 | try f.writeCValue(writer, local, .Other); |
| | 4951 | try writer.print(".{ }, ", .{fmtIdent(field_name)}); |
| | 4952 | try f.writeCValue(writer, try f.resolveInst(element), .FunctionArgument); |
| | 4953 | try writer.writeAll(", sizeof("); |
| | 4954 | try f.renderTypecast(writer, element_ty); |
| | 4955 | try writer.writeAll("));\n"); |
| 4606 | } | 4956 | } |
| | 4957 | }, |
| | 4958 | .Packed => { |
| | 4959 | const int_info = inst_ty.intInfo(target); |
| 4607 | | 4960 | |
| 4608 | const element_ty = f.air.typeOf(element); | 4961 | var bit_offset_ty_pl = Type.Payload.Bits{ |
| 4609 | try f.writeCValue(writer, switch (element_ty.zigTypeTag()) { | 4962 | .base = .{ .tag = .int_unsigned }, |
| 4610 | .Array => CValue{ .undef = element_ty }, | 4963 | .data = Type.smallestUnsignedBits(int_info.bits - 1), |
| 4611 | else => try f.resolveInst(element), | 4964 | }; |
| 4612 | }, .Initializer); | 4965 | const bit_offset_ty = Type.initPayload(&bit_offset_ty_pl.base); |
| 4613 | empty = false; | | |
| 4614 | } | | |
| 4615 | if (empty) try writer.print("{}", .{try f.fmtIntLiteral(Type.u8, Value.zero)}); | | |
| 4616 | try writer.writeAll("};\n"); | | |
| 4617 | | 4966 | |
| 4618 | for (elements) |element, index| { | 4967 | var bit_offset_val_pl: Value.Payload.U64 = .{ .base = .{ .tag = .int_u64 }, .data = 0 }; |
| 4619 | if (inst_ty.structFieldValueComptime(index)) |_| continue; | 4968 | const bit_offset_val = Value.initPayload(&bit_offset_val_pl.base); |
| 4620 | | 4969 | |
| 4621 | const element_ty = f.air.typeOf(element); | 4970 | var empty = true; |
| 4622 | if (element_ty.zigTypeTag() != .Array) continue; | 4971 | for (elements) |_, index| { |
| | 4972 | const field_ty = inst_ty.structFieldType(index); |
| | 4973 | if (!field_ty.hasRuntimeBitsIgnoreComptime()) continue; |
| 4623 | | 4974 | |
| 4624 | var field_name_storage: ?[]u8 = null; | 4975 | if (!empty) { |
| 4625 | defer if (field_name_storage) |storage| f.object.dg.gpa.free(storage); | 4976 | try writer.writeAll("zig_or_"); |
| 4626 | const field_name = if (inst_ty.isTupleOrAnonStruct()) field_name: { | 4977 | try f.renderTypeForBuiltinFnName(writer, inst_ty); |
| 4627 | const name = try std.fmt.allocPrint(f.object.dg.gpa, "field_{d}", .{index}); | 4978 | try writer.writeByte('('); |
| 4628 | field_name_storage = name; | 4979 | } |
| 4629 | break :field_name name; | 4980 | empty = false; |
| 4630 | } else inst_ty.structFieldName(index); | 4981 | } |
| | 4982 | empty = true; |
| | 4983 | for (elements) |element, index| { |
| | 4984 | const field_ty = inst_ty.structFieldType(index); |
| | 4985 | if (!field_ty.hasRuntimeBitsIgnoreComptime()) continue; |
| | 4986 | |
| | 4987 | if (!empty) try writer.writeAll(", "); |
| | 4988 | try writer.writeAll("zig_shlw_"); |
| | 4989 | try f.renderTypeForBuiltinFnName(writer, inst_ty); |
| | 4990 | try writer.writeAll("(("); |
| | 4991 | try f.renderTypecast(writer, inst_ty); |
| | 4992 | try writer.writeByte(')'); |
| | 4993 | try f.writeCValue(writer, try f.resolveInst(element), .Other); |
| | 4994 | try writer.writeAll(", "); |
| | 4995 | try f.object.dg.renderValue(writer, bit_offset_ty, bit_offset_val, .FunctionArgument); |
| | 4996 | try f.renderBuiltinInfo(writer, inst_ty, .Bits); |
| | 4997 | try writer.writeByte(')'); |
| | 4998 | if (!empty) try writer.writeByte(')'); |
| 4631 | | 4999 | |
| | 5000 | bit_offset_val_pl.data += field_ty.bitSize(target); |
| | 5001 | empty = false; |
| | 5002 | } |
| | 5003 | if (empty) try f.writeCValue(writer, .{ .undef = inst_ty }, .Initializer); |
| 4632 | try writer.writeAll(";\n"); | 5004 | try writer.writeAll(";\n"); |
| 4633 | try writer.writeAll("memcpy("); | 5005 | }, |
| 4634 | try f.writeCValue(writer, local, .Other); | | |
| 4635 | try writer.print(".{ }, ", .{fmtIdent(field_name)}); | | |
| 4636 | try f.writeCValue(writer, try f.resolveInst(element), .FunctionArgument); | | |
| 4637 | try writer.writeAll(", sizeof("); | | |
| 4638 | try f.renderTypecast(writer, element_ty); | | |
| 4639 | try writer.writeAll("));\n"); | | |
| 4640 | } | | |
| 4641 | }, | 5006 | }, |
| 4642 | .Vector => return f.fail("TODO: C backend: implement airAggregateInit for vectors", .{}), | 5007 | .Vector => return f.fail("TODO: C backend: implement airAggregateInit for vectors", .{}), |
| 4643 | else => unreachable, | 5008 | else => unreachable, |
| ... | @@ -4947,7 +5312,7 @@ fn formatIntLiteral( | ... | @@ -4947,7 +5312,7 @@ fn formatIntLiteral( |
| 4947 | const int_info = data.ty.intInfo(target); | 5312 | const int_info = data.ty.intInfo(target); |
| 4948 | | 5313 | |
| 4949 | const Limb = std.math.big.Limb; | 5314 | const Limb = std.math.big.Limb; |
| 4950 | const expected_contents = struct { | 5315 | const ExpectedContents = struct { |
| 4951 | const base = 10; | 5316 | const base = 10; |
| 4952 | const limbs_count_128 = BigInt.calcTwosCompLimbCount(128); | 5317 | const limbs_count_128 = BigInt.calcTwosCompLimbCount(128); |
| 4953 | const expected_needed_limbs_count = BigInt.calcToStringLimbsBufferLen(limbs_count_128, base); | 5318 | const expected_needed_limbs_count = BigInt.calcToStringLimbsBufferLen(limbs_count_128, base); |
| ... | @@ -4959,8 +5324,8 @@ fn formatIntLiteral( | ... | @@ -4959,8 +5324,8 @@ fn formatIntLiteral( |
| 4959 | undef_limbs: [limbs_count_128]Limb, | 5324 | undef_limbs: [limbs_count_128]Limb, |
| 4960 | wrap_limbs: [limbs_count_128]Limb, | 5325 | wrap_limbs: [limbs_count_128]Limb, |
| 4961 | }; | 5326 | }; |
| 4962 | var stack align(@alignOf(expected_contents)) = | 5327 | var stack align(@alignOf(ExpectedContents)) = |
| 4963 | std.heap.stackFallback(@sizeOf(expected_contents), data.mod.gpa); | 5328 | std.heap.stackFallback(@sizeOf(ExpectedContents), data.mod.gpa); |
| 4964 | const allocator = stack.get(); | 5329 | const allocator = stack.get(); |
| 4965 | | 5330 | |
| 4966 | var undef_limbs: []Limb = &.{}; | 5331 | var undef_limbs: []Limb = &.{}; |
| ... | @@ -5092,18 +5457,60 @@ fn formatIntLiteral( | ... | @@ -5092,18 +5457,60 @@ fn formatIntLiteral( |
| 5092 | } | 5457 | } |
| 5093 | } | 5458 | } |
| 5094 | | 5459 | |
| 5095 | fn loweredFnRetTyHasBits(fn_ty: Type) bool { | | |
| 5096 | const ret_ty = fn_ty.fnReturnType(); | | |
| 5097 | if (ret_ty.hasRuntimeBitsIgnoreComptime()) { | | |
| 5098 | return true; | | |
| 5099 | } | | |
| 5100 | if (ret_ty.isError()) { | | |
| 5101 | return true; | | |
| 5102 | } | | |
| 5103 | return false; | | |
| 5104 | } | | |
| 5105 | | | |
| 5106 | fn isByRef(ty: Type) bool { | 5460 | fn isByRef(ty: Type) bool { |
| 5107 | _ = ty; | 5461 | _ = ty; |
| 5108 | return false; | 5462 | return false; |
| 5109 | } | 5463 | } |
| | 5464 | |
| | 5465 | const LowerFnRetTyBuffer = struct { |
| | 5466 | const names = [1][]const u8{"array"}; |
| | 5467 | types: [1]Type, |
| | 5468 | values: [1]Value, |
| | 5469 | payload: Type.Payload.AnonStruct, |
| | 5470 | }; |
| | 5471 | fn lowerFnRetTy(ret_ty: Type, buffer: *LowerFnRetTyBuffer, target: std.Target) Type { |
| | 5472 | if (ret_ty.zigTypeTag() == .NoReturn) return Type.initTag(.noreturn); |
| | 5473 | |
| | 5474 | if (lowersToArray(ret_ty, target)) { |
| | 5475 | buffer.types = [1]Type{ret_ty}; |
| | 5476 | buffer.values = [1]Value{Value.initTag(.unreachable_value)}; |
| | 5477 | buffer.payload = .{ .data = .{ |
| | 5478 | .names = &LowerFnRetTyBuffer.names, |
| | 5479 | .types = &buffer.types, |
| | 5480 | .values = &buffer.values, |
| | 5481 | } }; |
| | 5482 | return Type.initPayload(&buffer.payload.base); |
| | 5483 | } |
| | 5484 | |
| | 5485 | return if (ret_ty.hasRuntimeBitsIgnoreComptime()) ret_ty else Type.void; |
| | 5486 | } |
| | 5487 | |
| | 5488 | fn lowersToArray(ty: Type, target: std.Target) bool { |
| | 5489 | return switch (ty.zigTypeTag()) { |
| | 5490 | .Array => return true, |
| | 5491 | else => return ty.isAbiInt() and toCIntBits(@intCast(u32, ty.bitSize(target))) == null, |
| | 5492 | }; |
| | 5493 | } |
| | 5494 | |
| | 5495 | fn loweredArrayInfo(ty: Type, target: std.Target) ?Type.ArrayInfo { |
| | 5496 | if (!lowersToArray(ty, target)) return null; |
| | 5497 | |
| | 5498 | switch (ty.zigTypeTag()) { |
| | 5499 | .Array => return ty.arrayInfo(), |
| | 5500 | else => { |
| | 5501 | const abi_size = ty.abiSize(target); |
| | 5502 | const abi_align = ty.abiAlignment(target); |
| | 5503 | return Type.ArrayInfo{ |
| | 5504 | .elem_type = switch (abi_align) { |
| | 5505 | 1 => Type.u8, |
| | 5506 | 2 => Type.u16, |
| | 5507 | 4 => Type.u32, |
| | 5508 | 8 => Type.u64, |
| | 5509 | 16 => Type.initTag(.u128), |
| | 5510 | else => unreachable, |
| | 5511 | }, |
| | 5512 | .len = @divExact(abi_size, abi_align), |
| | 5513 | }; |
| | 5514 | }, |
| | 5515 | } |
| | 5516 | } |