Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RDDSP operands are added too late #27490

Open
MatzeB opened this issue Mar 29, 2016 · 4 comments
Open

RDDSP operands are added too late #27490

MatzeB opened this issue Mar 29, 2016 · 4 comments
Labels
backend:MIPS bugzilla Issues migrated from bugzilla

Comments

@MatzeB
Copy link
Contributor

MatzeB commented Mar 29, 2016

Bugzilla Link 27116
Version trunk
OS All

Extended Description

The RDDSPs operands are currently added in MipsSEDAGToDAGISel::processFunctionAfterISel(), if they are the only user of a physreg then these physreg will appear dead during the earlier InstrEmitter phase of selection dag, so some defs will be incorrectly marked as dead.

This is currently not a problem because the LiveVariables pass happens to reset all dead flags, however long term we plan to remove the whole LiveVariables pass.

(The problem is visible in some functions in test/CodeGen/Mips/dsp-r1.ll when dead flag removal is disabled in the LiveVariables pass.)

@llvmbot
Copy link
Collaborator

llvmbot commented Mar 31, 2016

I don't think how early the implicit uses are added is the whole problem. When InstrEmitter::EmitMachineNode() processes the implicit-def in the CMPU_EQ_Qb instruction, it doesn't see a MVT::Glue value and doesn't see the RDDSP instruction. As a result, it wouldn't see the implicit-use even if it were there.

Shouldn't this function be following both the chain and the glue? I only see code for the glue.

@llvmbot
Copy link
Collaborator

llvmbot commented Mar 31, 2016

I forgot to mention that I've been looking into moving the addition of the implicit-uses to the hasPostISelHook mechanism. This is still too late at the moment but it's very close.

@llvmbot
Copy link
Collaborator

llvmbot commented Apr 1, 2016

I've posted my current experimental patch at http://reviews.llvm.org/differential/diff/52368/ to help me explain why I think there's more to this. Aside from some debug-related noise, this patch moves RDDSP/WRDSP's implicit-use/implicit-def handling into the hasPostISelHook mechanism and moves that mechanism before the call to setPhysRegsDeadExcept().

If I run a test that only contains the failing function from dsp-r1.ll, it emits the output at the bottom of this comment. The interesting bit is between the '{ CMPU_...' and '} CMPU_...' lines which shows that %DSPCCond is declared dead without looking at the RDDSP. This is because it's only looking at uses in the glue chain. I believe it should be looking at the output chain as well.

If we were to search the output chain as well, we would then find the RDDSP but would only consult the statically defined implicit-defs/implicit-uses in the MCInstrDesc objects. In the case of RDDSP/WRDSP, these are currently calculated from the immediate and are added in the post-ISel hook. This can be solved by iterating over the implicit_operands() of the newly created instruction but we don't appear to have enough liveness information to get the dead flag correct and the safe assumption (always live) harms register allocation*.

At this point I don't see a simple way to fix the crash while preserving the dynamically generated implicit-defs/implicit-uses. Does anyone have any suggestions? If not, I'll probably have to make RDDSP/WRDSP say they always act on the whole dsp control register. This will harm code quality but hopefully it will only be a tiny amount.

  • While looking into this I've noticed a few other physical registers that are declared dead despite having later uses. One example is the stack pointer after an ADJCALLSTACKUP or ADJCALLSTACKDOWN. This is wrong but the stack pointer is a reserved register so it's probably harmless. However, return registers from call instructions are also dead before they are copied to virtual registers. This isn't very obvious because the instruction printer sometimes omits dead implicit-defs (see HasAliasLive in MachineInstr.cpp).

Output:
.text
.abicalls
.section .mdebug.abi32,"",@progbits
.nan legacy
.file "tmp.ll"
< t10: ch = CMPU_EQ_QB t7, t8, t0
{ CMPU_EQ_QB %vreg4, %vreg3, %DSPCCond; DSPR:%vreg4,%vreg3
.. no phys reg outs
.. no glue to scan

t10: ch = CMPU_EQ_QB t7, t8, t0
} CMPU_EQ_QB %vreg4, %vreg3, %DSPCCond<imp-def,dead>; DSPR:%vreg4,%vreg3
< t13: i32,ch = RDDSP TargetConstant:i32<31>, t10
{ %vreg5 = RDDSP 31; G#32 :%vreg5
.. no phys reg outs
.. no glue to scan
t13: i32,ch = RDDSP TargetConstant:i32<31>, t10
} %vreg5 = RDDSP 31, %DSPPos, %DSPSCount, %DSPCarry, %DSPOutFlag, %DSPCCond; G#32 :%vreg5
< t16: ch = RetRA Register:i32 %V0, t15, t15:1
{ RetRA %V0
.. no phys reg outs
.. no glue to scan
t16: ch = RetRA Register:i32 %V0, t15, t15:1
} RetRA %V0

In Register Scavenger

Machine code for function test__builtin_mips_cmpu_eq_qb1: Properties: : Post SSA

Function Live Ins: %A1, %A2

BB#0: derived from LLVM BB %entry
Live Ins: %A1 %A2
CMPU_EQ_QB %A1, %A2, %DSPCCond<imp-def,dead>
%V0 = RDDSP 31, %DSPPos, %DSPSCount, %DSPCarry, %DSPOutFlag, %DSPCCond<imp-use,kill>
RetRA %V0

End machine code for function test__builtin_mips_cmpu_eq_qb1.

*** Bad machine code: Using an undefined physical register ***

  • function: test__builtin_mips_cmpu_eq_qb1
  • basic block: BB#0 entry (0x157f6f8)
  • instruction: %V0 = RDDSP
  • operand 6: %DSPCCond<imp-use,kill>
    LLVM ERROR: Found 1 machine code errors.

@MatzeB
Copy link
Contributor Author

MatzeB commented Apr 2, 2016

I think if the operands are just added to the MachineInstr it is too late either way as the InstrEmitter code only looks at the selection DAG nodes and the MCInstrDesc. With the current code we would need additional SDNode operands to show the reads/writes, maybe there is a way to produce CopyFromReg/CopyToReg in a custom lower callback?

I am not sure why we deal with adding dead flags in code selection at all. The liveness calculations (LiveVariables + LiveIntervalAnalysis) can both detect them so the allocation should be the same. The only register allocator affected would be FastRegAlloc which is designed for compile time first anyway.

The fact that we add a dead flag to a reserved register is also very odd but indeed harmless as none of the liveness based architecture depends on it.

Note that this issue can be low priority at the moment. The issue mainly popped up because I am in the process of adding a new pass (DetectDeadLanes) which uses a more precise dataflow analysis across COPY-like instructions to find dead/unused operands. I just needed the LiveVariables pass to not remove the dead flags added by the more precise analysis, luckily this only affects virtual regs, so I left the code that removes dead flags from physregs in.

@llvmbot llvmbot transferred this issue from llvm/llvm-bugzilla-archive Dec 10, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
backend:MIPS bugzilla Issues migrated from bugzilla
Projects
None yet
Development

No branches or pull requests

2 participants