[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