compiler: Check scalar IL emission helpers

f9a33a9346323481474221d09381d498e73b66156515e051036cc2e92e01df91
Alexis Sellier committed ago 1 parent ad670606
lib/std/lang/lower.rad +20 -20
2456 2456
2457 2457
    try emitBr(self, condReg, thenBlock, elseBlock);
2458 2458
}
2459 2459
2460 2460
/// Emit a 32-bit store instruction at the given offset.
2461 -
unsafe fn emitStoreW32At 'arena 'phase 'function (self: &mut FnLowerer 'arena 'phase 'function, src: il::Val, dst: il::Reg, offset: i32) where 'arena: 'phase, 'phase: 'function {
2461 +
fn emitStoreW32At 'arena 'phase 'function (self: &mut FnLowerer 'arena 'phase 'function, src: il::Val, dst: il::Reg, offset: i32) where 'arena: 'phase, 'phase: 'function {
2462 2462
    emit(self, il::Instr::Store { typ: il::Type::W32, src, dst, offset });
2463 2463
}
2464 2464
2465 2465
/// Emit a 32-bit load instruction at the given offset.
2466 -
unsafe fn emitLoadW32At 'arena 'phase 'function (self: &mut FnLowerer 'arena 'phase 'function, dst: il::Reg, src: il::Reg, offset: i32) where 'arena: 'phase, 'phase: 'function {
2466 +
fn emitLoadW32At 'arena 'phase 'function (self: &mut FnLowerer 'arena 'phase 'function, dst: il::Reg, src: il::Reg, offset: i32) where 'arena: 'phase, 'phase: 'function {
2467 2467
    emit(self, il::Instr::Load { typ: il::Type::W32, dst, src, offset });
2468 2468
}
2469 2469
2470 2470
/// Emit an 8-bit store instruction at the given offset.
2471 -
unsafe fn emitStoreW8At 'arena 'phase 'function (self: &mut FnLowerer 'arena 'phase 'function, src: il::Val, dst: il::Reg, offset: i32) where 'arena: 'phase, 'phase: 'function {
2471 +
fn emitStoreW8At 'arena 'phase 'function (self: &mut FnLowerer 'arena 'phase 'function, src: il::Val, dst: il::Reg, offset: i32) where 'arena: 'phase, 'phase: 'function {
2472 2472
    emit(self, il::Instr::Store { typ: il::Type::W8, src, dst, offset });
2473 2473
}
2474 2474
2475 2475
/// Emit an 8-bit load instruction at the given offset.
2476 -
unsafe fn emitLoadW8At 'arena 'phase 'function (self: &mut FnLowerer 'arena 'phase 'function, dst: il::Reg, src: il::Reg, offset: i32) where 'arena: 'phase, 'phase: 'function {
2476 +
fn emitLoadW8At 'arena 'phase 'function (self: &mut FnLowerer 'arena 'phase 'function, dst: il::Reg, src: il::Reg, offset: i32) where 'arena: 'phase, 'phase: 'function {
2477 2477
    emit(self, il::Instr::Load { typ: il::Type::W8, dst, src, offset });
2478 2478
}
2479 2479
2480 2480
/// Emit a 64-bit store instruction at the given offset.
2481 -
unsafe fn emitStoreW64At 'arena 'phase 'function (self: &mut FnLowerer 'arena 'phase 'function, src: il::Val, dst: il::Reg, offset: i32) where 'arena: 'phase, 'phase: 'function {
2481 +
fn emitStoreW64At 'arena 'phase 'function (self: &mut FnLowerer 'arena 'phase 'function, src: il::Val, dst: il::Reg, offset: i32) where 'arena: 'phase, 'phase: 'function {
2482 2482
    emit(self, il::Instr::Store { typ: il::Type::W64, src, dst, offset });
2483 2483
}
2484 2484
2485 2485
/// Emit a 64-bit load instruction at the given offset.
2486 -
unsafe fn emitLoadW64At 'arena 'phase 'function (self: &mut FnLowerer 'arena 'phase 'function, dst: il::Reg, src: il::Reg, offset: i32) where 'arena: 'phase, 'phase: 'function {
2486 +
fn emitLoadW64At 'arena 'phase 'function (self: &mut FnLowerer 'arena 'phase 'function, dst: il::Reg, src: il::Reg, offset: i32) where 'arena: 'phase, 'phase: 'function {
2487 2487
    emit(self, il::Instr::Load { typ: il::Type::W64, dst, src, offset });
2488 2488
}
2489 2489
2490 2490
/// Load a tag from memory at `src` plus `offset` with the given IL type.
2491 -
unsafe fn loadTag 'arena 'phase 'function (self: &mut FnLowerer 'arena 'phase 'function, src: il::Reg, offset: i32, tagType: il::Type) -> il::Val where 'arena: 'phase, 'phase: 'function {
2491 +
fn loadTag 'arena 'phase 'function (self: &mut FnLowerer 'arena 'phase 'function, src: il::Reg, offset: i32, tagType: il::Type) -> il::Val where 'arena: 'phase, 'phase: 'function {
2492 2492
    let dst = nextReg(self);
2493 2493
    emit(self, il::Instr::Load { typ: tagType, dst, src, offset });
2494 2494
    return il::Val::Reg(dst);
2495 2495
}
2496 2496
2497 2497
/// Load the data pointer from a slice value.
2498 -
unsafe fn loadSlicePtr 'arena 'phase 'function (self: &mut FnLowerer 'arena 'phase 'function, sliceReg: il::Reg) -> il::Reg where 'arena: 'phase, 'phase: 'function {
2498 +
fn loadSlicePtr 'arena 'phase 'function (self: &mut FnLowerer 'arena 'phase 'function, sliceReg: il::Reg) -> il::Reg where 'arena: 'phase, 'phase: 'function {
2499 2499
    let ptrReg = nextReg(self);
2500 2500
    emitLoadW64At(self, ptrReg, sliceReg, SLICE_PTR_OFFSET);
2501 2501
    return ptrReg;
2502 2502
}
2503 2503
2504 2504
/// Load the length from a slice value.
2505 -
unsafe fn loadSliceLen 'arena 'phase 'function (self: &mut FnLowerer 'arena 'phase 'function, sliceReg: il::Reg) -> il::Val where 'arena: 'phase, 'phase: 'function {
2505 +
fn loadSliceLen 'arena 'phase 'function (self: &mut FnLowerer 'arena 'phase 'function, sliceReg: il::Reg) -> il::Val where 'arena: 'phase, 'phase: 'function {
2506 2506
    let lenReg = nextReg(self);
2507 2507
    emitLoadW32At(self, lenReg, sliceReg, SLICE_LEN_OFFSET);
2508 2508
    return il::Val::Reg(lenReg);
2509 2509
}
2510 2510
2511 2511
/// Return a fixed array length or load the length from a slice value.
2512 -
unsafe fn containerLength 'arena 'phase 'function (
2512 +
fn containerLength 'arena 'phase 'function (
2513 2513
    self: &mut FnLowerer 'arena 'phase 'function,
2514 2514
    base: il::Reg,
2515 2515
    length: ?u32
2516 2516
) -> il::Val where 'arena: 'phase, 'phase: 'function {
2517 2517
    if let len = length { // Array (length is known).
2520 2520
    // Slice (length must be loaded).
2521 2521
    return loadSliceLen(self, base);
2522 2522
}
2523 2523
2524 2524
/// Load the capacity from a slice value.
2525 -
unsafe fn loadSliceCap 'arena 'phase 'function (self: &mut FnLowerer 'arena 'phase 'function, sliceReg: il::Reg) -> il::Val where 'arena: 'phase, 'phase: 'function {
2525 +
fn loadSliceCap 'arena 'phase 'function (self: &mut FnLowerer 'arena 'phase 'function, sliceReg: il::Reg) -> il::Val where 'arena: 'phase, 'phase: 'function {
2526 2526
    let capReg = nextReg(self);
2527 2527
    emitLoadW32At(self, capReg, sliceReg, SLICE_CAP_OFFSET);
2528 2528
    return il::Val::Reg(capReg);
2529 2529
}
2530 2530
3406 3406
        else => return false,
3407 3407
    }
3408 3408
}
3409 3409
3410 3410
/// Load the tag byte from a tagged value aggregate (optionals and unions).
3411 -
unsafe fn tvalTagReg 'arena 'phase 'function (self: &mut FnLowerer 'arena 'phase 'function, base: il::Reg) -> il::Reg where 'arena: 'phase, 'phase: 'function {
3411 +
fn tvalTagReg 'arena 'phase 'function (self: &mut FnLowerer 'arena 'phase 'function, base: il::Reg) -> il::Reg where 'arena: 'phase, 'phase: 'function {
3412 3412
    let tagReg = nextReg(self);
3413 3413
    emitLoadW8At(self, tagReg, base, TVAL_TAG_OFFSET);
3414 3414
    return tagReg;
3415 3415
}
3416 3416
3417 3417
/// Load the tag word from a result aggregate.
3418 -
unsafe fn resultTagReg 'arena 'phase 'function (self: &mut FnLowerer 'arena 'phase 'function, base: il::Reg) -> il::Reg where 'arena: 'phase, 'phase: 'function {
3418 +
fn resultTagReg 'arena 'phase 'function (self: &mut FnLowerer 'arena 'phase 'function, base: il::Reg) -> il::Reg where 'arena: 'phase, 'phase: 'function {
3419 3419
    let tagReg = nextReg(self);
3420 3420
    emitLoadW64At(self, tagReg, base, TVAL_TAG_OFFSET);
3421 3421
    return tagReg;
3422 3422
}
3423 3423
3424 3424
/// Get the register to compare against `0` for optional `nil` checking.
3425 3425
/// For null-ptr-optimized types, loads the data pointer, or returns it
3426 3426
/// directly for scalar pointers. For aggregates, returns the tag register.
3427 -
unsafe fn optionalNilReg 'arena 'phase 'function (self: &mut FnLowerer 'arena 'phase 'function, val: il::Val, typ: resolver::Type) -> il::Reg throws (LowerError) where 'arena: 'phase, 'phase: 'function {
3427 +
fn optionalNilReg 'arena 'phase 'function (self: &mut FnLowerer 'arena 'phase 'function, val: il::Val, typ: resolver::Type) -> il::Reg throws (LowerError) where 'arena: 'phase, 'phase: 'function {
3428 3428
    let reg = emitValToReg(self, val);
3429 3429
3430 3430
    match typ {
3431 3431
        case resolver::Type::Optional(resolver::Type::Slice { .. }) => {
3432 3432
            let ptrReg = nextReg(self);
4425 4425
    let layout = resolver::getTypeLayout(typ);
4426 4426
    return emitReserveLayout(self, layout);
4427 4427
}
4428 4428
4429 4429
/// Reserve stack storage with an explicit layout.
4430 -
unsafe fn emitReserveLayout 'arena 'phase 'function (self: &mut FnLowerer 'arena 'phase 'function, layout: resolver::Layout) -> il::Reg where 'arena: 'phase, 'phase: 'function {
4430 +
fn emitReserveLayout 'arena 'phase 'function (self: &mut FnLowerer 'arena 'phase 'function, layout: resolver::Layout) -> il::Reg where 'arena: 'phase, 'phase: 'function {
4431 4431
    let dst = nextReg(self);
4432 4432
4433 4433
    emit(self, il::Instr::Reserve {
4434 4434
        dst,
4435 4435
        size: il::Val::Imm(layout.size as i64),
4611 4611
    });
4612 4612
    return il::Val::Reg(slot);
4613 4613
}
4614 4614
4615 4615
/// Compute a field pointer by adding a byte offset to a base address.
4616 -
unsafe fn emitPtrOffset 'arena 'phase 'function (self: &mut FnLowerer 'arena 'phase 'function, base: il::Reg, offset: i32) -> il::Reg where 'arena: 'phase, 'phase: 'function {
4616 +
fn emitPtrOffset 'arena 'phase 'function (self: &mut FnLowerer 'arena 'phase 'function, base: il::Reg, offset: i32) -> il::Reg where 'arena: 'phase, 'phase: 'function {
4617 4617
    if offset == 0 {
4618 4618
        return base;
4619 4619
    }
4620 4620
    let dst = nextReg(self);
4621 4621
4629 4629
    return dst;
4630 4630
}
4631 4631
4632 4632
/// Emit an element address computation for array/slice indexing.
4633 4633
/// Computes: `base + idx * stride`.
4634 -
unsafe fn emitElem 'arena 'phase 'function (self: &mut FnLowerer 'arena 'phase 'function, stride: u32, base: il::Reg, idx: il::Val) -> il::Reg where 'arena: 'phase, 'phase: 'function {
4634 +
fn emitElem 'arena 'phase 'function (self: &mut FnLowerer 'arena 'phase 'function, stride: u32, base: il::Reg, idx: il::Val) -> il::Reg where 'arena: 'phase, 'phase: 'function {
4635 4635
    // If index is zero, return base directly.
4636 4636
    if idx == il::Val::Imm(0) {
4637 4637
        return base;
4638 4638
    }
4639 4639
    // If stride is `1`, skip the multiply.
4670 4670
    });
4671 4671
    return dst;
4672 4672
}
4673 4673
4674 4674
/// Emit a typed binary operation, returning the result as a value.
4675 -
unsafe fn emitTypedBinOp 'arena 'phase 'function (self: &mut FnLowerer 'arena 'phase 'function, op: il::BinOp, typ: il::Type, a: il::Val, b: il::Val) -> il::Val where 'arena: 'phase, 'phase: 'function {
4675 +
fn emitTypedBinOp 'arena 'phase 'function (self: &mut FnLowerer 'arena 'phase 'function, op: il::BinOp, typ: il::Type, a: il::Val, b: il::Val) -> il::Val where 'arena: 'phase, 'phase: 'function {
4676 4676
    let dst = nextReg(self);
4677 4677
    emit(self, il::Instr::BinOp { op, typ, dst, a, b });
4678 4678
    return il::Val::Reg(dst);
4679 4679
}
4680 4680
4690 4690
    let binOp = il::BinOp::Eq if op == ast::BinaryOp::Eq else il::BinOp::Ne;
4691 4691
    return emitTypedBinOp(self, binOp, il::Type::W8, tag, il::Val::Imm(tagIdx));
4692 4692
}
4693 4693
4694 4694
/// Logical "and" between two values. Returns the result in a register.
4695 -
unsafe fn emitLogicalAnd 'arena 'phase 'function (self: &mut FnLowerer 'arena 'phase 'function, left: ?il::Val, right: il::Val) -> il::Val where 'arena: 'phase, 'phase: 'function {
4695 +
fn emitLogicalAnd 'arena 'phase 'function (self: &mut FnLowerer 'arena 'phase 'function, left: ?il::Val, right: il::Val) -> il::Val where 'arena: 'phase, 'phase: 'function {
4696 4696
    let prev = left else {
4697 4697
        return right;
4698 4698
    };
4699 4699
    return emitTypedBinOp(self, il::BinOp::And, il::Type::W32, prev, right);
4700 4700
}
6069 6069
6070 6070
    try emitRetVal(self, resultVal);
6071 6071
}
6072 6072
6073 6073
/// Ensure a value is in a register (eg. for branch conditions).
6074 -
unsafe fn emitValToReg 'arena 'phase 'function (self: &mut FnLowerer 'arena 'phase 'function, val: il::Val) -> il::Reg where 'arena: 'phase, 'phase: 'function {
6074 +
fn emitValToReg 'arena 'phase 'function (self: &mut FnLowerer 'arena 'phase 'function, val: il::Val) -> il::Reg where 'arena: 'phase, 'phase: 'function {
6075 6075
    match val {
6076 6076
        case il::Val::Reg(r) => return r,
6077 6077
        case il::Val::Imm(_), il::Val::DataSym(_), il::Val::FnAddr(_) => {
6078 6078
            let dst = nextReg(self);
6079 6079
            emit(self, il::Instr::Copy { dst, val });