Index: llvm/include/llvm/IR/Value.h =================================================================== --- llvm/include/llvm/IR/Value.h +++ llvm/include/llvm/IR/Value.h @@ -299,11 +299,16 @@ /// values or constant users. void replaceUsesOutsideBlock(Value *V, BasicBlock *BB); - /// replaceUsesExceptBlockAddr - Go through the uses list for this definition + /// replaceCfiUses - Go through the uses list for this definition /// and make each use point to "V" instead of "this" when the use is outside /// the block. 'This's use list is expected to have at least one element. - /// Unlike replaceAllUsesWith this function skips blockaddr uses. - void replaceUsesExceptBlockAddr(Value *New); + /// Unlike replaceAllUsesWith this function skips blockaddr and direct call + /// uses. + void replaceCfiUses(Value *New); + + /// replaceDirectCalls - Go through the uses list for this definition and + /// replace each use, which is a direct function call. + void replaceDirectCalls(Value *New); //---------------------------------------------------------------------- // Methods for handling the chain of uses of this Value. Index: llvm/lib/IR/Value.cpp =================================================================== --- llvm/lib/IR/Value.cpp +++ llvm/lib/IR/Value.cpp @@ -465,16 +465,22 @@ } } -void Value::replaceUsesExceptBlockAddr(Value *New) { +void Value::replaceCfiUses(Value *New) { SmallSetVector Constants; use_iterator UI = use_begin(), E = use_end(); for (; UI != E;) { Use &U = *UI; ++UI; + // Skip block addresses if (isa(U.getUser())) continue; + // Skip direct calls + auto *Usr = dyn_cast(U.getUser()); + if (Usr && Usr->getCalledFunction() == dyn_cast(this)) + continue; + // Must handle Constants specially, we cannot call replaceUsesOfWith on a // constant because they are uniqued. if (auto *C = dyn_cast(U.getUser())) { @@ -494,6 +500,19 @@ C->handleOperandChange(this, New); } +void Value::replaceDirectCalls(Value *New) { + use_iterator UI = use_begin(), E = use_end(); + for (; UI != E;) { + Use &U = *UI; + ++UI; + + auto *Usr = dyn_cast(U.getUser()); + if (!Usr || Usr->getCalledFunction() != dyn_cast(this)) + continue; + U.set(New); + } +} + namespace { // Various metrics for how much to strip off of pointers. enum PointerStripKind { Index: llvm/lib/Transforms/IPO/LowerTypeTests.cpp =================================================================== --- llvm/lib/Transforms/IPO/LowerTypeTests.cpp +++ llvm/lib/Transforms/IPO/LowerTypeTests.cpp @@ -963,15 +963,17 @@ void LowerTypeTestsModule::importFunction(Function *F, bool isDefinition) { assert(F->getType()->getAddressSpace() == 0); - // Declaration of a local function - nothing to do. - if (F->isDeclarationForLinker() && isDefinition) - return; - GlobalValue::VisibilityTypes Visibility = F->getVisibility(); std::string Name = F->getName(); Function *FDecl; - if (F->isDeclarationForLinker() && !isDefinition) { + if (F->isDeclarationForLinker() && isDefinition) { + FDecl = Function::Create(F->getFunctionType(), GlobalValue::ExternalLinkage, + Name + ".cfi", &M); + FDecl->setVisibility(Visibility); + F->replaceDirectCalls(FDecl); + return; + } else if (F->isDeclarationForLinker() && !isDefinition) { // Declaration of an external function. FDecl = Function::Create(F->getFunctionType(), GlobalValue::ExternalLinkage, Name + ".cfi_jt", &M); @@ -1010,7 +1012,7 @@ if (F->isWeakForLinker()) replaceWeakDeclarationWithJumpTablePtr(F, FDecl); else - F->replaceUsesExceptBlockAddr(FDecl); + F->replaceCfiUses(FDecl); } void LowerTypeTestsModule::lowerTypeTestCalls( @@ -1445,10 +1447,8 @@ FAlias->takeName(F); if (FAlias->hasName()) F->setName(FAlias->getName() + ".cfi"); - F->replaceUsesExceptBlockAddr(FAlias); + F->replaceCfiUses(FAlias); } - if (!F->isDeclarationForLinker()) - F->setLinkage(GlobalValue::InternalLinkage); } createJumpTable(JumpTableFn, Functions); Index: llvm/test/Transforms/LowerTypeTests/Inputs/cfi-direct-call.yaml =================================================================== --- /dev/null +++ llvm/test/Transforms/LowerTypeTests/Inputs/cfi-direct-call.yaml @@ -0,0 +1,9 @@ +--- +TypeIdMap: + typeid1: + TTRes: + Kind: AllOnes +CfiFunctionDefs: + - external +CfiFunctionDecls: +... Index: llvm/test/Transforms/LowerTypeTests/blockaddress.ll =================================================================== --- llvm/test/Transforms/LowerTypeTests/blockaddress.ll +++ llvm/test/Transforms/LowerTypeTests/blockaddress.ll @@ -1,7 +1,7 @@ ; RUN: opt -S %s -lowertypetests | FileCheck %s -; CHECK: define internal i8* @f2.cfi() !type !0 { +; CHECK: define i8* @f2.cfi() !type !0 { ; CHECK-NEXT: br label %b ; CHECK: b: ; CHECK-NEXT: ret i8* blockaddress(@f2.cfi, %b) Index: llvm/test/Transforms/LowerTypeTests/cfi-direct-call.ll =================================================================== --- /dev/null +++ llvm/test/Transforms/LowerTypeTests/cfi-direct-call.ll @@ -0,0 +1,15 @@ +; RUN: opt -lowertypetests -lowertypetests-summary-action=import -lowertypetests-read-summary=%p/Inputs/cfi-direct-call.yaml %s -S | FileCheck %s + +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux" + +declare void @external() + +; CHECK: define i8 @local_a() { +; CHECK-NEXT: call void @external.cfi() +; CHECK-NEXT: ret i8 1 +define i8 @local_a() { + call void @external() + ret i8 1 +} +; CHECK: declare void @external.cfi() Index: llvm/test/Transforms/LowerTypeTests/export-icall.ll =================================================================== --- llvm/test/Transforms/LowerTypeTests/export-icall.ll +++ llvm/test/Transforms/LowerTypeTests/export-icall.ll @@ -50,7 +50,7 @@ ; CHECK-DAG: @g = alias void (), void ()* [[JT2]] -; CHECK-DAG: define internal void @h.cfi(i8 {{.*}}) !type !{{.*}} +; CHECK-DAG: define void @h.cfi(i8 {{.*}}) !type !{{.*}} ; CHECK-DAG: declare !type !{{.*}} void @external() ; CHECK-DAG: declare !type !{{.*}} void @external_weak() ; CHECK-DAG: declare !type !{{.*}} void @f.cfi(i32) Index: llvm/test/Transforms/LowerTypeTests/function-disjoint.ll =================================================================== --- llvm/test/Transforms/LowerTypeTests/function-disjoint.ll +++ llvm/test/Transforms/LowerTypeTests/function-disjoint.ll @@ -11,13 +11,13 @@ ; WASM32: private constant [0 x i8] zeroinitializer @0 = private unnamed_addr constant [2 x void ()*] [void ()* @f, void ()* @g], align 16 -; X64: define internal void @f.cfi() +; X64: define void @f.cfi() ; WASM32: define void @f() !type !{{[0-9]+}} !wasm.index ![[I0:[0-9]+]] define void @f() !type !0 { ret void } -; X64: define internal void @g.cfi() +; X64: define void @g.cfi() ; WASM32: define void @g() !type !{{[0-9]+}} !wasm.index ![[I1:[0-9]+]] define void @g() !type !1 { ret void Index: llvm/test/Transforms/LowerTypeTests/function.ll =================================================================== --- llvm/test/Transforms/LowerTypeTests/function.ll +++ llvm/test/Transforms/LowerTypeTests/function.ll @@ -24,7 +24,7 @@ ; ARM: @g = internal alias void (), bitcast ([4 x i8]* getelementptr inbounds ([2 x [4 x i8]], [2 x [4 x i8]]* bitcast (void ()* @[[JT]] to [2 x [4 x i8]]*), i64 0, i64 1) to void ()*) ; THUMB: @g = internal alias void (), bitcast ([4 x i8]* getelementptr inbounds ([2 x [4 x i8]], [2 x [4 x i8]]* bitcast (void ()* @[[JT]] to [2 x [4 x i8]]*), i64 0, i64 1) to void ()*) -; NATIVE: define internal void @f.cfi() +; NATIVE: define void @f.cfi() ; WASM32: define void @f() !type !{{[0-9]+}} !wasm.index ![[I0:[0-9]+]] define void @f() !type !0 { ret void Index: llvm/test/Transforms/LowerTypeTests/import-icall.ll =================================================================== --- llvm/test/Transforms/LowerTypeTests/import-icall.ll +++ llvm/test/Transforms/LowerTypeTests/import-icall.ll @@ -28,14 +28,14 @@ declare extern_weak void @external_weak() ; CHECK: define hidden i8 @local_a.cfi() { -; CHECK-NEXT: call void @external.cfi_jt() +; CHECK-NEXT: call void @external() ; CHECK-NEXT: call void select (i1 icmp ne (void ()* @external_weak, void ()* null), void ()* @external_weak.cfi_jt, void ()* null)() ; CHECK-NEXT: ret i8 1 ; CHECK-NEXT: } ; internal @local_b is not the same function as "local_b" in the summary. ; CHECK: define internal i8 @local_b() { -; CHECK-NEXT: call i8 @local_a() +; CHECK-NEXT: call i8 @local_a.cfi() ; CHECK: define void @local_decl() ; CHECK-NEXT: call void @local_decl() Index: llvm/test/Transforms/LowerTypeTests/section.ll =================================================================== --- llvm/test/Transforms/LowerTypeTests/section.ll +++ llvm/test/Transforms/LowerTypeTests/section.ll @@ -6,7 +6,7 @@ target triple = "x86_64-unknown-linux-gnu" ; CHECK: @f = alias void (), void ()* @[[JT:.*]] -; CHECK: define internal void @f.cfi() section "xxx" +; CHECK: define void @f.cfi() section "xxx" define void @f() section "xxx" !type !0 { entry: