compiler: Check type classification and payload binding
548a8aa330a7c090b94cc68f62695616121ed66396ece433c4f26abcb64b23b7
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 |