Commit e057ff2496
src/arch/sparc64/bits.zig
@@ -1145,6 +1145,10 @@ pub const Instruction = union(enum) {
return format2c(0b001, .{ .icond = cond }, annul, pt, ccr, disp);
}
+ pub fn bpr(cond: RCondition, annul: bool, pt: bool, rs1: Register, disp: i18) Instruction {
+ return format2d(0b011, cond, annul, pt, rs1, disp);
+ }
+
pub fn jmpl(comptime s2: type, rs1: Register, rs2: s2, rd: Register) Instruction {
return switch (s2) {
Register => format3a(0b10, 0b11_1000, rs1, rs2, rd),
src/arch/sparc64/Emit.zig
@@ -51,9 +51,11 @@ const InnerError = error{
const BranchType = enum {
bpcc,
+ bpr,
fn default(tag: Mir.Inst.Tag) BranchType {
return switch (tag) {
.bpcc => .bpcc,
+ .bpr => .bpr,
else => unreachable,
};
}
@@ -78,6 +80,7 @@ pub fn emitMir(
.add => try emit.mirArithmetic3Op(inst),
+ .bpr => try emit.mirConditionalBranch(inst),
.bpcc => try emit.mirConditionalBranch(inst),
.call => @panic("TODO implement sparc64 call"),
@@ -232,15 +235,43 @@ fn mirArithmetic3Op(emit: *Emit, inst: Mir.Inst.Index) !void {
fn mirConditionalBranch(emit: *Emit, inst: Mir.Inst.Index) !void {
const tag = emit.mir.instructions.items(.tag)[inst];
- const branch_predict_int = emit.mir.instructions.items(.data)[inst].branch_predict_int;
-
- const offset = @intCast(i64, emit.code_offset_mapping.get(branch_predict_int.inst).?) - @intCast(i64, emit.code.items.len);
const branch_type = emit.branch_types.get(inst).?;
- log.debug("mirConditionalBranchImmediate: {} offset={}", .{ inst, offset });
switch (branch_type) {
.bpcc => switch (tag) {
- .bpcc => try emit.writeInstruction(Instruction.bpcc(branch_predict_int.cond, branch_predict_int.annul, branch_predict_int.pt, branch_predict_int.ccr, @intCast(i21, offset))),
+ .bpcc => {
+ const branch_predict_int = emit.mir.instructions.items(.data)[inst].branch_predict_int;
+ const offset = @intCast(i64, emit.code_offset_mapping.get(branch_predict_int.inst).?) - @intCast(i64, emit.code.items.len);
+ log.debug("mirConditionalBranch: {} offset={}", .{ inst, offset });
+
+ try emit.writeInstruction(
+ Instruction.bpcc(
+ branch_predict_int.cond,
+ branch_predict_int.annul,
+ branch_predict_int.pt,
+ branch_predict_int.ccr,
+ @intCast(i21, offset),
+ ),
+ );
+ },
+ else => unreachable,
+ },
+ .bpr => switch (tag) {
+ .bpr => {
+ const branch_predict_reg = emit.mir.instructions.items(.data)[inst].branch_predict_reg;
+ const offset = @intCast(i64, emit.code_offset_mapping.get(branch_predict_reg.inst).?) - @intCast(i64, emit.code.items.len);
+ log.debug("mirConditionalBranch: {} offset={}", .{ inst, offset });
+
+ try emit.writeInstruction(
+ Instruction.bpr(
+ branch_predict_reg.cond,
+ branch_predict_reg.annul,
+ branch_predict_reg.pt,
+ branch_predict_reg.rs1,
+ @intCast(i18, offset),
+ ),
+ );
+ },
else => unreachable,
},
}
@@ -291,6 +322,7 @@ fn branchTarget(emit: *Emit, inst: Mir.Inst.Index) Mir.Inst.Index {
switch (tag) {
.bpcc => return emit.mir.instructions.items(.data)[inst].branch_predict_int.inst,
+ .bpr => return emit.mir.instructions.items(.data)[inst].branch_predict_reg.inst,
else => unreachable,
}
}
@@ -343,6 +375,7 @@ fn instructionSize(emit: *Emit, inst: Mir.Inst.Index) usize {
fn isBranch(tag: Mir.Inst.Tag) bool {
return switch (tag) {
.bpcc => true,
+ .bpr => true,
else => false,
};
}
@@ -459,19 +492,27 @@ fn optimalBranchType(emit: *Emit, tag: Mir.Inst.Tag, offset: i64) !BranchType {
assert(offset & 0b11 == 0);
switch (tag) {
+ // TODO use the following strategy to implement long branches:
+ // - Negate the conditional and target of the original instruction;
+ // - In the space immediately after the branch, load
+ // the address of the original target, preferrably in
+ // a PC-relative way, into %o7; and
+ // - jmpl %o7 + %g0, %g0
+
.bpcc => {
if (std.math.cast(i21, offset)) |_| {
return BranchType.bpcc;
} else |_| {
- // TODO use the following strategy to implement long branches:
- // - Negate the conditional and target of the original BPcc;
- // - In the space immediately after the branch, load
- // the address of the original target, preferrably in
- // a PC-relative way, into %o7; and
- // - jmpl %o7 + %g0, %g0
return emit.fail("TODO support BPcc branches larger than +-1 MiB", .{});
}
},
+ .bpr => {
+ if (std.math.cast(i18, offset)) |_| {
+ return BranchType.bpr;
+ } else |_| {
+ return emit.fail("TODO support BPr branches larger than +-128 KiB", .{});
+ }
+ },
else => unreachable,
}
}
src/arch/sparc64/Mir.zig
@@ -43,6 +43,10 @@ pub const Inst = struct {
// TODO add other operations.
add,
+ /// A.3 Branch on Integer Register with Prediction (BPr)
+ /// This uses the branch_predict_reg field.
+ bpr,
+
/// A.7 Branch on Integer Condition Codes with Prediction (BPcc)
/// This uses the branch_predict_int field.
bpcc,
@@ -175,6 +179,16 @@ pub const Inst = struct {
inst: Index,
},
+ /// Branch with prediction, comparing a register's content with zero
+ /// Used by e.g. bpr
+ branch_predict_reg: struct {
+ annul: bool = false,
+ pt: bool = true,
+ cond: Instruction.RCondition,
+ rs1: Register,
+ inst: Index,
+ },
+
/// No additional data
///
/// Used by e.g. flushw