compiler: Check initial function descriptor assembly

b05a8d87270e67aa133b3549d4c4af9f392d1f0ab5518e378303cd9aa94f1241
Alexis Sellier committed ago 1 parent 81213327
lib/std/lang/lower.rad +20 -16
1062 1062
        };
1063 1063
    }
1064 1064
    return fnLow;
1065 1065
}
1066 1066
1067 +
/// Construct a function descriptor before its body is lowered.
1068 +
fn functionDescriptor(
1069 +
    name: *[u8],
1070 +
    params: *unsafe [il::Param],
1071 +
    returnType: il::Type,
1072 +
    attrs: ?ast::Attributes,
1073 +
    blocks: *unsafe [il::Block],
1074 +
) -> il::Fn {
1075 +
    return il::Fn {
1076 +
        name,
1077 +
        params,
1078 +
        returnType,
1079 +
        isExtern: checkAttr(attrs, ast::Attribute::Extern),
1080 +
        isLeaf: true,
1081 +
        blocks,
1082 +
    };
1083 +
}
1084 +
1067 1085
/// Lower a function declaration.
1068 1086
///
1069 1087
/// This sets up the per-function lowering state, processes parameters,
1070 1088
/// then lowers the function body into a CFG of basic blocks.
1071 1089
///
1113 1131
        // TODO: The resolver should set an appropriate type that takes into account
1114 1132
        //       the throws list. It shouldn't set the return type to the "success"
1115 1133
        //       value only.
1116 1134
        let returnType = il::Type::W64 if fnType.throwList.len > 0
1117 1135
            else ilType(fnLow.low, *fnType.returnType);
1118 -
        set *func = il::Fn {
1119 -
            name: qualName,
1120 -
            params: lowParams,
1121 -
            returnType,
1122 -
            isExtern,
1123 -
            isLeaf: true,
1124 -
            blocks: &[],
1125 -
        };
1136 +
        set *func = functionDescriptor(qualName, lowParams, returnType, decl.attrs, &[]);
1126 1137
        let body = decl.body else {
1127 1138
            // Extern functions have no body.
1128 1139
            assert isExtern;
1129 1140
            return (&*func) as *unsafe il::Fn;
1130 1141
        };
1276 1287
        let lowParams = try lowerParams(&mut fnLow, *fnType, sig.params, receiverName);
1277 1288
        let func = try! alloc::alloc(&mut *fnLow.arena, @sizeOf(il::Fn), @alignOf(il::Fn)) as *mut il::Fn;
1278 1289
1279 1290
        let returnType = il::Type::W64 if fnType.throwList.len > 0
1280 1291
            else ilType(fnLow.low, *fnType.returnType);
1281 -
        set *func = il::Fn {
1282 -
            name: qualName,
1283 -
            params: lowParams,
1284 -
            returnType,
1285 -
            isExtern: false,
1286 -
            isLeaf: true,
1287 -
            blocks: &[],
1288 -
        };
1292 +
        set *func = functionDescriptor(qualName, lowParams, returnType, nil, &[]);
1289 1293
        set func.blocks = try lowerFnBody(&mut fnLow, body);
1290 1294
        set func.isLeaf = fnLow.isLeaf;
1291 1295
1292 1296
        return (&*func) as *unsafe il::Fn;
1293 1297
    }
test/tests/ssa.instruction.storage.rad +7 -0
1 1
//! returns: 0
2 2
3 +
/// External declaration retained without a lowered body.
4 +
fn externalValue(value: u64) -> u64;
5 +
6 +
/// A void leaf function has an initialized descriptor and return block.
7 +
fn empty() {}
8 +
3 9
/// Input for method calls with branch-local values.
4 10
record Input: Copy {
5 11
    /// Full-width input retained by the receiver.
6 12
    value: u64,
7 13
}
41 47
}
42 48
43 49
/// Check call preservation, leaf state, and repeated instruction emission.
44 50
@default fn main() -> u32 {
45 51
    for index in 0..32 {
52 +
        empty();
46 53
        let value = (index as u64) + 0x100000000;
47 54
        let base = (value + 7) * 3 + (value + 14) * 5;
48 55
        assert combine(value, true) == base + (value + 21) * 11;
49 56
        assert combine(value, false) == base + (value + 21) * 13;
50 57
        let input = Input { value };