diff --git a/src/arch/sparc64/CodeGen.zig b/src/arch/sparc64/CodeGen.zig index 5b4ab0d564..9871023867 100644 --- a/src/arch/sparc64/CodeGen.zig +++ b/src/arch/sparc64/CodeGen.zig @@ -725,7 +725,7 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { .data = .{ .trap = .{ .is_imm = true, - .cond = 0b1000, // TODO need to look into changing this into an enum + .cond = .al, .rs2_or_imm = .{ .imm = 0x6d }, }, }, @@ -842,7 +842,7 @@ fn airBreakpoint(self: *Self) !void { .data = .{ .trap = .{ .is_imm = true, - .cond = 0b1000, // TODO need to look into changing this into an enum + .cond = .al, .rs2_or_imm = .{ .imm = 0x01 }, }, }, @@ -1648,7 +1648,7 @@ fn parseRegName(name: []const u8) ?Register { fn performReloc(self: *Self, inst: Mir.Inst.Index) !void { const tag = self.mir_instructions.items(.tag)[inst]; switch (tag) { - .bpcc => self.mir_instructions.items(.data)[inst].branch_predict.inst = @intCast(Mir.Inst.Index, self.mir_instructions.len), + .bpcc => self.mir_instructions.items(.data)[inst].branch_predict_int.inst = @intCast(Mir.Inst.Index, self.mir_instructions.len), else => unreachable, } } diff --git a/src/arch/sparc64/Mir.zig b/src/arch/sparc64/Mir.zig index bdf25814a9..f61f76bcba 100644 --- a/src/arch/sparc64/Mir.zig +++ b/src/arch/sparc64/Mir.zig @@ -44,7 +44,7 @@ pub const Inst = struct { add, /// A.7 Branch on Integer Condition Codes with Prediction (BPcc) - /// This uses the branch_predict field. + /// This uses the branch_predict_int field. bpcc, /// A.8 Call and Link @@ -165,13 +165,13 @@ pub const Inst = struct { link: Register = .o7, }, - /// Branch with prediction. + /// Branch with prediction, checking the integer status code /// Used by e.g. bpcc - branch_predict: struct { + branch_predict_int: struct { annul: bool = false, pt: bool = true, ccr: Instruction.CCR, - cond: Instruction.Condition, + cond: Instruction.ICondition, inst: Index, }, @@ -211,7 +211,7 @@ pub const Inst = struct { /// Used by e.g. tcc trap: struct { is_imm: bool = true, - cond: Instruction.Condition, + cond: Instruction.ICondition, ccr: Instruction.CCR = .icc, rs1: Register = .g0, rs2_or_imm: union { diff --git a/src/arch/sparc64/bits.zig b/src/arch/sparc64/bits.zig index e66b24f617..ac45f1876b 100644 --- a/src/arch/sparc64/bits.zig +++ b/src/arch/sparc64/bits.zig @@ -512,10 +512,172 @@ pub const Instruction = union(enum) { lookaside: bool = false, }; - // TODO: Need to define an enum for `cond` values - // This is kinda challenging since the cond values have different meanings - // depending on whether it's operating on integer or FP CCR. - pub const Condition = u4; + // In SPARCv9, FP and integer comparison operations + // are encoded differently. + + pub const FCondition = enum(u4) { + /// Branch Never + nv, + /// Branch on Not Equal + ne, + /// Branch on Less or Greater + lg, + /// Branch on Unordered or Less + ul, + /// Branch on Less + lt, + /// Branch on Unordered or Greater + ug, + /// Branch on Greater + gt, + /// Branch on Unordered + un, + /// Branch Always + al, + /// Branch on Equal + eq, + /// Branch on Unordered or Equal + ue, + /// Branch on Greater or Equal + ge, + /// Branch on Unordered or Greater or Equal + uge, + /// Branch on Less or Equal + le, + /// Branch on Unordered or Less or Equal + ule, + /// Branch on Ordered + ord, + + /// Converts a std.math.CompareOperator into a condition flag, + /// i.e. returns the condition that is true iff the result of the + /// comparison is true. + pub fn fromCompareOperator(op: std.math.CompareOperator) FCondition { + return switch (op) { + .gte => .ge, + .gt => .gt, + .neq => .ne, + .lt => .lt, + .lte => .le, + .eq => .eq, + }; + } + + /// Returns the condition which is true iff the given condition is + /// false (if such a condition exists). + pub fn negate(cond: FCondition) FCondition { + return switch (cond) { + .eq => .ne, + .ne => .eq, + .ge => .ul, + .ul => .ge, + .le => .ug, + .ug => .le, + .lt => .uge, + .uge => .lt, + .gt => .ule, + .ule => .gt, + .ue => .lg, + .lg => .ue, + .ord => .un, + .un => .ord, + .al => unreachable, + .nv => unreachable, + }; + } + }; + + pub const ICondition = enum(u4) { + /// Branch Never + nv, + /// Branch on Equal + eq, + /// Branch on Less or Equal + le, + /// Branch on Less + lt, + /// Branch on Less or Equal Unsigned + leu, + /// Branch on Carry Set (Less than, Unsigned) + cs, + /// Branch on Negative + neg, + /// Branch on Overflow Set + vs, + /// Branch Always + al, + /// Branch on Not Equal + ne, + /// Branch on Greater + gt, + /// Branch on Greater or Equal + ge, + /// Branch on Greater Unsigned + gu, + /// Branch on Carry Clear (Greater Than or Equal, Unsigned) + cc, + /// Branch on Positive + pos, + /// Branch on Overflow Clear + vc, + + /// Converts a std.math.CompareOperator into a condition flag, + /// i.e. returns the condition that is true iff the result of the + /// comparison is true. Assumes signed comparison. + pub fn fromCompareOperatorSigned(op: std.math.CompareOperator) ICondition { + return switch (op) { + .gte => .ge, + .gt => .gt, + .neq => .ne, + .lt => .lt, + .lte => .le, + .eq => .eq, + }; + } + + /// Converts a std.math.CompareOperator into a condition flag, + /// i.e. returns the condition that is true iff the result of the + /// comparison is true. Assumes unsigned comparison. + pub fn fromCompareOperatorUnsigned(op: std.math.CompareOperator) ICondition { + return switch (op) { + .gte => .cc, + .gt => .gu, + .neq => .ne, + .lt => .cs, + .lte => .le, + .eq => .eq, + }; + } + + /// Returns the condition which is true iff the given condition is + /// false (if such a condition exists). + pub fn negate(cond: ICondition) ICondition { + return switch (cond) { + .eq => .ne, + .ne => .eq, + .cs => .cc, + .cc => .cs, + .neg => .pos, + .pos => .neg, + .vs => .vc, + .vc => .vs, + .gu => .leu, + .leu => .gu, + .ge => .lt, + .lt => .ge, + .gt => .le, + .le => .gt, + .al => unreachable, + .nv => unreachable, + }; + } + }; + + pub const Condition = packed union { + fcond: FCondition, + icond: ICondition, + encoded: u4, + }; pub fn toU32(self: Instruction) u32 { // TODO: Remove this once packed structs work. @@ -593,7 +755,7 @@ pub const Instruction = union(enum) { return Instruction{ .format_2b = .{ .a = @boolToInt(annul), - .cond = cond, + .cond = cond.encoded, .op2 = op2, .disp22 = udisp_truncated, }, @@ -614,7 +776,7 @@ pub const Instruction = union(enum) { return Instruction{ .format_2c = .{ .a = @boolToInt(annul), - .cond = cond, + .cond = cond.encoded, .op2 = op2, .cc1 = ccr_cc1, .cc0 = ccr_cc0, @@ -895,7 +1057,7 @@ pub const Instruction = union(enum) { .rd = rd.enc(), .op3 = op3, .cc2 = ccr_cc2, - .cond = cond, + .cond = cond.encoded, .cc1 = ccr_cc1, .cc0 = ccr_cc0, .rs2 = rs2.enc(), @@ -912,7 +1074,7 @@ pub const Instruction = union(enum) { .rd = rd.enc(), .op3 = op3, .cc2 = ccr_cc2, - .cond = cond, + .cond = cond.encoded, .cc1 = ccr_cc1, .cc0 = ccr_cc0, .simm11 = @bitCast(u11, imm), @@ -960,7 +1122,7 @@ pub const Instruction = union(enum) { .format_4g = .{ .rd = rd.enc(), .op3 = op3, - .cond = cond, + .cond = cond.encoded, .opf_cc = opf_cc, .opf_low = opf_low, .rs2 = rs2.enc(), @@ -1099,11 +1261,11 @@ pub const Instruction = union(enum) { }; } - pub fn trap(comptime s2: type, cond: Condition, ccr: CCR, rs1: Register, rs2: s2) Instruction { + pub fn trap(comptime s2: type, cond: ICondition, ccr: CCR, rs1: Register, rs2: s2) Instruction { // Tcc instructions abuse the rd field to store the conditionals. return switch (s2) { - Register => format4a(0b11_1010, ccr, rs1, rs2, @intToEnum(Register, cond)), - u7 => format4e(0b11_1010, ccr, rs1, @intToEnum(Register, cond), rs2), + Register => format4a(0b11_1010, ccr, rs1, rs2, @intToEnum(Register, @enumToInt(cond))), + u7 => format4e(0b11_1010, ccr, rs1, @intToEnum(Register, @enumToInt(cond)), rs2), else => unreachable, }; } @@ -1128,11 +1290,11 @@ test "Serialize formats" { .expected = 0b00_00000_100_0000000000000000000000, }, .{ - .inst = Instruction.format2b(6, 3, true, -4), + .inst = Instruction.format2b(6, .{ .icond = .lt }, true, -4), .expected = 0b00_1_0011_110_1111111111111111111111, }, .{ - .inst = Instruction.format2c(3, 0, false, true, .xcc, 8), + .inst = Instruction.format2c(3, .{ .icond = .nv }, false, true, .xcc, 8), .expected = 0b00_0_0000_011_1_0_1_0000000000000000010, }, .{ @@ -1224,11 +1386,11 @@ test "Serialize formats" { .expected = 0b10_10010_001000_00000_1_1_0_11111111111, }, .{ - .inst = Instruction.format4c(8, 0, .xcc, .g0, .o1), + .inst = Instruction.format4c(8, .{ .icond = .nv }, .xcc, .g0, .o1), .expected = 0b10_01001_001000_1_0000_0_1_0_000000_00000, }, .{ - .inst = Instruction.format4d(8, 0, .xcc, 0, .l2), + .inst = Instruction.format4d(8, .{ .icond = .nv }, .xcc, 0, .l2), .expected = 0b10_10010_001000_1_0000_1_1_0_00000000000, }, .{ @@ -1240,7 +1402,7 @@ test "Serialize formats" { .expected = 0b10_10010_001000_00000_0_001_00100_01001, }, .{ - .inst = Instruction.format4g(8, 4, 2, 0, .o1, .l2), + .inst = Instruction.format4g(8, 4, 2, .{ .icond = .nv }, .o1, .l2), .expected = 0b10_10010_001000_0_0000_010_000100_01001, }, };