; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5 ; RUN: opt < %s -S -mtriple=aarch64-none-linux-gnu -mattr=+neon -passes=early-cse -earlycse-debug-hash | FileCheck %s ; RUN: opt < %s -S -mtriple=aarch64-none-linux-gnu -mattr=+neon -aa-pipeline=basic-aa -passes='early-cse' -verify-analysis-invalidation | FileCheck %s ; Check that ld1x2 is optimized away by EarlyCSE. define <4 x i32> @test_cse_for_st1x2_ld1x2(ptr %p, <4 x i32> %A, <4 x i32> %B) { ; CHECK-LABEL: define <4 x i32> @test_cse_for_st1x2_ld1x2( ; CHECK-SAME: ptr [[P:%.*]], <4 x i32> [[A:%.*]], <4 x i32> [[B:%.*]]) #[[ATTR0:[0-9]+]] { ; CHECK-NEXT: [[ENTRY:.*:]] ; CHECK-NEXT: [[TMP0:%.*]] = insertvalue { <4 x i32>, <4 x i32> } poison, <4 x i32> [[A]], 0 ; CHECK-NEXT: [[TMP1:%.*]] = insertvalue { <4 x i32>, <4 x i32> } [[TMP0]], <4 x i32> [[B]], 1 ; CHECK-NEXT: call void @llvm.aarch64.neon.st1x2.v4i32.p0(<4 x i32> [[A]], <4 x i32> [[B]], ptr [[P]]) ; CHECK-NEXT: ret <4 x i32> [[A]] ; entry: call void @llvm.aarch64.neon.st1x2.v4i32.p0(<4 x i32> %A, <4 x i32> %B, ptr %p) %ld = call { <4 x i32>, <4 x i32> } @llvm.aarch64.neon.ld1x2.v4i32.p0(ptr %p) %ext = extractvalue { <4 x i32>, <4 x i32> } %ld, 0 ret <4 x i32> %ext } ; Currently, the redundant st1x2 in this case is not optimized by EarlyCSE. define void @test_no_cse_for_st1x2_st1x2_case1(ptr %p, <4 x i32> %A, <4 x i32> %B) { ; CHECK-LABEL: define void @test_no_cse_for_st1x2_st1x2_case1( ; CHECK-SAME: ptr [[P:%.*]], <4 x i32> [[A:%.*]], <4 x i32> [[B:%.*]]) #[[ATTR0]] { ; CHECK-NEXT: [[ENTRY:.*:]] ; CHECK-NEXT: call void @llvm.aarch64.neon.st1x2.v4i32.p0(<4 x i32> [[A]], <4 x i32> [[B]], ptr [[P]]) ; CHECK-NEXT: call void @llvm.aarch64.neon.st1x2.v4i32.p0(<4 x i32> [[A]], <4 x i32> [[B]], ptr [[P]]) ; CHECK-NEXT: ret void ; entry: call void @llvm.aarch64.neon.st1x2.v4i32.p0(<4 x i32> %A, <4 x i32> %B, ptr %p) call void @llvm.aarch64.neon.st1x2.v4i32.p0(<4 x i32> %A, <4 x i32> %B, ptr %p) ret void } ; Currently, the redundant st1x2 in this case is not optimized by EarlyCSE. define void @test_no_cse_for_st1x2_st1x2_case2(ptr %p, <4 x i32> %A, <4 x i32> %B) { ; CHECK-LABEL: define void @test_no_cse_for_st1x2_st1x2_case2( ; CHECK-SAME: ptr [[P:%.*]], <4 x i32> [[A:%.*]], <4 x i32> [[B:%.*]]) #[[ATTR0]] { ; CHECK-NEXT: [[ENTRY:.*:]] ; CHECK-NEXT: call void @llvm.aarch64.neon.st1x2.v4i32.p0(<4 x i32> [[A]], <4 x i32> [[A]], ptr [[P]]) ; CHECK-NEXT: call void @llvm.aarch64.neon.st1x2.v4i32.p0(<4 x i32> [[A]], <4 x i32> [[B]], ptr [[P]]) ; CHECK-NEXT: ret void ; entry: call void @llvm.aarch64.neon.st1x2.v4i32.p0(<4 x i32> %A, <4 x i32> %A, ptr %p) call void @llvm.aarch64.neon.st1x2.v4i32.p0(<4 x i32> %A, <4 x i32> %B, ptr %p) ret void } ; Check that redundant ld1x2 is optimized away by EarlyCSE. define <4 x i32> @test_cse_for_ld1x2_ld1x2(ptr %p) { ; CHECK-LABEL: define <4 x i32> @test_cse_for_ld1x2_ld1x2( ; CHECK-SAME: ptr [[P:%.*]]) #[[ATTR0]] { ; CHECK-NEXT: [[ENTRY:.*:]] ; CHECK-NEXT: [[LD1:%.*]] = call { <4 x i32>, <4 x i32> } @llvm.aarch64.neon.ld1x2.v4i32.p0(ptr [[P]]) ; CHECK-NEXT: [[EXT1:%.*]] = extractvalue { <4 x i32>, <4 x i32> } [[LD1]], 0 ; CHECK-NEXT: [[EXT2:%.*]] = extractvalue { <4 x i32>, <4 x i32> } [[LD1]], 1 ; CHECK-NEXT: [[RES:%.*]] = add <4 x i32> [[EXT1]], [[EXT2]] ; CHECK-NEXT: ret <4 x i32> [[RES]] ; entry: %ld1 = call { <4 x i32>, <4 x i32> } @llvm.aarch64.neon.ld1x2.v4i32.p0(ptr %p) %ext1 = extractvalue { <4 x i32>, <4 x i32> } %ld1, 0 %ld2 = call { <4 x i32>, <4 x i32> } @llvm.aarch64.neon.ld1x2.v4i32.p0(ptr %p) %ext2 = extractvalue { <4 x i32>, <4 x i32> } %ld2, 1 %res = add <4 x i32> %ext1, %ext2 ret <4 x i32> %res } ; Check that the store prevents ld1x2 from being optimized away by EarlyCSE. define <4 x i32> @test_no_cse_for_st1x2_store_ld1x2(ptr %p, ptr %q, <4 x i32> %A, <4 x i32> %B) { ; CHECK-LABEL: define <4 x i32> @test_no_cse_for_st1x2_store_ld1x2( ; CHECK-SAME: ptr [[P:%.*]], ptr [[Q:%.*]], <4 x i32> [[A:%.*]], <4 x i32> [[B:%.*]]) #[[ATTR0]] { ; CHECK-NEXT: [[ENTRY:.*:]] ; CHECK-NEXT: call void @llvm.aarch64.neon.st1x2.v4i32.p0(<4 x i32> [[A]], <4 x i32> [[A]], ptr [[P]]) ; CHECK-NEXT: store i32 0, ptr [[Q]], align 4 ; CHECK-NEXT: [[LD:%.*]] = call { <4 x i32>, <4 x i32> } @llvm.aarch64.neon.ld1x2.v4i32.p0(ptr [[P]]) ; CHECK-NEXT: [[EXT:%.*]] = extractvalue { <4 x i32>, <4 x i32> } [[LD]], 0 ; CHECK-NEXT: ret <4 x i32> [[EXT]] ; entry: call void @llvm.aarch64.neon.st1x2.v4i32.p0(<4 x i32> %A, <4 x i32> %A, ptr %p) store i32 0, ptr %q %ld = call { <4 x i32>, <4 x i32> } @llvm.aarch64.neon.ld1x2.v4i32.p0(ptr %p) %ext = extractvalue { <4 x i32>, <4 x i32> } %ld, 0 ret <4 x i32> %ext } ; Check that ld1x3 is not optimized away by EarlyCSE. define <4 x i32> @test_no_cse_for_st1x2_ld1x3(ptr %p, <4 x i32> %A, <4 x i32> %B) { ; CHECK-LABEL: define <4 x i32> @test_no_cse_for_st1x2_ld1x3( ; CHECK-SAME: ptr [[P:%.*]], <4 x i32> [[A:%.*]], <4 x i32> [[B:%.*]]) #[[ATTR0]] { ; CHECK-NEXT: [[ENTRY:.*:]] ; CHECK-NEXT: call void @llvm.aarch64.neon.st1x2.v4i32.p0(<4 x i32> [[A]], <4 x i32> [[B]], ptr [[P]]) ; CHECK-NEXT: [[LD:%.*]] = call { <4 x i32>, <4 x i32>, <4 x i32> } @llvm.aarch64.neon.ld1x3.v4i32.p0(ptr [[P]]) ; CHECK-NEXT: [[EXT:%.*]] = extractvalue { <4 x i32>, <4 x i32>, <4 x i32> } [[LD]], 0 ; CHECK-NEXT: ret <4 x i32> [[EXT]] ; entry: call void @llvm.aarch64.neon.st1x2.v4i32.p0(<4 x i32> %A, <4 x i32> %B, ptr %p) %ld = call { <4 x i32>, <4 x i32>, <4 x i32> } @llvm.aarch64.neon.ld1x3.v4i32.p0(ptr %p) %ext = extractvalue { <4 x i32>, <4 x i32>, <4 x i32> } %ld, 0 ret <4 x i32> %ext } ; Check that st1x3 is not optimized away by EarlyCSE. define void @test_no_cse_for_st1x3_st1x2(ptr %p, <4 x i32> %A, <4 x i32> %B) { ; CHECK-LABEL: define void @test_no_cse_for_st1x3_st1x2( ; CHECK-SAME: ptr [[P:%.*]], <4 x i32> [[A:%.*]], <4 x i32> [[B:%.*]]) #[[ATTR0]] { ; CHECK-NEXT: [[ENTRY:.*:]] ; CHECK-NEXT: call void @llvm.aarch64.neon.st1x3.v4i32.p0(<4 x i32> [[A]], <4 x i32> [[B]], <4 x i32> [[B]], ptr [[P]]) ; CHECK-NEXT: call void @llvm.aarch64.neon.st1x2.v4i32.p0(<4 x i32> [[A]], <4 x i32> [[A]], ptr [[P]]) ; CHECK-NEXT: ret void ; entry: call void @llvm.aarch64.neon.st1x3.v4i32.p0(<4 x i32> %A, <4 x i32> %B, <4 x i32> %B, ptr %p) call void @llvm.aarch64.neon.st1x2.v4i32.p0(<4 x i32> %A, <4 x i32> %A, ptr %p) ret void } ; Check that st1x4 is not optimized away by EarlyCSE. define void @test_no_cse_for_ld1x4_st1x4(ptr %p, <16 x i8> %A, <16 x i8> %B) { ; CHECK-LABEL: define void @test_no_cse_for_ld1x4_st1x4( ; CHECK-SAME: ptr [[P:%.*]], <16 x i8> [[A:%.*]], <16 x i8> [[B:%.*]]) #[[ATTR0]] { ; CHECK-NEXT: [[ENTRY:.*:]] ; CHECK-NEXT: [[LD:%.*]] = call { <16 x i8>, <16 x i8>, <16 x i8>, <16 x i8> } @llvm.aarch64.neon.ld1x4.v16i8.p0(ptr [[P]]) ; CHECK-NEXT: [[EXT:%.*]] = extractvalue { <16 x i8>, <16 x i8>, <16 x i8>, <16 x i8> } [[LD]], 0 ; CHECK-NEXT: call void @llvm.aarch64.neon.st1x4.v16i8.p0(<16 x i8> [[EXT]], <16 x i8> [[A]], <16 x i8> [[B]], <16 x i8> zeroinitializer, ptr [[P]]) ; CHECK-NEXT: ret void ; entry: %ld = call { <16 x i8>, <16 x i8>, <16 x i8>, <16 x i8> } @llvm.aarch64.neon.ld1x4.v16i8.p0(ptr %p) %ext = extractvalue { <16 x i8>, <16 x i8>, <16 x i8>, <16 x i8> } %ld, 0 call void @llvm.aarch64.neon.st1x4.v16i8.p0(<16 x i8> %ext, <16 x i8> %A, <16 x i8> %B, <16 x i8> zeroinitializer, ptr %p) ret void } ; Check that st1x4 is not optimized away by EarlyCSE. define void @test_no_cse_for_ld2_st1x2(ptr %p) { ; CHECK-LABEL: define void @test_no_cse_for_ld2_st1x2( ; CHECK-SAME: ptr [[P:%.*]]) #[[ATTR0]] { ; CHECK-NEXT: [[ENTRY:.*:]] ; CHECK-NEXT: [[LD:%.*]] = call { <4 x i32>, <4 x i32> } @llvm.aarch64.neon.ld2.v4i32.p0(ptr [[P]]) ; CHECK-NEXT: [[X0:%.*]] = extractvalue { <4 x i32>, <4 x i32> } [[LD]], 0 ; CHECK-NEXT: [[X1:%.*]] = extractvalue { <4 x i32>, <4 x i32> } [[LD]], 1 ; CHECK-NEXT: call void @llvm.aarch64.neon.st1x2.v4i32.p0(<4 x i32> [[X0]], <4 x i32> [[X1]], ptr [[P]]) ; CHECK-NEXT: ret void ; entry: %ld = call { <4 x i32>, <4 x i32> } @llvm.aarch64.neon.ld2.v4i32.p0(ptr %p) %x0 = extractvalue { <4 x i32>, <4 x i32> } %ld, 0 %x1 = extractvalue { <4 x i32>, <4 x i32> } %ld, 1 call void @llvm.aarch64.neon.st1x2.v4i32.p0(<4 x i32> %x0, <4 x i32> %x1, ptr %p) ret void } ; Check that ld1x3 is optimized away by EarlyCSE. define <16 x i8> @test_cse_for_st1x3_ld1x3(ptr %p, <16 x i8> %A, <16 x i8> %B) { ; CHECK-LABEL: define <16 x i8> @test_cse_for_st1x3_ld1x3( ; CHECK-SAME: ptr [[P:%.*]], <16 x i8> [[A:%.*]], <16 x i8> [[B:%.*]]) #[[ATTR0]] { ; CHECK-NEXT: [[ENTRY:.*:]] ; CHECK-NEXT: [[TMP0:%.*]] = insertvalue { <16 x i8>, <16 x i8>, <16 x i8> } poison, <16 x i8> [[A]], 0 ; CHECK-NEXT: [[TMP1:%.*]] = insertvalue { <16 x i8>, <16 x i8>, <16 x i8> } [[TMP0]], <16 x i8> [[A]], 1 ; CHECK-NEXT: [[TMP2:%.*]] = insertvalue { <16 x i8>, <16 x i8>, <16 x i8> } [[TMP1]], <16 x i8> [[B]], 2 ; CHECK-NEXT: call void @llvm.aarch64.neon.st1x3.v16i8.p0(<16 x i8> [[A]], <16 x i8> [[A]], <16 x i8> [[B]], ptr [[P]]) ; CHECK-NEXT: ret <16 x i8> [[A]] ; entry: call void @llvm.aarch64.neon.st1x3.v16i8.p0(<16 x i8> %A, <16 x i8> %A, <16 x i8> %B, ptr %p) %ld = call { <16 x i8>, <16 x i8>, <16 x i8> } @llvm.aarch64.neon.ld1x3.v16i8.p0(ptr %p) %ext = extractvalue { <16 x i8>, <16 x i8>, <16 x i8> } %ld, 0 ret <16 x i8> %ext } ; Check that ld1x4 is optimized away by EarlyCSE. define <16 x i8> @test_cse_for_st1x4_ld1x4(ptr %p, <16 x i8> %A, <16 x i8> %B) { ; CHECK-LABEL: define <16 x i8> @test_cse_for_st1x4_ld1x4( ; CHECK-SAME: ptr [[P:%.*]], <16 x i8> [[A:%.*]], <16 x i8> [[B:%.*]]) #[[ATTR0]] { ; CHECK-NEXT: [[ENTRY:.*:]] ; CHECK-NEXT: [[TMP0:%.*]] = insertvalue { <16 x i8>, <16 x i8>, <16 x i8>, <16 x i8> } poison, <16 x i8> [[A]], 0 ; CHECK-NEXT: [[TMP1:%.*]] = insertvalue { <16 x i8>, <16 x i8>, <16 x i8>, <16 x i8> } [[TMP0]], <16 x i8> [[A]], 1 ; CHECK-NEXT: [[TMP2:%.*]] = insertvalue { <16 x i8>, <16 x i8>, <16 x i8>, <16 x i8> } [[TMP1]], <16 x i8> [[B]], 2 ; CHECK-NEXT: [[TMP3:%.*]] = insertvalue { <16 x i8>, <16 x i8>, <16 x i8>, <16 x i8> } [[TMP2]], <16 x i8> [[B]], 3 ; CHECK-NEXT: call void @llvm.aarch64.neon.st1x4.v16i8.p0(<16 x i8> [[A]], <16 x i8> [[A]], <16 x i8> [[B]], <16 x i8> [[B]], ptr [[P]]) ; CHECK-NEXT: ret <16 x i8> [[A]] ; entry: call void @llvm.aarch64.neon.st1x4.v16i8.p0(<16 x i8> %A, <16 x i8> %A, <16 x i8> %B, <16 x i8> %B, ptr %p) %ld = call { <16 x i8>, <16 x i8>, <16 x i8>, <16 x i8> } @llvm.aarch64.neon.ld1x4.v16i8.p0(ptr %p) %ext = extractvalue { <16 x i8>, <16 x i8>, <16 x i8>, <16 x i8> } %ld, 0 ret <16 x i8> %ext }