https://gcc.gnu.org/bugzilla/show_bug.cgi?id=79787
Alexander Ivchenko <aivchenk at gmail dot com> changed: What |Removed |Added ---------------------------------------------------------------------------- CC| |aivchenk at gmail dot com --- Comment #2 from Alexander Ivchenko <aivchenk at gmail dot com> --- Reduced testcase: inline __attribute__((__always_inline__)) __attribute__ ((target("bmi"))) int fn1() {} __attribute__((__always_inline__)) __attribute__ ((target("bmi"))) int fn2() { fn1(); } int fn3() { return fn1(); } Initial call graph: fn3 -(not inlinable because of attribute mismatch)-> fn1<bmi> fn2<bmi> -> fn1<bmi> Call graph before chkp_ecleanup fn3 -> fn3.chkp -(not inlinable because of attribute mismatch)-> fn1.chkp <bmi> fn2.chkp <bmi> -> fn1.chkp <bmi> fn2<bmi> (fn1 is inlined here) When compiler inlines fn1 to fn2 in expand_call_inline, it removes fn1 cnode, as it is no longer needed. There it execute this code (in cgraph_node::remove): if (instrumented_version) { instrumented_version->instrumented_version = NULL; instrumented_version = NULL; } Hence, now fn1.chkp.instrumened_version==NULL and fn1 is removed. And later on in chkp_cleanup in reachability analysis in symbol_table::remove_unreachable_nodes we fail on this assert, where cnode==fn1.chkp /* For instrumentation clones we always need original function node for proper LTO privatization. */ if (cnode->instrumentation_clone && cnode->definition) { => gcc_assert (cnode->instrumented_version || in_lto_p); (since fn1 is removed, we don't consider it in chkp_produce_thunks (early=false))