| ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py |
| ; RUN: opt < %s -passes=instcombine -S | FileCheck %s |
| |
| declare i8 @use8(i8) |
| declare i16 @use16(i16) |
| declare i32 @use32(i32) |
| declare i64 @use64(i64) |
| declare i128 @use128(i128) |
| declare i130 @use130(i130) |
| declare <2 x i8> @use_v2i8(<2 x i8>) |
| |
| ; The following 16 cases are used for cover the commuted operand ADD and MUL |
| ; with extra uses to more of these tests to exercise those cases. |
| ; The different _Ax suffix hints the variety of combinations MUL |
| ; The different _Bx suffix hints the variety of combinations ADD |
| ; 4 tests that use in0/in1 with different commutes |
| define i8 @mul8_low_A0_B0(i8 %in0, i8 %in1) { |
| ; CHECK-LABEL: @mul8_low_A0_B0( |
| ; CHECK-NEXT: [[RETLO:%.*]] = mul i8 [[IN0:%.*]], [[IN1:%.*]] |
| ; CHECK-NEXT: ret i8 [[RETLO]] |
| ; |
| %In0Lo = and i8 %in0, 15 |
| %In0Hi = lshr i8 %in0, 4 |
| %In1Lo = and i8 %in1, 15 |
| %In1Hi = lshr i8 %in1, 4 |
| %m10 = mul i8 %In1Hi, %in0 |
| %m01 = mul i8 %In0Hi, %in1 |
| %m00 = mul i8 %In1Lo, %In0Lo |
| %addc = add i8 %m10, %m01 |
| %shl = shl i8 %addc, 4 |
| %retLo = add i8 %shl, %m00 |
| ret i8 %retLo |
| } |
| |
| define i8 @mul8_low_A0_B1(i8 %p, i8 %in1) { |
| ; CHECK-LABEL: @mul8_low_A0_B1( |
| ; CHECK-NEXT: [[IN0:%.*]] = call i8 @use8(i8 [[P:%.*]]) |
| ; CHECK-NEXT: [[RETLO:%.*]] = mul i8 [[IN0]], [[IN1:%.*]] |
| ; CHECK-NEXT: ret i8 [[RETLO]] |
| ; |
| %in0 = call i8 @use8(i8 %p) ; thwart complexity-based canonicalization |
| %In0Lo = and i8 %in0, 15 |
| %In0Hi = lshr i8 %in0, 4 |
| %In1Lo = and i8 %in1, 15 |
| %In1Hi = lshr i8 %in1, 4 |
| %m10 = mul i8 %in0, %In1Hi |
| %m01 = mul i8 %In0Hi, %in1 |
| %m00 = mul i8 %In1Lo, %In0Lo |
| %addc = add i8 %m10, %m01 |
| %shl = shl i8 %addc, 4 |
| %retLo = add i8 %m00, %shl |
| ret i8 %retLo |
| } |
| |
| define i8 @mul8_low_A0_B2(i8 %in0, i8 %p) { |
| ; CHECK-LABEL: @mul8_low_A0_B2( |
| ; CHECK-NEXT: [[IN1:%.*]] = call i8 @use8(i8 [[P:%.*]]) |
| ; CHECK-NEXT: [[RETLO:%.*]] = mul i8 [[IN0:%.*]], [[IN1]] |
| ; CHECK-NEXT: ret i8 [[RETLO]] |
| ; |
| |
| %in1 = call i8 @use8(i8 %p) ; thwart complexity-based canonicalization |
| %In0Lo = and i8 %in0, 15 |
| %In0Hi = lshr i8 %in0, 4 |
| %In1Lo = and i8 %in1, 15 |
| %In1Hi = lshr i8 %in1, 4 |
| %m10 = mul i8 %In1Hi, %in0 |
| %m01 = mul i8 %in1, %In0Hi |
| %m00 = mul i8 %In1Lo, %In0Lo |
| %addc = add i8 %m01, %m10 |
| %shl = shl i8 %addc, 4 |
| %retLo = add i8 %shl, %m00 |
| ret i8 %retLo |
| } |
| |
| define i8 @mul8_low_A0_B3(i8 %p, i8 %q) { |
| ; CHECK-LABEL: @mul8_low_A0_B3( |
| ; CHECK-NEXT: [[IN0:%.*]] = call i8 @use8(i8 [[P:%.*]]) |
| ; CHECK-NEXT: [[IN1:%.*]] = call i8 @use8(i8 [[Q:%.*]]) |
| ; CHECK-NEXT: [[RETLO:%.*]] = mul i8 [[IN0]], [[IN1]] |
| ; CHECK-NEXT: ret i8 [[RETLO]] |
| ; |
| %in0 = call i8 @use8(i8 %p) ; thwart complexity-based canonicalization |
| %in1 = call i8 @use8(i8 %q) ; thwart complexity-based canonicalization |
| %In0Lo = and i8 %in0, 15 |
| %In0Hi = lshr i8 %in0, 4 |
| %In1Lo = and i8 %in1, 15 |
| %In1Hi = lshr i8 %in1, 4 |
| %m10 = mul i8 %in0, %In1Hi |
| %m01 = mul i8 %in1, %In0Hi |
| %m00 = mul i8 %In1Lo, %In0Lo |
| %addc = add i8 %m01, %m10 |
| %shl = shl i8 %addc, 4 |
| %retLo = add i8 %m00, %shl |
| ret i8 %retLo |
| } |
| |
| ; 4 tests that use In0Lo/In1Lo with different commutes |
| define i16 @mul16_low_A1_B0(i16 %in0, i16 %in1) { |
| ; CHECK-LABEL: @mul16_low_A1_B0( |
| ; CHECK-NEXT: [[IN0LO:%.*]] = and i16 [[IN0:%.*]], 255 |
| ; CHECK-NEXT: [[IN0HI:%.*]] = lshr i16 [[IN0]], 8 |
| ; CHECK-NEXT: [[IN1LO:%.*]] = and i16 [[IN1:%.*]], 255 |
| ; CHECK-NEXT: [[IN1HI:%.*]] = lshr i16 [[IN1]], 8 |
| ; CHECK-NEXT: [[M10:%.*]] = mul nuw i16 [[IN0LO]], [[IN1HI]] |
| ; CHECK-NEXT: call void @use16(i16 [[M10]]) |
| ; CHECK-NEXT: [[M01:%.*]] = mul nuw i16 [[IN1LO]], [[IN0HI]] |
| ; CHECK-NEXT: call void @use16(i16 [[M01]]) |
| ; CHECK-NEXT: [[RETLO:%.*]] = mul i16 [[IN0]], [[IN1]] |
| ; CHECK-NEXT: ret i16 [[RETLO]] |
| ; |
| %In0Lo = and i16 %in0, 255 |
| %In0Hi = lshr i16 %in0, 8 |
| %In1Lo = and i16 %in1, 255 |
| %In1Hi = lshr i16 %in1, 8 |
| %m10 = mul i16 %In0Lo, %In1Hi |
| call void @use16(i16 %m10) |
| %m01 = mul i16 %In1Lo, %In0Hi |
| call void @use16(i16 %m01) |
| %m00 = mul i16 %In1Lo, %In0Lo |
| %addc = add i16 %m10, %m01 |
| %shl = shl i16 %addc, 8 |
| %retLo = add i16 %shl, %m00 |
| ret i16 %retLo |
| } |
| |
| define i16 @mul16_low_A1_B1(i16 %in0, i16 %in1) { |
| ; CHECK-LABEL: @mul16_low_A1_B1( |
| ; CHECK-NEXT: [[IN0LO:%.*]] = and i16 [[IN0:%.*]], 255 |
| ; CHECK-NEXT: [[IN0HI:%.*]] = lshr i16 [[IN0]], 8 |
| ; CHECK-NEXT: [[IN1LO:%.*]] = and i16 [[IN1:%.*]], 255 |
| ; CHECK-NEXT: [[IN1HI:%.*]] = lshr i16 [[IN1]], 8 |
| ; CHECK-NEXT: [[M10:%.*]] = mul nuw i16 [[IN0LO]], [[IN1HI]] |
| ; CHECK-NEXT: call void @use16(i16 [[M10]]) |
| ; CHECK-NEXT: [[M01:%.*]] = mul nuw i16 [[IN0HI]], [[IN1LO]] |
| ; CHECK-NEXT: call void @use16(i16 [[M01]]) |
| ; CHECK-NEXT: [[RETLO:%.*]] = mul i16 [[IN0]], [[IN1]] |
| ; CHECK-NEXT: ret i16 [[RETLO]] |
| ; |
| %In0Lo = and i16 %in0, 255 |
| %In0Hi = lshr i16 %in0, 8 |
| %In1Lo = and i16 %in1, 255 |
| %In1Hi = lshr i16 %in1, 8 |
| %m10 = mul i16 %In0Lo, %In1Hi |
| call void @use16(i16 %m10) |
| %m01 = mul i16 %In0Hi, %In1Lo |
| call void @use16(i16 %m01) |
| %m00 = mul i16 %In1Lo, %In0Lo |
| %addc = add i16 %m10, %m01 |
| %shl = shl i16 %addc, 8 |
| %retLo = add i16 %m00, %shl |
| ret i16 %retLo |
| } |
| |
| define i16 @mul16_low_A1_B2(i16 %in0, i16 %in1) { |
| ; CHECK-LABEL: @mul16_low_A1_B2( |
| ; CHECK-NEXT: [[IN0LO:%.*]] = and i16 [[IN0:%.*]], 255 |
| ; CHECK-NEXT: [[IN0HI:%.*]] = lshr i16 [[IN0]], 8 |
| ; CHECK-NEXT: [[IN1LO:%.*]] = and i16 [[IN1:%.*]], 255 |
| ; CHECK-NEXT: [[IN1HI:%.*]] = lshr i16 [[IN1]], 8 |
| ; CHECK-NEXT: [[M10:%.*]] = mul nuw i16 [[IN1HI]], [[IN0LO]] |
| ; CHECK-NEXT: call void @use16(i16 [[M10]]) |
| ; CHECK-NEXT: [[M01:%.*]] = mul nuw i16 [[IN1LO]], [[IN0HI]] |
| ; CHECK-NEXT: call void @use16(i16 [[M01]]) |
| ; CHECK-NEXT: [[RETLO:%.*]] = mul i16 [[IN0]], [[IN1]] |
| ; CHECK-NEXT: ret i16 [[RETLO]] |
| ; |
| %In0Lo = and i16 %in0, 255 |
| %In0Hi = lshr i16 %in0, 8 |
| %In1Lo = and i16 %in1, 255 |
| %In1Hi = lshr i16 %in1, 8 |
| %m10 = mul i16 %In1Hi, %In0Lo |
| call void @use16(i16 %m10) |
| %m01 = mul i16 %In1Lo, %In0Hi |
| call void @use16(i16 %m01) |
| %m00 = mul i16 %In1Lo, %In0Lo |
| %addc = add i16 %m01, %m10 |
| %shl = shl i16 %addc, 8 |
| %retLo = add i16 %shl, %m00 |
| ret i16 %retLo |
| } |
| |
| define i16 @mul16_low_A1_B3(i16 %in0, i16 %in1) { |
| ; CHECK-LABEL: @mul16_low_A1_B3( |
| ; CHECK-NEXT: [[IN0LO:%.*]] = and i16 [[IN0:%.*]], 255 |
| ; CHECK-NEXT: [[IN0HI:%.*]] = lshr i16 [[IN0]], 8 |
| ; CHECK-NEXT: [[IN1LO:%.*]] = and i16 [[IN1:%.*]], 255 |
| ; CHECK-NEXT: [[IN1HI:%.*]] = lshr i16 [[IN1]], 8 |
| ; CHECK-NEXT: [[M10:%.*]] = mul nuw i16 [[IN0LO]], [[IN1HI]] |
| ; CHECK-NEXT: call void @use16(i16 [[M10]]) |
| ; CHECK-NEXT: [[M01:%.*]] = mul nuw i16 [[IN1LO]], [[IN0HI]] |
| ; CHECK-NEXT: call void @use16(i16 [[M01]]) |
| ; CHECK-NEXT: [[RETLO:%.*]] = mul i16 [[IN0]], [[IN1]] |
| ; CHECK-NEXT: ret i16 [[RETLO]] |
| ; |
| %In0Lo = and i16 %in0, 255 |
| %In0Hi = lshr i16 %in0, 8 |
| %In1Lo = and i16 %in1, 255 |
| %In1Hi = lshr i16 %in1, 8 |
| %m10 = mul i16 %In0Lo, %In1Hi |
| call void @use16(i16 %m10) |
| %m01 = mul i16 %In1Lo, %In0Hi |
| call void @use16(i16 %m01) |
| %m00 = mul i16 %In1Lo, %In0Lo |
| %addc = add i16 %m01, %m10 |
| %shl = shl i16 %addc, 8 |
| %retLo = add i16 %m00, %shl |
| ret i16 %retLo |
| } |
| |
| ; 4 tests that use In0Lo/in1 with different commutes |
| define i32 @mul32_low_A2_B0(i32 %in0, i32 %in1) { |
| ; CHECK-LABEL: @mul32_low_A2_B0( |
| ; CHECK-NEXT: [[IN0LO:%.*]] = and i32 [[IN0:%.*]], 65535 |
| ; CHECK-NEXT: [[IN1HI:%.*]] = lshr i32 [[IN1:%.*]], 16 |
| ; CHECK-NEXT: [[M10:%.*]] = mul nuw i32 [[IN1HI]], [[IN0LO]] |
| ; CHECK-NEXT: call void @use32(i32 [[M10]]) |
| ; CHECK-NEXT: [[RETLO:%.*]] = mul i32 [[IN0]], [[IN1]] |
| ; CHECK-NEXT: ret i32 [[RETLO]] |
| ; |
| %In0Lo = and i32 %in0, 65535 |
| %In0Hi = lshr i32 %in0, 16 |
| %In1Lo = and i32 %in1, 65535 |
| %In1Hi = lshr i32 %in1, 16 |
| %m10 = mul i32 %In1Hi, %In0Lo |
| call void @use32(i32 %m10) |
| %m01 = mul i32 %In0Hi, %in1 |
| %m00 = mul i32 %In1Lo, %In0Lo |
| %addc = add i32 %m10, %m01 |
| %shl = shl i32 %addc, 16 |
| %retLo = add i32 %shl, %m00 |
| ret i32 %retLo |
| } |
| |
| define i32 @mul32_low_A2_B1(i32 %in0, i32 %in1) { |
| ; CHECK-LABEL: @mul32_low_A2_B1( |
| ; CHECK-NEXT: [[IN0LO:%.*]] = and i32 [[IN0:%.*]], 65535 |
| ; CHECK-NEXT: [[IN1HI:%.*]] = lshr i32 [[IN1:%.*]], 16 |
| ; CHECK-NEXT: [[M10:%.*]] = mul nuw i32 [[IN1HI]], [[IN0LO]] |
| ; CHECK-NEXT: call void @use32(i32 [[M10]]) |
| ; CHECK-NEXT: [[RETLO:%.*]] = mul i32 [[IN0]], [[IN1]] |
| ; CHECK-NEXT: ret i32 [[RETLO]] |
| ; |
| %In0Lo = and i32 %in0, 65535 |
| %In0Hi = lshr i32 %in0, 16 |
| %In1Lo = and i32 %in1, 65535 |
| %In1Hi = lshr i32 %in1, 16 |
| %m10 = mul i32 %In1Hi, %In0Lo |
| call void @use32(i32 %m10) |
| %m01 = mul i32 %In0Hi, %in1 |
| %m00 = mul i32 %In1Lo, %In0Lo |
| %addc = add i32 %m10, %m01 |
| %shl = shl i32 %addc, 16 |
| %retLo = add i32 %m00, %shl |
| ret i32 %retLo |
| } |
| |
| define i32 @mul32_low_A2_B2(i32 %in0, i32 %p) { |
| ; CHECK-LABEL: @mul32_low_A2_B2( |
| ; CHECK-NEXT: [[IN1:%.*]] = call i32 @use32(i32 [[P:%.*]]) |
| ; CHECK-NEXT: [[IN0LO:%.*]] = and i32 [[IN0:%.*]], 65535 |
| ; CHECK-NEXT: [[IN1HI:%.*]] = lshr i32 [[IN1]], 16 |
| ; CHECK-NEXT: [[M10:%.*]] = mul nuw i32 [[IN0LO]], [[IN1HI]] |
| ; CHECK-NEXT: call void @use32(i32 [[M10]]) |
| ; CHECK-NEXT: [[RETLO:%.*]] = mul i32 [[IN0]], [[IN1]] |
| ; CHECK-NEXT: ret i32 [[RETLO]] |
| ; |
| %in1 = call i32 @use32(i32 %p) ; thwart complexity-based canonicalization |
| %In0Lo = and i32 %in0, 65535 |
| %In0Hi = lshr i32 %in0, 16 |
| %In1Lo = and i32 %in1, 65535 |
| %In1Hi = lshr i32 %in1, 16 |
| %m10 = mul i32 %In0Lo, %In1Hi |
| call void @use32(i32 %m10) |
| %m01 = mul i32 %in1, %In0Hi |
| %m00 = mul i32 %In1Lo, %In0Lo |
| %addc = add i32 %m01, %m10 |
| %shl = shl i32 %addc, 16 |
| %retLo = add i32 %shl, %m00 |
| ret i32 %retLo |
| } |
| |
| define i32 @mul32_low_A2_B3(i32 %in0, i32 %p) { |
| ; CHECK-LABEL: @mul32_low_A2_B3( |
| ; CHECK-NEXT: [[IN1:%.*]] = call i32 @use32(i32 [[P:%.*]]) |
| ; CHECK-NEXT: [[IN0LO:%.*]] = and i32 [[IN0:%.*]], 65535 |
| ; CHECK-NEXT: [[IN1HI:%.*]] = lshr i32 [[IN1]], 16 |
| ; CHECK-NEXT: [[M10:%.*]] = mul nuw i32 [[IN1HI]], [[IN0LO]] |
| ; CHECK-NEXT: call void @use32(i32 [[M10]]) |
| ; CHECK-NEXT: [[RETLO:%.*]] = mul i32 [[IN0]], [[IN1]] |
| ; CHECK-NEXT: ret i32 [[RETLO]] |
| ; |
| %in1 = call i32 @use32(i32 %p) ; thwart complexity-based canonicalization |
| %In0Lo = and i32 %in0, 65535 |
| %In0Hi = lshr i32 %in0, 16 |
| %In1Lo = and i32 %in1, 65535 |
| %In1Hi = lshr i32 %in1, 16 |
| %m10 = mul i32 %In1Hi, %In0Lo |
| call void @use32(i32 %m10) |
| %m01 = mul i32 %in1, %In0Hi |
| %m00 = mul i32 %In1Lo, %In0Lo |
| %addc = add i32 %m01, %m10 |
| %shl = shl i32 %addc, 16 |
| %retLo = add i32 %m00, %shl |
| ret i32 %retLo |
| } |
| |
| ; 4 tests that use in0/In1Lo with different commutes |
| define i64 @mul64_low_A3_B0(i64 %in0, i64 %in1) { |
| ; CHECK-LABEL: @mul64_low_A3_B0( |
| ; CHECK-NEXT: [[IN0HI:%.*]] = lshr i64 [[IN0:%.*]], 32 |
| ; CHECK-NEXT: [[IN1LO:%.*]] = and i64 [[IN1:%.*]], 4294967295 |
| ; CHECK-NEXT: [[M01:%.*]] = mul nuw i64 [[IN0HI]], [[IN1LO]] |
| ; CHECK-NEXT: call void @use64(i64 [[M01]]) |
| ; CHECK-NEXT: [[RETLO:%.*]] = mul i64 [[IN0]], [[IN1]] |
| ; CHECK-NEXT: ret i64 [[RETLO]] |
| ; |
| %In0Lo = and i64 %in0, 4294967295 |
| %In0Hi = lshr i64 %in0, 32 |
| %In1Lo = and i64 %in1, 4294967295 |
| %In1Hi = lshr i64 %in1, 32 |
| %m10 = mul i64 %In1Hi, %in0 |
| %m01 = mul i64 %In0Hi, %In1Lo |
| call void @use64(i64 %m01) |
| %m00 = mul i64 %In1Lo, %In0Lo |
| %addc = add i64 %m10, %m01 |
| %shl = shl i64 %addc, 32 |
| %retLo = add i64 %shl, %m00 |
| ret i64 %retLo |
| } |
| |
| define i64 @mul64_low_A3_B1(i64 %in0, i64 %in1) { |
| ; CHECK-LABEL: @mul64_low_A3_B1( |
| ; CHECK-NEXT: [[IN0HI:%.*]] = lshr i64 [[IN0:%.*]], 32 |
| ; CHECK-NEXT: [[IN1LO:%.*]] = and i64 [[IN1:%.*]], 4294967295 |
| ; CHECK-NEXT: [[M01:%.*]] = mul nuw i64 [[IN0HI]], [[IN1LO]] |
| ; CHECK-NEXT: call void @use64(i64 [[M01]]) |
| ; CHECK-NEXT: [[RETLO:%.*]] = mul i64 [[IN0]], [[IN1]] |
| ; CHECK-NEXT: ret i64 [[RETLO]] |
| ; |
| %In0Lo = and i64 %in0, 4294967295 |
| %In0Hi = lshr i64 %in0, 32 |
| %In1Lo = and i64 %in1, 4294967295 |
| %In1Hi = lshr i64 %in1, 32 |
| %m10 = mul i64 %In1Hi, %in0 |
| %m01 = mul i64 %In0Hi, %In1Lo |
| call void @use64(i64 %m01) |
| %m00 = mul i64 %In1Lo, %In0Lo |
| %addc = add i64 %m10, %m01 |
| %shl = shl i64 %addc, 32 |
| %retLo = add i64 %m00, %shl |
| ret i64 %retLo |
| } |
| |
| define i64 @mul64_low_A3_B2(i64 %p, i64 %in1) { |
| ; CHECK-LABEL: @mul64_low_A3_B2( |
| ; CHECK-NEXT: [[IN0:%.*]] = call i64 @use64(i64 [[P:%.*]]) |
| ; CHECK-NEXT: [[IN0HI:%.*]] = lshr i64 [[IN0]], 32 |
| ; CHECK-NEXT: [[IN1LO:%.*]] = and i64 [[IN1:%.*]], 4294967295 |
| ; CHECK-NEXT: [[M01:%.*]] = mul nuw i64 [[IN0HI]], [[IN1LO]] |
| ; CHECK-NEXT: call void @use64(i64 [[M01]]) |
| ; CHECK-NEXT: [[RETLO:%.*]] = mul i64 [[IN0]], [[IN1]] |
| ; CHECK-NEXT: ret i64 [[RETLO]] |
| ; |
| %in0 = call i64 @use64(i64 %p) ; thwart complexity-based canonicalization |
| %In0Lo = and i64 %in0, 4294967295 |
| %In0Hi = lshr i64 %in0, 32 |
| %In1Lo = and i64 %in1, 4294967295 |
| %In1Hi = lshr i64 %in1, 32 |
| %m10 = mul i64 %in0, %In1Hi |
| %m01 = mul i64 %In0Hi, %In1Lo |
| call void @use64(i64 %m01) |
| %m00 = mul i64 %In1Lo, %In0Lo |
| %addc = add i64 %m01, %m10 |
| %shl = shl i64 %addc, 32 |
| %retLo = add i64 %shl, %m00 |
| ret i64 %retLo |
| } |
| |
| define i64 @mul64_low_A3_B3(i64 %p, i64 %in1) { |
| ; CHECK-LABEL: @mul64_low_A3_B3( |
| ; CHECK-NEXT: [[IN0:%.*]] = call i64 @use64(i64 [[P:%.*]]) |
| ; CHECK-NEXT: [[IN0HI:%.*]] = lshr i64 [[IN0]], 32 |
| ; CHECK-NEXT: [[IN1LO:%.*]] = and i64 [[IN1:%.*]], 4294967295 |
| ; CHECK-NEXT: [[M01:%.*]] = mul nuw i64 [[IN1LO]], [[IN0HI]] |
| ; CHECK-NEXT: call void @use64(i64 [[M01]]) |
| ; CHECK-NEXT: [[RETLO:%.*]] = mul i64 [[IN0]], [[IN1]] |
| ; CHECK-NEXT: ret i64 [[RETLO]] |
| ; |
| %in0 = call i64 @use64(i64 %p) ; thwart complexity-based canonicalization |
| %In0Lo = and i64 %in0, 4294967295 |
| %In0Hi = lshr i64 %in0, 32 |
| %In1Lo = and i64 %in1, 4294967295 |
| %In1Hi = lshr i64 %in1, 32 |
| %m10 = mul i64 %in0, %In1Hi |
| %m01 = mul i64 %In1Lo, %In0Hi |
| call void @use64(i64 %m01) |
| %m00 = mul i64 %In1Lo, %In0Lo |
| %addc = add i64 %m01, %m10 |
| %shl = shl i64 %addc, 32 |
| %retLo = add i64 %m00, %shl |
| ret i64 %retLo |
| } |
| |
| define i32 @mul32_low_one_extra_user(i32 %in0, i32 %in1) { |
| ; CHECK-LABEL: @mul32_low_one_extra_user( |
| ; CHECK-NEXT: [[IN0LO:%.*]] = and i32 [[IN0:%.*]], 65535 |
| ; CHECK-NEXT: [[IN0HI:%.*]] = lshr i32 [[IN0]], 16 |
| ; CHECK-NEXT: [[IN1LO:%.*]] = and i32 [[IN1:%.*]], 65535 |
| ; CHECK-NEXT: [[IN1HI:%.*]] = lshr i32 [[IN1]], 16 |
| ; CHECK-NEXT: [[M10:%.*]] = mul nuw i32 [[IN1HI]], [[IN0LO]] |
| ; CHECK-NEXT: [[M01:%.*]] = mul nuw i32 [[IN1LO]], [[IN0HI]] |
| ; CHECK-NEXT: [[ADDC:%.*]] = add i32 [[M10]], [[M01]] |
| ; CHECK-NEXT: call void @use32(i32 [[ADDC]]) |
| ; CHECK-NEXT: [[RETLO:%.*]] = mul i32 [[IN0]], [[IN1]] |
| ; CHECK-NEXT: ret i32 [[RETLO]] |
| ; |
| %In0Lo = and i32 %in0, 65535 |
| %In0Hi = lshr i32 %in0, 16 |
| %In1Lo = and i32 %in1, 65535 |
| %In1Hi = lshr i32 %in1, 16 |
| %m10 = mul i32 %In1Hi, %In0Lo |
| %m01 = mul i32 %In1Lo, %In0Hi |
| %m00 = mul i32 %In1Lo, %In0Lo |
| %addc = add i32 %m10, %m01 |
| call void @use32(i32 %addc) |
| %shl = shl i32 %addc, 16 |
| %retLo = add i32 %shl, %m00 |
| ret i32 %retLo |
| } |
| |
| ; The following are variety types of target cases |
| ; https://alive2.llvm.org/ce/z/2BqKLt |
| define i8 @mul8_low(i8 %in0, i8 %in1) { |
| ; CHECK-LABEL: @mul8_low( |
| ; CHECK-NEXT: [[RETLO:%.*]] = mul i8 [[IN0:%.*]], [[IN1:%.*]] |
| ; CHECK-NEXT: ret i8 [[RETLO]] |
| ; |
| %In0Lo = and i8 %in0, 15 |
| %In0Hi = lshr i8 %in0, 4 |
| %In1Lo = and i8 %in1, 15 |
| %In1Hi = lshr i8 %in1, 4 |
| %m10 = mul i8 %In1Hi, %In0Lo |
| %m01 = mul i8 %In1Lo, %In0Hi |
| %m00 = mul i8 %In1Lo, %In0Lo |
| %addc = add i8 %m10, %m01 |
| %shl = shl i8 %addc, 4 |
| %retLo = add i8 %shl, %m00 |
| ret i8 %retLo |
| } |
| |
| define i16 @mul16_low(i16 %in0, i16 %in1) { |
| ; CHECK-LABEL: @mul16_low( |
| ; CHECK-NEXT: [[RETLO:%.*]] = mul i16 [[IN0:%.*]], [[IN1:%.*]] |
| ; CHECK-NEXT: ret i16 [[RETLO]] |
| ; |
| %In0Lo = and i16 %in0, 255 |
| %In0Hi = lshr i16 %in0, 8 |
| %In1Lo = and i16 %in1, 255 |
| %In1Hi = lshr i16 %in1, 8 |
| %m10 = mul i16 %In1Hi, %In0Lo |
| %m01 = mul i16 %In1Lo, %In0Hi |
| %m00 = mul i16 %In1Lo, %In0Lo |
| %addc = add i16 %m10, %m01 |
| %shl = shl i16 %addc, 8 |
| %retLo = add i16 %shl, %m00 |
| ret i16 %retLo |
| } |
| |
| define i32 @mul32_low(i32 %in0, i32 %in1) { |
| ; CHECK-LABEL: @mul32_low( |
| ; CHECK-NEXT: [[RETLO:%.*]] = mul i32 [[IN0:%.*]], [[IN1:%.*]] |
| ; CHECK-NEXT: ret i32 [[RETLO]] |
| ; |
| %In0Lo = and i32 %in0, 65535 |
| %In0Hi = lshr i32 %in0, 16 |
| %In1Lo = and i32 %in1, 65535 |
| %In1Hi = lshr i32 %in1, 16 |
| %m10 = mul i32 %In1Hi, %In0Lo |
| %m01 = mul i32 %In1Lo, %In0Hi |
| %m00 = mul i32 %In1Lo, %In0Lo |
| %addc = add i32 %m10, %m01 |
| %shl = shl i32 %addc, 16 |
| %retLo = add i32 %shl, %m00 |
| ret i32 %retLo |
| } |
| |
| define i64 @mul64_low(i64 %in0, i64 %in1) { |
| ; CHECK-LABEL: @mul64_low( |
| ; CHECK-NEXT: [[RETLO:%.*]] = mul i64 [[IN0:%.*]], [[IN1:%.*]] |
| ; CHECK-NEXT: ret i64 [[RETLO]] |
| ; |
| %In0Lo = and i64 %in0, 4294967295 |
| %In0Hi = lshr i64 %in0, 32 |
| %In1Lo = and i64 %in1, 4294967295 |
| %In1Hi = lshr i64 %in1, 32 |
| %m10 = mul i64 %In1Hi, %In0Lo |
| %m01 = mul i64 %In1Lo, %In0Hi |
| %m00 = mul i64 %In1Lo, %In0Lo |
| %addc = add i64 %m10, %m01 |
| %shl = shl i64 %addc, 32 |
| %retLo = add i64 %shl, %m00 |
| ret i64 %retLo |
| } |
| |
| define i128 @mul128_low(i128 %in0, i128 %in1) { |
| ; CHECK-LABEL: @mul128_low( |
| ; CHECK-NEXT: [[RETLO:%.*]] = mul i128 [[IN0:%.*]], [[IN1:%.*]] |
| ; CHECK-NEXT: ret i128 [[RETLO]] |
| ; |
| %In0Lo = and i128 %in0, 18446744073709551615 |
| %In0Hi = lshr i128 %in0, 64 |
| %In1Lo = and i128 %in1, 18446744073709551615 |
| %In1Hi = lshr i128 %in1, 64 |
| %m10 = mul i128 %In1Hi, %In0Lo |
| %m01 = mul i128 %In1Lo, %In0Hi |
| %m00 = mul i128 %In1Lo, %In0Lo |
| %addc = add i128 %m10, %m01 |
| %shl = shl i128 %addc, 64 |
| %retLo = add i128 %shl, %m00 |
| ret i128 %retLo |
| } |
| |
| ; Support vector type |
| define <2 x i8> @mul_v2i8_low(<2 x i8> %in0, <2 x i8> %in1) { |
| ; CHECK-LABEL: @mul_v2i8_low( |
| ; CHECK-NEXT: [[RETLO:%.*]] = mul <2 x i8> [[IN0:%.*]], [[IN1:%.*]] |
| ; CHECK-NEXT: ret <2 x i8> [[RETLO]] |
| ; |
| %In0Lo = and <2 x i8> %in0, <i8 15, i8 15> |
| %In0Hi = lshr <2 x i8> %in0, <i8 4, i8 4> |
| %In1Lo = and <2 x i8> %in1, <i8 15, i8 15> |
| %In1Hi = lshr <2 x i8> %in1, <i8 4, i8 4> |
| %m10 = mul <2 x i8> %In1Hi, %In0Lo |
| %m01 = mul <2 x i8> %In1Lo, %In0Hi |
| %m00 = mul <2 x i8> %In1Lo, %In0Lo |
| %addc = add <2 x i8> %m10, %m01 |
| %shl = shl <2 x i8> %addc, <i8 4, i8 4> |
| %retLo = add <2 x i8> %shl, %m00 |
| ret <2 x i8> %retLo |
| } |
| |
| define <2 x i8> @mul_v2i8_low_one_extra_user(<2 x i8> %in0, <2 x i8> %in1) { |
| ; CHECK-LABEL: @mul_v2i8_low_one_extra_user( |
| ; CHECK-NEXT: [[IN0HI:%.*]] = lshr <2 x i8> [[IN0:%.*]], splat (i8 4) |
| ; CHECK-NEXT: [[IN1LO:%.*]] = and <2 x i8> [[IN1:%.*]], splat (i8 15) |
| ; CHECK-NEXT: [[M01:%.*]] = mul nuw <2 x i8> [[IN1LO]], [[IN0HI]] |
| ; CHECK-NEXT: call void @use_v2i8(<2 x i8> [[M01]]) |
| ; CHECK-NEXT: [[RETLO:%.*]] = mul <2 x i8> [[IN0]], [[IN1]] |
| ; CHECK-NEXT: ret <2 x i8> [[RETLO]] |
| ; |
| %In0Lo = and <2 x i8> %in0, <i8 15, i8 15> |
| %In0Hi = lshr <2 x i8> %in0, <i8 4, i8 4> |
| %In1Lo = and <2 x i8> %in1, <i8 15, i8 15> |
| %In1Hi = lshr <2 x i8> %in1, <i8 4, i8 4> |
| %m10 = mul <2 x i8> %In1Hi, %In0Lo |
| %m01 = mul <2 x i8> %In1Lo, %In0Hi |
| call void @use_v2i8(<2 x i8> %m01) |
| %m00 = mul <2 x i8> %In1Lo, %In0Lo |
| %addc = add <2 x i8> %m10, %m01 |
| %shl = shl <2 x i8> %addc, <i8 4, i8 4> |
| %retLo = add <2 x i8> %shl, %m00 |
| ret <2 x i8> %retLo |
| } |
| |
| ; Support wide width |
| define i130 @mul130_low(i130 %in0, i130 %in1) { |
| ; CHECK-LABEL: @mul130_low( |
| ; CHECK-NEXT: [[RETLO:%.*]] = mul i130 [[IN0:%.*]], [[IN1:%.*]] |
| ; CHECK-NEXT: ret i130 [[RETLO]] |
| ; |
| %In0Lo = and i130 %in0, 36893488147419103231 |
| %In0Hi = lshr i130 %in0, 65 |
| %In1Lo = and i130 %in1, 36893488147419103231 |
| %In1Hi = lshr i130 %in1, 65 |
| %m10 = mul i130 %In1Hi, %In0Lo |
| %m01 = mul i130 %In1Lo, %In0Hi |
| %m00 = mul i130 %In1Lo, %In0Lo |
| %addc = add i130 %m10, %m01 |
| %shl = shl i130 %addc, 65 |
| %retLo = add i130 %shl, %m00 |
| ret i130 %retLo |
| } |
| |
| define i130 @mul130_low_one_extra_user(i130 %in0, i130 %in1) { |
| ; CHECK-LABEL: @mul130_low_one_extra_user( |
| ; CHECK-NEXT: [[IN0LO:%.*]] = and i130 [[IN0:%.*]], 36893488147419103231 |
| ; CHECK-NEXT: [[IN1HI:%.*]] = lshr i130 [[IN1:%.*]], 65 |
| ; CHECK-NEXT: [[M10:%.*]] = mul nuw i130 [[IN1HI]], [[IN0LO]] |
| ; CHECK-NEXT: call void @use130(i130 [[M10]]) |
| ; CHECK-NEXT: [[RETLO:%.*]] = mul i130 [[IN0]], [[IN1]] |
| ; CHECK-NEXT: ret i130 [[RETLO]] |
| ; |
| %In0Lo = and i130 %in0, 36893488147419103231 |
| %In0Hi = lshr i130 %in0, 65 |
| %In1Lo = and i130 %in1, 36893488147419103231 |
| %In1Hi = lshr i130 %in1, 65 |
| %m10 = mul i130 %In1Hi, %In0Lo |
| call void @use130(i130 %m10) |
| %m01 = mul i130 %In1Lo, %In0Hi |
| %m00 = mul i130 %In1Lo, %In0Lo |
| %addc = add i130 %m10, %m01 |
| %shl = shl i130 %addc, 65 |
| %retLo = add i130 %shl, %m00 |
| ret i130 %retLo |
| } |
| |
| ; Negative case: Skip odd bitwidth type |
| define i9 @mul9_low(i9 %in0, i9 %in1) { |
| ; CHECK-LABEL: @mul9_low( |
| ; CHECK-NEXT: [[IN0LO:%.*]] = and i9 [[IN0:%.*]], 15 |
| ; CHECK-NEXT: [[IN0HI:%.*]] = lshr i9 [[IN0]], 4 |
| ; CHECK-NEXT: [[IN1LO:%.*]] = and i9 [[IN1:%.*]], 15 |
| ; CHECK-NEXT: [[IN1HI:%.*]] = lshr i9 [[IN1]], 4 |
| ; CHECK-NEXT: [[M10:%.*]] = mul nuw i9 [[IN1HI]], [[IN0LO]] |
| ; CHECK-NEXT: [[M01:%.*]] = mul nuw i9 [[IN1LO]], [[IN0HI]] |
| ; CHECK-NEXT: [[M00:%.*]] = mul nuw nsw i9 [[IN1LO]], [[IN0LO]] |
| ; CHECK-NEXT: [[ADDC:%.*]] = add i9 [[M10]], [[M01]] |
| ; CHECK-NEXT: [[SHL:%.*]] = shl i9 [[ADDC]], 4 |
| ; CHECK-NEXT: [[RETLO:%.*]] = add i9 [[SHL]], [[M00]] |
| ; CHECK-NEXT: ret i9 [[RETLO]] |
| ; |
| %In0Lo = and i9 %in0, 15 |
| %In0Hi = lshr i9 %in0, 4 |
| %In1Lo = and i9 %in1, 15 |
| %In1Hi = lshr i9 %in1, 4 |
| %m10 = mul i9 %In1Hi, %In0Lo |
| %m01 = mul i9 %In1Lo, %In0Hi |
| %m00 = mul i9 %In1Lo, %In0Lo |
| %addc = add i9 %m10, %m01 |
| %shl = shl i9 %addc, 4 |
| %retLo = add i9 %shl, %m00 |
| ret i9 %retLo |
| } |
| |
| ; Negative test: Should not remote the "and", https://alive2.llvm.org/ce/z/JLmNU5 |
| define i64 @mul64_low_no_and(i64 %in0, i64 %in1) { |
| ; CHECK-LABEL: @mul64_low_no_and( |
| ; CHECK-NEXT: [[IN0HI:%.*]] = lshr i64 [[IN0:%.*]], 32 |
| ; CHECK-NEXT: [[IN1HI:%.*]] = lshr i64 [[IN1:%.*]], 32 |
| ; CHECK-NEXT: [[M10:%.*]] = mul i64 [[IN1HI]], [[IN0]] |
| ; CHECK-NEXT: [[M01:%.*]] = mul i64 [[IN1]], [[IN0HI]] |
| ; CHECK-NEXT: [[M00:%.*]] = mul i64 [[IN1]], [[IN0]] |
| ; CHECK-NEXT: [[ADDC:%.*]] = add i64 [[M10]], [[M01]] |
| ; CHECK-NEXT: [[SHL:%.*]] = shl i64 [[ADDC]], 32 |
| ; CHECK-NEXT: [[RETLO:%.*]] = add i64 [[SHL]], [[M00]] |
| ; CHECK-NEXT: ret i64 [[RETLO]] |
| ; |
| %In0Hi = lshr i64 %in0, 32 |
| %In1Hi = lshr i64 %in1, 32 |
| %m10 = mul i64 %In1Hi, %in0 |
| %m01 = mul i64 %in1, %In0Hi |
| %m00 = mul i64 %in1, %in0 |
| %addc = add i64 %m10, %m01 |
| %shl = shl i64 %addc, 32 |
| %retLo = add i64 %shl, %m00 |
| ret i64 %retLo |
| } |
| |
| ; Negative test: Miss match the shift amount |
| define i16 @mul16_low_miss_shift_amount(i16 %in0, i16 %in1) { |
| ; CHECK-LABEL: @mul16_low_miss_shift_amount( |
| ; CHECK-NEXT: [[IN0LO:%.*]] = and i16 [[IN0:%.*]], 127 |
| ; CHECK-NEXT: [[IN0HI:%.*]] = lshr i16 [[IN0]], 8 |
| ; CHECK-NEXT: [[IN1LO:%.*]] = and i16 [[IN1:%.*]], 127 |
| ; CHECK-NEXT: [[IN1HI:%.*]] = lshr i16 [[IN1]], 8 |
| ; CHECK-NEXT: [[M10:%.*]] = mul nuw nsw i16 [[IN1HI]], [[IN0LO]] |
| ; CHECK-NEXT: [[M01:%.*]] = mul nuw nsw i16 [[IN1LO]], [[IN0HI]] |
| ; CHECK-NEXT: [[M00:%.*]] = mul nuw nsw i16 [[IN1LO]], [[IN0LO]] |
| ; CHECK-NEXT: [[ADDC:%.*]] = add nuw i16 [[M10]], [[M01]] |
| ; CHECK-NEXT: [[SHL:%.*]] = shl i16 [[ADDC]], 8 |
| ; CHECK-NEXT: [[RETLO:%.*]] = add i16 [[SHL]], [[M00]] |
| ; CHECK-NEXT: ret i16 [[RETLO]] |
| ; |
| %In0Lo = and i16 %in0, 127 ; Should be 255 |
| %In0Hi = lshr i16 %in0, 8 |
| %In1Lo = and i16 %in1, 127 |
| %In1Hi = lshr i16 %in1, 8 |
| %m10 = mul i16 %In1Hi, %In0Lo |
| %m01 = mul i16 %In1Lo, %In0Hi |
| %m00 = mul i16 %In1Lo, %In0Lo |
| %addc = add i16 %m10, %m01 |
| %shl = shl i16 %addc, 8 |
| %retLo = add i16 %shl, %m00 |
| ret i16 %retLo |
| } |
| |
| ; Negative test: Miss match the half width |
| define i8 @mul8_low_miss_half_width(i8 %in0, i8 %in1) { |
| ; CHECK-LABEL: @mul8_low_miss_half_width( |
| ; CHECK-NEXT: [[IN0LO:%.*]] = and i8 [[IN0:%.*]], 15 |
| ; CHECK-NEXT: [[IN0HI:%.*]] = lshr i8 [[IN0]], 3 |
| ; CHECK-NEXT: [[IN1LO:%.*]] = and i8 [[IN1:%.*]], 15 |
| ; CHECK-NEXT: [[IN1HI:%.*]] = lshr i8 [[IN1]], 3 |
| ; CHECK-NEXT: [[M10:%.*]] = mul i8 [[IN1HI]], [[IN0LO]] |
| ; CHECK-NEXT: [[M01:%.*]] = mul i8 [[IN1LO]], [[IN0HI]] |
| ; CHECK-NEXT: [[M00:%.*]] = mul nuw i8 [[IN1LO]], [[IN0LO]] |
| ; CHECK-NEXT: [[ADDC:%.*]] = add i8 [[M10]], [[M01]] |
| ; CHECK-NEXT: [[SHL:%.*]] = shl i8 [[ADDC]], 3 |
| ; CHECK-NEXT: [[RETLO:%.*]] = add i8 [[SHL]], [[M00]] |
| ; CHECK-NEXT: ret i8 [[RETLO]] |
| ; |
| %In0Lo = and i8 %in0, 15 |
| %In0Hi = lshr i8 %in0, 3 ; Should be 4 |
| %In1Lo = and i8 %in1, 15 |
| %In1Hi = lshr i8 %in1, 3 |
| %m10 = mul i8 %In1Hi, %In0Lo |
| %m01 = mul i8 %In1Lo, %In0Hi |
| %m00 = mul i8 %In1Lo, %In0Lo |
| %addc = add i8 %m10, %m01 |
| %shl = shl i8 %addc, 3 |
| %retLo = add i8 %shl, %m00 |
| ret i8 %retLo |
| } |
| |
| ; Test case to show shl doesn't need hasOneUse constraint |
| define i32 @mul32_low_extra_shl_use(i32 %in0, i32 %in1) { |
| ; CHECK-LABEL: @mul32_low_extra_shl_use( |
| ; CHECK-NEXT: [[IN0HI:%.*]] = lshr i32 [[IN0:%.*]], 16 |
| ; CHECK-NEXT: [[IN1HI:%.*]] = lshr i32 [[IN1:%.*]], 16 |
| ; CHECK-NEXT: [[M10:%.*]] = mul i32 [[IN1HI]], [[IN0]] |
| ; CHECK-NEXT: [[M01:%.*]] = mul i32 [[IN1]], [[IN0HI]] |
| ; CHECK-NEXT: [[ADDC:%.*]] = add i32 [[M10]], [[M01]] |
| ; CHECK-NEXT: [[SHL:%.*]] = shl i32 [[ADDC]], 16 |
| ; CHECK-NEXT: call void @use32(i32 [[SHL]]) |
| ; CHECK-NEXT: [[RETLO:%.*]] = mul i32 [[IN0]], [[IN1]] |
| ; CHECK-NEXT: ret i32 [[RETLO]] |
| ; |
| %In0Lo = and i32 %in0, 65535 |
| %In0Hi = lshr i32 %in0, 16 |
| %In1Lo = and i32 %in1, 65535 |
| %In1Hi = lshr i32 %in1, 16 |
| %m10 = mul i32 %In1Hi, %In0Lo |
| %m01 = mul i32 %In1Lo, %In0Hi |
| %m00 = mul i32 %In1Lo, %In0Lo |
| %addc = add i32 %m10, %m01 |
| %shl = shl i32 %addc, 16 |
| call void @use32(i32 %shl) |
| %retLo = add i32 %shl, %m00 |
| ret i32 %retLo |
| } |