[RISCV] Add isel patterns for ANDN/ORN/XNOR with P+Zbb. (#175384)
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoP.td b/llvm/lib/Target/RISCV/RISCVInstrInfoP.td index f2aeacd..d42ab93 100644 --- a/llvm/lib/Target/RISCV/RISCVInstrInfoP.td +++ b/llvm/lib/Target/RISCV/RISCVInstrInfoP.td
@@ -1497,12 +1497,22 @@ def: Pat<(XLenVecI8VT (or GPR:$rs1, GPR:$rs2)), (OR GPR:$rs1, GPR:$rs2)>; def: Pat<(XLenVecI8VT (xor GPR:$rs1, GPR:$rs2)), (XOR GPR:$rs1, GPR:$rs2)>; def: Pat<(XLenVecI8VT (vnot GPR:$rs1)), (XORI GPR:$rs1, -1)>; + let Predicates = [HasStdExtP, HasStdExtZbbOrZbkb] in { + def: Pat<(XLenVecI8VT (and GPR:$rs1, (vnot GPR:$rs2))), (ANDN GPR:$rs1, GPR:$rs2)>; + def: Pat<(XLenVecI8VT (or GPR:$rs1, (vnot GPR:$rs2))), (ORN GPR:$rs1, GPR:$rs2)>; + def: Pat<(XLenVecI8VT (vnot (xor GPR:$rs1, GPR:$rs2))), (XNOR GPR:$rs1, GPR:$rs2)>; + } // 16-bit bitwise operation patterns def: Pat<(XLenVecI16VT (and GPR:$rs1, GPR:$rs2)), (AND GPR:$rs1, GPR:$rs2)>; def: Pat<(XLenVecI16VT (or GPR:$rs1, GPR:$rs2)), (OR GPR:$rs1, GPR:$rs2)>; def: Pat<(XLenVecI16VT (xor GPR:$rs1, GPR:$rs2)), (XOR GPR:$rs1, GPR:$rs2)>; def: Pat<(XLenVecI16VT (vnot GPR:$rs1)), (XORI GPR:$rs1, -1)>; + let Predicates = [HasStdExtP, HasStdExtZbbOrZbkb] in { + def: Pat<(XLenVecI16VT (and GPR:$rs1, (vnot GPR:$rs2))), (ANDN GPR:$rs1, GPR:$rs2)>; + def: Pat<(XLenVecI16VT (or GPR:$rs1, (vnot GPR:$rs2))), (ORN GPR:$rs1, GPR:$rs2)>; + def: Pat<(XLenVecI16VT (vnot (xor GPR:$rs1, GPR:$rs2))), (XNOR GPR:$rs1, GPR:$rs2)>; + } // 8-bit saturating add/sub patterns def: Pat<(XLenVecI8VT (saddsat GPR:$rs1, GPR:$rs2)), (PSADD_B GPR:$rs1, GPR:$rs2)>; @@ -1662,6 +1672,11 @@ def: Pat<(v2i32 (or GPR:$rs1, GPR:$rs2)), (OR GPR:$rs1, GPR:$rs2)>; def: Pat<(v2i32 (xor GPR:$rs1, GPR:$rs2)), (XOR GPR:$rs1, GPR:$rs2)>; def: Pat<(v2i32 (vnot GPR:$rs1)), (XORI GPR:$rs1, -1)>; + let Predicates = [HasStdExtP, HasStdExtZbbOrZbkb] in { + def: Pat<(v2i32 (and GPR:$rs1, (vnot GPR:$rs2))), (ANDN GPR:$rs1, GPR:$rs2)>; + def: Pat<(v2i32 (or GPR:$rs1, (vnot GPR:$rs2))), (ORN GPR:$rs1, GPR:$rs2)>; + def: Pat<(v2i32 (vnot (xor GPR:$rs1, GPR:$rs2))), (XNOR GPR:$rs1, GPR:$rs2)>; + } // 32-bit saturating add/sub patterns def: Pat<(v2i32 (saddsat GPR:$rs1, GPR:$rs2)), (PSADD_W GPR:$rs1, GPR:$rs2)>;
diff --git a/llvm/test/CodeGen/RISCV/rvp-ext-rv32.ll b/llvm/test/CodeGen/RISCV/rvp-ext-rv32.ll index ba9aa18..1222617 100644 --- a/llvm/test/CodeGen/RISCV/rvp-ext-rv32.ll +++ b/llvm/test/CodeGen/RISCV/rvp-ext-rv32.ll
@@ -114,6 +114,64 @@ ret void } +define void @test_andn_h(ptr %ret_ptr, ptr %a_ptr, ptr %b_ptr) { +; CHECK-LABEL: test_andn_h: +; CHECK: # %bb.0: +; CHECK-NEXT: lw a1, 0(a1) +; CHECK-NEXT: lw a2, 0(a2) +; CHECK-NEXT: andn a1, a1, a2 +; CHECK-NEXT: sw a1, 0(a0) +; CHECK-NEXT: ret + %a = load <2 x i16>, ptr %a_ptr + %b = load <2 x i16>, ptr %b_ptr + %not = xor <2 x i16> %b, splat (i16 -1) + %res = and <2 x i16> %a, %not + store <2 x i16> %res, ptr %ret_ptr + ret void +} + +define void @test_orn_h(ptr %ret_ptr, ptr %a_ptr, ptr %b_ptr) { +; CHECK-LABEL: test_orn_h: +; CHECK: # %bb.0: +; CHECK-NEXT: lw a1, 0(a1) +; CHECK-NEXT: lw a2, 0(a2) +; CHECK-NEXT: orn a1, a1, a2 +; CHECK-NEXT: sw a1, 0(a0) +; CHECK-NEXT: ret + %a = load <2 x i16>, ptr %a_ptr + %b = load <2 x i16>, ptr %b_ptr + %not = xor <2 x i16> %b, splat (i16 -1) + %res = or <2 x i16> %a, %not + store <2 x i16> %res, ptr %ret_ptr + ret void +} + +; FIXME: A bitcast is getting in the way on RV64. +define void @test_xnor_h(ptr %ret_ptr, ptr %a_ptr, ptr %b_ptr) { +; CHECK-RV32-LABEL: test_xnor_h: +; CHECK-RV32: # %bb.0: +; CHECK-RV32-NEXT: lw a1, 0(a1) +; CHECK-RV32-NEXT: lw a2, 0(a2) +; CHECK-RV32-NEXT: xnor a1, a2, a1 +; CHECK-RV32-NEXT: sw a1, 0(a0) +; CHECK-RV32-NEXT: ret +; +; CHECK-RV64-LABEL: test_xnor_h: +; CHECK-RV64: # %bb.0: +; CHECK-RV64-NEXT: lw a1, 0(a1) +; CHECK-RV64-NEXT: lw a2, 0(a2) +; CHECK-RV64-NEXT: xor a1, a2, a1 +; CHECK-RV64-NEXT: not a1, a1 +; CHECK-RV64-NEXT: sw a1, 0(a0) +; CHECK-RV64-NEXT: ret + %a = load <2 x i16>, ptr %a_ptr + %b = load <2 x i16>, ptr %b_ptr + %not = xor <2 x i16> %b, splat (i16 -1) + %res = xor <2 x i16> %a, %not + store <2 x i16> %res, ptr %ret_ptr + ret void +} + ; Test bitwise operations for v4i8 (use scalar instructions) define void @test_and_b(ptr %ret_ptr, ptr %a_ptr, ptr %b_ptr) { ; CHECK-LABEL: test_and_b: @@ -160,6 +218,64 @@ ret void } +define void @test_andn_b(ptr %ret_ptr, ptr %a_ptr, ptr %b_ptr) { +; CHECK-LABEL: test_andn_b: +; CHECK: # %bb.0: +; CHECK-NEXT: lw a1, 0(a1) +; CHECK-NEXT: lw a2, 0(a2) +; CHECK-NEXT: andn a1, a1, a2 +; CHECK-NEXT: sw a1, 0(a0) +; CHECK-NEXT: ret + %a = load <4 x i8>, ptr %a_ptr + %b = load <4 x i8>, ptr %b_ptr + %not = xor <4 x i8> %b, splat (i8 -1) + %res = and <4 x i8> %a, %not + store <4 x i8> %res, ptr %ret_ptr + ret void +} + +define void @test_orn_b(ptr %ret_ptr, ptr %a_ptr, ptr %b_ptr) { +; CHECK-LABEL: test_orn_b: +; CHECK: # %bb.0: +; CHECK-NEXT: lw a1, 0(a1) +; CHECK-NEXT: lw a2, 0(a2) +; CHECK-NEXT: orn a1, a1, a2 +; CHECK-NEXT: sw a1, 0(a0) +; CHECK-NEXT: ret + %a = load <4 x i8>, ptr %a_ptr + %b = load <4 x i8>, ptr %b_ptr + %not = xor <4 x i8> %b, splat (i8 -1) + %res = or <4 x i8> %a, %not + store <4 x i8> %res, ptr %ret_ptr + ret void +} + +; FIXME: A bitcast is getting in the way on RV64. +define void @test_xnor_b(ptr %ret_ptr, ptr %a_ptr, ptr %b_ptr) { +; CHECK-RV32-LABEL: test_xnor_b: +; CHECK-RV32: # %bb.0: +; CHECK-RV32-NEXT: lw a1, 0(a1) +; CHECK-RV32-NEXT: lw a2, 0(a2) +; CHECK-RV32-NEXT: xnor a1, a2, a1 +; CHECK-RV32-NEXT: sw a1, 0(a0) +; CHECK-RV32-NEXT: ret +; +; CHECK-RV64-LABEL: test_xnor_b: +; CHECK-RV64: # %bb.0: +; CHECK-RV64-NEXT: lw a1, 0(a1) +; CHECK-RV64-NEXT: lw a2, 0(a2) +; CHECK-RV64-NEXT: xor a1, a2, a1 +; CHECK-RV64-NEXT: not a1, a1 +; CHECK-RV64-NEXT: sw a1, 0(a0) +; CHECK-RV64-NEXT: ret + %a = load <4 x i8>, ptr %a_ptr + %b = load <4 x i8>, ptr %b_ptr + %not = xor <4 x i8> %b, splat (i8 -1) + %res = xor <4 x i8> %a, %not + store <4 x i8> %res, ptr %ret_ptr + ret void +} + define void @test_not_h(ptr %ret_ptr, ptr %a_ptr) { ; CHECK-LABEL: test_not_h: ; CHECK: # %bb.0:
diff --git a/llvm/test/CodeGen/RISCV/rvp-ext-rv64.ll b/llvm/test/CodeGen/RISCV/rvp-ext-rv64.ll index ba04c95..df6db52 100644 --- a/llvm/test/CodeGen/RISCV/rvp-ext-rv64.ll +++ b/llvm/test/CodeGen/RISCV/rvp-ext-rv64.ll
@@ -111,6 +111,54 @@ ret void } +define void @test_andn_h(ptr %ret_ptr, ptr %a_ptr, ptr %b_ptr) { +; CHECK-LABEL: test_andn_h: +; CHECK: # %bb.0: +; CHECK-NEXT: ld a1, 0(a1) +; CHECK-NEXT: ld a2, 0(a2) +; CHECK-NEXT: andn a1, a1, a2 +; CHECK-NEXT: sd a1, 0(a0) +; CHECK-NEXT: ret + %a = load <4 x i16>, ptr %a_ptr + %b = load <4 x i16>, ptr %b_ptr + %not = xor <4 x i16> %b, splat (i16 -1) + %res = and <4 x i16> %a, %not + store <4 x i16> %res, ptr %ret_ptr + ret void +} + +define void @test_orn_h(ptr %ret_ptr, ptr %a_ptr, ptr %b_ptr) { +; CHECK-LABEL: test_orn_h: +; CHECK: # %bb.0: +; CHECK-NEXT: ld a1, 0(a1) +; CHECK-NEXT: ld a2, 0(a2) +; CHECK-NEXT: orn a1, a1, a2 +; CHECK-NEXT: sd a1, 0(a0) +; CHECK-NEXT: ret + %a = load <4 x i16>, ptr %a_ptr + %b = load <4 x i16>, ptr %b_ptr + %not = xor <4 x i16> %b, splat (i16 -1) + %res = or <4 x i16> %a, %not + store <4 x i16> %res, ptr %ret_ptr + ret void +} + +define void @test_xnor_h(ptr %ret_ptr, ptr %a_ptr, ptr %b_ptr) { +; CHECK-LABEL: test_xnor_h: +; CHECK: # %bb.0: +; CHECK-NEXT: ld a1, 0(a1) +; CHECK-NEXT: ld a2, 0(a2) +; CHECK-NEXT: xnor a1, a2, a1 +; CHECK-NEXT: sd a1, 0(a0) +; CHECK-NEXT: ret + %a = load <4 x i16>, ptr %a_ptr + %b = load <4 x i16>, ptr %b_ptr + %not = xor <4 x i16> %b, splat (i16 -1) + %res = xor <4 x i16> %a, %not + store <4 x i16> %res, ptr %ret_ptr + ret void +} + ; Test bitwise operations for v8i8 (use scalar instructions) define void @test_and_b(ptr %ret_ptr, ptr %a_ptr, ptr %b_ptr) { ; CHECK-LABEL: test_and_b: @@ -157,6 +205,54 @@ ret void } +define void @test_andn_b(ptr %ret_ptr, ptr %a_ptr, ptr %b_ptr) { +; CHECK-LABEL: test_andn_b: +; CHECK: # %bb.0: +; CHECK-NEXT: ld a1, 0(a1) +; CHECK-NEXT: ld a2, 0(a2) +; CHECK-NEXT: andn a1, a1, a2 +; CHECK-NEXT: sd a1, 0(a0) +; CHECK-NEXT: ret + %a = load <8 x i8>, ptr %a_ptr + %b = load <8 x i8>, ptr %b_ptr + %not = xor <8 x i8> %b, splat (i8 -1) + %res = and <8 x i8> %a, %not + store <8 x i8> %res, ptr %ret_ptr + ret void +} + +define void @test_orn_b(ptr %ret_ptr, ptr %a_ptr, ptr %b_ptr) { +; CHECK-LABEL: test_orn_b: +; CHECK: # %bb.0: +; CHECK-NEXT: ld a1, 0(a1) +; CHECK-NEXT: ld a2, 0(a2) +; CHECK-NEXT: orn a1, a1, a2 +; CHECK-NEXT: sd a1, 0(a0) +; CHECK-NEXT: ret + %a = load <8 x i8>, ptr %a_ptr + %b = load <8 x i8>, ptr %b_ptr + %not = xor <8 x i8> %b, splat (i8 -1) + %res = or <8 x i8> %a, %not + store <8 x i8> %res, ptr %ret_ptr + ret void +} + +define void @test_xnor_b(ptr %ret_ptr, ptr %a_ptr, ptr %b_ptr) { +; CHECK-LABEL: test_xnor_b: +; CHECK: # %bb.0: +; CHECK-NEXT: ld a1, 0(a1) +; CHECK-NEXT: ld a2, 0(a2) +; CHECK-NEXT: xnor a1, a2, a1 +; CHECK-NEXT: sd a1, 0(a0) +; CHECK-NEXT: ret + %a = load <8 x i8>, ptr %a_ptr + %b = load <8 x i8>, ptr %b_ptr + %not = xor <8 x i8> %b, splat (i8 -1) + %res = xor <8 x i8> %a, %not + store <8 x i8> %res, ptr %ret_ptr + ret void +} + ; Test bitwise operations for v2i32 (use scalar instructions) define void @test_and_w(ptr %ret_ptr, ptr %a_ptr, ptr %b_ptr) { ; CHECK-LABEL: test_and_w: @@ -203,6 +299,54 @@ ret void } +define void @test_andn_w(ptr %ret_ptr, ptr %a_ptr, ptr %b_ptr) { +; CHECK-LABEL: test_andn_w: +; CHECK: # %bb.0: +; CHECK-NEXT: ld a1, 0(a1) +; CHECK-NEXT: ld a2, 0(a2) +; CHECK-NEXT: andn a1, a1, a2 +; CHECK-NEXT: sd a1, 0(a0) +; CHECK-NEXT: ret + %a = load <2 x i32>, ptr %a_ptr + %b = load <2 x i32>, ptr %b_ptr + %not = xor <2 x i32> %b, splat (i32 -1) + %res = and <2 x i32> %a, %not + store <2 x i32> %res, ptr %ret_ptr + ret void +} + +define void @test_orn_w(ptr %ret_ptr, ptr %a_ptr, ptr %b_ptr) { +; CHECK-LABEL: test_orn_w: +; CHECK: # %bb.0: +; CHECK-NEXT: ld a1, 0(a1) +; CHECK-NEXT: ld a2, 0(a2) +; CHECK-NEXT: orn a1, a1, a2 +; CHECK-NEXT: sd a1, 0(a0) +; CHECK-NEXT: ret + %a = load <2 x i32>, ptr %a_ptr + %b = load <2 x i32>, ptr %b_ptr + %not = xor <2 x i32> %b, splat (i32 -1) + %res = or <2 x i32> %a, %not + store <2 x i32> %res, ptr %ret_ptr + ret void +} + +define void @test_xnor_w(ptr %ret_ptr, ptr %a_ptr, ptr %b_ptr) { +; CHECK-LABEL: test_xnor_w: +; CHECK: # %bb.0: +; CHECK-NEXT: ld a1, 0(a1) +; CHECK-NEXT: ld a2, 0(a2) +; CHECK-NEXT: xnor a1, a2, a1 +; CHECK-NEXT: sd a1, 0(a0) +; CHECK-NEXT: ret + %a = load <2 x i32>, ptr %a_ptr + %b = load <2 x i32>, ptr %b_ptr + %not = xor <2 x i32> %b, splat (i32 -1) + %res = xor <2 x i32> %a, %not + store <2 x i32> %res, ptr %ret_ptr + ret void +} + define void @test_not_h(ptr %ret_ptr, ptr %a_ptr) { ; CHECK-LABEL: test_not_h: ; CHECK: # %bb.0: