blob: 220d98654add17c04e14d138236fc829ae22ac50 [file] [edit]
// Copyright 2021 The Clspv Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "llvm/IR/Module.h"
#include "llvm/Pass.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Transforms/Utils/Cloning.h"
#include "Builtins.h"
#include "BuiltinsEnum.h"
#include "NativeMathPass.h"
#include "ReplaceOpenCLBuiltinPass.h"
#include "clspv/Option.h"
#include <set>
using namespace llvm;
namespace {
bool is_libclc_builtin(llvm::Function *F) {
return F->getMetadata("clspv_libclc_builtin");
}
} // namespace
PreservedAnalyses clspv::NativeMathPass::run(Module &M,
ModuleAnalysisManager &) {
PreservedAnalyses PA;
auto nativeBuiltins = clspv::Option::UseNativeBuiltins();
for (auto &F : M) {
auto info = clspv::Builtins::Lookup(F.getName());
bool have_native_impl =
Builtins::getExtInstEnum(info) != Builtins::kGlslExtInstBad ||
ReplaceOpenCLBuiltinPass::ReplaceableBuiltins.count(info.getType()) > 0;
if (have_native_impl &&
(nativeBuiltins.count(info.getType()) || clspv::Option::NativeMath())) {
F.deleteBody();
} else if (!have_native_impl && nativeBuiltins.count(info.getType())) {
llvm::report_fatal_error(
llvm::StringRef("--use-native-builtins: couldn't replace builtin '" +
info.getName() + "' with a native implementation!"));
} else if (is_libclc_builtin(&F)) {
// Those builtin has been marked with noinline to make sure that we
// could replace them with native implementation. Now that we know
// that we will not do it, let's remove the attribute so that they
// can be inline if appropriate.
F.removeFnAttr(Attribute::AttrKind::NoInline);
}
}
// Force inlining of builtin inside builtin
bool changed = true;
while (changed) {
std::vector<CallInst *> to_inline;
for (auto &F : M) {
if (is_libclc_builtin(&F)) {
for (auto *user : F.users()) {
if (auto *call = dyn_cast<CallInst>(user)) {
if (is_libclc_builtin(call->getParent()->getParent())) {
to_inline.push_back(call);
}
}
}
}
}
changed = false;
for (auto call : to_inline) {
InlineFunctionInfo IFI;
changed |= InlineFunction(*call, IFI, false, nullptr, false).isSuccess();
}
}
return PA;
}