From e057ff249648bdcd8cf2e9be62b40a2379de03e9 Mon Sep 17 00:00:00 2001 From: Koakuma Date: Fri, 6 May 2022 23:16:07 +0700 Subject: [PATCH] stage2: sparc64: Implement SPARCv9 bpr --- src/arch/sparc64/Emit.zig | 63 ++++++++++++++++++++++++++++++++------- src/arch/sparc64/Mir.zig | 14 +++++++++ src/arch/sparc64/bits.zig | 4 +++ 3 files changed, 70 insertions(+), 11 deletions(-) diff --git a/src/arch/sparc64/Emit.zig b/src/arch/sparc64/Emit.zig index c7c6ac4904..738744fe90 100644 --- a/src/arch/sparc64/Emit.zig +++ b/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, } } diff --git a/src/arch/sparc64/Mir.zig b/src/arch/sparc64/Mir.zig index f61f76bcba..d9309f1524 100644 --- a/src/arch/sparc64/Mir.zig +++ b/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 diff --git a/src/arch/sparc64/bits.zig b/src/arch/sparc64/bits.zig index b6d61900ce..cb7fe36810 100644 --- a/src/arch/sparc64/bits.zig +++ b/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),