Index: clang/lib/CodeGen/CodeGenModule.cpp =================================================================== --- clang/lib/CodeGen/CodeGenModule.cpp +++ clang/lib/CodeGen/CodeGenModule.cpp @@ -5013,8 +5013,10 @@ Aliases.push_back(GD); llvm::Type *DeclTy = getTypes().ConvertTypeForMem(D->getType()); + llvm::Type *ResolverTy = + llvm::FunctionType::get(DeclTy->getPointerTo(), false); llvm::Constant *Resolver = - GetOrCreateLLVMFunction(IFA->getResolver(), DeclTy, GD, + GetOrCreateLLVMFunction(IFA->getResolver(), ResolverTy, GD, /*ForVTable=*/false); llvm::GlobalIFunc *GIF = llvm::GlobalIFunc::create(DeclTy, 0, llvm::Function::ExternalLinkage, Index: llvm/lib/IR/Globals.cpp =================================================================== --- llvm/lib/IR/Globals.cpp +++ llvm/lib/IR/Globals.cpp @@ -541,5 +541,5 @@ const Function *GlobalIFunc::getResolverFunction() const { DenseSet Aliases; - return cast(findBaseObject(getResolver(), Aliases)); + return dyn_cast(findBaseObject(getResolver(), Aliases)); } Index: llvm/lib/IR/Verifier.cpp =================================================================== --- llvm/lib/IR/Verifier.cpp +++ llvm/lib/IR/Verifier.cpp @@ -415,6 +415,9 @@ for (const GlobalAlias &GA : M.aliases()) visitGlobalAlias(GA); + for (const GlobalIFunc &GI : M.ifuncs()) + visitGlobalIFunc(GI); + for (const NamedMDNode &NMD : M.named_metadata()) visitNamedMDNode(NMD); @@ -440,6 +443,7 @@ void visitGlobalValue(const GlobalValue &GV); void visitGlobalVariable(const GlobalVariable &GV); void visitGlobalAlias(const GlobalAlias &GA); + void visitGlobalIFunc(const GlobalIFunc &GI); void visitAliaseeSubExpr(const GlobalAlias &A, const Constant &C); void visitAliaseeSubExpr(SmallPtrSetImpl &Visited, const GlobalAlias &A, const Constant &C); @@ -821,6 +825,24 @@ visitGlobalValue(GA); } +void Verifier::visitGlobalIFunc(const GlobalIFunc &GI) { + // Pierce through ConstantExprs and GlobalAliases and check that the resolver + // is a Function definition + const Function *Resolver = GI.getResolverFunction(); + Assert(Resolver, "IFunc must have a Function resolver", &GI); + Assert(!Resolver->isDeclarationForLinker(), + "IFunc resolver must be a definition", &GI); + + // Check that the immediate resolver operand (prior to any bitcasts) has a + // pointer-to-function type whose return type matches the ifunc + const auto *ResTy = dyn_cast(GI.getResolver()->getType()); + Assert(ResTy, "IFunc resolver must have a pointer type", &GI); + const auto *ResFuncTy = dyn_cast(ResTy->getElementType()); + Assert(ResFuncTy, "IFunc resolver type must be pointer to function", &GI); + Assert(GI.getType() == ResFuncTy->getReturnType(), + "IFunc resolver return type must match IFunc type", &GI); +} + void Verifier::visitNamedMDNode(const NamedMDNode &NMD) { // There used to be various other llvm.dbg.* nodes, but we don't support // upgrading them and we want to reserve the namespace for future uses. Index: llvm/test/Assembler/ifunc-asm.ll =================================================================== --- llvm/test/Assembler/ifunc-asm.ll +++ llvm/test/Assembler/ifunc-asm.ll @@ -2,11 +2,20 @@ target triple = "x86_64-unknown-linux-gnu" -@foo = ifunc i32 (i32), i64 ()* @foo_ifunc -; CHECK: @foo = ifunc i32 (i32), i64 ()* @foo_ifunc +@foo = ifunc i32 (i32), i32 (i32)* ()* @foo_ifunc +; CHECK: @foo = ifunc i32 (i32), i32 (i32)* ()* @foo_ifunc -define internal i64 @foo_ifunc() { +@strlen = ifunc i64 (i8*), bitcast (i64 (i32*)* ()* @mistyped_strlen_resolver to i64 (i8*)* ()*) +; CHECK: strlen = ifunc i64 (i8*), bitcast (i64 (i32*)* ()* @mistyped_strlen_resolver to i64 (i8*)* ()*) + +define internal i32 (i32)* @foo_ifunc() { +entry: + ret i32 (i32)* null +} +; CHECK: define internal i32 (i32)* @foo_ifunc() + +define internal i64 (i32*)* @mistyped_strlen_resolver() { entry: - ret i64 0 + ret i64 (i32*)* null } -; CHECK: define internal i64 @foo_ifunc() +; CHECK: define internal i64 (i32*)* @mistyped_strlen_resolver() Index: llvm/test/Assembler/ifunc-dsolocal.ll =================================================================== --- llvm/test/Assembler/ifunc-dsolocal.ll +++ llvm/test/Assembler/ifunc-dsolocal.ll @@ -1,9 +1,9 @@ ; RUN: llvm-as < %s | llvm-dis | FileCheck %s -@foo = dso_local ifunc i32 (i32), i64 ()* @foo_ifunc -; CHECK: @foo = dso_local ifunc i32 (i32), i64 ()* @foo_ifunc +@foo = dso_local ifunc i32 (i32), i32 (i32)* ()* @foo_ifunc +; CHECK: @foo = dso_local ifunc i32 (i32), i32 (i32)* ()* @foo_ifunc -define internal i64 @foo_ifunc() { +define internal i32 (i32)* @foo_ifunc() { entry: - ret i64 0 + ret i32 (i32)* null } Index: llvm/test/Assembler/ifunc-use-list-order.ll =================================================================== --- llvm/test/Assembler/ifunc-use-list-order.ll +++ llvm/test/Assembler/ifunc-use-list-order.ll @@ -6,11 +6,11 @@ ; Alias for ifunc. @alias_foo = alias void (), void ()* @foo_ifunc -@foo_ifunc = ifunc void (), i8* ()* @foo_resolver +@foo_ifunc = ifunc void (), void ()* ()* @foo_resolver -define i8* @foo_resolver() { +define void ()* @foo_resolver() { entry: - ret i8* null + ret void ()* null } ; Function referencing ifunc. @@ -26,12 +26,11 @@ ; Alias for function. @alias_bar = alias void (), void ()* @bar -@bar_ifunc = ifunc void (), i8* ()* @bar2_ifunc -@bar2_ifunc = ifunc i8* (), i8* ()* @bar_resolver +@bar_ifunc = ifunc void (), void ()* ()* @bar_resolver -define i8* @bar_resolver() { +define void ()* @bar_resolver() { entry: - ret i8* null + ret void ()* null } ; Function referencing bar. Index: llvm/test/Bindings/llvm-c/echo.ll =================================================================== --- llvm/test/Bindings/llvm-c/echo.ll +++ llvm/test/Bindings/llvm-c/echo.ll @@ -29,11 +29,11 @@ @aliased4 = weak alias i32, i32* @var @aliased5 = weak_odr alias i32, i32* @var -@ifunc = ifunc i32 (i32), i64 ()* @ifunc_resolver +@ifunc = ifunc i32 (i32), i32 (i32)* ()* @ifunc_resolver -define i64 @ifunc_resolver() { +define i32 (i32)* @ifunc_resolver() { entry: - ret i64 0 + ret i32 (i32)* null } define { i64, %S* } @unpackrepack(%S %s) { Index: llvm/test/Bitcode/compatibility-6.0.ll =================================================================== --- llvm/test/Bitcode/compatibility-6.0.ll +++ llvm/test/Bitcode/compatibility-6.0.ll @@ -254,24 +254,24 @@ ; * @ ; IFunc -- Linkage -@ifunc.external = external ifunc void (), i8* ()* @ifunc_resolver -; CHECK: @ifunc.external = ifunc void (), i8* ()* @ifunc_resolver -@ifunc.private = private ifunc void (), i8* ()* @ifunc_resolver -; CHECK: @ifunc.private = private ifunc void (), i8* ()* @ifunc_resolver -@ifunc.internal = internal ifunc void (), i8* ()* @ifunc_resolver -; CHECK: @ifunc.internal = internal ifunc void (), i8* ()* @ifunc_resolver +@ifunc.external = external ifunc void (), void ()* ()* @ifunc_resolver +; CHECK: @ifunc.external = ifunc void (), void ()* ()* @ifunc_resolver +@ifunc.private = private ifunc void (), void ()* ()* @ifunc_resolver +; CHECK: @ifunc.private = private ifunc void (), void ()* ()* @ifunc_resolver +@ifunc.internal = internal ifunc void (), void ()* ()* @ifunc_resolver +; CHECK: @ifunc.internal = internal ifunc void (), void ()* ()* @ifunc_resolver ; IFunc -- Visibility -@ifunc.default = default ifunc void (), i8* ()* @ifunc_resolver -; CHECK: @ifunc.default = ifunc void (), i8* ()* @ifunc_resolver -@ifunc.hidden = hidden ifunc void (), i8* ()* @ifunc_resolver -; CHECK: @ifunc.hidden = hidden ifunc void (), i8* ()* @ifunc_resolver -@ifunc.protected = protected ifunc void (), i8* ()* @ifunc_resolver -; CHECK: @ifunc.protected = protected ifunc void (), i8* ()* @ifunc_resolver - -define i8* @ifunc_resolver() { +@ifunc.default = default ifunc void (), void ()* ()* @ifunc_resolver +; CHECK: @ifunc.default = ifunc void (), void ()* ()* @ifunc_resolver +@ifunc.hidden = hidden ifunc void (), void ()* ()* @ifunc_resolver +; CHECK: @ifunc.hidden = hidden ifunc void (), void ()* ()* @ifunc_resolver +@ifunc.protected = protected ifunc void (), void ()* ()* @ifunc_resolver +; CHECK: @ifunc.protected = protected ifunc void (), void ()* ()* @ifunc_resolver + +define void ()* @ifunc_resolver() { entry: - ret i8* null + ret void ()* null } ;; Functions Index: llvm/test/Bitcode/compatibility.ll =================================================================== --- llvm/test/Bitcode/compatibility.ll +++ llvm/test/Bitcode/compatibility.ll @@ -264,28 +264,28 @@ ; * @ ; IFunc -- Linkage -@ifunc.external = external ifunc void (), i8* ()* @ifunc_resolver -; CHECK: @ifunc.external = ifunc void (), i8* ()* @ifunc_resolver -@ifunc.private = private ifunc void (), i8* ()* @ifunc_resolver -; CHECK: @ifunc.private = private ifunc void (), i8* ()* @ifunc_resolver -@ifunc.internal = internal ifunc void (), i8* ()* @ifunc_resolver -; CHECK: @ifunc.internal = internal ifunc void (), i8* ()* @ifunc_resolver +@ifunc.external = external ifunc void (), void ()* ()* @ifunc_resolver +; CHECK: @ifunc.external = ifunc void (), void ()* ()* @ifunc_resolver +@ifunc.private = private ifunc void (), void ()* ()* @ifunc_resolver +; CHECK: @ifunc.private = private ifunc void (), void ()* ()* @ifunc_resolver +@ifunc.internal = internal ifunc void (), void ()* ()* @ifunc_resolver +; CHECK: @ifunc.internal = internal ifunc void (), void ()* ()* @ifunc_resolver ; IFunc -- Visibility -@ifunc.default = default ifunc void (), i8* ()* @ifunc_resolver -; CHECK: @ifunc.default = ifunc void (), i8* ()* @ifunc_resolver -@ifunc.hidden = hidden ifunc void (), i8* ()* @ifunc_resolver -; CHECK: @ifunc.hidden = hidden ifunc void (), i8* ()* @ifunc_resolver -@ifunc.protected = protected ifunc void (), i8* ()* @ifunc_resolver -; CHECK: @ifunc.protected = protected ifunc void (), i8* ()* @ifunc_resolver +@ifunc.default = default ifunc void (), void ()* ()* @ifunc_resolver +; CHECK: @ifunc.default = ifunc void (), void ()* ()* @ifunc_resolver +@ifunc.hidden = hidden ifunc void (), void ()* ()* @ifunc_resolver +; CHECK: @ifunc.hidden = hidden ifunc void (), void ()* ()* @ifunc_resolver +@ifunc.protected = protected ifunc void (), void ()* ()* @ifunc_resolver +; CHECK: @ifunc.protected = protected ifunc void (), void ()* ()* @ifunc_resolver ; IFunc -- partition -; CHECK: @ifunc.partition = ifunc void (), i8* ()* @ifunc_resolver, partition "part" -@ifunc.partition = ifunc void (), i8* ()* @ifunc_resolver, partition "part" +; CHECK: @ifunc.partition = ifunc void (), void ()* ()* @ifunc_resolver, partition "part" +@ifunc.partition = ifunc void (), void ()* ()* @ifunc_resolver, partition "part" -define i8* @ifunc_resolver() { +define void ()* @ifunc_resolver() { entry: - ret i8* null + ret void ()* null } ;; Functions Index: llvm/test/Bitcode/dso_local_equivalent.ll =================================================================== --- llvm/test/Bitcode/dso_local_equivalent.ll +++ llvm/test/Bitcode/dso_local_equivalent.ll @@ -65,12 +65,12 @@ ret void } -@ifunc_func = ifunc void (), i64 ()* @resolver -@dso_local_ifunc_func = dso_local ifunc void (), i64 ()* @resolver +@ifunc_func = ifunc void (), void ()* ()* @resolver +@dso_local_ifunc_func = dso_local ifunc void (), void ()* ()* @resolver -define internal i64 @resolver() { +define internal void ()* @resolver() { entry: - ret i64 0 + ret void ()* null } define void @call_ifunc_func() { Index: llvm/test/Bitcode/dso_location.ll =================================================================== --- llvm/test/Bitcode/dso_location.ll +++ llvm/test/Bitcode/dso_location.ll @@ -27,8 +27,8 @@ @preemptable_alias = dso_preemptable alias i32, i32* @hidden_local_global ; CHECK-DAG: @preemptable_alias = alias i32, i32* @hidden_local_global -@preemptable_ifunc = dso_preemptable ifunc void (), i8* ()* @ifunc_resolver -; CHECK-DAG: @preemptable_ifunc = ifunc void (), i8* ()* @ifunc_resolver +@preemptable_ifunc = dso_preemptable ifunc void (), void ()* ()* @ifunc_resolver +; CHECK-DAG: @preemptable_ifunc = ifunc void (), void ()* ()* @ifunc_resolver declare dso_local default void @default_local() ; CHECK: declare dso_local void @default_local() @@ -41,7 +41,7 @@ ret void } -define i8* @ifunc_resolver() { +define void ()* @ifunc_resolver() { entry: - ret i8* null + ret void ()* null } Index: llvm/test/CodeGen/X86/addrsig.ll =================================================================== --- llvm/test/CodeGen/X86/addrsig.ll +++ llvm/test/CodeGen/X86/addrsig.ll @@ -6,9 +6,9 @@ ; CHECK: .addrsig ; CHECK: .addrsig_sym f1 -define void @f1() { - %f1 = bitcast void()* @f1 to i8* - %f2 = bitcast void()* @f2 to i8* +define void()* @f1() { + %f1 = bitcast void()* ()* @f1 to i8* + %f2 = bitcast void()* ()* @f2 to i8* %f3 = bitcast void()* @f3 to i8* %g1 = bitcast i32* @g1 to i8* %g2 = bitcast i32* @g2 to i8* @@ -34,7 +34,7 @@ declare void @metadata_f2() ; CHECK-NOT: .addrsig_sym f2 -define internal void @f2() local_unnamed_addr { +define internal void()* @f2() local_unnamed_addr { unreachable } @@ -63,9 +63,9 @@ @a2 = internal local_unnamed_addr alias i32, i32* @g2 ; CHECK: .addrsig_sym i1 -@i1 = ifunc void(), void()* @f1 +@i1 = ifunc void(), void()* ()* @f1 ; CHECK-NOT: .addrsig_sym i2 -@i2 = internal local_unnamed_addr ifunc void(), void()* @f2 +@i2 = internal local_unnamed_addr ifunc void(), void()* ()* @f2 declare void @llvm.dbg.value(metadata, metadata, metadata) Index: llvm/test/CodeGen/X86/dso_local_equivalent.ll =================================================================== --- llvm/test/CodeGen/X86/dso_local_equivalent.ll +++ llvm/test/CodeGen/X86/dso_local_equivalent.ll @@ -74,12 +74,12 @@ ret void } -@ifunc_func = ifunc void (), i64 ()* @resolver -@dso_local_ifunc_func = dso_local ifunc void (), i64 ()* @resolver +@ifunc_func = ifunc void (), void ()* ()* @resolver +@dso_local_ifunc_func = dso_local ifunc void (), void ()* ()* @resolver -define internal i64 @resolver() { +define internal void ()* @resolver() { entry: - ret i64 0 + ret void ()* null } ; If an ifunc is not dso_local already, then we should still emit a stub for it Index: llvm/test/CodeGen/X86/ifunc-asm.ll =================================================================== --- llvm/test/CodeGen/X86/ifunc-asm.ll +++ llvm/test/CodeGen/X86/ifunc-asm.ll @@ -2,13 +2,13 @@ target triple = "x86_64-unknown-linux-gnu" -define internal i64 @foo_ifunc() { +define internal i32 (i32)* @foo_ifunc() { entry: - ret i64 0 + ret i32 (i32)* null } ; CHECK: .type foo_ifunc,@function ; CHECK-NEXT: foo_ifunc: -@foo = ifunc i32 (i32), i64 ()* @foo_ifunc +@foo = ifunc i32 (i32), i32 (i32)* ()* @foo_ifunc ; CHECK: .type foo,@gnu_indirect_function ; CHECK-NEXT: .set foo, foo_ifunc Index: llvm/test/CodeGen/X86/partition.ll =================================================================== --- llvm/test/CodeGen/X86/partition.ll +++ llvm/test/CodeGen/X86/partition.ll @@ -17,7 +17,7 @@ ; CHECK-NEXT: .zero 1 ; CHECK-NEXT: .quad i1 -define void @f1() partition "part1" { +define void ()* @f1() partition "part1" { unreachable } @@ -30,4 +30,4 @@ @g1 = global i32 0, partition "part4" @a1 = alias i32, i32* @g1, partition "part5" -@i1 = ifunc void(), void()* @f1, partition "part6" +@i1 = ifunc void(), void()* ()* @f1, partition "part6" Index: llvm/test/LTO/Resolution/X86/Inputs/ifunc2.ll =================================================================== --- llvm/test/LTO/Resolution/X86/Inputs/ifunc2.ll +++ llvm/test/LTO/Resolution/X86/Inputs/ifunc2.ll @@ -1,6 +1,6 @@ target datalayout = "e-p:64:64" target triple = "x86_64-unknown-linux-gnu" -define i32 @foo_resolver() { - ret i32 2 +define i32 ()* @foo_resolver() { + ret i32 ()* inttoptr (i32 2 to i32 ()*) } Index: llvm/test/LTO/Resolution/X86/ifunc.ll =================================================================== --- llvm/test/LTO/Resolution/X86/ifunc.ll +++ llvm/test/LTO/Resolution/X86/ifunc.ll @@ -1,23 +1,15 @@ ; RUN: opt -module-summary -o %t.bc %s -; RUN: llvm-lto2 run %t.bc -r %t.bc,foo,pl -r %t.bc,strlen,pl -o %t2 +; RUN: llvm-lto2 run %t.bc -r %t.bc,foo,pl -o %t2 ; RUN: llvm-nm %t2.1 | FileCheck %s ; CHECK: i foo ; CHECK: t foo_resolver -; CHECK: i strlen -; CHECK: t strlen_resolver 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" -@foo = ifunc i32 (i32), i64 ()* @foo_resolver -@strlen = ifunc i64 (i8*), bitcast (i64 (i8*)* ()* @strlen_resolver to i64 (i8*)*) +@foo = ifunc i32 (i32), i32 (i32)* ()* @foo_resolver -define internal i64 @foo_resolver() { +define internal i32 (i32)* @foo_resolver() { entry: - ret i64 0 -} - -define internal i64 (i8*)* @strlen_resolver() { -entry: - ret i64 (i8*)* null + ret i32 (i32)* null } Index: llvm/test/LTO/Resolution/X86/ifunc2.ll =================================================================== --- llvm/test/LTO/Resolution/X86/ifunc2.ll +++ llvm/test/LTO/Resolution/X86/ifunc2.ll @@ -6,14 +6,14 @@ target datalayout = "e-p:64:64" target triple = "x86_64-unknown-linux-gnu" -; CHECK: @foo = ifunc i32 (), i32 ()* @foo_resolver.2 -@foo = ifunc i32 (), i32 ()* @foo_resolver +; CHECK: @foo = ifunc i32 (), i32 ()* ()* @foo_resolver.2 +@foo = ifunc i32 (), i32 ()* ()* @foo_resolver -; CHECK: define internal i32 @foo_resolver.2() { -; CHECK-NEXT: ret i32 1 -define weak i32 @foo_resolver() { - ret i32 1 +; CHECK: define internal i32 ()* @foo_resolver.2() { +; CHECK-NEXT: ret i32 ()* inttoptr (i32 1 to i32 ()*) +define weak i32 ()* @foo_resolver() { + ret i32 ()* inttoptr (i32 1 to i32 ()*) } -; CHECK: define i32 @foo_resolver() { -; CHECK-NEXT: ret i32 2 +; CHECK: define i32 ()* @foo_resolver() { +; CHECK-NEXT: ret i32 ()* inttoptr (i32 2 to i32 ()*) Index: llvm/test/Linker/ifunc.ll =================================================================== --- llvm/test/Linker/ifunc.ll +++ llvm/test/Linker/ifunc.ll @@ -3,18 +3,18 @@ ;; Check that ifuncs are linked in properly. -; CHECK-DAG: @foo = ifunc void (), bitcast (void ()* ()* @foo_resolve to void ()*) +; CHECK-DAG: @foo = ifunc void (), void ()* ()* @foo_resolve ; CHECK-DAG: define internal void ()* @foo_resolve() { -; CHECK-DAG: @bar = ifunc void (), bitcast (void ()* ()* @bar_resolve to void ()*) +; CHECK-DAG: @bar = ifunc void (), void ()* ()* @bar_resolve ; CHECK-DAG: define internal void ()* @bar_resolve() { ;--- a.ll declare void @bar() ;--- b.ll -@foo = ifunc void (), bitcast (void ()* ()* @foo_resolve to void ()*) -@bar = ifunc void (), bitcast (void ()* ()* @bar_resolve to void ()*) +@foo = ifunc void (), void ()* ()* @foo_resolve +@bar = ifunc void (), void ()* ()* @bar_resolve define internal void ()* @foo_resolve() { ret void ()* null Index: llvm/test/Object/X86/nm-ir.ll =================================================================== --- llvm/test/Object/X86/nm-ir.ll +++ llvm/test/Object/X86/nm-ir.ll @@ -32,12 +32,12 @@ @a1 = alias i32, i32* @g1 @a2 = internal alias i32, i32* @g1 -define void @f1() { +define void ()* @f1() { call void @f5() - ret void + ret void ()* null } -@ifunc_f1 = ifunc void (), void ()* @f1 +@ifunc_f1 = ifunc void (), void ()* ()* @f1 define internal void @f2() { ret void Index: llvm/test/ThinLTO/X86/empty-module.ll =================================================================== --- llvm/test/ThinLTO/X86/empty-module.ll +++ llvm/test/ThinLTO/X86/empty-module.ll @@ -10,9 +10,9 @@ 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" -@foo = ifunc i32 (i32), i64 ()* @foo_ifunc +@foo = ifunc i32 (i32), i32 (i32)* ()* @foo_ifunc -define internal i64 @foo_ifunc() { +define internal i32 (i32)* @foo_ifunc() { entry: - ret i64 0 + ret i32 (i32)* null } Index: llvm/test/Transforms/GlobalDCE/global-ifunc.ll =================================================================== --- llvm/test/Transforms/GlobalDCE/global-ifunc.ll +++ llvm/test/Transforms/GlobalDCE/global-ifunc.ll @@ -2,12 +2,12 @@ target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-unknown-linux-gnu" -@if = ifunc void (), void ()* @fn +@if = ifunc void (), void ()* ()* @fn -define internal void @fn() { +define internal void ()* @fn() { entry: - ret void + ret void ()* null } -; CHECK-DAG: @if = ifunc void (), void ()* @fn -; CHECK-DAG: define internal void @fn( +; CHECK-DAG: @if = ifunc void (), void ()* ()* @fn +; CHECK-DAG: define internal void ()* @fn(