Index: test/Transforms/InstCombine/set-lowbits-mask-canonicalize.ll =================================================================== --- /dev/null +++ test/Transforms/InstCombine/set-lowbits-mask-canonicalize.ll @@ -0,0 +1,294 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt < %s -instcombine -S | FileCheck %s + +; https://bugs.llvm.org/show_bug.cgi?id=37603 + +; Pattern: +; (1 << nbits) - 1 +; Should be transformed into: +; ~(-(1 << nbits)) +; The `not` may end up being folded into `and` + +; ============================================================================ ; +; Most basic positive tests +; ============================================================================ ; + +; No no-wrap tags on shl + +define i32 @shl_add(i32 %nbits) { +; CHECK-LABEL: @shl_add( +; CHECK-NEXT: [[SETBIT:%.*]] = shl i32 1, [[NBITS:%.*]] +; CHECK-NEXT: [[RET:%.*]] = add i32 [[SETBIT]], -1 +; CHECK-NEXT: ret i32 [[RET]] +; + %setbit = shl i32 1, %nbits + %ret = add i32 %setbit, -1 + ret i32 %ret +} + +define i32 @shl_add_nsw(i32 %nbits) { +; CHECK-LABEL: @shl_add_nsw( +; CHECK-NEXT: [[SETBIT:%.*]] = shl i32 1, [[NBITS:%.*]] +; CHECK-NEXT: [[RET:%.*]] = add nsw i32 [[SETBIT]], -1 +; CHECK-NEXT: ret i32 [[RET]] +; + %setbit = shl i32 1, %nbits + %ret = add nsw i32 %setbit, -1 + ret i32 %ret +} + +define i32 @shl_add_nuw(i32 %nbits) { +; CHECK-LABEL: @shl_add_nuw( +; CHECK-NEXT: [[SETBIT:%.*]] = shl i32 1, [[NBITS:%.*]] +; CHECK-NEXT: [[RET:%.*]] = add nuw i32 [[SETBIT]], -1 +; CHECK-NEXT: ret i32 [[RET]] +; + %setbit = shl i32 1, %nbits + %ret = add nuw i32 %setbit, -1 + ret i32 %ret +} + +define i32 @shl_add_nsw_nuw(i32 %nbits) { +; CHECK-LABEL: @shl_add_nsw_nuw( +; CHECK-NEXT: [[SETBIT:%.*]] = shl i32 1, [[NBITS:%.*]] +; CHECK-NEXT: [[RET:%.*]] = add nuw nsw i32 [[SETBIT]], -1 +; CHECK-NEXT: ret i32 [[RET]] +; + %setbit = shl i32 1, %nbits + %ret = add nuw nsw i32 %setbit, -1 + ret i32 %ret +} + +; shl is nsw + +define i32 @shl_nsw_add(i32 %nbits) { +; CHECK-LABEL: @shl_nsw_add( +; CHECK-NEXT: [[SETBIT:%.*]] = shl nsw i32 1, [[NBITS:%.*]] +; CHECK-NEXT: [[RET:%.*]] = add i32 [[SETBIT]], -1 +; CHECK-NEXT: ret i32 [[RET]] +; + %setbit = shl nsw i32 1, %nbits + %ret = add i32 %setbit, -1 + ret i32 %ret +} + +define i32 @shl_nsw_add_nsw(i32 %nbits) { +; CHECK-LABEL: @shl_nsw_add_nsw( +; CHECK-NEXT: [[SETBIT:%.*]] = shl nsw i32 1, [[NBITS:%.*]] +; CHECK-NEXT: [[RET:%.*]] = add nsw i32 [[SETBIT]], -1 +; CHECK-NEXT: ret i32 [[RET]] +; + %setbit = shl nsw i32 1, %nbits + %ret = add nsw i32 %setbit, -1 + ret i32 %ret +} + +define i32 @shl_nsw_add_nuw(i32 %nbits) { +; CHECK-LABEL: @shl_nsw_add_nuw( +; CHECK-NEXT: [[SETBIT:%.*]] = shl nsw i32 1, [[NBITS:%.*]] +; CHECK-NEXT: [[RET:%.*]] = add nuw i32 [[SETBIT]], -1 +; CHECK-NEXT: ret i32 [[RET]] +; + %setbit = shl nsw i32 1, %nbits + %ret = add nuw i32 %setbit, -1 + ret i32 %ret +} + +define i32 @shl_nsw_add_nsw_nuw(i32 %nbits) { +; CHECK-LABEL: @shl_nsw_add_nsw_nuw( +; CHECK-NEXT: [[SETBIT:%.*]] = shl nsw i32 1, [[NBITS:%.*]] +; CHECK-NEXT: [[RET:%.*]] = add nuw nsw i32 [[SETBIT]], -1 +; CHECK-NEXT: ret i32 [[RET]] +; + %setbit = shl nsw i32 1, %nbits + %ret = add nuw nsw i32 %setbit, -1 + ret i32 %ret +} + +; shl is nuw + +define i32 @shl_nuw_add(i32 %nbits) { +; CHECK-LABEL: @shl_nuw_add( +; CHECK-NEXT: [[SETBIT:%.*]] = shl nuw i32 1, [[NBITS:%.*]] +; CHECK-NEXT: [[RET:%.*]] = add i32 [[SETBIT]], -1 +; CHECK-NEXT: ret i32 [[RET]] +; + %setbit = shl nuw i32 1, %nbits + %ret = add i32 %setbit, -1 + ret i32 %ret +} + +define i32 @shl_nuw_add_nsw(i32 %nbits) { +; CHECK-LABEL: @shl_nuw_add_nsw( +; CHECK-NEXT: [[SETBIT:%.*]] = shl nuw i32 1, [[NBITS:%.*]] +; CHECK-NEXT: [[RET:%.*]] = add nsw i32 [[SETBIT]], -1 +; CHECK-NEXT: ret i32 [[RET]] +; + %setbit = shl nuw i32 1, %nbits + %ret = add nsw i32 %setbit, -1 + ret i32 %ret +} + +define i32 @shl_nuw_add_nuw(i32 %nbits) { +; CHECK-LABEL: @shl_nuw_add_nuw( +; CHECK-NEXT: [[SETBIT:%.*]] = shl nuw i32 1, [[NBITS:%.*]] +; CHECK-NEXT: [[RET:%.*]] = add nuw i32 [[SETBIT]], -1 +; CHECK-NEXT: ret i32 [[RET]] +; + %setbit = shl nuw i32 1, %nbits + %ret = add nuw i32 %setbit, -1 + ret i32 %ret +} + +define i32 @shl_nuw_add_nsw_nuw(i32 %nbits) { +; CHECK-LABEL: @shl_nuw_add_nsw_nuw( +; CHECK-NEXT: [[SETBIT:%.*]] = shl nuw i32 1, [[NBITS:%.*]] +; CHECK-NEXT: [[RET:%.*]] = add nuw nsw i32 [[SETBIT]], -1 +; CHECK-NEXT: ret i32 [[RET]] +; + %setbit = shl nuw i32 1, %nbits + %ret = add nuw nsw i32 %setbit, -1 + ret i32 %ret +} + +; shl is nuw nsw + +define i32 @shl_nsw_nuw_add(i32 %nbits) { +; CHECK-LABEL: @shl_nsw_nuw_add( +; CHECK-NEXT: [[SETBIT:%.*]] = shl nuw nsw i32 1, [[NBITS:%.*]] +; CHECK-NEXT: [[RET:%.*]] = add i32 [[SETBIT]], -1 +; CHECK-NEXT: ret i32 [[RET]] +; + %setbit = shl nuw nsw i32 1, %nbits + %ret = add i32 %setbit, -1 + ret i32 %ret +} + +define i32 @shl_nsw_nuw_add_nsw(i32 %nbits) { +; CHECK-LABEL: @shl_nsw_nuw_add_nsw( +; CHECK-NEXT: [[SETBIT:%.*]] = shl nuw nsw i32 1, [[NBITS:%.*]] +; CHECK-NEXT: [[RET:%.*]] = add nsw i32 [[SETBIT]], -1 +; CHECK-NEXT: ret i32 [[RET]] +; + %setbit = shl nuw nsw i32 1, %nbits + %ret = add nsw i32 %setbit, -1 + ret i32 %ret +} + +define i32 @shl_nsw_nuw_add_nuw(i32 %nbits) { +; CHECK-LABEL: @shl_nsw_nuw_add_nuw( +; CHECK-NEXT: [[SETBIT:%.*]] = shl nuw nsw i32 1, [[NBITS:%.*]] +; CHECK-NEXT: [[RET:%.*]] = add nuw i32 [[SETBIT]], -1 +; CHECK-NEXT: ret i32 [[RET]] +; + %setbit = shl nuw nsw i32 1, %nbits + %ret = add nuw i32 %setbit, -1 + ret i32 %ret +} + +define i32 @shl_nsw_nuw_add_nsw_nuw(i32 %nbits) { +; CHECK-LABEL: @shl_nsw_nuw_add_nsw_nuw( +; CHECK-NEXT: [[SETBIT:%.*]] = shl nuw nsw i32 1, [[NBITS:%.*]] +; CHECK-NEXT: [[RET:%.*]] = add nuw nsw i32 [[SETBIT]], -1 +; CHECK-NEXT: ret i32 [[RET]] +; + %setbit = shl nuw nsw i32 1, %nbits + %ret = add nuw nsw i32 %setbit, -1 + ret i32 %ret +} + +; ============================================================================ ; +; Vectors +; ============================================================================ ; + +define <2 x i32> @shl_add_vec(<2 x i32> %nbits) { +; CHECK-LABEL: @shl_add_vec( +; CHECK-NEXT: [[SETBIT:%.*]] = shl <2 x i32> , [[NBITS:%.*]] +; CHECK-NEXT: [[RET:%.*]] = add <2 x i32> [[SETBIT]], +; CHECK-NEXT: ret <2 x i32> [[RET]] +; + %setbit = shl <2 x i32> , %nbits + %ret = add <2 x i32> %setbit, + ret <2 x i32> %ret +} + +define <3 x i32> @shl_add_vec_undef(<3 x i32> %nbits) { +; CHECK-LABEL: @shl_add_vec_undef( +; CHECK-NEXT: [[SETBIT:%.*]] = shl <3 x i32> , [[NBITS:%.*]] +; CHECK-NEXT: [[RET:%.*]] = add <3 x i32> [[SETBIT]], +; CHECK-NEXT: ret <3 x i32> [[RET]] +; + %setbit = shl <3 x i32> , %nbits + %ret = add <3 x i32> %setbit, + ret <3 x i32> %ret +} + +; ============================================================================ ; +; Negative tests. Should not be folded. +; ============================================================================ ; + +declare void @use32(i32) + +; One use only. +define i32 @bad_oneuse0(i32 %nbits) { +; CHECK-LABEL: @bad_oneuse0( +; CHECK-NEXT: [[SETBIT:%.*]] = shl i32 1, [[NBITS:%.*]] +; CHECK-NEXT: call void @use32(i32 [[SETBIT]]) +; CHECK-NEXT: [[RET:%.*]] = add i32 [[SETBIT]], -1 +; CHECK-NEXT: ret i32 [[RET]] +; + %setbit = shl i32 1, %nbits + call void @use32(i32 %setbit) + %ret = add i32 %setbit, -1 + ret i32 %ret +} + +; shift base is not `1` constant + +define i32 @bad_shl(i32 %base, i32 %nbits) { +; CHECK-LABEL: @bad_shl( +; CHECK-NEXT: [[SETBIT:%.*]] = shl i32 [[BASE:%.*]], [[NBITS:%.*]] +; CHECK-NEXT: [[RET:%.*]] = add i32 [[SETBIT]], -1 +; CHECK-NEXT: ret i32 [[RET]] +; + %setbit = shl i32 %base, %nbits ; %base instead of 1 + %ret = add i32 %setbit, -1 + ret i32 %ret +} + +; Second `add` operand is not `-1` constant + +define i32 @bad_add0(i32 %nbits, i32 %addop2) { +; CHECK-LABEL: @bad_add0( +; CHECK-NEXT: [[SETBIT:%.*]] = shl i32 1, [[NBITS:%.*]] +; CHECK-NEXT: [[RET:%.*]] = add i32 [[SETBIT]], [[ADDOP2:%.*]] +; CHECK-NEXT: ret i32 [[RET]] +; + %setbit = shl i32 1, %nbits + %ret = add i32 %setbit, %addop2 + ret i32 %ret +} + +; Bad add constant + +define i32 @bad_add1(i32 %nbits) { +; CHECK-LABEL: @bad_add1( +; CHECK-NEXT: [[SETBIT:%.*]] = shl i32 1, [[NBITS:%.*]] +; CHECK-NEXT: [[RET:%.*]] = add i32 [[SETBIT]], 1 +; CHECK-NEXT: ret i32 [[RET]] +; + %setbit = shl i32 1, %nbits + %ret = add i32 %setbit, 1 ; not -1 + ret i32 %ret +} + +define i32 @bad_add2(i32 %nbits) { +; CHECK-LABEL: @bad_add2( +; CHECK-NEXT: [[SETBIT:%.*]] = shl i32 1, [[NBITS:%.*]] +; CHECK-NEXT: [[RET:%.*]] = add i32 [[SETBIT]], -2 +; CHECK-NEXT: ret i32 [[RET]] +; + %setbit = shl i32 1, %nbits + %ret = add i32 %setbit, -2 ; not -1 + ret i32 %ret +}