; NOTE: Assertions have been autogenerated by utils/update_test_checks.py ; RUN: opt -passes='require,function(codegenprepare)' -S %s | FileCheck %s target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128" target triple = "arm64-apple-ios" ; It's profitable to convert the zext to a shuffle, which in turn will be ; lowered to 4 tbl instructions. The masks are materialized outside the loop. define void @zext_v16i8_to_v16i32_in_loop(ptr %src, ptr %dst) { ; CHECK-LABEL: @zext_v16i8_to_v16i32_in_loop( ; CHECK-NEXT: entry: ; CHECK-NEXT: br label [[LOOP:%.*]] ; CHECK: loop: ; CHECK-NEXT: [[IV:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ] ; CHECK-NEXT: [[SRC_GEP:%.*]] = getelementptr i8, ptr [[SRC:%.*]], i64 [[IV]] ; CHECK-NEXT: [[LOAD:%.*]] = load <16 x i8>, ptr [[SRC_GEP]], align 16 ; CHECK-NEXT: [[TMP0:%.*]] = shufflevector <16 x i8> [[LOAD]], <16 x i8> , <64 x i32> ; CHECK-NEXT: [[TMP1:%.*]] = bitcast <64 x i8> [[TMP0]] to <16 x i32> ; CHECK-NEXT: [[DST_GEP:%.*]] = getelementptr i32, ptr [[DST:%.*]], i64 [[IV]] ; CHECK-NEXT: store <16 x i32> [[TMP1]], ptr [[DST_GEP]], align 64 ; CHECK-NEXT: [[IV_NEXT]] = add nuw i64 [[IV]], 16 ; CHECK-NEXT: [[EC:%.*]] = icmp eq i64 [[IV_NEXT]], 128 ; CHECK-NEXT: br i1 [[EC]], label [[EXIT:%.*]], label [[LOOP]] ; CHECK: exit: ; CHECK-NEXT: ret void ; entry: br label %loop loop: %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ] %src.gep = getelementptr i8, ptr %src, i64 %iv %load = load <16 x i8>, ptr %src.gep %ext = zext <16 x i8> %load to <16 x i32> %dst.gep = getelementptr i32, ptr %dst, i64 %iv store <16 x i32> %ext, ptr %dst.gep %iv.next = add nuw i64 %iv, 16 %ec = icmp eq i64 %iv.next, 128 br i1 %ec, label %exit, label %loop exit: ret void } ; Not profitable to use shuffle/tbl, as 4 tbls + materializing the masks ; require more instructions than lowering zext directly. define void @zext_v16i8_to_v16i32_no_loop(ptr %src, ptr %dst) { ; CHECK-LABEL: @zext_v16i8_to_v16i32_no_loop( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[LOAD:%.*]] = load <16 x i8>, ptr [[SRC:%.*]], align 16 ; CHECK-NEXT: [[EXT:%.*]] = zext <16 x i8> [[LOAD]] to <16 x i32> ; CHECK-NEXT: store <16 x i32> [[EXT]], ptr [[DST:%.*]], align 64 ; CHECK-NEXT: ret void ; entry: %load = load <16 x i8>, ptr %src %ext = zext <16 x i8> %load to <16 x i32> store <16 x i32> %ext, ptr %dst ret void } define void @zext_v16i8_to_v16i16_in_loop(ptr %src, ptr %dst) { ; CHECK-LABEL: @zext_v16i8_to_v16i16_in_loop( ; CHECK-NEXT: entry: ; CHECK-NEXT: br label [[LOOP:%.*]] ; CHECK: loop: ; CHECK-NEXT: [[IV:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ] ; CHECK-NEXT: [[SRC_GEP:%.*]] = getelementptr i8, ptr [[SRC:%.*]], i64 [[IV]] ; CHECK-NEXT: [[LOAD:%.*]] = load <16 x i8>, ptr [[SRC_GEP]], align 16 ; CHECK-NEXT: [[EXT:%.*]] = zext <16 x i8> [[LOAD]] to <16 x i16> ; CHECK-NEXT: [[DST_GEP:%.*]] = getelementptr i16, ptr [[DST:%.*]], i64 [[IV]] ; CHECK-NEXT: store <16 x i16> [[EXT]], ptr [[DST_GEP]], align 32 ; CHECK-NEXT: [[IV_NEXT]] = add nuw i64 [[IV]], 16 ; CHECK-NEXT: [[EC:%.*]] = icmp eq i64 [[IV_NEXT]], 128 ; CHECK-NEXT: br i1 [[EC]], label [[EXIT:%.*]], label [[LOOP]] ; CHECK: exit: ; CHECK-NEXT: ret void ; entry: br label %loop loop: %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ] %src.gep = getelementptr i8, ptr %src, i64 %iv %load = load <16 x i8>, ptr %src.gep %ext = zext <16 x i8> %load to <16 x i16> %dst.gep = getelementptr i16, ptr %dst, i64 %iv store <16 x i16> %ext, ptr %dst.gep %iv.next = add nuw i64 %iv, 16 %ec = icmp eq i64 %iv.next, 128 br i1 %ec, label %exit, label %loop exit: ret void } define void @zext_v8i8_to_v8i32_in_loop(ptr %src, ptr %dst) { ; CHECK-LABEL: @zext_v8i8_to_v8i32_in_loop( ; CHECK-NEXT: entry: ; CHECK-NEXT: br label [[LOOP:%.*]] ; CHECK: loop: ; CHECK-NEXT: [[IV:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ] ; CHECK-NEXT: [[SRC_GEP:%.*]] = getelementptr i8, ptr [[SRC:%.*]], i64 [[IV]] ; CHECK-NEXT: [[LOAD:%.*]] = load <8 x i8>, ptr [[SRC_GEP]], align 8 ; CHECK-NEXT: [[TMP0:%.*]] = shufflevector <8 x i8> [[LOAD]], <8 x i8> , <32 x i32> ; CHECK-NEXT: [[TMP1:%.*]] = bitcast <32 x i8> [[TMP0]] to <8 x i32> ; CHECK-NEXT: [[DST_GEP:%.*]] = getelementptr i32, ptr [[DST:%.*]], i64 [[IV]] ; CHECK-NEXT: store <8 x i32> [[TMP1]], ptr [[DST_GEP]], align 32 ; CHECK-NEXT: [[IV_NEXT]] = add nuw i64 [[IV]], 16 ; CHECK-NEXT: [[EC:%.*]] = icmp eq i64 [[IV_NEXT]], 128 ; CHECK-NEXT: br i1 [[EC]], label [[EXIT:%.*]], label [[LOOP]] ; CHECK: exit: ; CHECK-NEXT: ret void ; entry: br label %loop loop: %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ] %src.gep = getelementptr i8, ptr %src, i64 %iv %load = load <8 x i8>, ptr %src.gep %ext = zext <8 x i8> %load to <8 x i32> %dst.gep = getelementptr i32, ptr %dst, i64 %iv store <8 x i32> %ext, ptr %dst.gep %iv.next = add nuw i64 %iv, 16 %ec = icmp eq i64 %iv.next, 128 br i1 %ec, label %exit, label %loop exit: ret void } define void @zext_v16i8_to_v16i64_in_loop(ptr %src, ptr %dst) { ; CHECK-LABEL: @zext_v16i8_to_v16i64_in_loop( ; CHECK-NEXT: entry: ; CHECK-NEXT: br label [[LOOP:%.*]] ; CHECK: loop: ; CHECK-NEXT: [[IV:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ] ; CHECK-NEXT: [[SRC_GEP:%.*]] = getelementptr i8, ptr [[SRC:%.*]], i64 [[IV]] ; CHECK-NEXT: [[LOAD:%.*]] = load <16 x i8>, ptr [[SRC_GEP]], align 16 ; CHECK-NEXT: [[EXT:%.*]] = zext <16 x i8> [[LOAD]] to <16 x i64> ; CHECK-NEXT: [[DST_GEP:%.*]] = getelementptr i64, ptr [[DST:%.*]], i64 [[IV]] ; CHECK-NEXT: store <16 x i64> [[EXT]], ptr [[DST_GEP]], align 128 ; CHECK-NEXT: [[IV_NEXT]] = add nuw i64 [[IV]], 16 ; CHECK-NEXT: [[EC:%.*]] = icmp eq i64 [[IV_NEXT]], 128 ; CHECK-NEXT: br i1 [[EC]], label [[EXIT:%.*]], label [[LOOP]] ; CHECK: exit: ; CHECK-NEXT: ret void ; entry: br label %loop loop: %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ] %src.gep = getelementptr i8, ptr %src, i64 %iv %load = load <16 x i8>, ptr %src.gep %ext = zext <16 x i8> %load to <16 x i64> %dst.gep = getelementptr i64, ptr %dst, i64 %iv store <16 x i64> %ext, ptr %dst.gep %iv.next = add nuw i64 %iv, 16 %ec = icmp eq i64 %iv.next, 128 br i1 %ec, label %exit, label %loop exit: ret void }