| ... | ... | @@ -18,7 +18,7 @@ const Air = @import("../Air.zig"); |
| 18 | 18 | const Liveness = @import("../Liveness.zig"); |
| 19 | 19 | const CType = @import("../type.zig").CType; |
| 20 | 20 | |
| 21 | | const Mutability = enum { Const, Mut }; |
| 21 | const Mutability = enum { Const, ConstArgument, Mut }; |
| 22 | 22 | const BigInt = std.math.big.int; |
| 23 | 23 | |
| 24 | 24 | pub const CValue = union(enum) { |
| ... | ... | @@ -254,24 +254,20 @@ pub const Function = struct { |
| 254 | 254 | |
| 255 | 255 | const val = f.air.value(inst).?; |
| 256 | 256 | const ty = f.air.typeOf(inst); |
| 257 | | switch (ty.zigTypeTag()) { |
| 258 | | .Array => { |
| 259 | | const writer = f.object.code_header.writer(); |
| 260 | | const decl_c_value = f.allocLocalValue(); |
| 261 | | gop.value_ptr.* = decl_c_value; |
| 262 | | try writer.writeAll("static "); |
| 263 | | try f.object.dg.renderTypeAndName(writer, ty, decl_c_value, .Const, 0, .Complete); |
| 264 | | try writer.writeAll(" = "); |
| 265 | | try f.object.dg.renderValue(writer, ty, val, .Initializer); |
| 266 | | try writer.writeAll(";\n "); |
| 267 | | return decl_c_value; |
| 268 | | }, |
| 269 | | else => { |
| 270 | | const result = CValue{ .constant = inst }; |
| 271 | | gop.value_ptr.* = result; |
| 272 | | return result; |
| 273 | | }, |
| 274 | | } |
| 257 | |
| 258 | const result = if (lowersToArray(ty, f.object.dg.module.getTarget())) result: { |
| 259 | const writer = f.object.code_header.writer(); |
| 260 | const decl_c_value = f.allocLocalValue(); |
| 261 | try writer.writeAll("static "); |
| 262 | try f.object.dg.renderTypeAndName(writer, ty, decl_c_value, .Const, 0, .Complete); |
| 263 | try writer.writeAll(" = "); |
| 264 | try f.object.dg.renderValue(writer, ty, val, .Initializer); |
| 265 | try writer.writeAll(";\n "); |
| 266 | break :result decl_c_value; |
| 267 | } else CValue{ .constant = inst }; |
| 268 | |
| 269 | gop.value_ptr.* = result; |
| 270 | return result; |
| 275 | 271 | } |
| 276 | 272 | |
| 277 | 273 | fn wantSafety(f: *Function) bool { |
| ... | ... | @@ -374,7 +370,7 @@ pub const Function = struct { |
| 374 | 370 | |
| 375 | 371 | fn renderTypeForBuiltinFnName(f: *Function, writer: anytype, ty: Type) !void { |
| 376 | 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 | 374 | const int_info = ty.intInfo(target); |
| 379 | 375 | try writer.writeByte(signAbbrev(int_info.signedness)); |
| 380 | 376 | break :c_bits toCIntBits(int_info.bits) orelse |
| ... | ... | @@ -393,21 +389,21 @@ pub const Function = struct { |
| 393 | 389 | switch (info) { |
| 394 | 390 | .None => {}, |
| 395 | 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 | 393 | defer arena.deinit(); |
| 398 | 394 | |
| 399 | | const expected_contents = union { u: Value.Payload.U64, i: Value.Payload.I64 }; |
| 400 | | var stack align(@alignOf(expected_contents)) = |
| 401 | | std.heap.stackFallback(@sizeOf(expected_contents), arena.allocator()); |
| 395 | const ExpectedContents = union { u: Value.Payload.U64, i: Value.Payload.I64 }; |
| 396 | var stack align(@alignOf(ExpectedContents)) = |
| 397 | std.heap.stackFallback(@sizeOf(ExpectedContents), arena.allocator()); |
| 402 | 398 | |
| 403 | 399 | const int_info = ty.intInfo(target); |
| 404 | 400 | if (int_info.signedness == .signed) { |
| 405 | 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 | 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 | 408 | .Bits => { |
| 413 | 409 | var bits_pl = Value.Payload.U64{ |
| ... | ... | @@ -415,7 +411,7 @@ pub const Function = struct { |
| 415 | 411 | .data = ty.bitSize(target), |
| 416 | 412 | }; |
| 417 | 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 | 467 | @setCold(true); |
| 472 | 468 | const src = LazySrcLoc.nodeOffset(0); |
| 473 | 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 | 471 | return error.AnalysisFail; |
| 476 | 472 | } |
| 477 | 473 | |
| ... | ... | @@ -559,14 +555,55 @@ pub const DeclGen = struct { |
| 559 | 555 | try dg.renderDeclValue(writer, ptr_ty, ptr_val, decl_index); |
| 560 | 556 | }, |
| 561 | 557 | .field_ptr => { |
| 558 | const ptr_info = ptr_ty.ptrInfo(); |
| 562 | 559 | const field_ptr = ptr_val.castTag(.field_ptr).?.data; |
| 563 | 560 | const container_ty = field_ptr.container_ty; |
| 564 | 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 | 569 | const FieldInfo = struct { name: []const u8, ty: Type }; |
| 566 | 570 | const field_info: FieldInfo = switch (container_ty.zigTypeTag()) { |
| 567 | | .Struct => FieldInfo{ |
| 568 | | .name = container_ty.structFields().keys()[index], |
| 569 | | .ty = container_ty.structFields().values()[index].ty, |
| 571 | .Struct => switch (container_ty.containerLayout()) { |
| 572 | .Auto, .Extern => FieldInfo{ |
| 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 | 608 | .Union => FieldInfo{ |
| 572 | 609 | .name = container_ty.unionFields().keys()[index], |
| ... | ... | @@ -582,20 +619,16 @@ pub const DeclGen = struct { |
| 582 | 619 | }, |
| 583 | 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 | 623 | if (field_info.ty.hasRuntimeBitsIgnoreComptime()) { |
| 592 | 624 | try writer.writeAll("&("); |
| 593 | 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) { |
| 595 | | try writer.print(")->payload.{ }", .{fmtIdent(field_info.name)}); |
| 596 | | } else { |
| 597 | | try writer.print(")->{ }", .{fmtIdent(field_info.name)}); |
| 626 | try writer.writeAll(")->"); |
| 627 | switch (field_ptr.container_ty.tag()) { |
| 628 | .union_tagged, .union_safety_tagged => try writer.writeAll("payload."), |
| 629 | else => {}, |
| 598 | 630 | } |
| 631 | try writer.print("{ }", .{fmtIdent(field_info.name)}); |
| 599 | 632 | } else { |
| 600 | 633 | try dg.renderParentPtr(writer, field_ptr.container_ptr, field_info.ty); |
| 601 | 634 | } |
| ... | ... | @@ -694,25 +727,28 @@ pub const DeclGen = struct { |
| 694 | 727 | try dg.renderValue(writer, Type.bool, val, .Initializer); |
| 695 | 728 | return writer.writeAll(" }"); |
| 696 | 729 | }, |
| 697 | | .Struct => { |
| 698 | | if (location != .Initializer) { |
| 699 | | try writer.writeByte('('); |
| 700 | | try dg.renderTypecast(writer, ty); |
| 701 | | try writer.writeByte(')'); |
| 702 | | } |
| 730 | .Struct => switch (ty.containerLayout()) { |
| 731 | .Auto, .Extern => { |
| 732 | if (location != .Initializer) { |
| 733 | try writer.writeByte('('); |
| 734 | try dg.renderTypecast(writer, ty); |
| 735 | try writer.writeByte(')'); |
| 736 | } |
| 703 | 737 | |
| 704 | | try writer.writeByte('{'); |
| 705 | | var empty = true; |
| 706 | | for (ty.structFields().values()) |field| { |
| 707 | | if (!field.ty.hasRuntimeBits()) continue; |
| 738 | try writer.writeByte('{'); |
| 739 | var empty = true; |
| 740 | for (ty.structFields().values()) |field| { |
| 741 | if (!field.ty.hasRuntimeBits()) continue; |
| 708 | 742 | |
| 709 | | if (!empty) try writer.writeByte(','); |
| 710 | | try dg.renderValue(writer, field.ty, val, .Initializer); |
| 743 | if (!empty) try writer.writeByte(','); |
| 744 | try dg.renderValue(writer, field.ty, val, .Initializer); |
| 711 | 745 | |
| 712 | | empty = false; |
| 713 | | } |
| 714 | | if (empty) try writer.print("{x}", .{try dg.fmtIntLiteral(Type.u8, Value.undef)}); |
| 715 | | return writer.writeByte('}'); |
| 746 | empty = false; |
| 747 | } |
| 748 | if (empty) try writer.print("{x}", .{try dg.fmtIntLiteral(Type.u8, Value.undef)}); |
| 749 | return writer.writeByte('}'); |
| 750 | }, |
| 751 | .Packed => return writer.print("{x}", .{try dg.fmtIntLiteral(ty, Value.undef)}), |
| 716 | 752 | }, |
| 717 | 753 | .Union => { |
| 718 | 754 | if (location != .Initializer) { |
| ... | ... | @@ -898,7 +934,7 @@ pub const DeclGen = struct { |
| 898 | 934 | }, |
| 899 | 935 | else => { |
| 900 | 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 | 938 | defer arena.deinit(); |
| 903 | 939 | const arena_allocator = arena.allocator(); |
| 904 | 940 | |
| ... | ... | @@ -1024,28 +1060,63 @@ pub const DeclGen = struct { |
| 1024 | 1060 | }, |
| 1025 | 1061 | else => unreachable, |
| 1026 | 1062 | }, |
| 1027 | | .Struct => { |
| 1028 | | const field_vals = val.castTag(.aggregate).?.data; |
| 1063 | .Struct => switch (ty.containerLayout()) { |
| 1064 | .Auto, .Extern => { |
| 1065 | const field_vals = val.castTag(.aggregate).?.data; |
| 1029 | 1066 | |
| 1030 | | if (location != .Initializer) { |
| 1031 | | try writer.writeByte('('); |
| 1032 | | try dg.renderTypecast(writer, ty); |
| 1033 | | try writer.writeByte(')'); |
| 1034 | | } |
| 1067 | if (location != .Initializer) { |
| 1068 | try writer.writeByte('('); |
| 1069 | try dg.renderTypecast(writer, ty); |
| 1070 | try writer.writeByte(')'); |
| 1071 | } |
| 1035 | 1072 | |
| 1036 | | try writer.writeByte('{'); |
| 1037 | | var empty = true; |
| 1038 | | for (field_vals) |field_val, field_index| { |
| 1039 | | const field_ty = ty.structFieldType(field_index); |
| 1040 | | if (!field_ty.hasRuntimeBits()) continue; |
| 1073 | try writer.writeByte('{'); |
| 1074 | var empty = true; |
| 1075 | for (field_vals) |field_val, field_index| { |
| 1076 | const field_ty = ty.structFieldType(field_index); |
| 1077 | if (!field_ty.hasRuntimeBits()) continue; |
| 1041 | 1078 | |
| 1042 | | if (!empty) try writer.writeByte(','); |
| 1043 | | try dg.renderValue(writer, field_ty, field_val, .Initializer); |
| 1079 | if (!empty) try writer.writeByte(','); |
| 1080 | try dg.renderValue(writer, field_ty, field_val, .Initializer); |
| 1044 | 1081 | |
| 1045 | | empty = false; |
| 1046 | | } |
| 1047 | | if (empty) try writer.print("{}", .{try dg.fmtIntLiteral(Type.u8, Value.zero)}); |
| 1048 | | try writer.writeByte('}'); |
| 1082 | empty = false; |
| 1083 | } |
| 1084 | if (empty) try writer.print("{}", .{try dg.fmtIntLiteral(Type.u8, Value.zero)}); |
| 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 | 1121 | .Union => { |
| 1051 | 1122 | const union_obj = val.castTag(.@"union").?.data; |
| ... | ... | @@ -1103,11 +1174,12 @@ pub const DeclGen = struct { |
| 1103 | 1174 | if (fn_info.cc == .Naked) try w.writeAll("zig_naked "); |
| 1104 | 1175 | if (dg.decl.val.castTag(.function)) |func_payload| |
| 1105 | 1176 | if (func_payload.data.is_cold) try w.writeAll("zig_cold "); |
| 1106 | | const ret_ty = fn_info.return_type; |
| 1107 | | try dg.renderType(w, if (ret_ty.tag() == .noreturn or ret_ty.hasRuntimeBitsIgnoreComptime()) |
| 1108 | | ret_ty |
| 1109 | | else |
| 1110 | | Type.void, kind); |
| 1177 | |
| 1178 | const target = dg.module.getTarget(); |
| 1179 | var ret_buf: LowerFnRetTyBuffer = undefined; |
| 1180 | const ret_ty = lowerFnRetTy(fn_info.return_type, &ret_buf, target); |
| 1181 | |
| 1182 | try dg.renderType(w, ret_ty, kind); |
| 1111 | 1183 | try w.writeByte(' '); |
| 1112 | 1184 | try dg.renderDeclName(w, dg.decl_index); |
| 1113 | 1185 | try w.writeByte('('); |
| ... | ... | @@ -1117,7 +1189,7 @@ pub const DeclGen = struct { |
| 1117 | 1189 | if (!param_type.hasRuntimeBitsIgnoreComptime()) continue; |
| 1118 | 1190 | if (index > 0) try w.writeAll(", "); |
| 1119 | 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 | 1193 | index += 1; |
| 1122 | 1194 | } |
| 1123 | 1195 | |
| ... | ... | @@ -1137,10 +1209,13 @@ pub const DeclGen = struct { |
| 1137 | 1209 | |
| 1138 | 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 | 1216 | try bw.writeAll("typedef "); |
| 1141 | | try dg.renderType(bw, fn_info.return_type, .Forward); |
| 1217 | try dg.renderType(bw, ret_ty, .Forward); |
| 1142 | 1218 | try bw.writeAll(" (*"); |
| 1143 | | |
| 1144 | 1219 | const name_begin = buffer.items.len; |
| 1145 | 1220 | try bw.print("zig_F_{}", .{typeToCIdentifier(t, dg.module)}); |
| 1146 | 1221 | const name_end = buffer.items.len; |
| ... | ... | @@ -1315,8 +1390,12 @@ pub const DeclGen = struct { |
| 1315 | 1390 | const val = fields.values[i]; |
| 1316 | 1391 | if (val.tag() != .unreachable_value) continue; |
| 1317 | 1392 | |
| 1318 | | const field_name = try std.fmt.allocPrint(dg.typedefs.allocator, "field_{d}", .{i}); |
| 1319 | | defer dg.typedefs.allocator.free(field_name); |
| 1393 | var field_name_buf: []const u8 = &.{}; |
| 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 | 1400 | try buffer.append(' '); |
| 1322 | 1401 | try dg.renderTypeAndName(buffer.writer(), field_ty, .{ .identifier = field_name }, .Mut, 0, .Complete); |
| ... | ... | @@ -1463,7 +1542,10 @@ pub const DeclGen = struct { |
| 1463 | 1542 | try bw.print(" zig_A_{}_{d}", .{ typeToCIdentifier(info.elem_type, dg.module), info.len }); |
| 1464 | 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 | 1550 | const rendered = buffer.toOwnedSlice(); |
| 1469 | 1551 | errdefer dg.typedefs.allocator.free(rendered); |
| ... | ... | @@ -1487,7 +1569,7 @@ pub const DeclGen = struct { |
| 1487 | 1569 | try dg.renderTypeAndName(bw, child_type, .{ .identifier = "payload" }, .Mut, 0, .Complete); |
| 1488 | 1570 | try bw.writeAll(";\n "); |
| 1489 | 1571 | try dg.renderTypeAndName(bw, Type.bool, .{ .identifier = "is_null" }, .Mut, 0, .Complete); |
| 1490 | | try bw.writeAll("; } "); |
| 1572 | try bw.writeAll(";\n} "); |
| 1491 | 1573 | const name_begin = buffer.items.len; |
| 1492 | 1574 | try bw.print("zig_Q_{}", .{typeToCIdentifier(child_type, dg.module)}); |
| 1493 | 1575 | const name_end = buffer.items.len; |
| ... | ... | @@ -1566,18 +1648,29 @@ pub const DeclGen = struct { |
| 1566 | 1648 | try w.writeAll("zig_"); |
| 1567 | 1649 | try t.print(w, dg.module); |
| 1568 | 1650 | } else { |
| 1569 | | const info = t.intInfo(target); |
| 1570 | | const c_bits = toCIntBits(info.bits) orelse |
| 1571 | | return dg.fail("TODO: C backend: implement integer types larger than 128 bits", .{}); |
| 1572 | | try w.print("zig_{c}{d}", .{ signAbbrev(info.signedness), c_bits }); |
| 1651 | const int_info = t.intInfo(target); |
| 1652 | if (toCIntBits(int_info.bits)) |c_bits| |
| 1653 | return w.print("zig_{c}{d}", .{ signAbbrev(int_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 | 1668 | .Pointer => { |
| 1576 | | const child_ty = t.childType(); |
| 1577 | | if (t.isSlice()) { |
| 1669 | const ptr_info = t.ptrInfo().data; |
| 1670 | if (ptr_info.size == .Slice) { |
| 1578 | 1671 | var slice_pl = Type.Payload.ElemType{ |
| 1579 | 1672 | .base = .{ .tag = if (t.ptrIsMutable()) .mut_slice else .const_slice }, |
| 1580 | | .data = child_ty, |
| 1673 | .data = ptr_info.pointee_type, |
| 1581 | 1674 | }; |
| 1582 | 1675 | const slice_ty = Type.initPayload(&slice_pl.base); |
| 1583 | 1676 | |
| ... | ... | @@ -1587,14 +1680,22 @@ pub const DeclGen = struct { |
| 1587 | 1680 | return w.writeAll(name); |
| 1588 | 1681 | } |
| 1589 | 1682 | |
| 1590 | | if (child_ty.zigTypeTag() == .Fn) { |
| 1591 | | const name = dg.getTypedefName(child_ty) orelse |
| 1592 | | try dg.renderPtrToFnTypedef(child_ty); |
| 1683 | if (ptr_info.pointee_type.zigTypeTag() == .Fn) { |
| 1684 | const name = dg.getTypedefName(ptr_info.pointee_type) orelse |
| 1685 | try dg.renderPtrToFnTypedef(ptr_info.pointee_type); |
| 1593 | 1686 | |
| 1594 | 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 | 1699 | (dg.decl.val.tag() == .extern_fn or |
| 1599 | 1700 | std.mem.eql(u8, std.mem.span(dg.decl.name), "main"))) |
| 1600 | 1701 | { |
| ... | ... | @@ -1603,9 +1704,9 @@ pub const DeclGen = struct { |
| 1603 | 1704 | // u8 and i8 produce unsigned char and signed char respectively, |
| 1604 | 1705 | // which in C are (not very usefully) different than char. |
| 1605 | 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 | 1708 | .anyopaque => Type.void, |
| 1608 | | else => child_ty, |
| 1709 | else => ptr_info.pointee_type, |
| 1609 | 1710 | }, .Forward); |
| 1610 | 1711 | if (t.isConstPtr()) try w.writeAll(" const"); |
| 1611 | 1712 | if (t.isVolatilePtr()) try w.writeAll(" volatile"); |
| ... | ... | @@ -1654,7 +1755,9 @@ pub const DeclGen = struct { |
| 1654 | 1755 | |
| 1655 | 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 | 1761 | const name = dg.getTypedefName(t) orelse switch (tag) { |
| 1659 | 1762 | .Struct => if (t.isTupleOrAnonStruct()) |
| 1660 | 1763 | try dg.renderTupleTypedef(t) |
| ... | ... | @@ -1664,7 +1767,7 @@ pub const DeclGen = struct { |
| 1664 | 1767 | else => unreachable, |
| 1665 | 1768 | }; |
| 1666 | 1769 | |
| 1667 | | return w.writeAll(name); |
| 1770 | try w.writeAll(name); |
| 1668 | 1771 | } else { |
| 1669 | 1772 | var ptr_pl = Type.Payload.ElemType{ |
| 1670 | 1773 | .base = .{ .tag = .single_const_pointer }, |
| ... | ... | @@ -1675,7 +1778,7 @@ pub const DeclGen = struct { |
| 1675 | 1778 | const name = dg.getTypedefName(ptr_ty) orelse |
| 1676 | 1779 | try dg.renderFwdTypedef(ptr_ty); |
| 1677 | 1780 | |
| 1678 | | return w.writeAll(name); |
| 1781 | try w.writeAll(name); |
| 1679 | 1782 | }, |
| 1680 | 1783 | .Enum => { |
| 1681 | 1784 | // For enums, we simply use the integer tag type. |
| ... | ... | @@ -1751,24 +1854,32 @@ pub const DeclGen = struct { |
| 1751 | 1854 | ) error{ OutOfMemory, AnalysisFail }!void { |
| 1752 | 1855 | var suffix = std.ArrayList(u8).init(dg.gpa); |
| 1753 | 1856 | defer suffix.deinit(); |
| 1857 | const suffix_writer = suffix.writer(); |
| 1754 | 1858 | |
| 1755 | 1859 | // Any top-level array types are rendered here as a suffix, which |
| 1756 | 1860 | // avoids creating typedefs for every array type |
| 1861 | const target = dg.module.getTarget(); |
| 1757 | 1862 | var render_ty = ty; |
| 1758 | | while (render_ty.zigTypeTag() == .Array) { |
| 1759 | | const sentinel_bit = @boolToInt(render_ty.sentinel() != null); |
| 1760 | | const c_len = render_ty.arrayLen() + sentinel_bit; |
| 1761 | | try suffix.writer().print("[{d}]", .{c_len}); |
| 1762 | | render_ty = render_ty.elemType(); |
| 1863 | var depth: u32 = 0; |
| 1864 | while (loweredArrayInfo(render_ty, target)) |array_info| { |
| 1865 | const c_len = array_info.len + @boolToInt(array_info.sentinel != null); |
| 1866 | var c_len_pl: Value.Payload.U64 = .{ .base = .{ .tag = .int_u64 }, .data = c_len }; |
| 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 | 1877 | try w.print("zig_align({}) ", .{alignment}); |
| 1767 | 1878 | } |
| 1768 | 1879 | try dg.renderType(w, render_ty, kind); |
| 1769 | 1880 | |
| 1770 | 1881 | const const_prefix = switch (mutability) { |
| 1771 | | .Const => "const ", |
| 1882 | .Const, .ConstArgument => "const ", |
| 1772 | 1883 | .Mut => "", |
| 1773 | 1884 | }; |
| 1774 | 1885 | try w.print(" {s}", .{const_prefix}); |
| ... | ... | @@ -1935,7 +2046,7 @@ pub const DeclGen = struct { |
| 1935 | 2046 | } else if (decl.isExtern()) { |
| 1936 | 2047 | return writer.writeAll(mem.sliceTo(decl.name, 0)); |
| 1937 | 2048 | } else { |
| 1938 | | const gpa = dg.module.gpa; |
| 2049 | const gpa = dg.gpa; |
| 1939 | 2050 | const name = try decl.getFullyQualifiedName(dg.module); |
| 1940 | 2051 | defer gpa.free(name); |
| 1941 | 2052 | return writer.print("{ }", .{fmtIdent(name)}); |
| ... | ... | @@ -2298,8 +2409,8 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO |
| 2298 | 2409 | .trunc => try airTrunc(f, inst), |
| 2299 | 2410 | .bool_to_int => try airBoolToInt(f, inst), |
| 2300 | 2411 | .load => try airLoad(f, inst), |
| 2301 | | .ret => try airRet(f, inst), |
| 2302 | | .ret_load => try airRetLoad(f, inst), |
| 2412 | .ret => try airRet(f, inst, false), |
| 2413 | .ret_load => try airRet(f, inst, true), |
| 2303 | 2414 | .store => try airStore(f, inst), |
| 2304 | 2415 | .loop => try airLoop(f, inst), |
| 2305 | 2416 | .cond_br => try airCondBr(f, inst), |
| ... | ... | @@ -2588,14 +2699,15 @@ fn airArg(f: *Function) CValue { |
| 2588 | 2699 | |
| 2589 | 2700 | fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue { |
| 2590 | 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 | 2704 | const inst_ty = f.air.typeOfIndex(inst); |
| 2594 | 2705 | if (!inst_ty.hasRuntimeBitsIgnoreComptime() or |
| 2595 | | !is_volatile and f.liveness.isUnused(inst)) |
| 2706 | !ptr_info.@"volatile" and f.liveness.isUnused(inst)) |
| 2596 | 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 | 2711 | const operand = try f.resolveInst(ty_op.operand); |
| 2600 | 2712 | const writer = f.object.writer(); |
| 2601 | 2713 | |
| ... | ... | @@ -2612,26 +2724,88 @@ fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue { |
| 2612 | 2724 | try f.writeCValue(writer, operand, .FunctionArgument); |
| 2613 | 2725 | try writer.writeAll(", sizeof("); |
| 2614 | 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 | 2766 | } else { |
| 2617 | 2767 | try writer.writeAll(" = "); |
| 2618 | 2768 | try f.writeCValueDeref(writer, operand); |
| 2619 | | try writer.writeAll(";\n"); |
| 2620 | 2769 | } |
| 2770 | try writer.writeAll(";\n"); |
| 2621 | 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 | 2775 | const un_op = f.air.instructions.items(.data)[inst].un_op; |
| 2626 | 2776 | const writer = f.object.writer(); |
| 2627 | | const ret_ty = f.air.typeOf(un_op); |
| 2628 | | if (ret_ty.isFnOrHasRuntimeBitsIgnoreComptime()) { |
| 2777 | const target = f.object.dg.module.getTarget(); |
| 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 | 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 | 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 | 2808 | try writer.writeAll(";\n"); |
| 2633 | | } else if (ret_ty.isError()) { |
| 2634 | | try writer.writeAll("return 0;"); |
| 2635 | 2809 | } else if (f.object.dg.decl.ty.fnCallingConvention() != .Naked) { |
| 2636 | 2810 | // Not even allowed to return void in a naked function. |
| 2637 | 2811 | try writer.writeAll("return;\n"); |
| ... | ... | @@ -2639,24 +2813,6 @@ fn airRet(f: *Function, inst: Air.Inst.Index) !CValue { |
| 2639 | 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 | 2816 | fn airIntCast(f: *Function, inst: Air.Inst.Index) !CValue { |
| 2661 | 2817 | if (f.liveness.isUnused(inst)) |
| 2662 | 2818 | return CValue.none; |
| ... | ... | @@ -2696,12 +2852,12 @@ fn airTrunc(f: *Function, inst: Air.Inst.Index) !CValue { |
| 2696 | 2852 | try writer.writeAll(";\n"); |
| 2697 | 2853 | } else switch (dest_int_info.signedness) { |
| 2698 | 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 | 2856 | defer arena.deinit(); |
| 2701 | 2857 | |
| 2702 | | const expected_contents = union { u: Value.Payload.U64, i: Value.Payload.I64 }; |
| 2703 | | var stack align(@alignOf(expected_contents)) = |
| 2704 | | std.heap.stackFallback(@sizeOf(expected_contents), arena.allocator()); |
| 2858 | const ExpectedContents = union { u: Value.Payload.U64, i: Value.Payload.I64 }; |
| 2859 | var stack align(@alignOf(ExpectedContents)) = |
| 2860 | std.heap.stackFallback(@sizeOf(ExpectedContents), arena.allocator()); |
| 2705 | 2861 | |
| 2706 | 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 | 2912 | fn airStore(f: *Function, inst: Air.Inst.Index) !CValue { |
| 2757 | 2913 | // *a = b; |
| 2758 | 2914 | const bin_op = f.air.instructions.items(.data)[inst].bin_op; |
| 2759 | | const lhs_child_ty = f.air.typeOf(bin_op.lhs).childType(); |
| 2760 | | if (!lhs_child_ty.hasRuntimeBitsIgnoreComptime()) return CValue.none; |
| 2915 | const ptr_info = f.air.typeOf(bin_op.lhs).ptrInfo().data; |
| 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 | 2920 | const src_val = try f.resolveInst(bin_op.rhs); |
| 2764 | 2921 | |
| 2765 | 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 | 2924 | const src_val_is_undefined = |
| 2768 | 2925 | if (f.air.value(bin_op.rhs)) |v| v.isUndefDeep() else false; |
| 2769 | 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 | 2930 | const writer = f.object.writer(); |
| 2773 | | if (lhs_child_ty.zigTypeTag() == .Array) { |
| 2931 | if (lowersToArray(ptr_info.pointee_type, target)) { |
| 2774 | 2932 | // For this memcpy to safely work we need the rhs to have the same |
| 2775 | 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); |
| 2777 | | assert(rhs_type.eql(lhs_child_ty, f.object.dg.module)); |
| 2934 | assert(src_ty.eql(ptr_info.pointee_type, f.object.dg.module)); |
| 2778 | 2935 | |
| 2779 | 2936 | // If the source is a constant, writeCValue will emit a brace initialization |
| 2780 | 2937 | // so work around this by initializing into new local. |
| 2781 | 2938 | // TODO this should be done by manually initializing elements of the dest array |
| 2782 | 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 | 2941 | try writer.writeAll(" = "); |
| 2785 | 2942 | try f.writeCValue(writer, src_val, .Initializer); |
| 2786 | 2943 | try writer.writeAll(";\n"); |
| ... | ... | @@ -2789,18 +2946,69 @@ fn airStore(f: *Function, inst: Air.Inst.Index) !CValue { |
| 2789 | 2946 | } else src_val; |
| 2790 | 2947 | |
| 2791 | 2948 | try writer.writeAll("memcpy("); |
| 2792 | | try f.writeCValue(writer, dest_ptr, .FunctionArgument); |
| 2949 | try f.writeCValue(writer, ptr_val, .FunctionArgument); |
| 2793 | 2950 | try writer.writeAll(", "); |
| 2794 | 2951 | try f.writeCValue(writer, array_src, .FunctionArgument); |
| 2795 | 2952 | try writer.writeAll(", sizeof("); |
| 2796 | | try f.renderTypecast(writer, lhs_child_ty); |
| 2797 | | try writer.writeAll("));\n"); |
| 2953 | try f.renderTypecast(writer, src_ty); |
| 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 | 3006 | } else { |
| 2799 | | try f.writeCValueDeref(writer, dest_ptr); |
| 3007 | try f.writeCValueDeref(writer, ptr_val); |
| 2800 | 3008 | try writer.writeAll(" = "); |
| 2801 | 3009 | try f.writeCValue(writer, src_val, .Other); |
| 2802 | | try writer.writeAll(";\n"); |
| 2803 | 3010 | } |
| 3011 | try writer.writeAll(";\n"); |
| 2804 | 3012 | return CValue.none; |
| 2805 | 3013 | } |
| 2806 | 3014 | |
| ... | ... | @@ -2959,7 +3167,9 @@ fn airEquality( |
| 2959 | 3167 | } |
| 2960 | 3168 | |
| 2961 | 3169 | try f.writeCValue(writer, lhs, .Other); |
| 3170 | try writer.writeByte(' '); |
| 2962 | 3171 | try writer.writeAll(eq_op_str); |
| 3172 | try writer.writeByte(' '); |
| 2963 | 3173 | try f.writeCValue(writer, rhs, .Other); |
| 2964 | 3174 | try writer.writeAll(";\n"); |
| 2965 | 3175 | |
| ... | ... | @@ -3079,17 +3289,22 @@ fn airCall( |
| 3079 | 3289 | }; |
| 3080 | 3290 | const writer = f.object.writer(); |
| 3081 | 3291 | |
| 3082 | | const result_local: CValue = r: { |
| 3083 | | if (!loweredFnRetTyHasBits(fn_ty)) { |
| 3084 | | break :r .none; |
| 3085 | | } else if (f.liveness.isUnused(inst)) { |
| 3086 | | try writer.print("(void)", .{}); |
| 3087 | | break :r .none; |
| 3088 | | } else { |
| 3089 | | const local = try f.allocLocal(fn_ty.fnReturnType(), .Const); |
| 3090 | | try writer.writeAll(" = "); |
| 3091 | | break :r local; |
| 3092 | | } |
| 3292 | const target = f.object.dg.module.getTarget(); |
| 3293 | const ret_ty = fn_ty.fnReturnType(); |
| 3294 | var lowered_ret_buf: LowerFnRetTyBuffer = undefined; |
| 3295 | const lowered_ret_ty = lowerFnRetTy(ret_ty, &lowered_ret_buf, target); |
| 3296 | |
| 3297 | const result_local: CValue = if (!lowered_ret_ty.hasRuntimeBitsIgnoreComptime()) |
| 3298 | .none |
| 3299 | else if (f.liveness.isUnused(inst)) r: { |
| 3300 | try writer.writeByte('('); |
| 3301 | try f.renderTypecast(writer, Type.void); |
| 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 | 3310 | var is_extern = false; |
| ... | ... | @@ -3138,7 +3353,19 @@ fn airCall( |
| 3138 | 3353 | args_written += 1; |
| 3139 | 3354 | } |
| 3140 | 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 | 3371 | fn airDbgStmt(f: *Function, inst: Air.Inst.Index) !CValue { |
| ... | ... | @@ -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 | 3495 | const local = try f.allocLocal(result_ty, if (is_array) .Mut else .Const); |
| 3268 | 3496 | if (is_array) { |
| 3269 | 3497 | try writer.writeAll(";\n"); |
| ... | ... | @@ -3814,51 +4042,74 @@ fn airFieldParentPtr(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3814 | 4042 | |
| 3815 | 4043 | fn structFieldPtr(f: *Function, inst: Air.Inst.Index, struct_ptr_ty: Type, struct_ptr: CValue, index: u32) !CValue { |
| 3816 | 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 | 4047 | const struct_ty = struct_ptr_ty.elemType(); |
| 3818 | | var field_name: []const u8 = undefined; |
| 3819 | | var field_val_ty: Type = undefined; |
| 4048 | const field_ty = struct_ty.structFieldType(index); |
| 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 | 4064 | defer f.object.dg.gpa.free(field_name_buf); |
| 3823 | | switch (struct_ty.tag()) { |
| 3824 | | .@"struct" => { |
| 3825 | | const fields = struct_ty.structFields(); |
| 3826 | | field_name = fields.keys()[index]; |
| 3827 | | field_val_ty = fields.values()[index].ty; |
| 3828 | | }, |
| 3829 | | .@"union", .union_safety_tagged, .union_tagged => { |
| 3830 | | const fields = struct_ty.unionFields(); |
| 3831 | | field_name = fields.keys()[index]; |
| 3832 | | field_val_ty = fields.values()[index].ty; |
| 4065 | const field_name: ?[]const u8 = switch (struct_ty.tag()) { |
| 4066 | .@"struct" => switch (struct_ty.containerLayout()) { |
| 4067 | .Auto, .Extern => struct_ty.structFieldName(index), |
| 4068 | .Packed => if (field_ptr_info.data.host_size == 0) { |
| 4069 | const target = f.object.dg.module.getTarget(); |
| 4070 | |
| 4071 | const byte_offset = struct_ty.packedStructFieldByteOffset(index, target); |
| 4072 | var byte_offset_pl = Value.Payload.U64{ |
| 4073 | .base = .{ .tag = .int_u64 }, |
| 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 | 4092 | const tuple = struct_ty.tupleFields(); |
| 3836 | 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 | 4097 | field_name_buf = try std.fmt.allocPrint(f.object.dg.gpa, "field_{d}", .{index}); |
| 3839 | | field_name = field_name_buf; |
| 3840 | | field_val_ty = tuple.types[index]; |
| 4098 | break :field_name field_name_buf; |
| 3841 | 4099 | }, |
| 3842 | 4100 | else => unreachable, |
| 3843 | | } |
| 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); |
| 4101 | }; |
| 3848 | 4102 | |
| 3849 | | const inst_ty = f.air.typeOfIndex(inst); |
| 3850 | | const local = try f.allocLocal(inst_ty, .Const); |
| 3851 | | if (field_val_ty.hasRuntimeBitsIgnoreComptime()) { |
| 3852 | | try writer.writeAll(" = &"); |
| 3853 | | try f.writeCValueDeref(writer, struct_ptr); |
| 3854 | | try writer.print(".{s}{ };\n", .{ payload, fmtIdent(field_name) }); |
| 3855 | | } else { |
| 3856 | | try writer.writeAll(" = ("); |
| 3857 | | try f.renderTypecast(writer, inst_ty); |
| 3858 | | try writer.writeByte(')'); |
| 3859 | | try f.writeCValue(writer, struct_ptr, .Other); |
| 3860 | | try writer.writeAll(";\n"); |
| 3861 | | } |
| 4103 | if (field_ty.hasRuntimeBitsIgnoreComptime()) { |
| 4104 | try writer.writeByte('&'); |
| 4105 | if (extra_name orelse field_name) |name| |
| 4106 | try f.writeCValueDerefMember(writer, struct_ptr, .{ .identifier = name }) |
| 4107 | else |
| 4108 | try f.writeCValueDeref(writer, struct_ptr); |
| 4109 | if (extra_name) |_| if (field_name) |name| |
| 4110 | try writer.print(".{ }", .{fmtIdent(name)}); |
| 4111 | } else try f.writeCValue(writer, struct_ptr, .Other); |
| 4112 | try writer.writeAll(";\n"); |
| 3862 | 4113 | return local; |
| 3863 | 4114 | } |
| 3864 | 4115 | |
| ... | ... | @@ -3868,18 +4119,84 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3868 | 4119 | |
| 3869 | 4120 | const ty_pl = f.air.instructions.items(.data)[inst].ty_pl; |
| 3870 | 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 | 4124 | const struct_byval = try f.resolveInst(extra.struct_operand); |
| 3873 | 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 | 4131 | var field_name_buf: []const u8 = ""; |
| 3875 | 4132 | defer f.object.dg.gpa.free(field_name_buf); |
| 3876 | 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 | 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 | 4195 | const tuple = struct_ty.tupleFields(); |
| 3881 | 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 | 4200 | field_name_buf = try std.fmt.allocPrint(f.object.dg.gpa, "field_{d}", .{extra.field_index}); |
| 3884 | 4201 | break :blk field_name_buf; |
| 3885 | 4202 | }, |
| ... | ... | @@ -3887,13 +4204,8 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3887 | 4204 | }; |
| 3888 | 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. |
| 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; |
| 4207 | const is_array = lowersToArray(inst_ty, target); |
| 3895 | 4208 | const local = try f.allocLocal(inst_ty, if (is_array) .Mut else .Const); |
| 3896 | | |
| 3897 | 4209 | if (is_array) { |
| 3898 | 4210 | try writer.writeAll(";\n"); |
| 3899 | 4211 | try writer.writeAll("memcpy("); |
| ... | ... | @@ -4067,7 +4379,8 @@ fn airWrapErrUnionPay(f: *Function, inst: Air.Inst.Index) !CValue { |
| 4067 | 4379 | const inst_ty = f.air.typeOfIndex(inst); |
| 4068 | 4380 | const payload_ty = inst_ty.errorUnionPayload(); |
| 4069 | 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 | 4384 | const local = try f.allocLocal(inst_ty, if (is_array) .Mut else .Const); |
| 4072 | 4385 | try writer.writeAll(" = { .payload = "); |
| 4073 | 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 | 4454 | } else { |
| 4142 | 4455 | try writer.writeAll("&("); |
| 4143 | 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 | 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 | 4884 | const ty_pl = f.air.instructions.items(.data)[inst].ty_pl; |
| 4572 | 4885 | const len = @intCast(usize, inst_ty.arrayLen()); |
| 4573 | 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 | 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 | 4890 | } else .Const; |
| 4577 | 4891 | |
| 4578 | 4892 | const writer = f.object.writer(); |
| 4579 | 4893 | const local = try f.allocLocal(inst_ty, mutability); |
| 4580 | | try writer.writeAll(" = {"); |
| 4894 | try writer.writeAll(" = "); |
| 4581 | 4895 | switch (inst_ty.zigTypeTag()) { |
| 4582 | 4896 | .Array => { |
| 4583 | 4897 | const elem_ty = inst_ty.childType(); |
| 4898 | try writer.writeByte('{'); |
| 4584 | 4899 | var empty = true; |
| 4585 | 4900 | for (elements) |element| { |
| 4586 | 4901 | if (!empty) try writer.writeAll(", "); |
| ... | ... | @@ -4595,49 +4910,99 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue { |
| 4595 | 4910 | if (empty) try writer.print("{}", .{try f.fmtIntLiteral(Type.u8, Value.zero)}); |
| 4596 | 4911 | try writer.writeAll("};\n"); |
| 4597 | 4912 | }, |
| 4598 | | .Struct => { |
| 4599 | | var empty = true; |
| 4600 | | for (elements) |element, index| { |
| 4601 | | if (inst_ty.structFieldValueComptime(index)) |_| continue; |
| 4913 | .Struct => switch (inst_ty.containerLayout()) { |
| 4914 | .Auto, .Extern => { |
| 4915 | try writer.writeByte('{'); |
| 4916 | var empty = true; |
| 4917 | for (elements) |element, index| { |
| 4918 | if (inst_ty.structFieldValueComptime(index)) |_| continue; |
| 4602 | 4919 | |
| 4603 | | if (!empty) try writer.writeAll(", "); |
| 4604 | | if (!inst_ty.isTupleOrAnonStruct()) { |
| 4605 | | try writer.print(".{ } = ", .{fmtIdent(inst_ty.structFieldName(index))}); |
| 4920 | if (!empty) try writer.writeAll(", "); |
| 4921 | if (!inst_ty.isTupleOrAnonStruct()) { |
| 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); |
| 4609 | | try f.writeCValue(writer, switch (element_ty.zigTypeTag()) { |
| 4610 | | .Array => CValue{ .undef = element_ty }, |
| 4611 | | else => try f.resolveInst(element), |
| 4612 | | }, .Initializer); |
| 4613 | | empty = false; |
| 4614 | | } |
| 4615 | | if (empty) try writer.print("{}", .{try f.fmtIntLiteral(Type.u8, Value.zero)}); |
| 4616 | | try writer.writeAll("};\n"); |
| 4961 | var bit_offset_ty_pl = Type.Payload.Bits{ |
| 4962 | .base = .{ .tag = .int_unsigned }, |
| 4963 | .data = Type.smallestUnsignedBits(int_info.bits - 1), |
| 4964 | }; |
| 4965 | const bit_offset_ty = Type.initPayload(&bit_offset_ty_pl.base); |
| 4617 | 4966 | |
| 4618 | | for (elements) |element, index| { |
| 4619 | | if (inst_ty.structFieldValueComptime(index)) |_| continue; |
| 4967 | var bit_offset_val_pl: Value.Payload.U64 = .{ .base = .{ .tag = .int_u64 }, .data = 0 }; |
| 4968 | const bit_offset_val = Value.initPayload(&bit_offset_val_pl.base); |
| 4620 | 4969 | |
| 4621 | | const element_ty = f.air.typeOf(element); |
| 4622 | | if (element_ty.zigTypeTag() != .Array) continue; |
| 4970 | var empty = true; |
| 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; |
| 4625 | | defer if (field_name_storage) |storage| f.object.dg.gpa.free(storage); |
| 4626 | | const field_name = if (inst_ty.isTupleOrAnonStruct()) field_name: { |
| 4627 | | const name = try std.fmt.allocPrint(f.object.dg.gpa, "field_{d}", .{index}); |
| 4628 | | field_name_storage = name; |
| 4629 | | break :field_name name; |
| 4630 | | } else inst_ty.structFieldName(index); |
| 4975 | if (!empty) { |
| 4976 | try writer.writeAll("zig_or_"); |
| 4977 | try f.renderTypeForBuiltinFnName(writer, inst_ty); |
| 4978 | try writer.writeByte('('); |
| 4979 | } |
| 4980 | empty = false; |
| 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 | 5004 | try writer.writeAll(";\n"); |
| 4633 | | try writer.writeAll("memcpy("); |
| 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 | | } |
| 5005 | }, |
| 4641 | 5006 | }, |
| 4642 | 5007 | .Vector => return f.fail("TODO: C backend: implement airAggregateInit for vectors", .{}), |
| 4643 | 5008 | else => unreachable, |
| ... | ... | @@ -4947,7 +5312,7 @@ fn formatIntLiteral( |
| 4947 | 5312 | const int_info = data.ty.intInfo(target); |
| 4948 | 5313 | |
| 4949 | 5314 | const Limb = std.math.big.Limb; |
| 4950 | | const expected_contents = struct { |
| 5315 | const ExpectedContents = struct { |
| 4951 | 5316 | const base = 10; |
| 4952 | 5317 | const limbs_count_128 = BigInt.calcTwosCompLimbCount(128); |
| 4953 | 5318 | const expected_needed_limbs_count = BigInt.calcToStringLimbsBufferLen(limbs_count_128, base); |
| ... | ... | @@ -4959,8 +5324,8 @@ fn formatIntLiteral( |
| 4959 | 5324 | undef_limbs: [limbs_count_128]Limb, |
| 4960 | 5325 | wrap_limbs: [limbs_count_128]Limb, |
| 4961 | 5326 | }; |
| 4962 | | var stack align(@alignOf(expected_contents)) = |
| 4963 | | std.heap.stackFallback(@sizeOf(expected_contents), data.mod.gpa); |
| 5327 | var stack align(@alignOf(ExpectedContents)) = |
| 5328 | std.heap.stackFallback(@sizeOf(ExpectedContents), data.mod.gpa); |
| 4964 | 5329 | const allocator = stack.get(); |
| 4965 | 5330 | |
| 4966 | 5331 | var undef_limbs: []Limb = &.{}; |
| ... | ... | @@ -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 | 5460 | fn isByRef(ty: Type) bool { |
| 5107 | 5461 | _ = ty; |
| 5108 | 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 | } |