| ... | ... | @@ -34,8 +34,8 @@ pub const CValue = union(enum) { |
| 34 | 34 | /// By-value |
| 35 | 35 | decl: Decl.Index, |
| 36 | 36 | decl_ref: Decl.Index, |
| 37 | | /// An undefined (void *) pointer (cannot be dereferenced) |
| 38 | | undefined_ptr: Type, |
| 37 | /// An undefined value (cannot be dereferenced) |
| 38 | undef: Type, |
| 39 | 39 | /// Render the slice as an identifier (using fmtIdent) |
| 40 | 40 | identifier: []const u8, |
| 41 | 41 | /// Render these bytes literally. |
| ... | ... | @@ -342,8 +342,9 @@ pub const Function = struct { |
| 342 | 342 | const float_bits = float_ty.floatBits(target); |
| 343 | 343 | const is_longdouble = float_bits == CType.longdouble.sizeInBits(target); |
| 344 | 344 | const writer = f.object.writer(); |
| 345 | | if (!is_longdouble and float_bits == 80) { |
| 346 | | try writer.writeAll("__"); |
| 345 | try writer.writeAll("__"); |
| 346 | if (is_longdouble or float_bits != 80) { |
| 347 | try writer.writeAll("builtin_"); |
| 347 | 348 | } |
| 348 | 349 | try writer.writeAll(fn_name); |
| 349 | 350 | if (is_longdouble) { |
| ... | ... | @@ -410,10 +411,17 @@ pub const DeclGen = struct { |
| 410 | 411 | const decl = dg.module.declPtr(decl_index); |
| 411 | 412 | assert(decl.has_tv); |
| 412 | 413 | |
| 414 | // Render an undefined pointer if we have a pointer to a zero-bit or comptime type. |
| 413 | 415 | if (ty.isPtrAtRuntime() and !decl.ty.isFnOrHasRuntimeBits()) { |
| 414 | | return dg.writeCValue(writer, CValue{ .undefined_ptr = ty }); |
| 416 | return dg.writeCValue(writer, CValue{ .undef = ty }); |
| 415 | 417 | } |
| 416 | 418 | |
| 419 | // Chase function values in order to be able to reference the original function. |
| 420 | inline for (.{ .function, .extern_fn }) |tag| |
| 421 | if (decl.val.castTag(tag)) |func| |
| 422 | if (func.data.owner_decl != decl_index) |
| 423 | return dg.renderDeclValue(writer, ty, val, func.data.owner_decl); |
| 424 | |
| 417 | 425 | if (ty.isSlice()) { |
| 418 | 426 | try writer.writeByte('('); |
| 419 | 427 | try dg.renderTypecast(writer, ty); |
| ... | ... | @@ -588,9 +596,9 @@ pub const DeclGen = struct { |
| 588 | 596 | try writer.writeByte('('); |
| 589 | 597 | try dg.renderTypecast(writer, ty); |
| 590 | 598 | try writer.writeAll("){ .payload = "); |
| 591 | | try dg.renderValue(writer, Type.bool, val, location); |
| 592 | | try writer.writeAll(", .is_null = "); |
| 593 | 599 | try dg.renderValue(writer, payload_ty, val, location); |
| 600 | try writer.writeAll(", .is_null = "); |
| 601 | try dg.renderValue(writer, Type.bool, val, location); |
| 594 | 602 | return writer.writeAll(" }"); |
| 595 | 603 | }, |
| 596 | 604 | .Struct => { |
| ... | ... | @@ -635,7 +643,7 @@ pub const DeclGen = struct { |
| 635 | 643 | try writer.writeAll("){ .payload = "); |
| 636 | 644 | try dg.renderValue(writer, ty.errorUnionPayload(), val, location); |
| 637 | 645 | return writer.print(", .error = {x} }}", .{ |
| 638 | | try dg.fmtIntLiteral(ty.errorUnionSet(), Value.undef), |
| 646 | try dg.fmtIntLiteral(ty.errorUnionSet(), val), |
| 639 | 647 | }); |
| 640 | 648 | }, |
| 641 | 649 | .Array => { |
| ... | ... | @@ -844,13 +852,13 @@ pub const DeclGen = struct { |
| 844 | 852 | } |
| 845 | 853 | }, |
| 846 | 854 | .ErrorUnion => { |
| 847 | | const error_type = ty.errorUnionSet(); |
| 848 | | const payload_type = ty.errorUnionPayload(); |
| 855 | const error_ty = ty.errorUnionSet(); |
| 856 | const payload_ty = ty.errorUnionPayload(); |
| 849 | 857 | |
| 850 | | if (!payload_type.hasRuntimeBits()) { |
| 858 | if (!payload_ty.hasRuntimeBits()) { |
| 851 | 859 | // We use the error type directly as the type. |
| 852 | 860 | const err_val = if (val.errorUnionIsPayload()) Value.initTag(.zero) else val; |
| 853 | | return dg.renderValue(writer, error_type, err_val, location); |
| 861 | return dg.renderValue(writer, error_ty, err_val, location); |
| 854 | 862 | } |
| 855 | 863 | |
| 856 | 864 | try writer.writeByte('('); |
| ... | ... | @@ -859,11 +867,15 @@ pub const DeclGen = struct { |
| 859 | 867 | if (val.castTag(.eu_payload)) |pl| { |
| 860 | 868 | const payload_val = pl.data; |
| 861 | 869 | try writer.writeAll(" .payload = "); |
| 862 | | try dg.renderValue(writer, payload_type, payload_val, location); |
| 863 | | try writer.writeAll(", .error = 0 }"); |
| 870 | try dg.renderValue(writer, payload_ty, payload_val, location); |
| 871 | try writer.print(", .error = {} }}", .{ |
| 872 | try dg.fmtIntLiteral(error_ty, Value.zero), |
| 873 | }); |
| 864 | 874 | } else { |
| 865 | | try writer.writeAll(" .error = "); |
| 866 | | try dg.renderValue(writer, error_type, val, location); |
| 875 | try writer.writeAll(" .payload = "); |
| 876 | try dg.renderValue(writer, payload_ty, Value.undef, location); |
| 877 | try writer.writeAll(", .error = "); |
| 878 | try dg.renderValue(writer, error_ty, val, location); |
| 867 | 879 | try writer.writeAll(" }"); |
| 868 | 880 | } |
| 869 | 881 | }, |
| ... | ... | @@ -987,13 +999,16 @@ pub const DeclGen = struct { |
| 987 | 999 | if (!is_global) { |
| 988 | 1000 | try w.writeAll("static "); |
| 989 | 1001 | } |
| 1002 | const fn_info = dg.decl.ty.fnInfo(); |
| 1003 | if (fn_info.cc == .Naked) { |
| 1004 | try w.writeAll("ZIG_NAKED "); |
| 1005 | } |
| 990 | 1006 | if (dg.decl.val.castTag(.function)) |func_payload| { |
| 991 | 1007 | const func: *Module.Fn = func_payload.data; |
| 992 | 1008 | if (func.is_cold) { |
| 993 | 1009 | try w.writeAll("ZIG_COLD "); |
| 994 | 1010 | } |
| 995 | 1011 | } |
| 996 | | const fn_info = dg.decl.ty.fnInfo(); |
| 997 | 1012 | if (fn_info.return_type.hasRuntimeBits()) { |
| 998 | 1013 | try dg.renderType(w, fn_info.return_type); |
| 999 | 1014 | } else if (fn_info.return_type.isError()) { |
| ... | ... | @@ -1007,21 +1022,21 @@ pub const DeclGen = struct { |
| 1007 | 1022 | try dg.renderDeclName(w, dg.decl_index); |
| 1008 | 1023 | try w.writeByte('('); |
| 1009 | 1024 | |
| 1010 | | var params_written: usize = 0; |
| 1011 | | for (fn_info.param_types) |param_type, index| { |
| 1025 | var index: usize = 0; |
| 1026 | for (fn_info.param_types) |param_type| { |
| 1012 | 1027 | if (!param_type.hasRuntimeBitsIgnoreComptime()) continue; |
| 1013 | | if (params_written > 0) { |
| 1028 | if (index > 0) { |
| 1014 | 1029 | try w.writeAll(", "); |
| 1015 | 1030 | } |
| 1016 | 1031 | const name = CValue{ .arg = index }; |
| 1017 | 1032 | try dg.renderTypeAndName(w, param_type, name, .Mut, 0); |
| 1018 | | params_written += 1; |
| 1033 | index += 1; |
| 1019 | 1034 | } |
| 1020 | 1035 | |
| 1021 | 1036 | if (fn_info.is_var_args) { |
| 1022 | | if (params_written != 0) try w.writeAll(", "); |
| 1037 | if (index > 0) try w.writeAll(", "); |
| 1023 | 1038 | try w.writeAll("..."); |
| 1024 | | } else if (params_written == 0) { |
| 1039 | } else if (index == 0) { |
| 1025 | 1040 | try w.writeAll("void"); |
| 1026 | 1041 | } |
| 1027 | 1042 | try w.writeByte(')'); |
| ... | ... | @@ -1307,7 +1322,7 @@ pub const DeclGen = struct { |
| 1307 | 1322 | |
| 1308 | 1323 | fn renderErrorUnionTypedef(dg: *DeclGen, t: Type) error{ OutOfMemory, AnalysisFail }![]const u8 { |
| 1309 | 1324 | const payload_ty = t.errorUnionPayload(); |
| 1310 | | const error_ty = t.errorUnionSet(); |
| 1325 | assert(t.errorUnionSet().tag() == .anyerror); |
| 1311 | 1326 | |
| 1312 | 1327 | var buffer = std.ArrayList(u8).init(dg.typedefs.allocator); |
| 1313 | 1328 | defer buffer.deinit(); |
| ... | ... | @@ -1328,15 +1343,7 @@ pub const DeclGen = struct { |
| 1328 | 1343 | } |
| 1329 | 1344 | |
| 1330 | 1345 | const name_begin = buffer.items.len; |
| 1331 | | if (error_ty.castTag(.error_set_inferred)) |inf_err_set_payload| { |
| 1332 | | const func = inf_err_set_payload.data.func; |
| 1333 | | try bw.writeAll("zig_E_"); |
| 1334 | | try dg.renderDeclName(bw, func.owner_decl); |
| 1335 | | } else { |
| 1336 | | try bw.print("zig_E_{}_{}", .{ |
| 1337 | | typeToCIdentifier(error_ty, dg.module), typeToCIdentifier(payload_ty, dg.module), |
| 1338 | | }); |
| 1339 | | } |
| 1346 | try bw.print("zig_E_{}", .{typeToCIdentifier(payload_ty, dg.module)}); |
| 1340 | 1347 | const name_end = buffer.items.len; |
| 1341 | 1348 | try bw.writeAll(";\n"); |
| 1342 | 1349 | |
| ... | ... | @@ -1505,11 +1512,11 @@ pub const DeclGen = struct { |
| 1505 | 1512 | }, |
| 1506 | 1513 | .Pointer => { |
| 1507 | 1514 | if (t.isSlice()) { |
| 1508 | | var slice_ty_pl = Type.Payload.ElemType{ |
| 1515 | var slice_pl = Type.Payload.ElemType{ |
| 1509 | 1516 | .base = .{ .tag = if (t.ptrIsMutable()) .mut_slice else .const_slice }, |
| 1510 | 1517 | .data = t.childType(), |
| 1511 | 1518 | }; |
| 1512 | | const slice_ty = Type.initPayload(&slice_ty_pl.base); |
| 1519 | const slice_ty = Type.initPayload(&slice_pl.base); |
| 1513 | 1520 | |
| 1514 | 1521 | const name = dg.getTypedefName(slice_ty) orelse |
| 1515 | 1522 | try dg.renderSliceTypedef(slice_ty); |
| ... | ... | @@ -1525,7 +1532,9 @@ pub const DeclGen = struct { |
| 1525 | 1532 | } |
| 1526 | 1533 | |
| 1527 | 1534 | const child_ty = t.childType(); |
| 1528 | | if (t.isCPtr() and child_ty.eql(Type.u8, dg.module) and dg.decl.val.tag() == .extern_fn) { |
| 1535 | if (t.isCPtr() and child_ty.eql(Type.u8, dg.module) and |
| 1536 | (dg.decl.val.tag() == .extern_fn or std.mem.eql(u8, std.mem.span(dg.decl.name), "main"))) |
| 1537 | { |
| 1529 | 1538 | // This is a hack, since the c compiler expects a lot of external |
| 1530 | 1539 | // library functions to have char pointers in their signatures, but |
| 1531 | 1540 | // u8 and i8 produce unsigned char and signed char respectively, |
| ... | ... | @@ -1543,11 +1552,11 @@ pub const DeclGen = struct { |
| 1543 | 1552 | return w.writeAll(" *"); |
| 1544 | 1553 | }, |
| 1545 | 1554 | .Array => { |
| 1546 | | var array_ty_pl = Type.Payload.Array{ .base = .{ .tag = .array }, .data = .{ |
| 1555 | var array_pl = Type.Payload.Array{ .base = .{ .tag = .array }, .data = .{ |
| 1547 | 1556 | .len = t.arrayLenIncludingSentinel(), |
| 1548 | 1557 | .elem_type = t.childType(), |
| 1549 | 1558 | } }; |
| 1550 | | const array_ty = Type.initPayload(&array_ty_pl.base); |
| 1559 | const array_ty = Type.initPayload(&array_pl.base); |
| 1551 | 1560 | |
| 1552 | 1561 | const name = dg.getTypedefName(array_ty) orelse |
| 1553 | 1562 | try dg.renderArrayTypedef(array_ty); |
| ... | ... | @@ -1582,8 +1591,13 @@ pub const DeclGen = struct { |
| 1582 | 1591 | return dg.renderType(w, Type.anyerror); |
| 1583 | 1592 | } |
| 1584 | 1593 | |
| 1585 | | const name = dg.getTypedefName(t) orelse |
| 1586 | | try dg.renderErrorUnionTypedef(t); |
| 1594 | var error_union_pl = Type.Payload.ErrorUnion{ |
| 1595 | .data = .{ .error_set = Type.anyerror, .payload = payload_ty }, |
| 1596 | }; |
| 1597 | const error_union_ty = Type.initPayload(&error_union_pl.base); |
| 1598 | |
| 1599 | const name = dg.getTypedefName(error_union_ty) orelse |
| 1600 | try dg.renderErrorUnionTypedef(error_union_ty); |
| 1587 | 1601 | |
| 1588 | 1602 | return w.writeAll(name); |
| 1589 | 1603 | }, |
| ... | ... | @@ -1603,8 +1617,8 @@ pub const DeclGen = struct { |
| 1603 | 1617 | }, |
| 1604 | 1618 | .Enum => { |
| 1605 | 1619 | // For enums, we simply use the integer tag type. |
| 1606 | | var int_tag_ty_buffer: Type.Payload.Bits = undefined; |
| 1607 | | const int_tag_ty = t.intTagType(&int_tag_ty_buffer); |
| 1620 | var int_tag_buf: Type.Payload.Bits = undefined; |
| 1621 | const int_tag_ty = t.intTagType(&int_tag_buf); |
| 1608 | 1622 | |
| 1609 | 1623 | try dg.renderType(w, int_tag_ty); |
| 1610 | 1624 | }, |
| ... | ... | @@ -1801,11 +1815,7 @@ pub const DeclGen = struct { |
| 1801 | 1815 | try w.writeByte('&'); |
| 1802 | 1816 | return dg.renderDeclName(w, decl); |
| 1803 | 1817 | }, |
| 1804 | | .undefined_ptr => |ty| { |
| 1805 | | try w.writeAll("(("); |
| 1806 | | try dg.renderTypecast(w, ty); |
| 1807 | | return w.print("){x})", .{try dg.fmtIntLiteral(Type.usize, Value.undef)}); |
| 1808 | | }, |
| 1818 | .undef => |ty| return dg.renderValue(w, ty, Value.undef, .Other), |
| 1809 | 1819 | .identifier => |ident| return w.print("{ }", .{fmtIdent(ident)}), |
| 1810 | 1820 | .bytes => |bytes| return w.writeAll(bytes), |
| 1811 | 1821 | } |
| ... | ... | @@ -1824,7 +1834,7 @@ pub const DeclGen = struct { |
| 1824 | 1834 | return w.writeByte(')'); |
| 1825 | 1835 | }, |
| 1826 | 1836 | .decl_ref => |decl| return dg.renderDeclName(w, decl), |
| 1827 | | .undefined_ptr => unreachable, |
| 1837 | .undef => unreachable, |
| 1828 | 1838 | .identifier => |ident| return w.print("(*{ })", .{fmtIdent(ident)}), |
| 1829 | 1839 | .bytes => |bytes| { |
| 1830 | 1840 | try w.writeAll("(*"); |
| ... | ... | @@ -2151,10 +2161,10 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO |
| 2151 | 2161 | |
| 2152 | 2162 | .mul_add => try airMulAdd(f, inst), |
| 2153 | 2163 | |
| 2154 | | .add_with_overflow => try airOverflow(f, inst, "addo_"), |
| 2155 | | .sub_with_overflow => try airOverflow(f, inst, "subo_"), |
| 2156 | | .mul_with_overflow => try airOverflow(f, inst, "mulo_"), |
| 2157 | | .shl_with_overflow => try airOverflow(f, inst, "shlo_"), |
| 2164 | .add_with_overflow => try airOverflow(f, inst, "addo_", .range), |
| 2165 | .sub_with_overflow => try airOverflow(f, inst, "subo_", .range), |
| 2166 | .mul_with_overflow => try airOverflow(f, inst, "mulo_", .range), |
| 2167 | .shl_with_overflow => try airOverflow(f, inst, "shlo_", .bits), |
| 2158 | 2168 | |
| 2159 | 2169 | .min => try airMinMax(f, inst, "<"), |
| 2160 | 2170 | .max => try airMinMax(f, inst, ">"), |
| ... | ... | @@ -2284,8 +2294,8 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO |
| 2284 | 2294 | .slice_ptr => try airSliceField(f, inst, " = ", ".ptr;\n"), |
| 2285 | 2295 | .slice_len => try airSliceField(f, inst, " = ", ".len;\n"), |
| 2286 | 2296 | |
| 2287 | | .ptr_slice_len_ptr => try airSliceField(f, inst, " = &", ".len;\n"), |
| 2288 | | .ptr_slice_ptr_ptr => try airSliceField(f, inst, " = &", ".ptr;\n"), |
| 2297 | .ptr_slice_len_ptr => try airSliceField(f, inst, " = &", "->len;\n"), |
| 2298 | .ptr_slice_ptr_ptr => try airSliceField(f, inst, " = &", "->ptr;\n"), |
| 2289 | 2299 | |
| 2290 | 2300 | .ptr_elem_val => try airPtrElemVal(f, inst), |
| 2291 | 2301 | .ptr_elem_ptr => try airPtrElemPtr(f, inst), |
| ... | ... | @@ -2459,7 +2469,7 @@ fn airAlloc(f: *Function, inst: Air.Inst.Index) !CValue { |
| 2459 | 2469 | const elem_type = inst_ty.elemType(); |
| 2460 | 2470 | const mutability: Mutability = if (inst_ty.isConstPtr()) .Const else .Mut; |
| 2461 | 2471 | if (!elem_type.isFnOrHasRuntimeBitsIgnoreComptime()) { |
| 2462 | | return CValue{ .undefined_ptr = inst_ty }; |
| 2472 | return CValue{ .undef = inst_ty }; |
| 2463 | 2473 | } |
| 2464 | 2474 | |
| 2465 | 2475 | const target = f.object.dg.module.getTarget(); |
| ... | ... | @@ -2474,9 +2484,13 @@ fn airRetPtr(f: *Function, inst: Air.Inst.Index) !CValue { |
| 2474 | 2484 | const writer = f.object.writer(); |
| 2475 | 2485 | const inst_ty = f.air.typeOfIndex(inst); |
| 2476 | 2486 | |
| 2487 | const elem_ty = inst_ty.elemType(); |
| 2488 | if (!elem_ty.hasRuntimeBitsIgnoreComptime()) { |
| 2489 | return CValue{ .undef = inst_ty }; |
| 2490 | } |
| 2491 | |
| 2477 | 2492 | // First line: the variable used as data storage. |
| 2478 | | const elem_type = inst_ty.elemType(); |
| 2479 | | const local = try f.allocLocal(elem_type, .Mut); |
| 2493 | const local = try f.allocLocal(elem_ty, .Mut); |
| 2480 | 2494 | try writer.writeAll(";\n"); |
| 2481 | 2495 | |
| 2482 | 2496 | return CValue{ .local_ref = local.local }; |
| ... | ... | @@ -2507,8 +2521,7 @@ fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue { |
| 2507 | 2521 | if (is_array) { |
| 2508 | 2522 | // Insert a memcpy to initialize this array. The source operand is always a pointer |
| 2509 | 2523 | // and thus we only need to know size/type information from the local type/dest. |
| 2510 | | try writer.writeByte(';'); |
| 2511 | | try f.object.indent_writer.insertNewline(); |
| 2524 | try writer.writeAll(";\n"); |
| 2512 | 2525 | try writer.writeAll("memcpy("); |
| 2513 | 2526 | try f.writeCValue(writer, local); |
| 2514 | 2527 | try writer.writeAll(", "); |
| ... | ... | @@ -2535,7 +2548,8 @@ fn airRet(f: *Function, inst: Air.Inst.Index) !CValue { |
| 2535 | 2548 | try writer.writeAll(";\n"); |
| 2536 | 2549 | } else if (ret_ty.isError()) { |
| 2537 | 2550 | try writer.writeAll("return 0;"); |
| 2538 | | } else { |
| 2551 | } else if (f.object.dg.decl.ty.fnCallingConvention() != .Naked) { |
| 2552 | // Not even allowed to return void in a naked function. |
| 2539 | 2553 | try writer.writeAll("return;\n"); |
| 2540 | 2554 | } |
| 2541 | 2555 | return CValue.none; |
| ... | ... | @@ -2847,7 +2861,7 @@ fn airSatOp(f: *Function, inst: Air.Inst.Index, fn_op: [*:0]const u8) !CValue { |
| 2847 | 2861 | return ret; |
| 2848 | 2862 | } |
| 2849 | 2863 | |
| 2850 | | fn airOverflow(f: *Function, inst: Air.Inst.Index, op_abbrev: [*:0]const u8) !CValue { |
| 2864 | fn airOverflow(f: *Function, inst: Air.Inst.Index, op_abbrev: [*:0]const u8, kind: enum { range, bits }) !CValue { |
| 2851 | 2865 | if (f.liveness.isUnused(inst)) |
| 2852 | 2866 | return CValue.none; |
| 2853 | 2867 | |
| ... | ... | @@ -2879,23 +2893,29 @@ fn airOverflow(f: *Function, inst: Air.Inst.Index, op_abbrev: [*:0]const u8) !CV |
| 2879 | 2893 | try w.writeAll(", &"); |
| 2880 | 2894 | try f.writeCValue(w, ret); |
| 2881 | 2895 | try w.writeAll(".field_0, "); |
| 2882 | | { |
| 2883 | | var arena = std.heap.ArenaAllocator.init(f.object.dg.module.gpa); |
| 2884 | | defer arena.deinit(); |
| 2885 | | |
| 2886 | | const expected_contents = union { u: Value.Payload.U64, i: Value.Payload.I64 }; |
| 2887 | | var stack align(@alignOf(expected_contents)) = |
| 2888 | | std.heap.stackFallback(@sizeOf(expected_contents), arena.allocator()); |
| 2889 | | |
| 2890 | | if (int_info.signedness == .signed) { |
| 2891 | | const min_val = try scalar_ty.minInt(stack.get(), target); |
| 2892 | | try w.print("{}, ", .{try f.fmtIntLiteral(scalar_ty, min_val)}); |
| 2893 | | } |
| 2896 | switch (kind) { |
| 2897 | .range => { |
| 2898 | var arena = std.heap.ArenaAllocator.init(f.object.dg.module.gpa); |
| 2899 | defer arena.deinit(); |
| 2900 | |
| 2901 | const expected_contents = union { u: Value.Payload.U64, i: Value.Payload.I64 }; |
| 2902 | var stack align(@alignOf(expected_contents)) = |
| 2903 | std.heap.stackFallback(@sizeOf(expected_contents), arena.allocator()); |
| 2904 | |
| 2905 | if (int_info.signedness == .signed) { |
| 2906 | const min_val = try scalar_ty.minInt(stack.get(), target); |
| 2907 | try w.print("{}, ", .{try f.fmtIntLiteral(scalar_ty, min_val)}); |
| 2908 | } |
| 2894 | 2909 | |
| 2895 | | const max_val = try scalar_ty.maxInt(stack.get(), target); |
| 2896 | | try w.print("{});", .{try f.fmtIntLiteral(scalar_ty, max_val)}); |
| 2910 | const max_val = try scalar_ty.maxInt(stack.get(), target); |
| 2911 | try w.print("{});\n", .{try f.fmtIntLiteral(scalar_ty, max_val)}); |
| 2912 | }, |
| 2913 | .bits => { |
| 2914 | var bits_pl = Value.Payload.U64{ .base = .{ .tag = .int_u64 }, .data = int_info.bits }; |
| 2915 | const bits_val = Value.initPayload(&bits_pl.base); |
| 2916 | try w.print("{x});\n", .{try f.fmtIntLiteral(Type.u8, bits_val)}); |
| 2917 | }, |
| 2897 | 2918 | } |
| 2898 | | try f.object.indent_writer.insertNewline(); |
| 2899 | 2919 | return ret; |
| 2900 | 2920 | } |
| 2901 | 2921 | |
| ... | ... | @@ -3075,6 +3095,9 @@ fn airCall( |
| 3075 | 3095 | inst: Air.Inst.Index, |
| 3076 | 3096 | modifier: std.builtin.CallOptions.Modifier, |
| 3077 | 3097 | ) !CValue { |
| 3098 | // Not even allowed to call panic in a naked function. |
| 3099 | if (f.object.dg.decl.ty.fnCallingConvention() == .Naked) return .none; |
| 3100 | |
| 3078 | 3101 | switch (modifier) { |
| 3079 | 3102 | .auto => {}, |
| 3080 | 3103 | .always_tail => return f.fail("TODO: C backend: call with always_tail attribute", .{}), |
| ... | ... | @@ -3094,10 +3117,10 @@ fn airCall( |
| 3094 | 3117 | const writer = f.object.writer(); |
| 3095 | 3118 | |
| 3096 | 3119 | const result_local: CValue = r: { |
| 3097 | | if (f.liveness.isUnused(inst)) { |
| 3098 | | if (loweredFnRetTyHasBits(fn_ty)) { |
| 3099 | | try writer.print("(void)", .{}); |
| 3100 | | } |
| 3120 | if (!loweredFnRetTyHasBits(fn_ty)) { |
| 3121 | break :r .none; |
| 3122 | } else if (f.liveness.isUnused(inst)) { |
| 3123 | try writer.print("(void)", .{}); |
| 3101 | 3124 | break :r .none; |
| 3102 | 3125 | } else { |
| 3103 | 3126 | const local = try f.allocLocal(fn_ty.fnReturnType(), .Const); |
| ... | ... | @@ -3107,6 +3130,7 @@ fn airCall( |
| 3107 | 3130 | }; |
| 3108 | 3131 | |
| 3109 | 3132 | var is_extern = false; |
| 3133 | var name: [*:0]const u8 = ""; |
| 3110 | 3134 | callee: { |
| 3111 | 3135 | known: { |
| 3112 | 3136 | const fn_decl = fn_decl: { |
| ... | ... | @@ -3121,6 +3145,7 @@ fn airCall( |
| 3121 | 3145 | else => break :known, |
| 3122 | 3146 | }; |
| 3123 | 3147 | }; |
| 3148 | name = f.object.dg.module.declPtr(fn_decl).name; |
| 3124 | 3149 | try f.object.dg.renderDeclName(writer, fn_decl); |
| 3125 | 3150 | break :callee; |
| 3126 | 3151 | } |
| ... | ... | @@ -3137,7 +3162,9 @@ fn airCall( |
| 3137 | 3162 | if (args_written != 0) { |
| 3138 | 3163 | try writer.writeAll(", "); |
| 3139 | 3164 | } |
| 3140 | | if (is_extern and ty.isCPtr() and ty.childType().tag() == .u8) { |
| 3165 | if ((is_extern or std.mem.eql(u8, std.mem.span(name), "main")) and |
| 3166 | ty.isCPtr() and ty.childType().tag() == .u8) |
| 3167 | { |
| 3141 | 3168 | // Corresponds with hack in renderType .Pointer case. |
| 3142 | 3169 | try writer.writeAll("(char"); |
| 3143 | 3170 | if (ty.isConstPtr()) try writer.writeAll(" const"); |
| ... | ... | @@ -3286,15 +3313,27 @@ fn lowerTry( |
| 3286 | 3313 | } |
| 3287 | 3314 | } |
| 3288 | 3315 | |
| 3289 | | const local = try f.allocLocal(result_ty, .Const); |
| 3290 | | if (operand_is_ptr or isByRef(payload_ty)) { |
| 3291 | | try writer.writeAll(" = &"); |
| 3316 | const is_array = payload_ty.zigTypeTag() == .Array; |
| 3317 | const local = try f.allocLocal(result_ty, if (is_array) .Mut else .Const); |
| 3318 | if (is_array) { |
| 3319 | try writer.writeAll(";\n"); |
| 3320 | try writer.writeAll("memcpy("); |
| 3321 | try f.writeCValue(writer, local); |
| 3322 | try writer.writeAll(", "); |
| 3292 | 3323 | try f.writeCValue(writer, err_union); |
| 3293 | | try writer.writeAll("->payload;\n"); |
| 3324 | try writer.writeAll(".payload, sizeof("); |
| 3325 | try f.writeCValue(writer, local); |
| 3326 | try writer.writeAll("));\n"); |
| 3294 | 3327 | } else { |
| 3295 | | try writer.writeAll(" = "); |
| 3296 | | try f.writeCValue(writer, err_union); |
| 3297 | | try writer.writeAll(".payload;\n"); |
| 3328 | if (operand_is_ptr or isByRef(payload_ty)) { |
| 3329 | try writer.writeAll(" = &"); |
| 3330 | try f.writeCValue(writer, err_union); |
| 3331 | try writer.writeAll("->payload;\n"); |
| 3332 | } else { |
| 3333 | try writer.writeAll(" = "); |
| 3334 | try f.writeCValue(writer, err_union); |
| 3335 | try writer.writeAll(".payload;\n"); |
| 3336 | } |
| 3298 | 3337 | } |
| 3299 | 3338 | return local; |
| 3300 | 3339 | } |
| ... | ... | @@ -3361,15 +3400,21 @@ fn airBreakpoint(f: *Function) !CValue { |
| 3361 | 3400 | |
| 3362 | 3401 | fn airRetAddr(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3363 | 3402 | if (f.liveness.isUnused(inst)) return CValue.none; |
| 3403 | const writer = f.object.writer(); |
| 3364 | 3404 | const local = try f.allocLocal(Type.usize, .Const); |
| 3365 | | try f.object.writer().writeAll(" = zig_return_address();\n"); |
| 3405 | try writer.writeAll(" = ("); |
| 3406 | try f.renderTypecast(writer, Type.usize); |
| 3407 | try writer.writeAll(")zig_return_address();\n"); |
| 3366 | 3408 | return local; |
| 3367 | 3409 | } |
| 3368 | 3410 | |
| 3369 | 3411 | fn airFrameAddress(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3370 | 3412 | if (f.liveness.isUnused(inst)) return CValue.none; |
| 3413 | const writer = f.object.writer(); |
| 3371 | 3414 | const local = try f.allocLocal(Type.usize, .Const); |
| 3372 | | try f.object.writer().writeAll(" = zig_frame_address();\n"); |
| 3415 | try writer.writeAll(" = ("); |
| 3416 | try f.renderTypecast(writer, Type.usize); |
| 3417 | try writer.writeAll(")zig_frame_address();\n"); |
| 3373 | 3418 | return local; |
| 3374 | 3419 | } |
| 3375 | 3420 | |
| ... | ... | @@ -3385,6 +3430,9 @@ fn airFence(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3385 | 3430 | } |
| 3386 | 3431 | |
| 3387 | 3432 | fn airUnreach(f: *Function) !CValue { |
| 3433 | // Not even allowed to call unreachable in a naked function. |
| 3434 | if (f.object.dg.decl.ty.fnCallingConvention() == .Naked) return .none; |
| 3435 | |
| 3388 | 3436 | try f.object.writer().writeAll("zig_unreachable();\n"); |
| 3389 | 3437 | return CValue.none; |
| 3390 | 3438 | } |
| ... | ... | @@ -3479,15 +3527,12 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3479 | 3527 | const local = try f.allocLocal(inst_ty, .Mut); |
| 3480 | 3528 | if (f.wantSafety()) { |
| 3481 | 3529 | try writer.writeAll(" = "); |
| 3482 | | try f.object.dg.renderValue(writer, inst_ty, Value.undef, .Other); |
| 3530 | try f.writeCValue(writer, .{ .undef = inst_ty }); |
| 3483 | 3531 | } |
| 3484 | 3532 | try writer.writeAll(";\n"); |
| 3485 | 3533 | break :local local; |
| 3486 | 3534 | } else .none; |
| 3487 | 3535 | |
| 3488 | | try writer.writeAll("{\n"); |
| 3489 | | f.object.indent_writer.pushIndent(); |
| 3490 | | |
| 3491 | 3536 | const output_locals_begin = f.next_local_index; |
| 3492 | 3537 | f.next_local_index += outputs.len; |
| 3493 | 3538 | const constraints_extra_begin = extra_i; |
| ... | ... | @@ -3510,7 +3555,7 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3510 | 3555 | try writer.writeAll("\")"); |
| 3511 | 3556 | if (f.wantSafety()) { |
| 3512 | 3557 | try writer.writeAll(" = "); |
| 3513 | | try f.object.dg.renderValue(writer, output_ty, Value.undef, .Other); |
| 3558 | try f.writeCValue(writer, .{ .undef = output_ty }); |
| 3514 | 3559 | } |
| 3515 | 3560 | try writer.writeAll(";\n"); |
| 3516 | 3561 | } else if (constraint.len < 2 or constraint[0] != '=') { |
| ... | ... | @@ -3605,7 +3650,7 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3605 | 3650 | } else { |
| 3606 | 3651 | const input_val = try f.resolveInst(input); |
| 3607 | 3652 | try writer.print("{s}(", .{fmtStringLiteral(constraint)}); |
| 3608 | | try f.writeCValue(writer, if (input_val == .constant) .{ |
| 3653 | try f.writeCValue(writer, if (input_val == .constant) CValue{ |
| 3609 | 3654 | .local = input_locals_begin + index, |
| 3610 | 3655 | } else input_val); |
| 3611 | 3656 | } |
| ... | ... | @@ -3647,9 +3692,6 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3647 | 3692 | } |
| 3648 | 3693 | } |
| 3649 | 3694 | |
| 3650 | | f.object.indent_writer.popIndent(); |
| 3651 | | try writer.writeAll("}\n"); |
| 3652 | | |
| 3653 | 3695 | return local; |
| 3654 | 3696 | } |
| 3655 | 3697 | |
| ... | ... | @@ -3728,7 +3770,7 @@ fn airOptionalPayloadPtr(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3728 | 3770 | const inst_ty = f.air.typeOfIndex(inst); |
| 3729 | 3771 | |
| 3730 | 3772 | if (!inst_ty.childType().hasRuntimeBitsIgnoreComptime()) { |
| 3731 | | return CValue{ .undefined_ptr = inst_ty }; |
| 3773 | return CValue{ .undef = inst_ty }; |
| 3732 | 3774 | } |
| 3733 | 3775 | |
| 3734 | 3776 | if (opt_ty.optionalReprIsPayload()) { |
| ... | ... | @@ -3996,7 +4038,9 @@ fn airWrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3996 | 4038 | } |
| 3997 | 4039 | |
| 3998 | 4040 | const local = try f.allocLocal(err_un_ty, .Const); |
| 3999 | | try writer.writeAll(" = { .error = "); |
| 4041 | try writer.writeAll(" = { .payload = "); |
| 4042 | try f.writeCValue(writer, .{ .undef = payload_ty }); |
| 4043 | try writer.writeAll(", .error = "); |
| 4000 | 4044 | try f.writeCValue(writer, operand); |
| 4001 | 4045 | try writer.writeAll(" };\n"); |
| 4002 | 4046 | return local; |
| ... | ... | @@ -4059,10 +4103,25 @@ fn airWrapErrUnionPay(f: *Function, inst: Air.Inst.Index) !CValue { |
| 4059 | 4103 | const operand = try f.resolveInst(ty_op.operand); |
| 4060 | 4104 | |
| 4061 | 4105 | const inst_ty = f.air.typeOfIndex(inst); |
| 4062 | | const local = try f.allocLocal(inst_ty, .Const); |
| 4063 | | try writer.writeAll(" = { .error = 0, .payload = "); |
| 4064 | | try f.writeCValue(writer, operand); |
| 4065 | | try writer.writeAll(" };\n"); |
| 4106 | const payload_ty = inst_ty.errorUnionPayload(); |
| 4107 | const is_array = payload_ty.zigTypeTag() == .Array; |
| 4108 | const local = try f.allocLocal(inst_ty, if (is_array) .Mut else .Const); |
| 4109 | try writer.writeAll(" = { .payload = "); |
| 4110 | try f.writeCValue(writer, if (is_array) CValue{ .undef = payload_ty } else operand); |
| 4111 | try writer.print(", .error = {} }};\n", .{ |
| 4112 | try f.fmtIntLiteral(inst_ty.errorUnionSet(), Value.zero), |
| 4113 | }); |
| 4114 | |
| 4115 | if (is_array) { |
| 4116 | try writer.writeAll("memcpy("); |
| 4117 | try f.writeCValue(writer, local); |
| 4118 | try writer.writeAll(".payload, "); |
| 4119 | try f.writeCValue(writer, operand); |
| 4120 | try writer.writeAll(", sizeof("); |
| 4121 | try f.writeCValue(writer, local); |
| 4122 | try writer.writeAll(".payload));\n"); |
| 4123 | } |
| 4124 | |
| 4066 | 4125 | return local; |
| 4067 | 4126 | } |
| 4068 | 4127 | |
| ... | ... | @@ -4114,11 +4173,11 @@ fn airArrayToSlice(f: *Function, inst: Air.Inst.Index) !CValue { |
| 4114 | 4173 | const array_len = f.air.typeOf(ty_op.operand).elemType().arrayLen(); |
| 4115 | 4174 | |
| 4116 | 4175 | try writer.writeAll(" = { .ptr = "); |
| 4117 | | if (operand == .undefined_ptr) { |
| 4176 | if (operand == .undef) { |
| 4118 | 4177 | // Unfortunately, C does not support any equivalent to |
| 4119 | 4178 | // &(*(void *)p)[0], although LLVM does via GetElementPtr |
| 4120 | 4179 | var buf: Type.SlicePtrFieldTypeBuffer = undefined; |
| 4121 | | try f.writeCValue(writer, CValue{ .undefined_ptr = inst_ty.slicePtrFieldType(&buf) }); |
| 4180 | try f.writeCValue(writer, CValue{ .undef = inst_ty.slicePtrFieldType(&buf) }); |
| 4122 | 4181 | } else { |
| 4123 | 4182 | try writer.writeAll("&("); |
| 4124 | 4183 | try f.writeCValueDeref(writer, operand); |
| ... | ... | @@ -4528,9 +4587,12 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue { |
| 4528 | 4587 | const ty_pl = f.air.instructions.items(.data)[inst].ty_pl; |
| 4529 | 4588 | const len = @intCast(usize, inst_ty.arrayLen()); |
| 4530 | 4589 | const elements = @ptrCast([]const Air.Inst.Ref, f.air.extra[ty_pl.payload..][0..len]); |
| 4590 | const mutability: Mutability = for (elements) |element| { |
| 4591 | if (f.air.typeOf(element).zigTypeTag() == .Array) break .Mut; |
| 4592 | } else .Const; |
| 4531 | 4593 | |
| 4532 | 4594 | const writer = f.object.writer(); |
| 4533 | | const local = try f.allocLocal(inst_ty, .Const); |
| 4595 | const local = try f.allocLocal(inst_ty, mutability); |
| 4534 | 4596 | try writer.writeAll(" = {"); |
| 4535 | 4597 | switch (inst_ty.zigTypeTag()) { |
| 4536 | 4598 | .Array => { |
| ... | ... | @@ -4547,6 +4609,7 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue { |
| 4547 | 4609 | empty = false; |
| 4548 | 4610 | } |
| 4549 | 4611 | if (empty) try writer.print("{}", .{try f.fmtIntLiteral(Type.u8, Value.zero)}); |
| 4612 | try writer.writeAll("};\n"); |
| 4550 | 4613 | }, |
| 4551 | 4614 | .Struct => { |
| 4552 | 4615 | var empty = true; |
| ... | ... | @@ -4557,15 +4620,44 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue { |
| 4557 | 4620 | if (!inst_ty.isTupleOrAnonStruct()) { |
| 4558 | 4621 | try writer.print(".{ } = ", .{fmtIdent(inst_ty.structFieldName(index))}); |
| 4559 | 4622 | } |
| 4560 | | try f.writeCValue(writer, try f.resolveInst(element)); |
| 4623 | |
| 4624 | const element_ty = f.air.typeOf(element); |
| 4625 | try f.writeCValue(writer, switch (element_ty.zigTypeTag()) { |
| 4626 | .Array => CValue{ .undef = element_ty }, |
| 4627 | else => try f.resolveInst(element), |
| 4628 | }); |
| 4561 | 4629 | empty = false; |
| 4562 | 4630 | } |
| 4563 | 4631 | if (empty) try writer.print("{}", .{try f.fmtIntLiteral(Type.u8, Value.zero)}); |
| 4632 | try writer.writeAll("};\n"); |
| 4633 | |
| 4634 | for (elements) |element, index| { |
| 4635 | if (inst_ty.structFieldValueComptime(index)) |_| continue; |
| 4636 | |
| 4637 | const element_ty = f.air.typeOf(element); |
| 4638 | if (element_ty.zigTypeTag() != .Array) continue; |
| 4639 | |
| 4640 | var field_name_storage: ?[]u8 = null; |
| 4641 | defer if (field_name_storage) |storage| f.object.dg.gpa.free(storage); |
| 4642 | const field_name = if (inst_ty.isTupleOrAnonStruct()) field_name: { |
| 4643 | const name = try std.fmt.allocPrint(f.object.dg.gpa, "field_{d}", .{index}); |
| 4644 | field_name_storage = name; |
| 4645 | break :field_name name; |
| 4646 | } else inst_ty.structFieldName(index); |
| 4647 | |
| 4648 | try writer.writeAll(";\n"); |
| 4649 | try writer.writeAll("memcpy("); |
| 4650 | try f.writeCValue(writer, local); |
| 4651 | try writer.print(".{ }, ", .{fmtIdent(field_name)}); |
| 4652 | try f.writeCValue(writer, try f.resolveInst(element)); |
| 4653 | try writer.writeAll(", sizeof("); |
| 4654 | try f.writeCValue(writer, local); |
| 4655 | try writer.print(".{ }));\n", .{fmtIdent(field_name)}); |
| 4656 | } |
| 4564 | 4657 | }, |
| 4565 | 4658 | .Vector => return f.fail("TODO: C backend: implement airAggregateInit for vectors", .{}), |
| 4566 | 4659 | else => unreachable, |
| 4567 | 4660 | } |
| 4568 | | try writer.writeAll("};\n"); |
| 4569 | 4661 | |
| 4570 | 4662 | return local; |
| 4571 | 4663 | } |
| ... | ... | @@ -4732,8 +4824,8 @@ fn airMulAdd(f: *Function, inst: Air.Inst.Index) !CValue { |
| 4732 | 4824 | |
| 4733 | 4825 | fn toMemoryOrder(order: std.builtin.AtomicOrder) [:0]const u8 { |
| 4734 | 4826 | return switch (order) { |
| 4735 | | .Unordered => "memory_order_relaxed", |
| 4736 | | .Monotonic => "memory_order_consume", |
| 4827 | // Note: unordered is actually even less atomic than relaxed |
| 4828 | .Unordered, .Monotonic => "memory_order_relaxed", |
| 4737 | 4829 | .Acquire => "memory_order_acquire", |
| 4738 | 4830 | .Release => "memory_order_release", |
| 4739 | 4831 | .AcqRel => "memory_order_acq_rel", |