I have a simple CPU architecture with just SI registers / operations. The only
place bytes and words and used is during loads / stores.
I'm trying to understand how a QI/HI load to an SI register works. I have this
to expand moves --
(define_expand "mov<mode>"
[(set (match_operand:ALLMODES 0 "nonimmediate_operand" "")
(match_operand:ALLMODES 1 "general_operand" ""))]
""
{
if (ghost_expand_move (operands[0], operands[1])) DONE;
FAIL;
})
Where ALLMODES is QI,HI,SI. I have PROMOTE_MODE setup to promote anything
smaller than SI to SI (as RISCV etc).
With a simple function of "unsigned int fn(type *ptr) { return *ptr; }" I am
getting a tree of --
type = unsigned int :
(insn 7 4 8 2 (set (reg:SI 28)
(mem:SI (reg/v/f:SI 25 [ ptr ]) [0 S4 A32])) "test.c":3:9 discrim 1 -1
(nil))
(insn 8 7 12 2 (set (reg:SI 24 [ <retval> ])
(reg:SI 28)) "test.c":3:9 discrim 1 -1
(nil))
(expected, works fine)
type = unsigned char :
(insn 7 4 8 2 (set (reg:QI 29)
(mem:QI (reg/v/f:SI 26 [ ptr ]) [0 S1 A8])) "test.c":3:9 -1
(nil))
(insn 8 7 9 2 (set (reg:SI 28 [ _4 ])
(ashift:SI (subreg:SI (reg:QI 29) 0)
(const_int 24 [0x18]))) "test.c":3:9 -1
(nil))
(insn 9 8 10 2 (set (reg:SI 28 [ _4 ])
(ashift:SI (reg:SI 28 [ _4 ])
(const_int 24 [0x18]))) "test.c":3:9 -1
(nil))
(insn 10 9 14 2 (set (reg:SI 25 [ <retval> ])
(reg:SI 28 [ _4 ])) "test.c":3:9 discrim 1 -1
(nil))
It looks like it's doing a shift left 24 / right 24 to sign extend the top 24
bits (which is odd in itself as all vars are unsigned), but this ends up
generating incorrect code as I assume the shift subreg pattern isn't being
matched (I just have SI). I've also tried setting LOAD_EXTEND_OP to ZERO_EXTEND
but this makes no difference.
What am I missing to be able to match specific --
[(set (match_operand:SI 0 "register_operand" "=da")
(zero_extend:SI (mem:QI (match_operand:SI 1 "register_operand"
"a"))))]
Type patterns to directly load a byte into a 32bit register?
Any pointers appreciated, I assume I'm missing something fundamental.