| ... | @@ -512,10 +512,172 @@ pub const Instruction = union(enum) { | ... | @@ -512,10 +512,172 @@ pub const Instruction = union(enum) { |
| 512 | lookaside: bool = false, | 512 | lookaside: bool = false, |
| 513 | }; | 513 | }; |
| 514 | | 514 | |
| 515 | // TODO: Need to define an enum for `cond` values | 515 | // In SPARCv9, FP and integer comparison operations |
| 516 | // This is kinda challenging since the cond values have different meanings | 516 | // are encoded differently. |
| 517 | // depending on whether it's operating on integer or FP CCR. | 517 | |
| 518 | pub const Condition = u4; | 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 | pub fn toU32(self: Instruction) u32 { | 682 | pub fn toU32(self: Instruction) u32 { |
| 521 | // TODO: Remove this once packed structs work. | 683 | // TODO: Remove this once packed structs work. |
| ... | @@ -593,7 +755,7 @@ pub const Instruction = union(enum) { | ... | @@ -593,7 +755,7 @@ pub const Instruction = union(enum) { |
| 593 | return Instruction{ | 755 | return Instruction{ |
| 594 | .format_2b = .{ | 756 | .format_2b = .{ |
| 595 | .a = @boolToInt(annul), | 757 | .a = @boolToInt(annul), |
| 596 | .cond = cond, | 758 | .cond = cond.encoded, |
| 597 | .op2 = op2, | 759 | .op2 = op2, |
| 598 | .disp22 = udisp_truncated, | 760 | .disp22 = udisp_truncated, |
| 599 | }, | 761 | }, |
| ... | @@ -614,7 +776,7 @@ pub const Instruction = union(enum) { | ... | @@ -614,7 +776,7 @@ pub const Instruction = union(enum) { |
| 614 | return Instruction{ | 776 | return Instruction{ |
| 615 | .format_2c = .{ | 777 | .format_2c = .{ |
| 616 | .a = @boolToInt(annul), | 778 | .a = @boolToInt(annul), |
| 617 | .cond = cond, | 779 | .cond = cond.encoded, |
| 618 | .op2 = op2, | 780 | .op2 = op2, |
| 619 | .cc1 = ccr_cc1, | 781 | .cc1 = ccr_cc1, |
| 620 | .cc0 = ccr_cc0, | 782 | .cc0 = ccr_cc0, |
| ... | @@ -895,7 +1057,7 @@ pub const Instruction = union(enum) { | ... | @@ -895,7 +1057,7 @@ pub const Instruction = union(enum) { |
| 895 | .rd = rd.enc(), | 1057 | .rd = rd.enc(), |
| 896 | .op3 = op3, | 1058 | .op3 = op3, |
| 897 | .cc2 = ccr_cc2, | 1059 | .cc2 = ccr_cc2, |
| 898 | .cond = cond, | 1060 | .cond = cond.encoded, |
| 899 | .cc1 = ccr_cc1, | 1061 | .cc1 = ccr_cc1, |
| 900 | .cc0 = ccr_cc0, | 1062 | .cc0 = ccr_cc0, |
| 901 | .rs2 = rs2.enc(), | 1063 | .rs2 = rs2.enc(), |
| ... | @@ -912,7 +1074,7 @@ pub const Instruction = union(enum) { | ... | @@ -912,7 +1074,7 @@ pub const Instruction = union(enum) { |
| 912 | .rd = rd.enc(), | 1074 | .rd = rd.enc(), |
| 913 | .op3 = op3, | 1075 | .op3 = op3, |
| 914 | .cc2 = ccr_cc2, | 1076 | .cc2 = ccr_cc2, |
| 915 | .cond = cond, | 1077 | .cond = cond.encoded, |
| 916 | .cc1 = ccr_cc1, | 1078 | .cc1 = ccr_cc1, |
| 917 | .cc0 = ccr_cc0, | 1079 | .cc0 = ccr_cc0, |
| 918 | .simm11 = @bitCast(u11, imm), | 1080 | .simm11 = @bitCast(u11, imm), |
| ... | @@ -960,7 +1122,7 @@ pub const Instruction = union(enum) { | ... | @@ -960,7 +1122,7 @@ pub const Instruction = union(enum) { |
| 960 | .format_4g = .{ | 1122 | .format_4g = .{ |
| 961 | .rd = rd.enc(), | 1123 | .rd = rd.enc(), |
| 962 | .op3 = op3, | 1124 | .op3 = op3, |
| 963 | .cond = cond, | 1125 | .cond = cond.encoded, |
| 964 | .opf_cc = opf_cc, | 1126 | .opf_cc = opf_cc, |
| 965 | .opf_low = opf_low, | 1127 | .opf_low = opf_low, |
| 966 | .rs2 = rs2.enc(), | 1128 | .rs2 = rs2.enc(), |
| ... | @@ -1099,11 +1261,11 @@ pub const Instruction = union(enum) { | ... | @@ -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 | // Tcc instructions abuse the rd field to store the conditionals. | 1265 | // Tcc instructions abuse the rd field to store the conditionals. |
| 1104 | return switch (s2) { | 1266 | return switch (s2) { |
| 1105 | Register => format4a(0b11_1010, ccr, rs1, rs2, @intToEnum(Register, cond)), | 1267 | Register => format4a(0b11_1010, ccr, rs1, rs2, @intToEnum(Register, @enumToInt(cond))), |
| 1106 | u7 => format4e(0b11_1010, ccr, rs1, @intToEnum(Register, cond), rs2), | 1268 | u7 => format4e(0b11_1010, ccr, rs1, @intToEnum(Register, @enumToInt(cond)), rs2), |
| 1107 | else => unreachable, | 1269 | else => unreachable, |
| 1108 | }; | 1270 | }; |
| 1109 | } | 1271 | } |
| ... | @@ -1128,11 +1290,11 @@ test "Serialize formats" { | ... | @@ -1128,11 +1290,11 @@ test "Serialize formats" { |
| 1128 | .expected = 0b00_00000_100_0000000000000000000000, | 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 | .expected = 0b00_1_0011_110_1111111111111111111111, | 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 | .expected = 0b00_0_0000_011_1_0_1_0000000000000000010, | 1298 | .expected = 0b00_0_0000_011_1_0_1_0000000000000000010, |
| 1137 | }, | 1299 | }, |
| 1138 | .{ | 1300 | .{ |
| ... | @@ -1224,11 +1386,11 @@ test "Serialize formats" { | ... | @@ -1224,11 +1386,11 @@ test "Serialize formats" { |
| 1224 | .expected = 0b10_10010_001000_00000_1_1_0_11111111111, | 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 | .expected = 0b10_01001_001000_1_0000_0_1_0_000000_00000, | 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 | .expected = 0b10_10010_001000_1_0000_1_1_0_00000000000, | 1394 | .expected = 0b10_10010_001000_1_0000_1_1_0_00000000000, |
| 1233 | }, | 1395 | }, |
| 1234 | .{ | 1396 | .{ |
| ... | @@ -1240,7 +1402,7 @@ test "Serialize formats" { | ... | @@ -1240,7 +1402,7 @@ test "Serialize formats" { |
| 1240 | .expected = 0b10_10010_001000_00000_0_001_00100_01001, | 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 | .expected = 0b10_10010_001000_0_0000_010_000100_01001, | 1406 | .expected = 0b10_10010_001000_0_0000_010_000100_01001, |
| 1245 | }, | 1407 | }, |
| 1246 | }; | 1408 | }; |