compiler: Build initialized owned call arguments
97ee3683642eb6879a5ae2c1f4ac059fcfcf675904cc0709958da7a2b4d6b1b2
1 parent
01c24b42
lib/std/lang/lower.rad
+31 -20
| 6909 | 6909 | } |
|
| 6910 | 6910 | let layout = resolver::getTypeLayout(*allocation.item); |
|
| 6911 | 6911 | let size = layout.size if layout.size > 0 else 1; |
|
| 6912 | 6912 | let alignment = layout.alignment if layout.alignment > 0 else 1; |
|
| 6913 | 6913 | let runtime = allocation.traitInfo.methods[allocation.methodIndex].fnType; |
|
| 6914 | - | let argOffset: u32 = 1 if requiresReturnParam(runtime) else 0; |
|
| 6915 | - | let args = try allocVals(self, (4 if slice else 3) + argOffset); |
|
| 6916 | - | set args[argOffset] = il::Val::Reg(dataReg); |
|
| 6917 | - | set args[argOffset + 1] = il::Val::Imm(size as i64); |
|
| 6918 | - | set args[argOffset + 2] = il::Val::Imm(alignment as i64); |
|
| 6914 | + | let mut args = callArgs(self, runtime); |
|
| 6915 | + | args.append(il::Val::Reg(dataReg), alloc::arenaAllocator(self.arena)); |
|
| 6916 | + | args.append(il::Val::Imm(size as i64), alloc::arenaAllocator(self.arena)); |
|
| 6917 | + | args.append(il::Val::Imm(alignment as i64), alloc::arenaAllocator(self.arena)); |
|
| 6919 | 6918 | if slice { |
|
| 6920 | - | set args[argOffset + 3] = count; |
|
| 6919 | + | args.append(count, alloc::arenaAllocator(self.arena)); |
|
| 6921 | 6920 | } |
|
| 6922 | 6921 | let result = try emitCallValue(self, il::Val::Reg(functionReg), runtime, args); |
|
| 6923 | 6922 | return SessionInitialization { allocation, result, value, count }; |
|
| 6924 | 6923 | } |
|
| 6925 | 6924 |
| 7033 | 7032 | offset: slotOffset, |
|
| 7034 | 7033 | }); |
|
| 7035 | 7034 | let methodFnType = traitInfo.methods[methodIndex].fnType; |
|
| 7036 | 7035 | ||
| 7037 | 7036 | // Build args: optional return param slot + data pointer (receiver) + user args. |
|
| 7038 | - | let argOffset: u32 = 1 if requiresReturnParam(methodFnType) else 0; |
|
| 7039 | - | let args = try allocVals(self, call.args.len + 1 + argOffset); |
|
| 7040 | - | set args[argOffset] = il::Val::Reg(dataReg); |
|
| 7037 | + | let mut args = callArgs(self, methodFnType); |
|
| 7038 | + | args.append(il::Val::Reg(dataReg), alloc::arenaAllocator(self.arena)); |
|
| 7041 | 7039 | ||
| 7042 | 7040 | for arg, i in call.args { |
|
| 7043 | - | set args[i + 1 + argOffset] = try lowerCallArg( |
|
| 7041 | + | let value = try lowerCallArg( |
|
| 7044 | 7042 | self, arg, i + 1 < call.args.len |
|
| 7045 | 7043 | ); |
|
| 7044 | + | args.append(value, alloc::arenaAllocator(self.arena)); |
|
| 7046 | 7045 | } |
|
| 7047 | 7046 | return try emitCallValue(self, il::Val::Reg(fnPtrReg), methodFnType, args); |
|
| 7048 | 7047 | } |
|
| 7049 | 7048 | ||
| 7050 | 7049 | /// Lower a call argument, snapshotting aggregate place expressions before |
| 7063 | 7062 | } |
|
| 7064 | 7063 | } |
|
| 7065 | 7064 | return val; |
|
| 7066 | 7065 | } |
|
| 7067 | 7066 | ||
| 7067 | + | /// Start an argument table with a placeholder for the hidden return pointer. |
|
| 7068 | + | unsafe fn callArgs 'arena 'phase 'function ( |
|
| 7069 | + | self: &mut FnLowerer 'arena 'phase 'function, |
|
| 7070 | + | fnInfo: *resolver::FnType |
|
| 7071 | + | ) -> *mut [il::Val] where 'arena: 'phase, 'phase: 'function { |
|
| 7072 | + | let mut args: *mut [il::Val] = &mut []; |
|
| 7073 | + | if requiresReturnParam(fnInfo) { |
|
| 7074 | + | args.append(il::Val::Undef, alloc::arenaAllocator(self.arena)); |
|
| 7075 | + | } |
|
| 7076 | + | return args; |
|
| 7077 | + | } |
|
| 7078 | + | ||
| 7068 | 7079 | /// Emit a function call with return-parameter and small-aggregate handling. |
|
| 7069 | 7080 | /// |
|
| 7070 | 7081 | /// All call lowering paths (regular, trait method, standalone method) converge |
|
| 7071 | 7082 | /// here after preparing the callee value, function type, and argument array. |
|
| 7072 | 7083 | /// The `args` slice must already include a slot at index zero for the hidden |
|
| 7073 | 7084 | /// return parameter; that slot is filled by this function. |
|
| 7074 | 7085 | unsafe fn emitCallValue 'arena 'phase 'function ( |
|
| 7075 | 7086 | self: &mut FnLowerer 'arena 'phase 'function, |
|
| 7076 | 7087 | callee: il::Val, |
|
| 7077 | 7088 | fnInfo: *resolver::FnType, |
|
| 7078 | - | args: *unsafe mut [il::Val], |
|
| 7089 | + | args: *mut [il::Val], |
|
| 7079 | 7090 | ) -> il::Val throws (LowerError) where 'arena: 'phase, 'phase: 'function { |
|
| 7080 | 7091 | let retTy = *fnInfo.returnType; |
|
| 7081 | 7092 | ||
| 7082 | 7093 | if requiresReturnParam(fnInfo) { |
|
| 7083 | 7094 | if fnInfo.throwList.len > 0 { |
| 7090 | 7101 | ||
| 7091 | 7102 | emit(self, il::Instr::Call { |
|
| 7092 | 7103 | retTy: il::Type::W64, |
|
| 7093 | 7104 | dst, |
|
| 7094 | 7105 | func: callee, |
|
| 7095 | - | args, |
|
| 7106 | + | args: (&mut args[..]) as *unsafe mut [il::Val], |
|
| 7096 | 7107 | }); |
|
| 7097 | 7108 | return il::Val::Reg(dst); |
|
| 7098 | 7109 | } |
|
| 7099 | 7110 | let mut dst: ?il::Reg = nil; |
|
| 7100 | 7111 | if retTy <> resolver::Type::Void and retTy <> resolver::Type::Never { |
| 7102 | 7113 | } |
|
| 7103 | 7114 | emit(self, il::Instr::Call { |
|
| 7104 | 7115 | retTy: ilType(self.low, retTy), |
|
| 7105 | 7116 | dst, |
|
| 7106 | 7117 | func: callee, |
|
| 7107 | - | args, |
|
| 7118 | + | args: (&mut args[..]) as *unsafe mut [il::Val], |
|
| 7108 | 7119 | }); |
|
| 7109 | 7120 | ||
| 7110 | 7121 | if retTy == resolver::Type::Never { |
|
| 7111 | 7122 | emit(self, il::Instr::Unreachable); |
|
| 7112 | 7123 | } |
| 7176 | 7187 | ||
| 7177 | 7188 | let qualName = instanceMethodName(self.low, nil, method.concreteTypeName, method.name); |
|
| 7178 | 7189 | let fnInfo = method.fullFnType; |
|
| 7179 | 7190 | ||
| 7180 | 7191 | // Build args: optional return param slot + receiver + user args. |
|
| 7181 | - | let argOffset: u32 = 1 if requiresReturnParam(fnInfo) else 0; |
|
| 7182 | - | let args = try allocVals(self, call.args.len + 1 + argOffset); |
|
| 7183 | - | set args[argOffset] = receiverVal; |
|
| 7192 | + | let mut args = callArgs(self, fnInfo); |
|
| 7193 | + | args.append(receiverVal, alloc::arenaAllocator(self.arena)); |
|
| 7184 | 7194 | for arg, i in call.args { |
|
| 7185 | - | set args[i + 1 + argOffset] = try lowerCallArg( |
|
| 7195 | + | let value = try lowerCallArg( |
|
| 7186 | 7196 | self, arg, i + 1 < call.args.len |
|
| 7187 | 7197 | ); |
|
| 7198 | + | args.append(value, alloc::arenaAllocator(self.arena)); |
|
| 7188 | 7199 | } |
|
| 7189 | 7200 | return try emitCallValue(self, il::Val::FnAddr(qualName), fnInfo, args); |
|
| 7190 | 7201 | } |
|
| 7191 | 7202 | ||
| 7192 | 7203 | /// Check if a call is to a compiler intrinsic and lower it directly. |
| 7293 | 7304 | let calleeTy = try typeOf(self, call.callee); |
|
| 7294 | 7305 | let case resolver::Type::Fn(fnInfo) = calleeTy else { |
|
| 7295 | 7306 | throw LowerError::ExpectedFunction; |
|
| 7296 | 7307 | }; |
|
| 7297 | 7308 | let callee = try lowerCallee(self, call.callee); |
|
| 7298 | - | let offset: u32 = 1 if requiresReturnParam(fnInfo) else 0; |
|
| 7299 | - | let args = try allocVals(self, call.args.len + offset); |
|
| 7309 | + | let mut args = callArgs(self, fnInfo); |
|
| 7300 | 7310 | for arg, i in call.args { |
|
| 7301 | - | set args[i + offset] = try lowerCallArg( |
|
| 7311 | + | let value = try lowerCallArg( |
|
| 7302 | 7312 | self, arg, i + 1 < call.args.len |
|
| 7303 | 7313 | ); |
|
| 7314 | + | args.append(value, alloc::arenaAllocator(self.arena)); |
|
| 7304 | 7315 | } |
|
| 7305 | 7316 | ||
| 7306 | 7317 | return try emitCallValue(self, callee, fnInfo, args); |
|
| 7307 | 7318 | } |
|
| 7308 | 7319 |
test/tests/call.table.order.rad
added
+63 -0
| 1 | + | //! returns: 0 |
|
| 2 | + | ||
| 3 | + | /// Aggregate call result. |
|
| 4 | + | record Pair: Copy { |
|
| 5 | + | /// First argument value. |
|
| 6 | + | first: u32, |
|
| 7 | + | /// Second argument value. |
|
| 8 | + | second: u32, |
|
| 9 | + | } |
|
| 10 | + | ||
| 11 | + | /// Record one evaluated argument. |
|
| 12 | + | fn argument(trace: &mut u32, digit: u32) -> u32 { |
|
| 13 | + | set *trace = *trace * 10 + digit; |
|
| 14 | + | return digit; |
|
| 15 | + | } |
|
| 16 | + | ||
| 17 | + | /// Return both arguments through a hidden result pointer. |
|
| 18 | + | fn pair(first: u32, second: u32) -> Pair { |
|
| 19 | + | return Pair { first, second }; |
|
| 20 | + | } |
|
| 21 | + | ||
| 22 | + | /// Combine the receiver with explicit arguments. |
|
| 23 | + | fn (value: &Pair) combine(first: u32, second: u32) -> Pair { |
|
| 24 | + | return Pair { first: value.first + first, second: value.second + second }; |
|
| 25 | + | } |
|
| 26 | + | ||
| 27 | + | /// Return an aggregate result or an error after evaluating both arguments. |
|
| 28 | + | fn checked(first: u32, second: u32) -> Pair throws (u32) { |
|
| 29 | + | if first == 3 { |
|
| 30 | + | throw second; |
|
| 31 | + | } |
|
| 32 | + | return pair(first, second); |
|
| 33 | + | } |
|
| 34 | + | ||
| 35 | + | /// Check direct, indirect, method, and throwing call argument order. |
|
| 36 | + | @default fn main() -> u32 { |
|
| 37 | + | let mut trace: u32 = 0; |
|
| 38 | + | let first = pair(argument(&mut trace, 1), argument(&mut trace, 2)); |
|
| 39 | + | assert trace == 12; |
|
| 40 | + | let second = first.combine(argument(&mut trace, 3), argument(&mut trace, 4)); |
|
| 41 | + | assert trace == 1234; |
|
| 42 | + | assert second.first == 4; |
|
| 43 | + | assert second.second == 6; |
|
| 44 | + | let call: fn(u32, u32) -> Pair = pair; |
|
| 45 | + | let third = call(argument(&mut trace, 5), argument(&mut trace, 6)); |
|
| 46 | + | assert trace == 123456; |
|
| 47 | + | assert third.first == 5; |
|
| 48 | + | assert third.second == 6; |
|
| 49 | + | let result = try! checked(argument(&mut trace, 1), argument(&mut trace, 2)); |
|
| 50 | + | assert trace == 12345612; |
|
| 51 | + | assert result.first == 1; |
|
| 52 | + | assert result.second == 2; |
|
| 53 | + | set trace = 0; |
|
| 54 | + | let mut caught = false; |
|
| 55 | + | try checked(argument(&mut trace, 3), argument(&mut trace, 4)) catch { |
|
| 56 | + | set caught = true; |
|
| 57 | + | }; |
|
| 58 | + | assert caught; |
|
| 59 | + | assert trace == 34; |
|
| 60 | + | assert first.first == 1; |
|
| 61 | + | assert first.second == 2; |
|
| 62 | + | return 0; |
|
| 63 | + | } |