diff --git a/llvm/lib/Transforms/IPO/FunctionSpecialization.cpp b/llvm/lib/Transforms/IPO/FunctionSpecialization.cpp --- a/llvm/lib/Transforms/IPO/FunctionSpecialization.cpp +++ b/llvm/lib/Transforms/IPO/FunctionSpecialization.cpp @@ -675,6 +675,11 @@ continue; auto *V = CS.getArgOperand(A->getArgNo()); + if (isa(V)) + return false; + if (isa(V)) + return false; + // TrackValueOfGlobalVariable only tracks scalar global variables. if (auto *GV = dyn_cast(V)) { // Check if we want to specialize on the address of non-constant diff --git a/llvm/test/Transforms/FunctionSpecialization/function-specialization-constant-expression.ll b/llvm/test/Transforms/FunctionSpecialization/function-specialization-constant-expression.ll --- a/llvm/test/Transforms/FunctionSpecialization/function-specialization-constant-expression.ll +++ b/llvm/test/Transforms/FunctionSpecialization/function-specialization-constant-expression.ll @@ -9,15 +9,37 @@ %struct = type { i8, i16, i32, i64, i64} @Global = internal constant %struct {i8 0, i16 1, i32 2, i64 3, i64 4} +define internal i64 @func2(i64 *%x) { +; CHECK-LABEL: @func2( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[VAL:%.*]] = ptrtoint i64* [[X:%.*]] to i64 +; CHECK-NEXT: ret i64 [[VAL]] +; +entry: + %val = ptrtoint i64* %x to i64 + ret i64 %val +} + +define internal i64 @func(i64 *%x, i64 (i64*)* %binop) { +; CHECK-LABEL: @func( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[TMP0:%.*]] = call i64 [[BINOP:%.*]](i64* [[X:%.*]]) +; CHECK-NEXT: ret i64 [[TMP0]] +; +entry: + %tmp0 = call i64 %binop(i64* %x) + ret i64 %tmp0 +} + define internal i64 @zoo(i1 %flag) { ; CHECK-LABEL: @zoo( ; CHECK-NEXT: entry: ; CHECK-NEXT: br i1 [[FLAG:%.*]], label [[PLUS:%.*]], label [[MINUS:%.*]] ; CHECK: plus: -; CHECK-NEXT: [[TMP0:%.*]] = call i64 @func2.1(i64* getelementptr inbounds ([[STRUCT:%.*]], %struct* @Global, i32 0, i32 3)) +; CHECK-NEXT: [[TMP0:%.*]] = call i64 @func2(i64* getelementptr inbounds ([[STRUCT:%.*]], %struct* @Global, i32 0, i32 3)) ; CHECK-NEXT: br label [[MERGE:%.*]] ; CHECK: minus: -; CHECK-NEXT: [[TMP1:%.*]] = call i64 @func2.2(i64* getelementptr inbounds ([[STRUCT]], %struct* @Global, i32 0, i32 4)) +; CHECK-NEXT: [[TMP1:%.*]] = call i64 @func2(i64* getelementptr inbounds ([[STRUCT]], %struct* @Global, i32 0, i32 4)) ; CHECK-NEXT: br label [[MERGE]] ; CHECK: merge: ; CHECK-NEXT: [[TMP2:%.*]] = phi i64 [ [[TMP0]], [[PLUS]] ], [ [[TMP1]], [[MINUS]] ] @@ -41,27 +63,6 @@ ret i64 %tmp2 } -define internal i64 @func2(i64 *%x) { -; CHECK-LABEL: @func2( -; CHECK-NEXT: entry: -; CHECK-NEXT: [[VAL:%.*]] = ptrtoint i64* [[X:%.*]] to i64 -; CHECK-NEXT: ret i64 [[VAL]] -; -entry: - %val = ptrtoint i64* %x to i64 - ret i64 %val -} - -define internal i64 @func(i64 *%x, i64 (i64*)* %binop) { -; CHECK-LABEL: @func( -; CHECK-NEXT: entry: -; CHECK-NEXT: [[TMP0:%.*]] = call i64 [[BINOP:%.*]](i64* [[X:%.*]]) -; CHECK-NEXT: ret i64 [[TMP0]] -; -entry: - %tmp0 = call i64 %binop(i64* %x) - ret i64 %tmp0 -} define i64 @main() { ; CHECK-LABEL: @main( @@ -75,13 +76,3 @@ %3 = add i64 %1, %2 ret i64 %3 } - -; CHECK-LABEL: define internal i64 @func2.1( -; CHECK-NEXT: entry: -; CHECK-NEXT: ret i64 ptrtoint (i64* getelementptr inbounds (%struct, %struct* @Global, i32 0, i32 3) to i64) -; CHECK-NEXT: } - -; CHECK-LABEL: define internal i64 @func2.2( -; CHECK-NEXT: entry: -; CHECK-NEXT: ret i64 ptrtoint (i64* getelementptr inbounds (%struct, %struct* @Global, i32 0, i32 4) to i64) -; CHECK-NEXT: } diff --git a/llvm/test/Transforms/FunctionSpecialization/function-specialization-constant-expression2.ll b/llvm/test/Transforms/FunctionSpecialization/function-specialization-constant-expression2.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Transforms/FunctionSpecialization/function-specialization-constant-expression2.ll @@ -0,0 +1,44 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt -function-specialization -force-function-specialization -S < %s | FileCheck %s + +; Check that we don't crash and specialise on a constant expression. + +%struct.pluto = type { %struct.spam } +%struct.quux = type { i16 } +%struct.spam = type { i16 } + +@global.5 = external dso_local global [4 x %struct.pluto], align 1 +@global.12 = external global %struct.quux, align 1 + +define internal i16 @wobble.972(%struct.quux* byval(%struct.quux) align 1 %arg, i16 %arg1, %struct.spam* byval(%struct.spam) align 1 %arg2, %struct.quux* byval(%struct.quux) align 1 %arg3) #4 { +; CHECK-LABEL: @wobble.972( +; CHECK-NEXT: bb: +; CHECK-NEXT: [[TMP34:%.*]] = bitcast %struct.spam* [[ARG2:%.*]] to i16* +; CHECK-NEXT: unreachable +; +bb: + %tmp34 = bitcast %struct.spam* %arg2 to i16* + unreachable +} + +define internal i16 @snork() { +; CHECK-LABEL: @snork( +; CHECK-NEXT: bb4: +; CHECK-NEXT: [[TMP:%.*]] = call i16 @wobble.972(%struct.quux* byval([[STRUCT_QUUX:%.*]]) align 1 undef, i16 undef, %struct.spam* byval([[STRUCT_SPAM:%.*]]) align 1 getelementptr inbounds ([4 x %struct.pluto], [4 x %struct.pluto]* @global.5, i32 0, i32 3, i32 0), %struct.quux* byval([[STRUCT_QUUX]]) align 1 @global.12) +; CHECK-NEXT: unreachable +; +bb4: + %tmp = call i16 @wobble.972(%struct.quux* byval(%struct.quux) align 1 undef, i16 undef, %struct.spam* byval(%struct.spam) align 1 getelementptr inbounds ([4 x %struct.pluto], [4 x %struct.pluto]* @global.5, i32 0, i32 3, i32 0), %struct.quux* byval(%struct.quux) align 1 @global.12) + unreachable +} + +define i16 @main() { +; CHECK-LABEL: @main( +; CHECK-NEXT: bb: +; CHECK-NEXT: [[TMP:%.*]] = call i16 @snork() +; CHECK-NEXT: unreachable +; +bb: + %tmp = call i16 @snork() + unreachable +} diff --git a/llvm/test/Transforms/FunctionSpecialization/function-specialization-poison.ll b/llvm/test/Transforms/FunctionSpecialization/function-specialization-poison.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Transforms/FunctionSpecialization/function-specialization-poison.ll @@ -0,0 +1,42 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt -function-specialization -force-function-specialization -S < %s | FileCheck %s + +; Check that we don't crash and specialise on a poison value. + +%struct.quux = type { i16 } +%struct.spam = type { i16 } + +@global.12 = external global %struct.quux, align 1 + +define internal i16 @wobble(%struct.spam* byval(%struct.spam) %arg2) { +; CHECK-LABEL: @wobble( +; CHECK-NEXT: bb: +; CHECK-NEXT: [[C:%.*]] = bitcast %struct.spam* [[ARG2:%.*]] to i16* +; CHECK-NEXT: unreachable +; +bb: + %C = bitcast %struct.spam* %arg2 to i16* + unreachable +} + +define internal i16 @snork() { +; CHECK-LABEL: @snork( +; CHECK-NEXT: bb4: +; CHECK-NEXT: [[B:%.*]] = call i16 @wobble(%struct.spam* poison) +; CHECK-NEXT: unreachable +; +bb4: + %B = call i16 @wobble(%struct.spam* poison) + unreachable +} + +define i16 @main() { +; CHECK-LABEL: @main( +; CHECK-NEXT: bb: +; CHECK-NEXT: [[A:%.*]] = call i16 @snork() +; CHECK-NEXT: unreachable +; +bb: + %A = call i16 @snork() + unreachable +}