-
Notifications
You must be signed in to change notification settings - Fork 11.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Utils: Add utility pass to lower ifuncs
Create a global constructor which will initialize a global table of function pointers. For now, this is only used as a reduction technique for llvm-reduce. In the future this may be useful to support ifunc on systems where the program loader doesn't natively support it.
- Loading branch information
Showing
12 changed files
with
610 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
//===-- LowerIFunc.h --------------------------------------------*- C++ -*-===// | ||
// | ||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
// See https://llvm.org/LICENSE.txt for license information. | ||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
// | ||
//===----------------------------------------------------------------------===// | ||
|
||
#ifndef LLVM_TRANSFORMS_UTILS_LOWERIFUNC_H | ||
#define LLVM_TRANSFORMS_UTILS_LOWERIFUNC_H | ||
|
||
#include "llvm/IR/PassManager.h" | ||
|
||
namespace llvm { | ||
|
||
/// Pass to replace calls to ifuncs with indirect calls. This could be used to | ||
/// support ifunc on systems where the program loader does not natively support | ||
/// it. Constant initializer uses of ifuncs are not handled. | ||
class LowerIFuncPass : public PassInfoMixin<LowerIFuncPass> { | ||
public: | ||
LowerIFuncPass() = default; | ||
|
||
PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM); | ||
}; | ||
|
||
} // end namespace llvm | ||
|
||
#endif // LLVM_TRANSFORMS_UTILS_LOWERIFUNC_H |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
//===- LowerIFunc.cpp -----------------------------------------------------===// | ||
// | ||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
// See https://llvm.org/LICENSE.txt for license information. | ||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
// | ||
//===----------------------------------------------------------------------===// | ||
// | ||
// This file implements replacing calls to ifuncs by introducing indirect calls. | ||
// | ||
//===----------------------------------------------------------------------===// | ||
|
||
#include "llvm/Transforms/Utils/LowerIFunc.h" | ||
#include "llvm/IR/Module.h" | ||
#include "llvm/Pass.h" | ||
#include "llvm/Transforms/Utils/ModuleUtils.h" | ||
|
||
using namespace llvm; | ||
|
||
/// Replace all call users of ifuncs in the module. | ||
PreservedAnalyses LowerIFuncPass::run(Module &M, ModuleAnalysisManager &AM) { | ||
if (M.ifunc_empty()) | ||
return PreservedAnalyses::all(); | ||
|
||
lowerGlobalIFuncUsersAsGlobalCtor(M, {}); | ||
return PreservedAnalyses::none(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-globals --include-generated-funcs | ||
; RUN: opt -S -passes=lower-ifunc < %s | FileCheck %s | ||
|
||
define ptr @resolver() { | ||
ret ptr inttoptr (i64 333 to ptr) | ||
} | ||
|
||
@resolver_alias = alias ptr (), ptr @resolver | ||
@ifunc_alias = alias ptr (), ptr @resolver_alias | ||
|
||
@ifunc0_kept = ifunc float (i64), ptr @resolver_alias | ||
@ifunc1_removed = ifunc float (i64), ptr @resolver_alias | ||
|
||
@ifunc_def = ifunc float (i64), ptr @resolver | ||
@alias_of_ifunc = alias float (i64), ptr @ifunc_def | ||
|
||
define float @call_ifunc_aliasee(i64 %arg) { | ||
%call = call float @ifunc1_removed(i64 %arg) | ||
ret float %call | ||
} | ||
|
||
define float @call_alias_of_ifunc(i64 %arg) { | ||
%call = call float @alias_of_ifunc(i64 %arg) | ||
ret float %call | ||
} | ||
;. | ||
; CHECK: @[[GLOB0:[0-9]+]] = internal global [3 x ptr] poison, align 8 | ||
; CHECK: @[[LLVM_GLOBAL_CTORS:[a-zA-Z0-9_$"\\.-]+]] = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 10, ptr @[[GLOB1:[0-9]+]], ptr null }] | ||
; CHECK: @[[RESOLVER_ALIAS:[a-zA-Z0-9_$"\\.-]+]] = alias ptr (), ptr @resolver | ||
; CHECK: @[[IFUNC_ALIAS:[a-zA-Z0-9_$"\\.-]+]] = alias ptr (), ptr @resolver_alias | ||
; CHECK: @[[ALIAS_OF_IFUNC:[a-zA-Z0-9_$"\\.-]+]] = alias float (i64), ptr @ifunc_def | ||
; CHECK: @[[IFUNC_DEF:[a-zA-Z0-9_$"\\.-]+]] = ifunc float (i64), ptr @resolver | ||
;. | ||
; CHECK-LABEL: define {{[^@]+}}@resolver( | ||
; CHECK-NEXT: ret ptr inttoptr (i64 333 to ptr) | ||
; | ||
; | ||
; CHECK-LABEL: define {{[^@]+}}@call_ifunc_aliasee( | ||
; CHECK-NEXT: [[TMP1:%.*]] = load ptr, ptr getelementptr inbounds ([3 x ptr], ptr @[[GLOB0]], i32 0, i32 1), align 8 | ||
; CHECK-NEXT: [[CALL:%.*]] = call float [[TMP1]](i64 [[ARG:%.*]]) | ||
; CHECK-NEXT: ret float [[CALL]] | ||
; | ||
; | ||
; CHECK-LABEL: define {{[^@]+}}@call_alias_of_ifunc( | ||
; CHECK-NEXT: [[CALL:%.*]] = call float @alias_of_ifunc(i64 [[ARG:%.*]]) | ||
; CHECK-NEXT: ret float [[CALL]] | ||
; | ||
; | ||
; CHECK-LABEL: define {{[^@]+}}@1( | ||
; CHECK-NEXT: [[TMP1:%.*]] = call ptr @resolver() | ||
; CHECK-NEXT: store ptr [[TMP1]], ptr @[[GLOB0]], align 8 | ||
; CHECK-NEXT: [[TMP2:%.*]] = call ptr @resolver() | ||
; CHECK-NEXT: store ptr [[TMP2]], ptr getelementptr inbounds ([3 x ptr], ptr @[[GLOB0]], i32 0, i32 1), align 8 | ||
; CHECK-NEXT: [[TMP3:%.*]] = call ptr @resolver() | ||
; CHECK-NEXT: store ptr [[TMP3]], ptr getelementptr inbounds ([3 x ptr], ptr @[[GLOB0]], i32 0, i32 2), align 8 | ||
; CHECK-NEXT: ret void | ||
; |
34 changes: 34 additions & 0 deletions
34
llvm/test/Transforms/LowerIFunc/ifunc-nonsense-resolvers.ll
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-globals --include-generated-funcs | ||
; RUN: opt -S -passes=lower-ifunc < %s | FileCheck %s | ||
|
||
@ifunc_with_arg = ifunc void (), ptr @resolver_with_arg | ||
|
||
; Test a resolver with an argument (which probably should not be legal | ||
; IR). | ||
define ptr @resolver_with_arg(i64 %arg) { | ||
%cast = inttoptr i64 %arg to ptr | ||
ret ptr %cast | ||
} | ||
|
||
define void @call_with_arg() { | ||
call void @ifunc_with_arg() | ||
ret void | ||
} | ||
;. | ||
; CHECK: @[[GLOB0:[0-9]+]] = internal global [1 x ptr] poison, align 8 | ||
; CHECK: @[[LLVM_GLOBAL_CTORS:[a-zA-Z0-9_$"\\.-]+]] = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 10, ptr @[[GLOB1:[0-9]+]], ptr null }] | ||
; CHECK: @[[IFUNC_WITH_ARG:[a-zA-Z0-9_$"\\.-]+]] = ifunc void (), ptr @resolver_with_arg | ||
;. | ||
; CHECK-LABEL: define {{[^@]+}}@resolver_with_arg( | ||
; CHECK-NEXT: [[CAST:%.*]] = inttoptr i64 [[ARG:%.*]] to ptr | ||
; CHECK-NEXT: ret ptr [[CAST]] | ||
; | ||
; | ||
; CHECK-LABEL: define {{[^@]+}}@call_with_arg( | ||
; CHECK-NEXT: call void @ifunc_with_arg() | ||
; CHECK-NEXT: ret void | ||
; | ||
; | ||
; CHECK-LABEL: define {{[^@]+}}@1( | ||
; CHECK-NEXT: ret void | ||
; |
Oops, something went wrong.