diff --git a/llvm/test/Transforms/SROA/alloca-struct.ll b/llvm/test/Transforms/SROA/alloca-struct.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Transforms/SROA/alloca-struct.ll @@ -0,0 +1,149 @@ +; RUN: opt < %s -sroa -S | FileCheck %s +; RUN: opt < %s -passes=sroa -S | FileCheck %s +target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +%struct.RetValIntChar = type { i32, i8 } +%struct.RetValTwoInts = type { i32, i32 } +%struct.RetValOneIntTwoChar = type { i32, i8 } + +; Tests that a struct of type {i32, i8} is scalarized by SROA. +; FIXME: SROA should skip scalarization since there is no scalar access. +; Currently scalarization happens due to the mismatch of allocated size +; and the actual structure size. +define i64 @test_struct_of_int_char(i1 zeroext %test, i64 ()* %p) { +; CHECK-LABEL: @test_struct_of_int_char( +; CHECK-NEXT: entry: +; COM: Check that registers are used and alloca instructions are eliminated. +; CHECK-NOT: alloca +; CHECK: if.then: +; CHECK-NEXT: br label [[RETURN:%.*]] +; CHECK: if.end: +; CHECK-NEXT: call i64 [[P:%.*]]() +; CHECK: br label [[RETURN]] +; CHECK: return: +; COM: Check there are more than one PHI nodes to select scalarized values. +; CHECK-COUNT-3: phi +; CHECK: ret i64 +; +entry: + %retval = alloca %struct.RetValIntChar, align 4 + br i1 %test, label %if.then, label %if.end + +if.then: ; preds = %entry + %x = getelementptr inbounds %struct.RetValIntChar, %struct.RetValIntChar* %retval, i32 0, i32 0 + store i32 0, i32* %x, align 4, !tbaa !10 + %y = getelementptr inbounds %struct.RetValIntChar, %struct.RetValIntChar* %retval, i32 0, i32 1 + store i8 0, i8* %y, align 4, !tbaa !13 + br label %return + +if.end: ; preds = %entry + %call = call i64 %p() + %0 = bitcast %struct.RetValIntChar* %retval to i64* + store i64 %call, i64* %0, align 4 + br label %return + +return: ; preds = %if.end, %if.then + %1 = bitcast %struct.RetValIntChar* %retval to i64* + %2 = load i64, i64* %1, align 4 + ret i64 %2 +} + +; Test that the alloca of struct{int, int} will be scalarized by SROA. +define i64 @test_struct_of_two_int(i1 zeroext %test, i64 ()* %p) { +; CHECK-LABEL: @test_struct_of_two_int( +; CHECK-NEXT: entry: +; CHECK-NOT: alloca +; CHECK: if.then: +; CHECK-NEXT: br label [[RETURN:%.*]] +; CHECK: if.end: +; CHECK-NEXT: call i64 +; CHECK: return: +; COM: Check that there are more than one PHI nodes to select the scalarized values. +; CHECK-COUNT-2: phi +; CHECK: ret i64 +; +entry: + %retval = alloca %struct.RetValTwoInts, align 4 + br i1 %test, label %if.then, label %if.end + +if.then: ; preds = %entry + %x = getelementptr inbounds %struct.RetValTwoInts, %struct.RetValTwoInts* %retval, i32 0, i32 0 + store i32 0, i32* %x, align 4, !tbaa !14 + %y = getelementptr inbounds %struct.RetValTwoInts, %struct.RetValTwoInts* %retval, i32 0, i32 1 + store i32 0, i32* %y, align 4, !tbaa !16 + br label %return + +if.end: ; preds = %entry + %call = call i64 %p() + %0 = bitcast %struct.RetValTwoInts* %retval to i64* + store i64 %call, i64* %0, align 4 + br label %return + +return: ; preds = %if.end, %if.then + %1 = bitcast %struct.RetValTwoInts* %retval to i64* + %2 = load i64, i64* %1, align 4 + ret i64 %2 +} + +; Tests that allocated struct type is scalarized when non-constant values are +; stored into its fields. +define i64 @test_one_field_has_runtime_value(i1 zeroext %test, i64 ()* %p) { +; CHECK-LABEL: @test_one_field_has_runtime_value( +; CHECK-NEXT: entry: +; CHECK-NOT: alloca +; CHECK: call void @srand +; CHECK: if.then: +; CHECK-NEXT: call i32 @rand() +; CHECK-NEXT: br label +; CHECK: if.end: +; CHECK-NEXT: call i64 +; CHECK: return: +; CHECK-COUNT-2: phi i32 +; CHECK: ret i64 +; +entry: + %retval = alloca %struct.RetValTwoInts, align 4 + %call = call i64 @time(i64* null) + %conv = trunc i64 %call to i32 + call void @srand(i32 %conv) + br i1 %test, label %if.then, label %if.end + +if.then: ; preds = %entry + %x = getelementptr inbounds %struct.RetValTwoInts, %struct.RetValTwoInts* %retval, i32 0, i32 0 + %call1 = call i32 @rand() + store i32 %call1, i32* %x, align 4, !tbaa !14 + %y = getelementptr inbounds %struct.RetValTwoInts, %struct.RetValTwoInts* %retval, i32 0, i32 1 + store i32 1, i32* %y, align 4, !tbaa !16 + br label %return + +if.end: ; preds = %entry + %call2 = call i64 %p() + %0 = bitcast %struct.RetValTwoInts* %retval to i64* + store i64 %call2, i64* %0, align 4 + br label %return + +return: ; preds = %if.end, %if.then + %1 = bitcast %struct.RetValTwoInts* %retval to i64* + %2 = load i64, i64* %1, align 4 + ret i64 %2 +} + +; Function Attrs: nounwind +declare void @srand(i32) + +; Function Attrs: nounwind +declare i64 @time(i64*) + +; Function Attrs: nounwind +declare i32 @rand() + +!5 = !{!"omnipotent char", !6, i64 0} +!6 = !{!"Simple C++ TBAA"} +!10 = !{!11, !12, i64 0} +!11 = !{!"test_struct_of_int_char", !12, i64 0, !5, i64 4} +!12 = !{!"int", !5, i64 0} +!13 = !{!11, !5, i64 4} +!14 = !{!15, !12, i64 0} +!15 = !{!"test_struct_of_two_int", !12, i64 0, !12, i64 4} +!16 = !{!15, !12, i64 4}