1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py 2; RUN: opt < %s -reassociate -S | FileCheck %s 3 4; Basic pattern where two contiguous i8 loads form a wider i16 load 5define i16 @p0_i8_i8_i16(i8* %ptr) { 6; CHECK-LABEL: @p0_i8_i8_i16( 7; CHECK-NEXT: [[I:%.*]] = getelementptr inbounds i8, i8* [[PTR:%.*]], i64 1 8; CHECK-NEXT: [[I2:%.*]] = load i8, i8* [[I]], align 1 9; CHECK-NEXT: [[I3:%.*]] = zext i8 [[I2]] to i16 10; CHECK-NEXT: [[I4:%.*]] = shl i16 [[I3]], 8 11; CHECK-NEXT: [[I5:%.*]] = load i8, i8* [[PTR]], align 1 12; CHECK-NEXT: [[I6:%.*]] = zext i8 [[I5]] to i16 13; CHECK-NEXT: [[I7:%.*]] = or i16 [[I4]], [[I6]] 14; CHECK-NEXT: [[I8:%.*]] = add i16 [[I7]], 42 15; CHECK-NEXT: ret i16 [[I8]] 16; 17 %i = getelementptr inbounds i8, i8* %ptr, i64 1 18 %i2 = load i8, i8* %i 19 %i3 = zext i8 %i2 to i16 20 %i4 = shl i16 %i3, 8 21 %i5 = load i8, i8* %ptr 22 %i6 = zext i8 %i5 to i16 23 %i7 = or i16 %i4, %i6 24 %i8 = add i16 %i7, 42 25 ret i16 %i8 26} 27 28; Basic pattern where two contiguous i8 loads form a wider i16 load, with swapped endianness 29define i16 @p1_i8_i8_i16_swapped(i8* %ptr) { 30; CHECK-LABEL: @p1_i8_i8_i16_swapped( 31; CHECK-NEXT: [[I:%.*]] = load i8, i8* [[PTR:%.*]], align 1 32; CHECK-NEXT: [[I2:%.*]] = zext i8 [[I]] to i16 33; CHECK-NEXT: [[I3:%.*]] = shl i16 [[I2]], 8 34; CHECK-NEXT: [[I4:%.*]] = getelementptr inbounds i8, i8* [[PTR]], i64 1 35; CHECK-NEXT: [[I5:%.*]] = load i8, i8* [[I4]], align 1 36; CHECK-NEXT: [[I6:%.*]] = zext i8 [[I5]] to i16 37; CHECK-NEXT: [[I7:%.*]] = or i16 [[I3]], [[I6]] 38; CHECK-NEXT: [[I8:%.*]] = add i16 [[I7]], 42 39; CHECK-NEXT: ret i16 [[I8]] 40; 41 %i = load i8, i8* %ptr 42 %i2 = zext i8 %i to i16 43 %i3 = shl i16 %i2, 8 44 %i4 = getelementptr inbounds i8, i8* %ptr, i64 1 45 %i5 = load i8, i8* %i4 46 %i6 = zext i8 %i5 to i16 47 %i7 = or i16 %i3, %i6 48 %i8 = add i16 %i7, 42 49 ret i16 %i8 50} 51 52; Loads are spaced out by a bit, but we don't check for that. 53define i16 @p2(i8* %ptr) { 54; CHECK-LABEL: @p2( 55; CHECK-NEXT: [[I:%.*]] = getelementptr inbounds i8, i8* [[PTR:%.*]], i64 1 56; CHECK-NEXT: [[I2:%.*]] = load i8, i8* [[I]], align 1 57; CHECK-NEXT: [[I3:%.*]] = zext i8 [[I2]] to i16 58; CHECK-NEXT: [[I4:%.*]] = shl i16 [[I3]], 9 59; CHECK-NEXT: [[I5:%.*]] = load i8, i8* [[PTR]], align 1 60; CHECK-NEXT: [[I6:%.*]] = zext i8 [[I5]] to i16 61; CHECK-NEXT: [[I7:%.*]] = or i16 [[I4]], [[I6]] 62; CHECK-NEXT: [[I8:%.*]] = add i16 [[I7]], 42 63; CHECK-NEXT: ret i16 [[I8]] 64; 65 %i = getelementptr inbounds i8, i8* %ptr, i64 1 66 %i2 = load i8, i8* %i 67 %i3 = zext i8 %i2 to i16 68 %i4 = shl i16 %i3, 9 ; wrong shift amount 69 %i5 = load i8, i8* %ptr 70 %i6 = zext i8 %i5 to i16 71 %i7 = or i16 %i4, %i6 72 %i8 = add i16 %i7, 42 73 ret i16 %i8 74} 75 76; Both bytes are the same, but we don't check for that. 77define i16 @p3(i8* %ptr) { 78; CHECK-LABEL: @p3( 79; CHECK-NEXT: [[I:%.*]] = load i8, i8* [[PTR:%.*]], align 1 80; CHECK-NEXT: [[I2:%.*]] = zext i8 [[I]] to i16 81; CHECK-NEXT: [[I3:%.*]] = shl i16 [[I2]], 8 82; CHECK-NEXT: [[I4:%.*]] = or i16 [[I3]], [[I2]] 83; CHECK-NEXT: [[I5:%.*]] = add i16 [[I4]], 42 84; CHECK-NEXT: ret i16 [[I5]] 85; 86 %i = load i8, i8* %ptr 87 %i2 = zext i8 %i to i16 88 %i3 = shl i16 %i2, 8 89 %i4 = or i16 %i3, %i2 90 %i5 = add i16 %i4, 42 91 ret i16 %i5 92} 93 94; ---------------------------------------------------------------------------- ; 95; Negative tests, should be transformed. 96 97; Low bits are not a load 98define i16 @n4(i8* %ptr) { 99; CHECK-LABEL: @n4( 100; CHECK-NEXT: [[I:%.*]] = load i8, i8* [[PTR:%.*]], align 1 101; CHECK-NEXT: [[I2:%.*]] = zext i8 [[I]] to i16 102; CHECK-NEXT: [[I3:%.*]] = shl i16 [[I2]], 8 103; CHECK-NEXT: [[I5:%.*]] = add i16 [[I3]], 84 104; CHECK-NEXT: ret i16 [[I5]] 105; 106 %i = load i8, i8* %ptr 107 %i2 = zext i8 %i to i16 108 %i3 = shl i16 %i2, 8 109 %i4 = or i16 %i3, 42 ; Second operand is bad 110 %i5 = add i16 %i4, 42 111 ret i16 %i5 112} 113 114; Low bits are not a load 115define i16 @n5(i8* %ptr, i8 %lowbits) { 116; CHECK-LABEL: @n5( 117; CHECK-NEXT: [[I:%.*]] = load i8, i8* [[PTR:%.*]], align 1 118; CHECK-NEXT: [[I2:%.*]] = zext i8 [[I]] to i16 119; CHECK-NEXT: [[I3:%.*]] = shl i16 [[I2]], 8 120; CHECK-NEXT: [[I4:%.*]] = zext i8 [[LOWBITS:%.*]] to i16 121; CHECK-NEXT: [[I5:%.*]] = add i16 [[I4]], 42 122; CHECK-NEXT: [[I6:%.*]] = add i16 [[I5]], [[I3]] 123; CHECK-NEXT: ret i16 [[I6]] 124; 125 %i = load i8, i8* %ptr 126 %i2 = zext i8 %i to i16 127 %i3 = shl i16 %i2, 8 128 %i4 = zext i8 %lowbits to i16 ; base operand is bad 129 %i5 = or i16 %i3, %i4 130 %i6 = add i16 %i5, 42 131 ret i16 %i6 132} 133 134; High bits are not a load 135define i16 @n6(i8* %ptr, i8 %highbits) { 136; CHECK-LABEL: @n6( 137; CHECK-NEXT: [[I:%.*]] = getelementptr inbounds i8, i8* [[PTR:%.*]], i64 1 138; CHECK-NEXT: [[I4:%.*]] = shl i16 42, 8 139; CHECK-NEXT: [[I5:%.*]] = load i8, i8* [[PTR]], align 1 140; CHECK-NEXT: [[I6:%.*]] = zext i8 [[I5]] to i16 141; CHECK-NEXT: [[I7:%.*]] = add i16 [[I4]], 42 142; CHECK-NEXT: [[I8:%.*]] = add i16 [[I7]], [[I6]] 143; CHECK-NEXT: ret i16 [[I8]] 144; 145 %i = getelementptr inbounds i8, i8* %ptr, i64 1 146 %i2 = load i8, i8* %i 147 %i4 = shl i16 42, 8 ; base operand is bad 148 %i5 = load i8, i8* %ptr 149 %i6 = zext i8 %i5 to i16 150 %i7 = or i16 %i4, %i6 151 %i8 = add i16 %i7, 42 152 ret i16 %i8 153} 154