rv64: respect aggregate alignment in copies and returns

806b7604d9d82841e819aafa46b8c899ab2873e2cecabdb9ac763a15321c1793
Verified: make -C kernel check; make std-test bin-test with the machine-capable emulator; all pass.
Alexis Sellier committed ago 1 parent 5b8f59d1
kernel/NOTES.md +13 -6
1 1
# Kernel implementation decisions
2 2
3 3
The specification at https://radiant.computer/system/kernel takes precedence
4 4
for fixed call numbers, handle layout, rights, and object behavior. These notes
5 -
record the contracts established through step 6 of the 22-step plan.
5 +
record the contracts established through step 7 of the 22-step plan.
6 6
7 7
## Source and trust boundary
8 8
9 9
- Kernel mechanisms use freestanding Radiance; RAS owns machine entry, register
10 10
  state, atomics, and MMIO. Hosted checks exercise the same mechanism modules.
77 77
- Events cannot cross domains; the installed Events handle cannot be dropped.
78 78
  Interrupt authority cannot be granted and moves exclusively by transfer.
79 79
- Dropping a handle removes authority to invoke operations through that name
80 80
  and releases its object reference.
81 81
82 +
## Aligned aggregate code generation
83 +
84 +
- Aggregate copies retain their proven alignment. Small aggregate register
85 +
  returns load exactly their layout bytes with valid alignment. This does not
86 +
  change record layout or relax architectural alignment requirements.
87 +
- Machine execution uses the current machine-capable sibling emulator:
88 +
  FDT boot registers, independent hart state, shared coherent RAM, WFI wakeup,
89 +
  CLINT, PLIC, UART, and atomics. Explicit M-mode finish writes end checks;
90 +
  they are not a domain-exit operation. The boot checks for this boundary leave secondary harts idle.
91 +
82 92
## Validation
83 93
84 94
Use the current machine-capable sibling emulator. Set `RAD_EMULATOR`, pass
85 95
`EMU` to the kernel Make invocation, or put `emulator` on PATH. The kernel build
86 96
checks compiler dependencies. From the repository root, run:
87 97
88 98
```sh
89 99
make -C kernel check
100 +
make std-test bin-test
90 101
```
91 102
92 -
Exercise attenuation, self-grants, failed transfers with an intact source, Events locality, Interrupt exclusivity, and stale aliases.
93 -
94 -
The entry probe uses explicit M-mode success/fault finish writes; secondary
95 -
harts idle. This checks machine entry, not user-domain execution. Finish writes
96 -
are a check protocol, not a domain-exit operation.
103 +
Exercise aggregate-alignment machine regression and firmware boot on 1 and 8 harts, with secondary harts idle.
lib/std/arch/rv64.rad +1 -1
89 89
export constant INSTR_SIZE: i32 = 4;
90 90
/// Stack alignment requirement in bytes.
91 91
export constant STACK_ALIGNMENT: i32 = 16;
92 92
93 93
/// Minimum blit size (in bytes) to use a loop instead of inline copy.
94 -
/// Blits below this threshold are fully unrolled as LD/SD pairs.
94 +
/// Blits below this threshold are fully unrolled as naturally aligned pairs.
95 95
export constant BLIT_LOOP_THRESHOLD: i32 = 256;
96 96
97 97
/////////////////////////
98 98
// Codegen Allocation  //
99 99
/////////////////////////
lib/std/arch/rv64/isel.rad +38 -90
450 450
                },
451 451
                else =>
452 452
                    panic "selectInstr: invalid reserve operand",
453 453
            }
454 454
        },
455 -
        case il::Instr::Blit { dst, src, size } => {
455 +
        case il::Instr::Blit { dst, src, size, alignment } => {
456 456
            let case il::Val::Imm(staticSize) = size
457 457
                else panic "selectInstr: blit requires immediate size";
458 -
458 +
            if staticSize == 0 {
459 +
                return;
460 +
            }
459 461
            let bothSpilled = regalloc::spill::isSpilled(&s.ralloc.spill, dst)
460 462
                and regalloc::spill::isSpilled(&s.ralloc.spill, src);
461 463
462 -
            // When both are spilled, offsets must fit 12-bit immediates
463 -
            // since we can't advance base registers (they live in spill
464 -
            // slots, not real registers we can mutate).
465 -
            assert not (bothSpilled and staticSize as i32 > super::MAX_IMM), "selectInstr: blit both-spilled with large size";
466 -
467 -
            // Resolve dst/src base registers.
464 +
            // A spilled base uses SCRATCH2; SCRATCH1 carries each copied
465 +
            // value. If both bases spill, reload the source into SCRATCH1
466 +
            // before each load, keeping the destination in SCRATCH2.
468 467
            let mut rdst = super::SCRATCH2;
469 468
            let mut rsrc = super::SCRATCH1;
470 469
            let mut srcReload: ?i32 = nil;
471 -
472 470
            if bothSpilled {
473 471
                let dstSlot = regalloc::spill::spillSlot(&s.ralloc.spill, dst) else {
474 472
                    panic "selectInstr: blit dst not spilled";
475 473
                };
476 474
                let srcSlot = regalloc::spill::spillSlot(&s.ralloc.spill, src) else {
477 475
                    panic "selectInstr: blit src not spilled";
478 476
                };
479 -
                emit::emitLd(s.e, super::SCRATCH2, spillBase(s), spillOffset(s, dstSlot));
477 +
                emit::emitLd(s.e, rdst, spillBase(s), spillOffset(s, dstSlot));
480 478
                set srcReload = spillOffset(s, srcSlot);
481 479
            } else {
482 480
                set rdst = getSrcReg(s, dst, super::SCRATCH2);
483 481
                set rsrc = getSrcReg(s, src, super::SCRATCH2);
484 482
            }
485 -
            let mut offset: i32 = 0;
486 -
            let mut remaining = staticSize as i32;
487 -
488 -
            // For large blits where both pointers are in real registers,
489 -
            // use an inline loop instead of unrolled LD/SD pairs.
490 -
            let dwordBytes = remaining & ~(super::DWORD_SIZE - 1);
483 +
            let mut remaining = staticSize as u32;
484 +
            let typ = il::copyType(remaining, alignment);
485 +
            let width = il::typeSize(typ);
486 +
            let mut advanced: i32 = 0;
491 487
            let canLoop = not bothSpilled
492 488
                and *rsrc <> *super::SCRATCH1 and *rsrc <> *super::SCRATCH2
493 489
                and *rdst <> *super::SCRATCH1 and *rdst <> *super::SCRATCH2;
490 +
            let loopBytes = remaining & ~(width - 1);
494 491
495 -
            if canLoop and dwordBytes >= super::BLIT_LOOP_THRESHOLD {
496 -
                emit::emitAddImm(s.e, super::SCRATCH1, rsrc, dwordBytes);
497 -
492 +
            // Keep wide aligned copies fast, but use the proven width for
493 +
            // both the loop and its stride (including byte/halfword copies).
494 +
            if canLoop and loopBytes >= super::BLIT_LOOP_THRESHOLD as u32 {
495 +
                emit::emitAddImm(s.e, super::SCRATCH1, rsrc, loopBytes as i32);
498 496
                let loopStart = s.e.codeLen;
499 -
500 -
                emit::emitLd(s.e, super::SCRATCH2, rsrc, 0);
501 -
                emit::emitSd(s.e, super::SCRATCH2, rdst, 0);
502 -
                emit::emit(s.e, encode::addi(rsrc, rsrc, super::DWORD_SIZE));
503 -
497 +
                emit::emitLoad(s.e, super::SCRATCH2, rsrc, 0, typ);
498 +
                emit::emitStore(s.e, super::SCRATCH2, rdst, 0, typ);
499 +
                emit::emit(s.e, encode::addi(rsrc, rsrc, width as i32));
504 500
                if *rdst <> *rsrc {
505 -
                    emit::emit(s.e, encode::addi(rdst, rdst, super::DWORD_SIZE));
501 +
                    emit::emit(s.e, encode::addi(rdst, rdst, width as i32));
506 502
                }
507 503
                let brOff = (loopStart as i32 - s.e.codeLen as i32) * super::INSTR_SIZE;
508 -
509 504
                emit::emit(s.e, encode::bne(rsrc, super::SCRATCH1, brOff));
510 -
                set remaining -= dwordBytes;
505 +
                set remaining -= loopBytes;
506 +
                set advanced = loopBytes as i32;
511 507
            }
512 508
513 -
            // Copy remaining: 8 bytes, then 4 bytes, then 1 byte at a time.
514 -
            // Before each load/store pair, check whether the offset is
515 -
            // about to exceed the 12-bit signed immediate range. When
516 -
            // it does, advance the base registers by the accumulated
517 -
            // offset and reset to zero.
518 -
            while remaining >= super::DWORD_SIZE {
519 -
                if offset > super::MAX_IMM - super::DWORD_SIZE {
520 -
                    emit::emitAddImm(s.e, rsrc, rsrc, offset);
521 -
                    if *rdst <> *rsrc {
522 -
                        emit::emitAddImm(s.e, rdst, rdst, offset);
523 -
                    }
524 -
                    set offset = 0;
525 -
                }
526 -
                if let off = srcReload {
527 -
                    emit::emitLd(s.e, super::SCRATCH1, spillBase(s), off);
528 -
                    emit::emitLd(s.e, super::SCRATCH1, super::SCRATCH1, offset);
529 -
                } else {
530 -
                    emit::emitLd(s.e, super::SCRATCH1, rsrc, offset);
531 -
                }
532 -
                emit::emitSd(s.e, super::SCRATCH1, rdst, offset);
533 -
                set offset += super::DWORD_SIZE;
534 -
                set remaining -= super::DWORD_SIZE;
535 -
            }
536 -
            if remaining >= super::WORD_SIZE {
537 -
                if offset > super::MAX_IMM - super::WORD_SIZE {
538 -
                    emit::emitAddImm(s.e, rsrc, rsrc, offset);
539 -
                    if *rdst <> *rsrc {
540 -
                        emit::emitAddImm(s.e, rdst, rdst, offset);
541 -
                    }
542 -
                    set offset = 0;
543 -
                }
544 -
                if let off = srcReload {
545 -
                    emit::emitLd(s.e, super::SCRATCH1, spillBase(s), off);
546 -
                    emit::emitLw(s.e, super::SCRATCH1, super::SCRATCH1, offset);
547 -
                } else {
548 -
                    emit::emitLw(s.e, super::SCRATCH1, rsrc, offset);
549 -
                }
550 -
                emit::emitSw(s.e, super::SCRATCH1, rdst, offset);
551 -
                set offset += super::WORD_SIZE;
552 -
                set remaining -= super::WORD_SIZE;
553 -
            }
509 +
            // The emitter's dedicated address scratch handles large offsets
510 +
            // without clobbering either base or the copied value. This also
511 +
            // permits large copies when both pointers spill.
512 +
            let mut offset: i32 = 0;
554 513
            while remaining > 0 {
555 -
                if offset > super::MAX_IMM - 1 {
556 -
                    emit::emitAddImm(s.e, rsrc, rsrc, offset);
557 -
                    if *rdst <> *rsrc {
558 -
                        emit::emitAddImm(s.e, rdst, rdst, offset);
559 -
                    }
560 -
                    set offset = 0;
561 -
                }
514 +
                let partType = il::copyType(remaining, alignment);
515 +
                let partSize = il::typeSize(partType);
562 516
                if let off = srcReload {
563 517
                    emit::emitLd(s.e, super::SCRATCH1, spillBase(s), off);
564 -
                    emit::emitLb(s.e, super::SCRATCH1, super::SCRATCH1, offset);
565 -
                } else {
566 -
                    emit::emitLb(s.e, super::SCRATCH1, rsrc, offset);
567 518
                }
568 -
                emit::emitSb(s.e, super::SCRATCH1, rdst, offset);
569 -
                set offset += 1;
570 -
                set remaining -= 1;
519 +
                emit::emitLoad(s.e, super::SCRATCH1, rsrc, offset, partType);
520 +
                emit::emitStore(s.e, super::SCRATCH1, rdst, offset, partType);
521 +
                set offset += partSize as i32;
522 +
                set remaining -= partSize;
571 523
            }
572 -
            // Restore base registers if they were advanced (never happens
573 -
            // in the both-spilled case since size <= MAX_IMM).
574 -
            if not bothSpilled {
575 -
                let advanced = staticSize as i32 - offset;
576 -
                if advanced <> 0 {
577 -
                    emit::emitAddImm(s.e, rsrc, rsrc, 0 - advanced);
578 -
                    if *rdst <> *rsrc {
579 -
                        emit::emitAddImm(s.e, rdst, rdst, 0 - advanced);
580 -
                    }
524 +
            // Loop bases can be live after the copy (including a self-copy).
525 +
            if advanced <> 0 {
526 +
                emit::emitAddImm(s.e, rsrc, rsrc, 0 - advanced);
527 +
                if *rdst <> *rsrc {
528 +
                    emit::emitAddImm(s.e, rdst, rdst, 0 - advanced);
581 529
                }
582 530
            }
583 531
        },
584 532
        case il::Instr::Zext { typ, dst, val } => {
585 533
            let rd = getDstReg(s, dst, super::SCRATCH1);
lib/std/lang/il.rad +22 -3
123 123
        case Type::W32 => return 4,
124 124
        case Type::W64 => return 8,
125 125
    }
126 126
}
127 127
128 +
/// Widest naturally aligned load/store that fits a nonempty memory region.
129 +
/// `alignment` is a proven common power-of-two alignment of the addresses.
130 +
export fn copyType(size: u32, alignment: u32) -> Type {
131 +
    assert size > 0 and alignment > 0 and (alignment & (alignment - 1)) == 0;
132 +
    if size >= 8 and alignment >= 8 {
133 +
        return Type::W64;
134 +
    }
135 +
    if size >= 4 and alignment >= 4 {
136 +
        return Type::W32;
137 +
    }
138 +
    if size >= 2 and alignment >= 2 {
139 +
        return Type::W16;
140 +
    }
141 +
    return Type::W8;
142 +
}
143 +
128 144
/// SSA register reference.
129 145
export record Reg: Copy { n: u32 }
130 146
131 147
/// Instruction value.
132 148
export union Val: Copy {
207 223
        /// Destination address.
208 224
        dst: Reg,
209 225
        /// Byte offset from the base address.
210 226
        offset: i32
211 227
    },
212 -
    /// Copy memory region: `blit %dst %src <size>;`
228 +
    /// Copy memory region: `blit %dst %src <size> <alignment>;`
213 229
    /// Size can be an immediate or a register (eg. for generics).
214 230
    Blit {
215 231
        /// Destination address.
216 232
        dst: Reg,
217 233
        /// Source address.
218 234
        src: Reg,
219 235
        /// Size to copy in bytes.
220 -
        size: Val
236 +
        size: Val,
237 +
        /// Proven minimum alignment shared by source and destination.
238 +
        /// Must be a nonzero power of two; size need not be its multiple.
239 +
        alignment: u32,
221 240
    },
222 241
    /// Copy a value into a register: `copy %dst <val>;`.
223 242
    Copy { dst: Reg, val: Val },
224 243
225 244
    /////////////////////
435 454
        case Instr::Sload { src, .. } => f(src, ctx),
436 455
        case Instr::Store { src, dst, .. } => {
437 456
            withReg(src, f, ctx);
438 457
            f(dst, ctx);
439 458
        },
440 -
        case Instr::Blit { dst, src, size } => {
459 +
        case Instr::Blit { dst, src, size, .. } => {
441 460
            f(dst, ctx);
442 461
            f(src, ctx);
443 462
            withReg(size, f, ctx);
444 463
        },
445 464
        case Instr::Copy { val, .. } =>
lib/std/lang/il/printer.rad +3 -1
216 216
            write(out, " ");
217 217
            writeReg(out, dst);
218 218
            write(out, " ");
219 219
            writeI32(out, offset);
220 220
        }
221 -
        case super::Instr::Blit { dst, src, size } => {
221 +
        case super::Instr::Blit { dst, src, size, alignment } => {
222 222
            write(out, "blit ");
223 223
            writeReg(out, dst);
224 224
            write(out, " ");
225 225
            writeReg(out, src);
226 226
            write(out, " ");
227 227
            writeVal(out, size);
228 +
            write(out, " ");
229 +
            writeU32(out, alignment);
228 230
        }
229 231
        case super::Instr::Copy { dst, val } => {
230 232
            write(out, "copy ");
231 233
            writeReg(out, dst);
232 234
            write(out, " ");
lib/std/lang/lower.rad +48 -12
4148 4148
    if isAggregateType(typ) {
4149 4149
        let dst = emitPtrOffset(self, base, offset);
4150 4150
        let src = emitValToReg(self, src);
4151 4151
        let layout = resolver::getTypeLayout(typ);
4152 4152
4153 -
        emit(self, il::Instr::Blit { dst, src, size: il::Val::Imm(layout.size as i64) });
4153 +
        emit(self, il::Instr::Blit {
4154 +
            dst, src, size: il::Val::Imm(layout.size as i64), alignment: layout.alignment,
4155 +
        });
4154 4156
    } else {
4155 4157
        emit(self, il::Instr::Store {
4156 4158
            typ: ilType(self.low, typ),
4157 4159
            src,
4158 4160
            dst: base,
5705 5707
fn lowerContinue(self: *mut FnLowerer) throws (LowerError) {
5706 5708
    let block = try getOrCreateContinueBlock(self);
5707 5709
    try emitJmp(self, block);
5708 5710
}
5709 5711
5712 +
/// Pack a small aggregate into its little-endian return register without
5713 +
/// reading beyond its layout or assuming pointer-sized alignment.
5714 +
fn emitSmallAggregate(self: *mut FnLowerer, src: il::Reg, layout: resolver::Layout) -> il::Val {
5715 +
    let mut value = il::Val::Imm(0);
5716 +
    let mut offset: u32 = 0;
5717 +
    while offset < layout.size {
5718 +
        let typ = il::copyType(layout.size - offset, layout.alignment);
5719 +
        let dst = nextReg(self);
5720 +
        emit(self, il::Instr::Load { typ, dst, src, offset: offset as i32 });
5721 +
        if offset == 0 {
5722 +
            set value = il::Val::Reg(dst);
5723 +
        } else {
5724 +
            let shifted = emitTypedBinOp(
5725 +
                self, il::BinOp::Shl, il::Type::W64, il::Val::Reg(dst), il::Val::Imm((offset * 8) as i64)
5726 +
            );
5727 +
            set value = emitTypedBinOp(self, il::BinOp::Or, il::Type::W64, value, shifted);
5728 +
        }
5729 +
        set offset += il::typeSize(typ);
5730 +
    }
5731 +
    return value;
5732 +
}
5733 +
5710 5734
/// Emit a return, blitting into the caller's return buffer if needed.
5711 5735
///
5712 5736
/// When the function has a return buffer parameter, the value is blitted
5713 5737
/// into the buffer and the buffer pointer is returned. Otherwise, the value is
5714 5738
/// returned directly.
5715 5739
fn emitRetVal(self: *mut FnLowerer, val: il::Val) throws (LowerError) {
5716 5740
    if let retReg = self.returnReg {
5717 5741
        let src = emitValToReg(self, val);
5718 -
        let size = resolver::getResultLayout(*self.fnType.returnType, self.fnType.throwList).size
5742 +
        let layout = resolver::getResultLayout(*self.fnType.returnType, self.fnType.throwList)
5719 5743
            if self.fnType.throwList.len > 0
5720 -
            else resolver::getTypeLayout(*self.fnType.returnType).size;
5744 +
            else resolver::getTypeLayout(*self.fnType.returnType);
5721 5745
5722 -
        emit(self, il::Instr::Blit { dst: retReg, src, size: il::Val::Imm(size as i64) });
5746 +
        emit(self, il::Instr::Blit {
5747 +
            dst: retReg, src, size: il::Val::Imm(layout.size as i64), alignment: layout.alignment,
5748 +
        });
5723 5749
        emit(self, il::Instr::Ret { val: il::Val::Reg(retReg) });
5724 5750
    } else if isSmallAggregate(*self.fnType.returnType) {
5725 5751
        let src = emitValToReg(self, val);
5726 -
        let dst = nextReg(self);
5727 -
5728 -
        emit(self, il::Instr::Load { typ: il::Type::W64, dst, src, offset: 0 });
5729 -
        emit(self, il::Instr::Ret { val: il::Val::Reg(dst) });
5752 +
        let layout = resolver::getTypeLayout(*self.fnType.returnType);
5753 +
        let packed = emitSmallAggregate(self, src, layout);
5754 +
        emit(self, il::Instr::Ret { val: packed });
5730 5755
    } else {
5731 5756
        emit(self, il::Instr::Ret { val });
5732 5757
    }
5733 5758
}
5734 5759
5872 5897
5873 5898
        let mergeBlock = try createBlock(self, "cond#merge");
5874 5899
        try switchToAndSeal(self, thenBlock);
5875 5900
5876 5901
        let thenVal = emitValToReg(self, try lowerExpr(self, cond.thenExpr));
5877 -
        emit(self, il::Instr::Blit { dst, src: thenVal, size: il::Val::Imm(layout.size as i64) });
5902 +
        emit(self, il::Instr::Blit {
5903 +
            dst, src: thenVal, size: il::Val::Imm(layout.size as i64), alignment: layout.alignment,
5904 +
        });
5878 5905
5879 5906
        try emitJmp(self, mergeBlock);
5880 5907
        try switchToAndSeal(self, elseBlock);
5881 5908
5882 5909
        let elseVal = emitValToReg(self, try lowerExpr(self, cond.elseExpr));
5883 -
        emit(self, il::Instr::Blit { dst, src: elseVal, size: il::Val::Imm(layout.size as i64) });
5910 +
        emit(self, il::Instr::Blit {
5911 +
            dst, src: elseVal, size: il::Val::Imm(layout.size as i64), alignment: layout.alignment,
5912 +
        });
5884 5913
5885 5914
        try emitJmp(self, mergeBlock);
5886 5915
        try switchToAndSeal(self, mergeBlock);
5887 5916
5888 5917
        return il::Val::Reg(dst);
6322 6351
        let dst = emitReserveLayout(self, callerLayout);
6323 6352
6324 6353
        emitStoreW64At(self, il::Val::Reg(tagReg), dst, TVAL_TAG_OFFSET);
6325 6354
        let srcPayload = emitPtrOffset(self, base, RESULT_VAL_OFFSET);
6326 6355
        let dstPayload = emitPtrOffset(self, dst, RESULT_VAL_OFFSET);
6327 -
        emit(self, il::Instr::Blit { dst: dstPayload, src: srcPayload, size: il::Val::Imm(calleeErrSize as i64) });
6356 +
        // Both result buffers have pointer alignment and their payload starts
6357 +
        // after a pointer-sized tag, regardless of the active error's layout.
6358 +
        emit(self, il::Instr::Blit {
6359 +
            dst: dstPayload, src: srcPayload, size: il::Val::Imm(calleeErrSize as i64),
6360 +
            alignment: resolver::PTR_SIZE,
6361 +
        });
6328 6362
6329 6363
        try emitRetVal(self, il::Val::Reg(dst));
6330 6364
    }
6331 6365
6332 6366
    // Switch to the merge block if one was created. If all paths diverged
7108 7142
            // mutable copy so that callers that assign through the
7109 7143
            // resulting pointer do not fault.
7110 7144
            if isAggregateType(type) {
7111 7145
                let layout = resolver::getTypeLayout(type);
7112 7146
                let dst = emitReserveLayout(self, layout);
7113 -
                emit(self, il::Instr::Blit { dst, src, size: il::Val::Imm(layout.size as i64) });
7147 +
                emit(self, il::Instr::Blit {
7148 +
                    dst, src, size: il::Val::Imm(layout.size as i64), alignment: layout.alignment,
7149 +
                });
7114 7150
7115 7151
                return il::Val::Reg(dst);
7116 7152
            }
7117 7153
            return emitRead(self, src, 0, type);
7118 7154
        }
test/tests/aggregate.alignment.rad added +160 -0
1 +
//! Machine-only regression: build with aggregate.alignment.start.ras and run
2 +
//! with `emulator -machine`. Success writes 0x5555 to the finish device.
3 +
//! Typed aggregates may have alignment 1, 2 or 4 even when larger than a word.
4 +
5 +
record Bytes: Copy { data: [u8; 2057] }
6 +
record ByteBox: Copy { anchor: u64, pad: u8, value: Bytes }
7 +
record B3: Copy { a: u8, b: u8, c: u8 }
8 +
record SmallByteBox: Copy { anchor: u64, pad: u8, value: B3 }
9 +
record H3: Copy { a: u16, b: u16, c: u16 }
10 +
record SmallHalfBox: Copy { anchor: u64, pad: u16, value: H3 }
11 +
record Halves: Copy { data: [u16; 129] }
12 +
record HalfBox: Copy { anchor: u64, pad: u16, value: Halves }
13 +
record W2: Copy { a: u32, b: u32 }
14 +
record SmallWordBox: Copy { anchor: u64, pad: u32, value: W2 }
15 +
record Hart: Copy { a: u32, b: u32, c: u32, d: u32 }
16 +
record HartBox: Copy { anchor: u64, pad: u32, harts: [Hart; 2] }
17 +
union Short: Copy { Some(H3), None }
18 +
19 +
fn byteReturn(src: *B3) -> B3 { return *src; }
20 +
fn halfReturn(src: *H3) -> H3 { return *src; }
21 +
fn wordReturn(src: *W2, choose: bool) -> W2 {
22 +
    return *src if choose else W2 { a: 9, b: 10 };
23 +
}
24 +
fn shortReturn(src: *H3) -> Short { return Short::Some(*src); }
25 +
fn optionalReturn(src: *H3) -> ?H3 { return *src; }
26 +
fn bytesReturn(src: *Bytes, choose: bool) -> Bytes {
27 +
    // Both sides must copy into the conditional temporary before returning.
28 +
    return *src if choose else *src;
29 +
}
30 +
fn halvesReturn(src: *Halves) -> Halves { return *src; }
31 +
fn hartReturn(src: *Hart) -> Hart { return *src; }
32 +
fn sliceReturn(left: *[Hart], right: *[Hart], choose: bool) -> *[Hart] {
33 +
    return left if choose else right;
34 +
}
35 +
fn fallible(src: *Bytes, value: *H3, fail: bool) -> H3 throws (Bytes) {
36 +
    if fail { throw *src; }
37 +
    return *value;
38 +
}
39 +
fn propagate(src: *Bytes, value: *H3, fail: bool) -> H3 throws (Bytes) {
40 +
    return try fallible(src, value, fail);
41 +
}
42 +
43 +
// Keep more values live than the 23 allocatable registers. Source and
44 +
// destination remain live longest, including across this >2047-byte copy.
45 +
fn spilledCopy(dst: *mut Bytes, src: *Bytes, values: *[u32]) {
46 +
    let v0 = values[0];
47 +
    let v1 = values[1];
48 +
    let v2 = values[2];
49 +
    let v3 = values[3];
50 +
    let v4 = values[4];
51 +
    let v5 = values[5];
52 +
    let v6 = values[6];
53 +
    let v7 = values[7];
54 +
    let v8 = values[8];
55 +
    let v9 = values[9];
56 +
    let v10 = values[10];
57 +
    let v11 = values[11];
58 +
    let v12 = values[12];
59 +
    let v13 = values[13];
60 +
    let v14 = values[14];
61 +
    let v15 = values[15];
62 +
    let v16 = values[16];
63 +
    let v17 = values[17];
64 +
    let v18 = values[18];
65 +
    let v19 = values[19];
66 +
    let v20 = values[20];
67 +
    let v21 = values[21];
68 +
    let v22 = values[22];
69 +
    let v23 = values[23];
70 +
    set *dst = *src;
71 +
    assert v0 + v1 + v2 + v3 + v4 + v5 + v6 + v7 + v8 + v9 + v10 + v11
72 +
        + v12 + v13 + v14 + v15 + v16 + v17 + v18 + v19 + v20 + v21 + v22 + v23 == 276;
73 +
    for i in 0..2057 {
74 +
        assert dst.data[i] == src.data[i];
75 +
    }
76 +
}
77 +
78 +
fn smallCopies() {
79 +
    // The enclosing locals are aligned, but the fields deliberately aren't
80 +
    // aligned to eight. Returning these must neither overread nor issue LD.
81 +
    let mut bytes: SmallByteBox = undefined;
82 +
    let mut halves: SmallHalfBox = undefined;
83 +
    let mut words: SmallWordBox = undefined;
84 +
    set bytes.pad = 71;
85 +
    set halves.pad = 72;
86 +
    set words.pad = 73;
87 +
    set bytes.value = B3 { a: 0x81, b: 0xFE, c: 0xA3 };
88 +
    set halves.value = H3 { a: 0x8123, b: 0xFEDC, c: 0xA345 };
89 +
    set words.value = W2 { a: 0x81234567, b: 0xFEDCBA98 };
90 +
    let b = byteReturn(&bytes.value);
91 +
    let h = halfReturn(&halves.value);
92 +
    let w = wordReturn(&words.value, true);
93 +
    assert b.a == 0x81 and b.b == 0xFE and b.c == 0xA3;
94 +
    assert h.a == 0x8123 and h.b == 0xFEDC and h.c == 0xA345;
95 +
    assert w.a == 0x81234567 and w.b == 0xFEDCBA98;
96 +
    set words.value = wordReturn(&words.value, false);
97 +
    assert words.value.a == 9 and words.value.b == 10;
98 +
    let wrapped = shortReturn(&halves.value);
99 +
    match wrapped {
100 +
        case Short::Some(value) => { assert value == h; },
101 +
        case Short::None => panic "lost halfword payload",
102 +
    }
103 +
    let present = optionalReturn(&halves.value) else panic "lost optional payload";
104 +
    assert present == h;
105 +
    assert bytes.pad == 71 and halves.pad == 72 and words.pad == 73;
106 +
}
107 +
108 +
fn largeCopies() {
109 +
    let mut source: ByteBox = undefined;
110 +
    let mut target: ByteBox = undefined;
111 +
    set source.pad = 81;
112 +
    set target.pad = 82;
113 +
    for i in 0..2057 { set source.value.data[i] = i as u8; }
114 +
    set target.value = bytesReturn(&source.value, true);
115 +
    set target.value = bytesReturn(&target.value, false);
116 +
    let mut values: [u32; 24] = undefined;
117 +
    for i in 0..24 { set values[i] = i as u32; }
118 +
    spilledCopy(&mut target.value, &source.value, &values[..]);
119 +
    assert source.pad == 81 and target.pad == 82;
120 +
    set target.value.data[0] = 255;
121 +
    assert source.value.data[0] == 0;
122 +
123 +
    let mut halves: HalfBox = undefined;
124 +
    let mut copied: HalfBox = undefined;
125 +
    set copied.pad = 83;
126 +
    for i in 0..129 { set halves.value.data[i] = (i + 0x8000) as u16; }
127 +
    set copied.value = halvesReturn(&halves.value);
128 +
    for i in 0..129 { assert copied.value.data[i] == halves.value.data[i]; }
129 +
    assert copied.pad == 83;
130 +
131 +
    let value = H3 { a: 11, b: 22, c: 33 };
132 +
    let success = try! propagate(&source.value, &value, false);
133 +
    assert success == value;
134 +
    let mut caught = false;
135 +
    let _ = try propagate(&source.value, &value, true) catch error {
136 +
        assert error.data[0] == 0 and error.data[1023] == 255 and error.data[2056] == 8;
137 +
        set caught = true;
138 +
    };
139 +
    assert caught;
140 +
}
141 +
142 +
fn hartCopies() {
143 +
    let mut platform: HartBox = undefined;
144 +
    set platform.pad = 91;
145 +
    set platform.harts[0] = Hart { a: 1, b: 2, c: 3, d: 4 };
146 +
    set platform.harts[1] = hartReturn(&platform.harts[0]);
147 +
    let first = sliceReturn(&platform.harts[..1], &platform.harts[1..], true);
148 +
    let second = sliceReturn(&platform.harts[..1], &platform.harts[1..], false);
149 +
    assert first.len == 1 and second.len == 1;
150 +
    assert first[0] == second[0] and second[0].d == 4;
151 +
    set platform.harts[1].d = 99;
152 +
    assert platform.harts[0].d == 4 and platform.pad == 91;
153 +
}
154 +
155 +
@default fn main() -> i32 {
156 +
    smallCopies();
157 +
    largeCopies();
158 +
    hartCopies();
159 +
    return 0;
160 +
}
test/tests/aggregate.alignment.start.ras added +15 -0
1 +
.text;
2 +
	la     %t0    @fail;
3 +
	csrw   mtvec  %t0;
4 +
	call   @"::default";
5 +
	bnez   %a0    @fail;
6 +
	li     %t0    0x10001000;
7 +
	li     %t1    0x5555;
8 +
	sw     %t1    0(%t0);
9 +
@halt
10 +
	j      @halt;
11 +
@fail
12 +
	li     %t0    0x10001000;
13 +
	li     %t1    0x00013333;
14 +
	sw     %t1    0(%t0);
15 +
	j      @halt;
test/tests/array.assign.ril +1 -1
10 10
    store w32 8 %1 0;
11 11
    store w32 9 %1 4;
12 12
    store w32 7 %1 8;
13 13
    store w32 6 %1 12;
14 14
    store w32 0 %1 16;
15 -
    blit %1 %0 20;
15 +
    blit %1 %0 20 4;
16 16
    sload w32 %2 %1 0;
17 17
    mul w64 %3 3 4;
18 18
    add w64 %4 %1 %3;
19 19
    sload w32 %5 %4 0;
20 20
    add w32 %6 %2 %5;
test/tests/array.nested.ril +3 -3
3 3
    reserve %0 24 4;
4 4
    reserve %1 12 4;
5 5
    store w32 1 %1 0;
6 6
    store w32 2 %1 4;
7 7
    store w32 3 %1 8;
8 -
    blit %0 %1 12;
8 +
    blit %0 %1 12 4;
9 9
    reserve %2 12 4;
10 10
    store w32 4 %2 0;
11 11
    store w32 5 %2 4;
12 12
    store w32 6 %2 8;
13 13
    add w64 %3 %0 12;
14 -
    blit %3 %2 12;
14 +
    blit %3 %2 12 4;
15 15
    reserve %4 24 4;
16 -
    blit %4 %0 24;
16 +
    blit %4 %0 24 4;
17 17
    sload w32 %5 %0 0;
18 18
    mul w64 %6 1 4;
19 19
    add w64 %7 %4 %6;
20 20
    sload w32 %8 %7 0;
21 21
    add w32 %9 %5 %8;
test/tests/array.slice.full.ril +1 -1
2 2
  @entry0
3 3
    reserve %2 16 8;
4 4
    store w64 %1 %2 0;
5 5
    store w32 4 %2 8;
6 6
    store w32 4 %2 12;
7 -
    blit %0 %2 16;
7 +
    blit %0 %2 16 8;
8 8
    ret %0;
9 9
}
test/tests/array.slice.openend.ril +1 -1
10 10
    sub w32 %5 4 %2;
11 11
    reserve %6 16 8;
12 12
    store w64 %4 %6 0;
13 13
    store w32 %5 %6 8;
14 14
    store w32 %5 %6 12;
15 -
    blit %0 %6 16;
15 +
    blit %0 %6 16 8;
16 16
    ret %0;
17 17
}
test/tests/array.slice.openstart.ril +1 -1
7 7
  @guard#pass2
8 8
    reserve %3 16 8;
9 9
    store w64 %1 %3 0;
10 10
    store w32 %2 %3 8;
11 11
    store w32 %2 %3 12;
12 -
    blit %0 %3 16;
12 +
    blit %0 %3 16 8;
13 13
    ret %0;
14 14
}
test/tests/coercion.implicit.ril +4 -4
2 2
  @entry0
3 3
    reserve %0 8 4;
4 4
    store w8 1 %0 0;
5 5
    store w32 42 %0 4;
6 6
    reserve %1 8 4;
7 -
    blit %1 %0 8;
7 +
    blit %1 %0 8 4;
8 8
    load w8 %2 %1 0;
9 9
    br.ne w32 %2 0 @success1 @else2;
10 10
  @success1
11 11
    sload w32 %3 %1 4;
12 12
    jmp @merge3;
20 20
  @entry0
21 21
    reserve %1 8 4;
22 22
    store w8 1 %1 0;
23 23
    store w32 %0 %1 4;
24 24
    reserve %2 8 4;
25 -
    blit %2 %1 8;
25 +
    blit %2 %1 8 4;
26 26
    reserve %3 8 4;
27 -
    blit %3 %2 8;
27 +
    blit %3 %2 8 4;
28 28
    load w8 %4 %3 0;
29 29
    br.ne w32 %4 0 @success1 @else2;
30 30
  @success1
31 31
    sload w32 %5 %3 4;
32 32
    jmp @merge3;
39 39
fn w64 $optionalLiftReturn(w64 %0, w32 %1) {
40 40
  @entry0
41 41
    reserve %2 8 4;
42 42
    store w8 1 %2 0;
43 43
    store w32 %1 %2 4;
44 -
    blit %0 %2 8;
44 +
    blit %0 %2 8 4;
45 45
    ret %0;
46 46
}
47 47
48 48
fn w32 $numericU8ToU32(w8 %0) {
49 49
  @entry0
test/tests/cond.iflet.mut.ril +1 -1
1 1
fn w32 $ifLetMut(w64 %0) {
2 2
  @entry0
3 3
    reserve %1 8 4;
4 -
    blit %1 %0 8;
4 +
    blit %1 %0 8 4;
5 5
    load w8 %2 %1 0;
6 6
    br.ne w32 %2 0 @then1 @else2;
7 7
  @then1
8 8
    sload w32 %3 %1 4;
9 9
    add w32 %4 %3 1;
test/tests/cond.iflet.noelse.ril +1 -1
1 1
fn w32 $ifLetNoElse(w64 %0) {
2 2
  @entry0
3 3
    reserve %1 8 4;
4 -
    blit %1 %0 8;
4 +
    blit %1 %0 8 4;
5 5
    load w8 %2 %1 0;
6 6
    br.ne w32 %2 0 @then1 @else2;
7 7
  @then1
8 8
    sload w32 %3 %1 4;
9 9
    ret 1;
test/tests/cond.iflet.optional.value.ril +1 -1
1 1
fn w32 $ifLetOptionalValue(w64 %0) {
2 2
  @entry0
3 3
    reserve %1 8 4;
4 -
    blit %1 %0 8;
4 +
    blit %1 %0 8 4;
5 5
    load w8 %2 %1 0;
6 6
    br.ne w32 %2 0 @then1 @else2;
7 7
  @then1
8 8
    sload w32 %3 %1 4;
9 9
    ret %3;
test/tests/cond.letelse.mut.ril +1 -1
1 1
fn w32 $letMutElse(w64 %0) {
2 2
  @entry0
3 3
    reserve %1 8 4;
4 -
    blit %1 %0 8;
4 +
    blit %1 %0 8 4;
5 5
    load w8 %2 %1 0;
6 6
    br.ne w32 %2 0 @success1 @else2;
7 7
  @success1
8 8
    sload w32 %3 %1 4;
9 9
    jmp @merge3;
test/tests/const.record.mutcopy.ril +3 -3
8 8
9 9
fn w64 $test(w64 %0) {
10 10
  @entry0
11 11
    copy %1 $SCRATCH1;
12 12
    reserve %2 1 1;
13 -
    blit %2 %1 1;
13 +
    blit %2 %1 1 1;
14 14
    load w8 %3 %0 0;
15 15
    copy %4 $SCRATCH1;
16 16
    load w8 %5 %4 0;
17 17
    br.eq w8 %3 %5 @then1 @merge2;
18 18
  @then1
19 19
    copy %6 $SCRATCH2;
20 -
    blit %2 %6 1;
20 +
    blit %2 %6 1 1;
21 21
    jmp @merge2;
22 22
  @merge2
23 -
    load w64 %8 %2 0;
23 +
    load w8 %8 %2 0;
24 24
    ret %8;
25 25
}
test/tests/const.union.payload.ctor.ril +1 -1
6 6
7 7
fn w32 $main() {
8 8
  @entry0
9 9
    copy %0 $V;
10 10
    reserve %1 8 4;
11 -
    blit %1 %0 8;
11 +
    blit %1 %0 8 4;
12 12
    jmp @arm1;
13 13
  @arm1
14 14
    load w8 %2 %1 0;
15 15
    br.eq w8 %2 0 @case2 @arm3;
16 16
  @case2
test/tests/const.union.record.literal.ril +1 -1
7 7
8 8
fn w32 $main() {
9 9
  @entry0
10 10
    copy %0 $E;
11 11
    reserve %1 12 4;
12 -
    blit %1 %0 12;
12 +
    blit %1 %0 12 4;
13 13
    jmp @arm1;
14 14
  @arm1
15 15
    load w8 %2 %1 0;
16 16
    br.eq w8 %2 0 @case2 @arm3;
17 17
  @case2
test/tests/error.catch.return.ril +2 -2
5 5
    reserve %2 1 1;
6 6
    store w8 0 %2 0;
7 7
    reserve %3 12 8;
8 8
    store w64 1 %3 0;
9 9
    store w8 %2 %3 8;
10 -
    blit %0 %3 12;
10 +
    blit %0 %3 12 8;
11 11
    ret %0;
12 12
  @merge2
13 13
    reserve %4 12 8;
14 14
    store w64 0 %4 0;
15 15
    store w32 42 %4 8;
16 -
    blit %0 %4 12;
16 +
    blit %0 %4 12 8;
17 17
    ret %0;
18 18
}
19 19
20 20
fn w32 $caller(w8 %0) {
21 21
  @entry0
test/tests/field.aggregate.ril +9 -6
2 2
  @entry0
3 3
    reserve %0 12 4;
4 4
    reserve %1 8 4;
5 5
    store w32 10 %1 0;
6 6
    store w32 20 %1 4;
7 -
    blit %0 %1 8;
7 +
    blit %0 %1 8 4;
8 8
    store w32 30 %0 8;
9 9
    sload w32 %2 %0 4;
10 10
    ret %2;
11 11
}
12 12
16 16
    reserve %1 4 4;
17 17
    store w32 42 %1 0;
18 18
    reserve %2 8 4;
19 19
    store w8 1 %2 0;
20 20
    add w64 %3 %2 4;
21 -
    blit %3 %1 4;
22 -
    blit %0 %2 8;
21 +
    blit %3 %1 4 4;
22 +
    blit %0 %2 8 4;
23 23
    store w32 99 %0 8;
24 -
    load w64 %4 %0 0;
25 -
    ret %4;
24 +
    load w32 %4 %0 0;
25 +
    load w32 %5 %0 4;
26 +
    shl w64 %6 %5 32;
27 +
    or w64 %7 %4 %6;
28 +
    ret %7;
26 29
}
27 30
28 31
fn w32 $accessSliceField() {
29 32
  @entry0
30 33
    reserve %0 12 4;
34 37
    reserve %1 24 8;
35 38
    reserve %2 16 8;
36 39
    store w64 %0 %2 0;
37 40
    store w32 3 %2 8;
38 41
    store w32 3 %2 12;
39 -
    blit %1 %2 16;
42 +
    blit %1 %2 16 8;
40 43
    store w32 77 %1 16;
41 44
    load w32 %3 %1 8;
42 45
    ret %3;
43 46
}
test/tests/let.copy.semantics.ril +10 -7
1 1
fn w64 $makePoint() {
2 2
  @entry0
3 3
    reserve %0 8 4;
4 4
    store w32 1 %0 0;
5 5
    store w32 2 %0 4;
6 -
    load w64 %1 %0 0;
7 -
    ret %1;
6 +
    load w32 %1 %0 0;
7 +
    load w32 %2 %0 4;
8 +
    shl w64 %3 %2 32;
9 +
    or w64 %4 %1 %3;
10 +
    ret %4;
8 11
}
9 12
10 13
fn w32 $letFromCall() {
11 14
  @entry0
12 15
    call w64 %0 $makePoint();
20 23
  @entry0
21 24
    reserve %0 12 4;
22 25
    reserve %1 8 4;
23 26
    store w32 10 %1 0;
24 27
    store w32 20 %1 4;
25 -
    blit %0 %1 8;
28 +
    blit %0 %1 8 4;
26 29
    store w32 30 %0 8;
27 30
    reserve %2 8 4;
28 -
    blit %2 %0 8;
31 +
    blit %2 %0 8 4;
29 32
    sload w32 %3 %2 4;
30 33
    ret %3;
31 34
}
32 35
33 36
fn w32 $letFromSubscript() {
34 37
  @entry0
35 38
    reserve %0 16 4;
36 39
    reserve %1 8 4;
37 40
    store w32 1 %1 0;
38 41
    store w32 2 %1 4;
39 -
    blit %0 %1 8;
42 +
    blit %0 %1 8 4;
40 43
    reserve %2 8 4;
41 44
    store w32 3 %2 0;
42 45
    store w32 4 %2 4;
43 46
    add w64 %3 %0 8;
44 -
    blit %3 %2 8;
47 +
    blit %3 %2 8 4;
45 48
    mul w64 %4 1 8;
46 49
    add w64 %5 %0 %4;
47 50
    reserve %6 8 4;
48 -
    blit %6 %5 8;
51 +
    blit %6 %5 8 4;
49 52
    sload w32 %7 %6 0;
50 53
    ret %7;
51 54
}
test/tests/linear.ownership.ril +2 -2
1 1
fn w32 $consume(w64 %0) {
2 2
  @entry0
3 3
    reserve %1 8 4;
4 -
    blit %1 %0 8;
4 +
    blit %1 %0 8 4;
5 5
    jmp @arm1;
6 6
  @arm1
7 7
    jmp @case2;
8 8
  @case2
9 9
    load w32 %2 %1 4;
15 15
    reserve %0 4 4;
16 16
    store w32 42 %0 0;
17 17
    reserve %1 8 4;
18 18
    store w8 0 %1 0;
19 19
    add w64 %2 %1 4;
20 -
    blit %2 %0 4;
20 +
    blit %2 %0 4 4;
21 21
    call w32 %3 $consume(%1);
22 22
    ret %3;
23 23
}
test/tests/linear.reference.ril +2 -2
14 14
}
15 15
16 16
fn w32 $consume(w64 %0) {
17 17
  @entry0
18 18
    reserve %1 8 4;
19 -
    blit %1 %0 8;
19 +
    blit %1 %0 8 4;
20 20
    jmp @arm1;
21 21
  @arm1
22 22
    jmp @case2;
23 23
  @case2
24 24
    load w32 %2 %1 4;
30 30
    reserve %0 4 4;
31 31
    store w32 40 %0 0;
32 32
    reserve %1 8 4;
33 33
    store w8 0 %1 0;
34 34
    add w64 %2 %1 4;
35 -
    blit %2 %0 4;
35 +
    blit %2 %0 4 4;
36 36
    call w64 $increment(%1);
37 37
    call w64 $increment(%1);
38 38
    call w32 %3 $consume(%1);
39 39
    ret %3;
40 40
}
test/tests/loop.whilelet.union.ril +3 -3
1 1
fn w32 $sumWhileLet(w64 %0) {
2 2
  @entry0
3 3
    reserve %1 8 4;
4 -
    blit %1 %0 8;
4 +
    blit %1 %0 8 4;
5 5
    jmp @while1(%1, 0);
6 6
  @while1(w64 %2, w32 %6)
7 7
    reserve %3 8 4;
8 -
    blit %3 %2 8;
8 +
    blit %3 %2 8 4;
9 9
    load w8 %4 %3 0;
10 10
    br.eq w8 %4 1 @body2 @merge3;
11 11
  @body2
12 12
    load w32 %5 %3 4;
13 13
    add w32 %7 %6 %5;
14 14
    reserve %8 8 4;
15 15
    store w8 0 %8 0;
16 -
    blit %2 %8 8;
16 +
    blit %2 %8 8 4;
17 17
    jmp @while1(%2, %7);
18 18
  @merge3
19 19
    ret %6;
20 20
}
test/tests/match.nested.iflet.ril +4 -4
1 1
fn w32 $ifLetNested(w64 %0) {
2 2
  @entry0
3 3
    reserve %1 16 4;
4 -
    blit %1 %0 16;
4 +
    blit %1 %0 16 4;
5 5
    load w8 %2 %1 0;
6 6
    br.eq w8 %2 0 @then1 @else2;
7 7
  @then1
8 8
    add w64 %3 %1 4;
9 9
    sload w32 %4 %3 0;
19 19
}
20 20
21 21
fn w32 $ifLetNestedUnion(w64 %0) {
22 22
  @entry0
23 23
    reserve %1 12 4;
24 -
    blit %1 %0 12;
24 +
    blit %1 %0 12 4;
25 25
    load w8 %2 %1 0;
26 26
    br.eq w8 %2 0 @then1 @else2;
27 27
  @then1
28 28
    add w64 %3 %1 4;
29 29
    load w8 %4 %3 0;
40 40
}
41 41
42 42
fn w32 $ifLetPlaceholder(w64 %0) {
43 43
  @entry0
44 44
    reserve %1 16 4;
45 -
    blit %1 %0 16;
45 +
    blit %1 %0 16 4;
46 46
    load w8 %2 %1 0;
47 47
    br.eq w8 %2 0 @then1 @else2;
48 48
  @then1
49 49
    add w64 %3 %1 4;
50 50
    sload w32 %4 %3 0;
61 61
    store w8 0 %0 0;
62 62
    reserve %1 8 4;
63 63
    store w32 10 %1 0;
64 64
    store w32 20 %1 4;
65 65
    add w64 %2 %0 4;
66 -
    blit %2 %1 8;
66 +
    blit %2 %1 8 4;
67 67
    store w32 30 %0 12;
68 68
    call w32 %3 $ifLetNested(%0);
69 69
    br.eq w32 %3 60 @assert.ok2 @assert.fail1;
70 70
  @assert.fail1
71 71
    unreachable;
test/tests/match.nested.pattern.ril +18 -18
1 1
fn w32 $testNestedMatch(w64 %0) {
2 2
  @entry0
3 3
    reserve %1 16 4;
4 -
    blit %1 %0 16;
4 +
    blit %1 %0 16 4;
5 5
    jmp @arm1;
6 6
  @arm1
7 7
    load w8 %2 %1 0;
8 8
    br.eq w8 %2 0 @case2 @arm3;
9 9
  @case2
21 21
}
22 22
23 23
fn w32 $testNestedIfLetCase(w64 %0) {
24 24
  @entry0
25 25
    reserve %1 16 4;
26 -
    blit %1 %0 16;
26 +
    blit %1 %0 16 4;
27 27
    load w8 %2 %1 0;
28 28
    br.eq w8 %2 0 @then1 @else2;
29 29
  @then1
30 30
    add w64 %3 %1 4;
31 31
    sload w32 %4 %3 0;
41 41
}
42 42
43 43
fn w32 $testNestedPlaceholder(w64 %0) {
44 44
  @entry0
45 45
    reserve %1 16 4;
46 -
    blit %1 %0 16;
46 +
    blit %1 %0 16 4;
47 47
    jmp @arm1;
48 48
  @arm1
49 49
    load w8 %2 %1 0;
50 50
    br.eq w8 %2 0 @case2 @arm3;
51 51
  @case2
61 61
}
62 62
63 63
fn w32 $testDeepNesting(w64 %0) {
64 64
  @entry0
65 65
    reserve %1 16 4;
66 -
    blit %1 %0 16;
66 +
    blit %1 %0 16 4;
67 67
    jmp @arm1;
68 68
  @arm1
69 69
    load w8 %2 %1 0;
70 70
    br.eq w8 %2 0 @case2 @arm3;
71 71
  @case2
83 83
}
84 84
85 85
fn w32 $testNestedUnionLiteral(w64 %0) {
86 86
  @entry0
87 87
    reserve %1 12 4;
88 -
    blit %1 %0 12;
88 +
    blit %1 %0 12 4;
89 89
    jmp @arm1;
90 90
  @arm1
91 91
    load w8 %2 %1 0;
92 92
    br.eq w8 %2 0 @case2 @arm3;
93 93
  @case2
119 119
}
120 120
121 121
fn w32 $testMixedNesting(w64 %0) {
122 122
  @entry0
123 123
    reserve %1 20 4;
124 -
    blit %1 %0 20;
124 +
    blit %1 %0 20 4;
125 125
    jmp @arm1;
126 126
  @arm1
127 127
    load w8 %2 %1 0;
128 128
    br.eq w8 %2 0 @case2 @arm3;
129 129
  @case2
155 155
}
156 156
157 157
fn w32 $testNestedUnionInRecord(w64 %0) {
158 158
  @entry0
159 159
    reserve %1 20 4;
160 -
    blit %1 %0 20;
160 +
    blit %1 %0 20 4;
161 161
    jmp @arm1;
162 162
  @arm1
163 163
    load w8 %2 %1 0;
164 164
    br.eq w8 %2 0 @case2 @arm3;
165 165
  @case2
194 194
}
195 195
196 196
fn w32 $testPartialNesting(w64 %0) {
197 197
  @entry0
198 198
    reserve %1 20 4;
199 -
    blit %1 %0 20;
199 +
    blit %1 %0 20 4;
200 200
    jmp @arm1;
201 201
  @arm1
202 202
    load w8 %2 %1 0;
203 203
    br.eq w8 %2 0 @case2 @arm3;
204 204
  @case2
235 235
    store w8 0 %0 0;
236 236
    reserve %1 8 4;
237 237
    store w32 10 %1 0;
238 238
    store w32 20 %1 4;
239 239
    add w64 %2 %0 4;
240 -
    blit %2 %1 8;
240 +
    blit %2 %1 8 4;
241 241
    store w32 30 %0 12;
242 242
    call w32 %3 $testNestedMatch(%0);
243 243
    br.eq w32 %3 60 @assert.ok2 @assert.fail1;
244 244
  @assert.fail1
245 245
    unreachable;
271 271
    reserve %10 16 4;
272 272
    store w8 0 %10 0;
273 273
    reserve %11 8 4;
274 274
    reserve %12 4 4;
275 275
    store w32 100 %12 0;
276 -
    blit %11 %12 4;
276 +
    blit %11 %12 4 4;
277 277
    store w32 200 %11 4;
278 278
    add w64 %13 %10 4;
279 -
    blit %13 %11 8;
279 +
    blit %13 %11 8 4;
280 280
    store w32 300 %10 12;
281 281
    call w32 %14 $testDeepNesting(%10);
282 282
    br.eq w32 %14 600 @assert.ok12 @assert.fail11;
283 283
  @assert.fail11
284 284
    unreachable;
319 319
    store w8 0 %23 0;
320 320
    reserve %24 8 4;
321 321
    store w32 1 %24 0;
322 322
    store w32 2 %24 4;
323 323
    add w64 %25 %23 4;
324 -
    blit %25 %24 8;
324 +
    blit %25 %24 8 4;
325 325
    store w32 10 %23 12;
326 326
    call w32 %26 $testMixedNesting(%23);
327 327
    br.eq w32 %26 13 @assert.ok22 @assert.fail21;
328 328
  @assert.fail21
329 329
    unreachable;
332 332
    store w8 1 %27 0;
333 333
    reserve %28 8 4;
334 334
    store w32 3 %28 0;
335 335
    store w32 4 %28 4;
336 336
    add w64 %29 %27 4;
337 -
    blit %29 %28 8;
337 +
    blit %29 %28 8 4;
338 338
    reserve %30 8 4;
339 339
    store w32 5 %30 0;
340 340
    store w32 6 %30 4;
341 341
    add w64 %31 %27 12;
342 -
    blit %31 %30 8;
342 +
    blit %31 %30 8 4;
343 343
    call w32 %32 $testMixedNesting(%27);
344 344
    br.eq w32 %32 18 @assert.ok24 @assert.fail23;
345 345
  @assert.fail23
346 346
    unreachable;
347 347
  @assert.ok24
357 357
    reserve %36 16 4;
358 358
    reserve %37 12 4;
359 359
    store w8 0 %37 0;
360 360
    store w32 7 %37 4;
361 361
    store w32 8 %37 8;
362 -
    blit %36 %37 12;
362 +
    blit %36 %37 12 4;
363 363
    store w32 100 %36 12;
364 364
    add w64 %38 %35 4;
365 -
    blit %38 %36 16;
365 +
    blit %38 %36 16 4;
366 366
    call w32 %39 $testNestedUnionInRecord(%35);
367 367
    br.eq w32 %39 115 @assert.ok28 @assert.fail27;
368 368
  @assert.fail27
369 369
    unreachable;
370 370
  @assert.ok28
371 371
    reserve %40 20 4;
372 372
    store w8 0 %40 0;
373 373
    reserve %41 16 4;
374 374
    reserve %42 12 4;
375 375
    store w8 1 %42 0;
376 -
    blit %41 %42 12;
376 +
    blit %41 %42 12 4;
377 377
    store w32 99 %41 12;
378 378
    add w64 %43 %40 4;
379 -
    blit %43 %41 16;
379 +
    blit %43 %41 16 4;
380 380
    call w32 %44 $testNestedUnionInRecord(%40);
381 381
    br.eq w32 %44 -1 @assert.ok30 @assert.fail29;
382 382
  @assert.fail29
383 383
    unreachable;
384 384
  @assert.ok30
test/tests/match.nested.record.ril +7 -7
1 1
fn w32 $area(w64 %0) {
2 2
  @entry0
3 3
    reserve %1 20 4;
4 -
    blit %1 %0 20;
4 +
    blit %1 %0 20 4;
5 5
    jmp @arm1;
6 6
  @arm1
7 7
    load w8 %2 %1 0;
8 8
    br.eq w8 %2 0 @case2 @arm3;
9 9
  @case2
35 35
}
36 36
37 37
fn w32 $partial(w64 %0) {
38 38
  @entry0
39 39
    reserve %1 20 4;
40 -
    blit %1 %0 20;
40 +
    blit %1 %0 20 4;
41 41
    jmp @arm1;
42 42
  @arm1
43 43
    load w8 %2 %1 0;
44 44
    br.eq w8 %2 0 @case2 @arm3;
45 45
  @case2
70 70
}
71 71
72 72
fn w32 $withPlaceholder(w64 %0) {
73 73
  @entry0
74 74
    reserve %1 20 4;
75 -
    blit %1 %0 20;
75 +
    blit %1 %0 20 4;
76 76
    jmp @arm1;
77 77
  @arm1
78 78
    load w8 %2 %1 0;
79 79
    br.eq w8 %2 0 @case2 @arm3;
80 80
  @case2
105 105
    store w8 0 %0 0;
106 106
    reserve %1 8 4;
107 107
    store w32 3 %1 0;
108 108
    store w32 4 %1 4;
109 109
    add w64 %2 %0 4;
110 -
    blit %2 %1 8;
110 +
    blit %2 %1 8 4;
111 111
    store w32 5 %0 12;
112 112
    reserve %3 20 4;
113 113
    store w8 1 %3 0;
114 114
    reserve %4 16 4;
115 115
    reserve %5 8 4;
116 116
    store w32 1 %5 0;
117 117
    store w32 2 %5 4;
118 -
    blit %4 %5 8;
118 +
    blit %4 %5 8 4;
119 119
    reserve %6 8 4;
120 120
    store w32 10 %6 0;
121 121
    store w32 20 %6 4;
122 122
    add w64 %7 %4 8;
123 -
    blit %7 %6 8;
123 +
    blit %7 %6 8 4;
124 124
    add w64 %8 %3 4;
125 -
    blit %8 %4 16;
125 +
    blit %8 %4 16 4;
126 126
    call w32 %9 $area(%0);
127 127
    br.eq w32 %9 12 @assert.ok2 @assert.fail1;
128 128
  @assert.fail1
129 129
    unreachable;
130 130
  @assert.ok2
test/tests/match.nested.union.ril +2 -2
1 1
fn w32 $dispatch(w64 %0) {
2 2
  @entry0
3 3
    reserve %1 12 4;
4 -
    blit %1 %0 12;
4 +
    blit %1 %0 12 4;
5 5
    jmp @arm1;
6 6
  @arm1
7 7
    load w8 %2 %1 0;
8 8
    br.eq w8 %2 0 @case2 @arm3;
9 9
  @case2
83 83
}
84 84
85 85
fn w32 $moveOnly(w64 %0) {
86 86
  @entry0
87 87
    reserve %1 12 4;
88 -
    blit %1 %0 12;
88 +
    blit %1 %0 12 4;
89 89
    jmp @arm1;
90 90
  @arm1
91 91
    load w8 %2 %1 0;
92 92
    br.eq w8 %2 0 @case2 @arm3;
93 93
  @case2
test/tests/match.optional.aggregate.ril +1 -1
1 1
fn w32 $matchOptionalAggregate(w64 %0) {
2 2
  @entry0
3 3
    reserve %1 8 4;
4 -
    blit %1 %0 8;
4 +
    blit %1 %0 8 4;
5 5
    jmp @arm1;
6 6
  @arm1
7 7
    load w8 %2 %1 0;
8 8
    br.ne w32 %2 0 @arm3 @case2;
9 9
  @case2
test/tests/match.record.pattern.ril +1 -1
1 1
fn w32 $getFirst(w64 %0) {
2 2
  @entry0
3 3
    reserve %1 12 4;
4 -
    blit %1 %0 12;
4 +
    blit %1 %0 12 4;
5 5
    jmp @arm1;
6 6
  @arm1
7 7
    load w8 %2 %1 0;
8 8
    br.eq w8 %2 0 @case2 @arm3;
9 9
  @case2
test/tests/multi.throw.basic.ril +3 -3
5 5
    reserve %2 1 1;
6 6
    store w8 0 %2 0;
7 7
    reserve %3 12 8;
8 8
    store w64 1 %3 0;
9 9
    store w8 %2 %3 8;
10 -
    blit %0 %3 12;
10 +
    blit %0 %3 12 8;
11 11
    ret %0;
12 12
  @merge2
13 13
    br.eq w32 %1 2 @then3 @merge4;
14 14
  @then3
15 15
    reserve %4 1 1;
16 16
    store w8 0 %4 0;
17 17
    reserve %5 12 8;
18 18
    store w64 2 %5 0;
19 19
    store w8 %4 %5 8;
20 -
    blit %0 %5 12;
20 +
    blit %0 %5 12 8;
21 21
    ret %0;
22 22
  @merge4
23 23
    reserve %6 12 8;
24 24
    store w64 0 %6 0;
25 25
    store w32 42 %6 8;
26 -
    blit %0 %6 12;
26 +
    blit %0 %6 12 8;
27 27
    ret %0;
28 28
}
test/tests/multi.throw.catch.typed.ril +3 -3
5 5
    reserve %2 1 1;
6 6
    store w8 0 %2 0;
7 7
    reserve %3 12 8;
8 8
    store w64 1 %3 0;
9 9
    store w8 %2 %3 8;
10 -
    blit %0 %3 12;
10 +
    blit %0 %3 12 8;
11 11
    ret %0;
12 12
  @merge2
13 13
    br.eq w32 %1 2 @then3 @merge4;
14 14
  @then3
15 15
    reserve %4 1 1;
16 16
    store w8 0 %4 0;
17 17
    reserve %5 12 8;
18 18
    store w64 2 %5 0;
19 19
    store w8 %4 %5 8;
20 -
    blit %0 %5 12;
20 +
    blit %0 %5 12 8;
21 21
    ret %0;
22 22
  @merge4
23 23
    reserve %6 12 8;
24 24
    store w64 0 %6 0;
25 25
    store w32 42 %6 8;
26 -
    blit %0 %6 12;
26 +
    blit %0 %6 12 8;
27 27
    ret %0;
28 28
}
29 29
30 30
fn w32 $caller(w32 %0) {
31 31
  @entry0
test/tests/multi.throw.propagate.ril +5 -5
5 5
    reserve %2 1 1;
6 6
    store w8 0 %2 0;
7 7
    reserve %3 12 8;
8 8
    store w64 1 %3 0;
9 9
    store w8 %2 %3 8;
10 -
    blit %0 %3 12;
10 +
    blit %0 %3 12 8;
11 11
    ret %0;
12 12
  @merge2
13 13
    reserve %4 12 8;
14 14
    store w64 0 %4 0;
15 15
    store w32 10 %4 8;
16 -
    blit %0 %4 12;
16 +
    blit %0 %4 12 8;
17 17
    ret %0;
18 18
}
19 19
20 20
fn w64 $outer(w64 %0, w8 %1) {
21 21
  @entry0
31 31
  @err2
32 32
    reserve %7 12 8;
33 33
    store w64 %4 %7 0;
34 34
    add w64 %8 %3 8;
35 35
    add w64 %9 %7 8;
36 -
    blit %9 %8 1;
37 -
    blit %0 %7 12;
36 +
    blit %9 %8 1 8;
37 +
    blit %0 %7 12 8;
38 38
    ret %0;
39 39
  @merge3
40 40
    sload w32 %10 %5 0;
41 41
    add w32 %11 %10 1;
42 42
    reserve %12 12 8;
43 43
    store w64 0 %12 0;
44 44
    store w32 %11 %12 8;
45 -
    blit %0 %12 12;
45 +
    blit %0 %12 12 8;
46 46
    ret %0;
47 47
}
test/tests/opt.record.eq.rev.ril +3 -3
1 1
fn w64 $makeOpt(w64 %0, w64 %1) {
2 2
  @entry0
3 3
    reserve %2 8 4;
4 4
    store w8 1 %2 0;
5 5
    add w64 %3 %2 4;
6 -
    blit %3 %1 4;
7 -
    blit %0 %2 8;
6 +
    blit %3 %1 4 4;
7 +
    blit %0 %2 8 4;
8 8
    ret %0;
9 9
}
10 10
11 11
fn w32 $main() {
12 12
  @entry0
15 15
    reserve %1 8 4;
16 16
    call w64 %2 $makeOpt(%1, %0);
17 17
    reserve %3 8 4;
18 18
    store w8 1 %3 0;
19 19
    add w64 %4 %3 4;
20 -
    blit %4 %0 4;
20 +
    blit %4 %0 4 4;
21 21
    load w8 %5 %2 0;
22 22
    load w8 %6 %3 0;
23 23
    eq w8 %7 %5 %6;
24 24
    eq w8 %8 %5 0;
25 25
    load w32 %9 %2 4;
test/tests/opt.record.eq.ril +12 -12
5 5
    store w32 3 %1 0;
6 6
    store w32 9 %1 4;
7 7
    reserve %2 12 4;
8 8
    store w8 1 %2 0;
9 9
    add w64 %3 %2 4;
10 -
    blit %3 %1 8;
11 -
    blit %0 %2 12;
10 +
    blit %3 %1 8 4;
11 +
    blit %0 %2 12 4;
12 12
    reserve %4 12 4;
13 13
    reserve %5 8 4;
14 14
    store w32 3 %5 0;
15 15
    store w32 9 %5 4;
16 16
    reserve %6 12 4;
17 17
    store w8 1 %6 0;
18 18
    add w64 %7 %6 4;
19 -
    blit %7 %5 8;
20 -
    blit %4 %6 12;
19 +
    blit %7 %5 8 4;
20 +
    blit %4 %6 12 4;
21 21
    load w8 %8 %0 0;
22 22
    load w8 %9 %4 0;
23 23
    eq w8 %10 %8 %9;
24 24
    eq w8 %11 %8 0;
25 25
    sload w32 %12 %0 4;
41 41
    store w32 4 %23 0;
42 42
    store w32 6 %23 4;
43 43
    reserve %24 12 4;
44 44
    store w8 1 %24 0;
45 45
    add w64 %25 %24 4;
46 -
    blit %25 %23 8;
47 -
    blit %22 %24 12;
46 +
    blit %25 %23 8 4;
47 +
    blit %22 %24 12 4;
48 48
    load w8 %26 %0 0;
49 49
    load w8 %27 %22 0;
50 50
    eq w8 %28 %26 %27;
51 51
    eq w8 %29 %26 0;
52 52
    sload w32 %30 %0 4;
71 71
    reserve %42 16 4;
72 72
    store w8 0 %42 0;
73 73
    reserve %43 16 4;
74 74
    store w8 1 %43 0;
75 75
    add w64 %44 %43 4;
76 -
    blit %44 %0 12;
77 -
    blit %39 %43 16;
76 +
    blit %44 %0 12 4;
77 +
    blit %39 %43 16 4;
78 78
    reserve %45 16 4;
79 79
    store w8 1 %45 0;
80 80
    add w64 %46 %45 4;
81 -
    blit %46 %4 12;
82 -
    blit %40 %45 16;
81 +
    blit %46 %4 12 4;
82 +
    blit %40 %45 16 4;
83 83
    reserve %47 16 4;
84 84
    store w8 1 %47 0;
85 85
    add w64 %48 %47 4;
86 -
    blit %48 %22 12;
87 -
    blit %41 %47 16;
86 +
    blit %48 %22 12 4;
87 +
    blit %41 %47 16 4;
88 88
    load w8 %49 %39 0;
89 89
    load w8 %50 %40 0;
90 90
    eq w8 %51 %49 %50;
91 91
    eq w8 %52 %49 0;
92 92
    load w8 %53 %39 4;
test/tests/opt.return.nil.ril +1 -1
1 1
fn w64 $optReturnNil(w64 %0) {
2 2
  @entry0
3 3
    reserve %1 8 4;
4 4
    store w8 0 %1 0;
5 -
    blit %0 %1 8;
5 +
    blit %0 %1 8 4;
6 6
    ret %0;
7 7
}
test/tests/opt.return.value.ril +1 -1
1 1
fn w64 $optReturnValue(w64 %0) {
2 2
  @entry0
3 3
    reserve %1 8 4;
4 4
    store w8 1 %1 0;
5 5
    store w32 7 %1 4;
6 -
    blit %0 %1 8;
6 +
    blit %0 %1 8 4;
7 7
    ret %0;
8 8
}
test/tests/opt.slice.npo.ril +14 -14
43 43
    reserve %1 16 8;
44 44
    store w64 %0 %1 0;
45 45
    store w32 3 %1 8;
46 46
    store w32 3 %1 12;
47 47
    reserve %2 16 8;
48 -
    blit %2 %1 16;
48 +
    blit %2 %1 16 8;
49 49
    load w64 %3 %2 0;
50 50
    ne w64 %4 %3 0;
51 51
    br.ne w32 %4 0 @assert.ok2 @assert.fail1;
52 52
  @assert.fail1
53 53
    unreachable;
64 64
    reserve %1 16 8;
65 65
    store w64 %0 %1 0;
66 66
    store w32 3 %1 8;
67 67
    store w32 3 %1 12;
68 68
    reserve %2 16 8;
69 -
    blit %2 %1 16;
69 +
    blit %2 %1 16 8;
70 70
    reserve %3 16 8;
71 -
    blit %3 %2 16;
71 +
    blit %3 %2 16 8;
72 72
    load w64 %4 %3 0;
73 73
    br.ne w32 %4 0 @then1 @else2;
74 74
  @then1
75 75
    load w32 %5 %3 8;
76 76
    br.eq w32 %5 3 @assert.ok4 @assert.fail3;
109 109
    reserve %13 16 8;
110 110
    store w64 0 %13 0;
111 111
    store w32 0 %13 8;
112 112
    store w32 0 %13 12;
113 113
    reserve %14 16 8;
114 -
    blit %14 %13 16;
114 +
    blit %14 %13 16 8;
115 115
    load w64 %15 %14 0;
116 116
    br.ne w32 %15 0 @then14 @else15;
117 117
  @then14
118 118
    ret 35;
119 119
  @else15
131 131
    reserve %1 16 8;
132 132
    store w64 %0 %1 0;
133 133
    store w32 3 %1 8;
134 134
    store w32 3 %1 12;
135 135
    reserve %2 16 8;
136 -
    blit %2 %1 16;
136 +
    blit %2 %1 16 8;
137 137
    reserve %3 16 8;
138 -
    blit %3 %2 16;
138 +
    blit %3 %2 16 8;
139 139
    load w64 %4 %3 0;
140 140
    br.ne w32 %4 0 @success1 @else2;
141 141
  @success1
142 142
    jmp @merge3;
143 143
  @else2
155 155
  @entry0
156 156
    reserve %1 16 8;
157 157
    store w64 0 %1 0;
158 158
    store w32 0 %1 8;
159 159
    store w32 0 %1 12;
160 -
    blit %0 %1 16;
160 +
    blit %0 %1 16 8;
161 161
    ret %0;
162 162
}
163 163
164 164
fn w64 $returnSome(w64 %0) {
165 165
  @entry0
168 168
    store w8 99 %1 1;
169 169
    reserve %2 16 8;
170 170
    store w64 %1 %2 0;
171 171
    store w32 2 %2 8;
172 172
    store w32 2 %2 12;
173 -
    blit %0 %2 16;
173 +
    blit %0 %2 16 8;
174 174
    ret %0;
175 175
}
176 176
177 177
fn w8 $checkReturn() {
178 178
  @entry0
191 191
    br.ne w32 %7 0 @assert.ok4 @assert.fail3;
192 192
  @assert.fail3
193 193
    unreachable;
194 194
  @assert.ok4
195 195
    reserve %8 16 8;
196 -
    blit %8 %5 16;
196 +
    blit %8 %5 16 8;
197 197
    load w64 %9 %8 0;
198 198
    br.ne w32 %9 0 @then5 @else6;
199 199
  @then5
200 200
    load w32 %10 %8 8;
201 201
    br.ult w32 0 %10 @guard#pass9 @guard#trap10;
224 224
    reserve %1 16 8;
225 225
    store w64 %0 %1 0;
226 226
    store w32 2 %1 8;
227 227
    store w32 2 %1 12;
228 228
    reserve %2 16 8;
229 -
    blit %2 %1 16;
229 +
    blit %2 %1 16 8;
230 230
    reserve %3 16 8;
231 -
    blit %3 %2 16;
231 +
    blit %3 %2 16 8;
232 232
    jmp @arm1;
233 233
  @arm1
234 234
    load w64 %4 %3 0;
235 235
    br.eq w64 %4 0 @case2 @arm3;
236 236
  @case2
243 243
    reserve %5 16 8;
244 244
    store w64 0 %5 0;
245 245
    store w32 0 %5 8;
246 246
    store w32 0 %5 12;
247 247
    reserve %6 16 8;
248 -
    blit %6 %5 16;
248 +
    blit %6 %5 16 8;
249 249
    jmp @arm7;
250 250
  @arm7
251 251
    load w64 %7 %6 0;
252 252
    br.eq w64 %7 0 @case8 @arm9;
253 253
  @case8
287 287
    reserve %10 16 8;
288 288
    store w64 %9 %10 0;
289 289
    store w32 2 %10 8;
290 290
    store w32 2 %10 12;
291 291
    reserve %11 16 8;
292 -
    blit %11 %10 16;
292 +
    blit %11 %10 16 8;
293 293
    load w64 %12 %11 0;
294 294
    load w64 %13 %0 0;
295 295
    eq w64 %14 %12 %13;
296 296
    load w32 %15 %11 8;
297 297
    load w32 %16 %0 8;
301 301
    br.ne w32 %19 0 @assert.ok4 @assert.fail3;
302 302
  @assert.fail3
303 303
    unreachable;
304 304
  @assert.ok4
305 305
    reserve %20 16 8;
306 -
    blit %20 %10 16;
306 +
    blit %20 %10 16 8;
307 307
    load w64 %21 %11 0;
308 308
    load w64 %22 %20 0;
309 309
    eq w64 %23 %21 %22;
310 310
    load w32 %24 %11 8;
311 311
    load w32 %25 %20 8;
test/tests/ptr.deref.record.ril +1 -1
5 5
}
6 6
7 7
fn w32 $derefCopy(w64 %0) {
8 8
  @entry0
9 9
    reserve %1 8 4;
10 -
    blit %1 %0 8;
10 +
    blit %1 %0 8 4;
11 11
    sload w32 %2 %1 4;
12 12
    ret %2;
13 13
}
test/tests/record.assign.blit.ril +2 -2
2 2
  @entry0
3 3
    reserve %0 8 4;
4 4
    store w32 1 %0 0;
5 5
    store w32 2 %0 4;
6 6
    reserve %1 8 4;
7 -
    blit %1 %0 8;
8 -
    blit %1 %0 8;
7 +
    blit %1 %0 8 4;
8 +
    blit %1 %0 8 4;
9 9
    ret;
10 10
}
test/tests/record.ctor.tuple.ril +5 -2
1 1
fn w64 $make() {
2 2
  @entry0
3 3
    reserve %0 8 4;
4 4
    store w32 1 %0 0;
5 5
    store w32 2 %0 4;
6 -
    load w64 %1 %0 0;
7 -
    ret %1;
6 +
    load w32 %1 %0 0;
7 +
    load w32 %2 %0 4;
8 +
    shl w64 %3 %2 32;
9 +
    or w64 %4 %1 %3;
10 +
    ret %4;
8 11
}
test/tests/record.nested.lit.ril +1 -1
2 2
  @entry0
3 3
    reserve %0 12 4;
4 4
    reserve %1 8 4;
5 5
    store w32 1 %1 0;
6 6
    store w32 2 %1 4;
7 -
    blit %0 %1 8;
7 +
    blit %0 %1 8 4;
8 8
    store w32 3 %0 8;
9 9
    sload w32 %2 %0 4;
10 10
    ret %2;
11 11
}
test/tests/reference.array.repeat.ril +1 -1
7 7
    copy %1 $repeatedSlice$literal$0;
8 8
    reserve %2 16 8;
9 9
    store w64 %1 %2 0;
10 10
    store w32 3 %2 8;
11 11
    store w32 3 %2 12;
12 -
    blit %0 %2 16;
12 +
    blit %0 %2 16 8;
13 13
    ret %0;
14 14
}
test/tests/slice.append.ril +6 -6
3 3
}
4 4
5 5
fn w64 $newArena(w64 %0, w64 %1) {
6 6
  @entry0
7 7
    reserve %2 24 8;
8 -
    blit %2 %1 16;
8 +
    blit %2 %1 16 8;
9 9
    store w32 0 %2 16;
10 -
    blit %0 %2 24;
10 +
    blit %0 %2 24 8;
11 11
    ret %0;
12 12
}
13 13
14 14
fn w64 $arenaAlloc(w64 %0, w32 %1, w32 %2) {
15 15
  @entry0
46 46
  @entry0
47 47
    reserve %2 16 8;
48 48
    copy %3 $arenaAllocFn;
49 49
    store w64 %3 %2 0;
50 50
    store w64 %1 %2 8;
51 -
    blit %0 %2 16;
51 +
    blit %0 %2 16 8;
52 52
    ret %0;
53 53
}
54 54
55 55
fn w32 $main() {
56 56
  @entry0
600 600
    mul w64 %330 %314 4;
601 601
    add w64 %331 %329 %330;
602 602
    store w32 42 %331 0;
603 603
    add w32 %332 %314 1;
604 604
    store w32 %332 %311 8;
605 -
    blit %311 %311 16;
605 +
    blit %311 %311 16 8;
606 606
    load w32 %335 %311 8;
607 607
    br.eq w32 %335 1 @assert.ok123 @assert.fail122;
608 608
  @append.grow118
609 609
    shl w32 %316 %315 1;
610 610
    or w32 %317 %316 1;
651 651
    mul w64 %357 %341 4;
652 652
    add w64 %358 %356 %357;
653 653
    store w32 43 %358 0;
654 654
    add w32 %359 %341 1;
655 655
    store w32 %359 %311 8;
656 -
    blit %311 %311 16;
656 +
    blit %311 %311 16 8;
657 657
    load w32 %362 %311 8;
658 658
    br.eq w32 %362 2 @assert.ok134 @assert.fail133;
659 659
  @append.grow129
660 660
    shl w32 %343 %342 1;
661 661
    or w32 %344 %343 1;
697 697
    mul w64 %383 %367 4;
698 698
    add w64 %384 %382 %383;
699 699
    store w32 44 %384 0;
700 700
    add w32 %385 %367 1;
701 701
    store w32 %385 %311 8;
702 -
    blit %311 %311 16;
702 +
    blit %311 %311 16 8;
703 703
    load w32 %388 %311 8;
704 704
    br.eq w32 %388 3 @assert.ok143 @assert.fail142;
705 705
  @append.grow138
706 706
    shl w32 %369 %368 1;
707 707
    or w32 %370 %369 1;
test/tests/slice.basic.ril +4 -4
17 17
}
18 18
19 19
fn w64 $sliceCopy(w64 %0, w64 %1) {
20 20
  @entry0
21 21
    reserve %2 16 8;
22 -
    blit %2 %1 16;
23 -
    blit %0 %2 16;
22 +
    blit %2 %1 16 8;
23 +
    blit %0 %2 16 8;
24 24
    ret %0;
25 25
}
26 26
27 27
fn w64 $sliceOf(w64 %0, w64 %1, w32 %2) {
28 28
  @entry0
29 29
    reserve %3 16 8;
30 30
    store w64 %1 %3 0;
31 31
    store w32 %2 %3 8;
32 32
    store w32 %2 %3 12;
33 -
    blit %0 %3 16;
33 +
    blit %0 %3 16 8;
34 34
    ret %0;
35 35
}
36 36
37 37
fn w64 $sliceOfWithCap(w64 %0, w64 %1, w32 %2, w32 %3) {
38 38
  @entry0
43 43
  @guard#pass2
44 44
    reserve %4 16 8;
45 45
    store w64 %1 %4 0;
46 46
    store w32 %2 %4 8;
47 47
    store w32 %3 %4 12;
48 -
    blit %0 %4 16;
48 +
    blit %0 %4 16 8;
49 49
    ret %0;
50 50
}
test/tests/slice.range.ril +5 -5
22 22
    sub w32 %8 %3 %2;
23 23
    reserve %9 16 8;
24 24
    store w64 %7 %9 0;
25 25
    store w32 %8 %9 8;
26 26
    store w32 %8 %9 12;
27 -
    blit %0 %9 16;
27 +
    blit %0 %9 16 8;
28 28
    ret %0;
29 29
}
30 30
31 31
fn w64 $sliceRangeOpenEnd(w64 %0, w64 %1, w32 %2) {
32 32
  @entry0
42 42
    sub w32 %7 %4 %2;
43 43
    reserve %8 16 8;
44 44
    store w64 %6 %8 0;
45 45
    store w32 %7 %8 8;
46 46
    store w32 %7 %8 12;
47 -
    blit %0 %8 16;
47 +
    blit %0 %8 16 8;
48 48
    ret %0;
49 49
}
50 50
51 51
fn w64 $sliceRangeOpenStart(w64 %0, w64 %1, w32 %2) {
52 52
  @entry0
59 59
  @guard#pass2
60 60
    reserve %5 16 8;
61 61
    store w64 %3 %5 0;
62 62
    store w32 %2 %5 8;
63 63
    store w32 %2 %5 12;
64 -
    blit %0 %5 16;
64 +
    blit %0 %5 16 8;
65 65
    ret %0;
66 66
}
67 67
68 68
fn w64 $sliceRangeFull(w64 %0, w64 %1) {
69 69
  @entry0
71 71
    load w32 %3 %1 8;
72 72
    reserve %4 16 8;
73 73
    store w64 %2 %4 0;
74 74
    store w32 %3 %4 8;
75 75
    store w32 %3 %4 12;
76 -
    blit %0 %4 16;
76 +
    blit %0 %4 16 8;
77 77
    ret %0;
78 78
}
79 79
80 80
fn w64 $sliceArray(w64 %0, w64 %1) {
81 81
  @entry0
84 84
    sub w32 %4 3 1;
85 85
    reserve %5 16 8;
86 86
    store w64 %3 %5 0;
87 87
    store w32 %4 %5 8;
88 88
    store w32 %4 %5 12;
89 -
    blit %0 %5 16;
89 +
    blit %0 %5 16 8;
90 90
    ret %0;
91 91
}
test/tests/slice.runtime.i32.ril +3 -3
4 4
    store w32 %1 %2 0;
5 5
    reserve %3 16 8;
6 6
    store w64 %2 %3 0;
7 7
    store w32 1 %3 8;
8 8
    store w32 1 %3 12;
9 -
    blit %0 %3 16;
9 +
    blit %0 %3 16 8;
10 10
    ret %0;
11 11
}
12 12
13 13
fn w64 $sliceWithVars(w64 %0, w32 %1, w32 %2) {
14 14
  @entry0
17 17
    store w32 %2 %3 4;
18 18
    reserve %4 16 8;
19 19
    store w64 %3 %4 0;
20 20
    store w32 2 %4 8;
21 21
    store w32 2 %4 12;
22 -
    blit %0 %4 16;
22 +
    blit %0 %4 16 8;
23 23
    ret %0;
24 24
}
25 25
26 26
fn w64 $sliceWithMixed(w64 %0, w32 %1) {
27 27
  @entry0
31 31
    store w32 %1 %2 8;
32 32
    reserve %3 16 8;
33 33
    store w64 %2 %3 0;
34 34
    store w32 3 %3 8;
35 35
    store w32 3 %3 12;
36 -
    blit %0 %3 16;
36 +
    blit %0 %3 16 8;
37 37
    ret %0;
38 38
}
test/tests/slice.runtime.literal.ril +2 -2
4 4
    store w8 %1 %2 0;
5 5
    reserve %3 16 8;
6 6
    store w64 %2 %3 0;
7 7
    store w32 1 %3 8;
8 8
    store w32 1 %3 12;
9 -
    blit %0 %3 16;
9 +
    blit %0 %3 16 8;
10 10
    ret %0;
11 11
}
12 12
13 13
fn w64 $sliceWithVars(w64 %0, w8 %1, w8 %2) {
14 14
  @entry0
17 17
    store w8 %2 %3 1;
18 18
    reserve %4 16 8;
19 19
    store w64 %3 %4 0;
20 20
    store w32 2 %4 8;
21 21
    store w32 2 %4 12;
22 -
    blit %0 %4 16;
22 +
    blit %0 %4 16 8;
23 23
    ret %0;
24 24
}
test/tests/try.basic.ril +5 -5
5 5
    reserve %2 1 1;
6 6
    store w8 0 %2 0;
7 7
    reserve %3 12 8;
8 8
    store w64 1 %3 0;
9 9
    store w8 %2 %3 8;
10 -
    blit %0 %3 12;
10 +
    blit %0 %3 12 8;
11 11
    ret %0;
12 12
  @merge2
13 13
    reserve %4 12 8;
14 14
    store w64 0 %4 0;
15 15
    store w32 7 %4 8;
16 -
    blit %0 %4 12;
16 +
    blit %0 %4 12 8;
17 17
    ret %0;
18 18
}
19 19
20 20
fn w64 $caller(w64 %0, w8 %1) {
21 21
  @entry0
31 31
  @err2
32 32
    reserve %7 12 8;
33 33
    store w64 %4 %7 0;
34 34
    add w64 %8 %3 8;
35 35
    add w64 %9 %7 8;
36 -
    blit %9 %8 1;
37 -
    blit %0 %7 12;
36 +
    blit %9 %8 1 8;
37 +
    blit %0 %7 12 8;
38 38
    ret %0;
39 39
  @merge3
40 40
    sload w32 %10 %5 0;
41 41
    add w32 %11 %10 1;
42 42
    reserve %12 12 8;
43 43
    store w64 0 %12 0;
44 44
    store w32 %11 %12 8;
45 -
    blit %0 %12 12;
45 +
    blit %0 %12 12 8;
46 46
    ret %0;
47 47
}
test/tests/try.catch.ril +4 -4
5 5
    reserve %2 1 1;
6 6
    store w8 0 %2 0;
7 7
    reserve %3 12 8;
8 8
    store w64 1 %3 0;
9 9
    store w8 %2 %3 8;
10 -
    blit %0 %3 12;
10 +
    blit %0 %3 12 8;
11 11
    ret %0;
12 12
  @merge2
13 13
    reserve %4 12 8;
14 14
    store w64 0 %4 0;
15 15
    store w32 42 %4 8;
16 -
    blit %0 %4 12;
16 +
    blit %0 %4 12 8;
17 17
    ret %0;
18 18
}
19 19
20 20
fn w64 $caller(w64 %0, w8 %1) {
21 21
  @entry0
30 30
    jmp @merge3;
31 31
  @err2
32 32
    reserve %7 12 8;
33 33
    store w64 0 %7 0;
34 34
    store w32 1 %7 8;
35 -
    blit %0 %7 12;
35 +
    blit %0 %7 12 8;
36 36
    ret %0;
37 37
  @merge3
38 38
    sload w32 %8 %5 0;
39 39
    add w32 %9 %8 1;
40 40
    reserve %10 12 8;
41 41
    store w64 0 %10 0;
42 42
    store w32 %9 %10 8;
43 -
    blit %0 %10 12;
43 +
    blit %0 %10 12 8;
44 44
    ret %0;
45 45
}
test/tests/try.optional.ril +5 -5
5 5
    reserve %2 1 1;
6 6
    store w8 0 %2 0;
7 7
    reserve %3 12 8;
8 8
    store w64 1 %3 0;
9 9
    store w8 %2 %3 8;
10 -
    blit %0 %3 12;
10 +
    blit %0 %3 12 8;
11 11
    ret %0;
12 12
  @merge2
13 13
    reserve %4 12 8;
14 14
    store w64 0 %4 0;
15 15
    store w32 3 %4 8;
16 -
    blit %0 %4 12;
16 +
    blit %0 %4 12 8;
17 17
    ret %0;
18 18
}
19 19
20 20
fn w64 $caller(w64 %0, w8 %1) {
21 21
  @entry0
27 27
  @ok1
28 28
    sload w32 %6 %3 8;
29 29
    reserve %7 8 4;
30 30
    store w8 1 %7 0;
31 31
    store w32 %6 %7 4;
32 -
    blit %5 %7 8;
32 +
    blit %5 %7 8 4;
33 33
    jmp @merge3;
34 34
  @err2
35 35
    reserve %8 8 4;
36 36
    store w8 0 %8 0;
37 -
    blit %5 %8 8;
37 +
    blit %5 %8 8 4;
38 38
    jmp @merge3;
39 39
  @merge3
40 -
    blit %0 %5 8;
40 +
    blit %0 %5 8 4;
41 41
    ret %0;
42 42
}
test/tests/try.panic.ril +2 -2
5 5
    reserve %2 1 1;
6 6
    store w8 0 %2 0;
7 7
    reserve %3 12 8;
8 8
    store w64 1 %3 0;
9 9
    store w8 %2 %3 8;
10 -
    blit %0 %3 12;
10 +
    blit %0 %3 12 8;
11 11
    ret %0;
12 12
  @merge2
13 13
    reserve %4 12 8;
14 14
    store w64 0 %4 0;
15 15
    store w32 1 %4 8;
16 -
    blit %0 %4 12;
16 +
    blit %0 %4 12 8;
17 17
    ret %0;
18 18
}
19 19
20 20
fn w32 $caller(w8 %0) {
21 21
  @entry0
test/tests/undefined.record.field.ril +1 -1
29 29
  @entry0
30 30
    reserve %0 24 4;
31 31
    store w8 0 %0 0;
32 32
    store w32 99 %0 20;
33 33
    reserve %1 24 4;
34 -
    blit %1 %0 24;
34 +
    blit %1 %0 24 4;
35 35
    jmp @arm1;
36 36
  @arm1
37 37
    load w8 %2 %1 0;
38 38
    br.eq w8 %2 0 @case2 @arm3;
39 39
  @case2
test/tests/union.ctor.ril +11 -5
13 13
    reserve %0 4 4;
14 14
    store w32 7 %0 0;
15 15
    reserve %1 8 4;
16 16
    store w8 1 %1 0;
17 17
    add w64 %2 %1 4;
18 -
    blit %2 %0 4;
19 -
    load w64 %3 %1 0;
20 -
    ret %3;
18 +
    blit %2 %0 4 4;
19 +
    load w32 %3 %1 0;
20 +
    load w32 %4 %1 4;
21 +
    shl w64 %5 %4 32;
22 +
    or w64 %6 %3 %5;
23 +
    ret %6;
21 24
}
22 25
23 26
fn w64 $makeNone() {
24 27
  @entry0
25 28
    reserve %0 8 4;
26 29
    store w8 0 %0 0;
27 -
    load w64 %1 %0 0;
28 -
    ret %1;
30 +
    load w32 %1 %0 0;
31 +
    load w32 %2 %0 4;
32 +
    shl w64 %3 %2 32;
33 +
    or w64 %4 %1 %3;
34 +
    ret %4;
29 35
}
test/tests/union.match.bind.ril +1 -1
1 1
fn w32 $unwrap(w64 %0) {
2 2
  @entry0
3 3
    reserve %1 8 4;
4 -
    blit %1 %0 8;
4 +
    blit %1 %0 8 4;
5 5
    jmp @arm1;
6 6
  @arm1
7 7
    load w8 %2 %1 0;
8 8
    br.eq w8 %2 0 @case2 @arm3;
9 9
  @case2
test/tests/union.match.ref.ril +1 -1
57 57
    add w64 %3 %1 4;
58 58
    load w32 %5 %3 0;
59 59
    add w32 %6 %4 %5;
60 60
    reserve %7 8 4;
61 61
    store w8 0 %7 0;
62 -
    blit %1 %7 8;
62 +
    blit %1 %7 8 4;
63 63
    jmp @while1(%1, %6);
64 64
  @merge3
65 65
    ret %4;
66 66
}
67 67
test/tests/union.match.tag.ril +2 -2
29 29
}
30 30
31 31
fn w32 $matchTag(w64 %0) {
32 32
  @entry0
33 33
    reserve %1 8 4;
34 -
    blit %1 %0 8;
34 +
    blit %1 %0 8 4;
35 35
    jmp @arm1;
36 36
  @arm1
37 37
    load w8 %2 %1 0;
38 38
    br.eq w8 %2 0 @case2 @arm3;
39 39
  @case2
45 45
}
46 46
47 47
fn w32 $matchElse(w64 %0) {
48 48
  @entry0
49 49
    reserve %1 8 4;
50 -
    blit %1 %0 8;
50 +
    blit %1 %0 8 4;
51 51
    jmp @arm1;
52 52
  @arm1
53 53
    load w8 %2 %1 0;
54 54
    br.eq w8 %2 0 @case2 @arm3;
55 55
  @case2
test/tests/union.record.literal.ril +2 -2
2 2
  @entry0
3 3
    reserve %3 12 4;
4 4
    store w8 1 %3 0;
5 5
    store w32 %1 %3 4;
6 6
    store w32 %2 %3 8;
7 -
    blit %0 %3 12;
7 +
    blit %0 %3 12 4;
8 8
    ret %0;
9 9
}
10 10
11 11
fn w8 $isPair(w64 %0) {
12 12
  @entry0
13 13
    reserve %1 12 4;
14 -
    blit %1 %0 12;
14 +
    blit %1 %0 12 4;
15 15
    jmp @arm1;
16 16
  @arm1
17 17
    load w8 %2 %1 0;
18 18
    br.eq w8 %2 0 @case2 @arm3;
19 19
  @case2
test/tests/union.variant.access.ril +16 -7
10 10
11 11
fn w64 $makeNone() {
12 12
  @entry0
13 13
    reserve %0 8 4;
14 14
    store w8 0 %0 0;
15 -
    load w64 %1 %0 0;
16 -
    ret %1;
15 +
    load w32 %1 %0 0;
16 +
    load w32 %2 %0 4;
17 +
    shl w64 %3 %2 32;
18 +
    or w64 %4 %1 %3;
19 +
    ret %4;
17 20
}
18 21
19 22
fn w64 $makeSome(w32 %0) {
20 23
  @entry0
21 24
    reserve %1 4 4;
22 25
    store w32 %0 %1 0;
23 26
    reserve %2 8 4;
24 27
    store w8 1 %2 0;
25 28
    add w64 %3 %2 4;
26 -
    blit %3 %1 4;
27 -
    load w64 %4 %2 0;
28 -
    ret %4;
29 +
    blit %3 %1 4 4;
30 +
    load w32 %4 %2 0;
31 +
    load w32 %5 %2 4;
32 +
    shl w64 %6 %5 32;
33 +
    or w64 %7 %4 %6;
34 +
    ret %7;
29 35
}
30 36
31 37
fn w64 $assignNone() {
32 38
  @entry0
33 39
    reserve %0 8 4;
34 40
    store w8 0 %0 0;
35 -
    load w64 %1 %0 0;
36 -
    ret %1;
41 +
    load w32 %1 %0 0;
42 +
    load w32 %2 %0 4;
43 +
    shl w64 %3 %2 32;
44 +
    or w64 %4 %1 %3;
45 +
    ret %4;
37 46
}
test/tests/void.throw.ril +5 -5
5 5
    reserve %2 1 1;
6 6
    store w8 0 %2 0;
7 7
    reserve %3 9 8;
8 8
    store w64 1 %3 0;
9 9
    store w8 %2 %3 8;
10 -
    blit %0 %3 9;
10 +
    blit %0 %3 9 8;
11 11
    ret %0;
12 12
  @merge2
13 13
    reserve %4 9 8;
14 14
    store w64 0 %4 0;
15 -
    blit %0 %4 9;
15 +
    blit %0 %4 9 8;
16 16
    ret %0;
17 17
}
18 18
19 19
fn w64 $caller(w64 %0, w8 %1) {
20 20
  @entry0
27 27
  @err2
28 28
    reserve %5 9 8;
29 29
    store w64 %4 %5 0;
30 30
    add w64 %6 %3 8;
31 31
    add w64 %7 %5 8;
32 -
    blit %7 %6 1;
33 -
    blit %0 %5 9;
32 +
    blit %7 %6 1 8;
33 +
    blit %0 %5 9 8;
34 34
    ret %0;
35 35
  @merge3
36 36
    reserve %8 9 8;
37 37
    store w64 0 %8 0;
38 -
    blit %0 %8 9;
38 +
    blit %0 %8 9 8;
39 39
    ret %0;
40 40
}