| ... | ... | @@ -29,6 +29,7 @@ type_extra: std.ArrayListUnmanaged(u32) = .{}, |
| 29 | 29 | |
| 30 | 30 | globals: std.AutoArrayHashMapUnmanaged(String, Global) = .{}, |
| 31 | 31 | next_unnamed_global: String = @enumFromInt(0), |
| 32 | next_replaced_global: String = .none, |
| 32 | 33 | next_unique_global_id: std.AutoHashMapUnmanaged(String, u32) = .{}, |
| 33 | 34 | aliases: std.ArrayListUnmanaged(Alias) = .{}, |
| 34 | 35 | variables: std.ArrayListUnmanaged(Variable) = .{}, |
| ... | ... | @@ -55,6 +56,11 @@ pub const String = enum(u32) { |
| 55 | 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 | 64 | pub fn toSlice(self: String, b: *const Builder) ?[:0]const u8 { |
| 59 | 65 | const index = self.toIndex() orelse return null; |
| 60 | 66 | const start = b.string_indices.items[index]; |
| ... | ... | @@ -743,18 +749,36 @@ pub const Global = struct { |
| 743 | 749 | alias: Alias.Index, |
| 744 | 750 | variable: Variable.Index, |
| 745 | 751 | function: Function.Index, |
| 752 | replaced: Global.Index, |
| 746 | 753 | }, |
| 747 | 754 | |
| 748 | 755 | pub const Index = enum(u32) { |
| 749 | 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 | 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 | 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 | 784 | pub fn toConst(self: Index) Constant { |
| ... | ... | @@ -763,7 +787,7 @@ pub const Global = struct { |
| 763 | 787 | |
| 764 | 788 | pub fn toLlvm(self: Index, builder: *const Builder) *llvm.Value { |
| 765 | 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 | 793 | const FormatData = struct { |
| ... | ... | @@ -777,44 +801,80 @@ pub const Global = struct { |
| 777 | 801 | writer: anytype, |
| 778 | 802 | ) @TypeOf(writer).Error!void { |
| 779 | 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 | 807 | pub fn fmt(self: Index, builder: *const Builder) std.fmt.Formatter(format) { |
| 784 | 808 | return .{ .data = .{ .global = self, .builder = builder } }; |
| 785 | 809 | } |
| 786 | 810 | |
| 787 | | pub fn rename(self: Index, builder: *Builder, name: String) Allocator.Error!void { |
| 788 | | try builder.ensureUnusedCapacityGlobal(name); |
| 789 | | self.renameAssumeCapacity(builder, name); |
| 811 | pub fn rename(self: Index, new_name: String, builder: *Builder) Allocator.Error!void { |
| 812 | try builder.ensureUnusedCapacityGlobal(new_name); |
| 813 | self.renameAssumeCapacity(new_name, builder); |
| 790 | 814 | } |
| 791 | 815 | |
| 792 | | pub fn renameAssumeCapacity(self: Index, builder: *Builder, name: String) void { |
| 793 | | const index = @intFromEnum(self); |
| 794 | | if (builder.globals.keys()[index] == name) return; |
| 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); |
| 816 | pub fn takeName(self: Index, other: Index, builder: *Builder) Allocator.Error!void { |
| 817 | try builder.ensureUnusedCapacityGlobal(.empty); |
| 818 | self.takeNameAssumeCapacity(other, 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 | 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 { |
| 808 | | const other_name = builder.globals.keys()[@intFromEnum(other)]; |
| 809 | | other.renameAssumeCapacity(builder, .none); |
| 810 | | self.renameAssumeCapacity(builder, other_name); |
| 842 | fn takeNameAssumeCapacity(self: Index, other: Index, builder: *Builder) void { |
| 843 | const other_name = other.name(builder); |
| 844 | other.renameAssumeCapacity(.empty, builder); |
| 845 | self.renameAssumeCapacity(other_name, builder); |
| 811 | 846 | } |
| 812 | 847 | |
| 813 | 848 | fn updateName(self: Index, builder: *const Builder) void { |
| 814 | 849 | if (!builder.useLibLlvm()) return; |
| 815 | | const index = @intFromEnum(self); |
| 816 | | const slice = builder.globals.keys()[index].toSlice(builder) orelse ""; |
| 817 | | builder.llvm.globals.items[index].setValueName2(slice.ptr, slice.len); |
| 850 | const index = @intFromEnum(self.unwrap(builder)); |
| 851 | const name_slice = self.name(builder).toSlice(builder) orelse ""; |
| 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 | 1074 | insertelement, |
| 1015 | 1075 | shufflevector, |
| 1016 | 1076 | add, |
| 1077 | @"add nsw", |
| 1078 | @"add nuw", |
| 1017 | 1079 | sub, |
| 1080 | @"sub nsw", |
| 1081 | @"sub nuw", |
| 1018 | 1082 | mul, |
| 1083 | @"mul nsw", |
| 1084 | @"mul nuw", |
| 1019 | 1085 | shl, |
| 1020 | 1086 | lshr, |
| 1021 | 1087 | ashr, |
| ... | ... | @@ -1084,24 +1150,24 @@ pub const Constant = enum(u32) { |
| 1084 | 1150 | pub const Kind = enum { normal, inbounds }; |
| 1085 | 1151 | }; |
| 1086 | 1152 | |
| 1087 | | pub const Compare = struct { |
| 1153 | pub const Compare = extern struct { |
| 1088 | 1154 | cond: u32, |
| 1089 | 1155 | lhs: Constant, |
| 1090 | 1156 | rhs: Constant, |
| 1091 | 1157 | }; |
| 1092 | 1158 | |
| 1093 | | pub const ExtractElement = struct { |
| 1159 | pub const ExtractElement = extern struct { |
| 1094 | 1160 | arg: Constant, |
| 1095 | 1161 | index: Constant, |
| 1096 | 1162 | }; |
| 1097 | 1163 | |
| 1098 | | pub const InsertElement = struct { |
| 1164 | pub const InsertElement = extern struct { |
| 1099 | 1165 | arg: Constant, |
| 1100 | 1166 | elem: Constant, |
| 1101 | 1167 | index: Constant, |
| 1102 | 1168 | }; |
| 1103 | 1169 | |
| 1104 | | pub const ShuffleVector = struct { |
| 1170 | pub const ShuffleVector = extern struct { |
| 1105 | 1171 | lhs: Constant, |
| 1106 | 1172 | rhs: Constant, |
| 1107 | 1173 | mask: Constant, |
| ... | ... | @@ -1243,8 +1309,14 @@ pub const Constant = enum(u32) { |
| 1243 | 1309 | }; |
| 1244 | 1310 | }, |
| 1245 | 1311 | .add, |
| 1312 | .@"add nsw", |
| 1313 | .@"add nuw", |
| 1246 | 1314 | .sub, |
| 1315 | .@"sub nsw", |
| 1316 | .@"sub nuw", |
| 1247 | 1317 | .mul, |
| 1318 | .@"mul nsw", |
| 1319 | .@"mul nuw", |
| 1248 | 1320 | .shl, |
| 1249 | 1321 | .lshr, |
| 1250 | 1322 | .ashr, |
| ... | ... | @@ -1326,14 +1398,14 @@ pub const Constant = enum(u32) { |
| 1326 | 1398 | switch (item.tag) { |
| 1327 | 1399 | .positive_integer, |
| 1328 | 1400 | .negative_integer, |
| 1329 | | => { |
| 1401 | => |tag| { |
| 1330 | 1402 | const extra: *align(@alignOf(std.math.big.Limb)) Integer = |
| 1331 | 1403 | @ptrCast(data.builder.constant_limbs.items[item.data..][0..Integer.limbs]); |
| 1332 | 1404 | const limbs = data.builder.constant_limbs |
| 1333 | 1405 | .items[item.data + Integer.limbs ..][0..extra.limbs_len]; |
| 1334 | 1406 | const bigint = std.math.big.int.Const{ |
| 1335 | 1407 | .limbs = limbs, |
| 1336 | | .positive = item.tag == .positive_integer, |
| 1408 | .positive = tag == .positive_integer, |
| 1337 | 1409 | }; |
| 1338 | 1410 | const ExpectedContents = extern struct { |
| 1339 | 1411 | string: [(64 * 8 / std.math.log2(10)) + 2]u8, |
| ... | ... | @@ -1352,23 +1424,63 @@ pub const Constant = enum(u32) { |
| 1352 | 1424 | defer allocator.free(str); |
| 1353 | 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 | 1467 | .null, |
| 1356 | 1468 | .none, |
| 1357 | 1469 | .zeroinitializer, |
| 1358 | 1470 | .undef, |
| 1359 | 1471 | .poison, |
| 1360 | | => try writer.writeAll(@tagName(item.tag)), |
| 1472 | => |tag| try writer.writeAll(@tagName(tag)), |
| 1361 | 1473 | .structure, |
| 1362 | 1474 | .packed_structure, |
| 1363 | 1475 | .array, |
| 1364 | 1476 | .vector, |
| 1365 | | => { |
| 1477 | => |tag| { |
| 1366 | 1478 | const extra = data.builder.constantExtraDataTrail(Aggregate, item.data); |
| 1367 | 1479 | const len = extra.data.type.aggregateLen(data.builder); |
| 1368 | 1480 | const vals: []const Constant = |
| 1369 | 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 | 1484 | .structure => "{ ", |
| 1373 | 1485 | .packed_structure => "<{ ", |
| 1374 | 1486 | .array => "[", |
| ... | ... | @@ -1379,7 +1491,7 @@ pub const Constant = enum(u32) { |
| 1379 | 1491 | if (index > 0) try writer.writeAll(", "); |
| 1380 | 1492 | try writer.print("{%}", .{val.fmt(data.builder)}); |
| 1381 | 1493 | } |
| 1382 | | try writer.writeAll(switch (item.tag) { |
| 1494 | try writer.writeAll(switch (tag) { |
| 1383 | 1495 | .structure => " }", |
| 1384 | 1496 | .packed_structure => " }>", |
| 1385 | 1497 | .array => "]", |
| ... | ... | @@ -1387,33 +1499,130 @@ pub const Constant = enum(u32) { |
| 1387 | 1499 | else => unreachable, |
| 1388 | 1500 | }); |
| 1389 | 1501 | }, |
| 1390 | | .string => try writer.print( |
| 1391 | | \\c{"} |
| 1392 | | , .{@as(String, @enumFromInt(item.data)).fmt(data.builder)}), |
| 1393 | | .string_null => try writer.print( |
| 1394 | | \\c{"@} |
| 1395 | | , .{@as(String, @enumFromInt(item.data)).fmt(data.builder)}), |
| 1396 | | .blockaddress => { |
| 1502 | inline .string, |
| 1503 | .string_null, |
| 1504 | => |tag| try writer.print("c{\"" ++ switch (tag) { |
| 1505 | .string => "", |
| 1506 | .string_null => "@", |
| 1507 | else => unreachable, |
| 1508 | } ++ "}", .{@as(String, @enumFromInt(item.data)).fmt(data.builder)}), |
| 1509 | .blockaddress => |tag| { |
| 1397 | 1510 | const extra = data.builder.constantExtraData(BlockAddress, item.data); |
| 1398 | 1511 | const function = extra.function.ptrConst(data.builder); |
| 1399 | 1512 | try writer.print("{s}({}, %{d})", .{ |
| 1400 | | @tagName(item.tag), |
| 1513 | @tagName(tag), |
| 1401 | 1514 | function.global.fmt(data.builder), |
| 1402 | 1515 | @intFromEnum(extra.block), // TODO |
| 1403 | 1516 | }); |
| 1404 | 1517 | }, |
| 1405 | 1518 | .dso_local_equivalent, |
| 1406 | 1519 | .no_cfi, |
| 1407 | | => { |
| 1520 | => |tag| { |
| 1408 | 1521 | const extra = data.builder.constantExtraData(FunctionReference, item.data); |
| 1409 | 1522 | try writer.print("{s} {}", .{ |
| 1410 | | @tagName(item.tag), |
| 1523 | @tagName(tag), |
| 1411 | 1524 | extra.function.ptrConst(data.builder).global.fmt(data.builder), |
| 1412 | 1525 | }); |
| 1413 | 1526 | }, |
| 1414 | | else => try writer.print("<{s}:0x{X}>", .{ |
| 1415 | | @tagName(item.tag), @intFromEnum(data.constant), |
| 1416 | | }), |
| 1527 | .trunc, |
| 1528 | .zext, |
| 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 | 1628 | .global => |global| try writer.print("{}", .{global.fmt(data.builder)}), |
| ... | ... | @@ -1882,6 +2091,7 @@ pub fn namedTypeSetBody( |
| 1882 | 2091 | } |
| 1883 | 2092 | |
| 1884 | 2093 | pub fn addGlobal(self: *Builder, name: String, global: Global) Allocator.Error!Global.Index { |
| 2094 | assert(!name.isAnon()); |
| 1885 | 2095 | try self.ensureUnusedTypeCapacity(1, null, 0); |
| 1886 | 2096 | try self.ensureUnusedCapacityGlobal(name); |
| 1887 | 2097 | return self.addGlobalAssumeCapacity(name, global); |
| ... | ... | @@ -1890,9 +2100,10 @@ pub fn addGlobal(self: *Builder, name: String, global: Global) Allocator.Error!G |
| 1890 | 2100 | pub fn addGlobalAssumeCapacity(self: *Builder, name: String, global: Global) Global.Index { |
| 1891 | 2101 | _ = self.ptrTypeAssumeCapacity(global.addr_space); |
| 1892 | 2102 | var id = name; |
| 1893 | | if (id == .none) { |
| 2103 | if (name == .empty) { |
| 1894 | 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 | 2108 | while (true) { |
| 1898 | 2109 | const global_gop = self.globals.getOrPutAssumeCapacity(id); |
| ... | ... | @@ -2136,7 +2347,7 @@ pub fn binConst( |
| 2136 | 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 | 2351 | if (self.source_filename != .none) try writer.print( |
| 2141 | 2352 | \\; ModuleID = '{s}' |
| 2142 | 2353 | \\source_filename = {"} |
| ... | ... | @@ -2157,7 +2368,8 @@ pub fn dump(self: *Builder, writer: anytype) @TypeOf(writer).Error!void { |
| 2157 | 2368 | , .{ id.fmt(self), ty.fmt(self) }); |
| 2158 | 2369 | try writer.writeByte('\n'); |
| 2159 | 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 | 2373 | try writer.print( |
| 2162 | 2374 | \\{} ={}{}{}{}{}{}{}{} {s} {%}{ }{,} |
| 2163 | 2375 | \\ |
| ... | ... | @@ -2179,7 +2391,8 @@ pub fn dump(self: *Builder, writer: anytype) @TypeOf(writer).Error!void { |
| 2179 | 2391 | } |
| 2180 | 2392 | try writer.writeByte('\n'); |
| 2181 | 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 | 2396 | const item = self.type_items.items[@intFromEnum(global.type)]; |
| 2184 | 2397 | const extra = self.typeExtraDataTrail(Type.Function, item.data); |
| 2185 | 2398 | const params: []const Type = |
| ... | ... | @@ -2207,14 +2420,51 @@ pub fn dump(self: *Builder, writer: anytype) @TypeOf(writer).Error!void { |
| 2207 | 2420 | }, |
| 2208 | 2421 | else => unreachable, |
| 2209 | 2422 | } |
| 2210 | | try writer.print(") {}{}", .{ global.unnamed_addr, global.alignment }); |
| 2211 | | if (function.body) |_| try writer.print( |
| 2212 | | \\{{ |
| 2213 | | \\ ret {%} |
| 2214 | | \\}} |
| 2215 | | \\ |
| 2216 | | , .{extra.data.ret.fmt(self)}); |
| 2217 | | try writer.writeByte('\n'); |
| 2423 | try writer.print("){}{}", .{ global.unnamed_addr, global.alignment }); |
| 2424 | if (function.body) |_| { |
| 2425 | try writer.writeAll(" {\n ret "); |
| 2426 | void: { |
| 2427 | try writer.print("{%}", .{switch (extra.data.ret) { |
| 2428 | .void => |tag| { |
| 2429 | try writer.writeAll(@tagName(tag)); |
| 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 | 2747 | } |
| 2498 | 2748 | }; |
| 2499 | 2749 | var id = name; |
| 2500 | | if (name == .none) { |
| 2750 | if (name == .empty) { |
| 2501 | 2751 | id = self.next_unnamed_type; |
| 2502 | 2752 | assert(id != .none); |
| 2503 | 2753 | self.next_unnamed_type = @enumFromInt(@intFromEnum(id) + 1); |
| 2504 | | } else assert(name.toIndex() != null); |
| 2754 | } else assert(!name.isAnon()); |
| 2505 | 2755 | while (true) { |
| 2506 | 2756 | const type_gop = self.types.getOrPutAssumeCapacity(id); |
| 2507 | 2757 | if (!type_gop.found_existing) { |
| ... | ... | @@ -2783,8 +3033,8 @@ fn doubleConstAssumeCapacity(self: *Builder, val: f64) Constant { |
| 2783 | 3033 | self.constant_items.appendAssumeCapacity(.{ |
| 2784 | 3034 | .tag = .double, |
| 2785 | 3035 | .data = self.addConstantExtraAssumeCapacity(Constant.Double{ |
| 2786 | | .lo = @intCast(@as(u64, @bitCast(val)) >> 32), |
| 2787 | | .hi = @truncate(@as(u64, @bitCast(val))), |
| 3036 | .lo = @truncate(@as(u64, @bitCast(val))), |
| 3037 | .hi = @intCast(@as(u64, @bitCast(val)) >> 32), |
| 2788 | 3038 | }), |
| 2789 | 3039 | }); |
| 2790 | 3040 | if (self.useLibLlvm()) self.llvm.constants.appendAssumeCapacity( |
| ... | ... | @@ -3401,6 +3651,190 @@ fn gepConstAssumeCapacity( |
| 3401 | 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 | 3838 | fn binConstAssumeCapacity( |
| 3405 | 3839 | self: *Builder, |
| 3406 | 3840 | tag: Constant.Tag, |
| ... | ... | @@ -3408,7 +3842,22 @@ fn binConstAssumeCapacity( |
| 3408 | 3842 | rhs: Constant, |
| 3409 | 3843 | ) Constant { |
| 3410 | 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 | 3861 | else => unreachable, |
| 3413 | 3862 | } |
| 3414 | 3863 | const Key = struct { tag: Constant.Tag, bin: Constant.Binary }; |