diff options
author | Andy Hutchinson <hutchinsonandy@gcc.gnu.org> | 2009-12-24 19:53:57 +0000 |
---|---|---|
committer | Andy Hutchinson <hutchinsonandy@gcc.gnu.org> | 2009-12-24 19:53:57 +0000 |
commit | 846428f11f50136baccab7c761e8f3e9793a4bda (patch) | |
tree | a541b901f2c02ec4f7faee44f3966ad8a1406b71 /gcc/config | |
parent | a1b418cb9ff3805dadc1b140f96ad545484618ad (diff) | |
download | gcc-846428f11f50136baccab7c761e8f3e9793a4bda.zip gcc-846428f11f50136baccab7c761e8f3e9793a4bda.tar.gz gcc-846428f11f50136baccab7c761e8f3e9793a4bda.tar.bz2 |
PR target/35013, 27192
2009-12-24 Andy Hutchinson <hutchinsonandy@gcc.gnu.org>
PR target/35013, 27192
* config/avr/avr.c (print_operand_address): Print correct program
memory address.
Add warning for large device offset addresses.
(avr_assemble_integer): Ditto.
(print_operand): Add warnings for incorrect addressing.
(out_movqi_r_mr): Tag assembler with new address codes.
(out_movhi_r_mr): Ditto.
(out_movsi_r_mr): Ditto.
(out_movqi_mr_r): Ditto.
(out_movhi_mr_r): Ditto.
(out_movsi_mr_r): Ditto.
* config/avr/predicates.md (text_segment_operand): New predicate.
* config/avr/avr.md (jump): Tag assembler with new address codes.
(call_insn): Ditto.
(call_value_insn): Ditto.
(*tablejump_lib): Ditto.
(*cbi): Ditto.
(*sbi): Ditto.
(indirect_jump): New define_expand.
(jcindirect_jump): New pattern for constant expression jump.
(njcindirect_jump): Renamed old indirect_jump.
From-SVN: r155459
Diffstat (limited to 'gcc/config')
-rw-r--r-- | gcc/config/avr/avr.c | 112 | ||||
-rw-r--r-- | gcc/config/avr/avr.md | 38 | ||||
-rwxr-xr-x | gcc/config/avr/predicates.md | 23 |
3 files changed, 128 insertions, 45 deletions
diff --git a/gcc/config/avr/avr.c b/gcc/config/avr/avr.c index b1713a8..eff2179 100644 --- a/gcc/config/avr/avr.c +++ b/gcc/config/avr/avr.c @@ -1176,12 +1176,33 @@ print_operand_address (FILE *file, rtx addr) default: if (CONSTANT_ADDRESS_P (addr) - && ((GET_CODE (addr) == SYMBOL_REF && SYMBOL_REF_FUNCTION_P (addr)) - || GET_CODE (addr) == LABEL_REF)) + && text_segment_operand (addr, VOIDmode)) { - fprintf (file, "gs("); - output_addr_const (file,addr); - fprintf (file ,")"); + rtx x = XEXP (addr,0); + if (GET_CODE (x) == PLUS && GET_CODE (XEXP (x,1)) == CONST_INT) + { + /* Assembler gs() will implant word address. Make offset + a byte offset inside gs() for assembler. This is + needed because the more logical (constant+gs(sym)) is not + accepted by gas. For 128K and lower devices this is ok. For + large devices it will create a Trampoline to offset from symbol + which may not be what the user really wanted. */ + fprintf (file, "gs("); + output_addr_const (file, XEXP (x,0)); + fprintf (file,"+" HOST_WIDE_INT_PRINT_DEC ")", 2 * INTVAL (XEXP (x,1))); + if (AVR_3_BYTE_PC) + if (warning ( 0, "Pointer offset from symbol maybe incorrect.")) + { + output_addr_const (stderr, addr); + fprintf(stderr,"\n"); + } + } + else + { + fprintf (file, "gs("); + output_addr_const (file, addr); + fprintf (file, ")"); + } } else output_addr_const (file, addr); @@ -1221,12 +1242,18 @@ print_operand (FILE *file, rtx x, int code) else if (GET_CODE (x) == MEM) { rtx addr = XEXP (x,0); - - if (CONSTANT_P (addr) && abcd) + if (code == 'm') { - fputc ('(', file); - output_address (addr); - fprintf (file, ")+%d", abcd); + if (!CONSTANT_P (addr)) + fatal_insn ("bad address, not a constant):", addr); + /* Assembler template with m-code is data - not progmem section */ + if (text_segment_operand (addr, VOIDmode)) + if (warning ( 0, "accessing data memory with program memory address")) + { + output_addr_const (stderr, addr); + fprintf(stderr,"\n"); + } + output_addr_const (file, addr); } else if (code == 'o') { @@ -1257,6 +1284,18 @@ print_operand (FILE *file, rtx x, int code) else print_operand_address (file, addr); } + else if (code == 'x') + { + /* Constant progmem address - like used in jmp or call */ + if (0 == text_segment_operand (x, VOIDmode)) + if (warning ( 0, "accessing program memory with data memory address")) + { + output_addr_const (stderr, x); + fprintf(stderr,"\n"); + } + /* Use normal symbol for direct address no linker trampoline needed */ + output_addr_const (file, x); + } else if (GET_CODE (x) == CONST_DOUBLE) { long val; @@ -1874,10 +1913,10 @@ out_movqi_r_mr (rtx insn, rtx op[], int *l) if (optimize > 0 && io_address_operand (x, QImode)) { *l = 1; - return AS2 (in,%0,%1-0x20); + return AS2 (in,%0,%m1-0x20); } *l = 2; - return AS2 (lds,%0,%1); + return AS2 (lds,%0,%m1); } /* memory access by reg+disp */ else if (GET_CODE (x) == PLUS @@ -2062,12 +2101,12 @@ out_movhi_r_mr (rtx insn, rtx op[], int *l) if (optimize > 0 && io_address_operand (base, HImode)) { *l = 2; - return (AS2 (in,%A0,%A1-0x20) CR_TAB - AS2 (in,%B0,%B1-0x20)); + return (AS2 (in,%A0,%m1-0x20) CR_TAB + AS2 (in,%B0,%m1+1-0x20)); } *l = 4; - return (AS2 (lds,%A0,%A1) CR_TAB - AS2 (lds,%B0,%B1)); + return (AS2 (lds,%A0,%m1) CR_TAB + AS2 (lds,%B0,%m1+1)); } fatal_insn ("unknown move insn:",insn); @@ -2226,10 +2265,10 @@ out_movsi_r_mr (rtx insn, rtx op[], int *l) AS2 (ld,%C0,%1) CR_TAB AS2 (ld,%D0,%1)); else if (CONSTANT_ADDRESS_P (base)) - return *l=8, (AS2 (lds,%A0,%A1) CR_TAB - AS2 (lds,%B0,%B1) CR_TAB - AS2 (lds,%C0,%C1) CR_TAB - AS2 (lds,%D0,%D1)); + return *l=8, (AS2 (lds,%A0,%m1) CR_TAB + AS2 (lds,%B0,%m1+1) CR_TAB + AS2 (lds,%C0,%m1+2) CR_TAB + AS2 (lds,%D0,%m1+3)); fatal_insn ("unknown move insn:",insn); return ""; @@ -2249,10 +2288,10 @@ out_movsi_mr_r (rtx insn, rtx op[], int *l) l = &tmp; if (CONSTANT_ADDRESS_P (base)) - return *l=8,(AS2 (sts,%A0,%A1) CR_TAB - AS2 (sts,%B0,%B1) CR_TAB - AS2 (sts,%C0,%C1) CR_TAB - AS2 (sts,%D0,%D1)); + return *l=8,(AS2 (sts,%m0,%A1) CR_TAB + AS2 (sts,%m0+1,%B1) CR_TAB + AS2 (sts,%m0+2,%C1) CR_TAB + AS2 (sts,%m0+3,%D1)); if (reg_base > 0) /* (r) */ { if (reg_base == REG_X) /* (R26) */ @@ -2562,10 +2601,10 @@ out_movqi_mr_r (rtx insn, rtx op[], int *l) if (optimize > 0 && io_address_operand (x, QImode)) { *l = 1; - return AS2 (out,%0-0x20,%1); + return AS2 (out,%m0-0x20,%1); } *l = 2; - return AS2 (sts,%0,%1); + return AS2 (sts,%m0,%1); } /* memory access by reg+disp */ else if (GET_CODE (x) == PLUS @@ -2641,11 +2680,11 @@ out_movhi_mr_r (rtx insn, rtx op[], int *l) if (optimize > 0 && io_address_operand (base, HImode)) { *l = 2; - return (AS2 (out,%B0-0x20,%B1) CR_TAB - AS2 (out,%A0-0x20,%A1)); + return (AS2 (out,%m0+1-0x20,%B1) CR_TAB + AS2 (out,%m0-0x20,%A1)); } - return *l = 4, (AS2 (sts,%B0,%B1) CR_TAB - AS2 (sts,%A0,%A1)); + return *l = 4, (AS2 (sts,%m0+1,%B1) CR_TAB + AS2 (sts,%m0,%A1)); } if (reg_base > 0) { @@ -4502,8 +4541,7 @@ static bool avr_assemble_integer (rtx x, unsigned int size, int aligned_p) { if (size == POINTER_SIZE / BITS_PER_UNIT && aligned_p - && ((GET_CODE (x) == SYMBOL_REF && SYMBOL_REF_FUNCTION_P (x)) - || GET_CODE (x) == LABEL_REF)) + && text_segment_operand (x, VOIDmode) ) { fputs ("\t.word\tgs(", asm_out_file); output_addr_const (asm_out_file, x); @@ -5944,13 +5982,13 @@ avr_out_sbxx_branch (rtx insn, rtx operands[]) if (INTVAL (operands[1]) < 0x40) { if (comp == EQ) - output_asm_insn (AS2 (sbis,%1-0x20,%2), operands); + output_asm_insn (AS2 (sbis,%m1-0x20,%2), operands); else - output_asm_insn (AS2 (sbic,%1-0x20,%2), operands); + output_asm_insn (AS2 (sbic,%m1-0x20,%2), operands); } else { - output_asm_insn (AS2 (in,__tmp_reg__,%1-0x20), operands); + output_asm_insn (AS2 (in,__tmp_reg__,%m1-0x20), operands); if (comp == EQ) output_asm_insn (AS2 (sbrs,__tmp_reg__,%2), operands); else @@ -5979,9 +6017,9 @@ avr_out_sbxx_branch (rtx insn, rtx operands[]) if (long_jump) return (AS1 (rjmp,.+4) CR_TAB - AS1 (jmp,%3)); + AS1 (jmp,%x3)); if (!reverse) - return AS1 (rjmp,%3); + return AS1 (rjmp,%x3); return ""; } diff --git a/gcc/config/avr/avr.md b/gcc/config/avr/avr.md index 1271fa4..f0e59eb 100644 --- a/gcc/config/avr/avr.md +++ b/gcc/config/avr/avr.md @@ -28,9 +28,11 @@ ;; D Add 3. ;; j Branch condition. ;; k Reverse branch condition. +;;..m..Constant Direct Data memory address. ;; o Displacement for (mem (plus (reg) (const_int))) operands. ;; p POST_INC or PRE_DEC address as a pointer (X, Y, Z) ;; r POST_INC or PRE_DEC address as a register (r26, r28, r30) +;;..x..Constant Direct Program memory address. ;; ~ Output 'r' if not AVR_HAVE_JMP_CALL. ;; ! Output 'e' if AVR_HAVE_EIJMP_EICALL. @@ -2732,8 +2734,8 @@ "" "*{ if (AVR_HAVE_JMP_CALL && get_attr_length (insn) != 1) - return AS1 (jmp,%0); - return AS1 (rjmp,%0); + return AS1 (jmp,%x0); + return AS1 (rjmp,%x0); }" [(set (attr "length") (if_then_else (match_operand 0 "symbol_ref_operand" "") @@ -2785,7 +2787,7 @@ \"%!icall\"); } else if (which_alternative==2) - return AS1(%~call,%c0); + return AS1(%~call,%x0); return (AS2 (ldi,r30,lo8(%0)) CR_TAB AS2 (ldi,r31,hi8(%0)) CR_TAB \"%!icall\"); @@ -2822,7 +2824,7 @@ \"%!icall\"); } else if (which_alternative==2) - return AS1(%~call,%c1); + return AS1(%~call,%x1); return (AS2 (ldi, r30, lo8(%1)) CR_TAB AS2 (ldi, r31, hi8(%1)) CR_TAB \"%!icall\"); @@ -2846,7 +2848,27 @@ (set_attr "length" "1")]) ; indirect jump -(define_insn "indirect_jump" + +(define_expand "indirect_jump" + [(set (pc) (match_operand:HI 0 "nonmemory_operand" ""))] + "" + " if ((!AVR_HAVE_JMP_CALL) && !register_operand(operand0, HImode)) + { + operands[0] = copy_to_mode_reg(HImode, operand0); + }" +) + +; indirect jump +(define_insn "*jcindirect_jump" + [(set (pc) (match_operand:HI 0 "immediate_operand" "i"))] + "" + "@ + %~jmp %x0" + [(set_attr "length" "2") + (set_attr "cc" "none")]) + +;; +(define_insn "*njcindirect_jump" [(set (pc) (match_operand:HI 0 "register_operand" "!z,*r"))] "!AVR_HAVE_EIJMP_EICALL" "@ @@ -2884,7 +2906,7 @@ (use (label_ref (match_operand 1 "" ""))) (clobber (match_dup 0))] "AVR_HAVE_JMP_CALL && TARGET_CALL_PROLOGUES" - "jmp __tablejump2__" + "%~jmp __tablejump2__" [(set_attr "length" "2") (set_attr "cc" "clobber")]) @@ -2967,7 +2989,7 @@ "(optimize > 0)" { operands[2] = GEN_INT (exact_log2 (~INTVAL (operands[1]) & 0xff)); - return AS2 (cbi,%0-0x20,%2); + return AS2 (cbi,%m0-0x20,%2); } [(set_attr "length" "1") (set_attr "cc" "none")]) @@ -2979,7 +3001,7 @@ "(optimize > 0)" { operands[2] = GEN_INT (exact_log2 (INTVAL (operands[1]) & 0xff)); - return AS2 (sbi,%0-0x20,%2); + return AS2 (sbi,%m0-0x20,%2); } [(set_attr "length" "1") (set_attr "cc" "none")]) diff --git a/gcc/config/avr/predicates.md b/gcc/config/avr/predicates.md index 2aa3e88..9a3473b 100755 --- a/gcc/config/avr/predicates.md +++ b/gcc/config/avr/predicates.md @@ -71,6 +71,29 @@ (define_predicate "symbol_ref_operand" (match_code "symbol_ref")) +;; Return true if OP is a text segment reference. +;; This is needed for program memory address expressions. +(define_predicate "text_segment_operand" + (match_code "code_label,label_ref,symbol_ref,plus,const") +{ + switch (GET_CODE (op)) + { + case CODE_LABEL: + return true; + case LABEL_REF : + return true; + case SYMBOL_REF : + return SYMBOL_REF_FUNCTION_P (op); + case PLUS : + /* Assume canonical format of symbol + constant. + Fall through. */ + case CONST : + return text_segment_operand (XEXP (op, 0), VOIDmode); + default : + return false; + } +}) + ;; Return true if OP is a constant that contains only one 1 in its ;; binary representation. (define_predicate "single_one_operand" |