Changeset View
Changeset View
Standalone View
Standalone View
llvm/test/Transforms/InstCombine/shift-add.ll
Show First 20 Lines • Show All 428 Lines • ▼ Show 20 Lines | |||||
; | ; | ||||
%a = add i4 %x, 8 | %a = add i4 %x, 8 | ||||
%r = shl nsw i4 2, %a | %r = shl nsw i4 2, %a | ||||
ret i4 %r | ret i4 %r | ||||
} | } | ||||
define i2 @lshr_2_add_zext_basic(i1 %a, i1 %b) { | define i2 @lshr_2_add_zext_basic(i1 %a, i1 %b) { | ||||
; CHECK-LABEL: @lshr_2_add_zext_basic( | ; CHECK-LABEL: @lshr_2_add_zext_basic( | ||||
; CHECK-NEXT: [[TMP1:%.*]] = and i1 [[A:%.*]], [[B:%.*]] | ; CHECK-NEXT: [[TMP1:%.*]] = and i1 [[A:%.*]], [[B:%.*]] | ||||
; CHECK-NEXT: [[LSHR:%.*]] = zext i1 [[TMP1]] to i2 | ; CHECK-NEXT: [[LSHR:%.*]] = zext i1 [[TMP1]] to i2 | ||||
spatel: This is an awkward way to check if 2 bools are set.
We're missing the reduction of boolean math… | |||||
I removed support for types <3 bits; should I leave the test case in? Pierre-vh: I removed support for types <3 bits; should I leave the test case in? | |||||
; CHECK-NEXT: ret i2 [[LSHR]] | ; CHECK-NEXT: ret i2 [[LSHR]] | ||||
; | ; | ||||
%zext.a = zext i1 %a to i2 | %zext.a = zext i1 %a to i2 | ||||
%zext.b = zext i1 %b to i2 | %zext.b = zext i1 %b to i2 | ||||
%add = add i2 %zext.a, %zext.b | %add = add i2 %zext.a, %zext.b | ||||
%lshr = lshr i2 %add, 1 | %lshr = lshr i2 %add, 1 | ||||
ret i2 %lshr | ret i2 %lshr | ||||
} | } | ||||
Show All 10 Lines | ; | ||||
%zext.b = zext i1 %b to i2 | %zext.b = zext i1 %b to i2 | ||||
%add = add i2 %zext.a, %zext.b | %add = add i2 %zext.a, %zext.b | ||||
%lshr = ashr i2 %add, 1 | %lshr = ashr i2 %add, 1 | ||||
ret i2 %lshr | ret i2 %lshr | ||||
} | } | ||||
define i32 @lshr_16_add_zext_basic(i16 %a, i16 %b) { | define i32 @lshr_16_add_zext_basic(i16 %a, i16 %b) { | ||||
; CHECK-LABEL: @lshr_16_add_zext_basic( | ; CHECK-LABEL: @lshr_16_add_zext_basic( | ||||
; CHECK-NEXT: [[ZEXT_A:%.*]] = zext i16 [[A:%.*]] to i32 | ; CHECK-NEXT: [[TMP1:%.*]] = xor i16 [[A:%.*]], -1 | ||||
; CHECK-NEXT: [[ZEXT_B:%.*]] = zext i16 [[B:%.*]] to i32 | ; CHECK-NEXT: [[ADD_NARROWED_OVERFLOW:%.*]] = icmp ult i16 [[TMP1]], [[B:%.*]] | ||||
; CHECK-NEXT: [[ADD:%.*]] = add nuw nsw i32 [[ZEXT_A]], [[ZEXT_B]] | ; CHECK-NEXT: [[LSHR:%.*]] = zext i1 [[ADD_NARROWED_OVERFLOW]] to i32 | ||||
; CHECK-NEXT: [[LSHR:%.*]] = lshr i32 [[ADD]], 16 | |||||
; CHECK-NEXT: ret i32 [[LSHR]] | ; CHECK-NEXT: ret i32 [[LSHR]] | ||||
; | ; | ||||
%zext.a = zext i16 %a to i32 | %zext.a = zext i16 %a to i32 | ||||
%zext.b = zext i16 %b to i32 | %zext.b = zext i16 %b to i32 | ||||
%add = add i32 %zext.a, %zext.b | %add = add i32 %zext.a, %zext.b | ||||
%lshr = lshr i32 %add, 16 | %lshr = lshr i32 %add, 16 | ||||
ret i32 %lshr | ret i32 %lshr | ||||
} | } | ||||
▲ Show 20 Lines • Show All 42 Lines • ▼ Show 20 Lines | ; | ||||
%b16 = and i32 %b, 65535 ; 0x65535 | %b16 = and i32 %b, 65535 ; 0x65535 | ||||
%add = add i32 %a16, %b16 | %add = add i32 %a16, %b16 | ||||
%lshr = lshr i32 %add, 16 | %lshr = lshr i32 %add, 16 | ||||
ret i32 %lshr | ret i32 %lshr | ||||
} | } | ||||
define i64 @lshr_32_add_zext_basic(i32 %a, i32 %b) { | define i64 @lshr_32_add_zext_basic(i32 %a, i32 %b) { | ||||
; CHECK-LABEL: @lshr_32_add_zext_basic( | ; CHECK-LABEL: @lshr_32_add_zext_basic( | ||||
; CHECK-NEXT: [[ZEXT_A:%.*]] = zext i32 [[A:%.*]] to i64 | ; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[A:%.*]], -1 | ||||
; CHECK-NEXT: [[ZEXT_B:%.*]] = zext i32 [[B:%.*]] to i64 | ; CHECK-NEXT: [[ADD_NARROWED_OVERFLOW:%.*]] = icmp ult i32 [[TMP1]], [[B:%.*]] | ||||
; CHECK-NEXT: [[ADD:%.*]] = add nuw nsw i64 [[ZEXT_A]], [[ZEXT_B]] | ; CHECK-NEXT: [[LSHR:%.*]] = zext i1 [[ADD_NARROWED_OVERFLOW]] to i64 | ||||
; CHECK-NEXT: [[LSHR:%.*]] = lshr i64 [[ADD]], 32 | |||||
; CHECK-NEXT: ret i64 [[LSHR]] | ; CHECK-NEXT: ret i64 [[LSHR]] | ||||
; | ; | ||||
%zext.a = zext i32 %a to i64 | %zext.a = zext i32 %a to i64 | ||||
%zext.b = zext i32 %b to i64 | %zext.b = zext i32 %b to i64 | ||||
%add = add i64 %zext.a, %zext.b | %add = add i64 %zext.a, %zext.b | ||||
%lshr = lshr i64 %add, 32 | %lshr = lshr i64 %add, 32 | ||||
ret i64 %lshr | ret i64 %lshr | ||||
} | } | ||||
Show All 38 Lines | ; | ||||
%zext.b = zext i32 %b to i64 | %zext.b = zext i32 %b to i64 | ||||
%add = add i64 %zext.a, %zext.b | %add = add i64 %zext.a, %zext.b | ||||
%lshr = lshr i64 %add, 33 | %lshr = lshr i64 %add, 33 | ||||
ret i64 %lshr | ret i64 %lshr | ||||
} | } | ||||
define i64 @lshr_16_to_64_add_zext_basic(i16 %a, i16 %b) { | define i64 @lshr_16_to_64_add_zext_basic(i16 %a, i16 %b) { | ||||
; CHECK-LABEL: @lshr_16_to_64_add_zext_basic( | ; CHECK-LABEL: @lshr_16_to_64_add_zext_basic( | ||||
; CHECK-NEXT: [[ZEXT_A:%.*]] = zext i16 [[A:%.*]] to i64 | ; CHECK-NEXT: [[TMP1:%.*]] = xor i16 [[A:%.*]], -1 | ||||
; CHECK-NEXT: [[ZEXT_B:%.*]] = zext i16 [[B:%.*]] to i64 | ; CHECK-NEXT: [[ADD_NARROWED_OVERFLOW:%.*]] = icmp ult i16 [[TMP1]], [[B:%.*]] | ||||
; CHECK-NEXT: [[ADD:%.*]] = add nuw nsw i64 [[ZEXT_A]], [[ZEXT_B]] | ; CHECK-NEXT: [[LSHR:%.*]] = zext i1 [[ADD_NARROWED_OVERFLOW]] to i64 | ||||
; CHECK-NEXT: [[LSHR:%.*]] = lshr i64 [[ADD]], 16 | |||||
; CHECK-NEXT: ret i64 [[LSHR]] | ; CHECK-NEXT: ret i64 [[LSHR]] | ||||
; | ; | ||||
%zext.a = zext i16 %a to i64 | %zext.a = zext i16 %a to i64 | ||||
%zext.b = zext i16 %b to i64 | %zext.b = zext i16 %b to i64 | ||||
%add = add i64 %zext.a, %zext.b | %add = add i64 %zext.a, %zext.b | ||||
%lshr = lshr i64 %add, 16 | %lshr = lshr i64 %add, 16 | ||||
ret i64 %lshr | ret i64 %lshr | ||||
} | } | ||||
Show All 26 Lines | ; | ||||
%b32 = and i64 %b, 4294967295 ; 0xFFFFFFFF | %b32 = and i64 %b, 4294967295 ; 0xFFFFFFFF | ||||
%add = add i64 %a32, %b32 | %add = add i64 %a32, %b32 | ||||
%lshr = lshr i64 %add, 32 | %lshr = lshr i64 %add, 32 | ||||
ret i64 %lshr | ret i64 %lshr | ||||
} | } | ||||
define i32 @ashr_16_add_zext_basic(i16 %a, i16 %b) { | define i32 @ashr_16_add_zext_basic(i16 %a, i16 %b) { | ||||
; CHECK-LABEL: @ashr_16_add_zext_basic( | ; CHECK-LABEL: @ashr_16_add_zext_basic( | ||||
; CHECK-NEXT: [[ZEXT_A:%.*]] = zext i16 [[A:%.*]] to i32 | ; CHECK-NEXT: [[TMP1:%.*]] = xor i16 [[A:%.*]], -1 | ||||
; CHECK-NEXT: [[ZEXT_B:%.*]] = zext i16 [[B:%.*]] to i32 | ; CHECK-NEXT: [[ADD_NARROWED_OVERFLOW:%.*]] = icmp ult i16 [[TMP1]], [[B:%.*]] | ||||
; CHECK-NEXT: [[ADD:%.*]] = add nuw nsw i32 [[ZEXT_A]], [[ZEXT_B]] | ; CHECK-NEXT: [[LSHR:%.*]] = zext i1 [[ADD_NARROWED_OVERFLOW]] to i32 | ||||
; CHECK-NEXT: [[LSHR:%.*]] = lshr i32 [[ADD]], 16 | |||||
; CHECK-NEXT: ret i32 [[LSHR]] | ; CHECK-NEXT: ret i32 [[LSHR]] | ||||
; | ; | ||||
%zext.a = zext i16 %a to i32 | %zext.a = zext i16 %a to i32 | ||||
%zext.b = zext i16 %b to i32 | %zext.b = zext i16 %b to i32 | ||||
%add = add i32 %zext.a, %zext.b | %add = add i32 %zext.a, %zext.b | ||||
%lshr = lshr i32 %add, 16 | %lshr = lshr i32 %add, 16 | ||||
ret i32 %lshr | ret i32 %lshr | ||||
} | } | ||||
define i64 @ashr_32_add_zext_basic(i32 %a, i32 %b) { | define i64 @ashr_32_add_zext_basic(i32 %a, i32 %b) { | ||||
; CHECK-LABEL: @ashr_32_add_zext_basic( | ; CHECK-LABEL: @ashr_32_add_zext_basic( | ||||
; CHECK-NEXT: [[ZEXT_A:%.*]] = zext i32 [[A:%.*]] to i64 | ; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[A:%.*]], -1 | ||||
; CHECK-NEXT: [[ZEXT_B:%.*]] = zext i32 [[B:%.*]] to i64 | ; CHECK-NEXT: [[ADD_NARROWED_OVERFLOW:%.*]] = icmp ult i32 [[TMP1]], [[B:%.*]] | ||||
; CHECK-NEXT: [[ADD:%.*]] = add nuw nsw i64 [[ZEXT_A]], [[ZEXT_B]] | ; CHECK-NEXT: [[LSHR:%.*]] = zext i1 [[ADD_NARROWED_OVERFLOW]] to i64 | ||||
; CHECK-NEXT: [[LSHR:%.*]] = lshr i64 [[ADD]], 32 | |||||
For anything but the i1/i2 case, we should convert the ashr to lshr (as happened here and the next test)? spatel: For anything but the i1/i2 case, we should convert the `ashr` to `lshr` (as happened here and… | |||||
Ah I didn't know that, I'll simplify the combine to only check lshr then. Thanks! Pierre-vh: Ah I didn't know that, I'll simplify the combine to only check lshr then. Thanks! | |||||
; CHECK-NEXT: ret i64 [[LSHR]] | ; CHECK-NEXT: ret i64 [[LSHR]] | ||||
; | ; | ||||
%zext.a = zext i32 %a to i64 | %zext.a = zext i32 %a to i64 | ||||
%zext.b = zext i32 %b to i64 | %zext.b = zext i32 %b to i64 | ||||
%add = add i64 %zext.a, %zext.b | %add = add i64 %zext.a, %zext.b | ||||
%lshr = ashr i64 %add, 32 | %lshr = ashr i64 %add, 32 | ||||
ret i64 %lshr | ret i64 %lshr | ||||
} | } | ||||
define i64 @ashr_16_to_64_add_zext_basic(i16 %a, i16 %b) { | define i64 @ashr_16_to_64_add_zext_basic(i16 %a, i16 %b) { | ||||
; CHECK-LABEL: @ashr_16_to_64_add_zext_basic( | ; CHECK-LABEL: @ashr_16_to_64_add_zext_basic( | ||||
; CHECK-NEXT: [[ZEXT_A:%.*]] = zext i16 [[A:%.*]] to i64 | ; CHECK-NEXT: [[TMP1:%.*]] = xor i16 [[A:%.*]], -1 | ||||
; CHECK-NEXT: [[ZEXT_B:%.*]] = zext i16 [[B:%.*]] to i64 | ; CHECK-NEXT: [[ADD_NARROWED_OVERFLOW:%.*]] = icmp ult i16 [[TMP1]], [[B:%.*]] | ||||
; CHECK-NEXT: [[ADD:%.*]] = add nuw nsw i64 [[ZEXT_A]], [[ZEXT_B]] | ; CHECK-NEXT: [[LSHR:%.*]] = zext i1 [[ADD_NARROWED_OVERFLOW]] to i64 | ||||
; CHECK-NEXT: [[LSHR:%.*]] = lshr i64 [[ADD]], 16 | |||||
; CHECK-NEXT: ret i64 [[LSHR]] | ; CHECK-NEXT: ret i64 [[LSHR]] | ||||
; | ; | ||||
%zext.a = zext i16 %a to i64 | %zext.a = zext i16 %a to i64 | ||||
%zext.b = zext i16 %b to i64 | %zext.b = zext i16 %b to i64 | ||||
%add = add i64 %zext.a, %zext.b | %add = add i64 %zext.a, %zext.b | ||||
%lshr = ashr i64 %add, 16 | %lshr = ashr i64 %add, 16 | ||||
ret i64 %lshr | ret i64 %lshr | ||||
} | } | ||||
define i32 @lshr_32_add_zext_trunc(i32 %a, i32 %b) { | define i32 @lshr_32_add_zext_trunc(i32 %a, i32 %b) { | ||||
; CHECK-LABEL: @lshr_32_add_zext_trunc( | ; CHECK-LABEL: @lshr_32_add_zext_trunc( | ||||
; CHECK-NEXT: [[ZEXT_A:%.*]] = zext i32 [[A:%.*]] to i64 | ; CHECK-NEXT: [[ADD_NARROWED:%.*]] = add i32 [[A:%.*]], [[B:%.*]] | ||||
; CHECK-NEXT: [[ZEXT_B:%.*]] = zext i32 [[B:%.*]] to i64 | ; CHECK-NEXT: [[ADD_NARROWED_OVERFLOW:%.*]] = icmp ult i32 [[ADD_NARROWED]], [[A]] | ||||
; CHECK-NEXT: [[ADD:%.*]] = add nuw nsw i64 [[ZEXT_A]], [[ZEXT_B]] | ; CHECK-NEXT: [[TRUNC_SHR:%.*]] = zext i1 [[ADD_NARROWED_OVERFLOW]] to i32 | ||||
; CHECK-NEXT: [[TRUNC_ADD:%.*]] = trunc i64 [[ADD]] to i32 | ; CHECK-NEXT: [[RET:%.*]] = add i32 [[ADD_NARROWED]], [[TRUNC_SHR]] | ||||
; CHECK-NEXT: [[SHR:%.*]] = lshr i64 [[ADD]], 32 | |||||
; CHECK-NEXT: [[TRUNC_SHR:%.*]] = trunc i64 [[SHR]] to i32 | |||||
; CHECK-NEXT: [[RET:%.*]] = add i32 [[TRUNC_ADD]], [[TRUNC_SHR]] | |||||
; CHECK-NEXT: ret i32 [[RET]] | ; CHECK-NEXT: ret i32 [[RET]] | ||||
; | ; | ||||
%zext.a = zext i32 %a to i64 | %zext.a = zext i32 %a to i64 | ||||
%zext.b = zext i32 %b to i64 | %zext.b = zext i32 %b to i64 | ||||
%add = add i64 %zext.a, %zext.b | %add = add i64 %zext.a, %zext.b | ||||
%trunc.add = trunc i64 %add to i32 | %trunc.add = trunc i64 %add to i32 | ||||
%shr = lshr i64 %add, 32 | %shr = lshr i64 %add, 32 | ||||
%trunc.shr = trunc i64 %shr to i32 | %trunc.shr = trunc i64 %shr to i32 | ||||
%ret = add i32 %trunc.add, %trunc.shr | %ret = add i32 %trunc.add, %trunc.shr | ||||
ret i32 %ret | ret i32 %ret | ||||
} | } | ||||
define <3 x i32> @add3_i96(<3 x i32> %0, <3 x i32> %1) { | define <3 x i32> @add3_i96(<3 x i32> %0, <3 x i32> %1) { | ||||
; CHECK-LABEL: @add3_i96( | ; CHECK-LABEL: @add3_i96( | ||||
; CHECK-NEXT: [[TMP3:%.*]] = extractelement <3 x i32> [[TMP0:%.*]], i64 0 | ; CHECK-NEXT: [[TMP3:%.*]] = extractelement <3 x i32> [[TMP0:%.*]], i64 0 | ||||
; CHECK-NEXT: [[TMP4:%.*]] = zext i32 [[TMP3]] to i64 | ; CHECK-NEXT: [[TMP4:%.*]] = extractelement <3 x i32> [[TMP1:%.*]], i64 0 | ||||
; CHECK-NEXT: [[TMP5:%.*]] = extractelement <3 x i32> [[TMP1:%.*]], i64 0 | ; CHECK-NEXT: [[ADD_NARROWED:%.*]] = add i32 [[TMP4]], [[TMP3]] | ||||
; CHECK-NEXT: [[ADD_NARROWED_OVERFLOW:%.*]] = icmp ult i32 [[ADD_NARROWED]], [[TMP4]] | |||||
; CHECK-NEXT: [[TMP5:%.*]] = extractelement <3 x i32> [[TMP0]], i64 1 | |||||
; CHECK-NEXT: [[TMP6:%.*]] = zext i32 [[TMP5]] to i64 | ; CHECK-NEXT: [[TMP6:%.*]] = zext i32 [[TMP5]] to i64 | ||||
; CHECK-NEXT: [[TMP7:%.*]] = add nuw nsw i64 [[TMP6]], [[TMP4]] | ; CHECK-NEXT: [[TMP7:%.*]] = extractelement <3 x i32> [[TMP1]], i64 1 | ||||
; CHECK-NEXT: [[TMP8:%.*]] = extractelement <3 x i32> [[TMP0]], i64 1 | ; CHECK-NEXT: [[TMP8:%.*]] = zext i32 [[TMP7]] to i64 | ||||
; CHECK-NEXT: [[TMP9:%.*]] = zext i32 [[TMP8]] to i64 | ; CHECK-NEXT: [[TMP9:%.*]] = add nuw nsw i64 [[TMP8]], [[TMP6]] | ||||
; CHECK-NEXT: [[TMP10:%.*]] = extractelement <3 x i32> [[TMP1]], i64 1 | ; CHECK-NEXT: [[TMP10:%.*]] = zext i1 [[ADD_NARROWED_OVERFLOW]] to i64 | ||||
; CHECK-NEXT: [[TMP11:%.*]] = zext i32 [[TMP10]] to i64 | ; CHECK-NEXT: [[TMP11:%.*]] = add nuw nsw i64 [[TMP9]], [[TMP10]] | ||||
; CHECK-NEXT: [[TMP12:%.*]] = add nuw nsw i64 [[TMP11]], [[TMP9]] | ; CHECK-NEXT: [[TMP12:%.*]] = extractelement <3 x i32> [[TMP0]], i64 2 | ||||
; CHECK-NEXT: [[TMP13:%.*]] = lshr i64 [[TMP7]], 32 | ; CHECK-NEXT: [[TMP13:%.*]] = extractelement <3 x i32> [[TMP1]], i64 2 | ||||
; CHECK-NEXT: [[TMP14:%.*]] = add nuw nsw i64 [[TMP12]], [[TMP13]] | ; CHECK-NEXT: [[TMP14:%.*]] = add i32 [[TMP13]], [[TMP12]] | ||||
; CHECK-NEXT: [[TMP15:%.*]] = extractelement <3 x i32> [[TMP0]], i64 2 | ; CHECK-NEXT: [[TMP15:%.*]] = lshr i64 [[TMP11]], 32 | ||||
; CHECK-NEXT: [[TMP16:%.*]] = extractelement <3 x i32> [[TMP1]], i64 2 | ; CHECK-NEXT: [[TMP16:%.*]] = trunc i64 [[TMP15]] to i32 | ||||
; CHECK-NEXT: [[TMP17:%.*]] = add i32 [[TMP16]], [[TMP15]] | ; CHECK-NEXT: [[TMP17:%.*]] = add i32 [[TMP14]], [[TMP16]] | ||||
; CHECK-NEXT: [[TMP18:%.*]] = lshr i64 [[TMP14]], 32 | ; CHECK-NEXT: [[TMP18:%.*]] = insertelement <3 x i32> undef, i32 [[ADD_NARROWED]], i64 0 | ||||
; CHECK-NEXT: [[TMP19:%.*]] = trunc i64 [[TMP18]] to i32 | ; CHECK-NEXT: [[TMP19:%.*]] = trunc i64 [[TMP11]] to i32 | ||||
; CHECK-NEXT: [[TMP20:%.*]] = add i32 [[TMP17]], [[TMP19]] | ; CHECK-NEXT: [[TMP20:%.*]] = insertelement <3 x i32> [[TMP18]], i32 [[TMP19]], i64 1 | ||||
; CHECK-NEXT: [[TMP21:%.*]] = trunc i64 [[TMP7]] to i32 | ; CHECK-NEXT: [[TMP21:%.*]] = insertelement <3 x i32> [[TMP20]], i32 [[TMP17]], i64 2 | ||||
; CHECK-NEXT: [[TMP22:%.*]] = insertelement <3 x i32> undef, i32 [[TMP21]], i64 0 | ; CHECK-NEXT: ret <3 x i32> [[TMP21]] | ||||
; CHECK-NEXT: [[TMP23:%.*]] = trunc i64 [[TMP14]] to i32 | |||||
; CHECK-NEXT: [[TMP24:%.*]] = insertelement <3 x i32> [[TMP22]], i32 [[TMP23]], i64 1 | |||||
; CHECK-NEXT: [[TMP25:%.*]] = insertelement <3 x i32> [[TMP24]], i32 [[TMP20]], i64 2 | |||||
; CHECK-NEXT: ret <3 x i32> [[TMP25]] | |||||
; | ; | ||||
%3 = extractelement <3 x i32> %0, i64 0 | %3 = extractelement <3 x i32> %0, i64 0 | ||||
%4 = zext i32 %3 to i64 | %4 = zext i32 %3 to i64 | ||||
%5 = extractelement <3 x i32> %1, i64 0 | %5 = extractelement <3 x i32> %1, i64 0 | ||||
%6 = zext i32 %5 to i64 | %6 = zext i32 %5 to i64 | ||||
%7 = add nuw nsw i64 %6, %4 | %7 = add nuw nsw i64 %6, %4 | ||||
%8 = extractelement <3 x i32> %0, i64 1 | %8 = extractelement <3 x i32> %0, i64 1 | ||||
%9 = zext i32 %8 to i64 | %9 = zext i32 %8 to i64 | ||||
Show All 18 Lines |
This is an awkward way to check if 2 bools are set.
We're missing the reduction of boolean math to logic either way:
https://alive2.llvm.org/ce/z/4dBQhx