compiler: Check type classification and payload binding

548a8aa330a7c090b94cc68f62695616121ed66396ece433c4f26abcb64b23b7
Alexis Sellier committed ago 1 parent 07646b5d
lib/std/lang/lower.rad +14 -10
2536 2536
    return il::Val::Reg(capReg);
2537 2537
}
2538 2538
2539 2539
/// Emit a load instruction for a scalar value at `src` plus `offset`.
2540 2540
/// For reading values that may be aggregates, use `emitRead` instead.
2541 -
unsafe fn emitLoad 'arena 'phase 'function (self: &mut FnLowerer 'arena 'phase 'function, src: il::Reg, offset: i32, typ: resolver::Type) -> il::Val where 'arena: 'phase, 'phase: 'function {
2541 +
fn emitLoad 'arena 'phase 'function (self: &mut FnLowerer 'arena 'phase 'function, src: il::Reg, offset: i32, typ: resolver::Type) -> il::Val where 'arena: 'phase, 'phase: 'function {
2542 2542
    let dst = nextReg(self);
2543 2543
    let ilTyp = ilType(self.low, typ);
2544 2544
2545 2545
    if isSignedType(typ) {
2546 2546
        emit(self, il::Instr::Sload { typ: ilTyp, dst, src, offset });
2550 2550
    return il::Val::Reg(dst);
2551 2551
}
2552 2552
2553 2553
/// Read a value from memory at `src` plus `offset`. Aggregates are represented
2554 2554
/// as pointers, so we return the address directly. Scalars are loaded via [`emitLoad`].
2555 -
unsafe fn emitRead 'arena 'phase 'function (self: &mut FnLowerer 'arena 'phase 'function, src: il::Reg, offset: i32, typ: resolver::Type) -> il::Val where 'arena: 'phase, 'phase: 'function {
2555 +
fn emitRead 'arena 'phase 'function (self: &mut FnLowerer 'arena 'phase 'function, src: il::Reg, offset: i32, typ: resolver::Type) -> il::Val where 'arena: 'phase, 'phase: 'function {
2556 2556
    if isAggregateType(typ) {
2557 2557
        let ptr = emitPtrOffset(self, src, offset);
2558 2558
        return il::Val::Reg(ptr);
2559 2559
    }
2560 2560
    return emitLoad(self, src, offset, typ);
3464 3464
    let op = il::BinOp::Eq if isEq else il::BinOp::Ne;
3465 3465
    return emitTypedBinOp(self, op, cmpType, il::Val::Reg(cmpReg), il::Val::Imm(0));
3466 3466
}
3467 3467
3468 3468
/// Load the payload value from a tagged value aggregate at the given offset.
3469 -
unsafe fn tvalPayloadVal 'arena 'phase 'function (self: &mut FnLowerer 'arena 'phase 'function, base: il::Reg, payload: resolver::Type, valOffset: i32) -> il::Val where 'arena: 'phase, 'phase: 'function {
3469 +
fn tvalPayloadVal 'arena 'phase 'function (self: &mut FnLowerer 'arena 'phase 'function, base: il::Reg, payload: resolver::Type, valOffset: i32) -> il::Val where 'arena: 'phase, 'phase: 'function {
3470 3470
    if payload == resolver::Type::Void {
3471 3471
        return il::Val::Undef;
3472 3472
    }
3473 3473
    return emitRead(self, base, valOffset, payload);
3474 3474
}
3475 3475
3476 3476
/// Select the payload value or address for the declared match mode.
3477 -
unsafe fn tvalPayloadBinding 'arena 'phase 'function (
3477 +
fn tvalPayloadBinding 'arena 'phase 'function (
3478 3478
    self: &mut FnLowerer 'arena 'phase 'function,
3479 3479
    base: il::Reg,
3480 3480
    bindType: resolver::Type,
3481 3481
    matchBy: resolver::MatchBy,
3482 3482
    valOffset: i32
3488 3488
            return il::Val::Reg(emitPtrOffset(self, base, valOffset)),
3489 3489
    }
3490 3490
}
3491 3491
3492 3492
/// Bind a variable to a tagged value's payload.
3493 -
unsafe fn bindPayloadVariable 'arena 'phase 'function (
3493 +
fn bindPayloadVariable 'arena 'phase 'function (
3494 3494
    self: &mut FnLowerer 'arena 'phase 'function,
3495 3495
    name: *[u8],
3496 3496
    subjectVal: il::Val,
3497 3497
    bindType: resolver::Type,
3498 3498
    matchBy: resolver::MatchBy,
4355 4355
    }
4356 4356
    return ty;
4357 4357
}
4358 4358
4359 4359
/// Check if a resolver type lowers to an aggregate in memory.
4360 -
unsafe fn isAggregateType(typ: resolver::Type) -> bool {
4360 +
fn isAggregateType(typ: resolver::Type) -> bool {
4361 4361
    match typ {
4362 4362
        case resolver::Type::Slice { .. },
4363 4363
             resolver::Type::TraitObject { .. },
4364 4364
             resolver::Type::Session(_) => return true,
4365 4365
        case resolver::Type::Optional(resolver::Type::Pointer { .. }) => {
4370 4370
            // All other optionals, including optional slices, are aggregates.
4371 4371
            return true;
4372 4372
        }
4373 4373
        case resolver::Type::Nominal(_) => {
4374 4374
            // Void unions are small enough to pass by value.
4375 -
            return not resolver::isVoidUnion(typ);
4375 +
            unsafe {
4376 +
                return not resolver::isVoidUnion(typ);
4377 +
            }
4376 4378
        }
4377 4379
        case resolver::Type::Array(_),
4378 4380
             resolver::Type::Nil => return true,
4379 4381
        else => return false,
4380 4382
    }
7746 7748
/// are used. If a Radiance type doesn't fit in a machine word, it is passed
7747 7749
/// by reference.
7748 7750
///
7749 7751
/// The IL doesn't track signedness - that's encoded in the instructions
7750 7752
/// (e.g., Slt vs Ult).
7751 -
unsafe fn ilType 'arena 'phase (self: &mut Lowerer 'arena 'phase, typ: resolver::Type) -> il::Type where 'arena: 'phase {
7753 +
fn ilType 'arena 'phase (self: &mut Lowerer 'arena 'phase, typ: resolver::Type) -> il::Type where 'arena: 'phase {
7752 7754
    match typ {
7753 7755
        case resolver::Type::Bool,
7754 7756
             resolver::Type::I8,
7755 7757
             resolver::Type::U8 => return il::Type::W8,
7756 7758
        case resolver::Type::I16,
7766 7768
             resolver::Type::Optional(_),
7767 7769
             resolver::Type::Fn(_),
7768 7770
             resolver::Type::Session(_),
7769 7771
             resolver::Type::Cell { .. } => return il::Type::W64,
7770 7772
        case resolver::Type::Nominal(_) => {
7771 -
            if resolver::isVoidUnion(typ) {
7772 -
                return il::Type::W8;
7773 +
            unsafe {
7774 +
                if resolver::isVoidUnion(typ) {
7775 +
                    return il::Type::W8;
7776 +
                }
7773 7777
            }
7774 7778
            return il::Type::W64;
7775 7779
        }
7776 7780
        case resolver::Type::Void, resolver::Type::Never => return il::Type::W64,
7777 7781
        // [`Type::Int`] is the type of unsuffixed integer literals and their