compiler: Check initial function descriptor assembly
b05a8d87270e67aa133b3549d4c4af9f392d1f0ab5518e378303cd9aa94f1241
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 }; |