[LLVMdev] Def/Kill flags for subregisters
Jakob Stoklund Olesen
stoklund at 2pi.dk
Wed Apr 22 00:03:42 PDT 2009
I am trying to locate a bug that affects my Blackfin backend. I am
having some trouble understanding the semantics of def/kill flags on
machine operands when using subregisters.
I compile this function:
define void @i56_ls(i56 %x) nounwind {
store i56 %x, i56* @i56_s
ret void
}
And get this initial machine code:
Live Ins: %R0 %R1
%reg1025D<def> = MOVE %R1
%reg1024D<def> = MOVE %R0
%reg1026D<def> = MOVE %reg1025D
%reg1027P<def> = LOAD32imm <ga:i56_s>
%reg1028D<def> = SRLd %reg1025D, 16
%reg1029D16L<def> = EXTRACT_SUBREG %reg1026D, 1
%reg1030P<def> = ADDimm7 %reg1027P, 4
STORE16pi %reg1029D16L, %reg1030P, Mem:ST(2,4) [i56_s + 4]
STORE8p_imm16 %reg1028D, %reg1027P, 6, Mem:ST(1,2) [i56_s + 6]
STORE32p %reg1024D, %reg1027P, Mem:ST(4,4) [i56_s + 0]
RTS %RETS<imp-use>
So far so good. After coalescing and allocating registers, I have this
code:
Live Ins: %R0 %R1
%P0<def> = LOAD32imm <ga:i56_s>
%R2<def> = MOVE %R1<kill>
%R2<def> = SRLd %R2, 16
%P1<def> = MOVE %P0
%P1<def> = ADDimm7 %P1, 4
STORE16pi %R1L<kill>, %P1<kill>, Mem:ST(2,4) [i56_s + 4]
STORE8p_imm16 %R2<kill>, %P0, 6, Mem:ST(1,2) [i56_s + 6]
STORE32p %R0<kill>, %P0<kill>, Mem:ST(4,4) [i56_s + 0]
RTS %RETS<imp-use>
The important part is:
%R2<def> = MOVE %R1<kill>
STORE16pi %R1L<kill>, %P1<kill>, Mem:ST(2,4) [i56_s + 4]
The register R1L is a subregister of R1 (the low 16 bits). There is
also an R1H subregister, similar to AX/AL/AH in X86.
I assume that %R1<kill> means that now R1, R1L, and R1H are dead. The
register scavenger works that way, and barfs on the code above.
What would be the correct kill flags in this situation? If I remove
the kill flag from %R1<kill>, R1H is left alive.
How about this:
%R2<def> = MOVE %R1, %R1H<imp-use,kill>
STORE16pi %R1L<kill>, %P0<kill>, %R1<imp-use,kill>
According to comments in LiveVariables.cpp, not all of this is
implemented. That probably explains my confusion. How should def/kill
flags work with subregisters if they were fully implemented?
Here is my theory:
1. def/kill applies to all subregisters, so %R1<kill> will kill R1,
R1L, and R1H
2. Liveness of a register can be correctly inferred from the def/kill
flags. This seems to be the assumption of the register scavenger.
3. A register must be killed before it can be defined again.
Is this theory correct?
If so, it would be necessary to sprinkle extra <imp-use,kill> here and
there, like I have done above.
Here is an X86 example:
%EAX<def> = MOV32rm %ESP, 1, %noreg, 8, %noreg, Mem:LD(4,4)
[FixedStack-2 + 0]
%ECX<def> = MOV32rm %ESP, 1, %noreg, 4, %noreg, Mem:LD(4,16)
[FixedStack-1 + 0]
%EDX<def> = LEA32r %ECX, 1, %EAX, 0
%EDX<def> = ADD32rr %EDX, %EAX<kill>, %EFLAGS<imp-def,dead>
%EAX<def> = MOVZX32rr8 %CL<kill>
%EAX<def> = ADD32rr %EAX, %EDX<kill>, %EFLAGS<imp-def,dead>
RET %EAX<imp-use,kill>
This function defines ECX and kills CL, leaving ECX, CX, and CH still
alive. It is not a problem here because ECX is not reused, but I think
that if it were reused, it would not be properly killed first.
More information about the llvm-dev
mailing list