| ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py |
| ; RUN: llc -mtriple=x86_64-unknown-unknown -mattr=sse2 < %s | FileCheck %s |
| |
| ; PR22428: https://llvm.org/bugs/show_bug.cgi?id=22428 |
| ; f1, f2, f3, and f4 should use an integer logic instruction. |
| ; f5, f6, f9, and f10 should use an FP (SSE) logic instruction. |
| ; |
| ; f7 and f8 are less clear. |
| ; |
| ; For f7 and f8, the SSE instructions don't take immediate operands, so if we |
| ; use one of those, we either have to load a constant from memory or move the |
| ; scalar immediate value from an integer register over to an SSE register. |
| ; Optimizing for size may affect that decision. Also, note that there are no |
| ; scalar versions of the FP logic ops, so if we want to fold a load into a |
| ; logic op, we have to load or splat a 16-byte vector constant. |
| |
| ; 1 FP operand, 1 int operand, int result |
| |
| define i32 @f1(float %x, i32 %y) { |
| ; CHECK-LABEL: f1: |
| ; CHECK: # %bb.0: |
| ; CHECK-NEXT: movd %xmm0, %eax |
| ; CHECK-NEXT: andl %edi, %eax |
| ; CHECK-NEXT: retq |
| %bc1 = bitcast float %x to i32 |
| %and = and i32 %bc1, %y |
| ret i32 %and |
| } |
| |
| ; Swap operands of the logic op. |
| |
| define i32 @f2(float %x, i32 %y) { |
| ; CHECK-LABEL: f2: |
| ; CHECK: # %bb.0: |
| ; CHECK-NEXT: movd %xmm0, %eax |
| ; CHECK-NEXT: andl %edi, %eax |
| ; CHECK-NEXT: retq |
| %bc1 = bitcast float %x to i32 |
| %and = and i32 %y, %bc1 |
| ret i32 %and |
| } |
| |
| ; 1 FP operand, 1 constant operand, int result |
| |
| define i32 @f3(float %x) { |
| ; CHECK-LABEL: f3: |
| ; CHECK: # %bb.0: |
| ; CHECK-NEXT: movd %xmm0, %eax |
| ; CHECK-NEXT: andl $1, %eax |
| ; CHECK-NEXT: retq |
| %bc1 = bitcast float %x to i32 |
| %and = and i32 %bc1, 1 |
| ret i32 %and |
| } |
| |
| ; Swap operands of the logic op. |
| |
| define i32 @f4(float %x) { |
| ; CHECK-LABEL: f4: |
| ; CHECK: # %bb.0: |
| ; CHECK-NEXT: movd %xmm0, %eax |
| ; CHECK-NEXT: andl $2, %eax |
| ; CHECK-NEXT: retq |
| %bc1 = bitcast float %x to i32 |
| %and = and i32 2, %bc1 |
| ret i32 %and |
| } |
| |
| ; 1 FP operand, 1 integer operand, FP result |
| |
| define float @f5(float %x, i32 %y) { |
| ; CHECK-LABEL: f5: |
| ; CHECK: # %bb.0: |
| ; CHECK-NEXT: movd %edi, %xmm1 |
| ; CHECK-NEXT: pand %xmm1, %xmm0 |
| ; CHECK-NEXT: retq |
| %bc1 = bitcast float %x to i32 |
| %and = and i32 %bc1, %y |
| %bc2 = bitcast i32 %and to float |
| ret float %bc2 |
| } |
| |
| ; Swap operands of the logic op. |
| |
| define float @f6(float %x, i32 %y) { |
| ; CHECK-LABEL: f6: |
| ; CHECK: # %bb.0: |
| ; CHECK-NEXT: movd %edi, %xmm1 |
| ; CHECK-NEXT: pand %xmm1, %xmm0 |
| ; CHECK-NEXT: retq |
| %bc1 = bitcast float %x to i32 |
| %and = and i32 %y, %bc1 |
| %bc2 = bitcast i32 %and to float |
| ret float %bc2 |
| } |
| |
| ; 1 FP operand, 1 constant operand, FP result |
| |
| define float @f7(float %x) { |
| ; CHECK-LABEL: f7: |
| ; CHECK: # %bb.0: |
| ; CHECK-NEXT: movss {{.*#+}} xmm1 = mem[0],zero,zero,zero |
| ; CHECK-NEXT: andps %xmm1, %xmm0 |
| ; CHECK-NEXT: retq |
| %bc1 = bitcast float %x to i32 |
| %and = and i32 %bc1, 3 |
| %bc2 = bitcast i32 %and to float |
| ret float %bc2 |
| } |
| |
| ; Swap operands of the logic op. |
| |
| define float @f8(float %x) { |
| ; CHECK-LABEL: f8: |
| ; CHECK: # %bb.0: |
| ; CHECK-NEXT: movss {{.*#+}} xmm1 = mem[0],zero,zero,zero |
| ; CHECK-NEXT: andps %xmm1, %xmm0 |
| ; CHECK-NEXT: retq |
| %bc1 = bitcast float %x to i32 |
| %and = and i32 4, %bc1 |
| %bc2 = bitcast i32 %and to float |
| ret float %bc2 |
| } |
| |
| ; 2 FP operands, int result |
| |
| define i32 @f9(float %x, float %y) { |
| ; CHECK-LABEL: f9: |
| ; CHECK: # %bb.0: |
| ; CHECK-NEXT: pand %xmm1, %xmm0 |
| ; CHECK-NEXT: movd %xmm0, %eax |
| ; CHECK-NEXT: retq |
| %bc1 = bitcast float %x to i32 |
| %bc2 = bitcast float %y to i32 |
| %and = and i32 %bc1, %bc2 |
| ret i32 %and |
| } |
| |
| ; 2 FP operands, FP result |
| |
| define float @f10(float %x, float %y) { |
| ; CHECK-LABEL: f10: |
| ; CHECK: # %bb.0: |
| ; CHECK-NEXT: andps %xmm1, %xmm0 |
| ; CHECK-NEXT: retq |
| %bc1 = bitcast float %x to i32 |
| %bc2 = bitcast float %y to i32 |
| %and = and i32 %bc1, %bc2 |
| %bc3 = bitcast i32 %and to float |
| ret float %bc3 |
| } |
| |
| define float @or(float %x, float %y) { |
| ; CHECK-LABEL: or: |
| ; CHECK: # %bb.0: |
| ; CHECK-NEXT: orps %xmm1, %xmm0 |
| ; CHECK-NEXT: retq |
| %bc1 = bitcast float %x to i32 |
| %bc2 = bitcast float %y to i32 |
| %and = or i32 %bc1, %bc2 |
| %bc3 = bitcast i32 %and to float |
| ret float %bc3 |
| } |
| |
| define float @xor(float %x, float %y) { |
| ; CHECK-LABEL: xor: |
| ; CHECK: # %bb.0: |
| ; CHECK-NEXT: xorps %xmm1, %xmm0 |
| ; CHECK-NEXT: retq |
| %bc1 = bitcast float %x to i32 |
| %bc2 = bitcast float %y to i32 |
| %and = xor i32 %bc1, %bc2 |
| %bc3 = bitcast i32 %and to float |
| ret float %bc3 |
| } |
| |
| define float @f7_or(float %x) { |
| ; CHECK-LABEL: f7_or: |
| ; CHECK: # %bb.0: |
| ; CHECK-NEXT: movss {{.*#+}} xmm1 = mem[0],zero,zero,zero |
| ; CHECK-NEXT: orps %xmm1, %xmm0 |
| ; CHECK-NEXT: retq |
| %bc1 = bitcast float %x to i32 |
| %and = or i32 %bc1, 3 |
| %bc2 = bitcast i32 %and to float |
| ret float %bc2 |
| } |
| |
| define float @f7_xor(float %x) { |
| ; CHECK-LABEL: f7_xor: |
| ; CHECK: # %bb.0: |
| ; CHECK-NEXT: movss {{.*#+}} xmm1 = mem[0],zero,zero,zero |
| ; CHECK-NEXT: xorps %xmm1, %xmm0 |
| ; CHECK-NEXT: retq |
| %bc1 = bitcast float %x to i32 |
| %and = xor i32 %bc1, 3 |
| %bc2 = bitcast i32 %and to float |
| ret float %bc2 |
| } |
| |
| ; Make sure that doubles work too. |
| |
| define double @doubles(double %x, double %y) { |
| ; CHECK-LABEL: doubles: |
| ; CHECK: # %bb.0: |
| ; CHECK-NEXT: andps %xmm1, %xmm0 |
| ; CHECK-NEXT: retq |
| %bc1 = bitcast double %x to i64 |
| %bc2 = bitcast double %y to i64 |
| %and = and i64 %bc1, %bc2 |
| %bc3 = bitcast i64 %and to double |
| ret double %bc3 |
| } |
| |
| define double @f7_double(double %x) { |
| ; CHECK-LABEL: f7_double: |
| ; CHECK: # %bb.0: |
| ; CHECK-NEXT: movsd {{.*#+}} xmm1 = mem[0],zero |
| ; CHECK-NEXT: andps %xmm1, %xmm0 |
| ; CHECK-NEXT: retq |
| %bc1 = bitcast double %x to i64 |
| %and = and i64 %bc1, 3 |
| %bc2 = bitcast i64 %and to double |
| ret double %bc2 |
| } |
| |
| ; Grabbing the sign bit is a special case that could be handled |
| ; by movmskps/movmskpd, but if we're not shifting it over, then |
| ; a simple FP logic op is cheaper. |
| |
| define float @movmsk(float %x) { |
| ; CHECK-LABEL: movmsk: |
| ; CHECK: # %bb.0: |
| ; CHECK-NEXT: movss {{.*#+}} xmm1 = mem[0],zero,zero,zero |
| ; CHECK-NEXT: andps %xmm1, %xmm0 |
| ; CHECK-NEXT: retq |
| %bc1 = bitcast float %x to i32 |
| %and = and i32 %bc1, 2147483648 |
| %bc2 = bitcast i32 %and to float |
| ret float %bc2 |
| } |
| |
| define double @bitcast_fabs(double %x) { |
| ; CHECK-LABEL: bitcast_fabs: |
| ; CHECK: # %bb.0: |
| ; CHECK-NEXT: andps {{.*}}(%rip), %xmm0 |
| ; CHECK-NEXT: retq |
| %bc1 = bitcast double %x to i64 |
| %and = and i64 %bc1, 9223372036854775807 |
| %bc2 = bitcast i64 %and to double |
| ret double %bc2 |
| } |
| |
| define float @bitcast_fneg(float %x) { |
| ; CHECK-LABEL: bitcast_fneg: |
| ; CHECK: # %bb.0: |
| ; CHECK-NEXT: xorps {{.*}}(%rip), %xmm0 |
| ; CHECK-NEXT: retq |
| %bc1 = bitcast float %x to i32 |
| %xor = xor i32 %bc1, 2147483648 |
| %bc2 = bitcast i32 %xor to float |
| ret float %bc2 |
| } |
| |
| define <2 x double> @bitcast_fabs_vec(<2 x double> %x) { |
| ; CHECK-LABEL: bitcast_fabs_vec: |
| ; CHECK: # %bb.0: |
| ; CHECK-NEXT: andps {{.*}}(%rip), %xmm0 |
| ; CHECK-NEXT: retq |
| %bc1 = bitcast <2 x double> %x to <2 x i64> |
| %and = and <2 x i64> %bc1, <i64 9223372036854775807, i64 9223372036854775807> |
| %bc2 = bitcast <2 x i64> %and to <2 x double> |
| ret <2 x double> %bc2 |
| } |
| |
| define <4 x float> @bitcast_fneg_vec(<4 x float> %x) { |
| ; CHECK-LABEL: bitcast_fneg_vec: |
| ; CHECK: # %bb.0: |
| ; CHECK-NEXT: xorps {{.*}}(%rip), %xmm0 |
| ; CHECK-NEXT: retq |
| %bc1 = bitcast <4 x float> %x to <4 x i32> |
| %xor = xor <4 x i32> %bc1, <i32 2147483648, i32 2147483648, i32 2147483648, i32 2147483648> |
| %bc2 = bitcast <4 x i32> %xor to <4 x float> |
| ret <4 x float> %bc2 |
| } |
| |