;; DImode/DFmode patterns description of Andes NDS32 cpu for GNU compiler
;; Copyright (C) 2012-2020 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
;; .
;; -------------------------------------------------------------
;; Move DImode/DFmode instructions.
;; -------------------------------------------------------------
(define_expand "movdi"
[(set (match_operand:DI 0 "general_operand" "")
(match_operand:DI 1 "general_operand" ""))]
""
{
/* Need to force register if mem <- !reg. */
if (MEM_P (operands[0]) && !REG_P (operands[1]))
operands[1] = force_reg (DImode, operands[1]);
})
(define_expand "movdf"
[(set (match_operand:DF 0 "general_operand" "")
(match_operand:DF 1 "general_operand" ""))]
""
{
/* Need to force register if mem <- !reg. */
if (MEM_P (operands[0]) && !REG_P (operands[1]))
operands[1] = force_reg (DFmode, operands[1]);
})
(define_insn "move_"
[(set (match_operand:DIDF 0 "nonimmediate_operand" "=r, r, r, r, Da, m, f, Q, f, *r, *f")
(match_operand:DIDF 1 "general_operand" " r, i, Da, m, r, r, Q, f, f, *f, *r"))]
"register_operand(operands[0], mode)
|| register_operand(operands[1], mode)"
{
switch (which_alternative)
{
case 0:
return "movd44\t%0, %1";
case 1:
/* reg <- const_int, we ask gcc to split instruction. */
return "#";
case 2:
/* The memory format is (mem (reg)),
we can generate 'lmw.bi' instruction. */
return nds32_output_double (operands, true);
case 3:
/* We haven't 64-bit load instruction,
we split this pattern to two SImode pattern. */
return "#";
case 4:
/* The memory format is (mem (reg)),
we can generate 'smw.bi' instruction. */
return nds32_output_double (operands, false);
case 5:
/* We haven't 64-bit store instruction,
we split this pattern to two SImode pattern. */
return "#";
case 6:
return nds32_output_float_load (operands);
case 7:
return nds32_output_float_store (operands);
case 8:
return "fcpysd\t%0, %1, %1";
case 9:
return "fmfdr\t%0, %1";
case 10:
return "fmtdr\t%1, %0";
default:
gcc_unreachable ();
}
}
[(set_attr "type" "alu,alu,load,load,store,store,fload,fstore,fcpy,fmfdr,fmtdr")
(set_attr_alternative "length"
[
;; Alternative 0
(if_then_else (match_test "!TARGET_16_BIT")
(const_int 4)
(const_int 2))
;; Alternative 1
(const_int 16)
;; Alternative 2
(const_int 4)
;; Alternative 3
(const_int 8)
;; Alternative 4
(const_int 4)
;; Alternative 5
(const_int 8)
;; Alternative 6
(const_int 4)
;; Alternative 7
(const_int 4)
;; Alternative 8
(const_int 4)
;; Alternative 9
(const_int 4)
;; Alternative 10
(const_int 4)
])
(set_attr "feature" " v1, v1, v1, v1, v1, v1, fpu, fpu, fpu, fpu, fpu")])
;; Split move_di pattern when the hard register is odd.
(define_split
[(set (match_operand:DIDF 0 "register_operand" "")
(match_operand:DIDF 1 "register_operand" ""))]
"(NDS32_IS_GPR_REGNUM (REGNO (operands[0]))
&& ((REGNO (operands[0]) & 0x1) == 1))
|| (NDS32_IS_GPR_REGNUM (REGNO (operands[1]))
&& ((REGNO (operands[1]) & 0x1) == 1))"
[(set (match_dup 2) (match_dup 3))
(set (match_dup 4) (match_dup 5))]
{
operands[2] = gen_lowpart (SImode, operands[0]);
operands[4] = gen_highpart (SImode, operands[0]);
operands[3] = gen_lowpart (SImode, operands[1]);
operands[5] = gen_highpart (SImode, operands[1]);
}
)
(define_split
[(set (match_operand:DIDF 0 "register_operand" "")
(match_operand:DIDF 1 "const_double_operand" ""))]
"flag_pic || reload_completed"
[(set (match_dup 2) (match_dup 3))
(set (match_dup 4) (match_dup 5))]
{
/* Construct lowpart rtx. */
operands[2] = gen_lowpart (SImode, operands[0]);
operands[3] = gen_lowpart (SImode, operands[1]);
/* Construct highpart rtx. */
/* Note that operands[1] can be VOIDmode constant,
so we need to use gen_highpart_mode().
Refer to gcc/emit-rtl.c for more information. */
operands[4] = gen_highpart (SImode, operands[0]);
operands[5] = gen_highpart_mode (SImode,
GET_MODE (operands[0]), operands[1]);
/* Actually we would like to create move behavior by ourself.
So that movsi expander could have chance to split large constant. */
emit_move_insn (operands[2], operands[3]);
unsigned HOST_WIDE_INT mask = GET_MODE_MASK (SImode);
if ((UINTVAL (operands[3]) & mask) == (UINTVAL (operands[5]) & mask))
emit_move_insn (operands[4], operands[2]);
else
emit_move_insn (operands[4], operands[5]);
DONE;
})
;; There is 'movd44' instruction for DImode/DFmode movement under V3/V3M ISA.
;; We only need to split it under V2 ISA or none-16-bit code generation.
(define_split
[(set (match_operand:DIDF 0 "register_operand" "")
(match_operand:DIDF 1 "register_operand" ""))]
"reload_completed
&& (TARGET_ISA_V2 || !TARGET_16_BIT)
&& NDS32_IS_GPR_REGNUM (REGNO (operands[0]))
&& NDS32_IS_GPR_REGNUM (REGNO (operands[1]))"
[(set (match_dup 0) (match_dup 1))
(set (match_dup 2) (match_dup 3))]
{
operands[2] = gen_highpart (SImode, operands[0]);
operands[3] = gen_highpart (SImode, operands[1]);
operands[0] = gen_lowpart (SImode, operands[0]);
operands[1] = gen_lowpart (SImode, operands[1]);
/* Handle a partial overlap. */
if (rtx_equal_p (operands[0], operands[3]))
{
rtx tmp0 = operands[0];
rtx tmp1 = operands[1];
operands[0] = operands[2];
operands[1] = operands[3];
operands[2] = tmp0;
operands[3] = tmp1;
}
})
(define_split
[(set (match_operand:DIDF 0 "nds32_general_register_operand" "")
(match_operand:DIDF 1 "memory_operand" ""))]
"reload_completed
&& nds32_split_double_word_load_store_p (operands, true)"
[(set (match_dup 2) (match_dup 3))
(set (match_dup 4) (match_dup 5))]
{
nds32_spilt_doubleword (operands, true);
})
(define_split
[(set (match_operand:DIDF 0 "memory_operand" "")
(match_operand:DIDF 1 "nds32_general_register_operand" ""))]
"reload_completed
&& nds32_split_double_word_load_store_p (operands, false)"
[(set (match_dup 2) (match_dup 3))
(set (match_dup 4) (match_dup 5))]
{
nds32_spilt_doubleword (operands, false);
})
;; -------------------------------------------------------------
;; Boolean DImode instructions.
;; -------------------------------------------------------------
;; Nowadays, the generic code is supposed to split the DImode
;; boolean operations and have good code generation.
;; Unless we find out some bad cases, there is no need to
;; define DImode boolean operations by ourself.
;; -------------------------------------------------------------