(sess: &Session, module: &mut Module)
| 28 | } |
| 29 | |
| 30 | pub fn inline(sess: &Session, module: &mut Module) -> super::Result<()> { |
| 31 | // This algorithm gets real sad if there's recursion - but, good news, SPIR-V bans recursion |
| 32 | deny_recursion_in_module(sess, module)?; |
| 33 | |
| 34 | let custom_ext_inst_set_import = module |
| 35 | .ext_inst_imports |
| 36 | .iter() |
| 37 | .find(|inst| { |
| 38 | assert_eq!(inst.class.opcode, Op::ExtInstImport); |
| 39 | inst.operands[0].unwrap_literal_string() == &custom_insts::CUSTOM_EXT_INST_SET[..] |
| 40 | }) |
| 41 | .map(|inst| inst.result_id.unwrap()); |
| 42 | |
| 43 | // HACK(eddyb) compute the set of functions that may `Abort` *transitively*, |
| 44 | // which is only needed because of how we inline (sometimes it's outside-in, |
| 45 | // aka top-down, instead of always being inside-out, aka bottom-up). |
| 46 | // |
| 47 | // (inlining is needed in the first place because our custom `Abort` |
| 48 | // instructions get lowered to a simple `OpReturn` in entry-points, but |
| 49 | // that requires that they get inlined all the way up to the entry-points) |
| 50 | let functions_that_may_abort = custom_ext_inst_set_import |
| 51 | .map(|custom_ext_inst_set_import| { |
| 52 | let mut may_abort_by_id = FxHashSet::default(); |
| 53 | |
| 54 | // FIXME(eddyb) use this `CallGraph` abstraction more during inlining. |
| 55 | let call_graph = CallGraph::collect(module); |
| 56 | for func_idx in call_graph.post_order() { |
| 57 | let func_id = module.functions[func_idx].def_id().unwrap(); |
| 58 | |
| 59 | let any_callee_may_abort = call_graph.callees[func_idx].iter().any(|&callee_idx| { |
| 60 | may_abort_by_id.contains(&module.functions[callee_idx].def_id().unwrap()) |
| 61 | }); |
| 62 | if any_callee_may_abort { |
| 63 | may_abort_by_id.insert(func_id); |
| 64 | continue; |
| 65 | } |
| 66 | |
| 67 | let may_abort_directly = module.functions[func_idx].blocks.iter().any(|block| { |
| 68 | match &block.instructions[..] { |
| 69 | [.., last_normal_inst, terminator_inst] |
| 70 | if last_normal_inst.class.opcode == Op::ExtInst |
| 71 | && last_normal_inst.operands[0].unwrap_id_ref() |
| 72 | == custom_ext_inst_set_import |
| 73 | && CustomOp::decode_from_ext_inst(last_normal_inst) |
| 74 | == CustomOp::Abort => |
| 75 | { |
| 76 | assert_eq!(terminator_inst.class.opcode, Op::Unreachable); |
| 77 | true |
| 78 | } |
| 79 | |
| 80 | _ => false, |
| 81 | } |
| 82 | }); |
| 83 | if may_abort_directly { |
| 84 | may_abort_by_id.insert(func_id); |
| 85 | } |
| 86 | } |
| 87 |
no test coverage detected