[llvm-dev] {ARM} IfConversion does not detect BX instruction as a branch

Friedman, Eli via llvm-dev llvm-dev at lists.llvm.org
Tue Oct 10 16:48:00 PDT 2017


On 10/9/2017 3:10 AM, Gaël Jobin via llvm-dev wrote:
>
> Hi all,
>
> I got a silly bug when compiling our project with the latest Clang. 
> Here's the outputted assembly:
>
>> tst r3, #255
>> strbeq r6, [r7]
>> ldreq r6, [r4, r6, lsl #2]
>> strne r6, [r7, #4]
>> ldr r6, [r4, r6, lsl #2]
>> bx r6
>>
> For the code to execute correctly, either the /ldr/ should be a 
> /ldrne/ instruction or the /ldreq/ instruction should be removed. The 
> error seems to come from the IfConvertion MachinePass. Here's is what 
> it looks like before and after.
>
>> #BEFORE IfConversion MachinePass
>>
>> BB#7:
>>    Live Ins: %LR %R0 %R1 %R2 %R4 %R5 %R6 %R7 %R8 %R9 %R10 %R12
>>    Predecessors according to CFG: BB#5 BB#6
>>    STRBi12 %R5, %R6<kill>, 0, pred:14, pred:%noreg; 
>> mem:ST1[%cond.i23.i.i.i]
>>    %R6<def> = LDRBi12 %R7, 0, pred:14, pred:%noreg; 
>> mem:LD1[%15](align=4)
>>    %R3<def> = EORri %R6, 254, pred:14, pred:%noreg, opt:%noreg
>>    %R3<def> = ANDrr %R3<kill>, %R6<kill>, pred:14, pred:%noreg, 
>> opt:%noreg
>>    %R6<def> = MOVi 0, pred:14, pred:%noreg, opt:%noreg
>>    TSTri %R3<kill>, 255, pred:14, pred:%noreg, %CPSR<imp-def>;
>>    Bcc <BB#9>, pred:0, pred:%CPSR<kill>;
>>
>>
>> BB#8:
>>    Live Ins: %LR %R0 %R1 %R2 %R4 %R5 %R6 %R7 %R8 %R9 %R10 %R12
>>    Predecessors according to CFG: BB#7
>>    STRi12 %R6, %R7<kill>, 4, pred:14, pred:%noreg; 
>> mem:ST4[%__size_.i3.i.i.i.i]
>>    %R6<def> = LDRrs %R4, %R6<kill>, 16386, pred:14, pred:%noreg; 
>> mem:LD4[%0]
>>    BX %R6<kill>
>>
>> BB#9:
>>    Live Ins: %LR %R0 %R1 %R2 %R4 %R5 %R6 %R7 %R8 %R9 %R10 %R12
>>    Predecessors according to CFG: BB#7
>>    STRBi12 %R6, %R7<kill>, 0, pred:14, pred:%noreg; 
>> mem:ST1[%21](align=4)
>>    %R6<def> = LDRrs %R4, %R6<kill>, 16386, pred:14, pred:%noreg; 
>> mem:LD4[%0]
>>    BX %R6<kill>
>>
>> #AFTER IfConversion MachinePass
>>
>> BB#7:
>>    ...
>>    TSTri %R3<kill>, 255, pred:14, pred:%noreg, %CPSR<imp-def>;
>>    STRBi12 %R6, %R7, 0, pred:0, pred:%CPSR; mem:ST1[%21](align=4)
>>    %R6<def> = LDRrs %R4, %R6<kill>, 16386, pred:0, pred:%CPSR, 
>> %R6<imp-use,kill>; mem:LD4[%0]
>>    STRi12 %R6, %R7<kill>, 4, pred:1, pred:%CPSR<kill>; 
>> mem:ST4[%__size_.i3.i.i.i.i]
>>    %R6<def> = LDRrs %R4, %R6<kill>, 16386, pred:14, pred:%noreg; 
>> mem:LD4[%0]
>>    BX %R6<kill>
>>
> Inside the /IfConvertDiamondCommon(...)/ function of IfConversion.cpp, 
> the function is called with /NumDups2=1/, which makes sense because 
> BB#8 and BB#9 share the same /LDRrs/ instruction with the same 
> operands. The problem is the call to /TTI->removeBranch(...)/ function 
> that does not remove the /BX/ instruction. Thus, when removing the 
> common instructions, the /BX/ is removed instead of the /LDRs/ 
> instruction.
>
>> # Before removeBranch call on MBB1
>> BB#9: derived from LLVM BB %if.else.i.i.i.i
>>    Live Ins: %LR %R0 %R1 %R2 %R4 %R5 %R6 %R7 %R8 %R9 %R10 %R12
>>    Predecessors according to CFG: BB#7
>>    STRBi12 %R6, %R7<kill>, 0, pred:14, pred:%noreg; 
>> mem:ST1[%21](align=4)
>>    %R6<def> = LDRrs %R4, %R6<kill>, 16386, pred:14, pred:%noreg; 
>> mem:LD4[%0]
>>    BX %R6<kill>
>>
>> # After removeBranch call on MBB1, returned value:0
>> BB#9: derived from LLVM BB %if.else.i.i.i.i
>>    Live Ins: %LR %R0 %R1 %R2 %R4 %R5 %R6 %R7 %R8 %R9 %R10 %R12
>>    Predecessors according to CFG: BB#7
>>    STRBi12 %R6, %R7<kill>, 0, pred:14, pred:%noreg; 
>> mem:ST1[%21](align=4)
>>    %R6<def> = LDRrs %R4, %R6<kill>, 16386, pred:14, pred:%noreg; 
>> mem:LD4[%0]
>>    BX %R6<kill>
>>
>> #After removing common instructions (NumDups2=1) on MBB1
>> BB#9: derived from LLVM BB %if.else.i.i.i.i
>>    Live Ins: %LR %R0 %R1 %R2 %R4 %R5 %R6 %R7 %R8 %R9 %R10 %R12
>>    Predecessors according to CFG: BB#7
>>    STRBi12 %R6, %R7<kill>, 0, pred:14, pred:%noreg; 
>> mem:ST1[%21](align=4)
>>   %R6<def> = LDRrs %R4, %R6<kill>, 16386, pred:14, pred:%noreg; 
>> mem:LD4[%0]
>>
>> #After predicated on MBB1
>> BB#9: derived from LLVM BB %if.else.i.i.i.i
>>    Live Ins: %LR %R0 %R1 %R2 %R4 %R5 %R6 %R7 %R8 %R9 %R10 %R12
>>    Predecessors according to CFG: BB#7
>>    STRBi12 %R6, %R7<kill>, 0, pred:0, pred:%CPSR; mem:ST1[%21](align=4)
>>   %R6<def> = LDRrs %R4, %R6<kill>, 16386, pred:0, pred:%CPSR; mem:LD4[%0]
>>
> We can clearly see that the /LDRrs/ is still there. As a result, after 
> BB#9 and BB#8 have been merged into BB#7, the /LDRs/ instruction is 
> done twice when the "positive" path is taken.
>
> My current fix is the following:
>
>> @@ -408,7 +408,8 @@ unsigned 
>> ARMBaseInstrInfo::removeBranch(MachineBasicBlock &MBB,
>>    return 0;
>>
>>    if (!isUncondBranchOpcode(I->getOpcode()) &&
>> -      !isCondBranchOpcode(I->getOpcode()))
>> +     !isCondBranchOpcode(I->getOpcode()) &&
>> +     !isIndirectBranchOpcode(I->getOpcode()))
>>       return 0;
>>
> Does that makes sense?
>

Target-independent code is only supposed to call removeBranch in cases 
where analyzeBranch returns false; as far as I can tell, 
ARMBaseInstrInfo::analyzeBranch will never return false for an indirect 
branch.  So I would guess there's a bug in IfConversion, rather than the 
ARM backend.

-Eli

-- 
Employee of Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20171010/ecbce300/attachment.html>


More information about the llvm-dev mailing list