authorgravatar for koachan@protonmail.comKoakuma <koachan@protonmail.com> 2022-05-06 23:16:07+07:00
committergravatar for koachan@protonmail.comKoakuma <koachan@protonmail.com> 2022-05-16 23:17:11+07:00
loge057ff249648bdcd8cf2e9be62b40a2379de03e9
tree832e5602be2becc2ba2ca7eaa1b1f6b23d6653e4
parent8f8853cd4ff48237770d9eeb4ea4f83979e77b5b

stage2: sparc64: Implement SPARCv9 bpr


3 files changed, 70 insertions(+), 11 deletions(-)

src/arch/sparc64/Emit.zig+52-11
...@@ -51,9 +51,11 @@ const InnerError = error{...@@ -51,9 +51,11 @@ const InnerError = error{
5151
52const BranchType = enum {52const BranchType = enum {
53 bpcc,53 bpcc,
54 bpr,
54 fn default(tag: Mir.Inst.Tag) BranchType {55 fn default(tag: Mir.Inst.Tag) BranchType {
55 return switch (tag) {56 return switch (tag) {
56 .bpcc => .bpcc,57 .bpcc => .bpcc,
58 .bpr => .bpr,
57 else => unreachable,59 else => unreachable,
58 };60 };
59 }61 }
...@@ -78,6 +80,7 @@ pub fn emitMir(...@@ -78,6 +80,7 @@ pub fn emitMir(
7880
79 .add => try emit.mirArithmetic3Op(inst),81 .add => try emit.mirArithmetic3Op(inst),
8082
83 .bpr => try emit.mirConditionalBranch(inst),
81 .bpcc => try emit.mirConditionalBranch(inst),84 .bpcc => try emit.mirConditionalBranch(inst),
8285
83 .call => @panic("TODO implement sparc64 call"),86 .call => @panic("TODO implement sparc64 call"),
...@@ -232,15 +235,43 @@ fn mirArithmetic3Op(emit: *Emit, inst: Mir.Inst.Index) !void {...@@ -232,15 +235,43 @@ fn mirArithmetic3Op(emit: *Emit, inst: Mir.Inst.Index) !void {
232235
233fn mirConditionalBranch(emit: *Emit, inst: Mir.Inst.Index) !void {236fn mirConditionalBranch(emit: *Emit, inst: Mir.Inst.Index) !void {
234 const tag = emit.mir.instructions.items(.tag)[inst];237 const tag = emit.mir.instructions.items(.tag)[inst];
235 const branch_predict_int = emit.mir.instructions.items(.data)[inst].branch_predict_int;
236
237 const offset = @intCast(i64, emit.code_offset_mapping.get(branch_predict_int.inst).?) - @intCast(i64, emit.code.items.len);
238 const branch_type = emit.branch_types.get(inst).?;238 const branch_type = emit.branch_types.get(inst).?;
239 log.debug("mirConditionalBranchImmediate: {} offset={}", .{ inst, offset });
240239
241 switch (branch_type) {240 switch (branch_type) {
242 .bpcc => switch (tag) {241 .bpcc => switch (tag) {
243 .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))),242 .bpcc => {
243 const branch_predict_int = emit.mir.instructions.items(.data)[inst].branch_predict_int;
244 const offset = @intCast(i64, emit.code_offset_mapping.get(branch_predict_int.inst).?) - @intCast(i64, emit.code.items.len);
245 log.debug("mirConditionalBranch: {} offset={}", .{ inst, offset });
246
247 try emit.writeInstruction(
248 Instruction.bpcc(
249 branch_predict_int.cond,
250 branch_predict_int.annul,
251 branch_predict_int.pt,
252 branch_predict_int.ccr,
253 @intCast(i21, offset),
254 ),
255 );
256 },
257 else => unreachable,
258 },
259 .bpr => switch (tag) {
260 .bpr => {
261 const branch_predict_reg = emit.mir.instructions.items(.data)[inst].branch_predict_reg;
262 const offset = @intCast(i64, emit.code_offset_mapping.get(branch_predict_reg.inst).?) - @intCast(i64, emit.code.items.len);
263 log.debug("mirConditionalBranch: {} offset={}", .{ inst, offset });
264
265 try emit.writeInstruction(
266 Instruction.bpr(
267 branch_predict_reg.cond,
268 branch_predict_reg.annul,
269 branch_predict_reg.pt,
270 branch_predict_reg.rs1,
271 @intCast(i18, offset),
272 ),
273 );
274 },
244 else => unreachable,275 else => unreachable,
245 },276 },
246 }277 }
...@@ -291,6 +322,7 @@ fn branchTarget(emit: *Emit, inst: Mir.Inst.Index) Mir.Inst.Index {...@@ -291,6 +322,7 @@ fn branchTarget(emit: *Emit, inst: Mir.Inst.Index) Mir.Inst.Index {
291322
292 switch (tag) {323 switch (tag) {
293 .bpcc => return emit.mir.instructions.items(.data)[inst].branch_predict_int.inst,324 .bpcc => return emit.mir.instructions.items(.data)[inst].branch_predict_int.inst,
325 .bpr => return emit.mir.instructions.items(.data)[inst].branch_predict_reg.inst,
294 else => unreachable,326 else => unreachable,
295 }327 }
296}328}
...@@ -343,6 +375,7 @@ fn instructionSize(emit: *Emit, inst: Mir.Inst.Index) usize {...@@ -343,6 +375,7 @@ fn instructionSize(emit: *Emit, inst: Mir.Inst.Index) usize {
343fn isBranch(tag: Mir.Inst.Tag) bool {375fn isBranch(tag: Mir.Inst.Tag) bool {
344 return switch (tag) {376 return switch (tag) {
345 .bpcc => true,377 .bpcc => true,
378 .bpr => true,
346 else => false,379 else => false,
347 };380 };
348}381}
...@@ -459,19 +492,27 @@ fn optimalBranchType(emit: *Emit, tag: Mir.Inst.Tag, offset: i64) !BranchType {...@@ -459,19 +492,27 @@ fn optimalBranchType(emit: *Emit, tag: Mir.Inst.Tag, offset: i64) !BranchType {
459 assert(offset & 0b11 == 0);492 assert(offset & 0b11 == 0);
460493
461 switch (tag) {494 switch (tag) {
495 // TODO use the following strategy to implement long branches:
496 // - Negate the conditional and target of the original instruction;
497 // - In the space immediately after the branch, load
498 // the address of the original target, preferrably in
499 // a PC-relative way, into %o7; and
500 // - jmpl %o7 + %g0, %g0
501
462 .bpcc => {502 .bpcc => {
463 if (std.math.cast(i21, offset)) |_| {503 if (std.math.cast(i21, offset)) |_| {
464 return BranchType.bpcc;504 return BranchType.bpcc;
465 } else |_| {505 } else |_| {
466 // TODO use the following strategy to implement long branches:
467 // - Negate the conditional and target of the original BPcc;
468 // - In the space immediately after the branch, load
469 // the address of the original target, preferrably in
470 // a PC-relative way, into %o7; and
471 // - jmpl %o7 + %g0, %g0
472 return emit.fail("TODO support BPcc branches larger than +-1 MiB", .{});506 return emit.fail("TODO support BPcc branches larger than +-1 MiB", .{});
473 }507 }
474 },508 },
509 .bpr => {
510 if (std.math.cast(i18, offset)) |_| {
511 return BranchType.bpr;
512 } else |_| {
513 return emit.fail("TODO support BPr branches larger than +-128 KiB", .{});
514 }
515 },
475 else => unreachable,516 else => unreachable,
476 }517 }
477}518}
src/arch/sparc64/Mir.zig+14
...@@ -43,6 +43,10 @@ pub const Inst = struct {...@@ -43,6 +43,10 @@ pub const Inst = struct {
43 // TODO add other operations.43 // TODO add other operations.
44 add,44 add,
4545
46 /// A.3 Branch on Integer Register with Prediction (BPr)
47 /// This uses the branch_predict_reg field.
48 bpr,
49
46 /// A.7 Branch on Integer Condition Codes with Prediction (BPcc)50 /// A.7 Branch on Integer Condition Codes with Prediction (BPcc)
47 /// This uses the branch_predict_int field.51 /// This uses the branch_predict_int field.
48 bpcc,52 bpcc,
...@@ -175,6 +179,16 @@ pub const Inst = struct {...@@ -175,6 +179,16 @@ pub const Inst = struct {
175 inst: Index,179 inst: Index,
176 },180 },
177181
182 /// Branch with prediction, comparing a register's content with zero
183 /// Used by e.g. bpr
184 branch_predict_reg: struct {
185 annul: bool = false,
186 pt: bool = true,
187 cond: Instruction.RCondition,
188 rs1: Register,
189 inst: Index,
190 },
191
178 /// No additional data192 /// No additional data
179 ///193 ///
180 /// Used by e.g. flushw194 /// Used by e.g. flushw
src/arch/sparc64/bits.zig+4
...@@ -1145,6 +1145,10 @@ pub const Instruction = union(enum) {...@@ -1145,6 +1145,10 @@ pub const Instruction = union(enum) {
1145 return format2c(0b001, .{ .icond = cond }, annul, pt, ccr, disp);1145 return format2c(0b001, .{ .icond = cond }, annul, pt, ccr, disp);
1146 }1146 }
11471147
1148 pub fn bpr(cond: RCondition, annul: bool, pt: bool, rs1: Register, disp: i18) Instruction {
1149 return format2d(0b011, cond, annul, pt, rs1, disp);
1150 }
1151
1148 pub fn jmpl(comptime s2: type, rs1: Register, rs2: s2, rd: Register) Instruction {1152 pub fn jmpl(comptime s2: type, rs1: Register, rs2: s2, rd: Register) Instruction {
1149 return switch (s2) {1153 return switch (s2) {
1150 Register => format3a(0b10, 0b11_1000, rs1, rs2, rd),1154 Register => format3a(0b10, 0b11_1000, rs1, rs2, rd),