| ; 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 |
| } |