re PR target/49868 (Implement named address space to place/access data in flash memory)

gcc/
	PR target/49868
	* config/avr/avr.h (base_arch_s): Add field n_segments.
	(ADDR_SPACE_PGM1, ADDR_SPACE_PGM2, ADDR_SPACE_PGM3,
	ADDR_SPACE_PGM4, ADDR_SPACE_PGM5, ADDR_SPACE_PGMX): New address spaces.
	(AVR_HAVE_ELPM, AVR_HAVE_ELPMX): New defines.
	(INIT_EXPANDERS): New define.
	* config/avr/avr-protos.h (avr_mem_pgmx_p): New.
	(avr_init_expanders): New.
	(avr_emit_movmemhi, avr_out_movmem): New.
	(avr_xload_libgcc_p): New.
	* config/avr/avr-c.c (avr_register_target_pragmas): Register
	address spaces __pgm1, __pgm2,  __pgm3,  __pgm4  __pgm5,  __pgmx.
	(avr_cpu_cpp_builtins): Add built-in defines __PGM1,
	__PGM2, __PGM3, __PGM4, __PGM5, __PGMX.
	* config/avr/avr-devices.c (avr_arch_types): Set field n_segments.

	* config/avr/avr.c (AVR_SECTION_PROGMEM): Change define to cover
	3 bits instead of just 1.
	(xstring_empty, xstring_e, rampz_rtx): New static GTYed variables.
	(progmem_section): Change from section to array of sections.
	(progmem_section_prefix): New static variable.
	(avr_file_start): Print set for __RAMPZ__
	(avr_option_override): Move initialization of RTXes from here...
	(avr_init_expanders): ...to this new function.
	(avr_pgm_segment): New static function.
	(avr_decl_pgm_p): Handle error_mark_node.
	(avr_mem_pgmx_p, avr_decl_pgmx_p): New static functions.
	(avr_out_xload,	avr_find_unused_d_reg): New static functions.
	(expand_prologue, expand_epilogue): Use rampz_rtx.
	(print_operand): Hande CONST_STRING.
	(avr_xload_libgcc_p): New static function.
	(avr_out_lpm_no_lpmx, avr_out_lpm): Handle ELPM.
	(avr_progmem_p): Return 2 for 24-bit flash address space.
	(avr_out_sbxx_branch): Clean-up code from ASn macros.
	(out_movqi_r_mr, out_movqi_mr_r): Ditto. And recognize RAMPZ's
	address and print symbolically.
	(avr_asm_named_section, avr_section_type_flags,
	avr_encode_section_info, avr_asm_select_section,
	avr_addr_space_address_mode, avr_addr_space_pointer_mode,
	avr_addr_space_legitimate_address_p, avr_addr_space_convert,
	avr_addr_space_legitimize_address): Handle new address spaces.
	(avr_output_progmem_section_asm_op): New static function.
	(avr_asm_init_sections): Initialize progmem_section[].
	(adjust_insn_length): Handle ADJUST_LEN_XLOAD, ADJUST_LEN_MOVMEM.
	(avr_const_address_lo16): New static function.
	(avr_assemble_integer): Use it to handle 3-byte integers.
	(avr_emit_movmemhi, avr_out_movmem): New functions.
	
	* config/avr/predicates.md (nox_general_operand): Handle new
	address spaces.
	* config/avr/avr.md (unspec): Add UNSPEC_MOVMEM.
	(adjust_len): Add xload, movmem.
	(SP_ADDR): New define_constants.
	(isa): Add "lpm", "lpmx", "elpm", "elpmx".
	(enabled): Handle them.
	(load<mode>_libgcc): New expander.
	(*load.<mode>.libgcc): Rename to load_<mode>_libgcc.
	(xload8_A, xload<mode>_A): New insn-and-splits.
	(xload_8, xload_<mode>_libgcc, xload_<mode>, loadmem_elpm): New insns.
	(mov<mode>): Handle new address spaces.
	(movmemhi): Rewrite using avr_emit_movmemhi.
	(MOVMEM_r_d): New mode attribute.
	(movmem_<mode>, movmem_qi_elpm): New insns.
	(setmemhi, *clrmemqi, *clrmemhi, strlenhi, *strlenhi): Unquote
	C-code.  Use label instead of hard-coded instrunction lengths.
	
libgcc/
	PR target/49868
	* config/avr/t-avr (LIB1ASMFUNCS): Add _xload_2 _xload_3 _xload_4.
	* config/avr/lib1funcs.S (__xload_2, __xload_3, __xload_4):
	New functions.

From-SVN: r181482
This commit is contained in:
Georg-Johann Lay 2011-11-18 16:44:00 +00:00 committed by Georg-Johann Lay
parent 59659b5967
commit 7bc6df2ca1
11 changed files with 1439 additions and 389 deletions

View File

@ -1,3 +1,71 @@
2011-11-18 Georg-Johann Lay <avr@gjlay.de>
PR target/49868
* config/avr/avr.h (base_arch_s): Add field n_segments.
(ADDR_SPACE_PGM1, ADDR_SPACE_PGM2, ADDR_SPACE_PGM3,
ADDR_SPACE_PGM4, ADDR_SPACE_PGM5, ADDR_SPACE_PGMX): New address spaces.
(AVR_HAVE_ELPM, AVR_HAVE_ELPMX): New defines.
(INIT_EXPANDERS): New define.
* config/avr/avr-protos.h (avr_mem_pgmx_p): New.
(avr_init_expanders): New.
(avr_emit_movmemhi, avr_out_movmem): New.
(avr_xload_libgcc_p): New.
* config/avr/avr-c.c (avr_register_target_pragmas): Register
address spaces __pgm1, __pgm2, __pgm3, __pgm4 __pgm5, __pgmx.
(avr_cpu_cpp_builtins): Add built-in defines __PGM1,
__PGM2, __PGM3, __PGM4, __PGM5, __PGMX.
* config/avr/avr-devices.c (avr_arch_types): Set field n_segments.
* config/avr/avr.c (AVR_SECTION_PROGMEM): Change define to cover
3 bits instead of just 1.
(xstring_empty, xstring_e, rampz_rtx): New static GTYed variables.
(progmem_section): Change from section to array of sections.
(progmem_section_prefix): New static variable.
(avr_file_start): Print set for __RAMPZ__
(avr_option_override): Move initialization of RTXes from here...
(avr_init_expanders): ...to this new function.
(avr_pgm_segment): New static function.
(avr_decl_pgm_p): Handle error_mark_node.
(avr_mem_pgmx_p, avr_decl_pgmx_p): New static functions.
(avr_out_xload, avr_find_unused_d_reg): New static functions.
(expand_prologue, expand_epilogue): Use rampz_rtx.
(print_operand): Hande CONST_STRING.
(avr_xload_libgcc_p): New static function.
(avr_out_lpm_no_lpmx, avr_out_lpm): Handle ELPM.
(avr_progmem_p): Return 2 for 24-bit flash address space.
(avr_out_sbxx_branch): Clean-up code from ASn macros.
(out_movqi_r_mr, out_movqi_mr_r): Ditto. And recognize RAMPZ's
address and print symbolically.
(avr_asm_named_section, avr_section_type_flags,
avr_encode_section_info, avr_asm_select_section,
avr_addr_space_address_mode, avr_addr_space_pointer_mode,
avr_addr_space_legitimate_address_p, avr_addr_space_convert,
avr_addr_space_legitimize_address): Handle new address spaces.
(avr_output_progmem_section_asm_op): New static function.
(avr_asm_init_sections): Initialize progmem_section[].
(adjust_insn_length): Handle ADJUST_LEN_XLOAD, ADJUST_LEN_MOVMEM.
(avr_const_address_lo16): New static function.
(avr_assemble_integer): Use it to handle 3-byte integers.
(avr_emit_movmemhi, avr_out_movmem): New functions.
* config/avr/predicates.md (nox_general_operand): Handle new
address spaces.
* config/avr/avr.md (unspec): Add UNSPEC_MOVMEM.
(adjust_len): Add xload, movmem.
(SP_ADDR): New define_constants.
(isa): Add "lpm", "lpmx", "elpm", "elpmx".
(enabled): Handle them.
(load<mode>_libgcc): New expander.
(*load.<mode>.libgcc): Rename to load_<mode>_libgcc.
(xload8_A, xload<mode>_A): New insn-and-splits.
(xload_8, xload_<mode>_libgcc, xload_<mode>, loadmem_elpm): New insns.
(mov<mode>): Handle new address spaces.
(movmemhi): Rewrite using avr_emit_movmemhi.
(MOVMEM_r_d): New mode attribute.
(movmem_<mode>, movmem_qi_elpm): New insns.
(setmemhi, *clrmemqi, *clrmemhi, strlenhi, *strlenhi): Unquote
C-code. Use label instead of hard-coded instrunction lengths.
2011-11-18 Martin Jambor <mjambor@suse.cz>
PR tree-optimization/50605

View File

@ -37,6 +37,12 @@ void
avr_register_target_pragmas (void)
{
c_register_addr_space ("__pgm", ADDR_SPACE_PGM);
c_register_addr_space ("__pgm1", ADDR_SPACE_PGM1);
c_register_addr_space ("__pgm2", ADDR_SPACE_PGM2);
c_register_addr_space ("__pgm3", ADDR_SPACE_PGM3);
c_register_addr_space ("__pgm4", ADDR_SPACE_PGM4);
c_register_addr_space ("__pgm5", ADDR_SPACE_PGM5);
c_register_addr_space ("__pgmx", ADDR_SPACE_PGMX);
}
@ -109,6 +115,12 @@ avr_cpu_cpp_builtins (struct cpp_reader *pfile)
if (!strcmp (lang_hooks.name, "GNU C"))
{
cpp_define (pfile, "__PGM=__pgm");
cpp_define (pfile, "__PGM1=__pgm1");
cpp_define (pfile, "__PGM2=__pgm2");
cpp_define (pfile, "__PGM3=__pgm3");
cpp_define (pfile, "__PGM4=__pgm4");
cpp_define (pfile, "__PGM5=__pgm5");
cpp_define (pfile, "__PGMX=__pgmx");
}
/* Define builtin macros so that the user can

View File

@ -25,18 +25,27 @@
/* List of all known AVR MCU architectures. */
const struct base_arch_s avr_arch_types[] = {
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x0060, NULL, "avr2" }, /* unknown device specified */
{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0x0060, "__AVR_ARCH__=1", "avr1" },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x0060, "__AVR_ARCH__=2", "avr2" },
{ 0, 0, 0, 1, 0, 0, 0, 0, 0, 0x0060, "__AVR_ARCH__=25", "avr25" },
{ 0, 0, 1, 0, 0, 0, 0, 0, 0, 0x0060, "__AVR_ARCH__=3", "avr3" },
{ 0, 0, 1, 0, 1, 0, 0, 0, 0, 0x0060, "__AVR_ARCH__=31", "avr31" },
{ 0, 0, 1, 1, 0, 0, 0, 0, 0, 0x0060, "__AVR_ARCH__=35", "avr35" },
{ 0, 1, 0, 1, 0, 0, 0, 0, 0, 0x0060, "__AVR_ARCH__=4", "avr4" },
{ 0, 1, 1, 1, 0, 0, 0, 0, 0, 0x0060, "__AVR_ARCH__=5", "avr5" },
{ 0, 1, 1, 1, 1, 1, 0, 0, 0, 0x0060, "__AVR_ARCH__=51", "avr51" },
{ 0, 1, 1, 1, 1, 1, 1, 0, 0, 0x0060, "__AVR_ARCH__=6", "avr6" }
const struct base_arch_s
avr_arch_types[] =
{
/* unknown device specified */
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x0060, 1, NULL, "avr2" },
/*
A M J L E E E d S # F
S U M P L L I a t 6 l
M L P M P P J - - t a 4 a
X M M M a r s
X P t k h */
{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0x0060, 1, "__AVR_ARCH__=1", "avr1" },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x0060, 1, "__AVR_ARCH__=2", "avr2" },
{ 0, 0, 0, 1, 0, 0, 0, 0, 0, 0x0060, 1, "__AVR_ARCH__=25", "avr25" },
{ 0, 0, 1, 0, 0, 0, 0, 0, 0, 0x0060, 1, "__AVR_ARCH__=3", "avr3" },
{ 0, 0, 1, 0, 1, 0, 0, 0, 0, 0x0060, 2, "__AVR_ARCH__=31", "avr31" },
{ 0, 0, 1, 1, 0, 0, 0, 0, 0, 0x0060, 1, "__AVR_ARCH__=35", "avr35" },
{ 0, 1, 0, 1, 0, 0, 0, 0, 0, 0x0060, 1, "__AVR_ARCH__=4", "avr4" },
{ 0, 1, 1, 1, 0, 0, 0, 0, 0, 0x0060, 1, "__AVR_ARCH__=5", "avr5" },
{ 0, 1, 1, 1, 1, 1, 0, 0, 0, 0x0060, 2, "__AVR_ARCH__=51", "avr51" },
{ 0, 1, 1, 1, 1, 1, 1, 0, 0, 0x0060, 4, "__AVR_ARCH__=6", "avr6" }
};
const struct mcu_type_s avr_mcu_types[] = {

View File

@ -34,6 +34,7 @@ extern int avr_hard_regno_rename_ok (unsigned int, unsigned int);
extern rtx avr_return_addr_rtx (int count, rtx tem);
extern void avr_register_target_pragmas (void);
extern bool avr_accumulate_outgoing_args (void);
extern void avr_init_expanders (void);
#ifdef TREE_CODE
extern void avr_asm_output_aligned_decl_common (FILE*, const_tree, const char*, unsigned HOST_WIDE_INT, unsigned int, bool);
@ -84,6 +85,7 @@ extern bool avr_rotate_bytes (rtx operands[]);
extern void expand_prologue (void);
extern void expand_epilogue (bool);
extern bool avr_emit_movmemhi (rtx*);
extern int avr_epilogue_uses (int regno);
extern int avr_starting_frame_offset (void);
@ -94,6 +96,8 @@ extern const char* avr_out_bitop (rtx, rtx*, int*);
extern const char* avr_out_plus (rtx*, int*, int*);
extern const char* avr_out_plus_noclobber (rtx*, int*, int*);
extern const char* avr_out_addto_sp (rtx*, int*);
extern const char* avr_out_xload (rtx, rtx*, int*);
extern const char* avr_out_movmem (rtx, rtx*, int*);
extern bool avr_popcount_each_byte (rtx, int, int);
extern int extra_constraint_Q (rtx x);
@ -122,7 +126,9 @@ extern bool avr_regno_mode_code_ok_for_base_p (int, enum machine_mode, addr_spac
extern rtx avr_incoming_return_addr_rtx (void);
extern rtx avr_legitimize_reload_address (rtx*, enum machine_mode, int, int, int, int, rtx (*)(rtx,int));
extern bool avr_mem_pgm_p (rtx);
extern bool avr_mem_pgmx_p (rtx);
extern bool avr_load_libgcc_p (rtx);
extern bool avr_xload_libgcc_p (enum machine_mode);
#endif /* RTX_CODE */
#ifdef REAL_VALUE_TYPE

File diff suppressed because it is too large Load Diff

View File

@ -54,6 +54,9 @@ struct base_arch_s {
/* Default start of data section address for architecture. */
int default_data_section_start;
/* Number of 64k segments in the flash. */
int n_segments;
const char *const macro;
/* Architecture name. */
@ -131,6 +134,8 @@ extern const struct base_arch_s avr_arch_types[];
#define AVR_HAVE_MUL (avr_current_arch->have_mul)
#define AVR_HAVE_MOVW (avr_current_arch->have_movw_lpmx)
#define AVR_HAVE_LPMX (avr_current_arch->have_movw_lpmx)
#define AVR_HAVE_ELPM (avr_current_arch->have_elpm)
#define AVR_HAVE_ELPMX (avr_current_arch->have_elpmx)
#define AVR_HAVE_RAMPZ (avr_current_arch->have_elpm)
#define AVR_HAVE_EIJMP_EICALL (avr_current_arch->have_eijmp_eicall)
#define AVR_HAVE_8BIT_SP (avr_current_device->short_sp || TARGET_TINY_STACK)
@ -393,6 +398,12 @@ typedef struct avr_args {
#define ADDR_SPACE_PGM 1
#define ADDR_SPACE_PGM1 2
#define ADDR_SPACE_PGM2 3
#define ADDR_SPACE_PGM3 4
#define ADDR_SPACE_PGM4 5
#define ADDR_SPACE_PGM5 6
#define ADDR_SPACE_PGMX 7
#define REGISTER_TARGET_PRAGMAS() \
do { \
@ -645,3 +656,5 @@ struct GTY(()) machine_function
#define PUSH_ROUNDING(X) (X)
#define ACCUMULATE_OUTGOING_ARGS avr_accumulate_outgoing_args()
#define INIT_EXPANDERS avr_init_expanders()

View File

@ -47,11 +47,15 @@
(ZERO_REGNO 1) ; zero register r1
(SREG_ADDR 0x5F)
(SP_ADDR 0x5D)
;; Register holding the address' high part when loading via ELPM
(RAMPZ_ADDR 0x5B)
])
(define_c_enum "unspec"
[UNSPEC_STRLEN
UNSPEC_MOVMEM
UNSPEC_INDEX_JMP
UNSPEC_FMUL
UNSPEC_FMULS
@ -128,6 +132,7 @@
"out_bitop, out_plus, out_plus_noclobber, addto_sp,
tsthi, tstpsi, tstsi, compare, call,
mov8, mov16, mov24, mov32, reload_in16, reload_in24, reload_in32,
xload, movmem,
ashlqi, ashrqi, lshrqi,
ashlhi, ashrhi, lshrhi,
ashlsi, ashrsi, lshrsi,
@ -137,15 +142,14 @@
;; Flavours of instruction set architecture (ISA), used in enabled attribute
;; mov: ISA has no MOVW
;; movw: ISA has MOVW
;; rjmp: ISA has no CALL/JMP
;; jmp: ISA has CALL/JMP
;; ijmp: ISA has no EICALL/EIJMP
;; eijmp: ISA has EICALL/EIJMP
;; mov : ISA has no MOVW movw : ISA has MOVW
;; rjmp : ISA has no CALL/JMP jmp : ISA has CALL/JMP
;; ijmp : ISA has no EICALL/EIJMP eijmp : ISA has EICALL/EIJMP
;; lpm : ISA has no LPMX lpmx : ISA has LPMX
;; elpm : ISA has ELPM but no ELPMX elpmx : ISA has ELPMX
(define_attr "isa"
"mov,movw, rjmp,jmp, ijmp,eijmp,
"mov,movw, rjmp,jmp, ijmp,eijmp, lpm,lpmx, elpm,elpmx,
standard"
(const_string "standard"))
@ -176,6 +180,22 @@
(and (eq_attr "isa" "eijmp")
(match_test "AVR_HAVE_EIJMP_EICALL"))
(const_int 1)
(and (eq_attr "isa" "lpm")
(match_test "!AVR_HAVE_LPMX"))
(const_int 1)
(and (eq_attr "isa" "lpmx")
(match_test "AVR_HAVE_LPMX"))
(const_int 1)
(and (eq_attr "isa" "elpm")
(match_test "AVR_HAVE_ELPM && !AVR_HAVE_ELPMX"))
(const_int 1)
(and (eq_attr "isa" "elpmx")
(match_test "AVR_HAVE_ELPMX"))
(const_int 1)
] (const_int 0)))
@ -243,12 +263,10 @@
;; even though its function is identical to that in builtins.c
(define_expand "nonlocal_goto"
[
(use (match_operand 0 "general_operand"))
(use (match_operand 1 "general_operand"))
(use (match_operand 2 "general_operand"))
(use (match_operand 3 "general_operand"))
]
[(use (match_operand 0 "general_operand"))
(use (match_operand 1 "general_operand"))
(use (match_operand 2 "general_operand"))
(use (match_operand 3 "general_operand"))]
""
{
rtx r_label = copy_to_reg (operands[1]);
@ -333,7 +351,7 @@
set_mem_addr_space (operands[1], ADDR_SPACE_PGM);
})
(define_insn "*load.<mode>.libgcc"
(define_insn "load_<mode>_libgcc"
[(set (reg:MOVMODE 22)
(match_operand:MOVMODE 0 "memory_operand" "m,m"))]
"avr_load_libgcc_p (operands[0])
@ -348,6 +366,135 @@
(set_attr "cc" "clobber")])
(define_insn_and_split "xload8_A"
[(set (match_operand:QI 0 "register_operand" "=r")
(match_operand:QI 1 "memory_operand" "m"))
(clobber (reg:HI REG_Z))]
"can_create_pseudo_p()
&& avr_mem_pgmx_p (operands[1])
&& REG_P (XEXP (operands[1], 0))"
{ gcc_unreachable(); }
"&& 1"
[(clobber (const_int 0))]
{
rtx insn, addr = XEXP (operands[1], 0);
rtx hi8 = gen_reg_rtx (QImode);
rtx reg_z = gen_rtx_REG (HImode, REG_Z);
emit_move_insn (reg_z, simplify_gen_subreg (HImode, addr, PSImode, 0));
emit_move_insn (hi8, simplify_gen_subreg (QImode, addr, PSImode, 2));
insn = emit_insn (gen_xload_8 (operands[0], hi8));
set_mem_addr_space (SET_SRC (single_set (insn)),
MEM_ADDR_SPACE (operands[1]));
DONE;
})
(define_insn_and_split "xload<mode>_A"
[(set (match_operand:MOVMODE 0 "register_operand" "=r")
(match_operand:MOVMODE 1 "memory_operand" "m"))
(clobber (reg:QI 21))
(clobber (reg:HI REG_Z))]
"QImode != <MODE>mode
&& can_create_pseudo_p()
&& avr_mem_pgmx_p (operands[1])
&& REG_P (XEXP (operands[1], 0))"
{ gcc_unreachable(); }
"&& 1"
[(clobber (const_int 0))]
{
rtx addr = XEXP (operands[1], 0);
rtx reg_z = gen_rtx_REG (HImode, REG_Z);
rtx addr_hi8 = simplify_gen_subreg (QImode, addr, PSImode, 2);
addr_space_t as = MEM_ADDR_SPACE (operands[1]);
rtx hi8, insn;
emit_move_insn (reg_z, simplify_gen_subreg (HImode, addr, PSImode, 0));
if (avr_xload_libgcc_p (<MODE>mode))
{
emit_move_insn (gen_rtx_REG (QImode, 21), addr_hi8);
insn = emit_insn (gen_xload_<mode>_libgcc ());
emit_move_insn (operands[0], gen_rtx_REG (<MODE>mode, 22));
}
else if (avr_current_arch->n_segments == 1
&& GET_MODE_SIZE (<MODE>mode) > 2
&& !AVR_HAVE_LPMX)
{
rtx src = gen_rtx_MEM (<MODE>mode, reg_z);
as = ADDR_SPACE_PGM;
insn = emit_insn (gen_load_<mode>_libgcc (src));
emit_move_insn (operands[0], gen_rtx_REG (<MODE>mode, 22));
}
else
{
hi8 = gen_reg_rtx (QImode);
emit_move_insn (hi8, addr_hi8);
insn = emit_insn (gen_xload_<mode> (operands[0], hi8));
}
set_mem_addr_space (SET_SRC (single_set (insn)), as);
DONE;
})
;; Move value from address space pgmx to a register
;; These insns must be prior to respective generic move insn.
(define_insn "xload_8"
[(set (match_operand:QI 0 "register_operand" "=r")
(mem:QI (lo_sum:PSI (match_operand:QI 1 "register_operand" "r")
(reg:HI REG_Z))))]
""
{
return avr_out_xload (insn, operands, NULL);
}
[(set_attr "adjust_len" "xload")
(set_attr "cc" "clobber")])
;; "xload_hi_libgcc"
;; "xload_psi_libgcc"
;; "xload_si_libgcc"
;; "xload_sf_libgcc"
(define_insn "xload_<mode>_libgcc"
[(set (reg:MOVMODE 22)
(mem:MOVMODE (lo_sum:PSI (reg:QI 21)
(reg:HI REG_Z))))
(clobber (reg:QI 21))
(clobber (reg:HI REG_Z))]
"<MODE>mode != QImode
&& avr_xload_libgcc_p (<MODE>mode)"
{
rtx x_bytes = GEN_INT (GET_MODE_SIZE (<MODE>mode));
/* Devices with ELPM* also have CALL. */
output_asm_insn ("call __xload_%0", &x_bytes);
return "";
}
[(set_attr "length" "2")
(set_attr "cc" "clobber")])
;; "xload_hi"
;; "xload_psi"
;; "xload_si"
;; "xload_sf"
(define_insn "xload_<mode>"
[(set (match_operand:MOVMODE 0 "register_operand" "=r")
(mem:MOVMODE (lo_sum:PSI (match_operand:QI 1 "register_operand" "r")
(reg:HI REG_Z))))
(clobber (scratch:HI))
(clobber (reg:HI REG_Z))]
"<MODE>mode != QImode
&& !avr_xload_libgcc_p (<MODE>mode)"
{
return avr_out_xload (insn, operands, NULL);
}
[(set_attr "adjust_len" "xload")
(set_attr "cc" "clobber")])
;; General move expanders
;; "movqi"
@ -375,6 +522,21 @@
operands[1] = src = copy_to_mode_reg (<MODE>mode, src);
}
if (avr_mem_pgmx_p (src))
{
rtx addr = XEXP (src, 0);
if (!REG_P (addr))
src = replace_equiv_address (src, copy_to_mode_reg (PSImode, addr));
if (QImode == <MODE>mode)
emit_insn (gen_xload8_A (dest, src));
else
emit_insn (gen_xload<mode>_A (dest, src));
DONE;
}
if (avr_load_libgcc_p (src))
{
/* For the small devices, do loads per libgcc call. */
@ -673,171 +835,164 @@
;;=========================================================================
;; move string (like memcpy)
;; implement as RTL loop
(define_expand "movmemhi"
[(parallel [(set (match_operand:BLK 0 "memory_operand" "")
(match_operand:BLK 1 "memory_operand" ""))
(use (match_operand:HI 2 "const_int_operand" ""))
(use (match_operand:HI 3 "const_int_operand" ""))])]
(match_operand:BLK 1 "memory_operand" ""))
(use (match_operand:HI 2 "const_int_operand" ""))
(use (match_operand:HI 3 "const_int_operand" ""))])]
""
"{
int prob;
HOST_WIDE_INT count;
enum machine_mode mode;
rtx label = gen_label_rtx ();
rtx loop_reg;
rtx jump, src;
/* Copy pointers into new psuedos - they will be changed. */
rtx addr0 = copy_to_mode_reg (Pmode, XEXP (operands[0], 0));
rtx addr1 = copy_to_mode_reg (Pmode, XEXP (operands[1], 0));
/* Create rtx for tmp register - we use this as scratch. */
rtx tmp_reg_rtx = gen_rtx_REG (QImode, TMP_REGNO);
if (avr_mem_pgm_p (operands[0]))
DONE;
if (GET_CODE (operands[2]) != CONST_INT)
{
if (avr_emit_movmemhi (operands))
DONE;
FAIL;
})
count = INTVAL (operands[2]);
if (count <= 0)
FAIL;
(define_mode_attr MOVMEM_r_d [(QI "r")
(HI "d")])
/* Work out branch probability for latter use. */
prob = REG_BR_PROB_BASE - REG_BR_PROB_BASE / count;
;; $0, $4 : & dest
;; $1, $5 : & src
;; $2 : Address Space
;; $3, $7 : Loop register
;; $6 : Scratch register
/* See if constant fit 8 bits. */
mode = (count < 0x100) ? QImode : HImode;
/* Create loop counter register. */
loop_reg = copy_to_mode_reg (mode, gen_int_mode (count, mode));
;; "movmem_qi"
;; "movmem_hi"
(define_insn "movmem_<mode>"
[(set (mem:BLK (match_operand:HI 0 "register_operand" "x"))
(mem:BLK (match_operand:HI 1 "register_operand" "z")))
(unspec [(match_operand:QI 2 "const_int_operand" "LP")]
UNSPEC_MOVMEM)
(use (match_operand:QIHI 3 "register_operand" "<MOVMEM_r_d>"))
(clobber (match_operand:HI 4 "register_operand" "=0"))
(clobber (match_operand:HI 5 "register_operand" "=1"))
(clobber (match_operand:QI 6 "register_operand" "=&r"))
(clobber (match_operand:QIHI 7 "register_operand" "=3"))]
""
{
return avr_out_movmem (insn, operands, NULL);
}
[(set_attr "adjust_len" "movmem")
(set_attr "cc" "clobber")])
/* Now create RTL code for move loop. */
/* Label at top of loop. */
emit_label (label);
;; Ditto and
;; $8, $9 : hh8 (& src)
;; $10 : RAMPZ_ADDR
/* Move one byte into scratch and inc pointer. */
src = gen_rtx_MEM (QImode, addr1);
set_mem_addr_space (src, MEM_ADDR_SPACE (operands[1]));
emit_move_insn (tmp_reg_rtx, src);
emit_move_insn (addr1, gen_rtx_PLUS (Pmode, addr1, const1_rtx));
;; "movmem_qi_elpm"
;; "movmem_hi_elpm"
(define_insn "movmem_<mode>_elpm"
[(set (mem:BLK (match_operand:HI 0 "register_operand" "x"))
(mem:BLK (lo_sum:PSI (match_operand:QI 8 "register_operand" "r")
(match_operand:HI 1 "register_operand" "z"))))
(unspec [(match_operand:QI 2 "const_int_operand" "n")]
UNSPEC_MOVMEM)
(use (match_operand:QIHI 3 "register_operand" "<MOVMEM_r_d>"))
(clobber (match_operand:HI 4 "register_operand" "=0"))
(clobber (match_operand:HI 5 "register_operand" "=1"))
(clobber (match_operand:QI 6 "register_operand" "=&r"))
(clobber (match_operand:QIHI 7 "register_operand" "=3"))
(clobber (match_operand:QI 9 "register_operand" "=8"))
(clobber (mem:QI (match_operand:QI 10 "io_address_operand" "n")))]
""
{
return avr_out_movmem (insn, operands, NULL);
}
[(set_attr "adjust_len" "movmem")
(set_attr "cc" "clobber")])
/* Move to mem and inc pointer. */
emit_move_insn (gen_rtx_MEM (QImode, addr0), tmp_reg_rtx);
emit_move_insn (addr0, gen_rtx_PLUS (Pmode, addr0, const1_rtx));
/* Decrement count. */
emit_move_insn (loop_reg, gen_rtx_PLUS (mode, loop_reg, constm1_rtx));
/* Compare with zero and jump if not equal. */
emit_cmp_and_jump_insns (loop_reg, const0_rtx, NE, NULL_RTX, mode, 1,
label);
/* Set jump probability based on loop count. */
jump = get_last_insn ();
add_reg_note (jump, REG_BR_PROB, GEN_INT (prob));
DONE;
}")
;; =%2 =%2 =%2 =%2 =%2 =%2 =%2 =%2 =%2 =%2 =%2 =%2 =%2 =%2 =%2 =%2 =%2 =%2 =%2 =%2 =%2
;; =%2 =%2 =%2 =%2 =%2 =%2 =%2 =%2 =%2 =%2 =%2 =%2 =%2 =%2 =%2 =%2 =%2 =%2
;; memset (%0, %2, %1)
(define_expand "setmemhi"
[(parallel [(set (match_operand:BLK 0 "memory_operand" "")
(match_operand 2 "const_int_operand" ""))
(use (match_operand:HI 1 "const_int_operand" ""))
(use (match_operand:HI 3 "const_int_operand" "n"))
(clobber (match_scratch:HI 4 ""))
(clobber (match_dup 5))])]
(match_operand 2 "const_int_operand" ""))
(use (match_operand:HI 1 "const_int_operand" ""))
(use (match_operand:HI 3 "const_int_operand" ""))
(clobber (match_scratch:HI 4 ""))
(clobber (match_dup 5))])]
""
"{
rtx addr0;
enum machine_mode mode;
{
rtx addr0;
enum machine_mode mode;
/* If value to set is not zero, use the library routine. */
if (operands[2] != const0_rtx)
FAIL;
/* If value to set is not zero, use the library routine. */
if (operands[2] != const0_rtx)
FAIL;
if (!CONST_INT_P (operands[1]))
FAIL;
if (!CONST_INT_P (operands[1]))
FAIL;
mode = u8_operand (operands[1], VOIDmode) ? QImode : HImode;
operands[5] = gen_rtx_SCRATCH (mode);
operands[1] = copy_to_mode_reg (mode,
gen_int_mode (INTVAL (operands[1]), mode));
addr0 = copy_to_mode_reg (Pmode, XEXP (operands[0], 0));
operands[0] = gen_rtx_MEM (BLKmode, addr0);
})
mode = u8_operand (operands[1], VOIDmode) ? QImode : HImode;
operands[5] = gen_rtx_SCRATCH (mode);
operands[1] = copy_to_mode_reg (mode,
gen_int_mode (INTVAL (operands[1]), mode));
addr0 = copy_to_mode_reg (Pmode, XEXP (operands[0], 0));
operands[0] = gen_rtx_MEM (BLKmode, addr0);
}")
(define_insn "*clrmemqi"
[(set (mem:BLK (match_operand:HI 0 "register_operand" "e"))
(const_int 0))
(const_int 0))
(use (match_operand:QI 1 "register_operand" "r"))
(use (match_operand:QI 2 "const_int_operand" "n"))
(clobber (match_scratch:HI 3 "=0"))
(clobber (match_scratch:QI 4 "=&1"))]
""
"st %a0+,__zero_reg__
dec %1
brne .-6"
"0:\;st %a0+,__zero_reg__\;dec %1\;brne 0b"
[(set_attr "length" "3")
(set_attr "cc" "clobber")])
(define_insn "*clrmemhi"
[(set (mem:BLK (match_operand:HI 0 "register_operand" "e,e"))
(const_int 0))
(const_int 0))
(use (match_operand:HI 1 "register_operand" "!w,d"))
(use (match_operand:HI 2 "const_int_operand" "n,n"))
(clobber (match_scratch:HI 3 "=0,0"))
(clobber (match_scratch:HI 4 "=&1,&1"))]
""
"*{
if (which_alternative==0)
return (AS2 (st,%a0+,__zero_reg__) CR_TAB
AS2 (sbiw,%A1,1) CR_TAB
AS1 (brne,.-6));
else
return (AS2 (st,%a0+,__zero_reg__) CR_TAB
AS2 (subi,%A1,1) CR_TAB
AS2 (sbci,%B1,0) CR_TAB
AS1 (brne,.-8));
}"
"@
0:\;st %a0+,__zero_reg__\;sbiw %A1,1\;brne 0b
0:\;st %a0+,__zero_reg__\;subi %A1,1\;sbci %B1,0\;brne 0b"
[(set_attr "length" "3,4")
(set_attr "cc" "clobber,clobber")])
(define_expand "strlenhi"
[(set (match_dup 4)
(unspec:HI [(match_operand:BLK 1 "memory_operand" "")
(match_operand:QI 2 "const_int_operand" "")
(match_operand:HI 3 "immediate_operand" "")]
UNSPEC_STRLEN))
(set (match_dup 4) (plus:HI (match_dup 4)
(const_int -1)))
(set (match_operand:HI 0 "register_operand" "")
(minus:HI (match_dup 4)
(match_dup 5)))]
""
"{
rtx addr;
if (operands[2] != const0_rtx)
FAIL;
addr = copy_to_mode_reg (Pmode, XEXP (operands[1],0));
operands[1] = gen_rtx_MEM (BLKmode, addr);
operands[5] = addr;
operands[4] = gen_reg_rtx (HImode);
}")
[(set (match_dup 4)
(unspec:HI [(match_operand:BLK 1 "memory_operand" "")
(match_operand:QI 2 "const_int_operand" "")
(match_operand:HI 3 "immediate_operand" "")]
UNSPEC_STRLEN))
(set (match_dup 4)
(plus:HI (match_dup 4)
(const_int -1)))
(set (match_operand:HI 0 "register_operand" "")
(minus:HI (match_dup 4)
(match_dup 5)))]
""
{
rtx addr;
if (operands[2] != const0_rtx)
FAIL;
addr = copy_to_mode_reg (Pmode, XEXP (operands[1], 0));
operands[1] = gen_rtx_MEM (BLKmode, addr);
operands[5] = addr;
operands[4] = gen_reg_rtx (HImode);
})
(define_insn "*strlenhi"
[(set (match_operand:HI 0 "register_operand" "=e")
(unspec:HI [(mem:BLK (match_operand:HI 1 "register_operand" "%0"))
(const_int 0)
(match_operand:HI 2 "immediate_operand" "i")]
UNSPEC_STRLEN))]
[(set (match_operand:HI 0 "register_operand" "=e")
(unspec:HI [(mem:BLK (match_operand:HI 1 "register_operand" "0"))
(const_int 0)
(match_operand:HI 2 "immediate_operand" "i")]
UNSPEC_STRLEN))]
""
"ld __tmp_reg__,%a0+
tst __tmp_reg__
brne .-6"
"0:\;ld __tmp_reg__,%a0+\;tst __tmp_reg__\;brne 0b"
[(set_attr "length" "3")
(set_attr "cc" "clobber")])

View File

@ -63,10 +63,11 @@
(match_test "!avr_mem_pgm_p (op)")))
;; Return 1 if OP is an "ordinary" general operand, i.e. a general
;; operand whose load is not handled by a libgcc call.
;; operand whose load is not handled by a libgcc call or ELPM.
(define_predicate "nox_general_operand"
(and (match_operand 0 "general_operand")
(match_test "!avr_load_libgcc_p (op)")))
(not (match_test "avr_load_libgcc_p (op)"))
(not (match_test "avr_mem_pgmx_p (op)"))))
;; Return 1 if OP is the zero constant for MODE.
(define_predicate "const0_operand"

View File

@ -1,3 +1,10 @@
2011-11-18 Georg-Johann Lay <avr@gjlay.de>
PR target/49868
* config/avr/t-avr (LIB1ASMFUNCS): Add _xload_2 _xload_3 _xload_4.
* config/avr/lib1funcs.S (__xload_2, __xload_3, __xload_4):
New functions.
2011-11-16 Matthew Gretton-Dann <matthew.gretton-dann@arm.com>
* config/arm/lib1funcs.asm (udivsi3): Add support for divide

View File

@ -1227,6 +1227,73 @@ ENDF __load_4
#endif /* L_load_3 || L_load_3 */
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Loading n bytes from Flash; n = 2,3,4
;; R22... = Flash[R21:Z]
;; Clobbers: __tmp_reg__, R21, R30, R31
#if (defined (L_xload_2) \
|| defined (L_xload_3) \
|| defined (L_xload_4)) \
&& defined (__AVR_HAVE_ELPM__) \
&& !defined (__AVR_HAVE_ELPMX__)
#if !defined (__AVR_HAVE_RAMPZ__)
#error Need RAMPZ
#endif /* have RAMPZ */
;; Destination
#define D0 22
#define D1 D0+1
#define D2 D0+2
#define D3 D0+3
;; Register containing bits 16+ of the address
#define HHI8 21
.macro .xload dest, n
elpm
mov \dest, r0
.if \dest != D0+\n-1
adiw r30, 1
adc HHI8, __zero_reg__
out __RAMPZ__, HHI8
.endif
.endm
#if defined (L_xload_2)
DEFUN __xload_2
out __RAMPZ__, HHI8
.xload D0, 2
.xload D1, 2
ret
ENDF __xload_2
#endif /* L_xload_2 */
#if defined (L_xload_3)
DEFUN __xload_3
out __RAMPZ__, HHI8
.xload D0, 3
.xload D1, 3
.xload D2, 3
ret
ENDF __xload_3
#endif /* L_xload_3 */
#if defined (L_xload_4)
DEFUN __xload_4
out __RAMPZ__, HHI8
.xload D0, 4
.xload D1, 4
.xload D2, 4
.xload D3, 4
ret
ENDF __xload_4
#endif /* L_xload_4 */
#endif /* L_xload_{2|3|4} && ELPM */
.section .text.libgcc.builtins, "ax", @progbits

View File

@ -22,6 +22,7 @@ LIB1ASMFUNCS = \
_tablejump \
_tablejump_elpm \
_load_3 _load_4 \
_xload_2 _xload_3 _xload_4 \
_copy_data \
_clear_bss \
_ctors \