| ... | ... | @@ -4,22 +4,25 @@ strip: bool, |
| 4 | 4 | |
| 5 | 5 | llvm: if (build_options.have_llvm) struct { |
| 6 | 6 | context: *llvm.Context, |
| 7 | | module: ?*llvm.Module = null, |
| 8 | | target: ?*llvm.Target = null, |
| 9 | | di_builder: ?*llvm.DIBuilder = null, |
| 10 | | di_compile_unit: ?*llvm.DICompileUnit = null, |
| 11 | | types: std.ArrayListUnmanaged(*llvm.Type) = .{}, |
| 12 | | globals: std.ArrayListUnmanaged(*llvm.Value) = .{}, |
| 13 | | constants: std.ArrayListUnmanaged(*llvm.Value) = .{}, |
| 7 | module: ?*llvm.Module, |
| 8 | target: ?*llvm.Target, |
| 9 | di_builder: ?*llvm.DIBuilder, |
| 10 | di_compile_unit: ?*llvm.DICompileUnit, |
| 11 | attribute_kind_ids: ?*[Attribute.Kind.len]c_uint, |
| 12 | attributes: std.ArrayListUnmanaged(*llvm.Attribute), |
| 13 | types: std.ArrayListUnmanaged(*llvm.Type), |
| 14 | globals: std.ArrayListUnmanaged(*llvm.Value), |
| 15 | constants: std.ArrayListUnmanaged(*llvm.Value), |
| 14 | 16 | } else void, |
| 15 | 17 | |
| 16 | 18 | source_filename: String, |
| 17 | 19 | data_layout: String, |
| 18 | 20 | target_triple: String, |
| 21 | module_asm: std.ArrayListUnmanaged(u8), |
| 19 | 22 | |
| 20 | 23 | string_map: std.AutoArrayHashMapUnmanaged(void, void), |
| 21 | | string_bytes: std.ArrayListUnmanaged(u8), |
| 22 | 24 | string_indices: std.ArrayListUnmanaged(u32), |
| 25 | string_bytes: std.ArrayListUnmanaged(u8), |
| 23 | 26 | |
| 24 | 27 | types: std.AutoArrayHashMapUnmanaged(String, Type), |
| 25 | 28 | next_unnamed_type: String, |
| ... | ... | @@ -28,6 +31,11 @@ type_map: std.AutoArrayHashMapUnmanaged(void, void), |
| 28 | 31 | type_items: std.ArrayListUnmanaged(Type.Item), |
| 29 | 32 | type_extra: std.ArrayListUnmanaged(u32), |
| 30 | 33 | |
| 34 | attributes: std.AutoArrayHashMapUnmanaged(Attribute.Storage, void), |
| 35 | attributes_map: std.AutoArrayHashMapUnmanaged(void, void), |
| 36 | attributes_indices: std.ArrayListUnmanaged(u32), |
| 37 | attributes_extra: std.ArrayListUnmanaged(u32), |
| 38 | |
| 31 | 39 | globals: std.AutoArrayHashMapUnmanaged(String, Global), |
| 32 | 40 | next_unnamed_global: String, |
| 33 | 41 | next_replaced_global: String, |
| ... | ... | @@ -41,6 +49,7 @@ constant_items: std.MultiArrayList(Constant.Item), |
| 41 | 49 | constant_extra: std.ArrayListUnmanaged(u32), |
| 42 | 50 | constant_limbs: std.ArrayListUnmanaged(std.math.big.Limb), |
| 43 | 51 | |
| 52 | pub const expected_args_len = 16; |
| 44 | 53 | pub const expected_fields_len = 32; |
| 45 | 54 | pub const expected_gep_indices_len = 8; |
| 46 | 55 | pub const expected_cases_len = 8; |
| ... | ... | @@ -65,7 +74,7 @@ pub const String = enum(u32) { |
| 65 | 74 | return self.toIndex() == null; |
| 66 | 75 | } |
| 67 | 76 | |
| 68 | | pub fn toSlice(self: String, b: *const Builder) ?[:0]const u8 { |
| 77 | pub fn slice(self: String, b: *const Builder) ?[:0]const u8 { |
| 69 | 78 | const index = self.toIndex() orelse return null; |
| 70 | 79 | const start = b.string_indices.items[index]; |
| 71 | 80 | const end = b.string_indices.items[index + 1]; |
| ... | ... | @@ -85,20 +94,14 @@ pub const String = enum(u32) { |
| 85 | 94 | if (comptime std.mem.indexOfNone(u8, fmt_str, "@\"")) |_| |
| 86 | 95 | @compileError("invalid format string: '" ++ fmt_str ++ "'"); |
| 87 | 96 | assert(data.string != .none); |
| 88 | | const slice = data.string.toSlice(data.builder) orelse |
| 97 | const sentinel_slice = data.string.slice(data.builder) orelse |
| 89 | 98 | return writer.print("{d}", .{@intFromEnum(data.string)}); |
| 90 | | const full_slice = slice[0 .. slice.len + comptime @intFromBool( |
| 99 | try printEscapedString(sentinel_slice[0 .. sentinel_slice.len + comptime @intFromBool( |
| 91 | 100 | std.mem.indexOfScalar(u8, fmt_str, '@') != null, |
| 92 | | )]; |
| 93 | | const need_quotes = (comptime std.mem.indexOfScalar(u8, fmt_str, '"') != null) or |
| 94 | | !isValidIdentifier(full_slice); |
| 95 | | if (need_quotes) try writer.writeByte('"'); |
| 96 | | for (full_slice) |character| switch (character) { |
| 97 | | '\\' => try writer.writeAll("\\\\"), |
| 98 | | ' '...'"' - 1, '"' + 1...'\\' - 1, '\\' + 1...'~' => try writer.writeByte(character), |
| 99 | | else => try writer.print("\\{X:0>2}", .{character}), |
| 100 | | }; |
| 101 | | if (need_quotes) try writer.writeByte('"'); |
| 101 | )], if (comptime std.mem.indexOfScalar(u8, fmt_str, '"')) |_| |
| 102 | .always_quote |
| 103 | else |
| 104 | .quote_unless_valid_identifier, writer); |
| 102 | 105 | } |
| 103 | 106 | pub fn fmt(self: String, builder: *const Builder) std.fmt.Formatter(format) { |
| 104 | 107 | return .{ .data = .{ .string = self, .builder = builder } }; |
| ... | ... | @@ -108,6 +111,7 @@ pub const String = enum(u32) { |
| 108 | 111 | return @enumFromInt(@as(u32, @intCast((index orelse return .none) + |
| 109 | 112 | @intFromEnum(String.empty)))); |
| 110 | 113 | } |
| 114 | |
| 111 | 115 | fn toIndex(self: String) ?usize { |
| 112 | 116 | return std.math.sub(u32, @intFromEnum(self), @intFromEnum(String.empty)) catch null; |
| 113 | 117 | } |
| ... | ... | @@ -118,7 +122,7 @@ pub const String = enum(u32) { |
| 118 | 122 | return @truncate(std.hash.Wyhash.hash(0, key)); |
| 119 | 123 | } |
| 120 | 124 | pub fn eql(ctx: Adapter, lhs_key: []const u8, _: void, rhs_index: usize) bool { |
| 121 | | return std.mem.eql(u8, lhs_key, String.fromIndex(rhs_index).toSlice(ctx.builder).?); |
| 125 | return std.mem.eql(u8, lhs_key, String.fromIndex(rhs_index).slice(ctx.builder).?); |
| 122 | 126 | } |
| 123 | 127 | }; |
| 124 | 128 | }; |
| ... | ... | @@ -290,6 +294,17 @@ pub const Type = enum(u32) { |
| 290 | 294 | }; |
| 291 | 295 | } |
| 292 | 296 | |
| 297 | pub fn pointerAddrSpace(self: Type, builder: *const Builder) AddrSpace { |
| 298 | switch (self) { |
| 299 | .ptr => return .default, |
| 300 | else => { |
| 301 | const item = builder.type_items.items[@intFromEnum(self)]; |
| 302 | assert(item.tag == .pointer); |
| 303 | return @enumFromInt(item.data); |
| 304 | }, |
| 305 | } |
| 306 | } |
| 307 | |
| 293 | 308 | pub fn isFunction(self: Type, builder: *const Builder) bool { |
| 294 | 309 | return switch (self.tag(builder)) { |
| 295 | 310 | .function, .vararg_function => true, |
| ... | ... | @@ -606,7 +621,7 @@ pub const Type = enum(u32) { |
| 606 | 621 | var extra = data.builder.typeExtraDataTrail(Type.Target, item.data); |
| 607 | 622 | const types = extra.trail.next(extra.data.types_len, Type, data.builder); |
| 608 | 623 | const ints = extra.trail.next(extra.data.ints_len, u32, data.builder); |
| 609 | | try writer.print("t{s}", .{extra.data.name.toSlice(data.builder).?}); |
| 624 | try writer.print("t{s}", .{extra.data.name.slice(data.builder).?}); |
| 610 | 625 | for (types) |ty| try writer.print("_{m}", .{ty.fmt(data.builder)}); |
| 611 | 626 | for (ints) |int| try writer.print("_{d}", .{int}); |
| 612 | 627 | try writer.writeByte('t'); |
| ... | ... | @@ -641,7 +656,7 @@ pub const Type = enum(u32) { |
| 641 | 656 | .named_structure => { |
| 642 | 657 | const extra = data.builder.typeExtraData(Type.NamedStructure, item.data); |
| 643 | 658 | try writer.writeAll("s_"); |
| 644 | | if (extra.id.toSlice(data.builder)) |id| try writer.writeAll(id); |
| 659 | if (extra.id.slice(data.builder)) |id| try writer.writeAll(id); |
| 645 | 660 | }, |
| 646 | 661 | } |
| 647 | 662 | return; |
| ... | ... | @@ -823,6 +838,849 @@ pub const Type = enum(u32) { |
| 823 | 838 | } |
| 824 | 839 | }; |
| 825 | 840 | |
| 841 | pub const Attribute = union(Kind) { |
| 842 | // Parameter Attributes |
| 843 | zeroext, |
| 844 | signext, |
| 845 | inreg, |
| 846 | byval: Type, |
| 847 | byref: Type, |
| 848 | preallocated: Type, |
| 849 | inalloca: Type, |
| 850 | sret: Type, |
| 851 | elementtype: Type, |
| 852 | @"align": Alignment, |
| 853 | @"noalias", |
| 854 | nocapture, |
| 855 | nofree, |
| 856 | nest, |
| 857 | returned, |
| 858 | nonnull, |
| 859 | dereferenceable: u32, |
| 860 | dereferenceable_or_null: u32, |
| 861 | swiftself, |
| 862 | swiftasync, |
| 863 | swifterror, |
| 864 | immarg, |
| 865 | noundef, |
| 866 | nofpclass: FpClass, |
| 867 | alignstack: Alignment, |
| 868 | allocalign, |
| 869 | allocptr, |
| 870 | readnone, |
| 871 | readonly, |
| 872 | writeonly, |
| 873 | |
| 874 | // Function Attributes |
| 875 | //alignstack: Alignment, |
| 876 | allockind: AllocKind, |
| 877 | allocsize: AllocSize, |
| 878 | alwaysinline, |
| 879 | builtin, |
| 880 | cold, |
| 881 | convergent, |
| 882 | disable_sanitizer_information, |
| 883 | fn_ret_thunk_extern, |
| 884 | hot, |
| 885 | inlinehint, |
| 886 | jumptable, |
| 887 | memory: Memory, |
| 888 | minsize, |
| 889 | naked, |
| 890 | nobuiltin, |
| 891 | nocallback, |
| 892 | noduplicate, |
| 893 | //nofree, |
| 894 | noimplicitfloat, |
| 895 | @"noinline", |
| 896 | nomerge, |
| 897 | nonlazybind, |
| 898 | noprofile, |
| 899 | skipprofile, |
| 900 | noredzone, |
| 901 | noreturn, |
| 902 | norecurse, |
| 903 | willreturn, |
| 904 | nosync, |
| 905 | nounwind, |
| 906 | nosanitize_bounds, |
| 907 | nosanitize_coverage, |
| 908 | null_pointer_is_valid, |
| 909 | optforfuzzing, |
| 910 | optnone, |
| 911 | optsize, |
| 912 | //preallocated: Type, |
| 913 | returns_twice, |
| 914 | safestack, |
| 915 | sanitize_address, |
| 916 | sanitize_memory, |
| 917 | sanitize_thread, |
| 918 | sanitize_hwaddress, |
| 919 | sanitize_memtag, |
| 920 | speculative_load_hardening, |
| 921 | speculatable, |
| 922 | ssp, |
| 923 | sspstrong, |
| 924 | sspreq, |
| 925 | strictfp, |
| 926 | uwtable: UwTable, |
| 927 | nocf_check, |
| 928 | shadowcallstack, |
| 929 | mustprogress, |
| 930 | vscale_range: VScaleRange, |
| 931 | |
| 932 | // Global Attributes |
| 933 | no_sanitize_address, |
| 934 | no_sanitize_hwaddress, |
| 935 | //sanitize_memtag, |
| 936 | sanitize_address_dyninit, |
| 937 | |
| 938 | string: struct { kind: String, value: String }, |
| 939 | none: noreturn, |
| 940 | |
| 941 | pub const Index = enum(u32) { |
| 942 | _, |
| 943 | |
| 944 | pub fn getKind(self: Index, builder: *const Builder) Kind { |
| 945 | return self.toStorage(builder).kind; |
| 946 | } |
| 947 | |
| 948 | pub fn toAttribute(self: Index, builder: *const Builder) Attribute { |
| 949 | @setEvalBranchQuota(2_000); |
| 950 | const storage = self.toStorage(builder); |
| 951 | if (storage.kind.toString()) |kind| return .{ .string = .{ |
| 952 | .kind = kind, |
| 953 | .value = @enumFromInt(storage.value), |
| 954 | } } else return switch (storage.kind) { |
| 955 | inline .zeroext, |
| 956 | .signext, |
| 957 | .inreg, |
| 958 | .byval, |
| 959 | .byref, |
| 960 | .preallocated, |
| 961 | .inalloca, |
| 962 | .sret, |
| 963 | .elementtype, |
| 964 | .@"align", |
| 965 | .@"noalias", |
| 966 | .nocapture, |
| 967 | .nofree, |
| 968 | .nest, |
| 969 | .returned, |
| 970 | .nonnull, |
| 971 | .dereferenceable, |
| 972 | .dereferenceable_or_null, |
| 973 | .swiftself, |
| 974 | .swiftasync, |
| 975 | .swifterror, |
| 976 | .immarg, |
| 977 | .noundef, |
| 978 | .nofpclass, |
| 979 | .alignstack, |
| 980 | .allocalign, |
| 981 | .allocptr, |
| 982 | .readnone, |
| 983 | .readonly, |
| 984 | .writeonly, |
| 985 | //.alignstack, |
| 986 | .allockind, |
| 987 | .allocsize, |
| 988 | .alwaysinline, |
| 989 | .builtin, |
| 990 | .cold, |
| 991 | .convergent, |
| 992 | .disable_sanitizer_information, |
| 993 | .fn_ret_thunk_extern, |
| 994 | .hot, |
| 995 | .inlinehint, |
| 996 | .jumptable, |
| 997 | .memory, |
| 998 | .minsize, |
| 999 | .naked, |
| 1000 | .nobuiltin, |
| 1001 | .nocallback, |
| 1002 | .noduplicate, |
| 1003 | //.nofree, |
| 1004 | .noimplicitfloat, |
| 1005 | .@"noinline", |
| 1006 | .nomerge, |
| 1007 | .nonlazybind, |
| 1008 | .noprofile, |
| 1009 | .skipprofile, |
| 1010 | .noredzone, |
| 1011 | .noreturn, |
| 1012 | .norecurse, |
| 1013 | .willreturn, |
| 1014 | .nosync, |
| 1015 | .nounwind, |
| 1016 | .nosanitize_bounds, |
| 1017 | .nosanitize_coverage, |
| 1018 | .null_pointer_is_valid, |
| 1019 | .optforfuzzing, |
| 1020 | .optnone, |
| 1021 | .optsize, |
| 1022 | //.preallocated, |
| 1023 | .returns_twice, |
| 1024 | .safestack, |
| 1025 | .sanitize_address, |
| 1026 | .sanitize_memory, |
| 1027 | .sanitize_thread, |
| 1028 | .sanitize_hwaddress, |
| 1029 | .sanitize_memtag, |
| 1030 | .speculative_load_hardening, |
| 1031 | .speculatable, |
| 1032 | .ssp, |
| 1033 | .sspstrong, |
| 1034 | .sspreq, |
| 1035 | .strictfp, |
| 1036 | .uwtable, |
| 1037 | .nocf_check, |
| 1038 | .shadowcallstack, |
| 1039 | .mustprogress, |
| 1040 | .vscale_range, |
| 1041 | .no_sanitize_address, |
| 1042 | .no_sanitize_hwaddress, |
| 1043 | .sanitize_address_dyninit, |
| 1044 | => |kind| { |
| 1045 | const field = @typeInfo(Attribute).Union.fields[@intFromEnum(kind)]; |
| 1046 | comptime assert(std.mem.eql(u8, @tagName(kind), field.name)); |
| 1047 | return @unionInit(Attribute, field.name, switch (field.type) { |
| 1048 | void => {}, |
| 1049 | u32 => storage.value, |
| 1050 | Alignment, String, Type, UwTable => @enumFromInt(storage.value), |
| 1051 | AllocKind, AllocSize, FpClass, Memory, VScaleRange => @bitCast(storage.value), |
| 1052 | else => @compileError("bad payload type: " ++ @typeName(field.type)), |
| 1053 | }); |
| 1054 | }, |
| 1055 | .string, .none => unreachable, |
| 1056 | _ => unreachable, |
| 1057 | }; |
| 1058 | } |
| 1059 | |
| 1060 | const FormatData = struct { |
| 1061 | attribute_index: Index, |
| 1062 | builder: *const Builder, |
| 1063 | }; |
| 1064 | fn format( |
| 1065 | data: FormatData, |
| 1066 | comptime fmt_str: []const u8, |
| 1067 | _: std.fmt.FormatOptions, |
| 1068 | writer: anytype, |
| 1069 | ) @TypeOf(writer).Error!void { |
| 1070 | if (comptime std.mem.indexOfNone(u8, fmt_str, "\"#")) |_| |
| 1071 | @compileError("invalid format string: '" ++ fmt_str ++ "'"); |
| 1072 | const attribute = data.attribute_index.toAttribute(data.builder); |
| 1073 | switch (attribute) { |
| 1074 | .zeroext, |
| 1075 | .signext, |
| 1076 | .inreg, |
| 1077 | .@"noalias", |
| 1078 | .nocapture, |
| 1079 | .nofree, |
| 1080 | .nest, |
| 1081 | .returned, |
| 1082 | .nonnull, |
| 1083 | .swiftself, |
| 1084 | .swiftasync, |
| 1085 | .swifterror, |
| 1086 | .immarg, |
| 1087 | .noundef, |
| 1088 | .allocalign, |
| 1089 | .allocptr, |
| 1090 | .readnone, |
| 1091 | .readonly, |
| 1092 | .writeonly, |
| 1093 | .alwaysinline, |
| 1094 | .builtin, |
| 1095 | .cold, |
| 1096 | .convergent, |
| 1097 | .disable_sanitizer_information, |
| 1098 | .fn_ret_thunk_extern, |
| 1099 | .hot, |
| 1100 | .inlinehint, |
| 1101 | .jumptable, |
| 1102 | .minsize, |
| 1103 | .naked, |
| 1104 | .nobuiltin, |
| 1105 | .nocallback, |
| 1106 | .noduplicate, |
| 1107 | .noimplicitfloat, |
| 1108 | .@"noinline", |
| 1109 | .nomerge, |
| 1110 | .nonlazybind, |
| 1111 | .noprofile, |
| 1112 | .skipprofile, |
| 1113 | .noredzone, |
| 1114 | .noreturn, |
| 1115 | .norecurse, |
| 1116 | .willreturn, |
| 1117 | .nosync, |
| 1118 | .nounwind, |
| 1119 | .nosanitize_bounds, |
| 1120 | .nosanitize_coverage, |
| 1121 | .null_pointer_is_valid, |
| 1122 | .optforfuzzing, |
| 1123 | .optnone, |
| 1124 | .optsize, |
| 1125 | .returns_twice, |
| 1126 | .safestack, |
| 1127 | .sanitize_address, |
| 1128 | .sanitize_memory, |
| 1129 | .sanitize_thread, |
| 1130 | .sanitize_hwaddress, |
| 1131 | .sanitize_memtag, |
| 1132 | .speculative_load_hardening, |
| 1133 | .speculatable, |
| 1134 | .ssp, |
| 1135 | .sspstrong, |
| 1136 | .sspreq, |
| 1137 | .strictfp, |
| 1138 | .nocf_check, |
| 1139 | .shadowcallstack, |
| 1140 | .mustprogress, |
| 1141 | .no_sanitize_address, |
| 1142 | .no_sanitize_hwaddress, |
| 1143 | .sanitize_address_dyninit, |
| 1144 | => try writer.print(" {s}", .{@tagName(attribute)}), |
| 1145 | .byval, |
| 1146 | .byref, |
| 1147 | .preallocated, |
| 1148 | .inalloca, |
| 1149 | .sret, |
| 1150 | .elementtype, |
| 1151 | => |ty| try writer.print(" {s}({%})", .{ @tagName(attribute), ty.fmt(data.builder) }), |
| 1152 | .@"align" => |alignment| try writer.print("{}", .{alignment}), |
| 1153 | .dereferenceable, |
| 1154 | .dereferenceable_or_null, |
| 1155 | => |size| try writer.print(" {s}({d})", .{ @tagName(attribute), size }), |
| 1156 | .nofpclass => |fpclass| { |
| 1157 | const Int = @typeInfo(FpClass).Struct.backing_integer.?; |
| 1158 | try writer.print("{s}(", .{@tagName(attribute)}); |
| 1159 | var any = false; |
| 1160 | var remaining: Int = @bitCast(fpclass); |
| 1161 | inline for (@typeInfo(FpClass).Struct.decls) |decl| { |
| 1162 | if (!decl.is_pub) continue; |
| 1163 | const pattern: Int = @bitCast(@field(FpClass, decl.name)); |
| 1164 | if (remaining & pattern == pattern) { |
| 1165 | if (!any) { |
| 1166 | try writer.writeByte(' '); |
| 1167 | any = true; |
| 1168 | } |
| 1169 | try writer.writeAll(decl.name); |
| 1170 | remaining &= ~pattern; |
| 1171 | } |
| 1172 | } |
| 1173 | try writer.writeByte(')'); |
| 1174 | }, |
| 1175 | .alignstack => |alignment| try writer.print( |
| 1176 | if (comptime std.mem.indexOfScalar(u8, fmt_str, '#') != null) |
| 1177 | "{s}={d}" |
| 1178 | else |
| 1179 | "{s}({d})", |
| 1180 | .{ @tagName(attribute), alignment.toByteUnits() orelse return }, |
| 1181 | ), |
| 1182 | .allockind => |allockind| { |
| 1183 | try writer.print("{s}(\"", .{@tagName(attribute)}); |
| 1184 | var any = false; |
| 1185 | inline for (@typeInfo(AllocKind).Struct.fields) |field| { |
| 1186 | if (comptime std.mem.eql(u8, field.name, "_")) continue; |
| 1187 | if (@field(allockind, field.name)) { |
| 1188 | if (!any) { |
| 1189 | try writer.writeByte(','); |
| 1190 | any = true; |
| 1191 | } |
| 1192 | try writer.writeAll(field.name); |
| 1193 | } |
| 1194 | } |
| 1195 | try writer.writeAll("\")"); |
| 1196 | }, |
| 1197 | .allocsize => |allocsize| { |
| 1198 | try writer.print("{s}({d}", .{ @tagName(attribute), allocsize.elem_size }); |
| 1199 | if (allocsize.num_elems != AllocSize.none) |
| 1200 | try writer.print(",{d}", .{allocsize.num_elems}); |
| 1201 | try writer.writeByte(')'); |
| 1202 | }, |
| 1203 | .memory => |memory| try writer.print("{s}({s}, argmem: {s}, inaccessiblemem: {s})", .{ |
| 1204 | @tagName(attribute), |
| 1205 | @tagName(memory.other), |
| 1206 | @tagName(memory.argmem), |
| 1207 | @tagName(memory.inaccessiblemem), |
| 1208 | }), |
| 1209 | .uwtable => |uwtable| if (uwtable != .none) { |
| 1210 | try writer.writeAll(@tagName(attribute)); |
| 1211 | if (uwtable != UwTable.default) try writer.print("({s})", .{@tagName(uwtable)}); |
| 1212 | }, |
| 1213 | .vscale_range => |vscale_range| try writer.print("{s}({d},{d})", .{ |
| 1214 | @tagName(attribute), |
| 1215 | vscale_range.min.toByteUnits().?, |
| 1216 | vscale_range.max.toByteUnits() orelse 0, |
| 1217 | }), |
| 1218 | .string => |string_attr| if (comptime std.mem.indexOfScalar(u8, fmt_str, '"') != null) { |
| 1219 | try writer.print(" {\"}", .{string_attr.kind.fmt(data.builder)}); |
| 1220 | if (string_attr.value != .empty) |
| 1221 | try writer.print("={\"}", .{string_attr.value.fmt(data.builder)}); |
| 1222 | }, |
| 1223 | .none => unreachable, |
| 1224 | } |
| 1225 | } |
| 1226 | pub fn fmt(self: Index, builder: *const Builder) std.fmt.Formatter(format) { |
| 1227 | return .{ .data = .{ .attribute_index = self, .builder = builder } }; |
| 1228 | } |
| 1229 | |
| 1230 | fn toStorage(self: Index, builder: *const Builder) Storage { |
| 1231 | return builder.attributes.keys()[@intFromEnum(self)]; |
| 1232 | } |
| 1233 | |
| 1234 | fn toLlvm(self: Index, builder: *const Builder) *llvm.Attribute { |
| 1235 | assert(builder.useLibLlvm()); |
| 1236 | return builder.llvm.attributes.items[@intFromEnum(self)]; |
| 1237 | } |
| 1238 | }; |
| 1239 | |
| 1240 | pub const Kind = enum(u32) { |
| 1241 | // Parameter Attributes |
| 1242 | zeroext, |
| 1243 | signext, |
| 1244 | inreg, |
| 1245 | byval, |
| 1246 | byref, |
| 1247 | preallocated, |
| 1248 | inalloca, |
| 1249 | sret, |
| 1250 | elementtype, |
| 1251 | @"align", |
| 1252 | @"noalias", |
| 1253 | nocapture, |
| 1254 | nofree, |
| 1255 | nest, |
| 1256 | returned, |
| 1257 | nonnull, |
| 1258 | dereferenceable, |
| 1259 | dereferenceable_or_null, |
| 1260 | swiftself, |
| 1261 | swiftasync, |
| 1262 | swifterror, |
| 1263 | immarg, |
| 1264 | noundef, |
| 1265 | nofpclass, |
| 1266 | alignstack, |
| 1267 | allocalign, |
| 1268 | allocptr, |
| 1269 | readnone, |
| 1270 | readonly, |
| 1271 | writeonly, |
| 1272 | |
| 1273 | // Function Attributes |
| 1274 | //alignstack, |
| 1275 | allockind, |
| 1276 | allocsize, |
| 1277 | alwaysinline, |
| 1278 | builtin, |
| 1279 | cold, |
| 1280 | convergent, |
| 1281 | disable_sanitizer_information, |
| 1282 | fn_ret_thunk_extern, |
| 1283 | hot, |
| 1284 | inlinehint, |
| 1285 | jumptable, |
| 1286 | memory, |
| 1287 | minsize, |
| 1288 | naked, |
| 1289 | nobuiltin, |
| 1290 | nocallback, |
| 1291 | noduplicate, |
| 1292 | //nofree, |
| 1293 | noimplicitfloat, |
| 1294 | @"noinline", |
| 1295 | nomerge, |
| 1296 | nonlazybind, |
| 1297 | noprofile, |
| 1298 | skipprofile, |
| 1299 | noredzone, |
| 1300 | noreturn, |
| 1301 | norecurse, |
| 1302 | willreturn, |
| 1303 | nosync, |
| 1304 | nounwind, |
| 1305 | nosanitize_bounds, |
| 1306 | nosanitize_coverage, |
| 1307 | null_pointer_is_valid, |
| 1308 | optforfuzzing, |
| 1309 | optnone, |
| 1310 | optsize, |
| 1311 | //preallocated, |
| 1312 | returns_twice, |
| 1313 | safestack, |
| 1314 | sanitize_address, |
| 1315 | sanitize_memory, |
| 1316 | sanitize_thread, |
| 1317 | sanitize_hwaddress, |
| 1318 | sanitize_memtag, |
| 1319 | speculative_load_hardening, |
| 1320 | speculatable, |
| 1321 | ssp, |
| 1322 | sspstrong, |
| 1323 | sspreq, |
| 1324 | strictfp, |
| 1325 | uwtable, |
| 1326 | nocf_check, |
| 1327 | shadowcallstack, |
| 1328 | mustprogress, |
| 1329 | vscale_range, |
| 1330 | |
| 1331 | // Global Attributes |
| 1332 | no_sanitize_address, |
| 1333 | no_sanitize_hwaddress, |
| 1334 | //sanitize_memtag, |
| 1335 | sanitize_address_dyninit, |
| 1336 | |
| 1337 | string = std.math.maxInt(u31) - 1, |
| 1338 | none = std.math.maxInt(u31), |
| 1339 | _, |
| 1340 | |
| 1341 | pub const len = @typeInfo(Kind).Enum.fields.len - 2; |
| 1342 | |
| 1343 | pub fn fromString(str: String) Kind { |
| 1344 | assert(!str.isAnon()); |
| 1345 | return @enumFromInt(@intFromEnum(str)); |
| 1346 | } |
| 1347 | |
| 1348 | fn toString(self: Kind) ?String { |
| 1349 | const str: String = @enumFromInt(@intFromEnum(self)); |
| 1350 | return if (str.isAnon()) null else str; |
| 1351 | } |
| 1352 | }; |
| 1353 | |
| 1354 | pub const FpClass = packed struct(u32) { |
| 1355 | signaling_nan: bool = false, |
| 1356 | quiet_nan: bool = false, |
| 1357 | negative_infinity: bool = false, |
| 1358 | negative_normal: bool = false, |
| 1359 | negative_subnormal: bool = false, |
| 1360 | negative_zero: bool = false, |
| 1361 | positive_zero: bool = false, |
| 1362 | positive_subnormal: bool = false, |
| 1363 | positive_normal: bool = false, |
| 1364 | positive_infinity: bool = false, |
| 1365 | _: u22 = 0, |
| 1366 | |
| 1367 | pub const all = FpClass{ |
| 1368 | .signaling_nan = true, |
| 1369 | .quiet_nan = true, |
| 1370 | .negative_infinity = true, |
| 1371 | .negative_normal = true, |
| 1372 | .negative_subnormal = true, |
| 1373 | .negative_zero = true, |
| 1374 | .positive_zero = true, |
| 1375 | .positive_subnormal = true, |
| 1376 | .positive_normal = true, |
| 1377 | .positive_infinity = true, |
| 1378 | }; |
| 1379 | |
| 1380 | pub const nan = FpClass{ .signaling_nan = true, .quiet_nan = true }; |
| 1381 | pub const snan = FpClass{ .signaling_nan = true }; |
| 1382 | pub const qnan = FpClass{ .quiet_nan = true }; |
| 1383 | |
| 1384 | pub const inf = FpClass{ .negative_infinity = true, .positive_infinity = true }; |
| 1385 | pub const ninf = FpClass{ .negative_infinity = true }; |
| 1386 | pub const pinf = FpClass{ .positive_infinity = true }; |
| 1387 | |
| 1388 | pub const zero = FpClass{ .positive_zero = true, .negative_zero = true }; |
| 1389 | pub const nzero = FpClass{ .negative_zero = true }; |
| 1390 | pub const pzero = FpClass{ .positive_zero = true }; |
| 1391 | |
| 1392 | pub const sub = FpClass{ .positive_subnormal = true, .negative_subnormal = true }; |
| 1393 | pub const nsub = FpClass{ .negative_subnormal = true }; |
| 1394 | pub const psub = FpClass{ .positive_subnormal = true }; |
| 1395 | |
| 1396 | pub const norm = FpClass{ .positive_normal = true, .negative_normal = true }; |
| 1397 | pub const nnorm = FpClass{ .negative_normal = true }; |
| 1398 | pub const pnorm = FpClass{ .positive_normal = true }; |
| 1399 | }; |
| 1400 | |
| 1401 | pub const AllocKind = packed struct(u32) { |
| 1402 | alloc: bool, |
| 1403 | realloc: bool, |
| 1404 | free: bool, |
| 1405 | uninitialized: bool, |
| 1406 | zeroed: bool, |
| 1407 | aligned: bool, |
| 1408 | _: u26 = 0, |
| 1409 | }; |
| 1410 | |
| 1411 | pub const AllocSize = packed struct(u32) { |
| 1412 | elem_size: u16, |
| 1413 | num_elems: u16, |
| 1414 | |
| 1415 | pub const none = std.math.maxInt(u16); |
| 1416 | |
| 1417 | fn toLlvm(self: AllocSize) packed struct(u64) { num_elems: u32, elem_size: u32 } { |
| 1418 | return .{ .num_elems = switch (self.num_elems) { |
| 1419 | else => self.num_elems, |
| 1420 | none => std.math.maxInt(u32), |
| 1421 | }, .elem_size = self.elem_size }; |
| 1422 | } |
| 1423 | }; |
| 1424 | |
| 1425 | pub const Memory = packed struct(u32) { |
| 1426 | argmem: Effect, |
| 1427 | inaccessiblemem: Effect, |
| 1428 | other: Effect, |
| 1429 | _: u26 = 0, |
| 1430 | |
| 1431 | pub const Effect = enum(u2) { none, read, write, readwrite }; |
| 1432 | }; |
| 1433 | |
| 1434 | pub const UwTable = enum(u32) { |
| 1435 | none, |
| 1436 | sync, |
| 1437 | @"async", |
| 1438 | |
| 1439 | pub const default = UwTable.@"async"; |
| 1440 | }; |
| 1441 | |
| 1442 | pub const VScaleRange = packed struct(u32) { |
| 1443 | min: Alignment, |
| 1444 | max: Alignment, |
| 1445 | _: u20 = 0, |
| 1446 | |
| 1447 | fn toLlvm(self: VScaleRange) packed struct(u64) { max: u32, min: u32 } { |
| 1448 | return .{ |
| 1449 | .max = @intCast(self.max.toByteUnits() orelse 0), |
| 1450 | .min = @intCast(self.min.toByteUnits().?), |
| 1451 | }; |
| 1452 | } |
| 1453 | }; |
| 1454 | |
| 1455 | pub fn getKind(self: Attribute) Kind { |
| 1456 | return switch (self) { |
| 1457 | else => self, |
| 1458 | .string => |string_attr| Kind.fromString(string_attr.kind), |
| 1459 | }; |
| 1460 | } |
| 1461 | |
| 1462 | const Storage = extern struct { |
| 1463 | kind: Kind, |
| 1464 | value: u32, |
| 1465 | }; |
| 1466 | |
| 1467 | fn toStorage(self: Attribute) Storage { |
| 1468 | return switch (self) { |
| 1469 | inline else => |value| .{ .kind = @as(Kind, self), .value = switch (@TypeOf(value)) { |
| 1470 | void => 0, |
| 1471 | u32 => value, |
| 1472 | Alignment, String, Type, UwTable => @intFromEnum(value), |
| 1473 | AllocKind, AllocSize, FpClass, Memory, VScaleRange => @bitCast(value), |
| 1474 | else => @compileError("bad payload type: " ++ @typeName(@TypeOf(value))), |
| 1475 | } }, |
| 1476 | .string => |string_attr| .{ |
| 1477 | .kind = Kind.fromString(string_attr.kind), |
| 1478 | .value = @intFromEnum(string_attr.value), |
| 1479 | }, |
| 1480 | .none => unreachable, |
| 1481 | }; |
| 1482 | } |
| 1483 | }; |
| 1484 | |
| 1485 | pub const Attributes = enum(u32) { |
| 1486 | none, |
| 1487 | _, |
| 1488 | |
| 1489 | pub fn slice(self: Attributes, builder: *const Builder) []const Attribute.Index { |
| 1490 | const start = builder.attributes_indices.items[@intFromEnum(self)]; |
| 1491 | const end = builder.attributes_indices.items[@intFromEnum(self) + 1]; |
| 1492 | return @ptrCast(builder.attributes_extra.items[start..end]); |
| 1493 | } |
| 1494 | |
| 1495 | const FormatData = struct { |
| 1496 | attributes: Attributes, |
| 1497 | builder: *const Builder, |
| 1498 | }; |
| 1499 | fn format( |
| 1500 | data: FormatData, |
| 1501 | comptime fmt_str: []const u8, |
| 1502 | fmt_opts: std.fmt.FormatOptions, |
| 1503 | writer: anytype, |
| 1504 | ) @TypeOf(writer).Error!void { |
| 1505 | for (data.attributes.slice(data.builder)) |attribute_index| try Attribute.Index.format(.{ |
| 1506 | .attribute_index = attribute_index, |
| 1507 | .builder = data.builder, |
| 1508 | }, fmt_str, fmt_opts, writer); |
| 1509 | } |
| 1510 | pub fn fmt(self: Attributes, builder: *const Builder) std.fmt.Formatter(format) { |
| 1511 | return .{ .data = .{ .attributes = self, .builder = builder } }; |
| 1512 | } |
| 1513 | }; |
| 1514 | |
| 1515 | pub const FunctionAttributes = enum(u32) { |
| 1516 | none, |
| 1517 | _, |
| 1518 | |
| 1519 | const function_index = 0; |
| 1520 | const return_index = 1; |
| 1521 | const params_index = 2; |
| 1522 | |
| 1523 | pub const Wip = struct { |
| 1524 | maps: Maps = .{}, |
| 1525 | |
| 1526 | const Map = std.AutoArrayHashMapUnmanaged(Attribute.Kind, Attribute.Index); |
| 1527 | const Maps = std.ArrayListUnmanaged(Map); |
| 1528 | |
| 1529 | pub fn deinit(self: *Wip, builder: *const Builder) void { |
| 1530 | for (self.maps.items) |*map| map.deinit(builder.gpa); |
| 1531 | self.maps.deinit(builder.gpa); |
| 1532 | self.* = undefined; |
| 1533 | } |
| 1534 | |
| 1535 | pub fn addFnAttr(self: *Wip, attribute: Attribute, builder: *Builder) Allocator.Error!void { |
| 1536 | try self.addAttr(function_index, attribute, builder); |
| 1537 | } |
| 1538 | |
| 1539 | pub fn addFnAttrIndex( |
| 1540 | self: *Wip, |
| 1541 | attribute_index: Attribute.Index, |
| 1542 | builder: *const Builder, |
| 1543 | ) Allocator.Error!void { |
| 1544 | try self.addAttrIndex(function_index, attribute_index, builder); |
| 1545 | } |
| 1546 | |
| 1547 | pub fn removeFnAttr(self: *Wip, attribute_kind: Attribute.Kind) Allocator.Error!bool { |
| 1548 | return self.removeAttr(function_index, attribute_kind); |
| 1549 | } |
| 1550 | |
| 1551 | pub fn addRetAttr(self: *Wip, attribute: Attribute, builder: *Builder) Allocator.Error!void { |
| 1552 | try self.addAttr(return_index, attribute, builder); |
| 1553 | } |
| 1554 | |
| 1555 | pub fn addRetAttrIndex( |
| 1556 | self: *Wip, |
| 1557 | attribute_index: Attribute.Index, |
| 1558 | builder: *const Builder, |
| 1559 | ) Allocator.Error!void { |
| 1560 | try self.addAttrIndex(return_index, attribute_index, builder); |
| 1561 | } |
| 1562 | |
| 1563 | pub fn removeRetAttr(self: *Wip, attribute_kind: Attribute.Kind) Allocator.Error!bool { |
| 1564 | return self.removeAttr(return_index, attribute_kind); |
| 1565 | } |
| 1566 | |
| 1567 | pub fn addParamAttr( |
| 1568 | self: *Wip, |
| 1569 | param_index: usize, |
| 1570 | attribute: Attribute, |
| 1571 | builder: *Builder, |
| 1572 | ) Allocator.Error!void { |
| 1573 | try self.addAttr(params_index + param_index, attribute, builder); |
| 1574 | } |
| 1575 | |
| 1576 | pub fn addParamAttrIndex( |
| 1577 | self: *Wip, |
| 1578 | param_index: usize, |
| 1579 | attribute_index: Attribute.Index, |
| 1580 | builder: *const Builder, |
| 1581 | ) Allocator.Error!void { |
| 1582 | try self.addAttrIndex(params_index + param_index, attribute_index, builder); |
| 1583 | } |
| 1584 | |
| 1585 | pub fn removeParamAttr( |
| 1586 | self: *Wip, |
| 1587 | param_index: usize, |
| 1588 | attribute_kind: Attribute.Kind, |
| 1589 | ) Allocator.Error!bool { |
| 1590 | return self.removeAttr(params_index + param_index, attribute_kind); |
| 1591 | } |
| 1592 | |
| 1593 | pub fn finish(self: *const Wip, builder: *Builder) Allocator.Error!FunctionAttributes { |
| 1594 | const attributes = try builder.gpa.alloc(Attributes, self.maps.items.len); |
| 1595 | defer builder.gpa.free(attributes); |
| 1596 | for (attributes, self.maps.items) |*attribute, map| |
| 1597 | attribute.* = try builder.attrs(map.values()); |
| 1598 | return builder.fnAttrs(attributes); |
| 1599 | } |
| 1600 | |
| 1601 | fn addAttr( |
| 1602 | self: *Wip, |
| 1603 | index: usize, |
| 1604 | attribute: Attribute, |
| 1605 | builder: *Builder, |
| 1606 | ) Allocator.Error!void { |
| 1607 | const map = try self.getOrPutMap(builder.gpa, index); |
| 1608 | try map.put(builder.gpa, attribute.getKind(), try builder.attr(attribute)); |
| 1609 | } |
| 1610 | |
| 1611 | fn addAttrIndex( |
| 1612 | self: *Wip, |
| 1613 | index: usize, |
| 1614 | attribute_index: Attribute.Index, |
| 1615 | builder: *const Builder, |
| 1616 | ) Allocator.Error!void { |
| 1617 | const map = try self.getOrPutMap(builder.gpa, index); |
| 1618 | try map.put(builder.gpa, attribute_index.getKind(builder), attribute_index); |
| 1619 | } |
| 1620 | |
| 1621 | fn removeAttr(self: *Wip, index: usize, attribute_kind: Attribute.Kind) Allocator.Error!bool { |
| 1622 | const map = self.getMap(index) orelse return false; |
| 1623 | return map.swapRemove(attribute_kind); |
| 1624 | } |
| 1625 | |
| 1626 | fn getOrPutMap(self: *Wip, allocator: Allocator, index: usize) Allocator.Error!*Map { |
| 1627 | if (index >= self.maps.items.len) |
| 1628 | try self.maps.appendNTimes(allocator, .{}, index + 1 - self.maps.items.len); |
| 1629 | return &self.maps.items[index]; |
| 1630 | } |
| 1631 | |
| 1632 | fn getMap(self: *Wip, index: usize) ?*Map { |
| 1633 | return if (index >= self.maps.items.len) null else &self.maps.items[index]; |
| 1634 | } |
| 1635 | |
| 1636 | fn ensureTotalLength(self: *Wip, new_len: usize) Allocator.Error!void { |
| 1637 | try self.maps.appendNTimes( |
| 1638 | .{}, |
| 1639 | std.math.sub(usize, new_len, self.maps.items.len) catch return, |
| 1640 | ); |
| 1641 | } |
| 1642 | }; |
| 1643 | |
| 1644 | pub fn func(self: FunctionAttributes, builder: *const Builder) Attributes { |
| 1645 | return self.get(function_index, builder); |
| 1646 | } |
| 1647 | |
| 1648 | pub fn ret(self: FunctionAttributes, builder: *const Builder) Attributes { |
| 1649 | return self.get(return_index, builder); |
| 1650 | } |
| 1651 | |
| 1652 | pub fn param(self: FunctionAttributes, param_index: usize, builder: *const Builder) Attributes { |
| 1653 | return self.get(params_index + param_index, builder); |
| 1654 | } |
| 1655 | |
| 1656 | pub fn toWip(self: FunctionAttributes, builder: *const Builder) Allocator.Error!Wip { |
| 1657 | var wip: Wip = .{}; |
| 1658 | errdefer wip.deinit(builder); |
| 1659 | const attributes_slice = self.slice(builder); |
| 1660 | try wip.maps.ensureTotalCapacityPrecise(builder.gpa, attributes_slice.len); |
| 1661 | for (attributes_slice) |attributes| { |
| 1662 | const map = wip.maps.addOneAssumeCapacity(); |
| 1663 | map.* = .{}; |
| 1664 | const attribute_slice = attributes.slice(builder); |
| 1665 | try map.ensureTotalCapacity(builder.gpa, attribute_slice.len); |
| 1666 | for (attributes.slice(builder)) |attribute| |
| 1667 | map.putAssumeCapacityNoClobber(attribute.getKind(builder), attribute); |
| 1668 | } |
| 1669 | return wip; |
| 1670 | } |
| 1671 | |
| 1672 | fn get(self: FunctionAttributes, index: usize, builder: *const Builder) Attributes { |
| 1673 | const attribute_slice = self.slice(builder); |
| 1674 | return if (index < attribute_slice.len) attribute_slice[index] else .none; |
| 1675 | } |
| 1676 | |
| 1677 | fn slice(self: FunctionAttributes, builder: *const Builder) []const Attributes { |
| 1678 | const start = builder.attributes_indices.items[@intFromEnum(self)]; |
| 1679 | const end = builder.attributes_indices.items[@intFromEnum(self) + 1]; |
| 1680 | return @ptrCast(builder.attributes_extra.items[start..end]); |
| 1681 | } |
| 1682 | }; |
| 1683 | |
| 826 | 1684 | pub const Linkage = enum { |
| 827 | 1685 | external, |
| 828 | 1686 | private, |
| ... | ... | @@ -1053,6 +1911,127 @@ pub const Alignment = enum(u6) { |
| 1053 | 1911 | } |
| 1054 | 1912 | }; |
| 1055 | 1913 | |
| 1914 | pub const CallConv = enum(u10) { |
| 1915 | ccc, |
| 1916 | |
| 1917 | fastcc = 8, |
| 1918 | coldcc, |
| 1919 | ghccc, |
| 1920 | |
| 1921 | webkit_jscc = 12, |
| 1922 | anyregcc, |
| 1923 | preserve_mostcc, |
| 1924 | preserve_allcc, |
| 1925 | swiftcc, |
| 1926 | cxx_fast_tlscc, |
| 1927 | tailcc, |
| 1928 | cfguard_checkcc, |
| 1929 | swifttailcc, |
| 1930 | |
| 1931 | x86_stdcallcc = 64, |
| 1932 | x86_fastcallcc, |
| 1933 | arm_apcscc, |
| 1934 | arm_aapcscc, |
| 1935 | arm_aapcs_vfpcc, |
| 1936 | msp430_intrcc, |
| 1937 | x86_thiscallcc, |
| 1938 | ptx_kernel, |
| 1939 | ptx_device, |
| 1940 | |
| 1941 | spir_func = 75, |
| 1942 | spir_kernel, |
| 1943 | intel_ocl_bicc, |
| 1944 | x86_64_sysvcc, |
| 1945 | win64cc, |
| 1946 | x86_vectorcallcc, |
| 1947 | hhvmcc, |
| 1948 | hhvm_ccc, |
| 1949 | x86_intrcc, |
| 1950 | avr_intrcc, |
| 1951 | avr_signalcc, |
| 1952 | |
| 1953 | amdgpu_vs = 87, |
| 1954 | amdgpu_gs, |
| 1955 | amdgpu_ps, |
| 1956 | amdgpu_cs, |
| 1957 | amdgpu_kernel, |
| 1958 | x86_regcallcc, |
| 1959 | amdgpu_hs, |
| 1960 | |
| 1961 | amdgpu_ls = 95, |
| 1962 | amdgpu_es, |
| 1963 | aarch64_vector_pcs, |
| 1964 | aarch64_sve_vector_pcs, |
| 1965 | |
| 1966 | amdgpu_gfx = 100, |
| 1967 | |
| 1968 | aarch64_sme_preservemost_from_x0 = 102, |
| 1969 | aarch64_sme_preservemost_from_x2, |
| 1970 | |
| 1971 | _, |
| 1972 | |
| 1973 | pub const default = CallConv.ccc; |
| 1974 | |
| 1975 | pub fn format( |
| 1976 | self: CallConv, |
| 1977 | comptime _: []const u8, |
| 1978 | _: std.fmt.FormatOptions, |
| 1979 | writer: anytype, |
| 1980 | ) @TypeOf(writer).Error!void { |
| 1981 | switch (self) { |
| 1982 | default => {}, |
| 1983 | .fastcc, |
| 1984 | .coldcc, |
| 1985 | .ghccc, |
| 1986 | .webkit_jscc, |
| 1987 | .anyregcc, |
| 1988 | .preserve_mostcc, |
| 1989 | .preserve_allcc, |
| 1990 | .swiftcc, |
| 1991 | .cxx_fast_tlscc, |
| 1992 | .tailcc, |
| 1993 | .cfguard_checkcc, |
| 1994 | .swifttailcc, |
| 1995 | .x86_stdcallcc, |
| 1996 | .x86_fastcallcc, |
| 1997 | .arm_apcscc, |
| 1998 | .arm_aapcscc, |
| 1999 | .arm_aapcs_vfpcc, |
| 2000 | .msp430_intrcc, |
| 2001 | .x86_thiscallcc, |
| 2002 | .ptx_kernel, |
| 2003 | .ptx_device, |
| 2004 | .spir_func, |
| 2005 | .spir_kernel, |
| 2006 | .intel_ocl_bicc, |
| 2007 | .x86_64_sysvcc, |
| 2008 | .win64cc, |
| 2009 | .x86_vectorcallcc, |
| 2010 | .hhvmcc, |
| 2011 | .hhvm_ccc, |
| 2012 | .x86_intrcc, |
| 2013 | .avr_intrcc, |
| 2014 | .avr_signalcc, |
| 2015 | .amdgpu_vs, |
| 2016 | .amdgpu_gs, |
| 2017 | .amdgpu_ps, |
| 2018 | .amdgpu_cs, |
| 2019 | .amdgpu_kernel, |
| 2020 | .x86_regcallcc, |
| 2021 | .amdgpu_hs, |
| 2022 | .amdgpu_ls, |
| 2023 | .amdgpu_es, |
| 2024 | .aarch64_vector_pcs, |
| 2025 | .aarch64_sve_vector_pcs, |
| 2026 | .amdgpu_gfx, |
| 2027 | .aarch64_sme_preservemost_from_x0, |
| 2028 | .aarch64_sme_preservemost_from_x2, |
| 2029 | => try writer.print(" {s}", .{@tagName(self)}), |
| 2030 | _ => try writer.print(" cc{d}", .{@intFromEnum(self)}), |
| 2031 | } |
| 2032 | } |
| 2033 | }; |
| 2034 | |
| 1056 | 2035 | pub const Global = struct { |
| 1057 | 2036 | linkage: Linkage = .external, |
| 1058 | 2037 | preemption: Preemption = .dso_preemptable, |
| ... | ... | @@ -1170,7 +2149,7 @@ pub const Global = struct { |
| 1170 | 2149 | fn updateName(self: Index, builder: *const Builder) void { |
| 1171 | 2150 | if (!builder.useLibLlvm()) return; |
| 1172 | 2151 | const index = @intFromEnum(self.unwrap(builder)); |
| 1173 | | const name_slice = self.name(builder).toSlice(builder) orelse ""; |
| 2152 | const name_slice = self.name(builder).slice(builder) orelse ""; |
| 1174 | 2153 | builder.llvm.globals.items[index].setValueName2(name_slice.ptr, name_slice.len); |
| 1175 | 2154 | } |
| 1176 | 2155 | |
| ... | ... | @@ -1301,6 +2280,8 @@ pub const Variable = struct { |
| 1301 | 2280 | |
| 1302 | 2281 | pub const Function = struct { |
| 1303 | 2282 | global: Global.Index, |
| 2283 | call_conv: CallConv = CallConv.default, |
| 2284 | attributes: FunctionAttributes = .none, |
| 1304 | 2285 | section: String = .none, |
| 1305 | 2286 | alignment: Alignment = .default, |
| 1306 | 2287 | blocks: []const Block = &.{}, |
| ... | ... | @@ -1364,6 +2345,8 @@ pub const Function = struct { |
| 1364 | 2345 | block, |
| 1365 | 2346 | br, |
| 1366 | 2347 | br_cond, |
| 2348 | call, |
| 2349 | @"call fast", |
| 1367 | 2350 | extractelement, |
| 1368 | 2351 | extractvalue, |
| 1369 | 2352 | fadd, |
| ... | ... | @@ -1454,6 +2437,10 @@ pub const Function = struct { |
| 1454 | 2437 | @"mul nsw", |
| 1455 | 2438 | @"mul nuw", |
| 1456 | 2439 | @"mul nuw nsw", |
| 2440 | @"musttail call", |
| 2441 | @"musttail call fast", |
| 2442 | @"notail call", |
| 2443 | @"notail call fast", |
| 1457 | 2444 | @"or", |
| 1458 | 2445 | phi, |
| 1459 | 2446 | @"phi fast", |
| ... | ... | @@ -1481,6 +2468,8 @@ pub const Function = struct { |
| 1481 | 2468 | @"sub nuw", |
| 1482 | 2469 | @"sub nuw nsw", |
| 1483 | 2470 | @"switch", |
| 2471 | @"tail call", |
| 2472 | @"tail call fast", |
| 1484 | 2473 | trunc, |
| 1485 | 2474 | udiv, |
| 1486 | 2475 | @"udiv exact", |
| ... | ... | @@ -1511,6 +2500,7 @@ pub const Function = struct { |
| 1511 | 2500 | .br_cond, |
| 1512 | 2501 | .ret, |
| 1513 | 2502 | .@"ret void", |
| 2503 | .@"switch", |
| 1514 | 2504 | .@"unreachable", |
| 1515 | 2505 | => true, |
| 1516 | 2506 | else => false, |
| ... | ... | @@ -1528,8 +2518,19 @@ pub const Function = struct { |
| 1528 | 2518 | .@"store atomic", |
| 1529 | 2519 | .@"store atomic volatile", |
| 1530 | 2520 | .@"store volatile", |
| 2521 | .@"switch", |
| 1531 | 2522 | .@"unreachable", |
| 1532 | 2523 | => false, |
| 2524 | .call, |
| 2525 | .@"call fast", |
| 2526 | .@"musttail call", |
| 2527 | .@"musttail call fast", |
| 2528 | .@"notail call", |
| 2529 | .@"notail call fast", |
| 2530 | .@"tail call", |
| 2531 | .@"tail call fast", |
| 2532 | .unimplemented, |
| 2533 | => self.typeOfWip(wip) != .void, |
| 1533 | 2534 | else => true, |
| 1534 | 2535 | }; |
| 1535 | 2536 | } |
| ... | ... | @@ -1625,6 +2626,15 @@ pub const Function = struct { |
| 1625 | 2626 | .@"switch", |
| 1626 | 2627 | .@"unreachable", |
| 1627 | 2628 | => .none, |
| 2629 | .call, |
| 2630 | .@"call fast", |
| 2631 | .@"musttail call", |
| 2632 | .@"musttail call fast", |
| 2633 | .@"notail call", |
| 2634 | .@"notail call fast", |
| 2635 | .@"tail call", |
| 2636 | .@"tail call fast", |
| 2637 | => wip.extraData(Call, instruction.data).ty.functionReturn(wip.builder), |
| 1628 | 2638 | .extractelement => wip.extraData(ExtractElement, instruction.data) |
| 1629 | 2639 | .val.typeOfWip(wip).childType(wip.builder), |
| 1630 | 2640 | .extractvalue => { |
| ... | ... | @@ -1813,6 +2823,15 @@ pub const Function = struct { |
| 1813 | 2823 | .@"switch", |
| 1814 | 2824 | .@"unreachable", |
| 1815 | 2825 | => .none, |
| 2826 | .call, |
| 2827 | .@"call fast", |
| 2828 | .@"musttail call", |
| 2829 | .@"musttail call fast", |
| 2830 | .@"notail call", |
| 2831 | .@"notail call fast", |
| 2832 | .@"tail call", |
| 2833 | .@"tail call fast", |
| 2834 | => function.extraData(Call, instruction.data).ty.functionReturn(builder), |
| 1816 | 2835 | .extractelement => function.extraData(ExtractElement, instruction.data) |
| 1817 | 2836 | .val.typeOf(function_index, builder).childType(builder), |
| 1818 | 2837 | .extractvalue => { |
| ... | ... | @@ -1955,7 +2974,7 @@ pub const Function = struct { |
| 1955 | 2974 | return if (wip.builder.strip) |
| 1956 | 2975 | "" |
| 1957 | 2976 | else |
| 1958 | | wip.names.items[@intFromEnum(self)].toSlice(wip.builder).?; |
| 2977 | wip.names.items[@intFromEnum(self)].slice(wip.builder).?; |
| 1959 | 2978 | } |
| 1960 | 2979 | }; |
| 1961 | 2980 | |
| ... | ... | @@ -2063,6 +3082,30 @@ pub const Function = struct { |
| 2063 | 3082 | rhs: Value, |
| 2064 | 3083 | }; |
| 2065 | 3084 | |
| 3085 | pub const Call = struct { |
| 3086 | info: Info, |
| 3087 | attributes: FunctionAttributes, |
| 3088 | ty: Type, |
| 3089 | callee: Value, |
| 3090 | args_len: u32, |
| 3091 | //args: [args_len]Value, |
| 3092 | |
| 3093 | pub const Kind = enum { |
| 3094 | normal, |
| 3095 | fast, |
| 3096 | musttail, |
| 3097 | musttail_fast, |
| 3098 | notail, |
| 3099 | notail_fast, |
| 3100 | tail, |
| 3101 | tail_fast, |
| 3102 | }; |
| 3103 | pub const Info = packed struct(u32) { |
| 3104 | call_conv: CallConv, |
| 3105 | _: u22 = undefined, |
| 3106 | }; |
| 3107 | }; |
| 3108 | |
| 2066 | 3109 | pub const VaArg = struct { |
| 2067 | 3110 | list: Value, |
| 2068 | 3111 | type: Type, |
| ... | ... | @@ -2117,8 +3160,17 @@ pub const Function = struct { |
| 2117 | 3160 | inline for (fields, self.extra[index..][0..fields.len]) |field, value| |
| 2118 | 3161 | @field(result, field.name) = switch (field.type) { |
| 2119 | 3162 | u32 => value, |
| 2120 | | Alignment, AtomicOrdering, Block.Index, Type, Value => @enumFromInt(value), |
| 2121 | | MemoryAccessInfo, Instruction.Alloca.Info => @bitCast(value), |
| 3163 | Alignment, |
| 3164 | AtomicOrdering, |
| 3165 | Block.Index, |
| 3166 | FunctionAttributes, |
| 3167 | Type, |
| 3168 | Value, |
| 3169 | => @enumFromInt(value), |
| 3170 | MemoryAccessInfo, |
| 3171 | Instruction.Alloca.Info, |
| 3172 | Instruction.Call.Info, |
| 3173 | => @bitCast(value), |
| 2122 | 3174 | else => @compileError("bad field type: " ++ @typeName(field.type)), |
| 2123 | 3175 | }; |
| 2124 | 3176 | return .{ |
| ... | ... | @@ -2243,7 +3295,7 @@ pub const WipFunction = struct { |
| 2243 | 3295 | if (self.builder.useLibLlvm()) self.llvm.blocks.appendAssumeCapacity( |
| 2244 | 3296 | self.builder.llvm.context.appendBasicBlock( |
| 2245 | 3297 | self.function.toLlvm(self.builder), |
| 2246 | | final_name.toSlice(self.builder).?, |
| 3298 | final_name.slice(self.builder).?, |
| 2247 | 3299 | ), |
| 2248 | 3300 | ); |
| 2249 | 3301 | return index; |
| ... | ... | @@ -2755,7 +3807,7 @@ pub const WipFunction = struct { |
| 2755 | 3807 | @intFromEnum(addr_space), |
| 2756 | 3808 | instruction.llvmName(self), |
| 2757 | 3809 | ); |
| 2758 | | if (alignment.toByteUnits()) |a| llvm_instruction.setAlignment(@intCast(a)); |
| 3810 | if (alignment.toByteUnits()) |bytes| llvm_instruction.setAlignment(@intCast(bytes)); |
| 2759 | 3811 | self.llvm.instructions.appendAssumeCapacity(llvm_instruction); |
| 2760 | 3812 | } |
| 2761 | 3813 | return instruction.toValue(); |
| ... | ... | @@ -2811,7 +3863,7 @@ pub const WipFunction = struct { |
| 2811 | 3863 | instruction.llvmName(self), |
| 2812 | 3864 | ); |
| 2813 | 3865 | if (ordering != .none) llvm_instruction.setOrdering(@enumFromInt(@intFromEnum(ordering))); |
| 2814 | | if (alignment.toByteUnits()) |a| llvm_instruction.setAlignment(@intCast(a)); |
| 3866 | if (alignment.toByteUnits()) |bytes| llvm_instruction.setAlignment(@intCast(bytes)); |
| 2815 | 3867 | self.llvm.instructions.appendAssumeCapacity(llvm_instruction); |
| 2816 | 3868 | } |
| 2817 | 3869 | return instruction.toValue(); |
| ... | ... | @@ -2865,7 +3917,7 @@ pub const WipFunction = struct { |
| 2865 | 3917 | .@"volatile" => llvm_instruction.setVolatile(.True), |
| 2866 | 3918 | } |
| 2867 | 3919 | if (ordering != .none) llvm_instruction.setOrdering(@enumFromInt(@intFromEnum(ordering))); |
| 2868 | | if (alignment.toByteUnits()) |a| llvm_instruction.setAlignment(@intCast(a)); |
| 3920 | if (alignment.toByteUnits()) |bytes| llvm_instruction.setAlignment(@intCast(bytes)); |
| 2869 | 3921 | self.llvm.instructions.appendAssumeCapacity(llvm_instruction); |
| 2870 | 3922 | } |
| 2871 | 3923 | return instruction; |
| ... | ... | @@ -3162,6 +4214,102 @@ pub const WipFunction = struct { |
| 3162 | 4214 | return self.selectTag(.@"select fast", cond, lhs, rhs, name); |
| 3163 | 4215 | } |
| 3164 | 4216 | |
| 4217 | pub fn call( |
| 4218 | self: *WipFunction, |
| 4219 | kind: Instruction.Call.Kind, |
| 4220 | call_conv: CallConv, |
| 4221 | function_attributes: FunctionAttributes, |
| 4222 | ty: Type, |
| 4223 | callee: Value, |
| 4224 | args: []const Value, |
| 4225 | name: []const u8, |
| 4226 | ) Allocator.Error!Value { |
| 4227 | const ret_ty = ty.functionReturn(self.builder); |
| 4228 | assert(ty.isFunction(self.builder)); |
| 4229 | assert(callee.typeOfWip(self).isPointer(self.builder)); |
| 4230 | const params = ty.functionParameters(self.builder); |
| 4231 | for (params, args[0..params.len]) |param, arg_val| assert(param == arg_val.typeOfWip(self)); |
| 4232 | |
| 4233 | try self.ensureUnusedExtraCapacity(1, Instruction.Call, args.len); |
| 4234 | const instruction = try self.addInst(switch (ret_ty) { |
| 4235 | .void => null, |
| 4236 | else => name, |
| 4237 | }, .{ |
| 4238 | .tag = .call, |
| 4239 | .data = self.addExtraAssumeCapacity(Instruction.Call{ |
| 4240 | .info = .{ .call_conv = call_conv }, |
| 4241 | .attributes = function_attributes, |
| 4242 | .ty = ty, |
| 4243 | .callee = callee, |
| 4244 | .args_len = @intCast(args.len), |
| 4245 | }), |
| 4246 | }); |
| 4247 | self.extra.appendSliceAssumeCapacity(@ptrCast(args)); |
| 4248 | if (self.builder.useLibLlvm()) { |
| 4249 | const ExpectedContents = [expected_args_len]*llvm.Value; |
| 4250 | var stack align(@alignOf(ExpectedContents)) = |
| 4251 | std.heap.stackFallback(@sizeOf(ExpectedContents), self.builder.gpa); |
| 4252 | const allocator = stack.get(); |
| 4253 | |
| 4254 | const llvm_args = try allocator.alloc(*llvm.Value, args.len); |
| 4255 | defer allocator.free(llvm_args); |
| 4256 | for (llvm_args, args) |*llvm_arg, arg_val| llvm_arg.* = arg_val.toLlvm(self); |
| 4257 | |
| 4258 | switch (kind) { |
| 4259 | .normal, |
| 4260 | .musttail, |
| 4261 | .notail, |
| 4262 | .tail, |
| 4263 | => self.llvm.builder.setFastMath(false), |
| 4264 | .fast, |
| 4265 | .musttail_fast, |
| 4266 | .notail_fast, |
| 4267 | .tail_fast, |
| 4268 | => self.llvm.builder.setFastMath(true), |
| 4269 | } |
| 4270 | const llvm_instruction = self.llvm.builder.buildCall( |
| 4271 | ty.toLlvm(self.builder), |
| 4272 | callee.toLlvm(self), |
| 4273 | llvm_args.ptr, |
| 4274 | @intCast(llvm_args.len), |
| 4275 | switch (ret_ty) { |
| 4276 | .void => "", |
| 4277 | else => instruction.llvmName(self), |
| 4278 | }, |
| 4279 | ); |
| 4280 | llvm_instruction.setInstructionCallConv(@enumFromInt(@intFromEnum(call_conv))); |
| 4281 | llvm_instruction.setTailCallKind(switch (kind) { |
| 4282 | .normal, .fast => .None, |
| 4283 | .musttail, .musttail_fast => .MustTail, |
| 4284 | .notail, .notail_fast => .NoTail, |
| 4285 | .tail, .tail_fast => .Tail, |
| 4286 | }); |
| 4287 | for (0.., function_attributes.slice(self.builder)) |index, attributes| { |
| 4288 | const attribute_index = @as(llvm.AttributeIndex, @intCast(index)) -% 1; |
| 4289 | for (attributes.slice(self.builder)) |attribute| llvm_instruction.addCallSiteAttribute( |
| 4290 | attribute_index, |
| 4291 | attribute.toLlvm(self.builder), |
| 4292 | ); |
| 4293 | } |
| 4294 | self.llvm.instructions.appendAssumeCapacity(llvm_instruction); |
| 4295 | } |
| 4296 | return instruction.toValue(); |
| 4297 | } |
| 4298 | |
| 4299 | pub fn callAsm( |
| 4300 | self: *WipFunction, |
| 4301 | function_attributes: FunctionAttributes, |
| 4302 | ty: Type, |
| 4303 | kind: Constant.Asm.Info, |
| 4304 | assembly: String, |
| 4305 | constraints: String, |
| 4306 | args: []const Value, |
| 4307 | name: []const u8, |
| 4308 | ) Allocator.Error!Value { |
| 4309 | const callee = try self.builder.asmValue(ty, kind, assembly, constraints); |
| 4310 | return self.call(.normal, CallConv.default, function_attributes, ty, callee, args, name); |
| 4311 | } |
| 4312 | |
| 3165 | 4313 | pub fn vaArg(self: *WipFunction, list: Value, ty: Type, name: []const u8) Allocator.Error!Value { |
| 3166 | 4314 | try self.ensureUnusedExtraCapacity(1, Instruction.VaArg, 0); |
| 3167 | 4315 | const instruction = try self.addInst(name, .{ |
| ... | ... | @@ -3246,8 +4394,17 @@ pub const WipFunction = struct { |
| 3246 | 4394 | const value = @field(extra, field.name); |
| 3247 | 4395 | wip_extra.items[wip_extra.index] = switch (field.type) { |
| 3248 | 4396 | u32 => value, |
| 3249 | | Alignment, AtomicOrdering, Block.Index, Type, Value => @intFromEnum(value), |
| 3250 | | MemoryAccessInfo, Instruction.Alloca.Info => @bitCast(value), |
| 4397 | Alignment, |
| 4398 | AtomicOrdering, |
| 4399 | Block.Index, |
| 4400 | FunctionAttributes, |
| 4401 | Type, |
| 4402 | Value, |
| 4403 | => @intFromEnum(value), |
| 4404 | MemoryAccessInfo, |
| 4405 | Instruction.Alloca.Info, |
| 4406 | Instruction.Call.Info, |
| 4407 | => @bitCast(value), |
| 3251 | 4408 | else => @compileError("bad field type: " ++ @typeName(field.type)), |
| 3252 | 4409 | }; |
| 3253 | 4410 | wip_extra.index += 1; |
| ... | ... | @@ -3256,13 +4413,14 @@ pub const WipFunction = struct { |
| 3256 | 4413 | } |
| 3257 | 4414 | |
| 3258 | 4415 | fn appendSlice(wip_extra: *@This(), slice: anytype) void { |
| 3259 | | if (@typeInfo(@TypeOf(slice)).Pointer.child == Value) @compileError("use appendValues"); |
| 4416 | if (@typeInfo(@TypeOf(slice)).Pointer.child == Value) |
| 4417 | @compileError("use appendMappedValues"); |
| 3260 | 4418 | const data: []const u32 = @ptrCast(slice); |
| 3261 | 4419 | @memcpy(wip_extra.items[wip_extra.index..][0..data.len], data); |
| 3262 | 4420 | wip_extra.index += @intCast(data.len); |
| 3263 | 4421 | } |
| 3264 | 4422 | |
| 3265 | | fn appendValues(wip_extra: *@This(), vals: []const Value, ctx: anytype) void { |
| 4423 | fn appendMappedValues(wip_extra: *@This(), vals: []const Value, ctx: anytype) void { |
| 3266 | 4424 | for (wip_extra.items[wip_extra.index..][0..vals.len], vals) |*extra, val| |
| 3267 | 4425 | extra.* = @intFromEnum(ctx.map(val)); |
| 3268 | 4426 | wip_extra.index += @intCast(vals.len); |
| ... | ... | @@ -3494,6 +4652,26 @@ pub const WipFunction = struct { |
| 3494 | 4652 | .@"else" = extra.@"else", |
| 3495 | 4653 | }); |
| 3496 | 4654 | }, |
| 4655 | .call, |
| 4656 | .@"call fast", |
| 4657 | .@"musttail call", |
| 4658 | .@"musttail call fast", |
| 4659 | .@"notail call", |
| 4660 | .@"notail call fast", |
| 4661 | .@"tail call", |
| 4662 | .@"tail call fast", |
| 4663 | => { |
| 4664 | var extra = self.extraDataTrail(Instruction.Call, instruction.data); |
| 4665 | const args = extra.trail.next(extra.data.args_len, Value, self); |
| 4666 | instruction.data = wip_extra.addExtra(Instruction.Call{ |
| 4667 | .info = extra.data.info, |
| 4668 | .attributes = extra.data.attributes, |
| 4669 | .ty = extra.data.ty, |
| 4670 | .callee = instructions.map(extra.data.callee), |
| 4671 | .args_len = extra.data.args_len, |
| 4672 | }); |
| 4673 | wip_extra.appendMappedValues(args, instructions); |
| 4674 | }, |
| 3497 | 4675 | .extractvalue => { |
| 3498 | 4676 | var extra = self.extraDataTrail(Instruction.ExtractValue, instruction.data); |
| 3499 | 4677 | const indices = extra.trail.next(extra.data.indices_len, u32, self); |
| ... | ... | @@ -3517,7 +4695,7 @@ pub const WipFunction = struct { |
| 3517 | 4695 | .base = instructions.map(extra.data.base), |
| 3518 | 4696 | .indices_len = extra.data.indices_len, |
| 3519 | 4697 | }); |
| 3520 | | wip_extra.appendValues(indices, instructions); |
| 4698 | wip_extra.appendMappedValues(indices, instructions); |
| 3521 | 4699 | }, |
| 3522 | 4700 | .insertelement => { |
| 3523 | 4701 | const extra = self.extraData(Instruction.InsertElement, instruction.data); |
| ... | ... | @@ -3559,7 +4737,7 @@ pub const WipFunction = struct { |
| 3559 | 4737 | instruction.data = wip_extra.addExtra(Instruction.Phi{ |
| 3560 | 4738 | .type = extra.data.type, |
| 3561 | 4739 | }); |
| 3562 | | wip_extra.appendValues(incoming_vals, instructions); |
| 4740 | wip_extra.appendMappedValues(incoming_vals, instructions); |
| 3563 | 4741 | wip_extra.appendSlice(incoming_blocks); |
| 3564 | 4742 | }, |
| 3565 | 4743 | .select, |
| ... | ... | @@ -3932,8 +5110,17 @@ pub const WipFunction = struct { |
| 3932 | 5110 | const value = @field(extra, field.name); |
| 3933 | 5111 | self.extra.appendAssumeCapacity(switch (field.type) { |
| 3934 | 5112 | u32 => value, |
| 3935 | | Alignment, AtomicOrdering, Block.Index, Type, Value => @intFromEnum(value), |
| 3936 | | MemoryAccessInfo, Instruction.Alloca.Info => @bitCast(value), |
| 5113 | Alignment, |
| 5114 | AtomicOrdering, |
| 5115 | Block.Index, |
| 5116 | FunctionAttributes, |
| 5117 | Type, |
| 5118 | Value, |
| 5119 | => @intFromEnum(value), |
| 5120 | MemoryAccessInfo, |
| 5121 | Instruction.Alloca.Info, |
| 5122 | Instruction.Call.Info, |
| 5123 | => @bitCast(value), |
| 3937 | 5124 | else => @compileError("bad field type: " ++ @typeName(field.type)), |
| 3938 | 5125 | }); |
| 3939 | 5126 | } |
| ... | ... | @@ -3971,8 +5158,17 @@ pub const WipFunction = struct { |
| 3971 | 5158 | inline for (fields, self.extra.items[index..][0..fields.len]) |field, value| |
| 3972 | 5159 | @field(result, field.name) = switch (field.type) { |
| 3973 | 5160 | u32 => value, |
| 3974 | | Alignment, AtomicOrdering, Block.Index, Type, Value => @enumFromInt(value), |
| 3975 | | MemoryAccessInfo, Instruction.Alloca.Info => @bitCast(value), |
| 5161 | Alignment, |
| 5162 | AtomicOrdering, |
| 5163 | Block.Index, |
| 5164 | FunctionAttributes, |
| 5165 | Type, |
| 5166 | Value, |
| 5167 | => @enumFromInt(value), |
| 5168 | MemoryAccessInfo, |
| 5169 | Instruction.Alloca.Info, |
| 5170 | Instruction.Call.Info, |
| 5171 | => @bitCast(value), |
| 3976 | 5172 | else => @compileError("bad field type: " ++ @typeName(field.type)), |
| 3977 | 5173 | }; |
| 3978 | 5174 | return .{ |
| ... | ... | @@ -4092,7 +5288,7 @@ pub const Constant = enum(u32) { |
| 4092 | 5288 | |
| 4093 | 5289 | const first_global: Constant = @enumFromInt(1 << 30); |
| 4094 | 5290 | |
| 4095 | | pub const Tag = enum(u6) { |
| 5291 | pub const Tag = enum(u7) { |
| 4096 | 5292 | positive_integer, |
| 4097 | 5293 | negative_integer, |
| 4098 | 5294 | half, |
| ... | ... | @@ -4152,6 +5348,22 @@ pub const Constant = enum(u32) { |
| 4152 | 5348 | @"and", |
| 4153 | 5349 | @"or", |
| 4154 | 5350 | xor, |
| 5351 | @"asm", |
| 5352 | @"asm sideeffect", |
| 5353 | @"asm alignstack", |
| 5354 | @"asm sideeffect alignstack", |
| 5355 | @"asm inteldialect", |
| 5356 | @"asm sideeffect inteldialect", |
| 5357 | @"asm alignstack inteldialect", |
| 5358 | @"asm sideeffect alignstack inteldialect", |
| 5359 | @"asm unwind", |
| 5360 | @"asm sideeffect unwind", |
| 5361 | @"asm alignstack unwind", |
| 5362 | @"asm sideeffect alignstack unwind", |
| 5363 | @"asm inteldialect unwind", |
| 5364 | @"asm sideeffect inteldialect unwind", |
| 5365 | @"asm alignstack inteldialect unwind", |
| 5366 | @"asm sideeffect alignstack inteldialect unwind", |
| 4155 | 5367 | }; |
| 4156 | 5368 | |
| 4157 | 5369 | pub const Item = struct { |
| ... | ... | @@ -4247,6 +5459,19 @@ pub const Constant = enum(u32) { |
| 4247 | 5459 | rhs: Constant, |
| 4248 | 5460 | }; |
| 4249 | 5461 | |
| 5462 | pub const Asm = extern struct { |
| 5463 | type: Type, |
| 5464 | assembly: String, |
| 5465 | constraints: String, |
| 5466 | |
| 5467 | pub const Info = packed struct { |
| 5468 | sideeffect: bool = false, |
| 5469 | alignstack: bool = false, |
| 5470 | inteldialect: bool = false, |
| 5471 | unwind: bool = false, |
| 5472 | }; |
| 5473 | }; |
| 5474 | |
| 4250 | 5475 | pub fn unwrap(self: Constant) union(enum) { |
| 4251 | 5476 | constant: u30, |
| 4252 | 5477 | global: Global.Index, |
| ... | ... | @@ -4294,7 +5519,7 @@ pub const Constant = enum(u32) { |
| 4294 | 5519 | .string, |
| 4295 | 5520 | .string_null, |
| 4296 | 5521 | => builder.arrayTypeAssumeCapacity( |
| 4297 | | @as(String, @enumFromInt(item.data)).toSlice(builder).?.len + |
| 5522 | @as(String, @enumFromInt(item.data)).slice(builder).?.len + |
| 4298 | 5523 | @intFromBool(item.tag == .string_null), |
| 4299 | 5524 | .i8, |
| 4300 | 5525 | ), |
| ... | ... | @@ -4365,6 +5590,23 @@ pub const Constant = enum(u32) { |
| 4365 | 5590 | .@"or", |
| 4366 | 5591 | .xor, |
| 4367 | 5592 | => builder.constantExtraData(Binary, item.data).lhs.typeOf(builder), |
| 5593 | .@"asm", |
| 5594 | .@"asm sideeffect", |
| 5595 | .@"asm alignstack", |
| 5596 | .@"asm sideeffect alignstack", |
| 5597 | .@"asm inteldialect", |
| 5598 | .@"asm sideeffect inteldialect", |
| 5599 | .@"asm alignstack inteldialect", |
| 5600 | .@"asm sideeffect alignstack inteldialect", |
| 5601 | .@"asm unwind", |
| 5602 | .@"asm sideeffect unwind", |
| 5603 | .@"asm alignstack unwind", |
| 5604 | .@"asm sideeffect alignstack unwind", |
| 5605 | .@"asm inteldialect unwind", |
| 5606 | .@"asm sideeffect inteldialect unwind", |
| 5607 | .@"asm alignstack inteldialect unwind", |
| 5608 | .@"asm sideeffect alignstack inteldialect unwind", |
| 5609 | => .ptr, |
| 4368 | 5610 | }; |
| 4369 | 5611 | }, |
| 4370 | 5612 | .global => |global| return builder.ptrTypeAssumeCapacity( |
| ... | ... | @@ -4712,6 +5954,30 @@ pub const Constant = enum(u32) { |
| 4712 | 5954 | extra.rhs.fmt(data.builder), |
| 4713 | 5955 | }); |
| 4714 | 5956 | }, |
| 5957 | .@"asm", |
| 5958 | .@"asm sideeffect", |
| 5959 | .@"asm alignstack", |
| 5960 | .@"asm sideeffect alignstack", |
| 5961 | .@"asm inteldialect", |
| 5962 | .@"asm sideeffect inteldialect", |
| 5963 | .@"asm alignstack inteldialect", |
| 5964 | .@"asm sideeffect alignstack inteldialect", |
| 5965 | .@"asm unwind", |
| 5966 | .@"asm sideeffect unwind", |
| 5967 | .@"asm alignstack unwind", |
| 5968 | .@"asm sideeffect alignstack unwind", |
| 5969 | .@"asm inteldialect unwind", |
| 5970 | .@"asm sideeffect inteldialect unwind", |
| 5971 | .@"asm alignstack inteldialect unwind", |
| 5972 | .@"asm sideeffect alignstack inteldialect unwind", |
| 5973 | => |tag| { |
| 5974 | const extra = data.builder.constantExtraData(Asm, item.data); |
| 5975 | try writer.print("{s} {\"}, {\"}", .{ |
| 5976 | @tagName(tag), |
| 5977 | extra.assembly.fmt(data.builder), |
| 5978 | extra.constraints.fmt(data.builder), |
| 5979 | }); |
| 5980 | }, |
| 4715 | 5981 | } |
| 4716 | 5982 | }, |
| 4717 | 5983 | .global => |global| try writer.print("{}", .{global.fmt(data.builder)}), |
| ... | ... | @@ -4819,10 +6085,11 @@ pub fn init(options: Options) InitError!Builder { |
| 4819 | 6085 | .source_filename = .none, |
| 4820 | 6086 | .data_layout = .none, |
| 4821 | 6087 | .target_triple = .none, |
| 6088 | .module_asm = .{}, |
| 4822 | 6089 | |
| 4823 | 6090 | .string_map = .{}, |
| 4824 | | .string_bytes = .{}, |
| 4825 | 6091 | .string_indices = .{}, |
| 6092 | .string_bytes = .{}, |
| 4826 | 6093 | |
| 4827 | 6094 | .types = .{}, |
| 4828 | 6095 | .next_unnamed_type = @enumFromInt(0), |
| ... | ... | @@ -4831,6 +6098,11 @@ pub fn init(options: Options) InitError!Builder { |
| 4831 | 6098 | .type_items = .{}, |
| 4832 | 6099 | .type_extra = .{}, |
| 4833 | 6100 | |
| 6101 | .attributes = .{}, |
| 6102 | .attributes_map = .{}, |
| 6103 | .attributes_indices = .{}, |
| 6104 | .attributes_extra = .{}, |
| 6105 | |
| 4834 | 6106 | .globals = .{}, |
| 4835 | 6107 | .next_unnamed_global = @enumFromInt(0), |
| 4836 | 6108 | .next_replaced_global = .none, |
| ... | ... | @@ -4844,7 +6116,18 @@ pub fn init(options: Options) InitError!Builder { |
| 4844 | 6116 | .constant_extra = .{}, |
| 4845 | 6117 | .constant_limbs = .{}, |
| 4846 | 6118 | }; |
| 4847 | | if (self.useLibLlvm()) self.llvm = .{ .context = llvm.Context.create() }; |
| 6119 | if (self.useLibLlvm()) self.llvm = .{ |
| 6120 | .context = llvm.Context.create(), |
| 6121 | .module = null, |
| 6122 | .target = null, |
| 6123 | .di_builder = null, |
| 6124 | .di_compile_unit = null, |
| 6125 | .attribute_kind_ids = null, |
| 6126 | .attributes = .{}, |
| 6127 | .types = .{}, |
| 6128 | .globals = .{}, |
| 6129 | .constants = .{}, |
| 6130 | }; |
| 4848 | 6131 | errdefer self.deinit(); |
| 4849 | 6132 | |
| 4850 | 6133 | try self.string_indices.append(self.gpa, 0); |
| ... | ... | @@ -4853,7 +6136,7 @@ pub fn init(options: Options) InitError!Builder { |
| 4853 | 6136 | if (options.name.len > 0) self.source_filename = try self.string(options.name); |
| 4854 | 6137 | self.initializeLLVMTarget(options.target.cpu.arch); |
| 4855 | 6138 | if (self.useLibLlvm()) self.llvm.module = llvm.Module.createWithName( |
| 4856 | | (self.source_filename.toSlice(&self) orelse "").ptr, |
| 6139 | (self.source_filename.slice(&self) orelse "").ptr, |
| 4857 | 6140 | self.llvm.context, |
| 4858 | 6141 | ); |
| 4859 | 6142 | |
| ... | ... | @@ -4864,20 +6147,20 @@ pub fn init(options: Options) InitError!Builder { |
| 4864 | 6147 | var error_message: [*:0]const u8 = undefined; |
| 4865 | 6148 | var target: *llvm.Target = undefined; |
| 4866 | 6149 | if (llvm.Target.getFromTriple( |
| 4867 | | self.target_triple.toSlice(&self).?, |
| 6150 | self.target_triple.slice(&self).?, |
| 4868 | 6151 | &target, |
| 4869 | 6152 | &error_message, |
| 4870 | 6153 | ).toBool()) { |
| 4871 | 6154 | defer llvm.disposeMessage(error_message); |
| 4872 | 6155 | |
| 4873 | 6156 | log.err("LLVM failed to parse '{s}': {s}", .{ |
| 4874 | | self.target_triple.toSlice(&self).?, |
| 6157 | self.target_triple.slice(&self).?, |
| 4875 | 6158 | error_message, |
| 4876 | 6159 | }); |
| 4877 | 6160 | return InitError.InvalidLlvmTriple; |
| 4878 | 6161 | } |
| 4879 | 6162 | self.llvm.target = target; |
| 4880 | | self.llvm.module.?.setTarget(self.target_triple.toSlice(&self).?); |
| 6163 | self.llvm.module.?.setTarget(self.target_triple.slice(&self).?); |
| 4881 | 6164 | } |
| 4882 | 6165 | } |
| 4883 | 6166 | |
| ... | ... | @@ -4902,6 +6185,16 @@ pub fn init(options: Options) InitError!Builder { |
| 4902 | 6185 | assert(self.ptrTypeAssumeCapacity(@enumFromInt(addr_space)) == .ptr); |
| 4903 | 6186 | } |
| 4904 | 6187 | |
| 6188 | { |
| 6189 | if (self.useLibLlvm()) { |
| 6190 | self.llvm.attribute_kind_ids = try self.gpa.create([Attribute.Kind.len]c_uint); |
| 6191 | @memset(self.llvm.attribute_kind_ids.?, 0); |
| 6192 | } |
| 6193 | try self.attributes_indices.append(self.gpa, 0); |
| 6194 | assert(try self.attrs(&.{}) == .none); |
| 6195 | assert(try self.fnAttrs(&.{}) == .none); |
| 6196 | } |
| 6197 | |
| 4905 | 6198 | assert(try self.intConst(.i1, 0) == .false); |
| 4906 | 6199 | assert(try self.intConst(.i1, 1) == .true); |
| 4907 | 6200 | assert(try self.noneConst(.token) == .none); |
| ... | ... | @@ -4910,9 +6203,11 @@ pub fn init(options: Options) InitError!Builder { |
| 4910 | 6203 | } |
| 4911 | 6204 | |
| 4912 | 6205 | pub fn deinit(self: *Builder) void { |
| 6206 | self.module_asm.deinit(self.gpa); |
| 6207 | |
| 4913 | 6208 | self.string_map.deinit(self.gpa); |
| 4914 | | self.string_bytes.deinit(self.gpa); |
| 4915 | 6209 | self.string_indices.deinit(self.gpa); |
| 6210 | self.string_bytes.deinit(self.gpa); |
| 4916 | 6211 | |
| 4917 | 6212 | self.types.deinit(self.gpa); |
| 4918 | 6213 | self.next_unique_type_id.deinit(self.gpa); |
| ... | ... | @@ -4920,6 +6215,11 @@ pub fn deinit(self: *Builder) void { |
| 4920 | 6215 | self.type_items.deinit(self.gpa); |
| 4921 | 6216 | self.type_extra.deinit(self.gpa); |
| 4922 | 6217 | |
| 6218 | self.attributes.deinit(self.gpa); |
| 6219 | self.attributes_map.deinit(self.gpa); |
| 6220 | self.attributes_indices.deinit(self.gpa); |
| 6221 | self.attributes_extra.deinit(self.gpa); |
| 6222 | |
| 4923 | 6223 | self.globals.deinit(self.gpa); |
| 4924 | 6224 | self.next_unique_global_id.deinit(self.gpa); |
| 4925 | 6225 | self.aliases.deinit(self.gpa); |
| ... | ... | @@ -4936,6 +6236,8 @@ pub fn deinit(self: *Builder) void { |
| 4936 | 6236 | self.llvm.constants.deinit(self.gpa); |
| 4937 | 6237 | self.llvm.globals.deinit(self.gpa); |
| 4938 | 6238 | self.llvm.types.deinit(self.gpa); |
| 6239 | self.llvm.attributes.deinit(self.gpa); |
| 6240 | if (self.llvm.attribute_kind_ids) |attribute_kind_ids| self.gpa.destroy(attribute_kind_ids); |
| 4939 | 6241 | if (self.llvm.di_builder) |di_builder| di_builder.dispose(); |
| 4940 | 6242 | if (self.llvm.module) |module| module.dispose(); |
| 4941 | 6243 | self.llvm.context.dispose(); |
| ... | ... | @@ -5136,6 +6438,22 @@ pub fn initializeLLVMTarget(self: *const Builder, arch: std.Target.Cpu.Arch) voi |
| 5136 | 6438 | } |
| 5137 | 6439 | } |
| 5138 | 6440 | |
| 6441 | pub fn setModuleAsm(self: *Builder) std.ArrayListUnmanaged(u8).Writer { |
| 6442 | self.module_asm.clearRetainingCapacity(); |
| 6443 | return self.appendModuleAsm(); |
| 6444 | } |
| 6445 | |
| 6446 | pub fn appendModuleAsm(self: *Builder) std.ArrayListUnmanaged(u8).Writer { |
| 6447 | return self.module_asm.writer(self.gpa); |
| 6448 | } |
| 6449 | |
| 6450 | pub fn finishModuleAsm(self: *Builder) Allocator.Error!void { |
| 6451 | if (self.module_asm.getLastOrNull()) |last| if (last != '\n') |
| 6452 | try self.module_asm.append(self.gpa, '\n'); |
| 6453 | if (self.useLibLlvm()) |
| 6454 | self.llvm.module.?.setModuleInlineAsm(self.module_asm.items.ptr, self.module_asm.items.len); |
| 6455 | } |
| 6456 | |
| 5139 | 6457 | pub fn string(self: *Builder, bytes: []const u8) Allocator.Error!String { |
| 5140 | 6458 | try self.string_bytes.ensureUnusedCapacity(self.gpa, bytes.len + 1); |
| 5141 | 6459 | try self.string_indices.ensureUnusedCapacity(self.gpa, 1); |
| ... | ... | @@ -5230,7 +6548,7 @@ pub fn structType( |
| 5230 | 6548 | |
| 5231 | 6549 | pub fn opaqueType(self: *Builder, name: String) Allocator.Error!Type { |
| 5232 | 6550 | try self.string_map.ensureUnusedCapacity(self.gpa, 1); |
| 5233 | | if (name.toSlice(self)) |id| { |
| 6551 | if (name.slice(self)) |id| { |
| 5234 | 6552 | const count: usize = comptime std.fmt.count("{d}" ++ .{0}, .{std.math.maxInt(u32)}); |
| 5235 | 6553 | try self.string_bytes.ensureUnusedCapacity(self.gpa, id.len + count); |
| 5236 | 6554 | } |
| ... | ... | @@ -5268,6 +6586,99 @@ pub fn namedTypeSetBody( |
| 5268 | 6586 | } |
| 5269 | 6587 | } |
| 5270 | 6588 | |
| 6589 | pub fn attr(self: *Builder, attribute: Attribute) Allocator.Error!Attribute.Index { |
| 6590 | try self.attributes.ensureUnusedCapacity(self.gpa, 1); |
| 6591 | if (self.useLibLlvm()) try self.llvm.attributes.ensureUnusedCapacity(self.gpa, 1); |
| 6592 | |
| 6593 | const gop = self.attributes.getOrPutAssumeCapacity(attribute.toStorage()); |
| 6594 | if (!gop.found_existing) { |
| 6595 | gop.value_ptr.* = {}; |
| 6596 | if (self.useLibLlvm()) self.llvm.attributes.appendAssumeCapacity(switch (attribute) { |
| 6597 | else => llvm_attr: { |
| 6598 | const kind_id = &self.llvm.attribute_kind_ids.?[@intFromEnum(attribute)]; |
| 6599 | if (kind_id.* == 0) { |
| 6600 | const name = @tagName(attribute); |
| 6601 | kind_id.* = llvm.getEnumAttributeKindForName(name.ptr, name.len); |
| 6602 | assert(kind_id.* != 0); |
| 6603 | } |
| 6604 | break :llvm_attr switch (attribute) { |
| 6605 | else => switch (attribute) { |
| 6606 | inline else => |value| self.llvm.context.createEnumAttribute( |
| 6607 | kind_id.*, |
| 6608 | switch (@TypeOf(value)) { |
| 6609 | void => 0, |
| 6610 | u32 => value, |
| 6611 | Attribute.FpClass, |
| 6612 | Attribute.AllocKind, |
| 6613 | Attribute.Memory, |
| 6614 | => @as(u32, @bitCast(value)), |
| 6615 | Alignment => value.toByteUnits() orelse 0, |
| 6616 | Attribute.AllocSize, |
| 6617 | Attribute.VScaleRange, |
| 6618 | => @bitCast(value.toLlvm()), |
| 6619 | Attribute.UwTable => @intFromEnum(value), |
| 6620 | else => @compileError( |
| 6621 | "bad payload type: " ++ @typeName(@TypeOf(value)), |
| 6622 | ), |
| 6623 | }, |
| 6624 | ), |
| 6625 | .byval, |
| 6626 | .byref, |
| 6627 | .preallocated, |
| 6628 | .inalloca, |
| 6629 | .sret, |
| 6630 | .elementtype, |
| 6631 | .string, |
| 6632 | .none, |
| 6633 | => unreachable, |
| 6634 | }, |
| 6635 | .byval, |
| 6636 | .byref, |
| 6637 | .preallocated, |
| 6638 | .inalloca, |
| 6639 | .sret, |
| 6640 | .elementtype, |
| 6641 | => |ty| self.llvm.context.createTypeAttribute(kind_id.*, ty.toLlvm(self)), |
| 6642 | .string, .none => unreachable, |
| 6643 | }; |
| 6644 | }, |
| 6645 | .string => |string_attr| llvm_attr: { |
| 6646 | const kind = string_attr.kind.slice(self).?; |
| 6647 | const value = string_attr.value.slice(self).?; |
| 6648 | break :llvm_attr self.llvm.context.createStringAttribute( |
| 6649 | kind.ptr, |
| 6650 | @intCast(kind.len), |
| 6651 | value.ptr, |
| 6652 | @intCast(value.len), |
| 6653 | ); |
| 6654 | }, |
| 6655 | .none => unreachable, |
| 6656 | }); |
| 6657 | } |
| 6658 | return @enumFromInt(gop.index); |
| 6659 | } |
| 6660 | |
| 6661 | pub fn attrs(self: *Builder, attributes: []Attribute.Index) Allocator.Error!Attributes { |
| 6662 | std.sort.heap(Attribute.Index, attributes, self, struct { |
| 6663 | pub fn lessThan(builder: *const Builder, lhs: Attribute.Index, rhs: Attribute.Index) bool { |
| 6664 | const lhs_kind = lhs.getKind(builder); |
| 6665 | const rhs_kind = rhs.getKind(builder); |
| 6666 | assert(lhs_kind != rhs_kind); |
| 6667 | return @intFromEnum(lhs_kind) < @intFromEnum(rhs_kind); |
| 6668 | } |
| 6669 | }.lessThan); |
| 6670 | return @enumFromInt(try self.attrGeneric(@ptrCast(attributes))); |
| 6671 | } |
| 6672 | |
| 6673 | pub fn fnAttrs(self: *Builder, fn_attributes: []const Attributes) Allocator.Error!FunctionAttributes { |
| 6674 | return @enumFromInt(try self.attrGeneric(@ptrCast( |
| 6675 | fn_attributes[0..if (std.mem.lastIndexOfNone(Attributes, fn_attributes, &.{.none})) |last| |
| 6676 | last + 1 |
| 6677 | else |
| 6678 | 0], |
| 6679 | ))); |
| 6680 | } |
| 6681 | |
| 5271 | 6682 | pub fn addGlobal(self: *Builder, name: String, global: Global) Allocator.Error!Global.Index { |
| 5272 | 6683 | assert(!name.isAnon()); |
| 5273 | 6684 | try self.ensureUnusedTypeCapacity(1, NoExtra, 0); |
| ... | ... | @@ -5295,7 +6706,7 @@ pub fn addGlobalAssumeCapacity(self: *Builder, name: String, global: Global) Glo |
| 5295 | 6706 | |
| 5296 | 6707 | const unique_gop = self.next_unique_global_id.getOrPutAssumeCapacity(name); |
| 5297 | 6708 | if (!unique_gop.found_existing) unique_gop.value_ptr.* = 2; |
| 5298 | | id = self.fmtAssumeCapacity("{s}.{d}", .{ name.toSlice(self).?, unique_gop.value_ptr.* }); |
| 6709 | id = self.fmtAssumeCapacity("{s}.{d}", .{ name.slice(self).?, unique_gop.value_ptr.* }); |
| 5299 | 6710 | unique_gop.value_ptr.* += 1; |
| 5300 | 6711 | } |
| 5301 | 6712 | } |
| ... | ... | @@ -5309,8 +6720,9 @@ pub fn intConst(self: *Builder, ty: Type, value: anytype) Allocator.Error!Consta |
| 5309 | 6720 | switch (@typeInfo(@TypeOf(value))) { |
| 5310 | 6721 | .Int => |info| std.math.big.int.calcTwosCompLimbCount(info.bits), |
| 5311 | 6722 | .ComptimeInt => std.math.big.int.calcLimbLen(value), |
| 5312 | | else => @compileError("intConst expected an integral value, got " ++ |
| 5313 | | @typeName(@TypeOf(value))), |
| 6723 | else => @compileError( |
| 6724 | "intConst expected an integral value, got " ++ @typeName(@TypeOf(value)), |
| 6725 | ), |
| 5314 | 6726 | } |
| 5315 | 6727 | ]std.math.big.Limb = undefined; |
| 5316 | 6728 | return self.bigIntConst(ty, std.math.big.int.Mutable.init(&limbs, value).toConst()); |
| ... | ... | @@ -5721,6 +7133,27 @@ pub fn binValue(self: *Builder, tag: Constant.Tag, lhs: Constant, rhs: Constant) |
| 5721 | 7133 | return (try self.binConst(tag, lhs, rhs)).toValue(); |
| 5722 | 7134 | } |
| 5723 | 7135 | |
| 7136 | pub fn asmConst( |
| 7137 | self: *Builder, |
| 7138 | ty: Type, |
| 7139 | info: Constant.Asm.Info, |
| 7140 | assembly: String, |
| 7141 | constraints: String, |
| 7142 | ) Allocator.Error!Constant { |
| 7143 | try self.ensureUnusedConstantCapacity(1, Constant.Asm, 0); |
| 7144 | return self.asmConstAssumeCapacity(ty, info, assembly, constraints); |
| 7145 | } |
| 7146 | |
| 7147 | pub fn asmValue( |
| 7148 | self: *Builder, |
| 7149 | ty: Type, |
| 7150 | info: Constant.Asm.Info, |
| 7151 | assembly: String, |
| 7152 | constraints: String, |
| 7153 | ) Allocator.Error!Value { |
| 7154 | return (try self.asmConst(ty, info, assembly, constraints)).toValue(); |
| 7155 | } |
| 7156 | |
| 5724 | 7157 | pub fn dump(self: *Builder) void { |
| 5725 | 7158 | if (self.useLibLlvm()) |
| 5726 | 7159 | self.llvm.module.?.dump() |
| ... | ... | @@ -5766,457 +7199,604 @@ pub fn printUnbuffered( |
| 5766 | 7199 | self: *Builder, |
| 5767 | 7200 | writer: anytype, |
| 5768 | 7201 | ) (@TypeOf(writer).Error || Allocator.Error)!void { |
| 5769 | | if (self.source_filename != .none) try writer.print( |
| 5770 | | \\; ModuleID = '{s}' |
| 5771 | | \\source_filename = {"} |
| 5772 | | \\ |
| 5773 | | , .{ self.source_filename.toSlice(self).?, self.source_filename.fmt(self) }); |
| 5774 | | if (self.data_layout != .none) try writer.print( |
| 5775 | | \\target datalayout = {"} |
| 5776 | | \\ |
| 5777 | | , .{self.data_layout.fmt(self)}); |
| 5778 | | if (self.target_triple != .none) try writer.print( |
| 5779 | | \\target triple = {"} |
| 5780 | | \\ |
| 5781 | | , .{self.target_triple.fmt(self)}); |
| 5782 | | try writer.writeByte('\n'); |
| 5783 | | for (self.types.keys(), self.types.values()) |id, ty| try writer.print( |
| 5784 | | \\%{} = type {} |
| 5785 | | \\ |
| 5786 | | , .{ id.fmt(self), ty.fmt(self) }); |
| 5787 | | try writer.writeByte('\n'); |
| 5788 | | for (self.variables.items) |variable| { |
| 5789 | | if (variable.global.getReplacement(self) != .none) continue; |
| 5790 | | const global = variable.global.ptrConst(self); |
| 5791 | | try writer.print( |
| 5792 | | \\{} ={}{}{}{}{}{}{}{} {s} {%}{ }{,} |
| 7202 | var need_newline = false; |
| 7203 | |
| 7204 | if (self.source_filename != .none or self.data_layout != .none or self.target_triple != .none) { |
| 7205 | if (need_newline) try writer.writeByte('\n'); |
| 7206 | if (self.source_filename != .none) try writer.print( |
| 7207 | \\; ModuleID = '{s}' |
| 7208 | \\source_filename = {"} |
| 5793 | 7209 | \\ |
| 5794 | | , .{ |
| 5795 | | variable.global.fmt(self), |
| 5796 | | global.linkage, |
| 5797 | | global.preemption, |
| 5798 | | global.visibility, |
| 5799 | | global.dll_storage_class, |
| 5800 | | variable.thread_local, |
| 5801 | | global.unnamed_addr, |
| 5802 | | global.addr_space, |
| 5803 | | global.externally_initialized, |
| 5804 | | @tagName(variable.mutability), |
| 5805 | | global.type.fmt(self), |
| 5806 | | variable.init.fmt(self), |
| 5807 | | variable.alignment, |
| 5808 | | }); |
| 7210 | , .{ self.source_filename.slice(self).?, self.source_filename.fmt(self) }); |
| 7211 | if (self.data_layout != .none) try writer.print( |
| 7212 | \\target datalayout = {"} |
| 7213 | \\ |
| 7214 | , .{self.data_layout.fmt(self)}); |
| 7215 | if (self.target_triple != .none) try writer.print( |
| 7216 | \\target triple = {"} |
| 7217 | \\ |
| 7218 | , .{self.target_triple.fmt(self)}); |
| 7219 | need_newline = true; |
| 5809 | 7220 | } |
| 5810 | | try writer.writeByte('\n'); |
| 5811 | | for (0.., self.functions.items) |function_i, function| { |
| 5812 | | const function_index: Function.Index = @enumFromInt(function_i); |
| 5813 | | if (function.global.getReplacement(self) != .none) continue; |
| 5814 | | const global = function.global.ptrConst(self); |
| 5815 | | const params_len = global.type.functionParameters(self).len; |
| 5816 | | try writer.print( |
| 5817 | | \\{s}{}{}{}{} {} {}( |
| 5818 | | , .{ |
| 5819 | | if (function.instructions.len > 0) "define" else "declare", |
| 5820 | | global.linkage, |
| 5821 | | global.preemption, |
| 5822 | | global.visibility, |
| 5823 | | global.dll_storage_class, |
| 5824 | | global.type.functionReturn(self).fmt(self), |
| 5825 | | function.global.fmt(self), |
| 5826 | | }); |
| 5827 | | for (0..params_len) |arg| { |
| 5828 | | if (arg > 0) try writer.writeAll(", "); |
| 5829 | | if (function.instructions.len > 0) |
| 5830 | | try writer.print("{%}", .{function.arg(@intCast(arg)).fmt(function_index, self)}) |
| 5831 | | else |
| 5832 | | try writer.print("{%}", .{global.type.functionParameters(self)[arg].fmt(self)}); |
| 7221 | |
| 7222 | if (self.module_asm.items.len > 0) { |
| 7223 | if (need_newline) try writer.writeByte('\n'); |
| 7224 | var line_it = std.mem.tokenizeScalar(u8, self.module_asm.items, '\n'); |
| 7225 | while (line_it.next()) |line| { |
| 7226 | try writer.writeAll("module asm "); |
| 7227 | try printEscapedString(line, .always_quote, writer); |
| 7228 | try writer.writeByte('\n'); |
| 5833 | 7229 | } |
| 5834 | | switch (global.type.functionKind(self)) { |
| 5835 | | .normal => {}, |
| 5836 | | .vararg => { |
| 5837 | | if (params_len > 0) try writer.writeAll(", "); |
| 5838 | | try writer.writeAll("..."); |
| 5839 | | }, |
| 7230 | need_newline = true; |
| 7231 | } |
| 7232 | |
| 7233 | if (self.types.count() > 0) { |
| 7234 | if (need_newline) try writer.writeByte('\n'); |
| 7235 | for (self.types.keys(), self.types.values()) |id, ty| try writer.print( |
| 7236 | \\%{} = type {} |
| 7237 | \\ |
| 7238 | , .{ id.fmt(self), ty.fmt(self) }); |
| 7239 | need_newline = true; |
| 7240 | } |
| 7241 | |
| 7242 | if (self.variables.items.len > 0) { |
| 7243 | if (need_newline) try writer.writeByte('\n'); |
| 7244 | for (self.variables.items) |variable| { |
| 7245 | if (variable.global.getReplacement(self) != .none) continue; |
| 7246 | const global = variable.global.ptrConst(self); |
| 7247 | try writer.print( |
| 7248 | \\{} ={}{}{}{}{}{}{}{} {s} {%}{ }{,} |
| 7249 | \\ |
| 7250 | , .{ |
| 7251 | variable.global.fmt(self), |
| 7252 | global.linkage, |
| 7253 | global.preemption, |
| 7254 | global.visibility, |
| 7255 | global.dll_storage_class, |
| 7256 | variable.thread_local, |
| 7257 | global.unnamed_addr, |
| 7258 | global.addr_space, |
| 7259 | global.externally_initialized, |
| 7260 | @tagName(variable.mutability), |
| 7261 | global.type.fmt(self), |
| 7262 | variable.init.fmt(self), |
| 7263 | variable.alignment, |
| 7264 | }); |
| 5840 | 7265 | } |
| 5841 | | try writer.print("){}{}", .{ global.unnamed_addr, function.alignment }); |
| 5842 | | if (function.instructions.len > 0) { |
| 5843 | | var block_incoming_len: u32 = undefined; |
| 5844 | | try writer.writeAll(" {\n"); |
| 5845 | | for (params_len..function.instructions.len) |instruction_i| { |
| 5846 | | const instruction_index: Function.Instruction.Index = @enumFromInt(instruction_i); |
| 5847 | | const instruction = function.instructions.get(@intFromEnum(instruction_index)); |
| 5848 | | switch (instruction.tag) { |
| 5849 | | .add, |
| 5850 | | .@"add nsw", |
| 5851 | | .@"add nuw", |
| 5852 | | .@"add nuw nsw", |
| 5853 | | .@"and", |
| 5854 | | .ashr, |
| 5855 | | .@"ashr exact", |
| 5856 | | .fadd, |
| 5857 | | .@"fadd fast", |
| 5858 | | .@"fcmp false", |
| 5859 | | .@"fcmp fast false", |
| 5860 | | .@"fcmp fast oeq", |
| 5861 | | .@"fcmp fast oge", |
| 5862 | | .@"fcmp fast ogt", |
| 5863 | | .@"fcmp fast ole", |
| 5864 | | .@"fcmp fast olt", |
| 5865 | | .@"fcmp fast one", |
| 5866 | | .@"fcmp fast ord", |
| 5867 | | .@"fcmp fast true", |
| 5868 | | .@"fcmp fast ueq", |
| 5869 | | .@"fcmp fast uge", |
| 5870 | | .@"fcmp fast ugt", |
| 5871 | | .@"fcmp fast ule", |
| 5872 | | .@"fcmp fast ult", |
| 5873 | | .@"fcmp fast une", |
| 5874 | | .@"fcmp fast uno", |
| 5875 | | .@"fcmp oeq", |
| 5876 | | .@"fcmp oge", |
| 5877 | | .@"fcmp ogt", |
| 5878 | | .@"fcmp ole", |
| 5879 | | .@"fcmp olt", |
| 5880 | | .@"fcmp one", |
| 5881 | | .@"fcmp ord", |
| 5882 | | .@"fcmp true", |
| 5883 | | .@"fcmp ueq", |
| 5884 | | .@"fcmp uge", |
| 5885 | | .@"fcmp ugt", |
| 5886 | | .@"fcmp ule", |
| 5887 | | .@"fcmp ult", |
| 5888 | | .@"fcmp une", |
| 5889 | | .@"fcmp uno", |
| 5890 | | .fdiv, |
| 5891 | | .@"fdiv fast", |
| 5892 | | .fmul, |
| 5893 | | .@"fmul fast", |
| 5894 | | .frem, |
| 5895 | | .@"frem fast", |
| 5896 | | .fsub, |
| 5897 | | .@"fsub fast", |
| 5898 | | .@"icmp eq", |
| 5899 | | .@"icmp ne", |
| 5900 | | .@"icmp sge", |
| 5901 | | .@"icmp sgt", |
| 5902 | | .@"icmp sle", |
| 5903 | | .@"icmp slt", |
| 5904 | | .@"icmp uge", |
| 5905 | | .@"icmp ugt", |
| 5906 | | .@"icmp ule", |
| 5907 | | .@"icmp ult", |
| 5908 | | .lshr, |
| 5909 | | .@"lshr exact", |
| 5910 | | .mul, |
| 5911 | | .@"mul nsw", |
| 5912 | | .@"mul nuw", |
| 5913 | | .@"mul nuw nsw", |
| 5914 | | .@"or", |
| 5915 | | .sdiv, |
| 5916 | | .@"sdiv exact", |
| 5917 | | .srem, |
| 5918 | | .shl, |
| 5919 | | .@"shl nsw", |
| 5920 | | .@"shl nuw", |
| 5921 | | .@"shl nuw nsw", |
| 5922 | | .sub, |
| 5923 | | .@"sub nsw", |
| 5924 | | .@"sub nuw", |
| 5925 | | .@"sub nuw nsw", |
| 5926 | | .udiv, |
| 5927 | | .@"udiv exact", |
| 5928 | | .urem, |
| 5929 | | .xor, |
| 5930 | | => |tag| { |
| 5931 | | const extra = function.extraData(Function.Instruction.Binary, instruction.data); |
| 5932 | | try writer.print(" %{} = {s} {%}, {}\n", .{ |
| 5933 | | instruction_index.name(&function).fmt(self), |
| 5934 | | @tagName(tag), |
| 5935 | | extra.lhs.fmt(function_index, self), |
| 5936 | | extra.rhs.fmt(function_index, self), |
| 5937 | | }); |
| 5938 | | }, |
| 5939 | | .addrspacecast, |
| 5940 | | .bitcast, |
| 5941 | | .fpext, |
| 5942 | | .fptosi, |
| 5943 | | .fptoui, |
| 5944 | | .fptrunc, |
| 5945 | | .inttoptr, |
| 5946 | | .ptrtoint, |
| 5947 | | .sext, |
| 5948 | | .sitofp, |
| 5949 | | .trunc, |
| 5950 | | .uitofp, |
| 5951 | | .zext, |
| 5952 | | => |tag| { |
| 5953 | | const extra = function.extraData(Function.Instruction.Cast, instruction.data); |
| 5954 | | try writer.print(" %{} = {s} {%} to {%}\n", .{ |
| 5955 | | instruction_index.name(&function).fmt(self), |
| 5956 | | @tagName(tag), |
| 5957 | | extra.val.fmt(function_index, self), |
| 5958 | | extra.type.fmt(self), |
| 5959 | | }); |
| 5960 | | }, |
| 5961 | | .alloca, |
| 5962 | | .@"alloca inalloca", |
| 5963 | | => |tag| { |
| 5964 | | const extra = function.extraData(Function.Instruction.Alloca, instruction.data); |
| 5965 | | try writer.print(" %{} = {s} {%}{,%}{,}{,}\n", .{ |
| 5966 | | instruction_index.name(&function).fmt(self), |
| 5967 | | @tagName(tag), |
| 5968 | | extra.type.fmt(self), |
| 5969 | | extra.len.fmt(function_index, self), |
| 5970 | | extra.info.alignment, |
| 5971 | | extra.info.addr_space, |
| 5972 | | }); |
| 5973 | | }, |
| 5974 | | .arg => unreachable, |
| 5975 | | .block => { |
| 5976 | | block_incoming_len = instruction.data; |
| 5977 | | const name = instruction_index.name(&function); |
| 5978 | | if (@intFromEnum(instruction_index) > params_len) try writer.writeByte('\n'); |
| 5979 | | try writer.print("{}:\n", .{name.fmt(self)}); |
| 5980 | | }, |
| 5981 | | .br => |tag| { |
| 5982 | | const target: Function.Block.Index = @enumFromInt(instruction.data); |
| 5983 | | try writer.print(" {s} {%}\n", .{ |
| 5984 | | @tagName(tag), target.toInst(&function).fmt(function_index, self), |
| 5985 | | }); |
| 5986 | | }, |
| 5987 | | .br_cond => { |
| 5988 | | const extra = function.extraData(Function.Instruction.BrCond, instruction.data); |
| 5989 | | try writer.print(" br {%}, {%}, {%}\n", .{ |
| 5990 | | extra.cond.fmt(function_index, self), |
| 5991 | | extra.then.toInst(&function).fmt(function_index, self), |
| 5992 | | extra.@"else".toInst(&function).fmt(function_index, self), |
| 5993 | | }); |
| 5994 | | }, |
| 5995 | | .extractelement => |tag| { |
| 5996 | | const extra = |
| 5997 | | function.extraData(Function.Instruction.ExtractElement, instruction.data); |
| 5998 | | try writer.print(" %{} = {s} {%}, {%}\n", .{ |
| 5999 | | instruction_index.name(&function).fmt(self), |
| 6000 | | @tagName(tag), |
| 6001 | | extra.val.fmt(function_index, self), |
| 6002 | | extra.index.fmt(function_index, self), |
| 6003 | | }); |
| 6004 | | }, |
| 6005 | | .extractvalue => |tag| { |
| 6006 | | var extra = |
| 6007 | | function.extraDataTrail(Function.Instruction.ExtractValue, instruction.data); |
| 6008 | | const indices = extra.trail.next(extra.data.indices_len, u32, &function); |
| 6009 | | try writer.print(" %{} = {s} {%}", .{ |
| 6010 | | instruction_index.name(&function).fmt(self), |
| 6011 | | @tagName(tag), |
| 6012 | | extra.data.val.fmt(function_index, self), |
| 6013 | | }); |
| 6014 | | for (indices) |index| try writer.print(", {d}", .{index}); |
| 6015 | | try writer.writeByte('\n'); |
| 6016 | | }, |
| 6017 | | .fence => |tag| { |
| 6018 | | const info: MemoryAccessInfo = @bitCast(instruction.data); |
| 6019 | | try writer.print(" {s}{}{}", .{ @tagName(tag), info.scope, info.ordering }); |
| 6020 | | }, |
| 6021 | | .fneg, |
| 6022 | | .@"fneg fast", |
| 6023 | | .ret, |
| 6024 | | => |tag| { |
| 6025 | | const val: Value = @enumFromInt(instruction.data); |
| 6026 | | try writer.print(" {s} {%}\n", .{ |
| 6027 | | @tagName(tag), |
| 6028 | | val.fmt(function_index, self), |
| 6029 | | }); |
| 6030 | | }, |
| 6031 | | .getelementptr, |
| 6032 | | .@"getelementptr inbounds", |
| 6033 | | => |tag| { |
| 6034 | | var extra = function.extraDataTrail( |
| 6035 | | Function.Instruction.GetElementPtr, |
| 6036 | | instruction.data, |
| 6037 | | ); |
| 6038 | | const indices = extra.trail.next(extra.data.indices_len, Value, &function); |
| 6039 | | try writer.print(" %{} = {s} {%}, {%}", .{ |
| 6040 | | instruction_index.name(&function).fmt(self), |
| 6041 | | @tagName(tag), |
| 6042 | | extra.data.type.fmt(self), |
| 6043 | | extra.data.base.fmt(function_index, self), |
| 6044 | | }); |
| 6045 | | for (indices) |index| try writer.print(", {%}", .{ |
| 6046 | | index.fmt(function_index, self), |
| 6047 | | }); |
| 6048 | | try writer.writeByte('\n'); |
| 6049 | | }, |
| 6050 | | .insertelement => |tag| { |
| 6051 | | const extra = |
| 6052 | | function.extraData(Function.Instruction.InsertElement, instruction.data); |
| 6053 | | try writer.print(" %{} = {s} {%}, {%}, {%}\n", .{ |
| 6054 | | instruction_index.name(&function).fmt(self), |
| 6055 | | @tagName(tag), |
| 6056 | | extra.val.fmt(function_index, self), |
| 6057 | | extra.elem.fmt(function_index, self), |
| 6058 | | extra.index.fmt(function_index, self), |
| 6059 | | }); |
| 6060 | | }, |
| 6061 | | .insertvalue => |tag| { |
| 6062 | | var extra = |
| 6063 | | function.extraDataTrail(Function.Instruction.InsertValue, instruction.data); |
| 6064 | | const indices = extra.trail.next(extra.data.indices_len, u32, &function); |
| 6065 | | try writer.print(" %{} = {s} {%}, {%}", .{ |
| 6066 | | instruction_index.name(&function).fmt(self), |
| 6067 | | @tagName(tag), |
| 6068 | | extra.data.val.fmt(function_index, self), |
| 6069 | | extra.data.elem.fmt(function_index, self), |
| 6070 | | }); |
| 6071 | | for (indices) |index| try writer.print(", {d}", .{index}); |
| 6072 | | try writer.writeByte('\n'); |
| 6073 | | }, |
| 6074 | | .@"llvm.maxnum.", |
| 6075 | | .@"llvm.minnum.", |
| 6076 | | .@"llvm.sadd.sat.", |
| 6077 | | .@"llvm.smax.", |
| 6078 | | .@"llvm.smin.", |
| 6079 | | .@"llvm.smul.fix.sat.", |
| 6080 | | .@"llvm.sshl.sat.", |
| 6081 | | .@"llvm.ssub.sat.", |
| 6082 | | .@"llvm.uadd.sat.", |
| 6083 | | .@"llvm.umax.", |
| 6084 | | .@"llvm.umin.", |
| 6085 | | .@"llvm.umul.fix.sat.", |
| 6086 | | .@"llvm.ushl.sat.", |
| 6087 | | .@"llvm.usub.sat.", |
| 6088 | | => |tag| { |
| 6089 | | const extra = function.extraData(Function.Instruction.Binary, instruction.data); |
| 6090 | | const ty = instruction_index.typeOf(function_index, self); |
| 6091 | | try writer.print(" %{} = call {%} @{s}{m}({%}, {%})\n", .{ |
| 6092 | | instruction_index.name(&function).fmt(self), |
| 6093 | | ty.fmt(self), |
| 6094 | | @tagName(tag), |
| 6095 | | ty.fmt(self), |
| 6096 | | extra.lhs.fmt(function_index, self), |
| 6097 | | extra.rhs.fmt(function_index, self), |
| 6098 | | }); |
| 6099 | | }, |
| 6100 | | .load, |
| 6101 | | .@"load atomic", |
| 6102 | | .@"load atomic volatile", |
| 6103 | | .@"load volatile", |
| 6104 | | => |tag| { |
| 6105 | | const extra = function.extraData(Function.Instruction.Load, instruction.data); |
| 6106 | | try writer.print(" %{} = {s} {%}, {%}{}{}{,}\n", .{ |
| 6107 | | instruction_index.name(&function).fmt(self), |
| 6108 | | @tagName(tag), |
| 6109 | | extra.type.fmt(self), |
| 6110 | | extra.ptr.fmt(function_index, self), |
| 6111 | | extra.info.scope, |
| 6112 | | extra.info.ordering, |
| 6113 | | extra.info.alignment, |
| 6114 | | }); |
| 6115 | | }, |
| 6116 | | .phi, |
| 6117 | | .@"phi fast", |
| 6118 | | => |tag| { |
| 6119 | | var extra = function.extraDataTrail(Function.Instruction.Phi, instruction.data); |
| 6120 | | const vals = extra.trail.next(block_incoming_len, Value, &function); |
| 6121 | | const blocks = |
| 6122 | | extra.trail.next(block_incoming_len, Function.Block.Index, &function); |
| 6123 | | try writer.print(" %{} = {s} {%} ", .{ |
| 6124 | | instruction_index.name(&function).fmt(self), |
| 6125 | | @tagName(tag), |
| 6126 | | vals[0].typeOf(function_index, self).fmt(self), |
| 6127 | | }); |
| 6128 | | for (0.., vals, blocks) |incoming_index, incoming_val, incoming_block| { |
| 6129 | | if (incoming_index > 0) try writer.writeAll(", "); |
| 6130 | | try writer.print("[ {}, {} ]", .{ |
| 6131 | | incoming_val.fmt(function_index, self), |
| 6132 | | incoming_block.toInst(&function).fmt(function_index, self), |
| 7266 | need_newline = true; |
| 7267 | } |
| 7268 | |
| 7269 | var attribute_groups: std.AutoArrayHashMapUnmanaged(Attributes, void) = .{}; |
| 7270 | defer attribute_groups.deinit(self.gpa); |
| 7271 | |
| 7272 | if (self.functions.items.len > 0) { |
| 7273 | if (need_newline) try writer.writeByte('\n'); |
| 7274 | for (0.., self.functions.items) |function_i, function| { |
| 7275 | if (function_i > 0) try writer.writeByte('\n'); |
| 7276 | const function_index: Function.Index = @enumFromInt(function_i); |
| 7277 | if (function.global.getReplacement(self) != .none) continue; |
| 7278 | const global = function.global.ptrConst(self); |
| 7279 | const params_len = global.type.functionParameters(self).len; |
| 7280 | const function_attributes = function.attributes.func(self); |
| 7281 | if (function_attributes != .none) try writer.print( |
| 7282 | \\; Function Attrs:{} |
| 7283 | \\ |
| 7284 | , .{function_attributes.fmt(self)}); |
| 7285 | try writer.print( |
| 7286 | \\{s}{}{}{}{}{}{"} {} {}( |
| 7287 | , .{ |
| 7288 | if (function.instructions.len > 0) "define" else "declare", |
| 7289 | global.linkage, |
| 7290 | global.preemption, |
| 7291 | global.visibility, |
| 7292 | global.dll_storage_class, |
| 7293 | function.call_conv, |
| 7294 | function.attributes.ret(self).fmt(self), |
| 7295 | global.type.functionReturn(self).fmt(self), |
| 7296 | function.global.fmt(self), |
| 7297 | }); |
| 7298 | for (0..params_len) |arg| { |
| 7299 | if (arg > 0) try writer.writeAll(", "); |
| 7300 | try writer.print( |
| 7301 | \\{%}{"} |
| 7302 | , .{ |
| 7303 | global.type.functionParameters(self)[arg].fmt(self), |
| 7304 | function.attributes.param(arg, self).fmt(self), |
| 7305 | }); |
| 7306 | if (function.instructions.len > 0) |
| 7307 | try writer.print(" {}", .{function.arg(@intCast(arg)).fmt(function_index, self)}); |
| 7308 | } |
| 7309 | switch (global.type.functionKind(self)) { |
| 7310 | .normal => {}, |
| 7311 | .vararg => { |
| 7312 | if (params_len > 0) try writer.writeAll(", "); |
| 7313 | try writer.writeAll("..."); |
| 7314 | }, |
| 7315 | } |
| 7316 | try writer.print("){}{}", .{ global.unnamed_addr, global.addr_space }); |
| 7317 | if (function_attributes != .none) try writer.print(" #{d}", .{ |
| 7318 | (try attribute_groups.getOrPutValue(self.gpa, function_attributes, {})).index, |
| 7319 | }); |
| 7320 | try writer.print("{}", .{function.alignment}); |
| 7321 | if (function.instructions.len > 0) { |
| 7322 | var block_incoming_len: u32 = undefined; |
| 7323 | try writer.writeAll(" {\n"); |
| 7324 | for (params_len..function.instructions.len) |instruction_i| { |
| 7325 | const instruction_index: Function.Instruction.Index = @enumFromInt(instruction_i); |
| 7326 | const instruction = function.instructions.get(@intFromEnum(instruction_index)); |
| 7327 | switch (instruction.tag) { |
| 7328 | .add, |
| 7329 | .@"add nsw", |
| 7330 | .@"add nuw", |
| 7331 | .@"add nuw nsw", |
| 7332 | .@"and", |
| 7333 | .ashr, |
| 7334 | .@"ashr exact", |
| 7335 | .fadd, |
| 7336 | .@"fadd fast", |
| 7337 | .@"fcmp false", |
| 7338 | .@"fcmp fast false", |
| 7339 | .@"fcmp fast oeq", |
| 7340 | .@"fcmp fast oge", |
| 7341 | .@"fcmp fast ogt", |
| 7342 | .@"fcmp fast ole", |
| 7343 | .@"fcmp fast olt", |
| 7344 | .@"fcmp fast one", |
| 7345 | .@"fcmp fast ord", |
| 7346 | .@"fcmp fast true", |
| 7347 | .@"fcmp fast ueq", |
| 7348 | .@"fcmp fast uge", |
| 7349 | .@"fcmp fast ugt", |
| 7350 | .@"fcmp fast ule", |
| 7351 | .@"fcmp fast ult", |
| 7352 | .@"fcmp fast une", |
| 7353 | .@"fcmp fast uno", |
| 7354 | .@"fcmp oeq", |
| 7355 | .@"fcmp oge", |
| 7356 | .@"fcmp ogt", |
| 7357 | .@"fcmp ole", |
| 7358 | .@"fcmp olt", |
| 7359 | .@"fcmp one", |
| 7360 | .@"fcmp ord", |
| 7361 | .@"fcmp true", |
| 7362 | .@"fcmp ueq", |
| 7363 | .@"fcmp uge", |
| 7364 | .@"fcmp ugt", |
| 7365 | .@"fcmp ule", |
| 7366 | .@"fcmp ult", |
| 7367 | .@"fcmp une", |
| 7368 | .@"fcmp uno", |
| 7369 | .fdiv, |
| 7370 | .@"fdiv fast", |
| 7371 | .fmul, |
| 7372 | .@"fmul fast", |
| 7373 | .frem, |
| 7374 | .@"frem fast", |
| 7375 | .fsub, |
| 7376 | .@"fsub fast", |
| 7377 | .@"icmp eq", |
| 7378 | .@"icmp ne", |
| 7379 | .@"icmp sge", |
| 7380 | .@"icmp sgt", |
| 7381 | .@"icmp sle", |
| 7382 | .@"icmp slt", |
| 7383 | .@"icmp uge", |
| 7384 | .@"icmp ugt", |
| 7385 | .@"icmp ule", |
| 7386 | .@"icmp ult", |
| 7387 | .lshr, |
| 7388 | .@"lshr exact", |
| 7389 | .mul, |
| 7390 | .@"mul nsw", |
| 7391 | .@"mul nuw", |
| 7392 | .@"mul nuw nsw", |
| 7393 | .@"or", |
| 7394 | .sdiv, |
| 7395 | .@"sdiv exact", |
| 7396 | .srem, |
| 7397 | .shl, |
| 7398 | .@"shl nsw", |
| 7399 | .@"shl nuw", |
| 7400 | .@"shl nuw nsw", |
| 7401 | .sub, |
| 7402 | .@"sub nsw", |
| 7403 | .@"sub nuw", |
| 7404 | .@"sub nuw nsw", |
| 7405 | .udiv, |
| 7406 | .@"udiv exact", |
| 7407 | .urem, |
| 7408 | .xor, |
| 7409 | => |tag| { |
| 7410 | const extra = |
| 7411 | function.extraData(Function.Instruction.Binary, instruction.data); |
| 7412 | try writer.print(" %{} = {s} {%}, {}\n", .{ |
| 7413 | instruction_index.name(&function).fmt(self), |
| 7414 | @tagName(tag), |
| 7415 | extra.lhs.fmt(function_index, self), |
| 7416 | extra.rhs.fmt(function_index, self), |
| 6133 | 7417 | }); |
| 6134 | | } |
| 6135 | | try writer.writeByte('\n'); |
| 6136 | | }, |
| 6137 | | .@"ret void", |
| 6138 | | .@"unreachable", |
| 6139 | | => |tag| try writer.print(" {s}\n", .{@tagName(tag)}), |
| 6140 | | .select, |
| 6141 | | .@"select fast", |
| 6142 | | => |tag| { |
| 6143 | | const extra = function.extraData(Function.Instruction.Select, instruction.data); |
| 6144 | | try writer.print(" %{} = {s} {%}, {%}, {%}\n", .{ |
| 6145 | | instruction_index.name(&function).fmt(self), |
| 6146 | | @tagName(tag), |
| 6147 | | extra.cond.fmt(function_index, self), |
| 6148 | | extra.lhs.fmt(function_index, self), |
| 6149 | | extra.rhs.fmt(function_index, self), |
| 6150 | | }); |
| 6151 | | }, |
| 6152 | | .shufflevector => |tag| { |
| 6153 | | const extra = |
| 6154 | | function.extraData(Function.Instruction.ShuffleVector, instruction.data); |
| 6155 | | try writer.print(" %{} = {s} {%}, {%}, {%}\n", .{ |
| 6156 | | instruction_index.name(&function).fmt(self), |
| 6157 | | @tagName(tag), |
| 6158 | | extra.lhs.fmt(function_index, self), |
| 6159 | | extra.rhs.fmt(function_index, self), |
| 6160 | | extra.mask.fmt(function_index, self), |
| 6161 | | }); |
| 6162 | | }, |
| 6163 | | .store, |
| 6164 | | .@"store atomic", |
| 6165 | | .@"store atomic volatile", |
| 6166 | | .@"store volatile", |
| 6167 | | => |tag| { |
| 6168 | | const extra = function.extraData(Function.Instruction.Store, instruction.data); |
| 6169 | | try writer.print(" {s} {%}, {%}{}{}{,}\n", .{ |
| 6170 | | @tagName(tag), |
| 6171 | | extra.val.fmt(function_index, self), |
| 6172 | | extra.ptr.fmt(function_index, self), |
| 6173 | | extra.info.scope, |
| 6174 | | extra.info.ordering, |
| 6175 | | extra.info.alignment, |
| 6176 | | }); |
| 6177 | | }, |
| 6178 | | .@"switch" => |tag| { |
| 6179 | | var extra = |
| 6180 | | function.extraDataTrail(Function.Instruction.Switch, instruction.data); |
| 6181 | | const vals = extra.trail.next(extra.data.cases_len, Constant, &function); |
| 6182 | | const blocks = |
| 6183 | | extra.trail.next(extra.data.cases_len, Function.Block.Index, &function); |
| 6184 | | try writer.print(" {s} {%}, {%} [", .{ |
| 6185 | | @tagName(tag), |
| 6186 | | extra.data.val.fmt(function_index, self), |
| 6187 | | extra.data.default.toInst(&function).fmt(function_index, self), |
| 6188 | | }); |
| 6189 | | for (vals, blocks) |case_val, case_block| try writer.print(" {%}, {%}\n", .{ |
| 6190 | | case_val.fmt(self), |
| 6191 | | case_block.toInst(&function).fmt(function_index, self), |
| 6192 | | }); |
| 6193 | | try writer.writeAll(" ]\n"); |
| 6194 | | }, |
| 6195 | | .unimplemented => |tag| { |
| 6196 | | const ty: Type = @enumFromInt(instruction.data); |
| 6197 | | try writer.writeAll(" "); |
| 6198 | | switch (ty) { |
| 6199 | | .none, .void => {}, |
| 6200 | | else => try writer.print("%{} = ", .{ |
| 7418 | }, |
| 7419 | .addrspacecast, |
| 7420 | .bitcast, |
| 7421 | .fpext, |
| 7422 | .fptosi, |
| 7423 | .fptoui, |
| 7424 | .fptrunc, |
| 7425 | .inttoptr, |
| 7426 | .ptrtoint, |
| 7427 | .sext, |
| 7428 | .sitofp, |
| 7429 | .trunc, |
| 7430 | .uitofp, |
| 7431 | .zext, |
| 7432 | => |tag| { |
| 7433 | const extra = |
| 7434 | function.extraData(Function.Instruction.Cast, instruction.data); |
| 7435 | try writer.print(" %{} = {s} {%} to {%}\n", .{ |
| 6201 | 7436 | instruction_index.name(&function).fmt(self), |
| 6202 | | }), |
| 6203 | | } |
| 6204 | | try writer.print("{s} {%}\n", .{ @tagName(tag), ty.fmt(self) }); |
| 6205 | | }, |
| 6206 | | .va_arg => |tag| { |
| 6207 | | const extra = function.extraData(Function.Instruction.VaArg, instruction.data); |
| 6208 | | try writer.print(" %{} = {s} {%}, {%}\n", .{ |
| 6209 | | instruction_index.name(&function).fmt(self), |
| 6210 | | @tagName(tag), |
| 6211 | | extra.list.fmt(function_index, self), |
| 6212 | | extra.type.fmt(self), |
| 6213 | | }); |
| 6214 | | }, |
| 7437 | @tagName(tag), |
| 7438 | extra.val.fmt(function_index, self), |
| 7439 | extra.type.fmt(self), |
| 7440 | }); |
| 7441 | }, |
| 7442 | .alloca, |
| 7443 | .@"alloca inalloca", |
| 7444 | => |tag| { |
| 7445 | const extra = |
| 7446 | function.extraData(Function.Instruction.Alloca, instruction.data); |
| 7447 | try writer.print(" %{} = {s} {%}{,%}{,}{,}\n", .{ |
| 7448 | instruction_index.name(&function).fmt(self), |
| 7449 | @tagName(tag), |
| 7450 | extra.type.fmt(self), |
| 7451 | extra.len.fmt(function_index, self), |
| 7452 | extra.info.alignment, |
| 7453 | extra.info.addr_space, |
| 7454 | }); |
| 7455 | }, |
| 7456 | .arg => unreachable, |
| 7457 | .block => { |
| 7458 | block_incoming_len = instruction.data; |
| 7459 | const name = instruction_index.name(&function); |
| 7460 | if (@intFromEnum(instruction_index) > params_len) |
| 7461 | try writer.writeByte('\n'); |
| 7462 | try writer.print("{}:\n", .{name.fmt(self)}); |
| 7463 | }, |
| 7464 | .br => |tag| { |
| 7465 | const target: Function.Block.Index = @enumFromInt(instruction.data); |
| 7466 | try writer.print(" {s} {%}\n", .{ |
| 7467 | @tagName(tag), target.toInst(&function).fmt(function_index, self), |
| 7468 | }); |
| 7469 | }, |
| 7470 | .br_cond => { |
| 7471 | const extra = |
| 7472 | function.extraData(Function.Instruction.BrCond, instruction.data); |
| 7473 | try writer.print(" br {%}, {%}, {%}\n", .{ |
| 7474 | extra.cond.fmt(function_index, self), |
| 7475 | extra.then.toInst(&function).fmt(function_index, self), |
| 7476 | extra.@"else".toInst(&function).fmt(function_index, self), |
| 7477 | }); |
| 7478 | }, |
| 7479 | .call, |
| 7480 | .@"call fast", |
| 7481 | .@"musttail call", |
| 7482 | .@"musttail call fast", |
| 7483 | .@"notail call", |
| 7484 | .@"notail call fast", |
| 7485 | .@"tail call", |
| 7486 | .@"tail call fast", |
| 7487 | => |tag| { |
| 7488 | var extra = |
| 7489 | function.extraDataTrail(Function.Instruction.Call, instruction.data); |
| 7490 | const args = extra.trail.next(extra.data.args_len, Value, &function); |
| 7491 | try writer.writeAll(" "); |
| 7492 | const ret_ty = extra.data.ty.functionReturn(self); |
| 7493 | switch (ret_ty) { |
| 7494 | .void => {}, |
| 7495 | else => try writer.print("%{} = ", .{ |
| 7496 | instruction_index.name(&function).fmt(self), |
| 7497 | }), |
| 7498 | .none => unreachable, |
| 7499 | } |
| 7500 | try writer.print("{s}{}{}{} {%} {}(", .{ |
| 7501 | @tagName(tag), |
| 7502 | extra.data.info.call_conv, |
| 7503 | extra.data.attributes.ret(self).fmt(self), |
| 7504 | extra.data.callee.typeOf(function_index, self).pointerAddrSpace(self), |
| 7505 | switch (extra.data.ty.functionKind(self)) { |
| 7506 | .normal => ret_ty, |
| 7507 | .vararg => extra.data.ty, |
| 7508 | }.fmt(self), |
| 7509 | extra.data.callee.fmt(function_index, self), |
| 7510 | }); |
| 7511 | for (0.., args) |arg_index, arg| { |
| 7512 | if (arg_index > 0) try writer.writeAll(", "); |
| 7513 | try writer.print("{%}{} {}", .{ |
| 7514 | arg.typeOf(function_index, self).fmt(self), |
| 7515 | extra.data.attributes.param(arg_index, self).fmt(self), |
| 7516 | arg.fmt(function_index, self), |
| 7517 | }); |
| 7518 | } |
| 7519 | try writer.writeByte(')'); |
| 7520 | const call_function_attributes = extra.data.attributes.func(self); |
| 7521 | if (call_function_attributes != .none) try writer.print(" #{d}", .{ |
| 7522 | (try attribute_groups.getOrPutValue( |
| 7523 | self.gpa, |
| 7524 | call_function_attributes, |
| 7525 | {}, |
| 7526 | )).index, |
| 7527 | }); |
| 7528 | try writer.writeByte('\n'); |
| 7529 | }, |
| 7530 | .extractelement => |tag| { |
| 7531 | const extra = function.extraData( |
| 7532 | Function.Instruction.ExtractElement, |
| 7533 | instruction.data, |
| 7534 | ); |
| 7535 | try writer.print(" %{} = {s} {%}, {%}\n", .{ |
| 7536 | instruction_index.name(&function).fmt(self), |
| 7537 | @tagName(tag), |
| 7538 | extra.val.fmt(function_index, self), |
| 7539 | extra.index.fmt(function_index, self), |
| 7540 | }); |
| 7541 | }, |
| 7542 | .extractvalue => |tag| { |
| 7543 | var extra = function.extraDataTrail( |
| 7544 | Function.Instruction.ExtractValue, |
| 7545 | instruction.data, |
| 7546 | ); |
| 7547 | const indices = extra.trail.next(extra.data.indices_len, u32, &function); |
| 7548 | try writer.print(" %{} = {s} {%}", .{ |
| 7549 | instruction_index.name(&function).fmt(self), |
| 7550 | @tagName(tag), |
| 7551 | extra.data.val.fmt(function_index, self), |
| 7552 | }); |
| 7553 | for (indices) |index| try writer.print(", {d}", .{index}); |
| 7554 | try writer.writeByte('\n'); |
| 7555 | }, |
| 7556 | .fence => |tag| { |
| 7557 | const info: MemoryAccessInfo = @bitCast(instruction.data); |
| 7558 | try writer.print(" {s}{}{}", .{ @tagName(tag), info.scope, info.ordering }); |
| 7559 | }, |
| 7560 | .fneg, |
| 7561 | .@"fneg fast", |
| 7562 | .ret, |
| 7563 | => |tag| { |
| 7564 | const val: Value = @enumFromInt(instruction.data); |
| 7565 | try writer.print(" {s} {%}\n", .{ |
| 7566 | @tagName(tag), |
| 7567 | val.fmt(function_index, self), |
| 7568 | }); |
| 7569 | }, |
| 7570 | .getelementptr, |
| 7571 | .@"getelementptr inbounds", |
| 7572 | => |tag| { |
| 7573 | var extra = function.extraDataTrail( |
| 7574 | Function.Instruction.GetElementPtr, |
| 7575 | instruction.data, |
| 7576 | ); |
| 7577 | const indices = extra.trail.next(extra.data.indices_len, Value, &function); |
| 7578 | try writer.print(" %{} = {s} {%}, {%}", .{ |
| 7579 | instruction_index.name(&function).fmt(self), |
| 7580 | @tagName(tag), |
| 7581 | extra.data.type.fmt(self), |
| 7582 | extra.data.base.fmt(function_index, self), |
| 7583 | }); |
| 7584 | for (indices) |index| try writer.print(", {%}", .{ |
| 7585 | index.fmt(function_index, self), |
| 7586 | }); |
| 7587 | try writer.writeByte('\n'); |
| 7588 | }, |
| 7589 | .insertelement => |tag| { |
| 7590 | const extra = function.extraData( |
| 7591 | Function.Instruction.InsertElement, |
| 7592 | instruction.data, |
| 7593 | ); |
| 7594 | try writer.print(" %{} = {s} {%}, {%}, {%}\n", .{ |
| 7595 | instruction_index.name(&function).fmt(self), |
| 7596 | @tagName(tag), |
| 7597 | extra.val.fmt(function_index, self), |
| 7598 | extra.elem.fmt(function_index, self), |
| 7599 | extra.index.fmt(function_index, self), |
| 7600 | }); |
| 7601 | }, |
| 7602 | .insertvalue => |tag| { |
| 7603 | var extra = function.extraDataTrail( |
| 7604 | Function.Instruction.InsertValue, |
| 7605 | instruction.data, |
| 7606 | ); |
| 7607 | const indices = extra.trail.next(extra.data.indices_len, u32, &function); |
| 7608 | try writer.print(" %{} = {s} {%}, {%}", .{ |
| 7609 | instruction_index.name(&function).fmt(self), |
| 7610 | @tagName(tag), |
| 7611 | extra.data.val.fmt(function_index, self), |
| 7612 | extra.data.elem.fmt(function_index, self), |
| 7613 | }); |
| 7614 | for (indices) |index| try writer.print(", {d}", .{index}); |
| 7615 | try writer.writeByte('\n'); |
| 7616 | }, |
| 7617 | .@"llvm.maxnum.", |
| 7618 | .@"llvm.minnum.", |
| 7619 | .@"llvm.sadd.sat.", |
| 7620 | .@"llvm.smax.", |
| 7621 | .@"llvm.smin.", |
| 7622 | .@"llvm.smul.fix.sat.", |
| 7623 | .@"llvm.sshl.sat.", |
| 7624 | .@"llvm.ssub.sat.", |
| 7625 | .@"llvm.uadd.sat.", |
| 7626 | .@"llvm.umax.", |
| 7627 | .@"llvm.umin.", |
| 7628 | .@"llvm.umul.fix.sat.", |
| 7629 | .@"llvm.ushl.sat.", |
| 7630 | .@"llvm.usub.sat.", |
| 7631 | => |tag| { |
| 7632 | const extra = |
| 7633 | function.extraData(Function.Instruction.Binary, instruction.data); |
| 7634 | const ty = instruction_index.typeOf(function_index, self); |
| 7635 | try writer.print(" %{} = call {%} @{s}{m}({%}, {%}{s})\n", .{ |
| 7636 | instruction_index.name(&function).fmt(self), |
| 7637 | ty.fmt(self), |
| 7638 | @tagName(tag), |
| 7639 | ty.fmt(self), |
| 7640 | extra.lhs.fmt(function_index, self), |
| 7641 | extra.rhs.fmt(function_index, self), |
| 7642 | switch (tag) { |
| 7643 | .@"llvm.smul.fix.sat.", |
| 7644 | .@"llvm.umul.fix.sat.", |
| 7645 | => ", i32 0", |
| 7646 | else => "", |
| 7647 | }, |
| 7648 | }); |
| 7649 | }, |
| 7650 | .load, |
| 7651 | .@"load atomic", |
| 7652 | .@"load atomic volatile", |
| 7653 | .@"load volatile", |
| 7654 | => |tag| { |
| 7655 | const extra = |
| 7656 | function.extraData(Function.Instruction.Load, instruction.data); |
| 7657 | try writer.print(" %{} = {s} {%}, {%}{}{}{,}\n", .{ |
| 7658 | instruction_index.name(&function).fmt(self), |
| 7659 | @tagName(tag), |
| 7660 | extra.type.fmt(self), |
| 7661 | extra.ptr.fmt(function_index, self), |
| 7662 | extra.info.scope, |
| 7663 | extra.info.ordering, |
| 7664 | extra.info.alignment, |
| 7665 | }); |
| 7666 | }, |
| 7667 | .phi, |
| 7668 | .@"phi fast", |
| 7669 | => |tag| { |
| 7670 | var extra = |
| 7671 | function.extraDataTrail(Function.Instruction.Phi, instruction.data); |
| 7672 | const vals = extra.trail.next(block_incoming_len, Value, &function); |
| 7673 | const blocks = |
| 7674 | extra.trail.next(block_incoming_len, Function.Block.Index, &function); |
| 7675 | try writer.print(" %{} = {s} {%} ", .{ |
| 7676 | instruction_index.name(&function).fmt(self), |
| 7677 | @tagName(tag), |
| 7678 | vals[0].typeOf(function_index, self).fmt(self), |
| 7679 | }); |
| 7680 | for (0.., vals, blocks) |incoming_index, incoming_val, incoming_block| { |
| 7681 | if (incoming_index > 0) try writer.writeAll(", "); |
| 7682 | try writer.print("[ {}, {} ]", .{ |
| 7683 | incoming_val.fmt(function_index, self), |
| 7684 | incoming_block.toInst(&function).fmt(function_index, self), |
| 7685 | }); |
| 7686 | } |
| 7687 | try writer.writeByte('\n'); |
| 7688 | }, |
| 7689 | .@"ret void", |
| 7690 | .@"unreachable", |
| 7691 | => |tag| try writer.print(" {s}\n", .{@tagName(tag)}), |
| 7692 | .select, |
| 7693 | .@"select fast", |
| 7694 | => |tag| { |
| 7695 | const extra = |
| 7696 | function.extraData(Function.Instruction.Select, instruction.data); |
| 7697 | try writer.print(" %{} = {s} {%}, {%}, {%}\n", .{ |
| 7698 | instruction_index.name(&function).fmt(self), |
| 7699 | @tagName(tag), |
| 7700 | extra.cond.fmt(function_index, self), |
| 7701 | extra.lhs.fmt(function_index, self), |
| 7702 | extra.rhs.fmt(function_index, self), |
| 7703 | }); |
| 7704 | }, |
| 7705 | .shufflevector => |tag| { |
| 7706 | const extra = function.extraData( |
| 7707 | Function.Instruction.ShuffleVector, |
| 7708 | instruction.data, |
| 7709 | ); |
| 7710 | try writer.print(" %{} = {s} {%}, {%}, {%}\n", .{ |
| 7711 | instruction_index.name(&function).fmt(self), |
| 7712 | @tagName(tag), |
| 7713 | extra.lhs.fmt(function_index, self), |
| 7714 | extra.rhs.fmt(function_index, self), |
| 7715 | extra.mask.fmt(function_index, self), |
| 7716 | }); |
| 7717 | }, |
| 7718 | .store, |
| 7719 | .@"store atomic", |
| 7720 | .@"store atomic volatile", |
| 7721 | .@"store volatile", |
| 7722 | => |tag| { |
| 7723 | const extra = |
| 7724 | function.extraData(Function.Instruction.Store, instruction.data); |
| 7725 | try writer.print(" {s} {%}, {%}{}{}{,}\n", .{ |
| 7726 | @tagName(tag), |
| 7727 | extra.val.fmt(function_index, self), |
| 7728 | extra.ptr.fmt(function_index, self), |
| 7729 | extra.info.scope, |
| 7730 | extra.info.ordering, |
| 7731 | extra.info.alignment, |
| 7732 | }); |
| 7733 | }, |
| 7734 | .@"switch" => |tag| { |
| 7735 | var extra = |
| 7736 | function.extraDataTrail(Function.Instruction.Switch, instruction.data); |
| 7737 | const vals = extra.trail.next(extra.data.cases_len, Constant, &function); |
| 7738 | const blocks = |
| 7739 | extra.trail.next(extra.data.cases_len, Function.Block.Index, &function); |
| 7740 | try writer.print(" {s} {%}, {%} [\n", .{ |
| 7741 | @tagName(tag), |
| 7742 | extra.data.val.fmt(function_index, self), |
| 7743 | extra.data.default.toInst(&function).fmt(function_index, self), |
| 7744 | }); |
| 7745 | for (vals, blocks) |case_val, case_block| try writer.print( |
| 7746 | " {%}, {%}\n", |
| 7747 | .{ |
| 7748 | case_val.fmt(self), |
| 7749 | case_block.toInst(&function).fmt(function_index, self), |
| 7750 | }, |
| 7751 | ); |
| 7752 | try writer.writeAll(" ]\n"); |
| 7753 | }, |
| 7754 | .unimplemented => |tag| { |
| 7755 | const ty: Type = @enumFromInt(instruction.data); |
| 7756 | if (true) { |
| 7757 | try writer.writeAll(" "); |
| 7758 | switch (ty) { |
| 7759 | .none, .void => {}, |
| 7760 | else => try writer.print("%{} = ", .{ |
| 7761 | instruction_index.name(&function).fmt(self), |
| 7762 | }), |
| 7763 | } |
| 7764 | try writer.print("{s} {%}\n", .{ @tagName(tag), ty.fmt(self) }); |
| 7765 | } else switch (ty) { |
| 7766 | .none, .void => {}, |
| 7767 | else => try writer.print(" %{} = load {%}, ptr undef\n", .{ |
| 7768 | instruction_index.name(&function).fmt(self), |
| 7769 | ty.fmt(self), |
| 7770 | }), |
| 7771 | } |
| 7772 | }, |
| 7773 | .va_arg => |tag| { |
| 7774 | const extra = |
| 7775 | function.extraData(Function.Instruction.VaArg, instruction.data); |
| 7776 | try writer.print(" %{} = {s} {%}, {%}\n", .{ |
| 7777 | instruction_index.name(&function).fmt(self), |
| 7778 | @tagName(tag), |
| 7779 | extra.list.fmt(function_index, self), |
| 7780 | extra.type.fmt(self), |
| 7781 | }); |
| 7782 | }, |
| 7783 | } |
| 6215 | 7784 | } |
| 7785 | try writer.writeByte('}'); |
| 6216 | 7786 | } |
| 6217 | | try writer.writeByte('}'); |
| 7787 | try writer.writeByte('\n'); |
| 6218 | 7788 | } |
| 6219 | | try writer.writeAll("\n\n"); |
| 7789 | need_newline = true; |
| 7790 | } |
| 7791 | |
| 7792 | if (attribute_groups.count() > 0) { |
| 7793 | if (need_newline) try writer.writeByte('\n') else need_newline = true; |
| 7794 | for (0.., attribute_groups.keys()) |attribute_group_index, attribute_group| |
| 7795 | try writer.print( |
| 7796 | \\attributes #{d} = {{{#"} }} |
| 7797 | \\ |
| 7798 | , .{ attribute_group_index, attribute_group.fmt(self) }); |
| 7799 | need_newline = true; |
| 6220 | 7800 | } |
| 6221 | 7801 | } |
| 6222 | 7802 | |
| ... | ... | @@ -6227,7 +7807,7 @@ pub inline fn useLibLlvm(self: *const Builder) bool { |
| 6227 | 7807 | const NoExtra = struct {}; |
| 6228 | 7808 | |
| 6229 | 7809 | fn isValidIdentifier(id: []const u8) bool { |
| 6230 | | for (id, 0..) |character, index| switch (character) { |
| 7810 | for (id, 0..) |byte, index| switch (byte) { |
| 6231 | 7811 | '$', '-', '.', 'A'...'Z', '_', 'a'...'z' => {}, |
| 6232 | 7812 | '0'...'9' => if (index == 0) return false, |
| 6233 | 7813 | else => return false, |
| ... | ... | @@ -6235,10 +7815,29 @@ fn isValidIdentifier(id: []const u8) bool { |
| 6235 | 7815 | return true; |
| 6236 | 7816 | } |
| 6237 | 7817 | |
| 7818 | const QuoteBehavior = enum { always_quote, quote_unless_valid_identifier }; |
| 7819 | fn printEscapedString( |
| 7820 | slice: []const u8, |
| 7821 | quotes: QuoteBehavior, |
| 7822 | writer: anytype, |
| 7823 | ) @TypeOf(writer).Error!void { |
| 7824 | const need_quotes = switch (quotes) { |
| 7825 | .always_quote => true, |
| 7826 | .quote_unless_valid_identifier => !isValidIdentifier(slice), |
| 7827 | }; |
| 7828 | if (need_quotes) try writer.writeByte('"'); |
| 7829 | for (slice) |byte| switch (byte) { |
| 7830 | '\\' => try writer.writeAll("\\\\"), |
| 7831 | ' '...'"' - 1, '"' + 1...'\\' - 1, '\\' + 1...'~' => try writer.writeByte(byte), |
| 7832 | else => try writer.print("\\{X:0>2}", .{byte}), |
| 7833 | }; |
| 7834 | if (need_quotes) try writer.writeByte('"'); |
| 7835 | } |
| 7836 | |
| 6238 | 7837 | fn ensureUnusedGlobalCapacity(self: *Builder, name: String) Allocator.Error!void { |
| 6239 | 7838 | if (self.useLibLlvm()) try self.llvm.globals.ensureUnusedCapacity(self.gpa, 1); |
| 6240 | 7839 | try self.string_map.ensureUnusedCapacity(self.gpa, 1); |
| 6241 | | if (name.toSlice(self)) |id| { |
| 7840 | if (name.slice(self)) |id| { |
| 6242 | 7841 | const count: usize = comptime std.fmt.count("{d}" ++ .{0}, .{std.math.maxInt(u32)}); |
| 6243 | 7842 | try self.string_bytes.ensureUnusedCapacity(self.gpa, id.len + count); |
| 6244 | 7843 | } |
| ... | ... | @@ -6528,14 +8127,14 @@ fn opaqueTypeAssumeCapacity(self: *Builder, name: String) Type { |
| 6528 | 8127 | const result: Type = @enumFromInt(gop.index); |
| 6529 | 8128 | type_gop.value_ptr.* = result; |
| 6530 | 8129 | if (self.useLibLlvm()) self.llvm.types.appendAssumeCapacity( |
| 6531 | | self.llvm.context.structCreateNamed(id.toSlice(self) orelse ""), |
| 8130 | self.llvm.context.structCreateNamed(id.slice(self) orelse ""), |
| 6532 | 8131 | ); |
| 6533 | 8132 | return result; |
| 6534 | 8133 | } |
| 6535 | 8134 | |
| 6536 | 8135 | const unique_gop = self.next_unique_type_id.getOrPutAssumeCapacity(name); |
| 6537 | 8136 | if (!unique_gop.found_existing) unique_gop.value_ptr.* = 2; |
| 6538 | | id = self.fmtAssumeCapacity("{s}.{d}", .{ name.toSlice(self).?, unique_gop.value_ptr.* }); |
| 8137 | id = self.fmtAssumeCapacity("{s}.{d}", .{ name.slice(self).?, unique_gop.value_ptr.* }); |
| 6539 | 8138 | unique_gop.value_ptr.* += 1; |
| 6540 | 8139 | } |
| 6541 | 8140 | } |
| ... | ... | @@ -6636,6 +8235,30 @@ fn typeExtraData(self: *const Builder, comptime T: type, index: Type.Item.ExtraI |
| 6636 | 8235 | return self.typeExtraDataTrail(T, index).data; |
| 6637 | 8236 | } |
| 6638 | 8237 | |
| 8238 | fn attrGeneric(self: *Builder, data: []const u32) Allocator.Error!u32 { |
| 8239 | try self.attributes_map.ensureUnusedCapacity(self.gpa, 1); |
| 8240 | try self.attributes_indices.ensureUnusedCapacity(self.gpa, 1); |
| 8241 | try self.attributes_extra.ensureUnusedCapacity(self.gpa, data.len); |
| 8242 | |
| 8243 | const Adapter = struct { |
| 8244 | builder: *const Builder, |
| 8245 | pub fn hash(_: @This(), key: []const u32) u32 { |
| 8246 | return @truncate(std.hash.Wyhash.hash(1, std.mem.sliceAsBytes(key))); |
| 8247 | } |
| 8248 | pub fn eql(ctx: @This(), lhs_key: []const u32, _: void, rhs_index: usize) bool { |
| 8249 | const start = ctx.builder.attributes_indices.items[rhs_index]; |
| 8250 | const end = ctx.builder.attributes_indices.items[rhs_index + 1]; |
| 8251 | return std.mem.eql(u32, lhs_key, ctx.builder.attributes_extra.items[start..end]); |
| 8252 | } |
| 8253 | }; |
| 8254 | const gop = self.attributes_map.getOrPutAssumeCapacityAdapted(data, Adapter{ .builder = self }); |
| 8255 | if (!gop.found_existing) { |
| 8256 | self.attributes_extra.appendSliceAssumeCapacity(data); |
| 8257 | self.attributes_indices.appendAssumeCapacity(@intCast(self.attributes_extra.items.len)); |
| 8258 | } |
| 8259 | return @intCast(gop.index); |
| 8260 | } |
| 8261 | |
| 6639 | 8262 | fn bigIntConstAssumeCapacity( |
| 6640 | 8263 | self: *Builder, |
| 6641 | 8264 | ty: Type, |
| ... | ... | @@ -7073,7 +8696,7 @@ fn arrayConstAssumeCapacity( |
| 7073 | 8696 | } |
| 7074 | 8697 | |
| 7075 | 8698 | fn stringConstAssumeCapacity(self: *Builder, val: String) Constant { |
| 7076 | | const slice = val.toSlice(self).?; |
| 8699 | const slice = val.slice(self).?; |
| 7077 | 8700 | const ty = self.arrayTypeAssumeCapacity(slice.len, .i8); |
| 7078 | 8701 | if (std.mem.allEqual(u8, slice, 0)) return self.zeroInitConstAssumeCapacity(ty); |
| 7079 | 8702 | const result = self.getOrPutConstantNoExtraAssumeCapacity( |
| ... | ... | @@ -7086,7 +8709,7 @@ fn stringConstAssumeCapacity(self: *Builder, val: String) Constant { |
| 7086 | 8709 | } |
| 7087 | 8710 | |
| 7088 | 8711 | fn stringNullConstAssumeCapacity(self: *Builder, val: String) Constant { |
| 7089 | | const slice = val.toSlice(self).?; |
| 8712 | const slice = val.slice(self).?; |
| 7090 | 8713 | const ty = self.arrayTypeAssumeCapacity(slice.len + 1, .i8); |
| 7091 | 8714 | if (std.mem.allEqual(u8, slice, 0)) return self.zeroInitConstAssumeCapacity(ty); |
| 7092 | 8715 | const result = self.getOrPutConstantNoExtraAssumeCapacity( |
| ... | ... | @@ -7737,30 +9360,30 @@ fn binConstAssumeCapacity( |
| 7737 | 9360 | => {}, |
| 7738 | 9361 | else => unreachable, |
| 7739 | 9362 | } |
| 7740 | | const Key = struct { tag: Constant.Tag, bin: Constant.Binary }; |
| 9363 | const Key = struct { tag: Constant.Tag, extra: Constant.Binary }; |
| 7741 | 9364 | const Adapter = struct { |
| 7742 | 9365 | builder: *const Builder, |
| 7743 | 9366 | pub fn hash(_: @This(), key: Key) u32 { |
| 7744 | 9367 | return @truncate(std.hash.Wyhash.hash( |
| 7745 | 9368 | std.hash.uint32(@intFromEnum(key.tag)), |
| 7746 | | std.mem.asBytes(&key.bin), |
| 9369 | std.mem.asBytes(&key.extra), |
| 7747 | 9370 | )); |
| 7748 | 9371 | } |
| 7749 | 9372 | pub fn eql(ctx: @This(), lhs_key: Key, _: void, rhs_index: usize) bool { |
| 7750 | 9373 | if (lhs_key.tag != ctx.builder.constant_items.items(.tag)[rhs_index]) return false; |
| 7751 | 9374 | const rhs_data = ctx.builder.constant_items.items(.data)[rhs_index]; |
| 7752 | 9375 | const rhs_extra = ctx.builder.constantExtraData(Constant.Binary, rhs_data); |
| 7753 | | return std.meta.eql(lhs_key.bin, rhs_extra); |
| 9376 | return std.meta.eql(lhs_key.extra, rhs_extra); |
| 7754 | 9377 | } |
| 7755 | 9378 | }; |
| 7756 | | const data = Key{ .tag = tag, .bin = .{ .lhs = lhs, .rhs = rhs } }; |
| 9379 | const data = Key{ .tag = tag, .extra = .{ .lhs = lhs, .rhs = rhs } }; |
| 7757 | 9380 | const gop = self.constant_map.getOrPutAssumeCapacityAdapted(data, Adapter{ .builder = self }); |
| 7758 | 9381 | if (!gop.found_existing) { |
| 7759 | 9382 | gop.key_ptr.* = {}; |
| 7760 | 9383 | gop.value_ptr.* = {}; |
| 7761 | 9384 | self.constant_items.appendAssumeCapacity(.{ |
| 7762 | 9385 | .tag = tag, |
| 7763 | | .data = self.addConstantExtraAssumeCapacity(data.bin), |
| 9386 | .data = self.addConstantExtraAssumeCapacity(data.extra), |
| 7764 | 9387 | }); |
| 7765 | 9388 | if (self.useLibLlvm()) self.llvm.constants.appendAssumeCapacity(switch (tag) { |
| 7766 | 9389 | .add => &llvm.Value.constAdd, |
| ... | ... | @@ -7778,6 +9401,63 @@ fn binConstAssumeCapacity( |
| 7778 | 9401 | return @enumFromInt(gop.index); |
| 7779 | 9402 | } |
| 7780 | 9403 | |
| 9404 | fn asmConstAssumeCapacity( |
| 9405 | self: *Builder, |
| 9406 | ty: Type, |
| 9407 | info: Constant.Asm.Info, |
| 9408 | assembly: String, |
| 9409 | constraints: String, |
| 9410 | ) Constant { |
| 9411 | assert(ty.functionKind(self) == .normal); |
| 9412 | |
| 9413 | const Key = struct { tag: Constant.Tag, extra: Constant.Asm }; |
| 9414 | const Adapter = struct { |
| 9415 | builder: *const Builder, |
| 9416 | pub fn hash(_: @This(), key: Key) u32 { |
| 9417 | return @truncate(std.hash.Wyhash.hash( |
| 9418 | std.hash.uint32(@intFromEnum(key.tag)), |
| 9419 | std.mem.asBytes(&key.extra), |
| 9420 | )); |
| 9421 | } |
| 9422 | pub fn eql(ctx: @This(), lhs_key: Key, _: void, rhs_index: usize) bool { |
| 9423 | if (lhs_key.tag != ctx.builder.constant_items.items(.tag)[rhs_index]) return false; |
| 9424 | const rhs_data = ctx.builder.constant_items.items(.data)[rhs_index]; |
| 9425 | const rhs_extra = ctx.builder.constantExtraData(Constant.Asm, rhs_data); |
| 9426 | return std.meta.eql(lhs_key.extra, rhs_extra); |
| 9427 | } |
| 9428 | }; |
| 9429 | |
| 9430 | const data = Key{ |
| 9431 | .tag = @enumFromInt(@intFromEnum(Constant.Tag.@"asm") + @as(u4, @bitCast(info))), |
| 9432 | .extra = .{ .type = ty, .assembly = assembly, .constraints = constraints }, |
| 9433 | }; |
| 9434 | const gop = self.constant_map.getOrPutAssumeCapacityAdapted(data, Adapter{ .builder = self }); |
| 9435 | if (!gop.found_existing) { |
| 9436 | gop.key_ptr.* = {}; |
| 9437 | gop.value_ptr.* = {}; |
| 9438 | self.constant_items.appendAssumeCapacity(.{ |
| 9439 | .tag = data.tag, |
| 9440 | .data = self.addConstantExtraAssumeCapacity(data.extra), |
| 9441 | }); |
| 9442 | if (self.useLibLlvm()) { |
| 9443 | const assembly_slice = assembly.slice(self).?; |
| 9444 | const constraints_slice = constraints.slice(self).?; |
| 9445 | self.llvm.constants.appendAssumeCapacity(llvm.getInlineAsm( |
| 9446 | ty.toLlvm(self), |
| 9447 | assembly_slice.ptr, |
| 9448 | assembly_slice.len, |
| 9449 | constraints_slice.ptr, |
| 9450 | constraints_slice.len, |
| 9451 | llvm.Bool.fromBool(info.sideeffect), |
| 9452 | llvm.Bool.fromBool(info.alignstack), |
| 9453 | if (info.inteldialect) .Intel else .ATT, |
| 9454 | llvm.Bool.fromBool(info.unwind), |
| 9455 | )); |
| 9456 | } |
| 9457 | } |
| 9458 | return @enumFromInt(gop.index); |
| 9459 | } |
| 9460 | |
| 7781 | 9461 | fn ensureUnusedConstantCapacity( |
| 7782 | 9462 | self: *Builder, |
| 7783 | 9463 | count: usize, |
| ... | ... | @@ -7868,7 +9548,7 @@ fn addConstantExtraAssumeCapacity(self: *Builder, extra: anytype) Constant.Item. |
| 7868 | 9548 | const value = @field(extra, field.name); |
| 7869 | 9549 | self.constant_extra.appendAssumeCapacity(switch (field.type) { |
| 7870 | 9550 | u32 => value, |
| 7871 | | Type, Constant, Function.Index, Function.Block.Index => @intFromEnum(value), |
| 9551 | String, Type, Constant, Function.Index, Function.Block.Index => @intFromEnum(value), |
| 7872 | 9552 | Constant.GetElementPtr.Info => @bitCast(value), |
| 7873 | 9553 | else => @compileError("bad field type: " ++ @typeName(field.type)), |
| 7874 | 9554 | }); |
| ... | ... | @@ -7907,7 +9587,7 @@ fn constantExtraDataTrail( |
| 7907 | 9587 | inline for (fields, self.constant_extra.items[index..][0..fields.len]) |field, value| |
| 7908 | 9588 | @field(result, field.name) = switch (field.type) { |
| 7909 | 9589 | u32 => value, |
| 7910 | | Type, Constant, Function.Index, Function.Block.Index => @enumFromInt(value), |
| 9590 | String, Type, Constant, Function.Index, Function.Block.Index => @enumFromInt(value), |
| 7911 | 9591 | Constant.GetElementPtr.Info => @bitCast(value), |
| 7912 | 9592 | else => @compileError("bad field type: " ++ @typeName(field.type)), |
| 7913 | 9593 | }; |