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{
5151
5252const BranchType = enum {
5353 bpcc,
54 bpr,
5455 fn default(tag: Mir.Inst.Tag) BranchType {
5556 return switch (tag) {
5657 .bpcc => .bpcc,
58 .bpr => .bpr,
5759 else => unreachable,
5860 };
5961 }
......@@ -78,6 +80,7 @@ pub fn emitMir(
7880
7981 .add => try emit.mirArithmetic3Op(inst),
8082
83 .bpr => try emit.mirConditionalBranch(inst),
8184 .bpcc => try emit.mirConditionalBranch(inst),
8285
8386 .call => @panic("TODO implement sparc64 call"),
......@@ -232,15 +235,43 @@ fn mirArithmetic3Op(emit: *Emit, inst: Mir.Inst.Index) !void {
232235
233236fn mirConditionalBranch(emit: *Emit, inst: Mir.Inst.Index) !void {
234237 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);
238238 const branch_type = emit.branch_types.get(inst).?;
239 log.debug("mirConditionalBranchImmediate: {} offset={}", .{ inst, offset });
240239
241240 switch (branch_type) {
242241 .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 },
244275 else => unreachable,
245276 },
246277 }
......@@ -291,6 +322,7 @@ fn branchTarget(emit: *Emit, inst: Mir.Inst.Index) Mir.Inst.Index {
291322
292323 switch (tag) {
293324 .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,
294326 else => unreachable,
295327 }
296328}
......@@ -343,6 +375,7 @@ fn instructionSize(emit: *Emit, inst: Mir.Inst.Index) usize {
343375fn isBranch(tag: Mir.Inst.Tag) bool {
344376 return switch (tag) {
345377 .bpcc => true,
378 .bpr => true,
346379 else => false,
347380 };
348381}
......@@ -459,19 +492,27 @@ fn optimalBranchType(emit: *Emit, tag: Mir.Inst.Tag, offset: i64) !BranchType {
459492 assert(offset & 0b11 == 0);
460493
461494 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
462502 .bpcc => {
463503 if (std.math.cast(i21, offset)) |_| {
464504 return BranchType.bpcc;
465505 } 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
472506 return emit.fail("TODO support BPcc branches larger than +-1 MiB", .{});
473507 }
474508 },
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 },
475516 else => unreachable,
476517 }
477518}
src/arch/sparc64/Mir.zig+14
......@@ -43,6 +43,10 @@ pub const Inst = struct {
4343 // TODO add other operations.
4444 add,
4545
46 /// A.3 Branch on Integer Register with Prediction (BPr)
47 /// This uses the branch_predict_reg field.
48 bpr,
49
4650 /// A.7 Branch on Integer Condition Codes with Prediction (BPcc)
4751 /// This uses the branch_predict_int field.
4852 bpcc,
......@@ -175,6 +179,16 @@ pub const Inst = struct {
175179 inst: Index,
176180 },
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
178192 /// No additional data
179193 ///
180194 /// Used by e.g. flushw
src/arch/sparc64/bits.zig+4
......@@ -1145,6 +1145,10 @@ pub const Instruction = union(enum) {
11451145 return format2c(0b001, .{ .icond = cond }, annul, pt, ccr, disp);
11461146 }
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
11481152 pub fn jmpl(comptime s2: type, rs1: Register, rs2: s2, rd: Register) Instruction {
11491153 return switch (s2) {
11501154 Register => format3a(0b10, 0b11_1000, rs1, rs2, rd),