(set_attr "znver1_decode" "double")
(set_attr "mode" "DI")])
+;; PR target/94790: Optimize a ^ ((a ^ b) & mask) to (~mask & a) | (b & mask)
+(define_insn_and_split "*xor2andn"
+ [(set (match_operand:SWI248 0 "nonimmediate_operand")
+ (xor:SWI248
+ (and:SWI248
+ (xor:SWI248
+ (match_operand:SWI248 1 "nonimmediate_operand")
+ (match_operand:SWI248 2 "nonimmediate_operand"))
+ (match_operand:SWI248 3 "nonimmediate_operand"))
+ (match_dup 1)))
+ (clobber (reg:CC FLAGS_REG))]
+ "(TARGET_BMI || TARGET_AVX512BW)
+ && ix86_pre_reload_split ()"
+ "#"
+ "&& 1"
+ [(parallel [(set (match_dup 4)
+ (and:SWI248
+ (not:SWI248
+ (match_dup 3))
+ (match_dup 1)))
+ (clobber (reg:CC FLAGS_REG))])
+ (parallel [(set (match_dup 5)
+ (and:SWI248
+ (match_dup 2)
+ (match_dup 3)))
+ (clobber (reg:CC FLAGS_REG))])
+ (parallel [(set (match_dup 0)
+ (ior:SWI248
+ (match_dup 4)
+ (match_dup 5)))
+ (clobber (reg:CC FLAGS_REG))])]
+{
+ operands[1] = force_reg (<MODE>mode, operands[1]);
+ operands[3] = force_reg (<MODE>mode, operands[3]);
+ operands[4] = gen_reg_rtx (<MODE>mode);
+ operands[5] = gen_reg_rtx (<MODE>mode);
+})
+
;; See comment for addsi_1_zext why we do use nonimmediate_operand
(define_insn "*<code>si_1_zext"
[(set (match_operand:DI 0 "register_operand" "=r")
--- /dev/null
+/* { dg-do compile } */
+/* { dg-options "-O2 -mbmi" } */
+/* { dg-final { scan-assembler-times "andn\[ \\t\]" 2 } } */
+/* { dg-final { scan-assembler-not "xorl\[ \\t\]" } } */
+
+unsigned r1(unsigned a, unsigned b, unsigned mask)
+{
+ return a ^ ((a ^ b) & mask);
+}
+
+unsigned r2(unsigned a, unsigned b, unsigned mask)
+{
+ return (~mask & a) | (b & mask);
+}
--- /dev/null
+/* { dg-do compile } */
+/* { dg-options "-O2 -mbmi" } */
+/* { dg-final { scan-assembler-not "andn\[ \\t\]" } } */
+/* { dg-final { scan-assembler-times "xorl\[ \\t\]" 2 } } */
+
+unsigned r1(unsigned a, unsigned b, unsigned mask)
+{
+ return a ^ ((a ^ b) & mask) + (a ^ b);
+}