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.
Alexis Sellier committed ago 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
        }