blob: 2f333371d78c743b6294089fd29d142dc155d2b9 [file] [log] [blame]
/* 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
<http://www.gnu.org/licenses/>. */
/* ------------------------------------------------------------------------ */
#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "tm.h"
#include "hash-set.h"
#include "machmode.h"
#include "vec.h"
#include "double-int.h"
#include "input.h"
#include "alias.h"
#include "symtab.h"
#include "wide-int.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 "real.h"
#include "fixed-value.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 (VOIDmode, 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 (VOIDmode, 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;
}
/* ------------------------------------------------------------------------ */