@@ -1260,6 +1260,22 @@ ix86_swap_binary_operands_p (enum rtx_code code, machine_mode mode,
return false;
}
+/* APX extends most (but not all) integer instructions with a new form that
+ has a third register operand called a nondestructive destination (NDD). */
+
+bool ix86_can_use_ndd_p (enum rtx_code code)
+{
+ if (!TARGET_APX_NDD)
+ return false;
+ switch (code)
+ {
+ case PLUS:
+ return true;
+ default:
+ return false;
+ }
+ return false;
+}
/* Fix up OPERANDS to satisfy ix86_binary_operator_ok. Return the
destination to use for the operation. If different from the true
@@ -1267,7 +1283,7 @@ ix86_swap_binary_operands_p (enum rtx_code code, machine_mode mode,
rtx
ix86_fixup_binary_operands (enum rtx_code code, machine_mode mode,
- rtx operands[])
+ rtx operands[], bool use_ndd)
{
rtx dst = operands[0];
rtx src1 = operands[1];
@@ -1307,7 +1323,7 @@ ix86_fixup_binary_operands (enum rtx_code code, machine_mode mode,
src1 = force_reg (mode, src1);
/* Source 1 cannot be a non-matching memory. */
- if (MEM_P (src1) && !rtx_equal_p (dst, src1))
+ if (!use_ndd && MEM_P (src1) && !rtx_equal_p (dst, src1))
src1 = force_reg (mode, src1);
/* Improve address combine. */
@@ -1338,11 +1354,11 @@ ix86_fixup_binary_operands_no_copy (enum rtx_code code,
void
ix86_expand_binary_operator (enum rtx_code code, machine_mode mode,
- rtx operands[])
+ rtx operands[], bool use_ndd)
{
rtx src1, src2, dst, op, clob;
- dst = ix86_fixup_binary_operands (code, mode, operands);
+ dst = ix86_fixup_binary_operands (code, mode, operands, use_ndd);
src1 = operands[1];
src2 = operands[2];
@@ -1352,7 +1368,8 @@ ix86_expand_binary_operator (enum rtx_code code, machine_mode mode,
if (reload_completed
&& code == PLUS
- && !rtx_equal_p (dst, src1))
+ && !rtx_equal_p (dst, src1)
+ && !use_ndd)
{
/* This is going to be an LEA; avoid splitting it later. */
emit_insn (op);
@@ -1451,7 +1468,7 @@ ix86_expand_vector_logical_operator (enum rtx_code code, machine_mode mode,
bool
ix86_binary_operator_ok (enum rtx_code code, machine_mode mode,
- rtx operands[3])
+ rtx operands[3], bool use_ndd)
{
rtx dst = operands[0];
rtx src1 = operands[1];
@@ -1475,7 +1492,7 @@ ix86_binary_operator_ok (enum rtx_code code, machine_mode mode,
return false;
/* Source 1 cannot be a non-matching memory. */
- if (MEM_P (src1) && !rtx_equal_p (dst, src1))
+ if (!use_ndd && MEM_P (src1) && !rtx_equal_p (dst, src1))
/* Support "andhi/andsi/anddi" as a zero-extending move. */
return (code == AND
&& (mode == HImode
@@ -2099,6 +2099,9 @@ ix86_option_override_internal (bool main_args_p,
if (TARGET_APX_F && !TARGET_64BIT)
error ("%<-mapxf%> is not supported for 32-bit code");
+ if (opts->x_ix86_apx_features != apx_none && !TARGET_64BIT)
+ error ("%<-mapx-features=%> option is not supported for 32-bit code");
+
if (TARGET_UINTR && !TARGET_64BIT)
error ("%<-muintr%> not supported for 32-bit code");
@@ -108,14 +108,15 @@ extern void ix86_expand_move (machine_mode, rtx[]);
extern void ix86_expand_vector_move (machine_mode, rtx[]);
extern void ix86_expand_vector_move_misalign (machine_mode, rtx[]);
extern rtx ix86_fixup_binary_operands (enum rtx_code,
- machine_mode, rtx[]);
+ machine_mode, rtx[], bool = false);
extern void ix86_fixup_binary_operands_no_copy (enum rtx_code,
machine_mode, rtx[]);
extern void ix86_expand_binary_operator (enum rtx_code,
- machine_mode, rtx[]);
+ machine_mode, rtx[], bool = false);
extern void ix86_expand_vector_logical_operator (enum rtx_code,
machine_mode, rtx[]);
-extern bool ix86_binary_operator_ok (enum rtx_code, machine_mode, rtx[3]);
+extern bool ix86_binary_operator_ok (enum rtx_code, machine_mode, rtx[3], bool = false);
+extern bool ix86_can_use_ndd_p (enum rtx_code);
extern bool ix86_avoid_lea_for_add (rtx_insn *, rtx[]);
extern bool ix86_use_lea_for_mov (rtx_insn *, rtx[]);
extern bool ix86_avoid_lea_for_addr (rtx_insn *, rtx[]);
@@ -559,7 +559,7 @@ (define_attr "unit" "integer,i387,sse,mmx,unknown"
;; Used to control the "enabled" attribute on a per-instruction basis.
(define_attr "isa" "base,x64,nox64,x64_sse2,x64_sse4,x64_sse4_noavx,
- x64_avx,x64_avx512bw,x64_avx512dq,aes,
+ x64_avx,x64_avx512bw,x64_avx512dq,aes,apx_ndd,
sse_noavx,sse2,sse2_noavx,sse3,sse3_noavx,sse4,sse4_noavx,
avx,noavx,avx2,noavx2,bmi,bmi2,fma4,fma,avx512f,avx512f_512,
noavx512f,avx512bw,avx512bw_512,noavx512bw,avx512dq,
@@ -957,6 +957,8 @@ (define_attr "enabled" ""
(symbol_ref "TARGET_AVX512BF16 && TARGET_AVX512VL")
(eq_attr "isa" "vpclmulqdqvl")
(symbol_ref "TARGET_VPCLMULQDQ && TARGET_AVX512VL")
+ (eq_attr "isa" "apx_ndd")
+ (symbol_ref "TARGET_APX_NDD")
(eq_attr "mmx_isa" "native")
(symbol_ref "!TARGET_MMX_WITH_SSE")
@@ -6229,7 +6231,8 @@ (define_expand "add<mode>3"
(plus:SDWIM (match_operand:SDWIM 1 "nonimmediate_operand")
(match_operand:SDWIM 2 "<general_hilo_operand>")))]
""
- "ix86_expand_binary_operator (PLUS, <MODE>mode, operands); DONE;")
+ "ix86_expand_binary_operator (PLUS, <MODE>mode, operands,
+ ix86_can_use_ndd_p (PLUS)); DONE;")
(define_insn_and_split "*add<dwi>3_doubleword"
[(set (match_operand:<DWI> 0 "nonimmediate_operand" "=ro,r")
@@ -6356,26 +6359,29 @@ (define_insn_and_split "*add<dwi>3_doubleword_concat_zext"
"split_double_mode (<DWI>mode, &operands[0], 1, &operands[0], &operands[5]);")
(define_insn "*add<mode>_1"
- [(set (match_operand:SWI48 0 "nonimmediate_operand" "=rm,r,r,r")
+ [(set (match_operand:SWI48 0 "nonimmediate_operand" "=rm,r,r,r,r,r")
(plus:SWI48
- (match_operand:SWI48 1 "nonimmediate_operand" "%0,0,r,r")
- (match_operand:SWI48 2 "x86_64_general_operand" "re,BM,0,le")))
+ (match_operand:SWI48 1 "nonimmediate_operand" "%0,0,r,r,rm,r")
+ (match_operand:SWI48 2 "x86_64_general_operand" "re,BM,0,le,re,BM")))
(clobber (reg:CC FLAGS_REG))]
- "ix86_binary_operator_ok (PLUS, <MODE>mode, operands)"
+ "ix86_binary_operator_ok (PLUS, <MODE>mode, operands,
+ ix86_can_use_ndd_p (PLUS))"
{
+ bool use_ndd = (which_alternative == 4 || which_alternative == 5);
switch (get_attr_type (insn))
{
case TYPE_LEA:
return "#";
case TYPE_INCDEC:
- gcc_assert (rtx_equal_p (operands[0], operands[1]));
if (operands[2] == const1_rtx)
- return "inc{<imodesuffix>}\t%0";
+ return use_ndd ? "inc{<imodesuffix>}\t{%1, %0|%0, %1}"
+ : "inc{<imodesuffix>}\t%0";
else
{
gcc_assert (operands[2] == constm1_rtx);
- return "dec{<imodesuffix>}\t%0";
+ return use_ndd ? "dec{<imodesuffix>}\t{%1, %0|%0, %1}"
+ : "dec{<imodesuffix>}\t%0";
}
default:
@@ -6384,14 +6390,16 @@ (define_insn "*add<mode>_1"
if (which_alternative == 2)
std::swap (operands[1], operands[2]);
- gcc_assert (rtx_equal_p (operands[0], operands[1]));
if (x86_maybe_negate_const_int (&operands[2], <MODE>mode))
- return "sub{<imodesuffix>}\t{%2, %0|%0, %2}";
+ return use_ndd ? "sub{<imodesuffix>}\t{%2, %1, %0|%0, %1, %2}"
+ : "sub{<imodesuffix>}\t{%2, %0|%0, %2}";
- return "add{<imodesuffix>}\t{%2, %0|%0, %2}";
+ return use_ndd ? "add{<imodesuffix>}\t{%2, %1, %0|%0, %1, %2}"
+ : "add{<imodesuffix>}\t{%2, %0|%0, %2}";
}
}
- [(set (attr "type")
+ [(set_attr "isa" "*,*,*,*,apx_ndd,apx_ndd")
+ (set (attr "type")
(cond [(eq_attr "alternative" "3")
(const_string "lea")
(match_operand:SWI48 2 "incdec_operand")
@@ -6460,25 +6468,26 @@ (define_insn "addsi_1_zext"
(set_attr "mode" "SI")])
(define_insn "*addhi_1"
- [(set (match_operand:HI 0 "nonimmediate_operand" "=rm,r,r,Yp")
- (plus:HI (match_operand:HI 1 "nonimmediate_operand" "%0,0,r,Yp")
- (match_operand:HI 2 "general_operand" "rn,m,0,ln")))
+ [(set (match_operand:HI 0 "nonimmediate_operand" "=rm,r,r,Yp,r,r")
+ (plus:HI (match_operand:HI 1 "nonimmediate_operand" "%0,0,r,Yp,rm,r")
+ (match_operand:HI 2 "general_operand" "rn,m,0,ln,rn,m")))
(clobber (reg:CC FLAGS_REG))]
- "ix86_binary_operator_ok (PLUS, HImode, operands)"
+ "ix86_binary_operator_ok (PLUS, HImode, operands,
+ ix86_can_use_ndd_p (PLUS))"
{
+ bool use_ndd = (which_alternative == 4 || which_alternative == 5);
switch (get_attr_type (insn))
{
case TYPE_LEA:
return "#";
case TYPE_INCDEC:
- gcc_assert (rtx_equal_p (operands[0], operands[1]));
if (operands[2] == const1_rtx)
- return "inc{w}\t%0";
+ return use_ndd ? "inc{w}\t{%1, %0|%0, %1}" : "inc{w}\t%0";
else
{
gcc_assert (operands[2] == constm1_rtx);
- return "dec{w}\t%0";
+ return use_ndd ? "dec{w}\t{%1, %0|%0, %1}" : "dec{w}\t%0";
}
default:
@@ -6487,14 +6496,16 @@ (define_insn "*addhi_1"
if (which_alternative == 2)
std::swap (operands[1], operands[2]);
- gcc_assert (rtx_equal_p (operands[0], operands[1]));
if (x86_maybe_negate_const_int (&operands[2], HImode))
- return "sub{w}\t{%2, %0|%0, %2}";
+ return use_ndd ? "sub{w}\t{%2, %1, %0|%0, %1, %2}"
+ : "sub{w}\t{%2, %0|%0, %2}";
- return "add{w}\t{%2, %0|%0, %2}";
+ return use_ndd ? "add{w}\t{%2, %1, %0|%0, %1, %2}"
+ : "add{w}\t{%2, %0|%0, %2}";
}
}
- [(set (attr "type")
+ [(set_attr "isa" "*,*,*,*,apx_ndd,apx_ndd")
+ (set (attr "type")
(cond [(eq_attr "alternative" "3")
(const_string "lea")
(match_operand:HI 2 "incdec_operand")
@@ -6506,30 +6517,38 @@ (define_insn "*addhi_1"
(and (eq_attr "type" "alu") (match_operand 2 "const128_operand"))
(const_string "1")
(const_string "*")))
- (set_attr "mode" "HI,HI,HI,SI")])
+ (set_attr "mode" "HI,HI,HI,SI,HI,HI")])
(define_insn "*addqi_1"
- [(set (match_operand:QI 0 "nonimmediate_operand" "=qm,q,q,r,r,Yp")
- (plus:QI (match_operand:QI 1 "nonimmediate_operand" "%0,0,q,0,r,Yp")
- (match_operand:QI 2 "general_operand" "qn,m,0,rn,0,ln")))
+ [(set (match_operand:QI 0 "nonimmediate_operand" "=qm,q,q,r,r,Yp,r,r")
+ (plus:QI (match_operand:QI 1 "nonimmediate_operand" "%0,0,q,0,r,Yp,rm,r")
+ (match_operand:QI 2 "general_operand" "qn,m,0,rn,0,ln,rn,m")))
(clobber (reg:CC FLAGS_REG))]
- "ix86_binary_operator_ok (PLUS, QImode, operands)"
+ "ix86_binary_operator_ok (PLUS, QImode, operands,
+ ix86_can_use_ndd_p (PLUS))"
{
bool widen = (get_attr_mode (insn) != MODE_QI);
-
+ bool use_ndd = (which_alternative == 6 || which_alternative == 7);
switch (get_attr_type (insn))
{
case TYPE_LEA:
return "#";
case TYPE_INCDEC:
- gcc_assert (rtx_equal_p (operands[0], operands[1]));
if (operands[2] == const1_rtx)
- return widen ? "inc{l}\t%k0" : "inc{b}\t%0";
+ if (use_ndd)
+ return widen ? "inc{l}\t{%1, %k0|%k0, %1}"
+ : "inc{b}\t{%1, %0|%0, %1}";
+ else
+ return widen ? "inc{l}\t%k0" : "inc{b}\t%0";
else
{
gcc_assert (operands[2] == constm1_rtx);
- return widen ? "dec{l}\t%k0" : "dec{b}\t%0";
+ if (use_ndd)
+ return widen ? "dec{l}\t{%1, %k0|%k0, %1}"
+ : "dec{b}\t{%1, %0|%0, %1}";
+ else
+ return widen ? "dec{l}\t%k0" : "dec{b}\t%0";
}
default:
@@ -6538,21 +6557,25 @@ (define_insn "*addqi_1"
if (which_alternative == 2 || which_alternative == 4)
std::swap (operands[1], operands[2]);
- gcc_assert (rtx_equal_p (operands[0], operands[1]));
if (x86_maybe_negate_const_int (&operands[2], QImode))
{
- if (widen)
- return "sub{l}\t{%2, %k0|%k0, %2}";
+ if (use_ndd)
+ return widen ? "sub{l}\t{%2, %1, %k0|%k0, %1, %2}"
+ : "sub{b}\t{%2, %1, %0|%0, %1, %2}";
else
- return "sub{b}\t{%2, %0|%0, %2}";
+ return widen ? "sub{l}\t{%2, %k0|%k0, %2}"
+ : "sub{b}\t{%2, %0|%0, %2}";
}
- if (widen)
- return "add{l}\t{%k2, %k0|%k0, %k2}";
+ if (use_ndd)
+ return widen ? "add{l}\t{%k2, %1, %k0|%k0, %1, %k2}"
+ : "add{b}\t{%2, %1, %0|%0, %1, %2}";
else
- return "add{b}\t{%2, %0|%0, %2}";
+ return widen ? "add{l}\t{%k2, %k0|%k0, %k2}"
+ : "add{b}\t{%2, %0|%0, %2}";
}
}
- [(set (attr "type")
+ [(set_attr "isa" "*,*,*,*,*,*,apx_ndd,apx_ndd")
+ (set (attr "type")
(cond [(eq_attr "alternative" "5")
(const_string "lea")
(match_operand:QI 2 "incdec_operand")
@@ -6564,10 +6587,10 @@ (define_insn "*addqi_1"
(and (eq_attr "type" "alu") (match_operand 2 "const128_operand"))
(const_string "1")
(const_string "*")))
- (set_attr "mode" "QI,QI,QI,SI,SI,SI")
+ (set_attr "mode" "QI,QI,QI,SI,SI,SI,SI,SI")
;; Potential partial reg stall on alternatives 3 and 4.
(set (attr "preferred_for_speed")
- (cond [(eq_attr "alternative" "3,4")
+ (cond [(eq_attr "alternative" "3,4,6,7")
(symbol_ref "!TARGET_PARTIAL_REG_STALL")]
(symbol_ref "true")))])
new file mode 100644
@@ -0,0 +1,21 @@
+/* { dg-do compile { target { ! ia32 } } } */
+/* { dg-options "-mapxf -O2" } */
+/* { dg-final { scan-assembler-not "movl"} } */
+
+int foo (int *a)
+{
+ int b = *a - 1;
+ return b;
+}
+
+int foo2 (int a, int b)
+{
+ int c = a + b;
+ return c;
+}
+
+int foo3 (int *a, int b)
+{
+ int c = *a + b;
+ return c;
+}