1 //! Legalize ABI boundaries.
2 //!
3 //! This legalizer sub-module contains code for dealing with ABI boundaries:
4 //!
5 //! - Function arguments passed to the entry block.
6 //! - Function arguments passed to call instructions.
7 //! - Return values from call instructions.
8 //! - Return values passed to return instructions.
9 //!
10 //! The ABI boundary legalization happens in two phases:
11 //!
12 //! 1. The `legalize_signatures` function rewrites all the preamble signatures with ABI information
13 //! and possibly new argument types. It also rewrites the entry block arguments to match.
14 //! 2. The `handle_call_abi` and `handle_return_abi` functions rewrite call and return instructions
15 //! to match the new ABI signatures.
16 //!
17 //! Between the two phases, preamble signatures and call/return arguments don't match. This
18 //! intermediate state doesn't type check.
19
20 use crate::abi::{legalize_abi_value, ValueConversion};
21 use crate::cursor::{Cursor, FuncCursor};
22 use crate::flowgraph::ControlFlowGraph;
23 use crate::ir::instructions::CallInfo;
24 use crate::ir::{
25 AbiParam, ArgumentLoc, ArgumentPurpose, Block, DataFlowGraph, Function, Inst, InstBuilder,
26 MemFlags, SigRef, Signature, StackSlotData, StackSlotKind, Type, Value, ValueLoc,
27 };
28 use crate::isa::TargetIsa;
29 use crate::legalizer::split::{isplit, vsplit};
30 use alloc::borrow::Cow;
31 use alloc::vec::Vec;
32 use core::mem;
33 use cranelift_entity::EntityList;
34 use log::debug;
35
36 /// Legalize all the function signatures in `func`.
37 ///
38 /// This changes all signatures to be ABI-compliant with full `ArgumentLoc` annotations. It doesn't
39 /// change the entry block arguments, calls, or return instructions, so this can leave the function
40 /// in a state with type discrepancies.
legalize_signatures(func: &mut Function, isa: &dyn TargetIsa)41 pub fn legalize_signatures(func: &mut Function, isa: &dyn TargetIsa) {
42 if let Some(new) = legalize_signature(&func.signature, true, isa) {
43 let old = mem::replace(&mut func.signature, new);
44 func.old_signature = Some(old);
45 }
46
47 for (sig_ref, sig_data) in func.dfg.signatures.iter_mut() {
48 if let Some(new) = legalize_signature(sig_data, false, isa) {
49 let old = mem::replace(sig_data, new);
50 func.dfg.old_signatures[sig_ref] = Some(old);
51 }
52 }
53
54 if let Some(entry) = func.layout.entry_block() {
55 legalize_entry_params(func, entry);
56 spill_entry_params(func, entry);
57 }
58 }
59
60 /// Legalize the libcall signature, which we may generate on the fly after
61 /// `legalize_signatures` has been called.
legalize_libcall_signature(signature: &mut Signature, isa: &dyn TargetIsa)62 pub fn legalize_libcall_signature(signature: &mut Signature, isa: &dyn TargetIsa) {
63 if let Some(s) = legalize_signature(signature, false, isa) {
64 *signature = s;
65 }
66 }
67
68 /// Legalize the given signature.
69 ///
70 /// `current` is true if this is the signature for the current function.
legalize_signature( signature: &Signature, current: bool, isa: &dyn TargetIsa, ) -> Option<Signature>71 fn legalize_signature(
72 signature: &Signature,
73 current: bool,
74 isa: &dyn TargetIsa,
75 ) -> Option<Signature> {
76 let mut cow = Cow::Borrowed(signature);
77 isa.legalize_signature(&mut cow, current);
78 match cow {
79 Cow::Borrowed(_) => None,
80 Cow::Owned(s) => Some(s),
81 }
82 }
83
84 /// Legalize the entry block parameters after `func`'s signature has been legalized.
85 ///
86 /// The legalized signature may contain more parameters than the original signature, and the
87 /// parameter types have been changed. This function goes through the parameters of the entry block
88 /// and replaces them with parameters of the right type for the ABI.
89 ///
90 /// The original entry block parameters are computed from the new ABI parameters by code inserted at
91 /// the top of the entry block.
legalize_entry_params(func: &mut Function, entry: Block)92 fn legalize_entry_params(func: &mut Function, entry: Block) {
93 let mut has_sret = false;
94 let mut has_link = false;
95 let mut has_vmctx = false;
96 let mut has_sigid = false;
97 let mut has_stack_limit = false;
98
99 // Insert position for argument conversion code.
100 // We want to insert instructions before the first instruction in the entry block.
101 // If the entry block is empty, append instructions to it instead.
102 let mut pos = FuncCursor::new(func).at_first_inst(entry);
103
104 // Keep track of the argument types in the ABI-legalized signature.
105 let mut abi_arg = 0;
106
107 // Process the block parameters one at a time, possibly replacing one argument with multiple new
108 // ones. We do this by detaching the entry block parameters first.
109 let block_params = pos.func.dfg.detach_block_params(entry);
110 let mut old_arg = 0;
111 while let Some(arg) = block_params.get(old_arg, &pos.func.dfg.value_lists) {
112 old_arg += 1;
113
114 let abi_type = pos.func.signature.params[abi_arg];
115 let arg_type = pos.func.dfg.value_type(arg);
116 if arg_type == abi_type.value_type {
117 // No value translation is necessary, this argument matches the ABI type.
118 // Just use the original block argument value. This is the most common case.
119 pos.func.dfg.attach_block_param(entry, arg);
120 match abi_type.purpose {
121 ArgumentPurpose::Normal => {}
122 ArgumentPurpose::FramePointer => {}
123 ArgumentPurpose::CalleeSaved => {}
124 ArgumentPurpose::StructReturn => {
125 debug_assert!(!has_sret, "Multiple sret arguments found");
126 has_sret = true;
127 }
128 ArgumentPurpose::VMContext => {
129 debug_assert!(!has_vmctx, "Multiple vmctx arguments found");
130 has_vmctx = true;
131 }
132 ArgumentPurpose::SignatureId => {
133 debug_assert!(!has_sigid, "Multiple sigid arguments found");
134 has_sigid = true;
135 }
136 ArgumentPurpose::StackLimit => {
137 debug_assert!(!has_stack_limit, "Multiple stack_limit arguments found");
138 has_stack_limit = true;
139 }
140 _ => panic!("Unexpected special-purpose arg {}", abi_type),
141 }
142 abi_arg += 1;
143 } else {
144 // Compute the value we want for `arg` from the legalized ABI parameters.
145 let mut get_arg = |func: &mut Function, ty| {
146 let abi_type = func.signature.params[abi_arg];
147 debug_assert_eq!(
148 abi_type.purpose,
149 ArgumentPurpose::Normal,
150 "Can't legalize special-purpose argument"
151 );
152 if ty == abi_type.value_type {
153 abi_arg += 1;
154 Ok(func.dfg.append_block_param(entry, ty))
155 } else {
156 Err(abi_type)
157 }
158 };
159 let converted = convert_from_abi(&mut pos, arg_type, Some(arg), &mut get_arg);
160 // The old `arg` is no longer an attached block argument, but there are probably still
161 // uses of the value.
162 debug_assert_eq!(pos.func.dfg.resolve_aliases(arg), converted);
163 }
164 }
165
166 // The legalized signature may contain additional parameters representing special-purpose
167 // registers.
168 for &arg in &pos.func.signature.params[abi_arg..] {
169 match arg.purpose {
170 // Any normal parameters should have been processed above.
171 ArgumentPurpose::Normal => {
172 panic!("Leftover arg: {}", arg);
173 }
174 // The callee-save parameters should not appear until after register allocation is
175 // done.
176 ArgumentPurpose::FramePointer | ArgumentPurpose::CalleeSaved => {
177 panic!("Premature callee-saved arg {}", arg);
178 }
179 // These can be meaningfully added by `legalize_signature()`.
180 ArgumentPurpose::Link => {
181 debug_assert!(!has_link, "Multiple link parameters found");
182 has_link = true;
183 }
184 ArgumentPurpose::StructReturn => {
185 debug_assert!(!has_sret, "Multiple sret parameters found");
186 has_sret = true;
187 }
188 ArgumentPurpose::VMContext => {
189 debug_assert!(!has_vmctx, "Multiple vmctx parameters found");
190 has_vmctx = true;
191 }
192 ArgumentPurpose::SignatureId => {
193 debug_assert!(!has_sigid, "Multiple sigid parameters found");
194 has_sigid = true;
195 }
196 ArgumentPurpose::StackLimit => {
197 debug_assert!(!has_stack_limit, "Multiple stack_limit parameters found");
198 has_stack_limit = true;
199 }
200 }
201
202 // Just create entry block values to match here. We will use them in `handle_return_abi()`
203 // below.
204 pos.func.dfg.append_block_param(entry, arg.value_type);
205 }
206 }
207
208 /// Legalize the results returned from a call instruction to match the ABI signature.
209 ///
210 /// The cursor `pos` points to a call instruction with at least one return value. The cursor will
211 /// be left pointing after the instructions inserted to convert the return values.
212 ///
213 /// This function is very similar to the `legalize_entry_params` function above.
214 ///
215 /// Returns the possibly new instruction representing the call.
legalize_inst_results<ResType>(pos: &mut FuncCursor, mut get_abi_type: ResType) -> Inst where ResType: FnMut(&Function, usize) -> AbiParam,216 fn legalize_inst_results<ResType>(pos: &mut FuncCursor, mut get_abi_type: ResType) -> Inst
217 where
218 ResType: FnMut(&Function, usize) -> AbiParam,
219 {
220 let call = pos
221 .current_inst()
222 .expect("Cursor must point to a call instruction");
223
224 // We theoretically allow for call instructions that return a number of fixed results before
225 // the call return values. In practice, it doesn't happen.
226 debug_assert_eq!(
227 pos.func.dfg[call]
228 .opcode()
229 .constraints()
230 .num_fixed_results(),
231 0,
232 "Fixed results on calls not supported"
233 );
234
235 let results = pos.func.dfg.detach_results(call);
236 let mut next_res = 0;
237 let mut abi_res = 0;
238
239 // Point immediately after the call.
240 pos.next_inst();
241
242 while let Some(res) = results.get(next_res, &pos.func.dfg.value_lists) {
243 next_res += 1;
244
245 let res_type = pos.func.dfg.value_type(res);
246 if res_type == get_abi_type(pos.func, abi_res).value_type {
247 // No value translation is necessary, this result matches the ABI type.
248 pos.func.dfg.attach_result(call, res);
249 abi_res += 1;
250 } else {
251 let mut get_res = |func: &mut Function, ty| {
252 let abi_type = get_abi_type(func, abi_res);
253 if ty == abi_type.value_type {
254 let last_res = func.dfg.append_result(call, ty);
255 abi_res += 1;
256 Ok(last_res)
257 } else {
258 Err(abi_type)
259 }
260 };
261 let v = convert_from_abi(pos, res_type, Some(res), &mut get_res);
262 debug_assert_eq!(pos.func.dfg.resolve_aliases(res), v);
263 }
264 }
265
266 call
267 }
268
assert_is_valid_sret_legalization( old_ret_list: &EntityList<Value>, old_sig: &Signature, new_sig: &Signature, pos: &FuncCursor, )269 fn assert_is_valid_sret_legalization(
270 old_ret_list: &EntityList<Value>,
271 old_sig: &Signature,
272 new_sig: &Signature,
273 pos: &FuncCursor,
274 ) {
275 debug_assert_eq!(
276 old_sig.returns.len(),
277 old_ret_list.len(&pos.func.dfg.value_lists)
278 );
279
280 // Assert that the only difference in special parameters is that there
281 // is an appended struct return pointer parameter.
282 let old_special_params: Vec<_> = old_sig
283 .params
284 .iter()
285 .filter(|r| r.purpose != ArgumentPurpose::Normal)
286 .collect();
287 let new_special_params: Vec<_> = new_sig
288 .params
289 .iter()
290 .filter(|r| r.purpose != ArgumentPurpose::Normal)
291 .collect();
292 debug_assert_eq!(old_special_params.len() + 1, new_special_params.len());
293 debug_assert!(old_special_params
294 .iter()
295 .zip(&new_special_params)
296 .all(|(old, new)| old.purpose == new.purpose));
297 debug_assert_eq!(
298 new_special_params.last().unwrap().purpose,
299 ArgumentPurpose::StructReturn
300 );
301
302 // If the special returns have changed at all, then the only change
303 // should be that the struct return pointer is returned back out of the
304 // function, so that callers don't have to load its stack address again.
305 let old_special_returns: Vec<_> = old_sig
306 .returns
307 .iter()
308 .filter(|r| r.purpose != ArgumentPurpose::Normal)
309 .collect();
310 let new_special_returns: Vec<_> = new_sig
311 .returns
312 .iter()
313 .filter(|r| r.purpose != ArgumentPurpose::Normal)
314 .collect();
315 debug_assert!(old_special_returns
316 .iter()
317 .zip(&new_special_returns)
318 .all(|(old, new)| old.purpose == new.purpose));
319 debug_assert!(
320 old_special_returns.len() == new_special_returns.len()
321 || (old_special_returns.len() + 1 == new_special_returns.len()
322 && new_special_returns.last().unwrap().purpose == ArgumentPurpose::StructReturn)
323 );
324 }
325
legalize_sret_call(isa: &dyn TargetIsa, pos: &mut FuncCursor, sig_ref: SigRef, call: Inst)326 fn legalize_sret_call(isa: &dyn TargetIsa, pos: &mut FuncCursor, sig_ref: SigRef, call: Inst) {
327 let old_ret_list = pos.func.dfg.detach_results(call);
328 let old_sig = pos.func.dfg.old_signatures[sig_ref]
329 .take()
330 .expect("must have an old signature when using an `sret` parameter");
331
332 // We make a bunch of assumptions about the shape of the old, multi-return
333 // signature and the new, sret-using signature in this legalization
334 // function. Assert that these assumptions hold true in debug mode.
335 if cfg!(debug_assertions) {
336 assert_is_valid_sret_legalization(
337 &old_ret_list,
338 &old_sig,
339 &pos.func.dfg.signatures[sig_ref],
340 &pos,
341 );
342 }
343
344 // Go through and remove all normal return values from the `call`
345 // instruction's returns list. These will be stored into the stack slot that
346 // the sret points to. At the same time, calculate the size of the sret
347 // stack slot.
348 let mut sret_slot_size = 0;
349 for (i, ret) in old_sig.returns.iter().enumerate() {
350 let v = old_ret_list.get(i, &pos.func.dfg.value_lists).unwrap();
351 let ty = pos.func.dfg.value_type(v);
352 if ret.purpose == ArgumentPurpose::Normal {
353 debug_assert_eq!(ret.location, ArgumentLoc::Unassigned);
354 let ty = legalized_type_for_sret(ty);
355 let size = ty.bytes();
356 sret_slot_size = round_up_to_multiple_of_type_align(sret_slot_size, ty) + size;
357 } else {
358 let new_v = pos.func.dfg.append_result(call, ty);
359 pos.func.dfg.change_to_alias(v, new_v);
360 }
361 }
362
363 let stack_slot = pos.func.stack_slots.push(StackSlotData {
364 kind: StackSlotKind::StructReturnSlot,
365 size: sret_slot_size,
366 offset: None,
367 });
368
369 // Append the sret pointer to the `call` instruction's arguments.
370 let ptr_type = Type::triple_pointer_type(isa.triple());
371 let sret_arg = pos.ins().stack_addr(ptr_type, stack_slot, 0);
372 pos.func.dfg.append_inst_arg(call, sret_arg);
373
374 // The sret pointer might be returned by the signature as well. If so, we
375 // need to add it to the `call` instruction's results list.
376 //
377 // Additionally, when the sret is explicitly returned in this calling
378 // convention, then use it when loading the sret returns back into ssa
379 // values to avoid keeping the original `sret_arg` live and potentially
380 // having to do spills and fills.
381 let sret =
382 if pos.func.dfg.signatures[sig_ref].uses_special_return(ArgumentPurpose::StructReturn) {
383 pos.func.dfg.append_result(call, ptr_type)
384 } else {
385 sret_arg
386 };
387
388 // Finally, load each of the call's return values out of the sret stack
389 // slot.
390 pos.goto_after_inst(call);
391 let mut offset = 0;
392 for i in 0..old_ret_list.len(&pos.func.dfg.value_lists) {
393 if old_sig.returns[i].purpose != ArgumentPurpose::Normal {
394 continue;
395 }
396
397 let old_v = old_ret_list.get(i, &pos.func.dfg.value_lists).unwrap();
398 let ty = pos.func.dfg.value_type(old_v);
399 let mut legalized_ty = legalized_type_for_sret(ty);
400
401 offset = round_up_to_multiple_of_type_align(offset, legalized_ty);
402
403 let new_legalized_v =
404 pos.ins()
405 .load(legalized_ty, MemFlags::trusted(), sret, offset as i32);
406
407 // "Illegalize" the loaded value from the legalized type back to its
408 // original `ty`. This is basically the opposite of
409 // `legalize_type_for_sret_store`.
410 let mut new_v = new_legalized_v;
411 if ty.is_bool() {
412 legalized_ty = legalized_ty.as_bool_pedantic();
413 new_v = pos.ins().raw_bitcast(legalized_ty, new_v);
414
415 if ty.bits() < legalized_ty.bits() {
416 legalized_ty = ty;
417 new_v = pos.ins().breduce(legalized_ty, new_v);
418 }
419 }
420
421 pos.func.dfg.change_to_alias(old_v, new_v);
422
423 offset += legalized_ty.bytes();
424 }
425
426 pos.func.dfg.old_signatures[sig_ref] = Some(old_sig);
427 }
428
429 /// Compute original value of type `ty` from the legalized ABI arguments.
430 ///
431 /// The conversion is recursive, controlled by the `get_arg` closure which is called to retrieve an
432 /// ABI argument. It returns:
433 ///
434 /// - `Ok(arg)` if the requested type matches the next ABI argument.
435 /// - `Err(arg_type)` if further conversions are needed from the ABI argument `arg_type`.
436 ///
437 /// If the `into_result` value is provided, the converted result will be written into that value.
convert_from_abi<GetArg>( pos: &mut FuncCursor, ty: Type, into_result: Option<Value>, get_arg: &mut GetArg, ) -> Value where GetArg: FnMut(&mut Function, Type) -> Result<Value, AbiParam>,438 fn convert_from_abi<GetArg>(
439 pos: &mut FuncCursor,
440 ty: Type,
441 into_result: Option<Value>,
442 get_arg: &mut GetArg,
443 ) -> Value
444 where
445 GetArg: FnMut(&mut Function, Type) -> Result<Value, AbiParam>,
446 {
447 // Terminate the recursion when we get the desired type.
448 let arg_type = match get_arg(pos.func, ty) {
449 Ok(v) => {
450 debug_assert_eq!(pos.func.dfg.value_type(v), ty);
451 debug_assert_eq!(into_result, None);
452 return v;
453 }
454 Err(t) => t,
455 };
456
457 // Reconstruct how `ty` was legalized into the `arg_type` argument.
458 let conversion = legalize_abi_value(ty, &arg_type);
459
460 debug!("convert_from_abi({}): {:?}", ty, conversion);
461
462 // The conversion describes value to ABI argument. We implement the reverse conversion here.
463 match conversion {
464 // Construct a `ty` by concatenating two ABI integers.
465 ValueConversion::IntSplit => {
466 let abi_ty = ty.half_width().expect("Invalid type for conversion");
467 let lo = convert_from_abi(pos, abi_ty, None, get_arg);
468 let hi = convert_from_abi(pos, abi_ty, None, get_arg);
469 debug!(
470 "intsplit {}: {}, {}: {}",
471 lo,
472 pos.func.dfg.value_type(lo),
473 hi,
474 pos.func.dfg.value_type(hi)
475 );
476 pos.ins().with_results([into_result]).iconcat(lo, hi)
477 }
478 // Construct a `ty` by concatenating two halves of a vector.
479 ValueConversion::VectorSplit => {
480 let abi_ty = ty.half_vector().expect("Invalid type for conversion");
481 let lo = convert_from_abi(pos, abi_ty, None, get_arg);
482 let hi = convert_from_abi(pos, abi_ty, None, get_arg);
483 pos.ins().with_results([into_result]).vconcat(lo, hi)
484 }
485 // Construct a `ty` by bit-casting from an integer type.
486 ValueConversion::IntBits => {
487 debug_assert!(!ty.is_int());
488 let abi_ty = Type::int(ty.bits()).expect("Invalid type for conversion");
489 let arg = convert_from_abi(pos, abi_ty, None, get_arg);
490 pos.ins().with_results([into_result]).bitcast(ty, arg)
491 }
492 // ABI argument is a sign-extended version of the value we want.
493 ValueConversion::Sext(abi_ty) => {
494 let arg = convert_from_abi(pos, abi_ty, None, get_arg);
495 // TODO: Currently, we don't take advantage of the ABI argument being sign-extended.
496 // We could insert an `assert_sreduce` which would fold with a following `sextend` of
497 // this value.
498 pos.ins().with_results([into_result]).ireduce(ty, arg)
499 }
500 ValueConversion::Uext(abi_ty) => {
501 let arg = convert_from_abi(pos, abi_ty, None, get_arg);
502 // TODO: Currently, we don't take advantage of the ABI argument being sign-extended.
503 // We could insert an `assert_ureduce` which would fold with a following `uextend` of
504 // this value.
505 pos.ins().with_results([into_result]).ireduce(ty, arg)
506 }
507 // ABI argument is a pointer to the value we want.
508 ValueConversion::Pointer(abi_ty) => {
509 let arg = convert_from_abi(pos, abi_ty, None, get_arg);
510 pos.ins()
511 .with_results([into_result])
512 .load(ty, MemFlags::new(), arg, 0)
513 }
514 }
515 }
516
517 /// Convert `value` to match an ABI signature by inserting instructions at `pos`.
518 ///
519 /// This may require expanding the value to multiple ABI arguments. The conversion process is
520 /// recursive and controlled by the `put_arg` closure. When a candidate argument value is presented
521 /// to the closure, it will perform one of two actions:
522 ///
523 /// 1. If the suggested argument has an acceptable value type, consume it by adding it to the list
524 /// of arguments and return `Ok(())`.
525 /// 2. If the suggested argument doesn't have the right value type, don't change anything, but
526 /// return the `Err(AbiParam)` that is needed.
527 ///
convert_to_abi<PutArg>( pos: &mut FuncCursor, cfg: &ControlFlowGraph, value: Value, put_arg: &mut PutArg, ) where PutArg: FnMut(&mut Function, Value) -> Result<(), AbiParam>,528 fn convert_to_abi<PutArg>(
529 pos: &mut FuncCursor,
530 cfg: &ControlFlowGraph,
531 value: Value,
532 put_arg: &mut PutArg,
533 ) where
534 PutArg: FnMut(&mut Function, Value) -> Result<(), AbiParam>,
535 {
536 // Start by invoking the closure to either terminate the recursion or get the argument type
537 // we're trying to match.
538 let arg_type = match put_arg(pos.func, value) {
539 Ok(_) => return,
540 Err(t) => t,
541 };
542
543 let ty = pos.func.dfg.value_type(value);
544 match legalize_abi_value(ty, &arg_type) {
545 ValueConversion::IntSplit => {
546 let curpos = pos.position();
547 let srcloc = pos.srcloc();
548 let (lo, hi) = isplit(&mut pos.func, cfg, curpos, srcloc, value);
549 convert_to_abi(pos, cfg, lo, put_arg);
550 convert_to_abi(pos, cfg, hi, put_arg);
551 }
552 ValueConversion::VectorSplit => {
553 let curpos = pos.position();
554 let srcloc = pos.srcloc();
555 let (lo, hi) = vsplit(&mut pos.func, cfg, curpos, srcloc, value);
556 convert_to_abi(pos, cfg, lo, put_arg);
557 convert_to_abi(pos, cfg, hi, put_arg);
558 }
559 ValueConversion::IntBits => {
560 debug_assert!(!ty.is_int());
561 let abi_ty = Type::int(ty.bits()).expect("Invalid type for conversion");
562 let arg = pos.ins().bitcast(abi_ty, value);
563 convert_to_abi(pos, cfg, arg, put_arg);
564 }
565 ValueConversion::Sext(abi_ty) => {
566 let arg = pos.ins().sextend(abi_ty, value);
567 convert_to_abi(pos, cfg, arg, put_arg);
568 }
569 ValueConversion::Uext(abi_ty) => {
570 let arg = pos.ins().uextend(abi_ty, value);
571 convert_to_abi(pos, cfg, arg, put_arg);
572 }
573 ValueConversion::Pointer(abi_ty) => {
574 // Note: This conversion can only happen for call arguments,
575 // so we can allocate the value on stack safely.
576 let stack_slot = pos.func.create_stack_slot(StackSlotData {
577 kind: StackSlotKind::ExplicitSlot,
578 size: ty.bytes(),
579 offset: None,
580 });
581 let arg = pos.ins().stack_addr(abi_ty, stack_slot, 0);
582 pos.ins().store(MemFlags::new(), value, arg, 0);
583 convert_to_abi(pos, cfg, arg, put_arg);
584 }
585 }
586 }
587
588 /// Check if a sequence of arguments match a desired sequence of argument types.
check_arg_types(dfg: &DataFlowGraph, args: &[Value], types: &[AbiParam]) -> bool589 fn check_arg_types(dfg: &DataFlowGraph, args: &[Value], types: &[AbiParam]) -> bool {
590 let arg_types = args.iter().map(|&v| dfg.value_type(v));
591 let sig_types = types.iter().map(|&at| at.value_type);
592 arg_types.eq(sig_types)
593 }
594
595 /// Check if the arguments of the call `inst` match the signature.
596 ///
597 /// Returns `Ok(())` if the signature matches and no changes are needed, or `Err(sig_ref)` if the
598 /// signature doesn't match.
check_call_signature(dfg: &DataFlowGraph, inst: Inst) -> Result<(), SigRef>599 fn check_call_signature(dfg: &DataFlowGraph, inst: Inst) -> Result<(), SigRef> {
600 // Extract the signature and argument values.
601 let (sig_ref, args) = match dfg[inst].analyze_call(&dfg.value_lists) {
602 CallInfo::Direct(func, args) => (dfg.ext_funcs[func].signature, args),
603 CallInfo::Indirect(sig_ref, args) => (sig_ref, args),
604 CallInfo::NotACall => panic!("Expected call, got {:?}", dfg[inst]),
605 };
606 let sig = &dfg.signatures[sig_ref];
607
608 if check_arg_types(dfg, args, &sig.params[..])
609 && check_arg_types(dfg, dfg.inst_results(inst), &sig.returns[..])
610 {
611 // All types check out.
612 Ok(())
613 } else {
614 // Call types need fixing.
615 Err(sig_ref)
616 }
617 }
618
619 /// Check if the arguments of the return `inst` match the signature.
check_return_signature(dfg: &DataFlowGraph, inst: Inst, sig: &Signature) -> bool620 fn check_return_signature(dfg: &DataFlowGraph, inst: Inst, sig: &Signature) -> bool {
621 check_arg_types(dfg, dfg.inst_variable_args(inst), &sig.returns)
622 }
623
624 /// Insert ABI conversion code for the arguments to the call or return instruction at `pos`.
625 ///
626 /// - `abi_args` is the number of arguments that the ABI signature requires.
627 /// - `get_abi_type` is a closure that can provide the desired `AbiParam` for a given ABI
628 /// argument number in `0..abi_args`.
629 ///
legalize_inst_arguments<ArgType>( pos: &mut FuncCursor, cfg: &ControlFlowGraph, abi_args: usize, mut get_abi_type: ArgType, ) where ArgType: FnMut(&Function, usize) -> AbiParam,630 fn legalize_inst_arguments<ArgType>(
631 pos: &mut FuncCursor,
632 cfg: &ControlFlowGraph,
633 abi_args: usize,
634 mut get_abi_type: ArgType,
635 ) where
636 ArgType: FnMut(&Function, usize) -> AbiParam,
637 {
638 let inst = pos
639 .current_inst()
640 .expect("Cursor must point to a call instruction");
641
642 // Lift the value list out of the call instruction so we modify it.
643 let mut vlist = pos.func.dfg[inst]
644 .take_value_list()
645 .expect("Call must have a value list");
646
647 // The value list contains all arguments to the instruction, including the callee on an
648 // indirect call which isn't part of the call arguments that must match the ABI signature.
649 // Figure out how many fixed values are at the front of the list. We won't touch those.
650 let num_fixed_values = pos.func.dfg[inst]
651 .opcode()
652 .constraints()
653 .num_fixed_value_arguments();
654 let have_args = vlist.len(&pos.func.dfg.value_lists) - num_fixed_values;
655 if abi_args < have_args {
656 // This happens with multiple return values after we've legalized the
657 // signature but haven't legalized the return instruction yet. This
658 // legalization is handled in `handle_return_abi`.
659 pos.func.dfg[inst].put_value_list(vlist);
660 return;
661 }
662
663 // Grow the value list to the right size and shift all the existing arguments to the right.
664 // This lets us write the new argument values into the list without overwriting the old
665 // arguments.
666 //
667 // Before:
668 //
669 // <--> fixed_values
670 // <-----------> have_args
671 // [FFFFOOOOOOOOOOOOO]
672 //
673 // After grow_at():
674 //
675 // <--> fixed_values
676 // <-----------> have_args
677 // <------------------> abi_args
678 // [FFFF-------OOOOOOOOOOOOO]
679 // ^
680 // old_arg_offset
681 //
682 // After writing the new arguments:
683 //
684 // <--> fixed_values
685 // <------------------> abi_args
686 // [FFFFNNNNNNNNNNNNNNNNNNNN]
687 //
688 vlist.grow_at(
689 num_fixed_values,
690 abi_args - have_args,
691 &mut pos.func.dfg.value_lists,
692 );
693 let old_arg_offset = num_fixed_values + abi_args - have_args;
694
695 let mut abi_arg = 0;
696 for old_arg in 0..have_args {
697 let old_value = vlist
698 .get(old_arg_offset + old_arg, &pos.func.dfg.value_lists)
699 .unwrap();
700 let mut put_arg = |func: &mut Function, arg| {
701 let abi_type = get_abi_type(func, abi_arg);
702 if func.dfg.value_type(arg) == abi_type.value_type {
703 // This is the argument type we need.
704 vlist.as_mut_slice(&mut func.dfg.value_lists)[num_fixed_values + abi_arg] = arg;
705 abi_arg += 1;
706 Ok(())
707 } else {
708 Err(abi_type)
709 }
710 };
711 convert_to_abi(pos, cfg, old_value, &mut put_arg);
712 }
713
714 // Put the modified value list back.
715 pos.func.dfg[inst].put_value_list(vlist);
716 }
717
718 /// Ensure that the `ty` being returned is a type that can be loaded and stored
719 /// (potentially after another narrowing legalization) from memory, since it
720 /// will go into the `sret` space.
legalized_type_for_sret(ty: Type) -> Type721 fn legalized_type_for_sret(ty: Type) -> Type {
722 if ty.is_bool() {
723 let bits = std::cmp::max(8, ty.bits());
724 Type::int(bits).unwrap()
725 } else {
726 ty
727 }
728 }
729
730 /// Insert any legalization code required to ensure that `val` can be stored
731 /// into the `sret` memory. Returns the (potentially new, potentially
732 /// unmodified) legalized value and its type.
legalize_type_for_sret_store(pos: &mut FuncCursor, val: Value, ty: Type) -> (Value, Type)733 fn legalize_type_for_sret_store(pos: &mut FuncCursor, val: Value, ty: Type) -> (Value, Type) {
734 if ty.is_bool() {
735 let bits = std::cmp::max(8, ty.bits());
736 let ty = Type::int(bits).unwrap();
737 let val = pos.ins().bint(ty, val);
738 (val, ty)
739 } else {
740 (val, ty)
741 }
742 }
743
744 /// Insert ABI conversion code before and after the call instruction at `pos`.
745 ///
746 /// Instructions inserted before the call will compute the appropriate ABI values for the
747 /// callee's new ABI-legalized signature. The function call arguments are rewritten in place to
748 /// match the new signature.
749 ///
750 /// Instructions will be inserted after the call to convert returned ABI values back to the
751 /// original return values. The call's result values will be adapted to match the new signature.
752 ///
753 /// Returns `true` if any instructions were inserted.
handle_call_abi( isa: &dyn TargetIsa, mut inst: Inst, func: &mut Function, cfg: &ControlFlowGraph, ) -> bool754 pub fn handle_call_abi(
755 isa: &dyn TargetIsa,
756 mut inst: Inst,
757 func: &mut Function,
758 cfg: &ControlFlowGraph,
759 ) -> bool {
760 let pos = &mut FuncCursor::new(func).at_inst(inst);
761 pos.use_srcloc(inst);
762
763 // Start by checking if the argument types already match the signature.
764 let sig_ref = match check_call_signature(&pos.func.dfg, inst) {
765 Ok(_) => return spill_call_arguments(pos),
766 Err(s) => s,
767 };
768
769 let sig = &pos.func.dfg.signatures[sig_ref];
770 let old_sig = &pos.func.dfg.old_signatures[sig_ref];
771
772 if sig.uses_struct_return_param()
773 && old_sig
774 .as_ref()
775 .map_or(false, |s| !s.uses_struct_return_param())
776 {
777 legalize_sret_call(isa, pos, sig_ref, inst);
778 } else {
779 if !pos.func.dfg.signatures[sig_ref].returns.is_empty() {
780 inst = legalize_inst_results(pos, |func, abi_res| {
781 func.dfg.signatures[sig_ref].returns[abi_res]
782 });
783 }
784 }
785
786 // Go back and fix the call arguments to match the ABI signature.
787 pos.goto_inst(inst);
788 let abi_args = pos.func.dfg.signatures[sig_ref].params.len();
789 legalize_inst_arguments(pos, cfg, abi_args, |func, abi_arg| {
790 func.dfg.signatures[sig_ref].params[abi_arg]
791 });
792
793 debug_assert!(
794 check_call_signature(&pos.func.dfg, inst).is_ok(),
795 "Signature still wrong: {}, {}{}",
796 pos.func.dfg.display_inst(inst, None),
797 sig_ref,
798 pos.func.dfg.signatures[sig_ref]
799 );
800
801 // Go back and insert spills for any stack arguments.
802 pos.goto_inst(inst);
803 spill_call_arguments(pos);
804
805 // Yes, we changed stuff.
806 true
807 }
808
809 /// Insert ABI conversion code before and after the return instruction at `inst`.
810 ///
811 /// Return `true` if any instructions were inserted.
handle_return_abi(inst: Inst, func: &mut Function, cfg: &ControlFlowGraph) -> bool812 pub fn handle_return_abi(inst: Inst, func: &mut Function, cfg: &ControlFlowGraph) -> bool {
813 // Check if the returned types already match the signature.
814 if check_return_signature(&func.dfg, inst, &func.signature) {
815 return false;
816 }
817
818 // Count the special-purpose return values (`link`, `sret`, and `vmctx`) that were appended to
819 // the legalized signature.
820 let special_args = func
821 .signature
822 .returns
823 .iter()
824 .rev()
825 .take_while(|&rt| {
826 rt.purpose == ArgumentPurpose::Link
827 || rt.purpose == ArgumentPurpose::StructReturn
828 || rt.purpose == ArgumentPurpose::VMContext
829 })
830 .count();
831 let abi_args = func.signature.returns.len() - special_args;
832
833 let pos = &mut FuncCursor::new(func).at_inst(inst);
834 pos.use_srcloc(inst);
835
836 legalize_inst_arguments(pos, cfg, abi_args, |func, abi_arg| {
837 let arg = func.signature.returns[abi_arg];
838 debug_assert!(
839 !arg.legalized_to_pointer,
840 "Return value cannot be legalized to pointer"
841 );
842 arg
843 });
844 // Append special return arguments for any `sret`, `link`, and `vmctx` return values added to
845 // the legalized signature. These values should simply be propagated from the entry block
846 // arguments.
847 if special_args > 0 {
848 debug!(
849 "Adding {} special-purpose arguments to {}",
850 special_args,
851 pos.func.dfg.display_inst(inst, None)
852 );
853 let mut vlist = pos.func.dfg[inst].take_value_list().unwrap();
854 let mut sret = None;
855
856 for arg in &pos.func.signature.returns[abi_args..] {
857 match arg.purpose {
858 ArgumentPurpose::Link
859 | ArgumentPurpose::StructReturn
860 | ArgumentPurpose::VMContext => {}
861 ArgumentPurpose::Normal => panic!("unexpected return value {}", arg),
862 _ => panic!("Unsupported special purpose return value {}", arg),
863 }
864 // A `link`/`sret`/`vmctx` return value can only appear in a signature that has a
865 // unique matching argument. They are appended at the end, so search the signature from
866 // the end.
867 let idx = pos
868 .func
869 .signature
870 .params
871 .iter()
872 .rposition(|t| t.purpose == arg.purpose)
873 .expect("No matching special purpose argument.");
874 // Get the corresponding entry block value and add it to the return instruction's
875 // arguments.
876 let val = pos
877 .func
878 .dfg
879 .block_params(pos.func.layout.entry_block().unwrap())[idx];
880 debug_assert_eq!(pos.func.dfg.value_type(val), arg.value_type);
881 vlist.push(val, &mut pos.func.dfg.value_lists);
882
883 if let ArgumentPurpose::StructReturn = arg.purpose {
884 sret = Some(val);
885 }
886 }
887
888 // Store all the regular returns into the retptr space and remove them
889 // from the `return` instruction's value list.
890 if let Some(sret) = sret {
891 let mut offset = 0;
892 let num_regular_rets = vlist.len(&pos.func.dfg.value_lists) - special_args;
893 for i in 0..num_regular_rets {
894 debug_assert_eq!(
895 pos.func.old_signature.as_ref().unwrap().returns[i].purpose,
896 ArgumentPurpose::Normal,
897 );
898
899 // The next return value to process is always at `0`, since the
900 // list is emptied as we iterate.
901 let v = vlist.get(0, &pos.func.dfg.value_lists).unwrap();
902 let ty = pos.func.dfg.value_type(v);
903 let (v, ty) = legalize_type_for_sret_store(pos, v, ty);
904
905 let size = ty.bytes();
906 offset = round_up_to_multiple_of_type_align(offset, ty);
907
908 pos.ins().store(MemFlags::trusted(), v, sret, offset as i32);
909 vlist.remove(0, &mut pos.func.dfg.value_lists);
910
911 offset += size;
912 }
913 }
914 pos.func.dfg[inst].put_value_list(vlist);
915 }
916
917 debug_assert_eq!(
918 pos.func.dfg.inst_variable_args(inst).len(),
919 abi_args + special_args
920 );
921 debug_assert!(
922 check_return_signature(&pos.func.dfg, inst, &pos.func.signature),
923 "Signature still wrong: {} / signature {}",
924 pos.func.dfg.display_inst(inst, None),
925 pos.func.signature
926 );
927
928 // Yes, we changed stuff.
929 true
930 }
931
round_up_to_multiple_of_type_align(bytes: u32, ty: Type) -> u32932 fn round_up_to_multiple_of_type_align(bytes: u32, ty: Type) -> u32 {
933 // We don't have a dedicated alignment for types, so assume they are
934 // size-aligned.
935 let align = ty.bytes();
936 round_up_to_multiple_of_pow2(bytes, align)
937 }
938
939 /// Round `n` up to the next multiple of `to` that is greater than or equal to
940 /// `n`.
941 ///
942 /// `to` must be a power of two and greater than zero.
943 ///
944 /// This is useful for rounding an offset or pointer up to some type's required
945 /// alignment.
round_up_to_multiple_of_pow2(n: u32, to: u32) -> u32946 fn round_up_to_multiple_of_pow2(n: u32, to: u32) -> u32 {
947 debug_assert!(to > 0);
948 debug_assert!(to.is_power_of_two());
949
950 // The simple version of this function is
951 //
952 // (n + to - 1) / to * to
953 //
954 // Consider the numerator: `n + to - 1`. This is ensuring that if there is
955 // any remainder for `n / to`, then the result of the division is one
956 // greater than `n / to`, and that otherwise we get exactly the same result
957 // as `n / to` due to integer division rounding off the remainder. In other
958 // words, we only round up if `n` is not aligned to `to`.
959 //
960 // However, we know `to` is a power of two, and therefore `anything / to` is
961 // equivalent to `anything >> log2(to)` and `anything * to` is equivalent to
962 // `anything << log2(to)`. We can therefore rewrite our simplified function
963 // into the following:
964 //
965 // (n + to - 1) >> log2(to) << log2(to)
966 //
967 // But shifting a value right by some number of bits `b` and then shifting
968 // it left by that same number of bits `b` is equivalent to clearing the
969 // bottom `b` bits of the number. We can clear the bottom `b` bits of a
970 // number by bit-wise and'ing the number with the bit-wise not of `2^b - 1`.
971 // Plugging this into our function and simplifying, we get:
972 //
973 // (n + to - 1) >> log2(to) << log2(to)
974 // = (n + to - 1) & !(2^log2(to) - 1)
975 // = (n + to - 1) & !(to - 1)
976 //
977 // And now we have the final version of this function!
978
979 (n + to - 1) & !(to - 1)
980 }
981
982 /// Assign stack slots to incoming function parameters on the stack.
983 ///
984 /// Values that are passed into the function on the stack must be assigned to an `IncomingArg`
985 /// stack slot already during legalization.
spill_entry_params(func: &mut Function, entry: Block)986 fn spill_entry_params(func: &mut Function, entry: Block) {
987 for (abi, &arg) in func
988 .signature
989 .params
990 .iter()
991 .zip(func.dfg.block_params(entry))
992 {
993 if let ArgumentLoc::Stack(offset) = abi.location {
994 let ss = func.stack_slots.make_incoming_arg(abi.value_type, offset);
995 func.locations[arg] = ValueLoc::Stack(ss);
996 }
997 }
998 }
999
1000 /// Assign stack slots to outgoing function arguments on the stack.
1001 ///
1002 /// Values that are passed to a called function on the stack must be assigned to a matching
1003 /// `OutgoingArg` stack slot. The assignment must happen immediately before the call.
1004 ///
1005 /// TODO: The outgoing stack slots can be written a bit earlier, as long as there are no branches
1006 /// or calls between writing the stack slots and the call instruction. Writing the slots earlier
1007 /// could help reduce register pressure before the call.
spill_call_arguments(pos: &mut FuncCursor) -> bool1008 fn spill_call_arguments(pos: &mut FuncCursor) -> bool {
1009 let inst = pos
1010 .current_inst()
1011 .expect("Cursor must point to a call instruction");
1012 let sig_ref = pos
1013 .func
1014 .dfg
1015 .call_signature(inst)
1016 .expect("Call instruction expected.");
1017
1018 // Start by building a list of stack slots and arguments to be replaced.
1019 // This requires borrowing `pos.func.dfg`, so we can't change anything.
1020 let arglist = {
1021 let locations = &pos.func.locations;
1022 let stack_slots = &mut pos.func.stack_slots;
1023 pos.func
1024 .dfg
1025 .inst_variable_args(inst)
1026 .iter()
1027 .zip(&pos.func.dfg.signatures[sig_ref].params)
1028 .enumerate()
1029 .filter_map(|(idx, (&arg, abi))| {
1030 match abi.location {
1031 ArgumentLoc::Stack(offset) => {
1032 // Assign `arg` to a new stack slot, unless it's already in the correct
1033 // slot. The legalization needs to be idempotent, so we should see a
1034 // correct outgoing slot on the second pass.
1035 let ss = stack_slots.get_outgoing_arg(abi.value_type, offset);
1036 if locations[arg] != ValueLoc::Stack(ss) {
1037 Some((idx, arg, ss))
1038 } else {
1039 None
1040 }
1041 }
1042 _ => None,
1043 }
1044 })
1045 .collect::<Vec<_>>()
1046 };
1047
1048 if arglist.is_empty() {
1049 return false;
1050 }
1051
1052 // Insert the spill instructions and rewrite call arguments.
1053 for (idx, arg, ss) in arglist {
1054 let stack_val = pos.ins().spill(arg);
1055 pos.func.locations[stack_val] = ValueLoc::Stack(ss);
1056 pos.func.dfg.inst_variable_args_mut(inst)[idx] = stack_val;
1057 }
1058
1059 // We changed stuff.
1060 true
1061 }
1062
1063 #[cfg(test)]
1064 mod tests {
1065 use super::round_up_to_multiple_of_pow2;
1066
1067 #[test]
round_up_to_multiple_of_pow2_works()1068 fn round_up_to_multiple_of_pow2_works() {
1069 for (n, to, expected) in vec![
1070 (0, 1, 0),
1071 (1, 1, 1),
1072 (2, 1, 2),
1073 (0, 2, 0),
1074 (1, 2, 2),
1075 (2, 2, 2),
1076 (3, 2, 4),
1077 (0, 4, 0),
1078 (1, 4, 4),
1079 (2, 4, 4),
1080 (3, 4, 4),
1081 (4, 4, 4),
1082 (5, 4, 8),
1083 ] {
1084 let actual = round_up_to_multiple_of_pow2(n, to);
1085 assert_eq!(
1086 actual, expected,
1087 "round_up_to_multiple_of_pow2(n = {}, to = {}) = {} (expected {})",
1088 n, to, actual, expected
1089 );
1090 }
1091 }
1092 }
1093