| ... | @@ -29,6 +29,7 @@ type_extra: std.ArrayListUnmanaged(u32) = .{}, | ... | @@ -29,6 +29,7 @@ type_extra: std.ArrayListUnmanaged(u32) = .{}, |
| 29 | | 29 | |
| 30 | globals: std.AutoArrayHashMapUnmanaged(String, Global) = .{}, | 30 | globals: std.AutoArrayHashMapUnmanaged(String, Global) = .{}, |
| 31 | next_unnamed_global: String = @enumFromInt(0), | 31 | next_unnamed_global: String = @enumFromInt(0), |
| | 32 | next_replaced_global: String = .none, |
| 32 | next_unique_global_id: std.AutoHashMapUnmanaged(String, u32) = .{}, | 33 | next_unique_global_id: std.AutoHashMapUnmanaged(String, u32) = .{}, |
| 33 | aliases: std.ArrayListUnmanaged(Alias) = .{}, | 34 | aliases: std.ArrayListUnmanaged(Alias) = .{}, |
| 34 | variables: std.ArrayListUnmanaged(Variable) = .{}, | 35 | variables: std.ArrayListUnmanaged(Variable) = .{}, |
| ... | @@ -55,6 +56,11 @@ pub const String = enum(u32) { | ... | @@ -55,6 +56,11 @@ pub const String = enum(u32) { |
| 55 | empty, | 56 | empty, |
| 56 | _, | 57 | _, |
| 57 | | 58 | |
| | 59 | pub fn isAnon(self: String) bool { |
| | 60 | assert(self != .none); |
| | 61 | return self.toIndex() == null; |
| | 62 | } |
| | 63 | |
| 58 | pub fn toSlice(self: String, b: *const Builder) ?[:0]const u8 { | 64 | pub fn toSlice(self: String, b: *const Builder) ?[:0]const u8 { |
| 59 | const index = self.toIndex() orelse return null; | 65 | const index = self.toIndex() orelse return null; |
| 60 | const start = b.string_indices.items[index]; | 66 | const start = b.string_indices.items[index]; |
| ... | @@ -743,18 +749,36 @@ pub const Global = struct { | ... | @@ -743,18 +749,36 @@ pub const Global = struct { |
| 743 | alias: Alias.Index, | 749 | alias: Alias.Index, |
| 744 | variable: Variable.Index, | 750 | variable: Variable.Index, |
| 745 | function: Function.Index, | 751 | function: Function.Index, |
| | 752 | replaced: Global.Index, |
| 746 | }, | 753 | }, |
| 747 | | 754 | |
| 748 | pub const Index = enum(u32) { | 755 | pub const Index = enum(u32) { |
| 749 | none = std.math.maxInt(u32), | 756 | none = std.math.maxInt(u32), |
| 750 | _, | 757 | _, |
| 751 | | 758 | |
| | 759 | pub fn unwrap(self: Index, builder: *const Builder) Index { |
| | 760 | var cur = self; |
| | 761 | while (true) { |
| | 762 | const replacement = cur.getReplacement(builder); |
| | 763 | if (replacement == .none) return cur; |
| | 764 | cur = replacement; |
| | 765 | } |
| | 766 | } |
| | 767 | |
| | 768 | pub fn eql(self: Index, other: Index, builder: *const Builder) bool { |
| | 769 | return self.unwrap(builder) == other.unwrap(builder); |
| | 770 | } |
| | 771 | |
| | 772 | pub fn name(self: Index, builder: *const Builder) String { |
| | 773 | return builder.globals.keys()[@intFromEnum(self.unwrap(builder))]; |
| | 774 | } |
| | 775 | |
| 752 | pub fn ptr(self: Index, builder: *Builder) *Global { | 776 | pub fn ptr(self: Index, builder: *Builder) *Global { |
| 753 | return &builder.globals.values()[@intFromEnum(self)]; | 777 | return &builder.globals.values()[@intFromEnum(self.unwrap(builder))]; |
| 754 | } | 778 | } |
| 755 | | 779 | |
| 756 | pub fn ptrConst(self: Index, builder: *const Builder) *const Global { | 780 | pub fn ptrConst(self: Index, builder: *const Builder) *const Global { |
| 757 | return &builder.globals.values()[@intFromEnum(self)]; | 781 | return &builder.globals.values()[@intFromEnum(self.unwrap(builder))]; |
| 758 | } | 782 | } |
| 759 | | 783 | |
| 760 | pub fn toConst(self: Index) Constant { | 784 | pub fn toConst(self: Index) Constant { |
| ... | @@ -763,7 +787,7 @@ pub const Global = struct { | ... | @@ -763,7 +787,7 @@ pub const Global = struct { |
| 763 | | 787 | |
| 764 | pub fn toLlvm(self: Index, builder: *const Builder) *llvm.Value { | 788 | pub fn toLlvm(self: Index, builder: *const Builder) *llvm.Value { |
| 765 | assert(builder.useLibLlvm()); | 789 | assert(builder.useLibLlvm()); |
| 766 | return builder.llvm.globals.items[@intFromEnum(self)]; | 790 | return builder.llvm.globals.items[@intFromEnum(self.unwrap(builder))]; |
| 767 | } | 791 | } |
| 768 | | 792 | |
| 769 | const FormatData = struct { | 793 | const FormatData = struct { |
| ... | @@ -777,44 +801,80 @@ pub const Global = struct { | ... | @@ -777,44 +801,80 @@ pub const Global = struct { |
| 777 | writer: anytype, | 801 | writer: anytype, |
| 778 | ) @TypeOf(writer).Error!void { | 802 | ) @TypeOf(writer).Error!void { |
| 779 | try writer.print("@{}", .{ | 803 | try writer.print("@{}", .{ |
| 780 | data.builder.globals.keys()[@intFromEnum(data.global)].fmt(data.builder), | 804 | data.global.unwrap(data.builder).name(data.builder).fmt(data.builder), |
| 781 | }); | 805 | }); |
| 782 | } | 806 | } |
| 783 | pub fn fmt(self: Index, builder: *const Builder) std.fmt.Formatter(format) { | 807 | pub fn fmt(self: Index, builder: *const Builder) std.fmt.Formatter(format) { |
| 784 | return .{ .data = .{ .global = self, .builder = builder } }; | 808 | return .{ .data = .{ .global = self, .builder = builder } }; |
| 785 | } | 809 | } |
| 786 | | 810 | |
| 787 | pub fn rename(self: Index, builder: *Builder, name: String) Allocator.Error!void { | 811 | pub fn rename(self: Index, new_name: String, builder: *Builder) Allocator.Error!void { |
| 788 | try builder.ensureUnusedCapacityGlobal(name); | 812 | try builder.ensureUnusedCapacityGlobal(new_name); |
| 789 | self.renameAssumeCapacity(builder, name); | 813 | self.renameAssumeCapacity(new_name, builder); |
| 790 | } | 814 | } |
| 791 | | 815 | |
| 792 | pub fn renameAssumeCapacity(self: Index, builder: *Builder, name: String) void { | 816 | pub fn takeName(self: Index, other: Index, builder: *Builder) Allocator.Error!void { |
| 793 | const index = @intFromEnum(self); | 817 | try builder.ensureUnusedCapacityGlobal(.empty); |
| 794 | if (builder.globals.keys()[index] == name) return; | 818 | self.takeNameAssumeCapacity(other, builder); |
| 795 | if (builder.useLibLlvm()) builder.llvm.globals.appendAssumeCapacity(builder.llvm.globals.items[index]); | | |
| 796 | _ = builder.addGlobalAssumeCapacity(name, builder.globals.values()[index]); | | |
| 797 | if (builder.useLibLlvm()) _ = builder.llvm.globals.pop(); | | |
| 798 | builder.globals.swapRemoveAt(index); | | |
| 799 | self.updateName(builder); | | |
| 800 | } | 819 | } |
| 801 | | 820 | |
| 802 | pub fn takeName(self: Index, builder: *Builder, other: Index) Allocator.Error!void { | 821 | pub fn replace(self: Index, other: Index, builder: *Builder) Allocator.Error!void { |
| 803 | try builder.ensureUnusedCapacityGlobal(.empty); | 822 | try builder.ensureUnusedCapacityGlobal(.empty); |
| 804 | self.takeNameAssumeCapacity(builder, other); | 823 | self.replaceAssumeCapacity(other, builder); |
| | 824 | } |
| | 825 | |
| | 826 | fn renameAssumeCapacity(self: Index, new_name: String, builder: *Builder) void { |
| | 827 | const old_name = self.name(builder); |
| | 828 | if (new_name == old_name) return; |
| | 829 | const index = @intFromEnum(self.unwrap(builder)); |
| | 830 | if (builder.useLibLlvm()) |
| | 831 | builder.llvm.globals.appendAssumeCapacity(builder.llvm.globals.items[index]); |
| | 832 | _ = builder.addGlobalAssumeCapacity(new_name, builder.globals.values()[index]); |
| | 833 | if (builder.useLibLlvm()) _ = builder.llvm.globals.pop(); |
| | 834 | builder.globals.swapRemoveAt(index); |
| | 835 | self.updateName(builder); |
| | 836 | if (!old_name.isAnon()) return; |
| | 837 | builder.next_unnamed_global = @enumFromInt(@intFromEnum(builder.next_unnamed_global) - 1); |
| | 838 | if (builder.next_unnamed_global == old_name) return; |
| | 839 | builder.getGlobal(builder.next_unnamed_global).?.renameAssumeCapacity(old_name, builder); |
| 805 | } | 840 | } |
| 806 | | 841 | |
| 807 | pub fn takeNameAssumeCapacity(self: Index, builder: *Builder, other: Index) void { | 842 | fn takeNameAssumeCapacity(self: Index, other: Index, builder: *Builder) void { |
| 808 | const other_name = builder.globals.keys()[@intFromEnum(other)]; | 843 | const other_name = other.name(builder); |
| 809 | other.renameAssumeCapacity(builder, .none); | 844 | other.renameAssumeCapacity(.empty, builder); |
| 810 | self.renameAssumeCapacity(builder, other_name); | 845 | self.renameAssumeCapacity(other_name, builder); |
| 811 | } | 846 | } |
| 812 | | 847 | |
| 813 | fn updateName(self: Index, builder: *const Builder) void { | 848 | fn updateName(self: Index, builder: *const Builder) void { |
| 814 | if (!builder.useLibLlvm()) return; | 849 | if (!builder.useLibLlvm()) return; |
| 815 | const index = @intFromEnum(self); | 850 | const index = @intFromEnum(self.unwrap(builder)); |
| 816 | const slice = builder.globals.keys()[index].toSlice(builder) orelse ""; | 851 | const name_slice = self.name(builder).toSlice(builder) orelse ""; |
| 817 | builder.llvm.globals.items[index].setValueName2(slice.ptr, slice.len); | 852 | builder.llvm.globals.items[index].setValueName2(name_slice.ptr, name_slice.len); |
| | 853 | } |
| | 854 | |
| | 855 | fn replaceAssumeCapacity(self: Index, other: Index, builder: *Builder) void { |
| | 856 | if (self.eql(other, builder)) return; |
| | 857 | builder.next_replaced_global = @enumFromInt(@intFromEnum(builder.next_replaced_global) - 1); |
| | 858 | self.renameAssumeCapacity(builder.next_replaced_global, builder); |
| | 859 | if (builder.useLibLlvm()) { |
| | 860 | const self_llvm = self.toLlvm(builder); |
| | 861 | self_llvm.replaceAllUsesWith(other.toLlvm(builder)); |
| | 862 | switch (self.ptr(builder).kind) { |
| | 863 | .alias, |
| | 864 | .variable, |
| | 865 | => self_llvm.deleteGlobal(), |
| | 866 | .function => self_llvm.deleteFunction(), |
| | 867 | .replaced => unreachable, |
| | 868 | } |
| | 869 | } |
| | 870 | self.ptr(builder).kind = .{ .replaced = other.unwrap(builder) }; |
| | 871 | } |
| | 872 | |
| | 873 | fn getReplacement(self: Index, builder: *const Builder) Index { |
| | 874 | return switch (builder.globals.values()[@intFromEnum(self)].kind) { |
| | 875 | .replaced => |replacement| replacement, |
| | 876 | else => .none, |
| | 877 | }; |
| 818 | } | 878 | } |
| 819 | }; | 879 | }; |
| 820 | | 880 | |
| ... | @@ -1014,8 +1074,14 @@ pub const Constant = enum(u32) { | ... | @@ -1014,8 +1074,14 @@ pub const Constant = enum(u32) { |
| 1014 | insertelement, | 1074 | insertelement, |
| 1015 | shufflevector, | 1075 | shufflevector, |
| 1016 | add, | 1076 | add, |
| | 1077 | @"add nsw", |
| | 1078 | @"add nuw", |
| 1017 | sub, | 1079 | sub, |
| | 1080 | @"sub nsw", |
| | 1081 | @"sub nuw", |
| 1018 | mul, | 1082 | mul, |
| | 1083 | @"mul nsw", |
| | 1084 | @"mul nuw", |
| 1019 | shl, | 1085 | shl, |
| 1020 | lshr, | 1086 | lshr, |
| 1021 | ashr, | 1087 | ashr, |
| ... | @@ -1084,24 +1150,24 @@ pub const Constant = enum(u32) { | ... | @@ -1084,24 +1150,24 @@ pub const Constant = enum(u32) { |
| 1084 | pub const Kind = enum { normal, inbounds }; | 1150 | pub const Kind = enum { normal, inbounds }; |
| 1085 | }; | 1151 | }; |
| 1086 | | 1152 | |
| 1087 | pub const Compare = struct { | 1153 | pub const Compare = extern struct { |
| 1088 | cond: u32, | 1154 | cond: u32, |
| 1089 | lhs: Constant, | 1155 | lhs: Constant, |
| 1090 | rhs: Constant, | 1156 | rhs: Constant, |
| 1091 | }; | 1157 | }; |
| 1092 | | 1158 | |
| 1093 | pub const ExtractElement = struct { | 1159 | pub const ExtractElement = extern struct { |
| 1094 | arg: Constant, | 1160 | arg: Constant, |
| 1095 | index: Constant, | 1161 | index: Constant, |
| 1096 | }; | 1162 | }; |
| 1097 | | 1163 | |
| 1098 | pub const InsertElement = struct { | 1164 | pub const InsertElement = extern struct { |
| 1099 | arg: Constant, | 1165 | arg: Constant, |
| 1100 | elem: Constant, | 1166 | elem: Constant, |
| 1101 | index: Constant, | 1167 | index: Constant, |
| 1102 | }; | 1168 | }; |
| 1103 | | 1169 | |
| 1104 | pub const ShuffleVector = struct { | 1170 | pub const ShuffleVector = extern struct { |
| 1105 | lhs: Constant, | 1171 | lhs: Constant, |
| 1106 | rhs: Constant, | 1172 | rhs: Constant, |
| 1107 | mask: Constant, | 1173 | mask: Constant, |
| ... | @@ -1243,8 +1309,14 @@ pub const Constant = enum(u32) { | ... | @@ -1243,8 +1309,14 @@ pub const Constant = enum(u32) { |
| 1243 | }; | 1309 | }; |
| 1244 | }, | 1310 | }, |
| 1245 | .add, | 1311 | .add, |
| | 1312 | .@"add nsw", |
| | 1313 | .@"add nuw", |
| 1246 | .sub, | 1314 | .sub, |
| | 1315 | .@"sub nsw", |
| | 1316 | .@"sub nuw", |
| 1247 | .mul, | 1317 | .mul, |
| | 1318 | .@"mul nsw", |
| | 1319 | .@"mul nuw", |
| 1248 | .shl, | 1320 | .shl, |
| 1249 | .lshr, | 1321 | .lshr, |
| 1250 | .ashr, | 1322 | .ashr, |
| ... | @@ -1326,14 +1398,14 @@ pub const Constant = enum(u32) { | ... | @@ -1326,14 +1398,14 @@ pub const Constant = enum(u32) { |
| 1326 | switch (item.tag) { | 1398 | switch (item.tag) { |
| 1327 | .positive_integer, | 1399 | .positive_integer, |
| 1328 | .negative_integer, | 1400 | .negative_integer, |
| 1329 | => { | 1401 | => |tag| { |
| 1330 | const extra: *align(@alignOf(std.math.big.Limb)) Integer = | 1402 | const extra: *align(@alignOf(std.math.big.Limb)) Integer = |
| 1331 | @ptrCast(data.builder.constant_limbs.items[item.data..][0..Integer.limbs]); | 1403 | @ptrCast(data.builder.constant_limbs.items[item.data..][0..Integer.limbs]); |
| 1332 | const limbs = data.builder.constant_limbs | 1404 | const limbs = data.builder.constant_limbs |
| 1333 | .items[item.data + Integer.limbs ..][0..extra.limbs_len]; | 1405 | .items[item.data + Integer.limbs ..][0..extra.limbs_len]; |
| 1334 | const bigint = std.math.big.int.Const{ | 1406 | const bigint = std.math.big.int.Const{ |
| 1335 | .limbs = limbs, | 1407 | .limbs = limbs, |
| 1336 | .positive = item.tag == .positive_integer, | 1408 | .positive = tag == .positive_integer, |
| 1337 | }; | 1409 | }; |
| 1338 | const ExpectedContents = extern struct { | 1410 | const ExpectedContents = extern struct { |
| 1339 | string: [(64 * 8 / std.math.log2(10)) + 2]u8, | 1411 | string: [(64 * 8 / std.math.log2(10)) + 2]u8, |
| ... | @@ -1352,23 +1424,63 @@ pub const Constant = enum(u32) { | ... | @@ -1352,23 +1424,63 @@ pub const Constant = enum(u32) { |
| 1352 | defer allocator.free(str); | 1424 | defer allocator.free(str); |
| 1353 | try writer.writeAll(str); | 1425 | try writer.writeAll(str); |
| 1354 | }, | 1426 | }, |
| | 1427 | .half, |
| | 1428 | .bfloat, |
| | 1429 | => |tag| try writer.print("0x{c}{X:0>4}", .{ @as(u8, switch (tag) { |
| | 1430 | .half => 'H', |
| | 1431 | .bfloat => 'R', |
| | 1432 | else => unreachable, |
| | 1433 | }), item.data >> switch (tag) { |
| | 1434 | .half => 0, |
| | 1435 | .bfloat => 16, |
| | 1436 | else => unreachable, |
| | 1437 | } }), |
| | 1438 | .float => try writer.print("0x{X:0>16}", .{ |
| | 1439 | @as(u64, @bitCast(@as(f64, @as(f32, @bitCast(item.data))))), |
| | 1440 | }), |
| | 1441 | .double => { |
| | 1442 | const extra = data.builder.constantExtraData(Double, item.data); |
| | 1443 | try writer.print("0x{X:0>8}{X:0>8}", .{ extra.hi, extra.lo }); |
| | 1444 | }, |
| | 1445 | .fp128, |
| | 1446 | .ppc_fp128, |
| | 1447 | => |tag| { |
| | 1448 | const extra = data.builder.constantExtraData(Fp128, item.data); |
| | 1449 | try writer.print("0x{c}{X:0>8}{X:0>8}{X:0>8}{X:0>8}", .{ |
| | 1450 | @as(u8, switch (tag) { |
| | 1451 | .fp128 => 'L', |
| | 1452 | .ppc_fp128 => 'M', |
| | 1453 | else => unreachable, |
| | 1454 | }), |
| | 1455 | extra.lo_hi, |
| | 1456 | extra.lo_lo, |
| | 1457 | extra.hi_hi, |
| | 1458 | extra.hi_lo, |
| | 1459 | }); |
| | 1460 | }, |
| | 1461 | .x86_fp80 => { |
| | 1462 | const extra = data.builder.constantExtraData(Fp80, item.data); |
| | 1463 | try writer.print("0xK{X:0>4}{X:0>8}{X:0>8}", .{ |
| | 1464 | extra.hi, extra.lo_hi, extra.lo_lo, |
| | 1465 | }); |
| | 1466 | }, |
| 1355 | .null, | 1467 | .null, |
| 1356 | .none, | 1468 | .none, |
| 1357 | .zeroinitializer, | 1469 | .zeroinitializer, |
| 1358 | .undef, | 1470 | .undef, |
| 1359 | .poison, | 1471 | .poison, |
| 1360 | => try writer.writeAll(@tagName(item.tag)), | 1472 | => |tag| try writer.writeAll(@tagName(tag)), |
| 1361 | .structure, | 1473 | .structure, |
| 1362 | .packed_structure, | 1474 | .packed_structure, |
| 1363 | .array, | 1475 | .array, |
| 1364 | .vector, | 1476 | .vector, |
| 1365 | => { | 1477 | => |tag| { |
| 1366 | const extra = data.builder.constantExtraDataTrail(Aggregate, item.data); | 1478 | const extra = data.builder.constantExtraDataTrail(Aggregate, item.data); |
| 1367 | const len = extra.data.type.aggregateLen(data.builder); | 1479 | const len = extra.data.type.aggregateLen(data.builder); |
| 1368 | const vals: []const Constant = | 1480 | const vals: []const Constant = |
| 1369 | @ptrCast(data.builder.constant_extra.items[extra.end..][0..len]); | 1481 | @ptrCast(data.builder.constant_extra.items[extra.end..][0..len]); |
| 1370 | | 1482 | |
| 1371 | try writer.writeAll(switch (item.tag) { | 1483 | try writer.writeAll(switch (tag) { |
| 1372 | .structure => "{ ", | 1484 | .structure => "{ ", |
| 1373 | .packed_structure => "<{ ", | 1485 | .packed_structure => "<{ ", |
| 1374 | .array => "[", | 1486 | .array => "[", |
| ... | @@ -1379,7 +1491,7 @@ pub const Constant = enum(u32) { | ... | @@ -1379,7 +1491,7 @@ pub const Constant = enum(u32) { |
| 1379 | if (index > 0) try writer.writeAll(", "); | 1491 | if (index > 0) try writer.writeAll(", "); |
| 1380 | try writer.print("{%}", .{val.fmt(data.builder)}); | 1492 | try writer.print("{%}", .{val.fmt(data.builder)}); |
| 1381 | } | 1493 | } |
| 1382 | try writer.writeAll(switch (item.tag) { | 1494 | try writer.writeAll(switch (tag) { |
| 1383 | .structure => " }", | 1495 | .structure => " }", |
| 1384 | .packed_structure => " }>", | 1496 | .packed_structure => " }>", |
| 1385 | .array => "]", | 1497 | .array => "]", |
| ... | @@ -1387,33 +1499,130 @@ pub const Constant = enum(u32) { | ... | @@ -1387,33 +1499,130 @@ pub const Constant = enum(u32) { |
| 1387 | else => unreachable, | 1499 | else => unreachable, |
| 1388 | }); | 1500 | }); |
| 1389 | }, | 1501 | }, |
| 1390 | .string => try writer.print( | 1502 | inline .string, |
| 1391 | \\c{"} | 1503 | .string_null, |
| 1392 | , .{@as(String, @enumFromInt(item.data)).fmt(data.builder)}), | 1504 | => |tag| try writer.print("c{\"" ++ switch (tag) { |
| 1393 | .string_null => try writer.print( | 1505 | .string => "", |
| 1394 | \\c{"@} | 1506 | .string_null => "@", |
| 1395 | , .{@as(String, @enumFromInt(item.data)).fmt(data.builder)}), | 1507 | else => unreachable, |
| 1396 | .blockaddress => { | 1508 | } ++ "}", .{@as(String, @enumFromInt(item.data)).fmt(data.builder)}), |
| | 1509 | .blockaddress => |tag| { |
| 1397 | const extra = data.builder.constantExtraData(BlockAddress, item.data); | 1510 | const extra = data.builder.constantExtraData(BlockAddress, item.data); |
| 1398 | const function = extra.function.ptrConst(data.builder); | 1511 | const function = extra.function.ptrConst(data.builder); |
| 1399 | try writer.print("{s}({}, %{d})", .{ | 1512 | try writer.print("{s}({}, %{d})", .{ |
| 1400 | @tagName(item.tag), | 1513 | @tagName(tag), |
| 1401 | function.global.fmt(data.builder), | 1514 | function.global.fmt(data.builder), |
| 1402 | @intFromEnum(extra.block), // TODO | 1515 | @intFromEnum(extra.block), // TODO |
| 1403 | }); | 1516 | }); |
| 1404 | }, | 1517 | }, |
| 1405 | .dso_local_equivalent, | 1518 | .dso_local_equivalent, |
| 1406 | .no_cfi, | 1519 | .no_cfi, |
| 1407 | => { | 1520 | => |tag| { |
| 1408 | const extra = data.builder.constantExtraData(FunctionReference, item.data); | 1521 | const extra = data.builder.constantExtraData(FunctionReference, item.data); |
| 1409 | try writer.print("{s} {}", .{ | 1522 | try writer.print("{s} {}", .{ |
| 1410 | @tagName(item.tag), | 1523 | @tagName(tag), |
| 1411 | extra.function.ptrConst(data.builder).global.fmt(data.builder), | 1524 | extra.function.ptrConst(data.builder).global.fmt(data.builder), |
| 1412 | }); | 1525 | }); |
| 1413 | }, | 1526 | }, |
| 1414 | else => try writer.print("<{s}:0x{X}>", .{ | 1527 | .trunc, |
| 1415 | @tagName(item.tag), @intFromEnum(data.constant), | 1528 | .zext, |
| 1416 | }), | 1529 | .sext, |
| | 1530 | .fptrunc, |
| | 1531 | .fpext, |
| | 1532 | .fptoui, |
| | 1533 | .fptosi, |
| | 1534 | .uitofp, |
| | 1535 | .sitofp, |
| | 1536 | .ptrtoint, |
| | 1537 | .inttoptr, |
| | 1538 | .bitcast, |
| | 1539 | .addrspacecast, |
| | 1540 | => |tag| { |
| | 1541 | const extra = data.builder.constantExtraData(Cast, item.data); |
| | 1542 | try writer.print("{s} ({%} to {%})", .{ |
| | 1543 | @tagName(tag), |
| | 1544 | extra.arg.fmt(data.builder), |
| | 1545 | extra.type.fmt(data.builder), |
| | 1546 | }); |
| | 1547 | }, |
| | 1548 | .getelementptr, |
| | 1549 | .@"getelementptr inbounds", |
| | 1550 | => |tag| { |
| | 1551 | const extra = data.builder.constantExtraDataTrail(GetElementPtr, item.data); |
| | 1552 | const indices: []const Constant = @ptrCast(data.builder.constant_extra |
| | 1553 | .items[extra.end..][0..extra.data.indices_len]); |
| | 1554 | try writer.print("{s} ({%}, {%}", .{ |
| | 1555 | @tagName(tag), |
| | 1556 | extra.data.type.fmt(data.builder), |
| | 1557 | extra.data.base.fmt(data.builder), |
| | 1558 | }); |
| | 1559 | for (indices) |index| try writer.print(", {%}", .{index.fmt(data.builder)}); |
| | 1560 | try writer.writeByte(')'); |
| | 1561 | }, |
| | 1562 | inline .icmp, |
| | 1563 | .fcmp, |
| | 1564 | => |tag| { |
| | 1565 | const extra = data.builder.constantExtraData(Compare, item.data); |
| | 1566 | try writer.print("{s} {s} ({%}, {%})", .{ |
| | 1567 | @tagName(tag), |
| | 1568 | @tagName(@as(switch (tag) { |
| | 1569 | .icmp => IntegerCondition, |
| | 1570 | .fcmp => FloatCondition, |
| | 1571 | else => unreachable, |
| | 1572 | }, @enumFromInt(extra.cond))), |
| | 1573 | extra.lhs.fmt(data.builder), |
| | 1574 | extra.rhs.fmt(data.builder), |
| | 1575 | }); |
| | 1576 | }, |
| | 1577 | .extractelement => |tag| { |
| | 1578 | const extra = data.builder.constantExtraData(ExtractElement, item.data); |
| | 1579 | try writer.print("{s} ({%}, {%})", .{ |
| | 1580 | @tagName(tag), |
| | 1581 | extra.arg.fmt(data.builder), |
| | 1582 | extra.index.fmt(data.builder), |
| | 1583 | }); |
| | 1584 | }, |
| | 1585 | .insertelement => |tag| { |
| | 1586 | const extra = data.builder.constantExtraData(InsertElement, item.data); |
| | 1587 | try writer.print("{s} ({%}, {%}, {%})", .{ |
| | 1588 | @tagName(tag), |
| | 1589 | extra.arg.fmt(data.builder), |
| | 1590 | extra.elem.fmt(data.builder), |
| | 1591 | extra.index.fmt(data.builder), |
| | 1592 | }); |
| | 1593 | }, |
| | 1594 | .shufflevector => |tag| { |
| | 1595 | const extra = data.builder.constantExtraData(ShuffleVector, item.data); |
| | 1596 | try writer.print("{s} ({%}, {%}, {%})", .{ |
| | 1597 | @tagName(tag), |
| | 1598 | extra.lhs.fmt(data.builder), |
| | 1599 | extra.rhs.fmt(data.builder), |
| | 1600 | extra.mask.fmt(data.builder), |
| | 1601 | }); |
| | 1602 | }, |
| | 1603 | .add, |
| | 1604 | .@"add nsw", |
| | 1605 | .@"add nuw", |
| | 1606 | .sub, |
| | 1607 | .@"sub nsw", |
| | 1608 | .@"sub nuw", |
| | 1609 | .mul, |
| | 1610 | .@"mul nsw", |
| | 1611 | .@"mul nuw", |
| | 1612 | .shl, |
| | 1613 | .lshr, |
| | 1614 | .ashr, |
| | 1615 | .@"and", |
| | 1616 | .@"or", |
| | 1617 | .xor, |
| | 1618 | => |tag| { |
| | 1619 | const extra = data.builder.constantExtraData(Binary, item.data); |
| | 1620 | try writer.print("{s} ({%}, {%})", .{ |
| | 1621 | @tagName(tag), |
| | 1622 | extra.lhs.fmt(data.builder), |
| | 1623 | extra.rhs.fmt(data.builder), |
| | 1624 | }); |
| | 1625 | }, |
| 1417 | } | 1626 | } |
| 1418 | }, | 1627 | }, |
| 1419 | .global => |global| try writer.print("{}", .{global.fmt(data.builder)}), | 1628 | .global => |global| try writer.print("{}", .{global.fmt(data.builder)}), |
| ... | @@ -1882,6 +2091,7 @@ pub fn namedTypeSetBody( | ... | @@ -1882,6 +2091,7 @@ pub fn namedTypeSetBody( |
| 1882 | } | 2091 | } |
| 1883 | | 2092 | |
| 1884 | pub fn addGlobal(self: *Builder, name: String, global: Global) Allocator.Error!Global.Index { | 2093 | pub fn addGlobal(self: *Builder, name: String, global: Global) Allocator.Error!Global.Index { |
| | 2094 | assert(!name.isAnon()); |
| 1885 | try self.ensureUnusedTypeCapacity(1, null, 0); | 2095 | try self.ensureUnusedTypeCapacity(1, null, 0); |
| 1886 | try self.ensureUnusedCapacityGlobal(name); | 2096 | try self.ensureUnusedCapacityGlobal(name); |
| 1887 | return self.addGlobalAssumeCapacity(name, global); | 2097 | return self.addGlobalAssumeCapacity(name, global); |
| ... | @@ -1890,9 +2100,10 @@ pub fn addGlobal(self: *Builder, name: String, global: Global) Allocator.Error!G | ... | @@ -1890,9 +2100,10 @@ pub fn addGlobal(self: *Builder, name: String, global: Global) Allocator.Error!G |
| 1890 | pub fn addGlobalAssumeCapacity(self: *Builder, name: String, global: Global) Global.Index { | 2100 | pub fn addGlobalAssumeCapacity(self: *Builder, name: String, global: Global) Global.Index { |
| 1891 | _ = self.ptrTypeAssumeCapacity(global.addr_space); | 2101 | _ = self.ptrTypeAssumeCapacity(global.addr_space); |
| 1892 | var id = name; | 2102 | var id = name; |
| 1893 | if (id == .none) { | 2103 | if (name == .empty) { |
| 1894 | id = self.next_unnamed_global; | 2104 | id = self.next_unnamed_global; |
| 1895 | self.next_unnamed_global = @enumFromInt(@intFromEnum(self.next_unnamed_global) + 1); | 2105 | assert(id != self.next_replaced_global); |
| | 2106 | self.next_unnamed_global = @enumFromInt(@intFromEnum(id) + 1); |
| 1896 | } | 2107 | } |
| 1897 | while (true) { | 2108 | while (true) { |
| 1898 | const global_gop = self.globals.getOrPutAssumeCapacity(id); | 2109 | const global_gop = self.globals.getOrPutAssumeCapacity(id); |
| ... | @@ -2136,7 +2347,7 @@ pub fn binConst( | ... | @@ -2136,7 +2347,7 @@ pub fn binConst( |
| 2136 | return self.binConstAssumeCapacity(tag, lhs, rhs); | 2347 | return self.binConstAssumeCapacity(tag, lhs, rhs); |
| 2137 | } | 2348 | } |
| 2138 | | 2349 | |
| 2139 | pub fn dump(self: *Builder, writer: anytype) @TypeOf(writer).Error!void { | 2350 | pub fn dump(self: *Builder, writer: anytype) (@TypeOf(writer).Error || Allocator.Error)!void { |
| 2140 | if (self.source_filename != .none) try writer.print( | 2351 | if (self.source_filename != .none) try writer.print( |
| 2141 | \\; ModuleID = '{s}' | 2352 | \\; ModuleID = '{s}' |
| 2142 | \\source_filename = {"} | 2353 | \\source_filename = {"} |
| ... | @@ -2157,7 +2368,8 @@ pub fn dump(self: *Builder, writer: anytype) @TypeOf(writer).Error!void { | ... | @@ -2157,7 +2368,8 @@ pub fn dump(self: *Builder, writer: anytype) @TypeOf(writer).Error!void { |
| 2157 | , .{ id.fmt(self), ty.fmt(self) }); | 2368 | , .{ id.fmt(self), ty.fmt(self) }); |
| 2158 | try writer.writeByte('\n'); | 2369 | try writer.writeByte('\n'); |
| 2159 | for (self.variables.items) |variable| { | 2370 | for (self.variables.items) |variable| { |
| 2160 | const global = self.globals.values()[@intFromEnum(variable.global)]; | 2371 | if (variable.global.getReplacement(self) != .none) continue; |
| | 2372 | const global = variable.global.ptrConst(self); |
| 2161 | try writer.print( | 2373 | try writer.print( |
| 2162 | \\{} ={}{}{}{}{}{}{}{} {s} {%}{ }{,} | 2374 | \\{} ={}{}{}{}{}{}{}{} {s} {%}{ }{,} |
| 2163 | \\ | 2375 | \\ |
| ... | @@ -2179,7 +2391,8 @@ pub fn dump(self: *Builder, writer: anytype) @TypeOf(writer).Error!void { | ... | @@ -2179,7 +2391,8 @@ pub fn dump(self: *Builder, writer: anytype) @TypeOf(writer).Error!void { |
| 2179 | } | 2391 | } |
| 2180 | try writer.writeByte('\n'); | 2392 | try writer.writeByte('\n'); |
| 2181 | for (self.functions.items) |function| { | 2393 | for (self.functions.items) |function| { |
| 2182 | const global = self.globals.values()[@intFromEnum(function.global)]; | 2394 | if (function.global.getReplacement(self) != .none) continue; |
| | 2395 | const global = function.global.ptrConst(self); |
| 2183 | const item = self.type_items.items[@intFromEnum(global.type)]; | 2396 | const item = self.type_items.items[@intFromEnum(global.type)]; |
| 2184 | const extra = self.typeExtraDataTrail(Type.Function, item.data); | 2397 | const extra = self.typeExtraDataTrail(Type.Function, item.data); |
| 2185 | const params: []const Type = | 2398 | const params: []const Type = |
| ... | @@ -2207,14 +2420,51 @@ pub fn dump(self: *Builder, writer: anytype) @TypeOf(writer).Error!void { | ... | @@ -2207,14 +2420,51 @@ pub fn dump(self: *Builder, writer: anytype) @TypeOf(writer).Error!void { |
| 2207 | }, | 2420 | }, |
| 2208 | else => unreachable, | 2421 | else => unreachable, |
| 2209 | } | 2422 | } |
| 2210 | try writer.print(") {}{}", .{ global.unnamed_addr, global.alignment }); | 2423 | try writer.print("){}{}", .{ global.unnamed_addr, global.alignment }); |
| 2211 | if (function.body) |_| try writer.print( | 2424 | if (function.body) |_| { |
| 2212 | \\{{ | 2425 | try writer.writeAll(" {\n ret "); |
| 2213 | \\ ret {%} | 2426 | void: { |
| 2214 | \\}} | 2427 | try writer.print("{%}", .{switch (extra.data.ret) { |
| 2215 | \\ | 2428 | .void => |tag| { |
| 2216 | , .{extra.data.ret.fmt(self)}); | 2429 | try writer.writeAll(@tagName(tag)); |
| 2217 | try writer.writeByte('\n'); | 2430 | break :void; |
| | 2431 | }, |
| | 2432 | inline .half, |
| | 2433 | .bfloat, |
| | 2434 | .float, |
| | 2435 | .double, |
| | 2436 | .fp128, |
| | 2437 | .x86_fp80, |
| | 2438 | => |tag| try @field(Builder, @tagName(tag) ++ "Const")(self, 0.0), |
| | 2439 | .ppc_fp128 => try self.ppc_fp128Const(.{ 0.0, 0.0 }), |
| | 2440 | .x86_amx, |
| | 2441 | .x86_mmx, |
| | 2442 | .label, |
| | 2443 | .metadata, |
| | 2444 | => unreachable, |
| | 2445 | .token => Constant.none, |
| | 2446 | else => switch (extra.data.ret.tag(self)) { |
| | 2447 | .simple, |
| | 2448 | .function, |
| | 2449 | .vararg_function, |
| | 2450 | => unreachable, |
| | 2451 | .integer => try self.intConst(extra.data.ret, 0), |
| | 2452 | .pointer => try self.nullConst(extra.data.ret), |
| | 2453 | .target, |
| | 2454 | .vector, |
| | 2455 | .scalable_vector, |
| | 2456 | .small_array, |
| | 2457 | .array, |
| | 2458 | .structure, |
| | 2459 | .packed_structure, |
| | 2460 | .named_structure, |
| | 2461 | => try self.zeroInitConst(extra.data.ret), |
| | 2462 | }, |
| | 2463 | }.fmt(self)}); |
| | 2464 | } |
| | 2465 | try writer.writeAll("\n}"); |
| | 2466 | } |
| | 2467 | try writer.writeAll("\n\n"); |
| 2218 | } | 2468 | } |
| 2219 | } | 2469 | } |
| 2220 | | 2470 | |
| ... | @@ -2497,11 +2747,11 @@ fn opaqueTypeAssumeCapacity(self: *Builder, name: String) Type { | ... | @@ -2497,11 +2747,11 @@ fn opaqueTypeAssumeCapacity(self: *Builder, name: String) Type { |
| 2497 | } | 2747 | } |
| 2498 | }; | 2748 | }; |
| 2499 | var id = name; | 2749 | var id = name; |
| 2500 | if (name == .none) { | 2750 | if (name == .empty) { |
| 2501 | id = self.next_unnamed_type; | 2751 | id = self.next_unnamed_type; |
| 2502 | assert(id != .none); | 2752 | assert(id != .none); |
| 2503 | self.next_unnamed_type = @enumFromInt(@intFromEnum(id) + 1); | 2753 | self.next_unnamed_type = @enumFromInt(@intFromEnum(id) + 1); |
| 2504 | } else assert(name.toIndex() != null); | 2754 | } else assert(!name.isAnon()); |
| 2505 | while (true) { | 2755 | while (true) { |
| 2506 | const type_gop = self.types.getOrPutAssumeCapacity(id); | 2756 | const type_gop = self.types.getOrPutAssumeCapacity(id); |
| 2507 | if (!type_gop.found_existing) { | 2757 | if (!type_gop.found_existing) { |
| ... | @@ -2783,8 +3033,8 @@ fn doubleConstAssumeCapacity(self: *Builder, val: f64) Constant { | ... | @@ -2783,8 +3033,8 @@ fn doubleConstAssumeCapacity(self: *Builder, val: f64) Constant { |
| 2783 | self.constant_items.appendAssumeCapacity(.{ | 3033 | self.constant_items.appendAssumeCapacity(.{ |
| 2784 | .tag = .double, | 3034 | .tag = .double, |
| 2785 | .data = self.addConstantExtraAssumeCapacity(Constant.Double{ | 3035 | .data = self.addConstantExtraAssumeCapacity(Constant.Double{ |
| 2786 | .lo = @intCast(@as(u64, @bitCast(val)) >> 32), | 3036 | .lo = @truncate(@as(u64, @bitCast(val))), |
| 2787 | .hi = @truncate(@as(u64, @bitCast(val))), | 3037 | .hi = @intCast(@as(u64, @bitCast(val)) >> 32), |
| 2788 | }), | 3038 | }), |
| 2789 | }); | 3039 | }); |
| 2790 | if (self.useLibLlvm()) self.llvm.constants.appendAssumeCapacity( | 3040 | if (self.useLibLlvm()) self.llvm.constants.appendAssumeCapacity( |
| ... | @@ -3401,6 +3651,190 @@ fn gepConstAssumeCapacity( | ... | @@ -3401,6 +3651,190 @@ fn gepConstAssumeCapacity( |
| 3401 | return @enumFromInt(gop.index); | 3651 | return @enumFromInt(gop.index); |
| 3402 | } | 3652 | } |
| 3403 | | 3653 | |
| | 3654 | fn icmpConstAssumeCapacity( |
| | 3655 | self: *Builder, |
| | 3656 | cond: IntegerCondition, |
| | 3657 | lhs: Constant, |
| | 3658 | rhs: Constant, |
| | 3659 | ) Constant { |
| | 3660 | const Adapter = struct { |
| | 3661 | builder: *const Builder, |
| | 3662 | pub fn hash(_: @This(), key: Constant.Compare) u32 { |
| | 3663 | return @truncate(std.hash.Wyhash.hash( |
| | 3664 | std.hash.uint32(@intFromEnum(Constant.tag.icmp)), |
| | 3665 | std.mem.asBytes(&key), |
| | 3666 | )); |
| | 3667 | } |
| | 3668 | pub fn eql(ctx: @This(), lhs_key: Constant.Compare, _: void, rhs_index: usize) bool { |
| | 3669 | if (ctx.builder.constant_items.items(.tag)[rhs_index] != .icmp) return false; |
| | 3670 | const rhs_data = ctx.builder.constant_items.items(.data)[rhs_index]; |
| | 3671 | const rhs_extra = ctx.builder.constantExtraData(Constant.Compare, rhs_data); |
| | 3672 | return std.meta.eql(lhs_key, rhs_extra); |
| | 3673 | } |
| | 3674 | }; |
| | 3675 | const data = Constant.Compare{ .cond = @intFromEnum(cond), .lhs = lhs, .rhs = rhs }; |
| | 3676 | const gop = self.constant_map.getOrPutAssumeCapacityAdapted(data, Adapter{ .builder = self }); |
| | 3677 | if (!gop.found_existing) { |
| | 3678 | gop.key_ptr.* = {}; |
| | 3679 | gop.value_ptr.* = {}; |
| | 3680 | self.constant_items.appendAssumeCapacity(.{ |
| | 3681 | .tag = .icmp, |
| | 3682 | .data = self.addConstantExtraAssumeCapacity(data), |
| | 3683 | }); |
| | 3684 | if (self.useLibLlvm()) self.llvm.constants.appendAssumeCapacity( |
| | 3685 | llvm.constICmp(@enumFromInt(@intFromEnum(cond)), lhs.toLlvm(self), rhs.toLlvm(self)), |
| | 3686 | ); |
| | 3687 | } |
| | 3688 | return @enumFromInt(gop.index); |
| | 3689 | } |
| | 3690 | |
| | 3691 | fn fcmpConstAssumeCapacity( |
| | 3692 | self: *Builder, |
| | 3693 | cond: FloatCondition, |
| | 3694 | lhs: Constant, |
| | 3695 | rhs: Constant, |
| | 3696 | ) Constant { |
| | 3697 | const Adapter = struct { |
| | 3698 | builder: *const Builder, |
| | 3699 | pub fn hash(_: @This(), key: Constant.Compare) u32 { |
| | 3700 | return @truncate(std.hash.Wyhash.hash( |
| | 3701 | std.hash.uint32(@intFromEnum(Constant.tag.fcmp)), |
| | 3702 | std.mem.asBytes(&key), |
| | 3703 | )); |
| | 3704 | } |
| | 3705 | pub fn eql(ctx: @This(), lhs_key: Constant.Compare, _: void, rhs_index: usize) bool { |
| | 3706 | if (ctx.builder.constant_items.items(.tag)[rhs_index] != .fcmp) return false; |
| | 3707 | const rhs_data = ctx.builder.constant_items.items(.data)[rhs_index]; |
| | 3708 | const rhs_extra = ctx.builder.constantExtraData(Constant.Compare, rhs_data); |
| | 3709 | return std.meta.eql(lhs_key, rhs_extra); |
| | 3710 | } |
| | 3711 | }; |
| | 3712 | const data = Constant.Compare{ .cond = @intFromEnum(cond), .lhs = lhs, .rhs = rhs }; |
| | 3713 | const gop = self.constant_map.getOrPutAssumeCapacityAdapted(data, Adapter{ .builder = self }); |
| | 3714 | if (!gop.found_existing) { |
| | 3715 | gop.key_ptr.* = {}; |
| | 3716 | gop.value_ptr.* = {}; |
| | 3717 | self.constant_items.appendAssumeCapacity(.{ |
| | 3718 | .tag = .fcmp, |
| | 3719 | .data = self.addConstantExtraAssumeCapacity(data), |
| | 3720 | }); |
| | 3721 | if (self.useLibLlvm()) self.llvm.constants.appendAssumeCapacity( |
| | 3722 | llvm.constFCmp(@enumFromInt(@intFromEnum(cond)), lhs.toLlvm(self), rhs.toLlvm(self)), |
| | 3723 | ); |
| | 3724 | } |
| | 3725 | return @enumFromInt(gop.index); |
| | 3726 | } |
| | 3727 | |
| | 3728 | fn extractElementConstAssumeCapacity( |
| | 3729 | self: *Builder, |
| | 3730 | arg: Constant, |
| | 3731 | index: Constant, |
| | 3732 | ) Constant { |
| | 3733 | const Adapter = struct { |
| | 3734 | builder: *const Builder, |
| | 3735 | pub fn hash(_: @This(), key: Constant.ExtractElement) u32 { |
| | 3736 | return @truncate(std.hash.Wyhash.hash( |
| | 3737 | comptime std.hash.uint32(@intFromEnum(Constant.Tag.extractelement)), |
| | 3738 | std.mem.asBytes(&key), |
| | 3739 | )); |
| | 3740 | } |
| | 3741 | pub fn eql(ctx: @This(), lhs_key: Constant.ExtractElement, _: void, rhs_index: usize) bool { |
| | 3742 | if (ctx.builder.constant_items.items(.tag)[rhs_index] != .extractelement) return false; |
| | 3743 | const rhs_data = ctx.builder.constant_items.items(.data)[rhs_index]; |
| | 3744 | const rhs_extra = ctx.builder.constantExtraData(Constant.ExtractElement, rhs_data); |
| | 3745 | return std.meta.eql(lhs_key, rhs_extra); |
| | 3746 | } |
| | 3747 | }; |
| | 3748 | const data = Constant.ExtractElement{ .arg = arg, .index = index }; |
| | 3749 | const gop = self.constant_map.getOrPutAssumeCapacityAdapted(data, Adapter{ .builder = self }); |
| | 3750 | if (!gop.found_existing) { |
| | 3751 | gop.key_ptr.* = {}; |
| | 3752 | gop.value_ptr.* = {}; |
| | 3753 | self.constant_items.appendAssumeCapacity(.{ |
| | 3754 | .tag = .extractelement, |
| | 3755 | .data = self.addConstantExtraAssumeCapacity(data), |
| | 3756 | }); |
| | 3757 | if (self.useLibLlvm()) self.llvm.constants.appendAssumeCapacity( |
| | 3758 | arg.toLlvm(self).constExtractElement(index.toLlvm(self)), |
| | 3759 | ); |
| | 3760 | } |
| | 3761 | return @enumFromInt(gop.index); |
| | 3762 | } |
| | 3763 | |
| | 3764 | fn insertElementConstAssumeCapacity( |
| | 3765 | self: *Builder, |
| | 3766 | arg: Constant, |
| | 3767 | elem: Constant, |
| | 3768 | index: Constant, |
| | 3769 | ) Constant { |
| | 3770 | const Adapter = struct { |
| | 3771 | builder: *const Builder, |
| | 3772 | pub fn hash(_: @This(), key: Constant.InsertElement) u32 { |
| | 3773 | return @truncate(std.hash.Wyhash.hash( |
| | 3774 | comptime std.hash.uint32(@intFromEnum(Constant.Tag.insertelement)), |
| | 3775 | std.mem.asBytes(&key), |
| | 3776 | )); |
| | 3777 | } |
| | 3778 | pub fn eql(ctx: @This(), lhs_key: Constant.InsertElement, _: void, rhs_index: usize) bool { |
| | 3779 | if (ctx.builder.constant_items.items(.tag)[rhs_index] != .insertelement) return false; |
| | 3780 | const rhs_data = ctx.builder.constant_items.items(.data)[rhs_index]; |
| | 3781 | const rhs_extra = ctx.builder.constantExtraData(Constant.InsertElement, rhs_data); |
| | 3782 | return std.meta.eql(lhs_key, rhs_extra); |
| | 3783 | } |
| | 3784 | }; |
| | 3785 | const data = Constant.InsertElement{ .arg = arg, .elem = elem, .index = index }; |
| | 3786 | const gop = self.constant_map.getOrPutAssumeCapacityAdapted(data, Adapter{ .builder = self }); |
| | 3787 | if (!gop.found_existing) { |
| | 3788 | gop.key_ptr.* = {}; |
| | 3789 | gop.value_ptr.* = {}; |
| | 3790 | self.constant_items.appendAssumeCapacity(.{ |
| | 3791 | .tag = .insertelement, |
| | 3792 | .data = self.addConstantExtraAssumeCapacity(data), |
| | 3793 | }); |
| | 3794 | if (self.useLibLlvm()) self.llvm.constants.appendAssumeCapacity( |
| | 3795 | arg.toLlvm(self).constInsertElement(elem.toLlvm(self), index.toLlvm(self)), |
| | 3796 | ); |
| | 3797 | } |
| | 3798 | return @enumFromInt(gop.index); |
| | 3799 | } |
| | 3800 | |
| | 3801 | fn shuffleVectorConstAssumeCapacity( |
| | 3802 | self: *Builder, |
| | 3803 | lhs: Constant, |
| | 3804 | rhs: Constant, |
| | 3805 | mask: Constant, |
| | 3806 | ) Constant { |
| | 3807 | const Adapter = struct { |
| | 3808 | builder: *const Builder, |
| | 3809 | pub fn hash(_: @This(), key: Constant.ShuffleVector) u32 { |
| | 3810 | return @truncate(std.hash.Wyhash.hash( |
| | 3811 | comptime std.hash.uint32(@intFromEnum(Constant.Tag.shufflevector)), |
| | 3812 | std.mem.asBytes(&key), |
| | 3813 | )); |
| | 3814 | } |
| | 3815 | pub fn eql(ctx: @This(), lhs_key: Constant.ShuffleVector, _: void, rhs_index: usize) bool { |
| | 3816 | if (ctx.builder.constant_items.items(.tag)[rhs_index] != .shufflevector) return false; |
| | 3817 | const rhs_data = ctx.builder.constant_items.items(.data)[rhs_index]; |
| | 3818 | const rhs_extra = ctx.builder.constantExtraData(Constant.ShuffleVector, rhs_data); |
| | 3819 | return std.meta.eql(lhs_key, rhs_extra); |
| | 3820 | } |
| | 3821 | }; |
| | 3822 | const data = Constant.ShuffleVector{ .lhs = lhs, .rhs = rhs, .mask = mask }; |
| | 3823 | const gop = self.constant_map.getOrPutAssumeCapacityAdapted(data, Adapter{ .builder = self }); |
| | 3824 | if (!gop.found_existing) { |
| | 3825 | gop.key_ptr.* = {}; |
| | 3826 | gop.value_ptr.* = {}; |
| | 3827 | self.constant_items.appendAssumeCapacity(.{ |
| | 3828 | .tag = .shufflevector, |
| | 3829 | .data = self.addConstantExtraAssumeCapacity(data), |
| | 3830 | }); |
| | 3831 | if (self.useLibLlvm()) self.llvm.constants.appendAssumeCapacity( |
| | 3832 | lhs.toLlvm(self).constShuffleVector(rhs.toLlvm(self), mask.toLlvm(self)), |
| | 3833 | ); |
| | 3834 | } |
| | 3835 | return @enumFromInt(gop.index); |
| | 3836 | } |
| | 3837 | |
| 3404 | fn binConstAssumeCapacity( | 3838 | fn binConstAssumeCapacity( |
| 3405 | self: *Builder, | 3839 | self: *Builder, |
| 3406 | tag: Constant.Tag, | 3840 | tag: Constant.Tag, |
| ... | @@ -3408,7 +3842,22 @@ fn binConstAssumeCapacity( | ... | @@ -3408,7 +3842,22 @@ fn binConstAssumeCapacity( |
| 3408 | rhs: Constant, | 3842 | rhs: Constant, |
| 3409 | ) Constant { | 3843 | ) Constant { |
| 3410 | switch (tag) { | 3844 | switch (tag) { |
| 3411 | .add, .sub, .mul, .shl, .lshr, .ashr, .@"and", .@"or", .xor => {}, | 3845 | .add, |
| | 3846 | .@"add nsw", |
| | 3847 | .@"add nuw", |
| | 3848 | .sub, |
| | 3849 | .@"sub nsw", |
| | 3850 | .@"sub nuw", |
| | 3851 | .mul, |
| | 3852 | .@"mul nsw", |
| | 3853 | .@"mul nuw", |
| | 3854 | .shl, |
| | 3855 | .lshr, |
| | 3856 | .ashr, |
| | 3857 | .@"and", |
| | 3858 | .@"or", |
| | 3859 | .xor, |
| | 3860 | => {}, |
| 3412 | else => unreachable, | 3861 | else => unreachable, |
| 3413 | } | 3862 | } |
| 3414 | const Key = struct { tag: Constant.Tag, bin: Constant.Binary }; | 3863 | const Key = struct { tag: Constant.Tag, bin: Constant.Binary }; |