Change IL's `Blit` size to `Val`
d21f24aaceaf81961ba42f0e26eb41096dbf372c365763cb58530eecc56fbe0a
Change the Blit instruction's size operand from a static integer to an `il::Val`. This prepares for dynamic blits needed by generic dictionary passing where the size is only known at runtime.
1 parent
dd43ff04
lib/std/arch/rv64/isel.rad
+6 -3
| 400 | 400 | else => |
|
| 401 | 401 | panic "selectInstr: invalid reserve operand", |
|
| 402 | 402 | } |
|
| 403 | 403 | }, |
|
| 404 | 404 | case il::Instr::Blit { dst, src, size } => { |
|
| 405 | + | let case il::Val::Imm(staticSize) = size |
|
| 406 | + | else panic "selectInstr: blit requires immediate size"; |
|
| 407 | + | ||
| 405 | 408 | let bothSpilled = regalloc::spill::isSpilled(&s.ralloc.spill, dst) |
|
| 406 | 409 | and regalloc::spill::isSpilled(&s.ralloc.spill, src); |
|
| 407 | 410 | ||
| 408 | 411 | // When both are spilled, offsets must fit 12-bit immediates |
|
| 409 | 412 | // since we can't advance base registers (they live in spill |
|
| 410 | 413 | // slots, not real registers we can mutate). |
|
| 411 | - | if bothSpilled and size as i32 > super::MAX_IMM { |
|
| 414 | + | if bothSpilled and staticSize as i32 > super::MAX_IMM { |
|
| 412 | 415 | panic "selectInstr: blit both-spilled with large size"; |
|
| 413 | 416 | } |
|
| 414 | 417 | ||
| 415 | 418 | // Resolve dst/src base registers. |
|
| 416 | 419 | let mut rdst = super::SCRATCH2; |
| 429 | 432 | } else { |
|
| 430 | 433 | rdst = getSrcReg(s, dst, super::SCRATCH2); |
|
| 431 | 434 | rsrc = getSrcReg(s, src, super::SCRATCH2); |
|
| 432 | 435 | } |
|
| 433 | 436 | let mut offset: i32 = 0; |
|
| 434 | - | let mut remaining = size as i32; |
|
| 437 | + | let mut remaining = staticSize as i32; |
|
| 435 | 438 | ||
| 436 | 439 | // Copy loop: 8 bytes, then 4 bytes, then 1 byte at a time. |
|
| 437 | 440 | // Before each load/store pair, check whether the offset is |
|
| 438 | 441 | // about to exceed the 12-bit signed immediate range. When |
|
| 439 | 442 | // it does, advance the base registers by the accumulated |
| 493 | 496 | remaining -= 1; |
|
| 494 | 497 | } |
|
| 495 | 498 | // Restore base registers if they were advanced (never happens |
|
| 496 | 499 | // in the both-spilled case since size <= MAX_IMM). |
|
| 497 | 500 | if not bothSpilled { |
|
| 498 | - | let advanced = size as i32 - offset; |
|
| 501 | + | let advanced = staticSize as i32 - offset; |
|
| 499 | 502 | if advanced != 0 { |
|
| 500 | 503 | emit::emitAddImm(s.e, rsrc, rsrc, 0 - advanced); |
|
| 501 | 504 | if rdst.n != rsrc.n { |
|
| 502 | 505 | emit::emitAddImm(s.e, rdst, rdst, 0 - advanced); |
|
| 503 | 506 | } |
lib/std/lang/il.rad
+4 -2
| 208 | 208 | dst: Reg, |
|
| 209 | 209 | /// Byte offset from the base address. |
|
| 210 | 210 | offset: i32 |
|
| 211 | 211 | }, |
|
| 212 | 212 | /// Copy memory region: `blit %dst %src <size>;` |
|
| 213 | + | /// Size can be an immediate or a register (eg. for generics). |
|
| 213 | 214 | Blit { |
|
| 214 | 215 | /// Destination address. |
|
| 215 | 216 | dst: Reg, |
|
| 216 | 217 | /// Source address. |
|
| 217 | 218 | src: Reg, |
|
| 218 | 219 | /// Size to copy in bytes. |
|
| 219 | - | size: u32 |
|
| 220 | + | size: Val |
|
| 220 | 221 | }, |
|
| 221 | 222 | /// Copy a value into a register: `copy %dst <val>;`. |
|
| 222 | 223 | Copy { dst: Reg, val: Val }, |
|
| 223 | 224 | ||
| 224 | 225 | ///////////////////// |
| 462 | 463 | case Instr::Sload { src, .. } => f(src, ctx), |
|
| 463 | 464 | case Instr::Store { src, dst, .. } => { |
|
| 464 | 465 | withReg(src, f, ctx); |
|
| 465 | 466 | f(dst, ctx); |
|
| 466 | 467 | }, |
|
| 467 | - | case Instr::Blit { dst, src, .. } => { |
|
| 468 | + | case Instr::Blit { dst, src, size } => { |
|
| 468 | 469 | f(dst, ctx); |
|
| 469 | 470 | f(src, ctx); |
|
| 471 | + | withReg(size, f, ctx); |
|
| 470 | 472 | }, |
|
| 471 | 473 | case Instr::Copy { val, .. } => |
|
| 472 | 474 | withReg(val, f, ctx), |
|
| 473 | 475 | case Instr::BinOp { a, b, .. } => { |
|
| 474 | 476 | withReg(a, f, ctx); |
lib/std/lang/il/printer.rad
+1 -1
| 256 | 256 | write(out, "blit "); |
|
| 257 | 257 | writeReg(out, a, dst); |
|
| 258 | 258 | write(out, " "); |
|
| 259 | 259 | writeReg(out, a, src); |
|
| 260 | 260 | write(out, " "); |
|
| 261 | - | write(out, formatU32(a, size)); |
|
| 261 | + | writeVal(out, a, size); |
|
| 262 | 262 | } |
|
| 263 | 263 | case super::Instr::Copy { dst, val } => { |
|
| 264 | 264 | write(out, "copy "); |
|
| 265 | 265 | writeReg(out, a, dst); |
|
| 266 | 266 | write(out, " "); |
lib/std/lang/lower.rad
+6 -6
| 3757 | 3757 | if isAggregateType(typ) { |
|
| 3758 | 3758 | let dst = emitPtrOffset(self, base, offset); |
|
| 3759 | 3759 | let src = try emitValToReg(self, src); |
|
| 3760 | 3760 | let layout = resolver::getTypeLayout(typ); |
|
| 3761 | 3761 | ||
| 3762 | - | emit(self, il::Instr::Blit { dst, src, size: layout.size }); |
|
| 3762 | + | emit(self, il::Instr::Blit { dst, src, size: il::Val::Imm(layout.size as i64) }); |
|
| 3763 | 3763 | } else { |
|
| 3764 | 3764 | emit(self, il::Instr::Store { |
|
| 3765 | 3765 | typ: ilType(self.low, typ), |
|
| 3766 | 3766 | src, |
|
| 3767 | 3767 | dst: base, |
| 5188 | 5188 | fn emitRetVal(self: *mut FnLowerer, val: il::Val) throws (LowerError) { |
|
| 5189 | 5189 | if let retReg = self.returnReg { |
|
| 5190 | 5190 | let src = try emitValToReg(self, val); |
|
| 5191 | 5191 | let size = retBufSize(self); |
|
| 5192 | 5192 | ||
| 5193 | - | emit(self, il::Instr::Blit { dst: retReg, src, size }); |
|
| 5193 | + | emit(self, il::Instr::Blit { dst: retReg, src, size: il::Val::Imm(size as i64) }); |
|
| 5194 | 5194 | emit(self, il::Instr::Ret { val: il::Val::Reg(retReg) }); |
|
| 5195 | 5195 | } else if isSmallAggregate(*self.fnType.returnType) { |
|
| 5196 | 5196 | let src = try emitValToReg(self, val); |
|
| 5197 | 5197 | let dst = nextReg(self); |
|
| 5198 | 5198 |
| 5356 | 5356 | ||
| 5357 | 5357 | let mergeBlock = try createBlock(self, "cond#merge"); |
|
| 5358 | 5358 | try switchToAndSeal(self, thenBlock); |
|
| 5359 | 5359 | ||
| 5360 | 5360 | let thenVal = try emitValToReg(self, try lowerExpr(self, cond.thenExpr)); |
|
| 5361 | - | emit(self, il::Instr::Blit { dst, src: thenVal, size: layout.size }); |
|
| 5361 | + | emit(self, il::Instr::Blit { dst, src: thenVal, size: il::Val::Imm(layout.size as i64) }); |
|
| 5362 | 5362 | ||
| 5363 | 5363 | try emitJmp(self, mergeBlock); |
|
| 5364 | 5364 | try switchToAndSeal(self, elseBlock); |
|
| 5365 | 5365 | ||
| 5366 | 5366 | let elseVal = try emitValToReg(self, try lowerExpr(self, cond.elseExpr)); |
|
| 5367 | - | emit(self, il::Instr::Blit { dst, src: elseVal, size: layout.size }); |
|
| 5367 | + | emit(self, il::Instr::Blit { dst, src: elseVal, size: il::Val::Imm(layout.size as i64) }); |
|
| 5368 | 5368 | ||
| 5369 | 5369 | try emitJmp(self, mergeBlock); |
|
| 5370 | 5370 | try switchToAndSeal(self, mergeBlock); |
|
| 5371 | 5371 | ||
| 5372 | 5372 | return il::Val::Reg(dst); |
| 5794 | 5794 | let dst = try emitReserveLayout(self, callerLayout); |
|
| 5795 | 5795 | ||
| 5796 | 5796 | emitStoreW64At(self, il::Val::Reg(tagReg), dst, TVAL_TAG_OFFSET); |
|
| 5797 | 5797 | let srcPayload = emitPtrOffset(self, base, RESULT_VAL_OFFSET); |
|
| 5798 | 5798 | let dstPayload = emitPtrOffset(self, dst, RESULT_VAL_OFFSET); |
|
| 5799 | - | emit(self, il::Instr::Blit { dst: dstPayload, src: srcPayload, size: calleeErrSize }); |
|
| 5799 | + | emit(self, il::Instr::Blit { dst: dstPayload, src: srcPayload, size: il::Val::Imm(calleeErrSize as i64) }); |
|
| 5800 | 5800 | ||
| 5801 | 5801 | try emitRetVal(self, il::Val::Reg(dst)); |
|
| 5802 | 5802 | } |
|
| 5803 | 5803 | ||
| 5804 | 5804 | // Switch to the merge block if one was created. If all paths diverged |
| 6230 | 6230 | // mutable copy so that callers that assign through the |
|
| 6231 | 6231 | // resulting pointer do not fault. |
|
| 6232 | 6232 | if isAggregateType(type) { |
|
| 6233 | 6233 | let layout = resolver::getTypeLayout(type); |
|
| 6234 | 6234 | let dst = try emitReserveLayout(self, layout); |
|
| 6235 | - | emit(self, il::Instr::Blit { dst, src, size: layout.size }); |
|
| 6235 | + | emit(self, il::Instr::Blit { dst, src, size: il::Val::Imm(layout.size as i64) }); |
|
| 6236 | 6236 | ||
| 6237 | 6237 | return il::Val::Reg(dst); |
|
| 6238 | 6238 | } |
|
| 6239 | 6239 | return emitRead(self, src, 0, type); |
|
| 6240 | 6240 | } |