1;; DImode/DFmode patterns description of Andes NDS32 cpu for GNU compiler 2;; Copyright (C) 2012-2018 Free Software Foundation, Inc. 3;; Contributed by Andes Technology Corporation. 4;; 5;; This file is part of GCC. 6;; 7;; GCC is free software; you can redistribute it and/or modify it 8;; under the terms of the GNU General Public License as published 9;; by the Free Software Foundation; either version 3, or (at your 10;; option) any later version. 11;; 12;; GCC is distributed in the hope that it will be useful, but WITHOUT 13;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 14;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public 15;; License for more details. 16;; 17;; You should have received a copy of the GNU General Public License 18;; along with GCC; see the file COPYING3. If not see 19;; <http://www.gnu.org/licenses/>. 20 21 22;; ------------------------------------------------------------- 23;; Move DImode/DFmode instructions. 24;; ------------------------------------------------------------- 25 26 27(define_expand "movdi" 28 [(set (match_operand:DI 0 "general_operand" "") 29 (match_operand:DI 1 "general_operand" ""))] 30 "" 31{ 32 /* Need to force register if mem <- !reg. */ 33 if (MEM_P (operands[0]) && !REG_P (operands[1])) 34 operands[1] = force_reg (DImode, operands[1]); 35}) 36 37(define_expand "movdf" 38 [(set (match_operand:DF 0 "general_operand" "") 39 (match_operand:DF 1 "general_operand" ""))] 40 "" 41{ 42 /* Need to force register if mem <- !reg. */ 43 if (MEM_P (operands[0]) && !REG_P (operands[1])) 44 operands[1] = force_reg (DFmode, operands[1]); 45}) 46 47 48(define_insn "move_<mode>" 49 [(set (match_operand:DIDF 0 "nonimmediate_operand" "=r, r, r, r, Da, m, f, Q, f, *r, *f") 50 (match_operand:DIDF 1 "general_operand" " r, i, Da, m, r, r, Q, f, f, *f, *r"))] 51 "register_operand(operands[0], <MODE>mode) 52 || register_operand(operands[1], <MODE>mode)" 53{ 54 switch (which_alternative) 55 { 56 case 0: 57 return "movd44\t%0, %1"; 58 case 1: 59 /* reg <- const_int, we ask gcc to split instruction. */ 60 return "#"; 61 case 2: 62 /* The memory format is (mem (reg)), 63 we can generate 'lmw.bi' instruction. */ 64 return nds32_output_double (operands, true); 65 case 3: 66 /* We haven't 64-bit load instruction, 67 we split this pattern to two SImode pattern. */ 68 return "#"; 69 case 4: 70 /* The memory format is (mem (reg)), 71 we can generate 'smw.bi' instruction. */ 72 return nds32_output_double (operands, false); 73 case 5: 74 /* We haven't 64-bit store instruction, 75 we split this pattern to two SImode pattern. */ 76 return "#"; 77 case 6: 78 return nds32_output_float_load (operands); 79 case 7: 80 return nds32_output_float_store (operands); 81 case 8: 82 return "fcpysd\t%0, %1, %1"; 83 case 9: 84 return "fmfdr\t%0, %1"; 85 case 10: 86 return "fmtdr\t%1, %0"; 87 default: 88 gcc_unreachable (); 89 } 90} 91 [(set_attr "type" "alu,alu,load,load,store,store,fload,fstore,fcpy,fmfdr,fmtdr") 92 (set_attr_alternative "length" 93 [ 94 ;; Alternative 0 95 (if_then_else (match_test "!TARGET_16_BIT") 96 (const_int 4) 97 (const_int 2)) 98 ;; Alternative 1 99 (const_int 16) 100 ;; Alternative 2 101 (const_int 4) 102 ;; Alternative 3 103 (const_int 8) 104 ;; Alternative 4 105 (const_int 4) 106 ;; Alternative 5 107 (const_int 8) 108 ;; Alternative 6 109 (const_int 4) 110 ;; Alternative 7 111 (const_int 4) 112 ;; Alternative 8 113 (const_int 4) 114 ;; Alternative 9 115 (const_int 4) 116 ;; Alternative 10 117 (const_int 4) 118 ]) 119 (set_attr "feature" " v1, v1, v1, v1, v1, v1, fpu, fpu, fpu, fpu, fpu")]) 120 121;; Split move_di pattern when the hard register is odd. 122(define_split 123 [(set (match_operand:DIDF 0 "register_operand" "") 124 (match_operand:DIDF 1 "register_operand" ""))] 125 "(NDS32_IS_GPR_REGNUM (REGNO (operands[0])) 126 && ((REGNO (operands[0]) & 0x1) == 1)) 127 || (NDS32_IS_GPR_REGNUM (REGNO (operands[1])) 128 && ((REGNO (operands[1]) & 0x1) == 1))" 129 [(set (match_dup 2) (match_dup 3)) 130 (set (match_dup 4) (match_dup 5))] 131 { 132 operands[2] = gen_lowpart (SImode, operands[0]); 133 operands[4] = gen_highpart (SImode, operands[0]); 134 operands[3] = gen_lowpart (SImode, operands[1]); 135 operands[5] = gen_highpart (SImode, operands[1]); 136 } 137) 138 139(define_split 140 [(set (match_operand:DIDF 0 "register_operand" "") 141 (match_operand:DIDF 1 "const_double_operand" ""))] 142 "reload_completed" 143 [(set (match_dup 2) (match_dup 3)) 144 (set (match_dup 4) (match_dup 5))] 145{ 146 /* Construct lowpart rtx. */ 147 operands[2] = gen_lowpart (SImode, operands[0]); 148 operands[3] = gen_lowpart (SImode, operands[1]); 149 150 /* Construct highpart rtx. */ 151 /* Note that operands[1] can be VOIDmode constant, 152 so we need to use gen_highpart_mode(). 153 Refer to gcc/emit-rtl.c for more information. */ 154 operands[4] = gen_highpart (SImode, operands[0]); 155 operands[5] = gen_highpart_mode (SImode, 156 GET_MODE (operands[0]), operands[1]); 157 158 /* Actually we would like to create move behavior by ourself. 159 So that movsi expander could have chance to split large constant. */ 160 emit_move_insn (operands[2], operands[3]); 161 162 unsigned HOST_WIDE_INT mask = GET_MODE_MASK (SImode); 163 if ((UINTVAL (operands[3]) & mask) == (UINTVAL (operands[5]) & mask)) 164 emit_move_insn (operands[4], operands[2]); 165 else 166 emit_move_insn (operands[4], operands[5]); 167 DONE; 168}) 169 170;; There is 'movd44' instruction for DImode/DFmode movement under V3/V3M ISA. 171;; We only need to split it under V2 ISA or none-16-bit code generation. 172(define_split 173 [(set (match_operand:DIDF 0 "register_operand" "") 174 (match_operand:DIDF 1 "register_operand" ""))] 175 "reload_completed 176 && (TARGET_ISA_V2 || !TARGET_16_BIT) 177 && NDS32_IS_GPR_REGNUM (REGNO (operands[0])) 178 && NDS32_IS_GPR_REGNUM (REGNO (operands[1]))" 179 [(set (match_dup 0) (match_dup 1)) 180 (set (match_dup 2) (match_dup 3))] 181{ 182 operands[2] = gen_highpart (SImode, operands[0]); 183 operands[3] = gen_highpart (SImode, operands[1]); 184 operands[0] = gen_lowpart (SImode, operands[0]); 185 operands[1] = gen_lowpart (SImode, operands[1]); 186 187 /* Handle a partial overlap. */ 188 if (rtx_equal_p (operands[0], operands[3])) 189 { 190 rtx tmp0 = operands[0]; 191 rtx tmp1 = operands[1]; 192 193 operands[0] = operands[2]; 194 operands[1] = operands[3]; 195 operands[2] = tmp0; 196 operands[3] = tmp1; 197 } 198}) 199 200(define_split 201 [(set (match_operand:DIDF 0 "nds32_general_register_operand" "") 202 (match_operand:DIDF 1 "memory_operand" ""))] 203 "reload_completed 204 && nds32_split_double_word_load_store_p (operands, true)" 205 [(set (match_dup 2) (match_dup 3)) 206 (set (match_dup 4) (match_dup 5))] 207{ 208 nds32_spilt_doubleword (operands, true); 209}) 210 211(define_split 212 [(set (match_operand:DIDF 0 "memory_operand" "") 213 (match_operand:DIDF 1 "nds32_general_register_operand" ""))] 214 "reload_completed 215 && nds32_split_double_word_load_store_p (operands, false)" 216 [(set (match_dup 2) (match_dup 3)) 217 (set (match_dup 4) (match_dup 5))] 218{ 219 nds32_spilt_doubleword (operands, false); 220}) 221 222;; ------------------------------------------------------------- 223;; Boolean DImode instructions. 224;; ------------------------------------------------------------- 225 226;; Nowadays, the generic code is supposed to split the DImode 227;; boolean operations and have good code generation. 228;; Unless we find out some bad cases, there is no need to 229;; define DImode boolean operations by ourself. 230 231;; ------------------------------------------------------------- 232