| ... | ... | @@ -51,9 +51,11 @@ const InnerError = error{ |
| 51 | 51 | |
| 52 | 52 | const BranchType = enum { |
| 53 | 53 | bpcc, |
| 54 | bpr, |
| 54 | 55 | fn default(tag: Mir.Inst.Tag) BranchType { |
| 55 | 56 | return switch (tag) { |
| 56 | 57 | .bpcc => .bpcc, |
| 58 | .bpr => .bpr, |
| 57 | 59 | else => unreachable, |
| 58 | 60 | }; |
| 59 | 61 | } |
| ... | ... | @@ -78,6 +80,7 @@ pub fn emitMir( |
| 78 | 80 | |
| 79 | 81 | .add => try emit.mirArithmetic3Op(inst), |
| 80 | 82 | |
| 83 | .bpr => try emit.mirConditionalBranch(inst), |
| 81 | 84 | .bpcc => try emit.mirConditionalBranch(inst), |
| 82 | 85 | |
| 83 | 86 | .call => @panic("TODO implement sparc64 call"), |
| ... | ... | @@ -232,15 +235,43 @@ fn mirArithmetic3Op(emit: *Emit, inst: Mir.Inst.Index) !void { |
| 232 | 235 | |
| 233 | 236 | fn mirConditionalBranch(emit: *Emit, inst: Mir.Inst.Index) !void { |
| 234 | 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 | 238 | const branch_type = emit.branch_types.get(inst).?; |
| 239 | | log.debug("mirConditionalBranchImmediate: {} offset={}", .{ inst, offset }); |
| 240 | 239 | |
| 241 | 240 | switch (branch_type) { |
| 242 | 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 | 275 | else => unreachable, |
| 245 | 276 | }, |
| 246 | 277 | } |
| ... | ... | @@ -291,6 +322,7 @@ fn branchTarget(emit: *Emit, inst: Mir.Inst.Index) Mir.Inst.Index { |
| 291 | 322 | |
| 292 | 323 | switch (tag) { |
| 293 | 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 | 326 | else => unreachable, |
| 295 | 327 | } |
| 296 | 328 | } |
| ... | ... | @@ -343,6 +375,7 @@ fn instructionSize(emit: *Emit, inst: Mir.Inst.Index) usize { |
| 343 | 375 | fn isBranch(tag: Mir.Inst.Tag) bool { |
| 344 | 376 | return switch (tag) { |
| 345 | 377 | .bpcc => true, |
| 378 | .bpr => true, |
| 346 | 379 | else => false, |
| 347 | 380 | }; |
| 348 | 381 | } |
| ... | ... | @@ -459,19 +492,27 @@ fn optimalBranchType(emit: *Emit, tag: Mir.Inst.Tag, offset: i64) !BranchType { |
| 459 | 492 | assert(offset & 0b11 == 0); |
| 460 | 493 | |
| 461 | 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 | 502 | .bpcc => { |
| 463 | 503 | if (std.math.cast(i21, offset)) |_| { |
| 464 | 504 | return BranchType.bpcc; |
| 465 | 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 | 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 | 516 | else => unreachable, |
| 476 | 517 | } |
| 477 | 518 | } |