| ... | ... | @@ -512,10 +512,172 @@ pub const Instruction = union(enum) { |
| 512 | 512 | lookaside: bool = false, |
| 513 | 513 | }; |
| 514 | 514 | |
| 515 | | // TODO: Need to define an enum for `cond` values |
| 516 | | // This is kinda challenging since the cond values have different meanings |
| 517 | | // depending on whether it's operating on integer or FP CCR. |
| 518 | | pub const Condition = u4; |
| 515 | // In SPARCv9, FP and integer comparison operations |
| 516 | // are encoded differently. |
| 517 | |
| 518 | pub const FCondition = enum(u4) { |
| 519 | /// Branch Never |
| 520 | nv, |
| 521 | /// Branch on Not Equal |
| 522 | ne, |
| 523 | /// Branch on Less or Greater |
| 524 | lg, |
| 525 | /// Branch on Unordered or Less |
| 526 | ul, |
| 527 | /// Branch on Less |
| 528 | lt, |
| 529 | /// Branch on Unordered or Greater |
| 530 | ug, |
| 531 | /// Branch on Greater |
| 532 | gt, |
| 533 | /// Branch on Unordered |
| 534 | un, |
| 535 | /// Branch Always |
| 536 | al, |
| 537 | /// Branch on Equal |
| 538 | eq, |
| 539 | /// Branch on Unordered or Equal |
| 540 | ue, |
| 541 | /// Branch on Greater or Equal |
| 542 | ge, |
| 543 | /// Branch on Unordered or Greater or Equal |
| 544 | uge, |
| 545 | /// Branch on Less or Equal |
| 546 | le, |
| 547 | /// Branch on Unordered or Less or Equal |
| 548 | ule, |
| 549 | /// Branch on Ordered |
| 550 | ord, |
| 551 | |
| 552 | /// Converts a std.math.CompareOperator into a condition flag, |
| 553 | /// i.e. returns the condition that is true iff the result of the |
| 554 | /// comparison is true. |
| 555 | pub fn fromCompareOperator(op: std.math.CompareOperator) FCondition { |
| 556 | return switch (op) { |
| 557 | .gte => .ge, |
| 558 | .gt => .gt, |
| 559 | .neq => .ne, |
| 560 | .lt => .lt, |
| 561 | .lte => .le, |
| 562 | .eq => .eq, |
| 563 | }; |
| 564 | } |
| 565 | |
| 566 | /// Returns the condition which is true iff the given condition is |
| 567 | /// false (if such a condition exists). |
| 568 | pub fn negate(cond: FCondition) FCondition { |
| 569 | return switch (cond) { |
| 570 | .eq => .ne, |
| 571 | .ne => .eq, |
| 572 | .ge => .ul, |
| 573 | .ul => .ge, |
| 574 | .le => .ug, |
| 575 | .ug => .le, |
| 576 | .lt => .uge, |
| 577 | .uge => .lt, |
| 578 | .gt => .ule, |
| 579 | .ule => .gt, |
| 580 | .ue => .lg, |
| 581 | .lg => .ue, |
| 582 | .ord => .un, |
| 583 | .un => .ord, |
| 584 | .al => unreachable, |
| 585 | .nv => unreachable, |
| 586 | }; |
| 587 | } |
| 588 | }; |
| 589 | |
| 590 | pub const ICondition = enum(u4) { |
| 591 | /// Branch Never |
| 592 | nv, |
| 593 | /// Branch on Equal |
| 594 | eq, |
| 595 | /// Branch on Less or Equal |
| 596 | le, |
| 597 | /// Branch on Less |
| 598 | lt, |
| 599 | /// Branch on Less or Equal Unsigned |
| 600 | leu, |
| 601 | /// Branch on Carry Set (Less than, Unsigned) |
| 602 | cs, |
| 603 | /// Branch on Negative |
| 604 | neg, |
| 605 | /// Branch on Overflow Set |
| 606 | vs, |
| 607 | /// Branch Always |
| 608 | al, |
| 609 | /// Branch on Not Equal |
| 610 | ne, |
| 611 | /// Branch on Greater |
| 612 | gt, |
| 613 | /// Branch on Greater or Equal |
| 614 | ge, |
| 615 | /// Branch on Greater Unsigned |
| 616 | gu, |
| 617 | /// Branch on Carry Clear (Greater Than or Equal, Unsigned) |
| 618 | cc, |
| 619 | /// Branch on Positive |
| 620 | pos, |
| 621 | /// Branch on Overflow Clear |
| 622 | vc, |
| 623 | |
| 624 | /// Converts a std.math.CompareOperator into a condition flag, |
| 625 | /// i.e. returns the condition that is true iff the result of the |
| 626 | /// comparison is true. Assumes signed comparison. |
| 627 | pub fn fromCompareOperatorSigned(op: std.math.CompareOperator) ICondition { |
| 628 | return switch (op) { |
| 629 | .gte => .ge, |
| 630 | .gt => .gt, |
| 631 | .neq => .ne, |
| 632 | .lt => .lt, |
| 633 | .lte => .le, |
| 634 | .eq => .eq, |
| 635 | }; |
| 636 | } |
| 637 | |
| 638 | /// Converts a std.math.CompareOperator into a condition flag, |
| 639 | /// i.e. returns the condition that is true iff the result of the |
| 640 | /// comparison is true. Assumes unsigned comparison. |
| 641 | pub fn fromCompareOperatorUnsigned(op: std.math.CompareOperator) ICondition { |
| 642 | return switch (op) { |
| 643 | .gte => .cc, |
| 644 | .gt => .gu, |
| 645 | .neq => .ne, |
| 646 | .lt => .cs, |
| 647 | .lte => .le, |
| 648 | .eq => .eq, |
| 649 | }; |
| 650 | } |
| 651 | |
| 652 | /// Returns the condition which is true iff the given condition is |
| 653 | /// false (if such a condition exists). |
| 654 | pub fn negate(cond: ICondition) ICondition { |
| 655 | return switch (cond) { |
| 656 | .eq => .ne, |
| 657 | .ne => .eq, |
| 658 | .cs => .cc, |
| 659 | .cc => .cs, |
| 660 | .neg => .pos, |
| 661 | .pos => .neg, |
| 662 | .vs => .vc, |
| 663 | .vc => .vs, |
| 664 | .gu => .leu, |
| 665 | .leu => .gu, |
| 666 | .ge => .lt, |
| 667 | .lt => .ge, |
| 668 | .gt => .le, |
| 669 | .le => .gt, |
| 670 | .al => unreachable, |
| 671 | .nv => unreachable, |
| 672 | }; |
| 673 | } |
| 674 | }; |
| 675 | |
| 676 | pub const Condition = packed union { |
| 677 | fcond: FCondition, |
| 678 | icond: ICondition, |
| 679 | encoded: u4, |
| 680 | }; |
| 519 | 681 | |
| 520 | 682 | pub fn toU32(self: Instruction) u32 { |
| 521 | 683 | // TODO: Remove this once packed structs work. |
| ... | ... | @@ -593,7 +755,7 @@ pub const Instruction = union(enum) { |
| 593 | 755 | return Instruction{ |
| 594 | 756 | .format_2b = .{ |
| 595 | 757 | .a = @boolToInt(annul), |
| 596 | | .cond = cond, |
| 758 | .cond = cond.encoded, |
| 597 | 759 | .op2 = op2, |
| 598 | 760 | .disp22 = udisp_truncated, |
| 599 | 761 | }, |
| ... | ... | @@ -614,7 +776,7 @@ pub const Instruction = union(enum) { |
| 614 | 776 | return Instruction{ |
| 615 | 777 | .format_2c = .{ |
| 616 | 778 | .a = @boolToInt(annul), |
| 617 | | .cond = cond, |
| 779 | .cond = cond.encoded, |
| 618 | 780 | .op2 = op2, |
| 619 | 781 | .cc1 = ccr_cc1, |
| 620 | 782 | .cc0 = ccr_cc0, |
| ... | ... | @@ -895,7 +1057,7 @@ pub const Instruction = union(enum) { |
| 895 | 1057 | .rd = rd.enc(), |
| 896 | 1058 | .op3 = op3, |
| 897 | 1059 | .cc2 = ccr_cc2, |
| 898 | | .cond = cond, |
| 1060 | .cond = cond.encoded, |
| 899 | 1061 | .cc1 = ccr_cc1, |
| 900 | 1062 | .cc0 = ccr_cc0, |
| 901 | 1063 | .rs2 = rs2.enc(), |
| ... | ... | @@ -912,7 +1074,7 @@ pub const Instruction = union(enum) { |
| 912 | 1074 | .rd = rd.enc(), |
| 913 | 1075 | .op3 = op3, |
| 914 | 1076 | .cc2 = ccr_cc2, |
| 915 | | .cond = cond, |
| 1077 | .cond = cond.encoded, |
| 916 | 1078 | .cc1 = ccr_cc1, |
| 917 | 1079 | .cc0 = ccr_cc0, |
| 918 | 1080 | .simm11 = @bitCast(u11, imm), |
| ... | ... | @@ -960,7 +1122,7 @@ pub const Instruction = union(enum) { |
| 960 | 1122 | .format_4g = .{ |
| 961 | 1123 | .rd = rd.enc(), |
| 962 | 1124 | .op3 = op3, |
| 963 | | .cond = cond, |
| 1125 | .cond = cond.encoded, |
| 964 | 1126 | .opf_cc = opf_cc, |
| 965 | 1127 | .opf_low = opf_low, |
| 966 | 1128 | .rs2 = rs2.enc(), |
| ... | ... | @@ -1099,11 +1261,11 @@ pub const Instruction = union(enum) { |
| 1099 | 1261 | }; |
| 1100 | 1262 | } |
| 1101 | 1263 | |
| 1102 | | pub fn trap(comptime s2: type, cond: Condition, ccr: CCR, rs1: Register, rs2: s2) Instruction { |
| 1264 | pub fn trap(comptime s2: type, cond: ICondition, ccr: CCR, rs1: Register, rs2: s2) Instruction { |
| 1103 | 1265 | // Tcc instructions abuse the rd field to store the conditionals. |
| 1104 | 1266 | return switch (s2) { |
| 1105 | | Register => format4a(0b11_1010, ccr, rs1, rs2, @intToEnum(Register, cond)), |
| 1106 | | u7 => format4e(0b11_1010, ccr, rs1, @intToEnum(Register, cond), rs2), |
| 1267 | Register => format4a(0b11_1010, ccr, rs1, rs2, @intToEnum(Register, @enumToInt(cond))), |
| 1268 | u7 => format4e(0b11_1010, ccr, rs1, @intToEnum(Register, @enumToInt(cond)), rs2), |
| 1107 | 1269 | else => unreachable, |
| 1108 | 1270 | }; |
| 1109 | 1271 | } |
| ... | ... | @@ -1128,11 +1290,11 @@ test "Serialize formats" { |
| 1128 | 1290 | .expected = 0b00_00000_100_0000000000000000000000, |
| 1129 | 1291 | }, |
| 1130 | 1292 | .{ |
| 1131 | | .inst = Instruction.format2b(6, 3, true, -4), |
| 1293 | .inst = Instruction.format2b(6, .{ .icond = .lt }, true, -4), |
| 1132 | 1294 | .expected = 0b00_1_0011_110_1111111111111111111111, |
| 1133 | 1295 | }, |
| 1134 | 1296 | .{ |
| 1135 | | .inst = Instruction.format2c(3, 0, false, true, .xcc, 8), |
| 1297 | .inst = Instruction.format2c(3, .{ .icond = .nv }, false, true, .xcc, 8), |
| 1136 | 1298 | .expected = 0b00_0_0000_011_1_0_1_0000000000000000010, |
| 1137 | 1299 | }, |
| 1138 | 1300 | .{ |
| ... | ... | @@ -1224,11 +1386,11 @@ test "Serialize formats" { |
| 1224 | 1386 | .expected = 0b10_10010_001000_00000_1_1_0_11111111111, |
| 1225 | 1387 | }, |
| 1226 | 1388 | .{ |
| 1227 | | .inst = Instruction.format4c(8, 0, .xcc, .g0, .o1), |
| 1389 | .inst = Instruction.format4c(8, .{ .icond = .nv }, .xcc, .g0, .o1), |
| 1228 | 1390 | .expected = 0b10_01001_001000_1_0000_0_1_0_000000_00000, |
| 1229 | 1391 | }, |
| 1230 | 1392 | .{ |
| 1231 | | .inst = Instruction.format4d(8, 0, .xcc, 0, .l2), |
| 1393 | .inst = Instruction.format4d(8, .{ .icond = .nv }, .xcc, 0, .l2), |
| 1232 | 1394 | .expected = 0b10_10010_001000_1_0000_1_1_0_00000000000, |
| 1233 | 1395 | }, |
| 1234 | 1396 | .{ |
| ... | ... | @@ -1240,7 +1402,7 @@ test "Serialize formats" { |
| 1240 | 1402 | .expected = 0b10_10010_001000_00000_0_001_00100_01001, |
| 1241 | 1403 | }, |
| 1242 | 1404 | .{ |
| 1243 | | .inst = Instruction.format4g(8, 4, 2, 0, .o1, .l2), |
| 1405 | .inst = Instruction.format4g(8, 4, 2, .{ .icond = .nv }, .o1, .l2), |
| 1244 | 1406 | .expected = 0b10_10010_001000_0_0000_010_000100_01001, |
| 1245 | 1407 | }, |
| 1246 | 1408 | }; |