; Example from Milanova, Rountev, and Ryder(Precise Call graphs for C programs with Function Pointers) ; Because table in const, func1, and func2 get inlined into main ;RUN: dsaopt %s -dsa-bu -analyze -check-callees=main,func1,func2 ; ModuleID = 'tt1.o' target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64" target triple = "x86_64-unknown-linux-gnu" %struct.parse_table = type { i8*, i32 ()* } @table = internal constant [2 x %struct.parse_table] [%struct.parse_table { i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str, i64 0, i64 0), i32 ()* @func1 }, %struct.parse_table { i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str1, i64 0, i64 0), i32 ()* @func2 }], align 32 ; <[2 x %struct.parse_table]*> [#uses=2] @.str = private constant [6 x i8] c"name1\00", align 1 ; <[6 x i8]*> [#uses=1] @.str1 = private constant [6 x i8] c"name2\00", align 1 ; <[6 x i8]*> [#uses=1] define internal i32 @func1() nounwind { entry: %retval = alloca i32 ; [#uses=2] %0 = alloca i32 ; [#uses=2] %"alloca point" = bitcast i32 0 to i32 ; [#uses=0] store i32 1, i32* %0, align 4 %1 = load i32, i32* %0, align 4 ; [#uses=1] store i32 %1, i32* %retval, align 4 br label %return return: ; preds = %entry %retval1 = load i32, i32* %retval ; [#uses=1] ret i32 %retval1 } define internal i32 @func2() nounwind { entry: %retval = alloca i32 ; [#uses=2] %0 = alloca i32 ; [#uses=2] %"alloca point" = bitcast i32 0 to i32 ; [#uses=0] store i32 2, i32* %0, align 4 %1 = load i32, i32* %0, align 4 ; [#uses=1] store i32 %1, i32* %retval, align 4 br label %return return: ; preds = %entry %retval1 = load i32, i32* %retval ; [#uses=1] ret i32 %retval1 } define internal i32 ()* @find_p_func(i8* %s) nounwind { entry: %s_addr = alloca i8* ; [#uses=2] %retval = alloca i32 ()* ; [#uses=2] %0 = alloca i32 ()* ; [#uses=3] %i = alloca i32 ; [#uses=6] %"alloca point" = bitcast i32 0 to i32 ; [#uses=0] store i8* %s, i8** %s_addr store i32 0, i32* %i, align 4 br label %bb3 bb: ; preds = %bb3 %1 = load i32, i32* %i, align 4 ; [#uses=1] %2 = sext i32 %1 to i64 ; [#uses=1] %3 = getelementptr inbounds [2 x %struct.parse_table], [2 x %struct.parse_table]* @table, i64 0, i64 %2 ; <%struct.parse_table*> [#uses=1] %4 = getelementptr inbounds %struct.parse_table, %struct.parse_table* %3, i32 0, i32 0 ; [#uses=1] %5 = load i8*, i8** %4, align 8 ; [#uses=1] %6 = load i8*, i8** %s_addr, align 8 ; [#uses=1] %7 = call i32 (...) bitcast (i32 (i8*, i8*)* @strcmp to i32 (...)*)(i8* %5, i8* %6) nounwind readonly ; [#uses=1] %8 = icmp eq i32 %7, 0 ; [#uses=1] br i1 %8, label %bb1, label %bb2 bb1: ; preds = %bb %9 = load i32, i32* %i, align 4 ; [#uses=1] %10 = sext i32 %9 to i64 ; [#uses=1] %11 = getelementptr inbounds [2 x %struct.parse_table], [2 x %struct.parse_table]* @table, i64 0, i64 %10 ; <%struct.parse_table*> [#uses=1] %12 = getelementptr inbounds %struct.parse_table, %struct.parse_table* %11, i32 0, i32 1 ; [#uses=1] %13 = load i32 ()*, i32 ()** %12, align 8 ; [#uses=1] store i32 ()* %13, i32 ()** %0, align 8 br label %bb5 bb2: ; preds = %bb %14 = load i32, i32* %i, align 4 ; [#uses=1] %15 = add nsw i32 %14, 1 ; [#uses=1] store i32 %15, i32* %i, align 4 br label %bb3 bb3: ; preds = %bb2, %entry %16 = load i32, i32* %i, align 4 ; [#uses=1] %17 = icmp sle i32 %16, 1 ; [#uses=1] br i1 %17, label %bb, label %bb4 bb4: ; preds = %bb3 store i32 ()* null, i32 ()** %0, align 8 br label %bb5 bb5: ; preds = %bb4, %bb1 %18 = load i32 ()*, i32 ()** %0, align 8 ; [#uses=1] store i32 ()* %18, i32 ()** %retval, align 8 br label %return return: ; preds = %bb5 %retval6 = load i32 ()*, i32 ()** %retval ; [#uses=1] ret i32 ()* %retval6 } declare i32 @strcmp(i8*, i8*) nounwind readonly define i32 @main(i32 %argc, i8** %argv) nounwind { entry: %argc_addr = alloca i32 ; [#uses=1] %argv_addr = alloca i8** ; [#uses=2] %retval = alloca i32 ; [#uses=1] %parse_func = alloca i32 ()* ; [#uses=3] %"alloca point" = bitcast i32 0 to i32 ; [#uses=0] store i32 %argc, i32* %argc_addr store i8** %argv, i8*** %argv_addr %0 = load i8**, i8*** %argv_addr, align 8 ; [#uses=1] %1 = getelementptr inbounds i8*, i8** %0, i64 1 ; [#uses=1] %2 = load i8*, i8** %1, align 1 ; [#uses=1] %3 = call i32 ()* (i8*) @find_p_func(i8* %2) nounwind ; [#uses=1] store i32 ()* %3, i32 ()** %parse_func, align 8 %4 = load i32 ()*, i32 ()** %parse_func, align 8 ; [#uses=1] %5 = icmp ne i32 ()* %4, null ; [#uses=1] br i1 %5, label %bb, label %bb1 bb: ; preds = %entry %6 = load i32 ()*, i32 ()** %parse_func, align 8 ; [#uses=1] %7 = call i32 %6() nounwind ; [#uses=0] br label %bb1 bb1: ; preds = %bb, %entry br label %return return: ; preds = %bb1 %retval2 = load i32, i32* %retval ; [#uses=1] ret i32 %retval2 }