blob: c90f08b7322ac5a7221ca1ae5a335e92b9f55a09 [file] [edit]
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
; RUN: opt -passes=instcombine %s -S | FileCheck %s
declare void @use.i32(i32)
declare void @use.i64(i64)
define i64 @full_shl(i32 %x) {
; CHECK-LABEL: define i64 @full_shl(
; CHECK-SAME: i32 [[X:%.*]]) {
; CHECK-NEXT: [[X_ZEXT:%.*]] = zext i32 [[X]] to i64
; CHECK-NEXT: [[LO_SHL:%.*]] = shl nuw nsw i64 [[X_ZEXT]], 24
; CHECK-NEXT: ret i64 [[LO_SHL]]
;
%lo = and i32 %x, u0xffff
%lo.zext = zext nneg i32 %lo to i64
%lo.shl = shl nuw nsw i64 %lo.zext, 24
%hi = lshr i32 %x, 16
%hi.zext = zext nneg i32 %hi to i64
%hi.shl = shl nuw nsw i64 %hi.zext, 40
%res = or disjoint i64 %lo.shl, %hi.shl
ret i64 %res
}
define <2 x i64> @full_shl_vec(<2 x i32> %v) {
; CHECK-LABEL: define <2 x i64> @full_shl_vec(
; CHECK-SAME: <2 x i32> [[V:%.*]]) {
; CHECK-NEXT: [[V_ZEXT:%.*]] = zext <2 x i32> [[V]] to <2 x i64>
; CHECK-NEXT: [[LO_SHL:%.*]] = shl nuw nsw <2 x i64> [[V_ZEXT]], splat (i64 24)
; CHECK-NEXT: ret <2 x i64> [[LO_SHL]]
;
%lo = and <2 x i32> %v, splat(i32 u0xffff)
%lo.zext = zext nneg <2 x i32> %lo to <2 x i64>
%lo.shl = shl nuw nsw <2 x i64> %lo.zext, splat(i64 24)
%hi = lshr <2 x i32> %v, splat(i32 16)
%hi.zext = zext nneg <2 x i32> %hi to <2 x i64>
%hi.shl = shl nuw nsw <2 x i64> %hi.zext, splat(i64 40)
%res = or disjoint <2 x i64> %lo.shl, %hi.shl
ret <2 x i64> %res
}
; u0xaabbccdd = -1430532899
define i64 @partial_shl(i32 %x) {
; CHECK-LABEL: define i64 @partial_shl(
; CHECK-SAME: i32 [[X:%.*]]) {
; CHECK-NEXT: [[X_MASK:%.*]] = and i32 [[X]], -1430532899
; CHECK-NEXT: [[X_ZEXT:%.*]] = zext i32 [[X_MASK]] to i64
; CHECK-NEXT: [[LO_SHL:%.*]] = shl nuw nsw i64 [[X_ZEXT]], 24
; CHECK-NEXT: ret i64 [[LO_SHL]]
;
%lo = and i32 %x, u0xccdd
%lo.zext = zext nneg i32 %lo to i64
%lo.shl = shl nuw nsw i64 %lo.zext, 24
%hi = lshr i32 %x, 16
%hi.mask = and i32 %hi, u0xaabb
%hi.zext = zext nneg i32 %hi.mask to i64
%hi.shl = shl nuw nsw i64 %hi.zext, 40
%res = or disjoint i64 %lo.shl, %hi.shl
ret i64 %res
}
define i64 @shl_multi_use_shl(i32 %x) {
; CHECK-LABEL: define i64 @shl_multi_use_shl(
; CHECK-SAME: i32 [[X:%.*]]) {
; CHECK-NEXT: [[TMP1:%.*]] = shl i32 [[X]], 24
; CHECK-NEXT: [[LO_SHL:%.*]] = zext i32 [[TMP1]] to i64
; CHECK-NEXT: call void @use.i64(i64 [[LO_SHL]])
; CHECK-NEXT: [[HI:%.*]] = lshr i32 [[X]], 16
; CHECK-NEXT: [[HI_ZEXT:%.*]] = zext nneg i32 [[HI]] to i64
; CHECK-NEXT: [[HI_SHL:%.*]] = shl nuw nsw i64 [[HI_ZEXT]], 40
; CHECK-NEXT: [[RES:%.*]] = or disjoint i64 [[HI_SHL]], [[LO_SHL]]
; CHECK-NEXT: ret i64 [[RES]]
;
%lo = and i32 %x, u0x00ff
%lo.zext = zext nneg i32 %lo to i64
%lo.shl = shl nuw nsw i64 %lo.zext, 24
call void @use.i64(i64 %lo.shl)
%hi = lshr i32 %x, 16
%hi.zext = zext nneg i32 %hi to i64
%hi.shl = shl nuw nsw i64 %hi.zext, 40
%res = or disjoint i64 %lo.shl, %hi.shl
ret i64 %res
}
define i64 @shl_multi_use_zext(i32 %x) {
; CHECK-LABEL: define i64 @shl_multi_use_zext(
; CHECK-SAME: i32 [[X:%.*]]) {
; CHECK-NEXT: [[LO:%.*]] = and i32 [[X]], 255
; CHECK-NEXT: [[LO_ZEXT:%.*]] = zext nneg i32 [[LO]] to i64
; CHECK-NEXT: call void @use.i64(i64 [[LO_ZEXT]])
; CHECK-NEXT: [[LO_SHL:%.*]] = shl nuw nsw i64 [[LO_ZEXT]], 24
; CHECK-NEXT: [[HI:%.*]] = lshr i32 [[X]], 16
; CHECK-NEXT: [[HI_ZEXT:%.*]] = zext nneg i32 [[HI]] to i64
; CHECK-NEXT: [[HI_SHL:%.*]] = shl nuw nsw i64 [[HI_ZEXT]], 40
; CHECK-NEXT: [[RES:%.*]] = or disjoint i64 [[LO_SHL]], [[HI_SHL]]
; CHECK-NEXT: ret i64 [[RES]]
;
%lo = and i32 %x, u0x00ff
%lo.zext = zext nneg i32 %lo to i64
call void @use.i64(i64 %lo.zext)
%lo.shl = shl nuw nsw i64 %lo.zext, 24
%hi = lshr i32 %x, 16
%hi.zext = zext nneg i32 %hi to i64
%hi.shl = shl nuw nsw i64 %hi.zext, 40
%res = or disjoint i64 %lo.shl, %hi.shl
ret i64 %res
}
define i64 @shl_multi_use_lshr(i32 %x) {
; CHECK-LABEL: define i64 @shl_multi_use_lshr(
; CHECK-SAME: i32 [[X:%.*]]) {
; CHECK-NEXT: [[TMP1:%.*]] = shl i32 [[X]], 24
; CHECK-NEXT: [[LO_SHL:%.*]] = zext i32 [[TMP1]] to i64
; CHECK-NEXT: [[HI:%.*]] = lshr i32 [[X]], 16
; CHECK-NEXT: call void @use.i32(i32 [[HI]])
; CHECK-NEXT: [[HI_ZEXT:%.*]] = zext nneg i32 [[HI]] to i64
; CHECK-NEXT: [[HI_SHL:%.*]] = shl nuw nsw i64 [[HI_ZEXT]], 40
; CHECK-NEXT: [[RES:%.*]] = or disjoint i64 [[HI_SHL]], [[LO_SHL]]
; CHECK-NEXT: ret i64 [[RES]]
;
%lo = and i32 %x, u0x00ff
%lo.zext = zext nneg i32 %lo to i64
%lo.shl = shl nuw nsw i64 %lo.zext, 24
%hi = lshr i32 %x, 16
call void @use.i32(i32 %hi)
%hi.zext = zext nneg i32 %hi to i64
%hi.shl = shl nuw nsw i64 %hi.zext, 40
%res = or disjoint i64 %lo.shl, %hi.shl
ret i64 %res
}
define i64 @shl_non_disjoint(i32 %x) {
; CHECK-LABEL: define i64 @shl_non_disjoint(
; CHECK-SAME: i32 [[X:%.*]]) {
; CHECK-NEXT: [[LO:%.*]] = and i32 [[X]], 16711680
; CHECK-NEXT: [[LO_ZEXT:%.*]] = zext nneg i32 [[LO]] to i64
; CHECK-NEXT: [[LO_SHL:%.*]] = shl nuw nsw i64 [[LO_ZEXT]], 24
; CHECK-NEXT: [[HI:%.*]] = lshr i32 [[X]], 16
; CHECK-NEXT: call void @use.i32(i32 [[HI]])
; CHECK-NEXT: [[HI_ZEXT:%.*]] = zext nneg i32 [[HI]] to i64
; CHECK-NEXT: [[HI_SHL:%.*]] = shl nuw nsw i64 [[HI_ZEXT]], 40
; CHECK-NEXT: [[RES:%.*]] = or i64 [[LO_SHL]], [[HI_SHL]]
; CHECK-NEXT: ret i64 [[RES]]
;
%lo = and i32 %x, u0x00ff0000
%lo.zext = zext nneg i32 %lo to i64
%lo.shl = shl nuw nsw i64 %lo.zext, 24
%hi = lshr i32 %x, 16
call void @use.i32(i32 %hi)
%hi.zext = zext nneg i32 %hi to i64
%hi.shl = shl nuw nsw i64 %hi.zext, 40
%res = or i64 %lo.shl, %hi.shl
ret i64 %res
}
define i64 @combine(i32 %lower, i32 %upper) {
; CHECK-LABEL: define i64 @combine(
; CHECK-SAME: i32 [[LOWER:%.*]], i32 [[UPPER:%.*]]) {
; CHECK-NEXT: [[BASE:%.*]] = zext i32 [[LOWER]] to i64
; CHECK-NEXT: [[UPPER_ZEXT:%.*]] = zext i32 [[UPPER]] to i64
; CHECK-NEXT: [[S_0:%.*]] = shl nuw i64 [[UPPER_ZEXT]], 32
; CHECK-NEXT: [[O_3:%.*]] = or disjoint i64 [[S_0]], [[BASE]]
; CHECK-NEXT: ret i64 [[O_3]]
;
%base = zext i32 %lower to i64
%u.0 = and i32 %upper, u0xff
%z.0 = zext i32 %u.0 to i64
%s.0 = shl i64 %z.0, 32
%o.0 = or i64 %base, %s.0
%r.1 = lshr i32 %upper, 8
%u.1 = and i32 %r.1, u0xff
%z.1 = zext i32 %u.1 to i64
%s.1 = shl i64 %z.1, 40
%o.1 = or i64 %o.0, %s.1
%r.2 = lshr i32 %upper, 16
%u.2 = and i32 %r.2, u0xff
%z.2 = zext i32 %u.2 to i64
%s.2 = shl i64 %z.2, 48
%o.2 = or i64 %o.1, %s.2
%r.3 = lshr i32 %upper, 24
%u.3 = and i32 %r.3, u0xff
%z.3 = zext i32 %u.3 to i64
%s.3 = shl i64 %z.3, 56
%o.3 = or i64 %o.2, %s.3
ret i64 %o.3
}
define i64 @combine_2(i32 %lower, i32 %upper) {
; CHECK-LABEL: define i64 @combine_2(
; CHECK-SAME: i32 [[LOWER:%.*]], i32 [[UPPER:%.*]]) {
; CHECK-NEXT: [[BASE:%.*]] = zext i32 [[LOWER]] to i64
; CHECK-NEXT: [[S_03:%.*]] = zext i32 [[UPPER]] to i64
; CHECK-NEXT: [[O:%.*]] = shl nuw i64 [[S_03]], 32
; CHECK-NEXT: [[RES:%.*]] = or disjoint i64 [[O]], [[BASE]]
; CHECK-NEXT: ret i64 [[RES]]
;
%base = zext i32 %lower to i64
%u.0 = and i32 %upper, u0xff
%z.0 = zext i32 %u.0 to i64
%s.0 = shl i64 %z.0, 32
%r.1 = lshr i32 %upper, 8
%u.1 = and i32 %r.1, u0xff
%z.1 = zext i32 %u.1 to i64
%s.1 = shl i64 %z.1, 40
%o.1 = or i64 %s.0, %s.1
%r.2 = lshr i32 %upper, 16
%u.2 = and i32 %r.2, u0xff
%z.2 = zext i32 %u.2 to i64
%s.2 = shl i64 %z.2, 48
%r.3 = lshr i32 %upper, 24
%u.3 = and i32 %r.3, u0xff
%z.3 = zext i32 %u.3 to i64
%s.3 = shl i64 %z.3, 56
%o.3 = or i64 %s.2, %s.3
%o = or i64 %o.1, %o.3
%res = or i64 %o, %base
ret i64 %res
}