compiler: Construct initialized container lengths
91c342336358f9fa25b611c39ef34bf8c45a066dadf104694e9892566032dc55
1 parent
82bcbace
lib/std/lang/lower.rad
+18 -10
| 2478 | 2478 | let lenReg = nextReg(self); |
|
| 2479 | 2479 | emitLoadW32At(self, lenReg, sliceReg, SLICE_LEN_OFFSET); |
|
| 2480 | 2480 | return il::Val::Reg(lenReg); |
|
| 2481 | 2481 | } |
|
| 2482 | 2482 | ||
| 2483 | + | /// Return a fixed array length or load the length from a slice value. |
|
| 2484 | + | unsafe fn containerLength 'arena 'phase 'function ( |
|
| 2485 | + | self: &mut FnLowerer 'arena 'phase 'function, |
|
| 2486 | + | base: il::Reg, |
|
| 2487 | + | length: ?u32 |
|
| 2488 | + | ) -> il::Val where 'arena: 'phase, 'phase: 'function { |
|
| 2489 | + | if let len = length { // Array (length is known). |
|
| 2490 | + | return il::Val::Imm(len as i64); |
|
| 2491 | + | } |
|
| 2492 | + | // Slice (length must be loaded). |
|
| 2493 | + | return loadSliceLen(self, base); |
|
| 2494 | + | } |
|
| 2495 | + | ||
| 2483 | 2496 | /// Load the capacity from a slice value. |
|
| 2484 | 2497 | unsafe fn loadSliceCap 'arena 'phase 'function (self: &mut FnLowerer 'arena 'phase 'function, sliceReg: il::Reg) -> il::Val where 'arena: 'phase, 'phase: 'function { |
|
| 2485 | 2498 | let capReg = nextReg(self); |
|
| 2486 | 2499 | emitLoadW32At(self, capReg, sliceReg, SLICE_CAP_OFFSET); |
|
| 2487 | 2500 | return il::Val::Reg(capReg); |
| 5111 | 5124 | ) -> SliceRangeResult throws (LowerError) where 'arena: 'phase, 'phase: 'function { |
|
| 5112 | 5125 | let baseVal = try lowerExpr(self, container); |
|
| 5113 | 5126 | let baseReg = emitValToReg(self, baseVal); |
|
| 5114 | 5127 | ||
| 5115 | 5128 | // Extract data pointer and container length. |
|
| 5129 | + | // Slice from array: the base register is the data pointer. |
|
| 5116 | 5130 | let mut dataReg = baseReg; |
|
| 5117 | - | let mut containerLen: il::Val = undefined; |
|
| 5118 | - | if let cap = info.capacity { // Slice from array. |
|
| 5119 | - | set containerLen = il::Val::Imm(cap as i64); |
|
| 5120 | - | } else { // Slice from slice. |
|
| 5131 | + | if info.capacity == nil { // Slice from slice. |
|
| 5121 | 5132 | set dataReg = loadSlicePtr(self, baseReg); |
|
| 5122 | - | set containerLen = loadSliceLen(self, baseReg); |
|
| 5123 | 5133 | } |
|
| 5134 | + | let containerLen = containerLength(self, baseReg, info.capacity); |
|
| 5124 | 5135 | ||
| 5125 | 5136 | // Compute range bounds. |
|
| 5126 | 5137 | let mut startVal: il::Val = il::Val::Imm(0); |
|
| 5127 | 5138 | if let start = range.start { |
|
| 5128 | 5139 | set startVal = try lowerExpr(self, start); |
| 5873 | 5884 | case resolver::ForLoopInfo::Collection { elemType, length, bindingName, indexName } => { |
|
| 5874 | 5885 | let containerVal = try lowerExpr(self, f.iterable); |
|
| 5875 | 5886 | let containerReg = emitValToReg(self, containerVal); |
|
| 5876 | 5887 | ||
| 5877 | 5888 | let mut dataReg = containerReg; |
|
| 5878 | - | let mut lengthVal: il::Val = undefined; |
|
| 5879 | - | if let len = length { // Array (length is known). |
|
| 5880 | - | set lengthVal = il::Val::Imm(len as i64); |
|
| 5881 | - | } else { // Slice (length must be loaded). |
|
| 5882 | - | set lengthVal = loadSliceLen(self, containerReg); |
|
| 5889 | + | let lengthVal = containerLength(self, containerReg, length); |
|
| 5890 | + | if length == nil { |
|
| 5883 | 5891 | set dataReg = loadSlicePtr(self, containerReg); |
|
| 5884 | 5892 | } |
|
| 5885 | 5893 | // Declare index value binidng. |
|
| 5886 | 5894 | let idxVar = newVar(self, indexName, il::Type::W32, false, il::Val::Imm(0)); |
|
| 5887 | 5895 |
test/tests/container.length.paths.rad
added
+42 -0
| 1 | + | //! returns: 0 |
|
| 2 | + | ||
| 3 | + | /// Sum a slice and check its iteration index. |
|
| 4 | + | fn sum(values: &[u32]) -> u32 { |
|
| 5 | + | let mut result: u32 = 0; |
|
| 6 | + | for value, index in values { |
|
| 7 | + | assert value == values[index]; |
|
| 8 | + | set result += value; |
|
| 9 | + | } |
|
| 10 | + | return result; |
|
| 11 | + | } |
|
| 12 | + | ||
| 13 | + | /// Compare array and slice lengths through every valid subrange. |
|
| 14 | + | @default fn main() -> u32 { |
|
| 15 | + | let data: [u32; 6] = [1, 2, 3, 4, 5, 6]; |
|
| 16 | + | let empty: [u32; 0] = []; |
|
| 17 | + | let mut total: u32 = 0; |
|
| 18 | + | for value, index in data { |
|
| 19 | + | assert value == index + 1; |
|
| 20 | + | set total += value; |
|
| 21 | + | } |
|
| 22 | + | assert total == 21; |
|
| 23 | + | for value in empty { |
|
| 24 | + | assert false; |
|
| 25 | + | } |
|
| 26 | + | assert sum(&empty[..]) == 0; |
|
| 27 | + | for start in 0..7 { |
|
| 28 | + | for end in start..7 { |
|
| 29 | + | let mut expected: u32 = 0; |
|
| 30 | + | for index in start..end { |
|
| 31 | + | set expected += index + 1; |
|
| 32 | + | } |
|
| 33 | + | assert sum(&data[start..end]) == expected; |
|
| 34 | + | let all: 'whole = &data[..] in { |
|
| 35 | + | assert sum(&all[start..end]) == expected; |
|
| 36 | + | assert sum(&all[start..]) == 21 - start * (start + 1) / 2; |
|
| 37 | + | assert sum(&all[..end]) == end * (end + 1) / 2; |
|
| 38 | + | } |
|
| 39 | + | } |
|
| 40 | + | } |
|
| 41 | + | return 0; |
|
| 42 | + | } |