Optimization passes break machine instructions on new backend

Hello!

I’m working on a new back-end and have hit a bit of a snag. I’m working on getting selectcc working and have followed the MSP430 model of emitting a custom CMP and SELECT_CC node and matching that with a pseudo-instruction that has useCustomEmitter=1. However, my output ends up very wrong, despite the Machine code being initially correct:

Machine code for function func:

Function Live Ins: %R0 in reg%16384, %R1 in reg%16385, %R2 in reg%16386, %R3 in reg%16387
Function Live Outs: %R0

BB#0: derived from LLVM BB %entry
Live Ins: %R0 %R1 %R2 %R3
%reg16387 = COPY %R3; IntRegs:%reg16387
%reg16386 = COPY %R2; IntRegs:%reg16386
%reg16385 = COPY %R1; IntRegs:%reg16385
%reg16384 = COPY %R0; IntRegs:%reg16384
%reg16390 = MOVE %reg16386; IntRegs:%reg16390,16386
%reg16388 = CMPrr %reg16384, %reg16385, %CFR<imp-def,dead>; IntRegs:%reg16388,16384,16385
SKIPCOND 1, %CFR
Successors according to CFG: BB#2 BB#1

BB#1: derived from LLVM BB %entry
Predecessors according to CFG: BB#0
%reg16391 = MOVE %reg16387; IntRegs:%reg16391,16387
Successors according to CFG: BB#2

BB#2: derived from LLVM BB %entry
Predecessors according to CFG: BB#0 BB#1
%reg16389 = PHI %reg16390, <BB#0>, %reg16391, <BB#1>; IntRegs:%reg16389,16390,16391
%R0 = COPY %reg16389; IntRegs:%reg16389
RET

End machine code for function func.

-print-before-all indicates that the machines code sinking pass is wrecking this, because after that the machine code becomes:

Machine code for function func:

Function Live Ins: %R0 in reg%16384, %R1 in reg%16385, %R2 in reg%16386, %R3 in reg%16387
Function Live Outs: %R0

BB#0: derived from LLVM BB %entry
Live Ins: %R0 %R1 %R2 %R3
%reg16387 = COPY %R3; IntRegs:%reg16387
%reg16386 = COPY %R2; IntRegs:%reg16386
%reg16385 = COPY %R1; IntRegs:%reg16385
%reg16384 = COPY %R0; IntRegs:%reg16384
%reg16390 = MOVE %reg16386; IntRegs:%reg16390,16386
SKIPCOND 1, %CFR
Successors according to CFG: BB#2 BB#1

BB#1: derived from LLVM BB %entry
Predecessors according to CFG: BB#0
%reg16391 = MOVE %reg16387; IntRegs:%reg16391,16387
Successors according to CFG: BB#2

BB#2: derived from LLVM BB %entry
Predecessors according to CFG: BB#0 BB#1
%reg16389 = PHI %reg16390, <BB#0>, %reg16391, <BB#1>; IntRegs:%reg16389,16390,16391
%reg16388 = CMPrr %reg16384, %reg16385, %CFR<imp-def,dead>; IntRegs:%reg16388,16384,16385
%R0 = COPY %reg16389; IntRegs:%reg16389
RET

End machine code for function func.

The CMPrr instruction is moved down to after the PHI node. My guess is that the ‘dead’ in CFR<imp-def,dead> is to blame, but I can’t see what I’m doing differently from MSP430/sparc that makes this not work. Any help GREATLY appreciated!

//Per

Hello Per,

The CMPrr instruction is moved down to after the PHI node. My guess is that
the 'dead' in CFR<imp-def,dead> is to blame, but I can't see what I'm doing
differently from MSP430/sparc that makes this not work. Any help GREATLY
appreciated!

It seems like no use of CFR after CMP, indeed. How condbranches on
your platform look like (patterns, etc.) ?

But in the first version it’s used on the next row:
%reg16388 = CMPrr %reg16384, %reg16385, %CFR<imp-def,dead>; IntRegs:%reg16388,16384,16385
SKIPCOND 1, %CFR
Or doesn’t that count?

Following are patters for cmp and skipcond:

def cmpcc : SDNode<“CSISD::CMP”, SDTIntBinOp, [SDNPOutFlag]>;
let Defs = [CFR] in {

def CMPrr : InstCS<(outs IntRegs:$dst), (ins IntRegs:$b, IntRegs:$c),
“cmp $c, $dst”,
[(set IntRegs:$dst, (cmpcc IntRegs:$b, IntRegs:$c)), (implicit CFR)]>;
}

let Uses = [CFR], isBranch = 1, isTerminator = 1 in
def SKIPCOND : InstCS<(outs), (ins CCOp:$cc),
“s$cc”,
[(skipcc imm:$cc)]>;

Hello Per,

 SKIPCOND 1, %CFR&lt;imp\-use&gt;

Or doesn't that count?

Ah, sorry, I didn't recognize the stuff due to funky name. Let me
think on the issue more thoroughly then :slight_smile:

It just occured to me that perhaps what happens is that since the cmp-instruction is initially followed by the pseudo-instruction - which doesn’t have Uses = [CFR] - that it’s marked dead initially, and never changed back when the SKIPCOND is inserted by the custom emitter? But I feel that this would happen in e.g. MSP430 too then…

Sorry to write so many small mails.

I just tried adding Uses = [CFR] to the selectcc pseudo instruction, and - voila! - it works! So I guess my question should be rephrased “Why would my back-end, modeled on another existing back-end, not be flagging the implicit register as live?”