compiler: Check edge argument storage construction

b0694d2637f1c490c87e71f4a65f3f713b1223800f9501d99c588697bb54d66b
Alexis Sellier committed ago 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
}