All, Thanks for all the help from the past. I'm (still) working on porting GCC to a new processor ISA and ran into the following problem: the CPU supports two kinds of register+offset based loads (and stores).
The generic format accepts any base register and any offset. The syntax for this type of operation is: $rX <- mem[$rB + <ofs>] For code compatness reasons, there's another (shorter) form, that accepts only $sp and $fp (the stack and frame pointers) as base registers, and an offset in the range of -256 and 252. Finally this form inly supports a transfer size of 32-bits. The syntax for this format is: $rX <- mem[tiny $rB + <ofs>] I would like to coerce GCC into using the 'tiny' form, whenever it can. In order to do that, I've created a new predicate: (define_predicate "brew_tiny_memory_operand" (and (match_operand 0 "memory_operand") (match_test "MEM_P(op) && brew_legitimate_tiny_address_p(XEXP(op, 0))" ) ) ) The function referenced in the predicate is as follows: static bool brew_reg_ok_for_tiny_base_p(const_rtx reg) { int regno = REGNO(reg); return regno == BREW_REG_FP || regno == BREW_REG_SP || regno == BREW_QFP || regno == BREW_QAP; } bool brew_legitimate_tiny_address_p(rtx x) { if ( GET_CODE(x) == PLUS && REG_P(XEXP(x, 0)) && brew_reg_ok_for_tiny_base_p(XEXP(x, 0)) && CONST_INT_P(XEXP(x, 1)) && IN_RANGE(INTVAL(XEXP(x, 1)), -256, 252) && (INTVAL(XEXP(x,1)) & 3) == 0 ) return true; return false; } Finally, I've created rules for the use of these new predicates: (define_expand "movsi" [(set (match_operand:SI 0 "general_operand" "") (match_operand:SI 1 "general_operand" "") )] "" " { if (!(reload_in_progress || reload_completed)) { if(MEM_P(operands[0])) { // For stores, force the second arg. into a register operands[1] = force_reg(SImode, operands[1]); // We should make sure that the address // generated for the store is based on a // <reg>+<offset> pattern if(MEM_P(XEXP(operands[0], 0))) operands[0] = gen_rtx_MEM( SImode, force_reg(SImode, XEXP(operands[0], 0)) ); } else if(MEM_P(operands[1])) { // We should make sure that the address // generated for the load is based on a // <reg>+<offset> pattern if(MEM_P(XEXP (operands[1], 0))) operands[1] = gen_rtx_MEM( SImode, force_reg(SImode, XEXP(operands[1], 0)) ); } } }") (define_insn "*movsi_tiny_store" [(set (match_operand:SI 0 "brew_tiny_memory_operand" "=m") (match_operand:SI 1 "register_operand" "r") )] "" "mem[tiny %0] <- %1" [(set_attr "length" "2")] ) (define_insn "*movsi_tiny_load" [(set (match_operand:SI 0 "register_operand" "=r") (match_operand:SI 1 "brew_tiny_memory_operand" "m") )] "" "%0 <- mem[tiny %1]" [(set_attr "length" "2")] ) (define_insn "*movsi_general" [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,r,r,m,r") (match_operand:SI 1 "general_operand" "N,L,i,r,r,m") )] "" "@ %0 <- tiny %1 %0 <- short %1 %0 <- %1 %0 <- %1 mem[%0] <- %1 %0 <- mem[%1]" [(set_attr "length" "2,4,6,2,6,6")] ) When I tested this code, I've noticed a funny thing: the function prologs and epilogs seem to use the 'tiny' versions of loads/stores just fine. However (I think) some of the spills/reloads for local variables end up using the extended version. Even more surprising is that this behavior only manifests itself during optimized (-Os, -O1, -O2) compilation. It seems that -O0 is free from this problem. Here's one example: .file "dtoa.c" .text .global __udivsi3 .p2align 1 .global quorem .type quorem, @function quorem: mem[tiny $sp + -4] <- $fp ########### <------- OK mem[tiny $sp + -8] <- $lr mem[tiny $sp + -12] <- $r8 mem[tiny $sp + -16] <- $r9 mem[tiny $sp + -20] <- $r10 mem[tiny $sp + -24] <- $r11 $fp <- $sp $sp <- short $sp - 48 $r9 <- $a0 $r8 <- mem[$a1 + 16] $r0 <- mem[$a0 + 16] if signed $r0 < $r8 $pc <- .L7 $r8 <- tiny $r8 + -1 $r0 <- tiny 2 $r0 <- $r8 << $r0 $r10 <- short $a0 + 20 $r1 <- $r10 + $r0 mem[$fp + -32] <- $r1 ############## <-------- should be 'tiny' $r11 <- mem[$r1] To a previous problem I've asked, Andrew Pinski replied that I should merge all *movsi patterns into a single one to avoid (in that case) strange deletions in the generated assembly. Is that possible here? It appears to me that I would need the ability to differentiate the different patterns using constraints, but is there a way to define custom versions of the 'm' pattern? I didn't find anything on that in the documentation. Did I miss something? Thanks a bunch, Andras