/* Auxiliary functions for expand movmem, setmem, cmpmem, load_multiple and store_multiple pattern of Andes NDS32 cpu for GNU compiler Copyright (C) 2012-2015 Free Software Foundation, Inc. Contributed by Andes Technology Corporation. This file is part of GCC. GCC is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GCC is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GCC; see the file COPYING3. If not see . */ /* ------------------------------------------------------------------------ */ #include "config.h" #include "system.h" #include "coretypes.h" #include "tm.h" #include "hash-set.h" #include "vec.h" #include "input.h" #include "alias.h" #include "symtab.h" #include "inchash.h" #include "tree.h" #include "stor-layout.h" #include "varasm.h" #include "calls.h" #include "rtl.h" #include "regs.h" #include "hard-reg-set.h" #include "insn-config.h" /* Required by recog.h. */ #include "conditions.h" #include "output.h" #include "insn-attr.h" /* For DFA state_t. */ #include "insn-codes.h" /* For CODE_FOR_xxx. */ #include "reload.h" /* For push_reload(). */ #include "flags.h" #include "function.h" #include "hashtab.h" #include "statistics.h" #include "insn-config.h" #include "expmed.h" #include "dojump.h" #include "explow.h" #include "emit-rtl.h" #include "stmt.h" #include "expr.h" #include "recog.h" #include "diagnostic-core.h" #include "dominance.h" #include "cfg.h" #include "cfgrtl.h" #include "cfganal.h" #include "lcm.h" #include "cfgbuild.h" #include "cfgcleanup.h" #include "predict.h" #include "basic-block.h" #include "df.h" #include "tm_p.h" #include "tm-constrs.h" #include "optabs.h" /* For GEN_FCN. */ #include "target.h" #include "target-def.h" #include "langhooks.h" /* For add_builtin_function(). */ #include "ggc.h" #include "builtins.h" /* ------------------------------------------------------------------------ */ /* Functions to expand load_multiple and store_multiple. They are auxiliary extern functions to help create rtx template. Check nds32-multiple.md file for the patterns. */ rtx nds32_expand_load_multiple (int base_regno, int count, rtx base_addr, rtx basemem) { int par_index; int offset; rtx result; rtx new_addr, mem, reg; /* Create the pattern that is presented in nds32-multiple.md. */ result = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (count)); for (par_index = 0; par_index < count; par_index++) { offset = par_index * 4; /* 4-byte for loading data to each register. */ new_addr = plus_constant (Pmode, base_addr, offset); mem = adjust_automodify_address_nv (basemem, SImode, new_addr, offset); reg = gen_rtx_REG (SImode, base_regno + par_index); XVECEXP (result, 0, par_index) = gen_rtx_SET (reg, mem); } return result; } rtx nds32_expand_store_multiple (int base_regno, int count, rtx base_addr, rtx basemem) { int par_index; int offset; rtx result; rtx new_addr, mem, reg; /* Create the pattern that is presented in nds32-multiple.md. */ result = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (count)); for (par_index = 0; par_index < count; par_index++) { offset = par_index * 4; /* 4-byte for storing data to memory. */ new_addr = plus_constant (Pmode, base_addr, offset); mem = adjust_automodify_address_nv (basemem, SImode, new_addr, offset); reg = gen_rtx_REG (SImode, base_regno + par_index); XVECEXP (result, 0, par_index) = gen_rtx_SET (mem, reg); } return result; } /* Function to move block memory content by using load_multiple and store_multiple. This is auxiliary extern function to help create rtx template. Check nds32-multiple.md file for the patterns. */ int nds32_expand_movmemqi (rtx dstmem, rtx srcmem, rtx total_bytes, rtx alignment) { HOST_WIDE_INT in_words, out_words; rtx dst_base_reg, src_base_reg; int maximum_bytes; /* Because reduced-set regsiters has few registers (r0~r5, r6~10, r15, r28~r31, where 'r15' and 'r28~r31' cannot be used for register allocation), using 8 registers (32 bytes) for moving memory block may easily consume all of them. It makes register allocation/spilling hard to work. So we only allow maximum=4 registers (16 bytes) for moving memory block under reduced-set registers. */ if (TARGET_REDUCED_REGS) maximum_bytes = 16; else maximum_bytes = 32; /* 1. Total_bytes is integer for sure. 2. Alignment is integer for sure. 3. Maximum 4 or 8 registers, 4 * 4 = 16 bytes, 8 * 4 = 32 bytes. 4. Requires (n * 4) block size. 5. Requires 4-byte alignment. */ if (GET_CODE (total_bytes) != CONST_INT || GET_CODE (alignment) != CONST_INT || INTVAL (total_bytes) > maximum_bytes || INTVAL (total_bytes) & 3 || INTVAL (alignment) & 3) return 0; dst_base_reg = copy_to_mode_reg (SImode, XEXP (dstmem, 0)); src_base_reg = copy_to_mode_reg (SImode, XEXP (srcmem, 0)); out_words = in_words = INTVAL (total_bytes) / UNITS_PER_WORD; emit_insn (nds32_expand_load_multiple (0, in_words, src_base_reg, srcmem)); emit_insn (nds32_expand_store_multiple (0, out_words, dst_base_reg, dstmem)); /* Successfully create patterns, return 1. */ return 1; } /* ------------------------------------------------------------------------ */