compiler: Check edge argument storage construction
b0694d2637f1c490c87e71f4a65f3f713b1223800f9501d99c588697bb54d66b
1 parent
6a788bde
lib/std/lang/lower.rad
+13 -10
| 2869 | 2869 | return block; |
|
| 2870 | 2870 | } |
|
| 2871 | 2871 | ||
| 2872 | 2872 | /// Copy complete values into the lowering arena. |
|
| 2873 | 2873 | unsafe fn copyVals 'arena 'phase 'function (self: &mut FnLowerer 'arena 'phase 'function, values: &[il::Val]) -> *unsafe mut [il::Val] throws (LowerError) where 'arena: 'phase, 'phase: 'function { |
|
| 2874 | + | let result = valueStorage(values, values.len, alloc::arenaAllocator(self.arena)); |
|
| 2875 | + | return (&mut result[..]) as *unsafe mut [il::Val]; |
|
| 2876 | + | } |
|
| 2877 | + | ||
| 2878 | + | /// Copy a value prefix into owned storage and initialize the suffix to Undef. |
|
| 2879 | + | fn valueStorage(values: &[il::Val], length: u32, allocator: alloc::Allocator) -> *mut [il::Val] { |
|
| 2880 | + | assert length >= values.len, "valueStorage: length is smaller than value prefix"; |
|
| 2874 | 2881 | let mut result: *mut [il::Val] = &mut []; |
|
| 2875 | 2882 | for value in values { |
|
| 2876 | - | result.append(value, alloc::arenaAllocator(self.arena)); |
|
| 2883 | + | result.append(value, allocator); |
|
| 2877 | 2884 | } |
|
| 2878 | - | return (&mut result[..]) as *unsafe mut [il::Val]; |
|
| 2885 | + | for i in values.len..length { |
|
| 2886 | + | result.append(il::Val::Undef, allocator); |
|
| 2887 | + | } |
|
| 2888 | + | return result; |
|
| 2879 | 2889 | } |
|
| 2880 | 2890 | ||
| 2881 | 2891 | /// Allocate a single-value slice in the lowering arena. |
|
| 2882 | 2892 | unsafe fn allocVal 'arena 'phase 'function (self: &mut FnLowerer 'arena 'phase 'function, val: il::Val) -> *unsafe mut [il::Val] throws (LowerError) where 'arena: 'phase, 'phase: 'function { |
|
| 2883 | 2893 | let values = [val]; |
| 3272 | 3282 | /// Grow an args array to hold at least the given capacity. |
|
| 3273 | 3283 | unsafe fn growArgs(args: *unsafe mut [il::Val], capacity: u32, allocator: alloc::Allocator) -> *unsafe mut [il::Val] { |
|
| 3274 | 3284 | if args.len >= capacity { |
|
| 3275 | 3285 | return args; |
|
| 3276 | 3286 | } |
|
| 3277 | - | let mut newArgs: *mut [il::Val] = &mut []; |
|
| 3278 | - | ||
| 3279 | - | for arg in args { |
|
| 3280 | - | newArgs.append(arg, allocator); |
|
| 3281 | - | } |
|
| 3282 | - | for i in args.len..capacity { |
|
| 3283 | - | newArgs.append(il::Val::Undef, allocator); |
|
| 3284 | - | } |
|
| 3287 | + | let newArgs = valueStorage(args, capacity, allocator); |
|
| 3285 | 3288 | return (&mut newArgs[..]) as *unsafe mut [il::Val]; |
|
| 3286 | 3289 | } |
|
| 3287 | 3290 | ||
| 3288 | 3291 | /// Select a receiver or explicit parameter name from its AST declaration. |
|
| 3289 | 3292 | fn paramName(params: &[*ast::Node], receiver: ?*ast::Node, index: u32) -> *[u8] throws (LowerError) { |
test/tests/ssa.argument.growth.rad
+26 -0
| 43 | 43 | set result += step * (84 if index % 2 == 0 else 120); |
|
| 44 | 44 | } |
|
| 45 | 45 | return result; |
|
| 46 | 46 | } |
|
| 47 | 47 | ||
| 48 | + | /// First function value carried through a control-flow edge. |
|
| 49 | + | fn addOne(value: u32) -> u32 { |
|
| 50 | + | return value + 1; |
|
| 51 | + | } |
|
| 52 | + | ||
| 53 | + | /// Second function value carried through a control-flow edge. |
|
| 54 | + | fn addThree(value: u32) -> u32 { |
|
| 55 | + | return value + 3; |
|
| 56 | + | } |
|
| 57 | + | ||
| 58 | + | /// Preserve symbol-valued arguments alongside loop-carried results. |
|
| 59 | + | fn dispatch(limit: u32) -> u32 { |
|
| 60 | + | let mut operation = addOne; |
|
| 61 | + | let mut result: u32 = 0; |
|
| 62 | + | for index in 0..limit { |
|
| 63 | + | if index % 2 == 0 { |
|
| 64 | + | set operation = addOne; |
|
| 65 | + | } else { |
|
| 66 | + | set operation = addThree; |
|
| 67 | + | } |
|
| 68 | + | set result += operation(index); |
|
| 69 | + | } |
|
| 70 | + | return result; |
|
| 71 | + | } |
|
| 72 | + | ||
| 48 | 73 | /// Check empty, single-iteration, and repeatedly merged control flow. |
|
| 49 | 74 | @default fn main() -> u32 { |
|
| 50 | 75 | for limit in 0..20 { |
|
| 51 | 76 | assert run(limit) == expected(limit); |
|
| 77 | + | assert dispatch(limit) == limit * (limit + 1) / 2 + 2 * (limit / 2); |
|
| 52 | 78 | } |
|
| 53 | 79 | return 0; |
|
| 54 | 80 | } |