;; Machine description for TI C6X.
-;; Copyright (C) 2010, 2011 Free Software Foundation, Inc.
+;; Copyright (C) 2010-2021 Free Software Foundation, Inc.
;; Contributed by Andrew Jenner <andrew@codesourcery.com>
;; Contributed by Bernd Schmidt <bernds@codesourcery.com>
;; Contributed by CodeSourcery.
"n,y"
(const_string "n"))
+;; This describes the relationship between operands and register files.
+;; For example, "sxs" means that operands 0 and 2 determine the side of
+;; the machine, and operand 1 can optionally use the cross path. "dt" and
+;; "td" are used to describe loads and stores.
+;; Used for register renaming in loops for improving modulo scheduling.
+(define_attr "op_pattern"
+ "unknown,dt,td,sx,sxs,ssx"
+ (cond [(eq_attr "type" "load") (const_string "td")
+ (eq_attr "type" "store") (const_string "dt")]
+ (const_string "unknown")))
+
(define_attr "has_shadow"
"n,y"
(const_string "n"))
(eq_attr "type" "mpysp2dp") (const_int 5)]
(const_int 1)))
+;; The number of cycles during which the instruction reserves functional
+;; units.
+(define_attr "reserve_cycles" ""
+ (cond [(eq_attr "type" "cmpdp") (const_int 2)
+ (eq_attr "type" "adddp") (const_int 2)
+ (eq_attr "type" "mpydp") (const_int 4)
+ (eq_attr "type" "mpyi") (const_int 4)
+ (eq_attr "type" "mpyid") (const_int 4)
+ (eq_attr "type" "mpyspdp") (const_int 2)]
+ (const_int 1)))
+
(define_attr "predicable" "no,yes"
(const_string "yes"))
]
(const_string "unknown")))
-(define_automaton "c6x_1,c6x_w1,c6x_2,c6x_w2,c6x_m1,c6x_m2,c6x_t1,c6x_t2,c6x_branch")
+(define_automaton "c6x_1,c6x_2,c6x_m1,c6x_m2,c6x_t1,c6x_t2,c6x_branch")
+(automata_option "no-comb-vect")
(automata_option "ndfa")
+(automata_option "collapse-ndfa")
-(define_cpu_unit "d1,l1,s1" "c6x_1")
+(define_query_cpu_unit "d1,l1,s1" "c6x_1")
(define_cpu_unit "x1" "c6x_1")
-(define_cpu_unit "l1w,s1w" "c6x_w1")
-(define_cpu_unit "m1" "c6x_m1")
+(define_cpu_unit "l1w,s1w" "c6x_1")
+(define_query_cpu_unit "m1" "c6x_m1")
(define_cpu_unit "m1w" "c6x_m1")
(define_cpu_unit "t1" "c6x_t1")
-(define_cpu_unit "d2,l2,s2" "c6x_2")
+(define_query_cpu_unit "d2,l2,s2" "c6x_2")
(define_cpu_unit "x2" "c6x_2")
-(define_cpu_unit "l2w,s2w" "c6x_w2")
-(define_cpu_unit "m2" "c6x_m2")
+(define_cpu_unit "l2w,s2w" "c6x_2")
+(define_query_cpu_unit "m2" "c6x_m2")
(define_cpu_unit "m2w" "c6x_m2")
(define_cpu_unit "t2" "c6x_t2")
+;; A special set of units used to identify specific reservations, rather than
+;; just units.
+(define_query_cpu_unit "fps1,fpl1,adddps1,adddpl1" "c6x_1")
+(define_query_cpu_unit "fps2,fpl2,adddps2,adddpl2" "c6x_2")
;; There can be up to two branches in one cycle (on the .s1 and .s2
;; units), but some instructions must not be scheduled in parallel
"%|%.\\tldw\\t%$\\t*+%1[%2], %0"
[(set_attr "type" "load")
(set_attr "units" "d_addr")
+ (set_attr "op_pattern" "unknown")
(set_attr "dest_regfile" "a,b")
(set_attr "addr_regfile" "b")])
[(set (match_dup 2) (match_dup 3))]
{
unsigned HOST_WIDE_INT mask, val;
- enum machine_mode inner_mode = GET_MODE_INNER (<MODE>mode);
+ machine_mode inner_mode = GET_MODE_INNER (<MODE>mode);
int i;
val = 0;
unsigned HOST_WIDE_INT mask;
unsigned HOST_WIDE_INT val[2];
rtx lo_half, hi_half;
- enum machine_mode inner_mode = GET_MODE_INNER (<MODE>mode);
+ machine_mode inner_mode = GET_MODE_INNER (<MODE>mode);
int i, j;
split_di (operands, 1, &lo_half, &hi_half);
(ashift:SI (match_dup 4) (const_int 16))))]
{
long values;
- REAL_VALUE_TYPE value;
gcc_assert (GET_CODE (operands[1]) == CONST_DOUBLE);
- REAL_VALUE_FROM_CONST_DOUBLE (value, operands[1]);
- REAL_VALUE_TO_TARGET_SINGLE (value, values);
+ REAL_VALUE_TO_TARGET_SINGLE (*CONST_DOUBLE_REAL_VALUE (operands[1]), values);
operands[2] = gen_rtx_REG (SImode, true_regnum (operands[0]));
operands[3] = GEN_INT (trunc_int_for_mode (values, HImode));
%|%.\\tadda%D2\\t%$\\t%1, %2, %0"
[(set_attr "units" "d")
(set_attr "cross" "y,n")
+ (set_attr "op_pattern" "unknown")
(set_attr "predicable" "no")])
;; Move instruction patterns
[(set_attr "type" "*,*,*,*,*,*,load,load,load,load,store,store,store,store")
(set_attr "units62" "dls,dls,ls,ls,s,s,d_addr,d_addr,d_addr,d_addr,d_addr,d_addr,d_addr,d_addr")
(set_attr "units64" "dls,dls,ls,ls,dl,s,d_addr,d_addr,d_addr,d_addr,d_addr,d_addr,d_addr,d_addr")
+ (set_attr "op_pattern" "sx,sx,sx,sx,*,*,*,*,*,*,*,*,*,*")
(set_attr "addr_regfile" "*,*,*,*,*,*,a,b,b,a,a,b,b,a")
(set_attr "dest_regfile" "*,*,*,*,*,*,a,a,b,b,a,a,b,b")
(set_attr "cross" "n,n,y,y,n,n,n,y,n,y,n,y,n,y")])
[(set_attr "type" "*,*,*,*,*,*,*,*,*,load,load,load,load,store,store,store,store")
(set_attr "units62" "dls,dls,ls,ls,s,s,d,d,*,d_addr,d_addr,d_addr,d_addr,d_addr,d_addr,d_addr,d_addr")
(set_attr "units64" "dls,dls,ls,ls,dl,s,d,d,*,d_addr,d_addr,d_addr,d_addr,d_addr,d_addr,d_addr,d_addr")
+ (set_attr "op_pattern" "sx,sx,sx,sx,*,*,*,*,*,*,*,*,*,*,*,*,*")
(set_attr "addr_regfile" "*,*,*,*,*,*,*,*,*,a,b,b,a,a,b,b,a")
(set_attr "dest_regfile" "*,*,*,*,*,*,*,*,*,a,a,b,b,a,a,b,b")
(set_attr "cross" "n,n,y,y,n,n,y,n,*,n,y,n,y,n,y,n,y")
UNSPEC_MISALIGNED_ACCESS))]
"TARGET_INSNS_64"
{
- if (memory_operand (operands[0], <MODE>mode))
+ if (MEM_P (operands[0]))
{
emit_insn (gen_movmisalign<mode>_store (operands[0], operands[1]));
DONE;
(define_insn "<ext_name><mode>si2"
[(set (match_operand:SI 0 "register_operand" "=a,b,a,?a, b,?b")
- (any_ext: SI (match_operand:QIHIM 1 "nonimmediate_operand" "a,b,Q, R, R, Q")))]
+ (any_ext:SI (match_operand:QIHIM 1 "nonimmediate_operand" "a,b,Q, R, R, Q")))]
""
"@
%|%.\\text<u>\\t%$\\t%1, <ext_shift>, <ext_shift>, %0
rtx tmpreg = gen_reg_rtx (SImode);
rtx t = gen_rtx_fmt_ee (reverse_condition (GET_CODE (operands[1])),
SImode, operands[2], operands[3]);
- emit_insn (gen_rtx_SET (VOIDmode, tmpreg, t));
+ emit_insn (gen_rtx_SET (tmpreg, t));
emit_insn (gen_scmpsi_insn (operands[0],
gen_rtx_fmt_ee (EQ, SImode, tmpreg, const0_rtx),
tmpreg, const0_rtx));
}"
)
+;; -------------------------------------------------------------------------
+;; Doloop
+;; -------------------------------------------------------------------------
+
+; operand 0 is the loop count pseudo register
+; operand 1 is the label to jump to at the top of the loop
+(define_expand "doloop_end"
+ [(parallel [(set (pc) (if_then_else
+ (ne (match_operand:SI 0 "" "")
+ (const_int 1))
+ (label_ref (match_operand 1 "" ""))
+ (pc)))
+ (set (match_dup 0)
+ (plus:SI (match_dup 0)
+ (const_int -1)))
+ (clobber (match_dup 2))])] ; match_scratch
+ "TARGET_INSNS_64PLUS && optimize"
+{
+ /* The loop optimizer doesn't check the predicates... */
+ if (GET_MODE (operands[0]) != SImode)
+ FAIL;
+ operands[2] = gen_rtx_SCRATCH (SImode);
+})
+
+(define_insn "mvilc"
+ [(set (reg:SI REG_ILC)
+ (unspec [(match_operand:SI 0 "register_operand" "a,b")] UNSPEC_MVILC))]
+ "TARGET_INSNS_64PLUS"
+ "%|%.\\tmvc\\t%$\\t%0, ILC"
+ [(set_attr "predicable" "no")
+ (set_attr "cross" "y,n")
+ (set_attr "units" "s")
+ (set_attr "dest_regfile" "b")
+ (set_attr "type" "mvilc")])
+
+(define_insn "sploop"
+ [(unspec_volatile [(match_operand:SI 0 "const_int_operand" "i")
+ (reg:SI REG_ILC)]
+ UNSPECV_SPLOOP)]
+ "TARGET_INSNS_64PLUS"
+ "%|%.\\tsploop\t%0"
+ [(set_attr "predicable" "no")
+ (set_attr "type" "sploop")])
+
+(define_insn "spkernel"
+ [(set (pc)
+ (if_then_else
+ (ne (unspec_volatile:SI
+ [(match_operand:SI 0 "const_int_operand" "i")
+ (match_operand:SI 1 "const_int_operand" "i")]
+ UNSPECV_SPKERNEL)
+ (const_int 1))
+ (label_ref (match_operand 2 "" ""))
+ (pc)))]
+ "TARGET_INSNS_64PLUS"
+ "%|%.\\tspkernel\t%0, %1"
+ [(set_attr "predicable" "no")
+ (set_attr "type" "spkernel")])
+
+(define_insn "loop_end"
+ [(set (pc)
+ (if_then_else (ne (match_operand:SI 3 "nonimmediate_operand" "0,0,0,*r")
+ (const_int 1))
+ (label_ref (match_operand 1 "" ""))
+ (pc)))
+ (set (match_operand:SI 0 "nonimmediate_operand" "=AB,*r,m,m")
+ (plus:SI (match_dup 3)
+ (const_int -1)))
+ (clobber (match_scratch:SI 2 "=X,&AB,&AB,&AB"))]
+ "TARGET_INSNS_64PLUS && optimize"
+ "#"
+ [(set_attr "type" "spkernel")])
+
+(define_split
+ [(set (pc)
+ (if_then_else (ne (match_operand:SI 3 "nonimmediate_operand" "")
+ (const_int 1))
+ (label_ref (match_operand 1 "" ""))
+ (pc)))
+ (set (match_operand:SI 0 "memory_operand" "")
+ (plus:SI (match_dup 3)
+ (const_int -1)))
+ (clobber (match_scratch 2))]
+ ""
+ [(set (match_dup 2) (plus:SI (match_dup 3) (const_int -1)))
+ (set (match_dup 0) (match_dup 2))
+ (set (pc)
+ (if_then_else (ne (match_dup 2) (const_int 0))
+ (label_ref (match_dup 1))
+ (pc)))]
+{
+ if (!REG_P (operands[3]))
+ {
+ emit_move_insn (operands[2], operands[3]);
+ operands[3] = operands[2];
+ }
+})
+
;; -------------------------------------------------------------------------
;; Delayed-branch real jumps and shadows
;; -------------------------------------------------------------------------
(define_insn "real_jump"
- [(unspec [(match_operand 0 "c6x_jump_operand" "a,b,s") (const_int 0)]
+ [(unspec [(match_operand 0 "c6x_jump_operand" "a,b,S3") (const_int 0)]
UNSPEC_REAL_JUMP)]
""
{
(set_attr "cross" "y,n")
(set_attr "dest_regfile" "b")])
+;; computed_jump_p returns true if it finds a constant; so use one in the
+;; unspec.
(define_insn "indirect_jump_shadow"
- [(set (pc) (unspec [(pc)] UNSPEC_JUMP_SHADOW))]
+ [(set (pc) (unspec [(const_int 1)] UNSPEC_JUMP_SHADOW))]
""
";; indirect jump occurs"
[(set_attr "type" "shadow")])
(define_expand "ctzdi2"
[(set (match_operand:DI 0 "register_operand" "")
- (ctz:SI (match_operand:DI 1 "register_operand" "")))]
+ (ctz:DI (match_operand:DI 1 "register_operand" "")))]
"TARGET_INSNS_64"
{
rtx tmpreg = gen_reg_rtx (DImode);
"TARGET_FP && flag_reciprocal_math"
{
operands[3] = force_reg (SFmode,
- CONST_DOUBLE_FROM_REAL_VALUE (dconst2, SFmode));
+ const_double_from_real_value (dconst2, SFmode));
operands[4] = gen_reg_rtx (SFmode);
operands[5] = gen_reg_rtx (SFmode);
operands[6] = gen_reg_rtx (SFmode);
"TARGET_FP && flag_reciprocal_math"
{
operands[3] = force_reg (DFmode,
- CONST_DOUBLE_FROM_REAL_VALUE (dconst2, DFmode));
+ const_double_from_real_value (dconst2, DFmode));
operands[4] = gen_reg_rtx (DFmode);
operands[5] = gen_reg_rtx (DFmode);
operands[6] = gen_reg_rtx (DFmode);
;; Block moves
;; -------------------------------------------------------------------------
-(define_expand "movmemsi"
+(define_expand "cpymemsi"
[(use (match_operand:BLK 0 "memory_operand" ""))
(use (match_operand:BLK 1 "memory_operand" ""))
(use (match_operand:SI 2 "nonmemory_operand" ""))
(use (match_operand:SI 5 "const_int_operand" ""))]
""
{
- if (c6x_expand_movmem (operands[0], operands[1], operands[2], operands[3],
+ if (c6x_expand_cpymem (operands[0], operands[1], operands[2], operands[3],
operands[4], operands[5]))
DONE;
else