https://gcc.gnu.org/bugzilla/show_bug.cgi?id=120702
Bug ID: 120702 Summary: Extraneous string constant at -Os Product: gcc Version: 13.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: tree-optimization Assignee: unassigned at gcc dot gnu.org Reporter: amacleod at redhat dot com Target Milestone: --- Target: arm-none-eabi Created attachment 61660 --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=61660&action=edit Testcase demonstrating the problem When compiled with -Os (or any optimization level) the attached testcase produces 2 copies of the string constant. This is a small sample of a much larger problem when we are suppose to be compiling to preserve size. The text from the email thread summarizes the issue: >>> After the gimple lowering, the verify routine remains the same, but >>> the benchmark () routine is transformed from a memcpy and becomes: >>> >>> >>> ;; Function benchmark (benchmark, funcdef_no=1, decl_uid=4718, >>> cgraph_uid=4, symbol_order=3) >>> >>> int benchmark () >>> { >>> int D.4726; >>> >>> MEM <unsigned char[10]> [(char * {ref-all})&test] = MEM >>> <unsigned char[10]> [(char * {ref-all})&orig]; >>> D.4726 = 0; >>> goto <D.4727>; >>> <D.4727>: >>> return D.4726; >>> } >>> >>> >>> It appears that forwprop is then transforming the statement to >>> <bb 2> : >>> MEM <unsigned char[10]> [(char * {ref-all})&test] = "J2OZF50FYL"; >>> return 0; >>> >>> And in the final output, there are now 2 copies of the original >>> character data: >>> >>> orig: >>> .ascii "J2OZF50FYL" >>> .space 2 >>> .LC0: >>> .ascii "J2OZF50FYL" >>> .bss >>> >>> >>> and I presume that new string is a copy of the orig text that >>> forwprop has created for some reason. >>> >>> Whats going on, and is there a way to disable this? Either at the >>> lowering stage or in forwprop? At -Os, they are not thrilled that a >>> bunch more redundant text is being generated in the object file. >>> This is a reduced testcase to demonstrate a much larger problem. >>> >> The hope is the static var can be elided and the read might be just a >> small part. In this case heuristics are misfiring I guess. You’d >> have to track down where exactly in folding we are replacing the RHS >> of an aggregate copy. I can’t recall off my head. >> >> Richard > > heres my traceback where the "magic" happens > > #0 fold_ctor_reference (type=0x7fffe9f3be70, ctor=0x7fffe9f2cc00, > poly_offset=..., poly_size=..., from_decl=0x7fffe9c6f980, suboff=0x0) at > /gcc/master/gcc/gcc/gimple-fold.cc:9955 > #1 0x0000000001200074 in fold_const_aggregate_ref_1 (t=0x7fffe9f46de8, > valueize=0x0) at /gcc/master/gcc/gcc/gimple-fold.cc:10134 > #2 0x0000000001200918 in fold_const_aggregate_ref (t=0x7fffe9f46de8) at > /gcc/master/gcc/gcc/gimple-fold.cc:10213 > #3 0x00000000011db1aa in maybe_fold_reference (expr=0x7fffe9f46de8) at > /gcc/master/gcc/gcc/gimple-fold.cc:325 > #4 0x00000000011db8bf in fold_gimple_assign (si=0x7fffffffd410) at > /gcc/master/gcc/gcc/gimple-fold.cc:473 > #5 0x00000000011f20d5 in fold_stmt_1 (gsi=0x7fffffffd410, > inplace=false, valueize=0x18d3b10 <fwprop_ssa_val(tree)>, > dce_worklist=0x7fffffffd4c0) at /gcc/master/gcc/gcc/gimple-fold.cc:6648 > > ctor is a STRING_CST tree and has the string in it : "J2OZF50FYL" > > The fold routine gets to : > > /* We found the field with exact match. */ > if (type > && useless_type_conversion_p (type, TREE_TYPE (ctor)) > && known_eq (poly_offset, 0U)) > return canonicalize_constructor_val (unshare_expr (ctor), from_decl); > > I would hazard a guess that it is the "unshare_expr (ctor)" that is > causing the duplication of the string? I presume we have a good reason > for doing this? Perhaps that is a bad thing at -Os? I don't relally > remember all the unsharing details 🙂 unshare_expr doesn't unshare a STRING_CST. But here I think it's fold_stmt_1 that shouldn't replace the RHS with a STRING_CST. We should really have the constant pool represented and have a CONST_DECL for each STRING_CST, but we don't. There might be cases where a STRING_CST is cheaper (for example when it's power-of-two size and less than word_mode as the copy can then be a store from an immediate), but in general a STRING_CST will end up as a new constant pool entry as you've seen.