Hi -- I'm working on creating the cstore and cbranch templates for the Xilinx MicroBlaze processor. I've run into some problems and an unexpected interaction with CSE processing. Possibly, the insns I'm generating for comparisons are not what the CSE optimization expects.
MicroBlaze has a bit unusual compare and branch architecture. There are no condition flags; comparison results are stored in a result register. There's one branch instruction, which compares a register with zero and branches based on condition (eq, ne, lt, gt, etc.). There are a number of different instructions which can be used for comparisons. Regular instructions like sub or xor can be used in some cases. There are also cmp/cmpu instructions which do a modified subtraction of signed and unsigned integers. There are other comparison instructions for eq/ne which give a 0 or one result. The FP comparisons are all coupled with a condition: fcmp.eq, fcmp.lt, etc. To generate the correct comparison instruction, I need to know both the operands and the test condition. It doesn't look like the (compare:CC ...) template can be used. Compare takes two operands and there is no place to save the condition. For comparisons, I'm generating insns like: (set (reg:CC rD) (eq:CC (reg:SI rA) (reg:SI rB)) followed by a branch: (if_then_else (eq:CC (reg:CC rD) (const_int 0)) (label_ref xx) (pc))) This looks OK and it appears to work reasonably well. At least without optimization. CSE appears to be misinterpreting the comparison insn and the code gets trashed. This is taken from strchr.c in Newlib. The preprocessed code snippet is unsigned char c = i; if (!c) { while (((long)s & (sizeof (long) - 1))) { if (!*s) return (char *) s; s++; } . . . Before CSE, this is the insn sequence: (insn 90 89 91 2 .../strchr.c:66 (set (reg/v:SI 137 [ c+-3 ]) (zero_extend:SI (subreg:QI (reg/v:SI 244 [ i ]) 3))) 33 (insn 92 91 93 2 .../strchr.c:73 (set (reg:SI 245) (const_int 0 [0x0])) 41 (insn 93 92 94 2 .../strchr.c:73 (set (reg:CC 246) (eq:CC (reg/v:SI 137 [ c+-3 ]) (reg:SI 245))) 71 (jump_insn 94 93 95 2 .../strchr.c:73 (set (pc) (if_then_else (eq:CC (reg:CC 246) (const_int 0 [0x0])) (label_ref 112) (pc))) This is the first if expression. Note that reg 137 [c] is set to the masked value of the search character i. Reg 245 is set to zero, which is used in the compare instruction in insn 93. The while expression is (insn 97 96 98 3 .../strchr.c:93 (set (reg:SI 247) (and:SI (reg/v/f:SI 140 [ s ]) (const_int 3 [0x3]))) 25 (insn 98 97 99 3 .../strchr.c:93 (set (reg:SI 248) (const_int 0 [0x0])) 41 (insn 99 98 100 3 .../strchr.c:93 (set (reg:CC 249) (eq:CC (reg:SI 247) (reg:SI 248))) 71 (jump_insn 100 99 101 3 .../strchr.c:93 (set (pc) (if_then_else (eq:CC (reg:CC 249) (const_int 0 [0x0])) (label_ref 225) (pc))) 75 Reg 247 is set to the masked value of s, the string pointer. Reg 248 is set to zero and is used in the compare in insn 99. All of this looks OK to me. There is an intermediate step where reg 248 is replaced by reg 245, since both are set to zero. Somehow, CSE is deciding that reg 137 is equal to zero and translates insn 99 to (insn 99 98 100 3 .../strchr.c:93 (set (reg:CC 249) (eq:CC (reg:SI 247) (reg/v:SI 137 [ c+-3 ]))) 71 There is a REG_EQUAL note on this insn saying that it is equal to const zero. At this point, the code is hosed. I've been stepping through CSE to figure out why it decides that reg 137 is equal to zero, but haven't found this yet. (Yes, I do recognize that a comparison with zero can be simplified into just the branch insn. That's on my to do list.) Questions: Is this a reasonable way to represent the comparisons? Are there other targets which save comparison results in registers and require the condition? Any suggestions on better ways to model the MicroBlaze comparison operations? Are there some restriction on using eq/ne/lt/... the way I am? Any suggestions on how to fix the problem in CSE? -- Michael Eager ea...@eagercon.com 1960 Park Blvd., Palo Alto, CA 94306 650-325-8077