| ... | @@ -51,9 +51,11 @@ const InnerError = error{ | ... | @@ -51,9 +51,11 @@ const InnerError = error{ |
| 51 | | 51 | |
| 52 | const BranchType = enum { | 52 | const 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( |
| 78 | | 80 | |
| 79 | .add => try emit.mirArithmetic3Op(inst), | 81 | .add => try emit.mirArithmetic3Op(inst), |
| 80 | | 82 | |
| | 83 | .bpr => try emit.mirConditionalBranch(inst), |
| 81 | .bpcc => try emit.mirConditionalBranch(inst), | 84 | .bpcc => try emit.mirConditionalBranch(inst), |
| 82 | | 85 | |
| 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 { |
| 232 | | 235 | |
| 233 | fn mirConditionalBranch(emit: *Emit, inst: Mir.Inst.Index) !void { | 236 | fn 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 }); | | |
| 240 | | 239 | |
| 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 { |
| 291 | | 322 | |
| 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 { |
| 343 | fn isBranch(tag: Mir.Inst.Tag) bool { | 375 | fn 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); |
| 460 | | 493 | |
| 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 | } |