aboutsummaryrefslogtreecommitdiff
path: root/gcc/config
diff options
context:
space:
mode:
authorAndy Hutchinson <hutchinsonandy@gcc.gnu.org>2009-12-24 19:53:57 +0000
committerAndy Hutchinson <hutchinsonandy@gcc.gnu.org>2009-12-24 19:53:57 +0000
commit846428f11f50136baccab7c761e8f3e9793a4bda (patch)
treea541b901f2c02ec4f7faee44f3966ad8a1406b71 /gcc/config
parenta1b418cb9ff3805dadc1b140f96ad545484618ad (diff)
downloadgcc-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.c112
-rw-r--r--gcc/config/avr/avr.md38
-rwxr-xr-xgcc/config/avr/predicates.md23
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"