Following is a simple example: #include <stdio.h> void foo (char*, FILE*); char* hprofStartupp(char *outputFileName, char *ctx) { char fileName[1000]; FILE *fp; sprintf(fileName, outputFileName); if (access(fileName, 1) == 0) { free(ctx); //A return 0; //A }
fp = fopen(fileName, 0); if (fp == 0) { free(ctx); //B return 0; //B } foo(outputFileName, fp); return ctx; } Basic block A and basic block B are exact same. They do some cleanup work and exit the function. This pattern is quite common in large software. GCC failed to merge them in this test case. With options -march=armv7-a -mthumb -Os, gcc generates: ... bl access mov r7, r0 cbnz r0, .L2 mov r0, r4 //C mov r4, r7 //C bl free //C b .L3 //C .L2: mov r0, sp movs r1, #0 bl fopen mov r5, r0 cbnz r0, .L4 mov r0, r4 //D mov r4, r5 //D bl free //D b .L3 //D .L4: ... Here basic block C corresponds to basic block A, and basic block D corresponds basic block B. They can be merged as following: ... bl access mov r5, r0 cbz r0, .L9 .L2: mov r0, sp movs r1, #0 bl fopen mov r5, r0 cbnz r0, .L4 .L9: mov r0, r4 mov r4, r5 bl free b .L3 .L4: ... The rtl cfg optimization can do some merge optimization. But it often fails due to difference of register numbers. We may need to do this at tree level. -- Summary: Same basic blocks should be merged Product: gcc Version: 4.6.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: middle-end AssignedTo: unassigned at gcc dot gnu dot org ReportedBy: carrot at google dot com GCC build triplet: i686-linux GCC host triplet: i686-linux GCC target triplet: arm-eabi http://gcc.gnu.org/bugzilla/show_bug.cgi?id=43864