https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85449
Bug ID: 85449 Summary: [8 Regression] Wrong specialization is called in self recursive functions after r259319 Product: gcc Version: 8.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: ipa Assignee: unassigned at gcc dot gnu.org Reporter: tnfchris at gcc dot gnu.org CC: marxin at gcc dot gnu.org Target Milestone: --- Created attachment 43977 --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=43977&action=edit preprocessed file After commit r259319 IPA seems to be calling the wrong specialized function. The testcase comes from the following library https://github.com/akheron/jansson, specifically this file https://github.com/akheron/jansson/blob/master/src/dump.c I have not been able to reduce it yet as I have no real easy way to check when it does the replacement wrong but I have attached a `.i` file and issue can be reproduced using it by using `-Ofast` or `-O3`. This is what I have been able to tell so far. The issue is caused by a self recursive call in the function static int do_dump(const json_t *json, size_t flags, int depth, json_dump_callback_t dump, void *data) where json_dump_callback_t dump is a function pointer to local functions. There are only two call sites for do_dump other than itself. char *json_dumps(const json_t *json, size_t flags) { strbuffer_t strbuff; char *result; if(strbuffer_init(&strbuff)) return NULL; if(json_dump_callback(json, dump_to_strbuffer, (void *)&strbuff, flags)) result = NULL; else result = jsonp_strdup(strbuffer_value(&strbuff)); strbuffer_close(&strbuff); return result; } int json_dumpf(const json_t *json, FILE *output, size_t flags) { return json_dump_callback(json, dump_to_file, (void *)output, flags); } where dump_to_strbuffer expects to write into a memory buffer and dump_to_file writing to an actual file. So IPA decides to create 8 specializations for this function (whereas before this patch it created 4.), it creates them by amongst others inlining the calls to these two dump callbacks, and eventually even inlines the callbacks themselves. The problematic specialization occurs for the function {{do_dumps}} which has amonst others .LVL289: .loc 1 368 24 fmov x4, d8 mov x3, x19 mov w2, 1 mov x1, x21 bl do_dump The first specialization occurs when a helper function {{dump_indent}} is inline, creating {{do_dumps.constprop.4}} which is supposed to still take the callbacks as arguments. and indeed looking at the assembly is shows json_dumps: ... .L260: adrp x2, dump_to_strbuffer mov x1, x20 mov x0, x19 add x3, sp, 40 .LVL440: add x2, x2, :lo12:dump_to_strbuffer bl do_dump.constprop.4 so far so good. But the recursive call to do_dump in the specialized constprop.4 version inexplicably calls do_dump.constprop.5 in some (2 out of the many) cases. Where do_dump.constprop.5 is a more specialized version of constprop.4 which also inlined the dump_to_file function. do_dump.constprop.5: ... add x0, x0, :lo12:.LC14 mov x1, 4 bl fwrite So the initial callback which is passed is dump_to_strbuffer is ignored and a call to dump_to_file is essentially made. causing a segfault. The first place this seems to go wrong is `.i.075i.cp` looking at the dependencies of `constprop.4/82` which is supposed to be the generic clone do_dump.constprop.4/82 (do_dump.constprop) @0x7ff4280128a0 ... Calls: json_integer_value/55 (119292717 (estimated locally),0.11 per call) snprintf/56 (119292717 (estimated locally),0.11 per call) json_real_value/57 (119292717 (estimated locally),0.11 per call) jsonp_dtostr/58 (119292717 (estimated locally),0.11 per call) json_string_value/59 (119292717 (estimated locally),0.11 per call) dump_string/39 (119292717 (estimated locally),0.11 per call) json_array_size/60 (116799499 (estimated locally),0.11 per call) dump_indent.constprop/85 (56497842 (estimated locally),0.05 per call) json_array_get/61 (341791464 (estimated locally),0.32 per call) do_dump.constprop/83 (341791464 (estimated locally),0.32 per call) dump_indent.constprop/85 (244621272 (estimated locally),0.23 per call) dump_indent/38 (70872647 (estimated locally),0.07 per call) json_object_iter/62 (116799499 (estimated locally),0.11 per call) dump_indent.constprop/85 (79811293 (estimated locally),0.07 per call) json_object_size/63 (26063814 (estimated locally),0.02 per call) jsonp_malloc/64 (26063814 (estimated locally),0.02 per call) jsonp_object_iter_fullkey/65 (209930993 (estimated locally),0.20 per call) json_object_iter_next/66 (209930993 (estimated locally),0.20 per call) __assert_fail/67 (10379 (estimated locally),0.00 per call) qsort/69 (25936149 (estimated locally),0.02 per call) json_object_get/70 (181163084 (estimated locally),0.17 per call) __assert_fail/67 (72465 (estimated locally),0.00 per call) dump_string/39 (181090619 (estimated locally),0.17 per call) do_dump.constprop/83 (175404373 (estimated locally),0.16 per call) <--- this reference is wrong jsonp_free/71 (11193943 (estimated locally),0.01 per call) dump_indent.constprop/85 (110256487 (estimated locally),0.10 per call) jsonp_free/71 (7036340 (estimated locally),0.01 per call) dump_indent/38 (56065903 (estimated locally),0.05 per call) jsonp_free/71 (1760469 (estimated locally),0.00 per call) jsonp_free/71 (5872931 (estimated locally),0.01 per call) json_object_iter_next/66 (309742814 (estimated locally),0.29 per call) json_object_iter_key/72 (309742814 (estimated locally),0.29 per call) dump_string/39 (309742814 (estimated locally),0.29 per call) json_object_iter_value/73 (298406227 (estimated locally),0.28 per call) do_dump.constprop/83 (298406227 (estimated locally),0.28 per call) dump_indent.constprop/85 (228688039 (estimated locally),0.21 per call) dump_indent/38 (50108559 (estimated locally),0.05 per call) ... But I have not figured out why it thinks this.