authorgravatar for koachan@protonmail.comKoakuma <koachan@protonmail.com> 2022-05-02 19:55:51+07:00
committergravatar for koachan@protonmail.comKoakuma <koachan@protonmail.com> 2022-05-16 22:47:52+07:00
logfd781195de54b58a5f103f86c5f0784454a53439
treea4acac4f390bac9996f2f89cb9058d97dea1a8ed
parent662a61fcc3824deacba510e5b036be6feb941d2b

stage2: sparc64: Split the conditionals between integer and FP ones

On SPARCv9 the integer and FP conditional branch codes doesn't align with each other at all, so the two need to be treated separately.

3 files changed, 187 insertions(+), 25 deletions(-)

src/arch/sparc64/CodeGen.zig+3-3
...@@ -725,7 +725,7 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {...@@ -725,7 +725,7 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
725 .data = .{725 .data = .{
726 .trap = .{726 .trap = .{
727 .is_imm = true,727 .is_imm = true,
728 .cond = 0b1000, // TODO need to look into changing this into an enum728 .cond = .al,
729 .rs2_or_imm = .{ .imm = 0x6d },729 .rs2_or_imm = .{ .imm = 0x6d },
730 },730 },
731 },731 },
...@@ -842,7 +842,7 @@ fn airBreakpoint(self: *Self) !void {...@@ -842,7 +842,7 @@ fn airBreakpoint(self: *Self) !void {
842 .data = .{842 .data = .{
843 .trap = .{843 .trap = .{
844 .is_imm = true,844 .is_imm = true,
845 .cond = 0b1000, // TODO need to look into changing this into an enum845 .cond = .al,
846 .rs2_or_imm = .{ .imm = 0x01 },846 .rs2_or_imm = .{ .imm = 0x01 },
847 },847 },
848 },848 },
...@@ -1648,7 +1648,7 @@ fn parseRegName(name: []const u8) ?Register {...@@ -1648,7 +1648,7 @@ fn parseRegName(name: []const u8) ?Register {
1648fn performReloc(self: *Self, inst: Mir.Inst.Index) !void {1648fn performReloc(self: *Self, inst: Mir.Inst.Index) !void {
1649 const tag = self.mir_instructions.items(.tag)[inst];1649 const tag = self.mir_instructions.items(.tag)[inst];
1650 switch (tag) {1650 switch (tag) {
1651 .bpcc => self.mir_instructions.items(.data)[inst].branch_predict.inst = @intCast(Mir.Inst.Index, self.mir_instructions.len),1651 .bpcc => self.mir_instructions.items(.data)[inst].branch_predict_int.inst = @intCast(Mir.Inst.Index, self.mir_instructions.len),
1652 else => unreachable,1652 else => unreachable,
1653 }1653 }
1654}1654}
src/arch/sparc64/Mir.zig+5-5
...@@ -44,7 +44,7 @@ pub const Inst = struct {...@@ -44,7 +44,7 @@ pub const Inst = struct {
44 add,44 add,
4545
46 /// A.7 Branch on Integer Condition Codes with Prediction (BPcc)46 /// A.7 Branch on Integer Condition Codes with Prediction (BPcc)
47 /// This uses the branch_predict field.47 /// This uses the branch_predict_int field.
48 bpcc,48 bpcc,
4949
50 /// A.8 Call and Link50 /// A.8 Call and Link
...@@ -165,13 +165,13 @@ pub const Inst = struct {...@@ -165,13 +165,13 @@ pub const Inst = struct {
165 link: Register = .o7,165 link: Register = .o7,
166 },166 },
167167
168 /// Branch with prediction.168 /// Branch with prediction, checking the integer status code
169 /// Used by e.g. bpcc169 /// Used by e.g. bpcc
170 branch_predict: struct {170 branch_predict_int: struct {
171 annul: bool = false,171 annul: bool = false,
172 pt: bool = true,172 pt: bool = true,
173 ccr: Instruction.CCR,173 ccr: Instruction.CCR,
174 cond: Instruction.Condition,174 cond: Instruction.ICondition,
175 inst: Index,175 inst: Index,
176 },176 },
177177
...@@ -211,7 +211,7 @@ pub const Inst = struct {...@@ -211,7 +211,7 @@ pub const Inst = struct {
211 /// Used by e.g. tcc211 /// Used by e.g. tcc
212 trap: struct {212 trap: struct {
213 is_imm: bool = true,213 is_imm: bool = true,
214 cond: Instruction.Condition,214 cond: Instruction.ICondition,
215 ccr: Instruction.CCR = .icc,215 ccr: Instruction.CCR = .icc,
216 rs1: Register = .g0,216 rs1: Register = .g0,
217 rs2_or_imm: union {217 rs2_or_imm: union {
src/arch/sparc64/bits.zig+179-17
...@@ -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 };
514514
515 // TODO: Need to define an enum for `cond` values515 // In SPARCv9, FP and integer comparison operations
516 // This is kinda challenging since the cond values have different meanings516 // 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 };
519681
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 }
11011263
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 };