Index: llvm/trunk/lib/Target/WebAssembly/WebAssemblyInstrSIMD.td =================================================================== --- llvm/trunk/lib/Target/WebAssembly/WebAssemblyInstrSIMD.td +++ llvm/trunk/lib/Target/WebAssembly/WebAssemblyInstrSIMD.td @@ -549,6 +549,11 @@ defm XOR : SIMDBitwise; } // isCommutable = 1 +// Bitwise logic: v128.andnot +def andnot : PatFrag<(ops node:$left, node:$right), (and $left, (vnot $right))>; +let Predicates = [HasUnimplementedSIMD128] in +defm ANDNOT : SIMDBitwise; + // Bitwise select: v128.bitselect foreach vec_t = [v16i8, v8i16, v4i32, v2i64, v4f32, v2f64] in defm BITSELECT_#vec_t : Index: llvm/trunk/test/CodeGen/WebAssembly/simd-arith.ll =================================================================== --- llvm/trunk/test/CodeGen/WebAssembly/simd-arith.ll +++ llvm/trunk/test/CodeGen/WebAssembly/simd-arith.ll @@ -223,6 +223,23 @@ ret <16 x i8> %a } +; CHECK-LABEL: andnot_v16i8: +; NO-SIMD128-NOT: v128 +; SIMD128-VM-NOT: v128.andnot +; SIMD128-NEXT: .functype andnot_v16i8 (v128, v128) -> (v128){{$}} +; SIMD128-SLOW-NEXT: v128.andnot $push[[R:[0-9]+]]=, $0, $1{{$}} +; SIMD128-SLOW-NEXT: return $pop[[R]]{{$}} +; SIMD128-FAST-NEXT: v128.not +; SIMD128-FAST-NEXT: v128.and +; SIMD128-FAST-NEXT: return +define <16 x i8> @andnot_v16i8(<16 x i8> %x, <16 x i8> %y) { + %inv_y = xor <16 x i8> %y, + + %a = and <16 x i8> %x, %inv_y + ret <16 x i8> %a +} + ; CHECK-LABEL: bitselect_v16i8: ; NO-SIMD128-NOT: v128 ; SIMD128-NEXT: .functype bitselect_v16i8 (v128, v128, v128) -> (v128){{$}} @@ -445,6 +462,22 @@ ret <8 x i16> %a } +; CHECK-LABEL: andnot_v8i16: +; SIMD128-VM-NOT: v128.andnot +; NO-SIMD128-NOT: v128 +; SIMD128-NEXT: .functype andnot_v8i16 (v128, v128) -> (v128){{$}} +; SIMD128-SLOW-NEXT: v128.andnot $push[[R:[0-9]+]]=, $0, $1{{$}} +; SIMD128-SLOW-NEXT: return $pop[[R]]{{$}} +; SIMD128-FAST-NEXT: v128.not +; SIMD128-FAST-NEXT: v128.and +; SIMD128-FAST-NEXT: return +define <8 x i16> @andnot_v8i16(<8 x i16> %x, <8 x i16> %y) { + %inv_y = xor <8 x i16> %y, + + %a = and <8 x i16> %x, %inv_y + ret <8 x i16> %a +} + ; CHECK-LABEL: bitselect_v8i16: ; NO-SIMD128-NOT: v128 ; SIMD128-NEXT: .functype bitselect_v8i16 (v128, v128, v128) -> (v128){{$}} @@ -652,6 +685,21 @@ ret <4 x i32> %a } +; CHECK-LABEL: andnot_v4i32: +; SIMD128-VM-NOT: v128.andnot +; NO-SIMD128-NOT: v128 +; SIMD128-NEXT: .functype andnot_v4i32 (v128, v128) -> (v128){{$}} +; SIMD128-SLOW-NEXT: v128.andnot $push[[R:[0-9]+]]=, $0, $1{{$}} +; SIMD128-SLOW-NEXT: return $pop[[R]]{{$}} +; SIMD128-FAST-NEXT: v128.not +; SIMD128-FAST-NEXT: v128.and +; SIMD128-FAST-NEXT: return +define <4 x i32> @andnot_v4i32(<4 x i32> %x, <4 x i32> %y) { + %inv_y = xor <4 x i32> %y, + %a = and <4 x i32> %x, %inv_y + ret <4 x i32> %a +} + ; CHECK-LABEL: bitselect_v4i32: ; NO-SIMD128-NOT: v128 ; SIMD128-NEXT: .functype bitselect_v4i32 (v128, v128, v128) -> (v128){{$}} @@ -962,6 +1010,21 @@ ret <2 x i64> %a } +; CHECK-LABEL: andnot_v2i64: +; SIMD128-VM-NOT: v128.andnot +; NO-SIMD128-NOT: v128 +; SIMD128-NEXT: .functype andnot_v2i64 (v128, v128) -> (v128){{$}} +; SIMD128-SLOW-NEXT: v128.andnot $push[[R:[0-9]+]]=, $0, $1{{$}} +; SIMD128-SLOW-NEXT: return $pop[[R]]{{$}} +; SIMD128-FAST-NEXT: v128.not +; SIMD128-FAST-NEXT: v128.and +; SIMD128-FAST-NEXT: return +define <2 x i64> @andnot_v2i64(<2 x i64> %x, <2 x i64> %y) { + %inv_y = xor <2 x i64> %y, + %a = and <2 x i64> %x, %inv_y + ret <2 x i64> %a +} + ; CHECK-LABEL: bitselect_v2i64: ; NO-SIMD128-NOT: v128 ; SIMD128-VM-NOT: v128 Index: llvm/trunk/test/MC/WebAssembly/simd-encodings.s =================================================================== --- llvm/trunk/test/MC/WebAssembly/simd-encodings.s +++ llvm/trunk/test/MC/WebAssembly/simd-encodings.s @@ -529,4 +529,7 @@ # CHECK: i64x2.load32x2_u 32 # encoding: [0xfd,0xd7,0x01,0x03,0x20] i64x2.load32x2_u 32 + # CHECK: v128.andnot # encoding: [0xfd,0xd8,0x01] + v128.andnot + end_function