brintos

brintos / llvm-project-archived public Read only

0
0
Text · 23.4 KiB · e573108 Raw
664 lines · plain
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py2; RUN: opt < %s -passes=instcombine -S | FileCheck %s3 4target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:128:128"5 6; Canonicalize or(shl,lshr) by constant to funnel shift intrinsics.7; This should help cost modeling for vectorization, inlining, etc.8; If a target does not have a fshl instruction, the expansion will9; be exactly these same 3 basic ops (shl/lshr/or).10 11define i32 @fshl_i32_constant(i32 %x, i32 %y) {12; CHECK-LABEL: @fshl_i32_constant(13; CHECK-NEXT:    [[R:%.*]] = call i32 @llvm.fshl.i32(i32 [[X:%.*]], i32 [[Y:%.*]], i32 11)14; CHECK-NEXT:    ret i32 [[R]]15;16  %shl = shl i32 %x, 1117  %shr = lshr i32 %y, 2118  %r = or i32 %shr, %shl19  ret i32 %r20}21 22define i42 @fshr_i42_constant(i42 %x, i42 %y) {23; CHECK-LABEL: @fshr_i42_constant(24; CHECK-NEXT:    [[R:%.*]] = call i42 @llvm.fshl.i42(i42 [[Y:%.*]], i42 [[X:%.*]], i42 11)25; CHECK-NEXT:    ret i42 [[R]]26;27  %shr = lshr i42 %x, 3128  %shl = shl i42 %y, 1129  %r = or i42 %shr, %shl30  ret i42 %r31}32 33; Vector types are allowed.34 35define <2 x i16> @fshl_v2i16_constant_splat(<2 x i16> %x, <2 x i16> %y) {36; CHECK-LABEL: @fshl_v2i16_constant_splat(37; CHECK-NEXT:    [[R:%.*]] = call <2 x i16> @llvm.fshl.v2i16(<2 x i16> [[X:%.*]], <2 x i16> [[Y:%.*]], <2 x i16> splat (i16 1))38; CHECK-NEXT:    ret <2 x i16> [[R]]39;40  %shl = shl <2 x i16> %x, <i16 1, i16 1>41  %shr = lshr <2 x i16> %y, <i16 15, i16 15>42  %r = or <2 x i16> %shl, %shr43  ret <2 x i16> %r44}45 46define <2 x i16> @fshl_v2i16_constant_splat_poison0(<2 x i16> %x, <2 x i16> %y) {47; CHECK-LABEL: @fshl_v2i16_constant_splat_poison0(48; CHECK-NEXT:    [[R:%.*]] = call <2 x i16> @llvm.fshl.v2i16(<2 x i16> [[X:%.*]], <2 x i16> [[Y:%.*]], <2 x i16> splat (i16 1))49; CHECK-NEXT:    ret <2 x i16> [[R]]50;51  %shl = shl <2 x i16> %x, <i16 poison, i16 1>52  %shr = lshr <2 x i16> %y, <i16 15, i16 15>53  %r = or <2 x i16> %shl, %shr54  ret <2 x i16> %r55}56 57define <2 x i16> @fshl_v2i16_constant_splat_poison1(<2 x i16> %x, <2 x i16> %y) {58; CHECK-LABEL: @fshl_v2i16_constant_splat_poison1(59; CHECK-NEXT:    [[R:%.*]] = call <2 x i16> @llvm.fshl.v2i16(<2 x i16> [[X:%.*]], <2 x i16> [[Y:%.*]], <2 x i16> splat (i16 1))60; CHECK-NEXT:    ret <2 x i16> [[R]]61;62  %shl = shl <2 x i16> %x, <i16 1, i16 1>63  %shr = lshr <2 x i16> %y, <i16 15, i16 poison>64  %r = or <2 x i16> %shl, %shr65  ret <2 x i16> %r66}67 68; Non-power-of-2 vector types are allowed.69 70define <2 x i17> @fshr_v2i17_constant_splat(<2 x i17> %x, <2 x i17> %y) {71; CHECK-LABEL: @fshr_v2i17_constant_splat(72; CHECK-NEXT:    [[R:%.*]] = call <2 x i17> @llvm.fshl.v2i17(<2 x i17> [[Y:%.*]], <2 x i17> [[X:%.*]], <2 x i17> splat (i17 5))73; CHECK-NEXT:    ret <2 x i17> [[R]]74;75  %shr = lshr <2 x i17> %x, <i17 12, i17 12>76  %shl = shl <2 x i17> %y, <i17 5, i17 5>77  %r = or <2 x i17> %shr, %shl78  ret <2 x i17> %r79}80 81define <2 x i17> @fshr_v2i17_constant_splat_poison0(<2 x i17> %x, <2 x i17> %y) {82; CHECK-LABEL: @fshr_v2i17_constant_splat_poison0(83; CHECK-NEXT:    [[R:%.*]] = call <2 x i17> @llvm.fshl.v2i17(<2 x i17> [[Y:%.*]], <2 x i17> [[X:%.*]], <2 x i17> splat (i17 5))84; CHECK-NEXT:    ret <2 x i17> [[R]]85;86  %shr = lshr <2 x i17> %x, <i17 12, i17 poison>87  %shl = shl <2 x i17> %y, <i17 poison, i17 5>88  %r = or <2 x i17> %shr, %shl89  ret <2 x i17> %r90}91 92define <2 x i17> @fshr_v2i17_constant_splat_poison1(<2 x i17> %x, <2 x i17> %y) {93; CHECK-LABEL: @fshr_v2i17_constant_splat_poison1(94; CHECK-NEXT:    [[R:%.*]] = call <2 x i17> @llvm.fshl.v2i17(<2 x i17> [[Y:%.*]], <2 x i17> [[X:%.*]], <2 x i17> splat (i17 5))95; CHECK-NEXT:    ret <2 x i17> [[R]]96;97  %shr = lshr <2 x i17> %x, <i17 12, i17 poison>98  %shl = shl <2 x i17> %y, <i17 5, i17 poison>99  %r = or <2 x i17> %shr, %shl100  ret <2 x i17> %r101}102 103; Allow arbitrary shift constants.104; Support poison elements.105 106define <2 x i32> @fshr_v2i32_constant_nonsplat(<2 x i32> %x, <2 x i32> %y) {107; CHECK-LABEL: @fshr_v2i32_constant_nonsplat(108; CHECK-NEXT:    [[R:%.*]] = call <2 x i32> @llvm.fshl.v2i32(<2 x i32> [[Y:%.*]], <2 x i32> [[X:%.*]], <2 x i32> <i32 15, i32 13>)109; CHECK-NEXT:    ret <2 x i32> [[R]]110;111  %shr = lshr <2 x i32> %x, <i32 17, i32 19>112  %shl = shl <2 x i32> %y, <i32 15, i32 13>113  %r = or <2 x i32> %shl, %shr114  ret <2 x i32> %r115}116 117define <2 x i32> @fshr_v2i32_constant_nonsplat_poison0(<2 x i32> %x, <2 x i32> %y) {118; CHECK-LABEL: @fshr_v2i32_constant_nonsplat_poison0(119; CHECK-NEXT:    [[R:%.*]] = call <2 x i32> @llvm.fshl.v2i32(<2 x i32> [[Y:%.*]], <2 x i32> [[X:%.*]], <2 x i32> <i32 0, i32 13>)120; CHECK-NEXT:    ret <2 x i32> [[R]]121;122  %shr = lshr <2 x i32> %x, <i32 poison, i32 19>123  %shl = shl <2 x i32> %y, <i32 15, i32 13>124  %r = or <2 x i32> %shl, %shr125  ret <2 x i32> %r126}127 128define <2 x i32> @fshr_v2i32_constant_nonsplat_poison1(<2 x i32> %x, <2 x i32> %y) {129; CHECK-LABEL: @fshr_v2i32_constant_nonsplat_poison1(130; CHECK-NEXT:    [[R:%.*]] = call <2 x i32> @llvm.fshl.v2i32(<2 x i32> [[Y:%.*]], <2 x i32> [[X:%.*]], <2 x i32> <i32 15, i32 poison>)131; CHECK-NEXT:    ret <2 x i32> [[R]]132;133  %shr = lshr <2 x i32> %x, <i32 17, i32 19>134  %shl = shl <2 x i32> %y, <i32 15, i32 poison>135  %r = or <2 x i32> %shl, %shr136  ret <2 x i32> %r137}138 139define <2 x i36> @fshl_v2i36_constant_nonsplat(<2 x i36> %x, <2 x i36> %y) {140; CHECK-LABEL: @fshl_v2i36_constant_nonsplat(141; CHECK-NEXT:    [[R:%.*]] = call <2 x i36> @llvm.fshl.v2i36(<2 x i36> [[X:%.*]], <2 x i36> [[Y:%.*]], <2 x i36> <i36 21, i36 11>)142; CHECK-NEXT:    ret <2 x i36> [[R]]143;144  %shl = shl <2 x i36> %x, <i36 21, i36 11>145  %shr = lshr <2 x i36> %y, <i36 15, i36 25>146  %r = or <2 x i36> %shl, %shr147  ret <2 x i36> %r148}149 150define <3 x i36> @fshl_v3i36_constant_nonsplat_poison0(<3 x i36> %x, <3 x i36> %y) {151; CHECK-LABEL: @fshl_v3i36_constant_nonsplat_poison0(152; CHECK-NEXT:    [[R:%.*]] = call <3 x i36> @llvm.fshl.v3i36(<3 x i36> [[X:%.*]], <3 x i36> [[Y:%.*]], <3 x i36> <i36 21, i36 11, i36 poison>)153; CHECK-NEXT:    ret <3 x i36> [[R]]154;155  %shl = shl <3 x i36> %x, <i36 21, i36 11, i36 poison>156  %shr = lshr <3 x i36> %y, <i36 15, i36 25, i36 poison>157  %r = or <3 x i36> %shl, %shr158  ret <3 x i36> %r159}160 161; Fold or(shl(x,a),lshr(y,bw-a)) -> fshl(x,y,a) iff a < bw162 163define i64 @fshl_sub_mask(i64 %x, i64 %y, i64 %a) {164; CHECK-LABEL: @fshl_sub_mask(165; CHECK-NEXT:    [[R:%.*]] = call i64 @llvm.fshl.i64(i64 [[X:%.*]], i64 [[Y:%.*]], i64 [[A:%.*]])166; CHECK-NEXT:    ret i64 [[R]]167;168  %mask = and i64 %a, 63169  %shl = shl i64 %x, %mask170  %sub = sub nuw nsw i64 64, %mask171  %shr = lshr i64 %y, %sub172  %r = or i64 %shl, %shr173  ret i64 %r174}175 176; Fold or(lshr(v,a),shl(v,bw-a)) -> fshr(y,x,a) iff a < bw177 178define i64 @fshr_sub_mask(i64 %x, i64 %y, i64 %a) {179; CHECK-LABEL: @fshr_sub_mask(180; CHECK-NEXT:    [[R:%.*]] = call i64 @llvm.fshr.i64(i64 [[Y:%.*]], i64 [[X:%.*]], i64 [[A:%.*]])181; CHECK-NEXT:    ret i64 [[R]]182;183  %mask = and i64 %a, 63184  %shr = lshr i64 %x, %mask185  %sub = sub nuw nsw i64 64, %mask186  %shl = shl i64 %y, %sub187  %r = or i64 %shl, %shr188  ret i64 %r189}190 191define <2 x i64> @fshr_sub_mask_vector(<2 x i64> %x, <2 x i64> %y, <2 x i64> %a) {192; CHECK-LABEL: @fshr_sub_mask_vector(193; CHECK-NEXT:    [[R:%.*]] = call <2 x i64> @llvm.fshr.v2i64(<2 x i64> [[Y:%.*]], <2 x i64> [[X:%.*]], <2 x i64> [[A:%.*]])194; CHECK-NEXT:    ret <2 x i64> [[R]]195;196  %mask = and <2 x i64> %a, <i64 63, i64 63>197  %shr = lshr <2 x i64> %x, %mask198  %sub = sub nuw nsw <2 x i64> <i64 64, i64 64>, %mask199  %shl = shl <2 x i64> %y, %sub200  %r = or <2 x i64> %shl, %shr201  ret <2 x i64> %r202}203 204; PR35155 - these are optionally UB-free funnel shift left/right patterns that are narrowed to a smaller bitwidth.205 206define i16 @fshl_16bit(i16 %x, i16 %y, i32 %shift) {207; CHECK-LABEL: @fshl_16bit(208; CHECK-NEXT:    [[TMP1:%.*]] = trunc i32 [[SHIFT:%.*]] to i16209; CHECK-NEXT:    [[CONV2:%.*]] = call i16 @llvm.fshl.i16(i16 [[X:%.*]], i16 [[Y:%.*]], i16 [[TMP1]])210; CHECK-NEXT:    ret i16 [[CONV2]]211;212  %and = and i32 %shift, 15213  %convx = zext i16 %x to i32214  %shl = shl i32 %convx, %and215  %sub = sub i32 16, %and216  %convy = zext i16 %y to i32217  %shr = lshr i32 %convy, %sub218  %or = or i32 %shr, %shl219  %conv2 = trunc i32 %or to i16220  ret i16 %conv2221}222 223; Commute the 'or' operands and try a vector type.224 225define <2 x i16> @fshl_commute_16bit_vec(<2 x i16> %x, <2 x i16> %y, <2 x i32> %shift) {226; CHECK-LABEL: @fshl_commute_16bit_vec(227; CHECK-NEXT:    [[TMP1:%.*]] = trunc <2 x i32> [[SHIFT:%.*]] to <2 x i16>228; CHECK-NEXT:    [[CONV2:%.*]] = call <2 x i16> @llvm.fshl.v2i16(<2 x i16> [[X:%.*]], <2 x i16> [[Y:%.*]], <2 x i16> [[TMP1]])229; CHECK-NEXT:    ret <2 x i16> [[CONV2]]230;231  %and = and <2 x i32> %shift, <i32 15, i32 15>232  %convx = zext <2 x i16> %x to <2 x i32>233  %shl = shl <2 x i32> %convx, %and234  %sub = sub <2 x i32> <i32 16, i32 16>, %and235  %convy = zext <2 x i16> %y to <2 x i32>236  %shr = lshr <2 x i32> %convy, %sub237  %or = or <2 x i32> %shl, %shr238  %conv2 = trunc <2 x i32> %or to <2 x i16>239  ret <2 x i16> %conv2240}241 242; Change the size, shift direction (the subtract is on the left-shift), and mask op.243 244define i8 @fshr_8bit(i8 %x, i8 %y, i3 %shift) {245; CHECK-LABEL: @fshr_8bit(246; CHECK-NEXT:    [[TMP1:%.*]] = zext i3 [[SHIFT:%.*]] to i8247; CHECK-NEXT:    [[CONV2:%.*]] = call i8 @llvm.fshr.i8(i8 [[Y:%.*]], i8 [[X:%.*]], i8 [[TMP1]])248; CHECK-NEXT:    ret i8 [[CONV2]]249;250  %and = zext i3 %shift to i32251  %convx = zext i8 %x to i32252  %shr = lshr i32 %convx, %and253  %sub = sub i32 8, %and254  %convy = zext i8 %y to i32255  %shl = shl i32 %convy, %sub256  %or = or i32 %shl, %shr257  %conv2 = trunc i32 %or to i8258  ret i8 %conv2259}260 261; The right-shifted value does not need to be a zexted value; here it is masked.262; The shift mask could be less than the bitwidth, but this is still ok.263 264define i8 @fshr_commute_8bit(i32 %x, i32 %y, i32 %shift) {265; CHECK-LABEL: @fshr_commute_8bit(266; CHECK-NEXT:    [[TMP1:%.*]] = trunc i32 [[SHIFT:%.*]] to i8267; CHECK-NEXT:    [[TMP2:%.*]] = and i8 [[TMP1]], 3268; CHECK-NEXT:    [[TMP3:%.*]] = trunc i32 [[Y:%.*]] to i8269; CHECK-NEXT:    [[TMP4:%.*]] = trunc i32 [[X:%.*]] to i8270; CHECK-NEXT:    [[CONV2:%.*]] = call i8 @llvm.fshr.i8(i8 [[TMP3]], i8 [[TMP4]], i8 [[TMP2]])271; CHECK-NEXT:    ret i8 [[CONV2]]272;273  %and = and i32 %shift, 3274  %convx = and i32 %x, 255275  %shr = lshr i32 %convx, %and276  %sub = sub i32 8, %and277  %convy = and i32 %y, 255278  %shl = shl i32 %convy, %sub279  %or = or i32 %shr, %shl280  %conv2 = trunc i32 %or to i8281  ret i8 %conv2282}283 284; The left-shifted value does not need to be masked at all.285 286define i8 @fshr_commute_8bit_unmasked_shl(i32 %x, i32 %y, i32 %shift) {287; CHECK-LABEL: @fshr_commute_8bit_unmasked_shl(288; CHECK-NEXT:    [[TMP1:%.*]] = trunc i32 [[SHIFT:%.*]] to i8289; CHECK-NEXT:    [[TMP2:%.*]] = and i8 [[TMP1]], 3290; CHECK-NEXT:    [[TMP3:%.*]] = trunc i32 [[Y:%.*]] to i8291; CHECK-NEXT:    [[TMP4:%.*]] = trunc i32 [[X:%.*]] to i8292; CHECK-NEXT:    [[CONV2:%.*]] = call i8 @llvm.fshr.i8(i8 [[TMP3]], i8 [[TMP4]], i8 [[TMP2]])293; CHECK-NEXT:    ret i8 [[CONV2]]294;295  %and = and i32 %shift, 3296  %convx = and i32 %x, 255297  %shr = lshr i32 %convx, %and298  %sub = sub i32 8, %and299  %convy = and i32 %y, 255300  %shl = shl i32 %y, %sub301  %or = or i32 %shr, %shl302  %conv2 = trunc i32 %or to i8303  ret i8 %conv2304}305 306; Convert select pattern to funnel shift that ends in 'or'.307 308define i8 @fshr_select(i8 %x, i8 %y, i8 %shamt) {309; CHECK-LABEL: @fshr_select(310; CHECK-NEXT:    [[TMP1:%.*]] = freeze i8 [[X:%.*]]311; CHECK-NEXT:    [[R:%.*]] = call i8 @llvm.fshr.i8(i8 [[TMP1]], i8 [[Y:%.*]], i8 [[SHAMT:%.*]])312; CHECK-NEXT:    ret i8 [[R]]313;314  %cmp = icmp eq i8 %shamt, 0315  %sub = sub i8 8, %shamt316  %shr = lshr i8 %y, %shamt317  %shl = shl i8 %x, %sub318  %or = or i8 %shl, %shr319  %r = select i1 %cmp, i8 %y, i8 %or320  ret i8 %r321}322 323; Convert select pattern to funnel shift that ends in 'or'.324 325define i16 @fshl_select(i16 %x, i16 %y, i16 %shamt) {326; CHECK-LABEL: @fshl_select(327; CHECK-NEXT:    [[TMP1:%.*]] = freeze i16 [[Y:%.*]]328; CHECK-NEXT:    [[R:%.*]] = call i16 @llvm.fshl.i16(i16 [[X:%.*]], i16 [[TMP1]], i16 [[SHAMT:%.*]])329; CHECK-NEXT:    ret i16 [[R]]330;331  %cmp = icmp eq i16 %shamt, 0332  %sub = sub i16 16, %shamt333  %shr = lshr i16 %y, %sub334  %shl = shl i16 %x, %shamt335  %or = or i16 %shr, %shl336  %r = select i1 %cmp, i16 %x, i16 %or337  ret i16 %r338}339 340; Convert select pattern to funnel shift that ends in 'or'.341 342define <2 x i64> @fshl_select_vector(<2 x i64> %x, <2 x i64> %y, <2 x i64> %shamt) {343; CHECK-LABEL: @fshl_select_vector(344; CHECK-NEXT:    [[TMP1:%.*]] = freeze <2 x i64> [[X:%.*]]345; CHECK-NEXT:    [[R:%.*]] = call <2 x i64> @llvm.fshl.v2i64(<2 x i64> [[Y:%.*]], <2 x i64> [[TMP1]], <2 x i64> [[SHAMT:%.*]])346; CHECK-NEXT:    ret <2 x i64> [[R]]347;348  %cmp = icmp eq <2 x i64> %shamt, zeroinitializer349  %sub = sub <2 x i64> <i64 64, i64 64>, %shamt350  %shr = lshr <2 x i64> %x, %sub351  %shl = shl <2 x i64> %y, %shamt352  %or = or <2 x i64> %shl, %shr353  %r = select <2 x i1> %cmp, <2 x i64> %y, <2 x i64> %or354  ret <2 x i64> %r355}356 357; Convert 'or concat' to fshl if opposite 'or concat' exists.358 359define i32 @fshl_concat_i8_i24(i8 %x, i24 %y, ptr %addr) {360; CHECK-LABEL: @fshl_concat_i8_i24(361; CHECK-NEXT:    [[ZEXT_X:%.*]] = zext i8 [[X:%.*]] to i32362; CHECK-NEXT:    [[SLX:%.*]] = shl nuw i32 [[ZEXT_X]], 24363; CHECK-NEXT:    [[ZEXT_Y:%.*]] = zext i24 [[Y:%.*]] to i32364; CHECK-NEXT:    [[XY:%.*]] = or disjoint i32 [[SLX]], [[ZEXT_Y]]365; CHECK-NEXT:    store i32 [[XY]], ptr [[ADDR:%.*]], align 4366; CHECK-NEXT:    [[YX:%.*]] = call i32 @llvm.fshl.i32(i32 [[XY]], i32 [[XY]], i32 8)367; CHECK-NEXT:    ret i32 [[YX]]368;369  %zext.x = zext i8 %x to i32370  %slx = shl i32 %zext.x, 24371  %zext.y = zext i24 %y to i32372  %xy = or i32 %zext.y, %slx373  store i32 %xy, ptr %addr, align 4374  %sly = shl i32 %zext.y, 8375  %yx = or i32 %zext.x, %sly376  ret i32 %yx377}378 379define i32 @fshl_concat_i8_i8(i8 %x, i8 %y, ptr %addr) {380; CHECK-LABEL: @fshl_concat_i8_i8(381; CHECK-NEXT:    [[ZEXT_X:%.*]] = zext i8 [[X:%.*]] to i32382; CHECK-NEXT:    [[SLX:%.*]] = shl nuw nsw i32 [[ZEXT_X]], 13383; CHECK-NEXT:    [[ZEXT_Y:%.*]] = zext i8 [[Y:%.*]] to i32384; CHECK-NEXT:    [[XY:%.*]] = or disjoint i32 [[SLX]], [[ZEXT_Y]]385; CHECK-NEXT:    store i32 [[XY]], ptr [[ADDR:%.*]], align 4386; CHECK-NEXT:    [[YX:%.*]] = call i32 @llvm.fshl.i32(i32 [[XY]], i32 [[XY]], i32 19)387; CHECK-NEXT:    ret i32 [[YX]]388;389  %zext.x = zext i8 %x to i32390  %slx = shl i32 %zext.x, 13391  %zext.y = zext i8 %y to i32392  %xy = or i32 %zext.y, %slx393  store i32 %xy, ptr %addr, align 4394  %sly = shl i32 %zext.y, 19395  %yx = or i32 %zext.x, %sly396  ret i32 %yx397}398 399define i32 @fshl_concat_i8_i8_overlap(i8 %x, i8 %y, ptr %addr) {400; CHECK-LABEL: @fshl_concat_i8_i8_overlap(401; CHECK-NEXT:    [[ZEXT_X:%.*]] = zext i8 [[X:%.*]] to i32402; CHECK-NEXT:    [[SLX:%.*]] = shl i32 [[ZEXT_X]], 25403; CHECK-NEXT:    [[ZEXT_Y:%.*]] = zext i8 [[Y:%.*]] to i32404; CHECK-NEXT:    [[XY:%.*]] = or disjoint i32 [[SLX]], [[ZEXT_Y]]405; CHECK-NEXT:    store i32 [[XY]], ptr [[ADDR:%.*]], align 4406; CHECK-NEXT:    [[SLY:%.*]] = shl nuw nsw i32 [[ZEXT_Y]], 7407; CHECK-NEXT:    [[YX:%.*]] = or i32 [[SLY]], [[ZEXT_X]]408; CHECK-NEXT:    ret i32 [[YX]]409;410  ; Test sly overlap.411  %zext.x = zext i8 %x to i32412  %slx = shl i32 %zext.x, 25413  %zext.y = zext i8 %y to i32414  %xy = or i32 %zext.y, %slx415  store i32 %xy, ptr %addr, align 4416  %sly = shl i32 %zext.y, 7417  %yx = or i32 %zext.x, %sly418  ret i32 %yx419}420 421define i32 @fshl_concat_i8_i8_drop(i8 %x, i8 %y, ptr %addr) {422; CHECK-LABEL: @fshl_concat_i8_i8_drop(423; CHECK-NEXT:    [[ZEXT_X:%.*]] = zext i8 [[X:%.*]] to i32424; CHECK-NEXT:    [[SLX:%.*]] = shl nuw nsw i32 [[ZEXT_X]], 7425; CHECK-NEXT:    [[ZEXT_Y:%.*]] = zext i8 [[Y:%.*]] to i32426; CHECK-NEXT:    [[XY:%.*]] = or i32 [[SLX]], [[ZEXT_Y]]427; CHECK-NEXT:    store i32 [[XY]], ptr [[ADDR:%.*]], align 4428; CHECK-NEXT:    [[SLY:%.*]] = shl i32 [[ZEXT_Y]], 25429; CHECK-NEXT:    [[YX:%.*]] = or disjoint i32 [[SLY]], [[ZEXT_X]]430; CHECK-NEXT:    ret i32 [[YX]]431;432  ; Test sly drop.433  %zext.x = zext i8 %x to i32434  %slx = shl i32 %zext.x, 7435  %zext.y = zext i8 %y to i32436  %xy = or i32 %zext.y, %slx437  store i32 %xy, ptr %addr, align 4438  %sly = shl i32 %zext.y, 25439  %yx = or i32 %zext.x, %sly440  ret i32 %yx441}442 443define i32 @fshl_concat_i8_i8_different_slot(i8 %x, i8 %y, ptr %addr) {444; CHECK-LABEL: @fshl_concat_i8_i8_different_slot(445; CHECK-NEXT:    [[ZEXT_X:%.*]] = zext i8 [[X:%.*]] to i32446; CHECK-NEXT:    [[SLX:%.*]] = shl nuw nsw i32 [[ZEXT_X]], 9447; CHECK-NEXT:    [[ZEXT_Y:%.*]] = zext i8 [[Y:%.*]] to i32448; CHECK-NEXT:    [[XY:%.*]] = or disjoint i32 [[SLX]], [[ZEXT_Y]]449; CHECK-NEXT:    store i32 [[XY]], ptr [[ADDR:%.*]], align 4450; CHECK-NEXT:    [[SLY:%.*]] = shl nuw nsw i32 [[ZEXT_Y]], 22451; CHECK-NEXT:    [[YX:%.*]] = or disjoint i32 [[SLY]], [[ZEXT_X]]452; CHECK-NEXT:    ret i32 [[YX]]453;454  %zext.x = zext i8 %x to i32455  %slx = shl i32 %zext.x, 9456  %zext.y = zext i8 %y to i32457  %xy = or i32 %zext.y, %slx458  store i32 %xy, ptr %addr, align 4459  %sly = shl i32 %zext.y, 22460  %yx = or i32 %zext.x, %sly461  ret i32 %yx462}463 464define i32 @fshl_concat_unknown_source(i32 %zext.x, i32 %zext.y, ptr %addr) {465; CHECK-LABEL: @fshl_concat_unknown_source(466; CHECK-NEXT:    [[SLX:%.*]] = shl i32 [[ZEXT_X:%.*]], 16467; CHECK-NEXT:    [[XY:%.*]] = or i32 [[ZEXT_Y:%.*]], [[SLX]]468; CHECK-NEXT:    store i32 [[XY]], ptr [[ADDR:%.*]], align 4469; CHECK-NEXT:    [[SLY:%.*]] = shl i32 [[ZEXT_Y]], 16470; CHECK-NEXT:    [[YX:%.*]] = or i32 [[ZEXT_X]], [[SLY]]471; CHECK-NEXT:    ret i32 [[YX]]472;473  %slx = shl i32 %zext.x, 16474  %xy = or i32 %zext.y, %slx475  store i32 %xy, ptr %addr, align 4476  %sly = shl i32 %zext.y, 16477  %yx = or i32 %zext.x, %sly478  ret i32 %yx479}480 481define <2 x i32> @fshl_concat_vector(<2 x i8> %x, <2 x i24> %y, ptr %addr) {482; CHECK-LABEL: @fshl_concat_vector(483; CHECK-NEXT:    [[ZEXT_X:%.*]] = zext <2 x i8> [[X:%.*]] to <2 x i32>484; CHECK-NEXT:    [[SLX:%.*]] = shl nuw <2 x i32> [[ZEXT_X]], splat (i32 24)485; CHECK-NEXT:    [[ZEXT_Y:%.*]] = zext <2 x i24> [[Y:%.*]] to <2 x i32>486; CHECK-NEXT:    [[XY:%.*]] = or disjoint <2 x i32> [[SLX]], [[ZEXT_Y]]487; CHECK-NEXT:    store <2 x i32> [[XY]], ptr [[ADDR:%.*]], align 4488; CHECK-NEXT:    [[YX:%.*]] = call <2 x i32> @llvm.fshl.v2i32(<2 x i32> [[XY]], <2 x i32> [[XY]], <2 x i32> splat (i32 8))489; CHECK-NEXT:    ret <2 x i32> [[YX]]490;491  %zext.x = zext <2 x i8> %x to <2 x i32>492  %slx = shl <2 x i32> %zext.x, <i32 24, i32 24>493  %zext.y = zext <2 x i24> %y to <2 x i32>494  %xy = or <2 x i32> %slx, %zext.y495  store <2 x i32> %xy, ptr %addr, align 4496  %sly = shl <2 x i32> %zext.y, <i32 8, i32 8>497  %yx = or <2 x i32> %sly, %zext.x498  ret <2 x i32> %yx499}500 501; Negative test - an oversized shift in the narrow type would produce the wrong value.502 503define i8 @unmasked_shlop_unmasked_shift_amount(i32 %x, i32 %y, i32 %shamt) {504; CHECK-LABEL: @unmasked_shlop_unmasked_shift_amount(505; CHECK-NEXT:    [[MASKY:%.*]] = and i32 [[Y:%.*]], 255506; CHECK-NEXT:    [[T4:%.*]] = sub i32 8, [[SHAMT:%.*]]507; CHECK-NEXT:    [[T5:%.*]] = shl i32 [[X:%.*]], [[T4]]508; CHECK-NEXT:    [[T6:%.*]] = lshr i32 [[MASKY]], [[SHAMT]]509; CHECK-NEXT:    [[T7:%.*]] = or i32 [[T5]], [[T6]]510; CHECK-NEXT:    [[T8:%.*]] = trunc i32 [[T7]] to i8511; CHECK-NEXT:    ret i8 [[T8]]512;513  %masky = and i32 %y, 255514  %t4 = sub i32 8, %shamt515  %t5 = shl i32 %x, %t4516  %t6 = lshr i32 %masky, %shamt517  %t7 = or i32 %t5, %t6518  %t8 = trunc i32 %t7 to i8519  ret i8 %t8520}521 522; Negative test - an oversized shift in the narrow type would produce the wrong value.523 524define i8 @unmasked_shlop_insufficient_mask_shift_amount(i16 %x, i16 %y, i16 %shamt) {525; CHECK-LABEL: @unmasked_shlop_insufficient_mask_shift_amount(526; CHECK-NEXT:    [[SHM:%.*]] = and i16 [[SHAMT:%.*]], 15527; CHECK-NEXT:    [[MASKX:%.*]] = and i16 [[X:%.*]], 255528; CHECK-NEXT:    [[T4:%.*]] = sub nsw i16 8, [[SHM]]529; CHECK-NEXT:    [[T5:%.*]] = shl i16 [[Y:%.*]], [[T4]]530; CHECK-NEXT:    [[T6:%.*]] = lshr i16 [[MASKX]], [[SHM]]531; CHECK-NEXT:    [[T7:%.*]] = or i16 [[T5]], [[T6]]532; CHECK-NEXT:    [[T8:%.*]] = trunc i16 [[T7]] to i8533; CHECK-NEXT:    ret i8 [[T8]]534;535  %shm = and i16 %shamt, 15536  %maskx = and i16 %x, 255537  %t4 = sub i16 8, %shm538  %t5 = shl i16 %y, %t4539  %t6 = lshr i16 %maskx, %shm540  %t7 = or i16 %t5, %t6541  %t8 = trunc i16 %t7 to i8542  ret i8 %t8543}544 545define i8 @unmasked_shlop_masked_shift_amount(i16 %x, i16 %y, i16 %shamt) {546; CHECK-LABEL: @unmasked_shlop_masked_shift_amount(547; CHECK-NEXT:    [[TMP1:%.*]] = trunc i16 [[SHAMT:%.*]] to i8548; CHECK-NEXT:    [[TMP2:%.*]] = trunc i16 [[Y:%.*]] to i8549; CHECK-NEXT:    [[TMP3:%.*]] = trunc i16 [[X:%.*]] to i8550; CHECK-NEXT:    [[T8:%.*]] = call i8 @llvm.fshr.i8(i8 [[TMP2]], i8 [[TMP3]], i8 [[TMP1]])551; CHECK-NEXT:    ret i8 [[T8]]552;553  %shm = and i16 %shamt, 7554  %maskx = and i16 %x, 255555  %t4 = sub i16 8, %shm556  %t5 = shl i16 %y, %t4557  %t6 = lshr i16 %maskx, %shm558  %t7 = or i16 %t5, %t6559  %t8 = trunc i16 %t7 to i8560  ret i8 %t8561}562 563define i32 @test_rotl_and_neg(i32 %x, i32 %shamt) {564; CHECK-LABEL: @test_rotl_and_neg(565; CHECK-NEXT:    [[OR:%.*]] = call i32 @llvm.fshl.i32(i32 [[X:%.*]], i32 [[X]], i32 [[SHAMT:%.*]])566; CHECK-NEXT:    ret i32 [[OR]]567;568  %shl = shl i32 %x, %shamt569  %neg = sub i32 0, %shamt570  %and = and i32 %neg, 31571  %shr = lshr i32 %x, %and572  %or = or i32 %shl, %shr573  ret i32 %or574}575 576define i32 @test_rotl_and_neg_commuted(i32 %x, i32 %shamt) {577; CHECK-LABEL: @test_rotl_and_neg_commuted(578; CHECK-NEXT:    [[OR:%.*]] = call i32 @llvm.fshl.i32(i32 [[X:%.*]], i32 [[X]], i32 [[SHAMT:%.*]])579; CHECK-NEXT:    ret i32 [[OR]]580;581  %shl = shl i32 %x, %shamt582  %neg = sub i32 0, %shamt583  %and = and i32 %neg, 31584  %shr = lshr i32 %x, %and585  %or = or i32 %shr, %shl586  ret i32 %or587}588 589define i32 @test_rotr_and_neg(i32 %x, i32 %shamt) {590; CHECK-LABEL: @test_rotr_and_neg(591; CHECK-NEXT:    [[OR:%.*]] = call i32 @llvm.fshr.i32(i32 [[X:%.*]], i32 [[X]], i32 [[SHAMT:%.*]])592; CHECK-NEXT:    ret i32 [[OR]]593;594  %shr = lshr i32 %x, %shamt595  %neg = sub i32 0, %shamt596  %and = and i32 %neg, 31597  %shl = shl i32 %x, %and598  %or = or i32 %shl, %shr599  ret i32 %or600}601 602; Negative tests603 604; Only work for rotation patterns605define i32 @test_fshl_and_neg(i32 %x, i32 %y, i32 %shamt) {606; CHECK-LABEL: @test_fshl_and_neg(607; CHECK-NEXT:    [[SHL:%.*]] = shl i32 [[X:%.*]], [[SHAMT:%.*]]608; CHECK-NEXT:    [[NEG:%.*]] = sub i32 0, [[SHAMT]]609; CHECK-NEXT:    [[AND:%.*]] = and i32 [[NEG]], 31610; CHECK-NEXT:    [[SHR:%.*]] = lshr i32 [[Y:%.*]], [[AND]]611; CHECK-NEXT:    [[OR:%.*]] = or i32 [[SHL]], [[SHR]]612; CHECK-NEXT:    ret i32 [[OR]]613;614  %shl = shl i32 %x, %shamt615  %neg = sub i32 0, %shamt616  %and = and i32 %neg, 31617  %shr = lshr i32 %y, %and618  %or = or i32 %shl, %shr619  ret i32 %or620}621 622define i32 @test_rotl_and_neg_wrong_mask(i32 %x, i32 %shamt) {623; CHECK-LABEL: @test_rotl_and_neg_wrong_mask(624; CHECK-NEXT:    [[SHL:%.*]] = shl i32 [[X:%.*]], [[SHAMT:%.*]]625; CHECK-NEXT:    [[NEG:%.*]] = sub i32 0, [[SHAMT]]626; CHECK-NEXT:    [[AND:%.*]] = and i32 [[NEG]], 15627; CHECK-NEXT:    [[SHR:%.*]] = lshr i32 [[X]], [[AND]]628; CHECK-NEXT:    [[OR:%.*]] = or i32 [[SHL]], [[SHR]]629; CHECK-NEXT:    ret i32 [[OR]]630;631  %shl = shl i32 %x, %shamt632  %neg = sub i32 0, %shamt633  %and = and i32 %neg, 15634  %shr = lshr i32 %x, %and635  %or = or i32 %shl, %shr636  ret i32 %or637}638 639declare void @use(i16)640 641; Make sure the reused result does not produce poison.642 643define i16 @fshl_concat_vector_may_produce_poison(i4 %x, i12 %y) {644; CHECK-LABEL: @fshl_concat_vector_may_produce_poison(645; CHECK-NEXT:    [[X_FR:%.*]] = freeze i4 [[X:%.*]]646; CHECK-NEXT:    [[ZEXT_X:%.*]] = zext i4 [[X_FR]] to i16647; CHECK-NEXT:    [[SLX:%.*]] = shl nuw i16 [[ZEXT_X]], 12648; CHECK-NEXT:    [[ZEXT_Y:%.*]] = zext i12 [[Y:%.*]] to i16649; CHECK-NEXT:    [[XY:%.*]] = or disjoint i16 [[SLX]], [[ZEXT_Y]]650; CHECK-NEXT:    call void @use(i16 [[XY]])651; CHECK-NEXT:    [[YX:%.*]] = call i16 @llvm.fshl.i16(i16 [[XY]], i16 [[XY]], i16 4)652; CHECK-NEXT:    ret i16 [[YX]]653;654  %x.fr = freeze i4 %x655  %zext.x = zext i4 %x.fr to i16656  %slx = shl nuw nsw i16 %zext.x, 12657  %zext.y = zext i12 %y to i16658  %xy = or disjoint i16 %slx, %zext.y659  call void @use(i16 %xy)660  %sly = shl nuw i16 %zext.y, 4661  %yx = or disjoint i16 %sly, %zext.x662  ret i16 %yx663}664