Optimize unconditional jumps
4579515f4565e20eb80f4f54800889b9ac1ea0a8c464cf40c23ca225f16447ed
Don't waste a slot for them.
1 parent
e5645fc3
lib/std/arch/rv64/emit.rad
+13 -20
| 247 | 247 | e.funcs[e.funcsLen] = types::FuncAddr { name, index: e.codeLen }; |
|
| 248 | 248 | e.funcsLen += 1; |
|
| 249 | 249 | } |
|
| 250 | 250 | ||
| 251 | 251 | /// Record a local branch needing later patching. |
|
| 252 | - | /// Emits two placeholder instructions that will be patched later. |
|
| 252 | + | /// Unconditional jumps use a single slot (J-type, +-1MB range). |
|
| 253 | + | /// Conditional branches use two slots (B-type has only +-4KB range, |
|
| 254 | + | /// so large functions may need the inverted-branch + JAL fallback). |
|
| 253 | 255 | pub fn recordBranch(e: *mut Emitter, targetBlock: u32, kind: BranchKind) { |
|
| 254 | 256 | if e.pendingBranchesLen >= e.pendingBranches.len { |
|
| 255 | 257 | panic "recordBranch: buffer full"; |
|
| 256 | 258 | } |
|
| 257 | 259 | e.pendingBranches[e.pendingBranchesLen] = PendingBranch { |
| 259 | 261 | target: targetBlock, |
|
| 260 | 262 | kind: kind, |
|
| 261 | 263 | }; |
|
| 262 | 264 | e.pendingBranchesLen += 1; |
|
| 263 | 265 | ||
| 264 | - | emit(e, encode::nop()); // Placeholder for branch/auipc. |
|
| 265 | - | emit(e, encode::nop()); // Placeholder for nop/jal/jalr. |
|
| 266 | + | emit(e, encode::nop()); // First slot, always needed. |
|
| 267 | + | ||
| 268 | + | match kind { |
|
| 269 | + | case BranchKind::Jump => {}, |
|
| 270 | + | else => emit(e, encode::nop()), // Second slot for conditional branches. |
|
| 271 | + | } |
|
| 266 | 272 | } |
|
| 267 | 273 | ||
| 268 | 274 | /// Record a function call needing later patching. |
|
| 269 | 275 | /// Emits placeholder instructions that will be patched later. |
|
| 270 | 276 | /// Uses two slots to support long-distance calls. |
| 311 | 317 | let p = e.pendingBranches[i]; |
|
| 312 | 318 | let offset = labels::branchToBlock(&e.labels, p.index, p.target, super::INSTR_SIZE); |
|
| 313 | 319 | match p.kind { |
|
| 314 | 320 | case BranchKind::Cond { op, rs1, rs2 } => { |
|
| 315 | 321 | if encode::isBranchImm(offset) { |
|
| 316 | - | // Short: direct branch. |
|
| 317 | 322 | patch(e, p.index, encodeCondBranch(op, rs1, rs2, offset)); |
|
| 318 | 323 | patch(e, p.index + 1, encode::nop()); |
|
| 319 | 324 | } else { |
|
| 320 | - | // Long: inverted branch skips `jal`; `jal` goes to target. |
|
| 321 | 325 | let adj = offset - super::INSTR_SIZE; |
|
| 322 | - | if not encode::isJumpImm(adj) { |
|
| 323 | - | panic "patchLocalBranches: branch offset too large"; |
|
| 324 | - | } |
|
| 325 | 326 | patch(e, p.index, encodeInvertedBranch(op, rs1, rs2, super::INSTR_SIZE * 2)); |
|
| 326 | 327 | patch(e, p.index + 1, encode::jal(super::ZERO, adj)); |
|
| 327 | 328 | } |
|
| 328 | 329 | }, |
|
| 329 | 330 | case BranchKind::InvertedCond { op, rs1, rs2 } => { |
|
| 330 | 331 | if encode::isBranchImm(offset) { |
|
| 331 | - | // Short: direct inverted branch. |
|
| 332 | 332 | patch(e, p.index, encodeInvertedBranch(op, rs1, rs2, offset)); |
|
| 333 | 333 | patch(e, p.index + 1, encode::nop()); |
|
| 334 | 334 | } else { |
|
| 335 | - | // Long: non-inverted branch skips `jal`, jal goes to target. |
|
| 336 | 335 | let adj = offset - super::INSTR_SIZE; |
|
| 337 | - | if not encode::isJumpImm(adj) { |
|
| 338 | - | panic "patchLocalBranches: branch offset too large"; |
|
| 339 | - | } |
|
| 340 | 336 | patch(e, p.index, encodeCondBranch(op, rs1, rs2, super::INSTR_SIZE * 2)); |
|
| 341 | 337 | patch(e, p.index + 1, encode::jal(super::ZERO, adj)); |
|
| 342 | 338 | } |
|
| 343 | 339 | }, |
|
| 344 | 340 | case BranchKind::Jump => { |
|
| 345 | - | if encode::isJumpImm(offset) { |
|
| 346 | - | patch(e, p.index, encode::jal(super::ZERO, offset)); |
|
| 347 | - | patch(e, p.index + 1, encode::nop()); |
|
| 348 | - | } else { |
|
| 349 | - | let s = splitImm(offset); |
|
| 350 | - | patch(e, p.index, encode::auipc(super::SCRATCH1, s.hi)); |
|
| 351 | - | patch(e, p.index + 1, encode::jalr(super::ZERO, super::SCRATCH1, s.lo)); |
|
| 341 | + | // Single-slot jump (J-type, +-1MB range). |
|
| 342 | + | if not encode::isJumpImm(offset) { |
|
| 343 | + | panic "patchLocalBranches: jump offset too large"; |
|
| 352 | 344 | } |
|
| 345 | + | patch(e, p.index, encode::jal(super::ZERO, offset)); |
|
| 353 | 346 | }, |
|
| 354 | 347 | } |
|
| 355 | 348 | } |
|
| 356 | 349 | e.pendingBranchesLen = 0; |
|
| 357 | 350 | } |