Returns `Ok(true)`/`Err(MustInlineToLegalize)` if `callee` should/must be inlined (either in general, or specifically from `call_site`, if provided). The distinction made is that `Err(MustInlineToLegalize)` is not a heuristic, and inlining is *mandatory* due to an illegal signature/arguments.
(
legal_globals: &FxHashMap<Word, LegalGlobal>,
functions_that_may_abort: &FxHashSet<Word>,
callee: &Function,
call_site: Option<CallSite<'_>>,
)
| 380 | /// The distinction made is that `Err(MustInlineToLegalize)` is not a heuristic, |
| 381 | /// and inlining is *mandatory* due to an illegal signature/arguments. |
| 382 | fn should_inline( |
| 383 | legal_globals: &FxHashMap<Word, LegalGlobal>, |
| 384 | functions_that_may_abort: &FxHashSet<Word>, |
| 385 | callee: &Function, |
| 386 | call_site: Option<CallSite<'_>>, |
| 387 | ) -> Result<bool, MustInlineToLegalize> { |
| 388 | let callee_def = callee.def.as_ref().unwrap(); |
| 389 | let callee_control = callee_def.operands[0].unwrap_function_control(); |
| 390 | |
| 391 | // HACK(eddyb) this "has a call-site" check ensures entry-points don't get |
| 392 | // accidentally removed as "must inline to legalize" function, but can still |
| 393 | // be inlined into other entry-points (if such an unusual situation arises). |
| 394 | if call_site.is_some() && functions_that_may_abort.contains(&callee.def_id().unwrap()) { |
| 395 | return Err(MustInlineToLegalize); |
| 396 | } |
| 397 | |
| 398 | let ret_ty = legal_globals |
| 399 | .get(&callee_def.result_type.unwrap()) |
| 400 | .ok_or(MustInlineToLegalize)?; |
| 401 | if !ret_ty.legal_as_fn_ret_ty() { |
| 402 | return Err(MustInlineToLegalize); |
| 403 | } |
| 404 | |
| 405 | for (i, param) in callee.parameters.iter().enumerate() { |
| 406 | let param_ty = legal_globals |
| 407 | .get(param.result_type.as_ref().unwrap()) |
| 408 | .ok_or(MustInlineToLegalize)?; |
| 409 | if !param_ty.legal_as_fn_param_ty() { |
| 410 | return Err(MustInlineToLegalize); |
| 411 | } |
| 412 | |
| 413 | // If the call isn't passing a legal pointer argument (a "memory object", |
| 414 | // i.e. an `OpVariable` or one of the caller's `OpFunctionParameters), |
| 415 | // then inlining is required to have a chance at producing legal SPIR-V. |
| 416 | // |
| 417 | // FIXME(eddyb) rewriting away the pointer could be another alternative. |
| 418 | if let (LegalGlobal::TypePointer(_), Some(call_site)) = (param_ty, call_site) { |
| 419 | let ptr_arg = call_site.call_inst.operands[i + 1].unwrap_id_ref(); |
| 420 | match legal_globals.get(&ptr_arg) { |
| 421 | Some(LegalGlobal::Variable) => {} |
| 422 | |
| 423 | // FIXME(eddyb) should some constants (undef/null) be allowed? |
| 424 | Some(_) => return Err(MustInlineToLegalize), |
| 425 | |
| 426 | None => { |
| 427 | let mut caller_param_and_var_ids = call_site |
| 428 | .caller |
| 429 | .parameters |
| 430 | .iter() |
| 431 | .chain( |
| 432 | call_site.caller.blocks[0] |
| 433 | .instructions |
| 434 | .iter() |
| 435 | .filter(|caller_inst| { |
| 436 | // HACK(eddyb) this only avoids scanning the |
| 437 | // whole entry block for `OpVariable`s, so |
| 438 | // it can overapproximate debuginfo insts. |
| 439 | let may_be_debuginfo = matches!( |
no test coverage detected