compiler: Construct initialized element pointer results
7988f48b4d3bd79e2c25b3aedab82fb3f9a6f42c16c22d83aed9e159ccad50a0
1 parent
f04dd59a
lib/std/lang/lower.rad
+9 -10
| 5321 | 5321 | let subjectTy = resolver::autoDeref(containerTy); |
|
| 5322 | 5322 | let baseVal = try lowerExpr(self, container); |
|
| 5323 | 5323 | let indexVal = try lowerExpr(self, index); |
|
| 5324 | 5324 | let baseReg = emitValToReg(self, baseVal); |
|
| 5325 | 5325 | ||
| 5326 | - | let mut dataReg = baseReg; |
|
| 5327 | - | let mut elemType: resolver::Type = undefined; |
|
| 5328 | - | ||
| 5329 | 5326 | match subjectTy { |
|
| 5330 | 5327 | case resolver::Type::Slice { item, .. } => { |
|
| 5331 | - | set elemType = *item; |
|
| 5328 | + | let elemType = *item; |
|
| 5332 | 5329 | let sliceLen = loadSliceLen(self, baseReg); |
|
| 5333 | 5330 | // Runtime safety check: index must be strictly less than slice length. |
|
| 5334 | 5331 | try emitTrapUnlessCmp(self, il::CmpOp::Ult, il::Type::W32, indexVal, sliceLen); |
|
| 5335 | 5332 | ||
| 5336 | - | set dataReg = loadSlicePtr(self, baseReg); |
|
| 5333 | + | let dataReg = loadSlicePtr(self, baseReg); |
|
| 5334 | + | let elemLayout = resolver::getTypeLayout(elemType); |
|
| 5335 | + | let elemReg = emitElem(self, elemLayout.size, dataReg, indexVal); |
|
| 5336 | + | return ElemPtrResult { elemReg, elemType }; |
|
| 5337 | 5337 | } |
|
| 5338 | 5338 | case resolver::Type::Array(arrInfo) => { |
|
| 5339 | - | set elemType = *arrInfo.item; |
|
| 5339 | + | let elemType = *arrInfo.item; |
|
| 5340 | 5340 | // Runtime safety check: index must be strictly less than array length. |
|
| 5341 | 5341 | // Skip when the index is a compile-time constant, since we check |
|
| 5342 | 5342 | // that in the resolver. |
|
| 5343 | 5343 | if not resolver::isConstExpr(self.low.resolver, index) { |
|
| 5344 | 5344 | let arrLen = il::Val::Imm(arrInfo.length as i64); |
|
| 5345 | 5345 | try emitTrapUnlessCmp(self, il::CmpOp::Ult, il::Type::W32, indexVal, arrLen); |
|
| 5346 | 5346 | } |
|
| 5347 | + | let elemLayout = resolver::getTypeLayout(elemType); |
|
| 5348 | + | let elemReg = emitElem(self, elemLayout.size, baseReg, indexVal); |
|
| 5349 | + | return ElemPtrResult { elemReg, elemType }; |
|
| 5347 | 5350 | } |
|
| 5348 | 5351 | else => throw LowerError::ExpectedSliceOrArray, |
|
| 5349 | 5352 | } |
|
| 5350 | - | let elemLayout = resolver::getTypeLayout(elemType); |
|
| 5351 | - | let elemReg = emitElem(self, elemLayout.size, dataReg, indexVal); |
|
| 5352 | - | ||
| 5353 | - | return ElemPtrResult { elemReg, elemType }; |
|
| 5354 | 5353 | } |
|
| 5355 | 5354 | ||
| 5356 | 5355 | /// Lower a dereference expression. |
|
| 5357 | 5356 | /// Handles both pointer deref (`*ptr`) and record deref (`*r` on single-field |
|
| 5358 | 5357 | /// unlabeled record). Both read at offset 0 using the resolver-assigned type. |
test/tests/element.pointer.widths.rad
added
+60 -0
| 1 | + | //! returns: 0 |
|
| 2 | + | ||
| 3 | + | /// Store and load one byte through a slice. |
|
| 4 | + | fn byteItem(items: &mut [u8], index: u32, value: u8) -> u8 { |
|
| 5 | + | set items[index] = value; |
|
| 6 | + | return items[index]; |
|
| 7 | + | } |
|
| 8 | + | ||
| 9 | + | /// Store and load one full-width word through a slice. |
|
| 10 | + | fn wordItem(items: &mut [u64], index: u32, value: u64) -> u64 { |
|
| 11 | + | set items[index] = value; |
|
| 12 | + | return items[index]; |
|
| 13 | + | } |
|
| 14 | + | ||
| 15 | + | /// An aggregate with two independently checked fields. |
|
| 16 | + | record Pair: Copy { |
|
| 17 | + | /// First word. |
|
| 18 | + | first: u32, |
|
| 19 | + | /// Second word. |
|
| 20 | + | second: u64, |
|
| 21 | + | } |
|
| 22 | + | ||
| 23 | + | /// Store and load an aggregate through a slice. |
|
| 24 | + | fn pairItem(items: &mut [Pair], index: u32, value: Pair) -> Pair { |
|
| 25 | + | set items[index] = value; |
|
| 26 | + | return items[index]; |
|
| 27 | + | } |
|
| 28 | + | ||
| 29 | + | /// Check dynamic array and slice addressing at each element boundary. |
|
| 30 | + | @default fn main() -> u32 { |
|
| 31 | + | let mut bytes: [u8; 5] = [0; 5]; |
|
| 32 | + | let mut words: [u64; 5] = [0; 5]; |
|
| 33 | + | let mut pairs: [Pair; 5] = [Pair { first: 0, second: 0 }; 5]; |
|
| 34 | + | for index in 0..5 { |
|
| 35 | + | set bytes[index] = index as u8; |
|
| 36 | + | set words[index] = 0x100000000 + index as u64; |
|
| 37 | + | set pairs[index] = Pair { first: index, second: words[index] }; |
|
| 38 | + | } |
|
| 39 | + | for index in 0..5 { |
|
| 40 | + | assert bytes[index] == index as u8; |
|
| 41 | + | assert words[index] == 0x100000000 + index as u64; |
|
| 42 | + | assert pairs[index].first == index; |
|
| 43 | + | assert pairs[index].second == words[index]; |
|
| 44 | + | assert byteItem(&mut bytes[..], index, 255 - index as u8) == 255 - index as u8; |
|
| 45 | + | assert wordItem(&mut words[..], index, 0x200000000 + index as u64) == 0x200000000 + index as u64; |
|
| 46 | + | let value = Pair { first: index + 10, second: words[index] }; |
|
| 47 | + | let result = pairItem(&mut pairs[..], index, value); |
|
| 48 | + | assert result.first == value.first; |
|
| 49 | + | assert result.second == value.second; |
|
| 50 | + | } |
|
| 51 | + | for index in 0..5 { |
|
| 52 | + | assert bytes[index] == 255 - index as u8; |
|
| 53 | + | assert words[index] == 0x200000000 + index as u64; |
|
| 54 | + | assert pairs[index].first == index + 10; |
|
| 55 | + | assert pairs[index].second == words[index]; |
|
| 56 | + | } |
|
| 57 | + | assert bytes[0] == 255; |
|
| 58 | + | assert bytes[4] == 251; |
|
| 59 | + | return 0; |
|
| 60 | + | } |