[LLVMdev] Question about an unusual jump instruction
Michele Scandale
michele.scandale at gmail.com
Wed Jul 25 00:48:02 PDT 2012
Dear all,
I'm working on an exploratory backend on llvm. In the instruction set I'm using
I have an instruction (called DECJNZ) that decrements a register and, if the
decremented value is not zero, jumps (with a relative jump) to a given offset.
I've described in tablegen this instruction as follow:
def DECJNZ : Instruction {
let Namespace = "MyTarget";
let OutOperandList = (outs GprRegs:$R0);
let InOperandList = (ins GprRegs: $R1, imm16:$dest);
let AsmString = "DECJNZ $R0, $dest";
let isBranch = 1;
let isTerminator = 1;
let Constraints = "$R1 = $R0";
let Defs = [SR];
}
I would like to create an optimization pass to make countable loops faster by
using this instruction.
The simplest loop that I would like to optimize is like:
//////////////////////////
int i = a;
do {
// loop body
--i;
} while (i != 0);
//////////////////////////
After code selection I've something like:
BB0:
%vreg0<def> = COPY %R0; // R0 contains 'a'
J <#BB1>
BB1:
%vreg1<def> = PHI %vreg0, <#BB0>, %vreg3, <#BB3>
J <#BB2>
BB2:
// loop body
BB3:
%vreg3<def> = ADDI %vreg1<kill>, 1
CMPNE %vreg3, 0, %SR<implicit,def>
JNZ <#BB1>
J <#BB4>
BB4:
// end
With the optimization pass I replace the decrement, comparison and conditional
jump with the DECJNZ. The resulting code will be:
BB0:
%vreg0<def> = COPY %R0; // R0 contains 'a'
J <#BB1>
BB1:
%vreg1<def> = PHI %vreg0, <#BB0>, %vreg3, <#BB3>
J <#BB2>
BB2:
// loop body
BB3:
%vreg3<def> = DECJNZ %vreg1<kill>, <#BB1>, %SR<implicit,def>
J <#BB4>
BB4:
// end
A first problem was related to PHIElimination, while eliminating the PHI-node a
copy was generated before the DECJNZ, because it's a terminator instruction, but
the copy should use the value defined by the DECJNZ.
To solve this problem I wrote a preprocess pass which is run just before
PHIElimination and change the opcode of PHIs that have at least one source alue
generated by a DECJNZ. In this way it is ignored by the PHIElimination passes
and then a pass run just after PHIElimination that 'lowers' in a custom way the
marked PHIs and updates the information about live variables.
With some tests I had a second problem generated by the spilling of the register
used as loop counter. A store instruction is generated after the definition of
the value, so is inserted between the DECJNZ and J.
I think that with another pass I can try to manually move the spill-store
instruction at the beginning of the destination basic block, but I think it's
not enough to preserve the semantics of the code.
Is my approach correct? Does it exist a cleaner and more elegant way to support
this kind of instruction? I tried to look for a similar instruction in other
targets, but I've found nothing...
Thanks in advance for future replies.
Regards,
Michele Scandale
More information about the llvm-dev
mailing list