Strip non-kernel functions from RS2SPIRV compilation
Added a pass to trim out non-kernel functions from the rest of SPIR-V
compilation passes. Also changed/enforced the pass ordering so that dead
globals exposed by this pass are removed prior of SPIR-V compilation.
Bug: 30964317
Test: RSoV, RSTest, RSoV LIT tests on Angler
Change-Id: I689758ae0977bca694341e948842b668f68caac8
diff --git a/rsov/compiler/Android.mk b/rsov/compiler/Android.mk
index 3e9eeb7..de86a0b 100644
--- a/rsov/compiler/Android.mk
+++ b/rsov/compiler/Android.mk
@@ -29,6 +29,7 @@
KernelSignature.cpp \
LinkerModule.cpp \
ReflectionPass.cpp \
+ RemoveNonkernelsPass.cpp \
RSAllocationUtils.cpp \
RSSPIRVWriter.cpp \
unit_tests/LinkerModuleTests.cpp
diff --git a/rsov/compiler/RSSPIRVWriter.cpp b/rsov/compiler/RSSPIRVWriter.cpp
index 000fc41..a23e97e 100644
--- a/rsov/compiler/RSSPIRVWriter.cpp
+++ b/rsov/compiler/RSSPIRVWriter.cpp
@@ -33,6 +33,7 @@
#include "InlinePreparationPass.h"
#include "LinkerModule.h"
#include "ReflectionPass.h"
+#include "RemoveNonkernelsPass.h"
#include <fstream>
#include <sstream>
@@ -83,7 +84,17 @@
M.setTargetTriple(NewTriple);
}
-void addPassesForRS2SPIRV(llvm::legacy::PassManager &PassMgr) {
+void addPassesForRS2SPIRV(llvm::legacy::PassManager &PassMgr,
+ bcinfo::MetadataExtractor &Extractor) {
+ PassMgr.add(createInlinePreparationPass(Extractor));
+ PassMgr.add(createAlwaysInlinerPass());
+ PassMgr.add(createRemoveNonkernelsPass(Extractor));
+ // Delete unreachable globals.
+ PassMgr.add(createGlobalDCEPass());
+ // Remove dead debug info.
+ PassMgr.add(createStripDeadDebugInfoPass());
+ // Remove dead func decls.
+ PassMgr.add(createStripDeadPrototypesPass());
PassMgr.add(createGlobalMergePass());
PassMgr.add(createPromoteMemoryToRegisterPass());
PassMgr.add(createTransOCLMD());
@@ -92,7 +103,6 @@
PassMgr.add(createSPIRVRegularizeLLVM());
PassMgr.add(createSPIRVLowerConstExpr());
PassMgr.add(createSPIRVLowerBool());
- PassMgr.add(createAlwaysInlinerPass());
}
bool WriteSPIRV(Module *M, llvm::raw_ostream &OS, std::string &ErrMsg) {
@@ -108,8 +118,7 @@
DEBUG(dbgs() << "Metadata extracted\n");
llvm::legacy::PassManager PassMgr;
- PassMgr.add(createInlinePreparationPass(ME));
- addPassesForRS2SPIRV(PassMgr);
+ addPassesForRS2SPIRV(PassMgr, ME);
std::ofstream WrapperF;
if (!WrapperOutputFile.empty()) {
diff --git a/rsov/compiler/RemoveNonkernelsPass.cpp b/rsov/compiler/RemoveNonkernelsPass.cpp
new file mode 100644
index 0000000..fb2d9ea
--- /dev/null
+++ b/rsov/compiler/RemoveNonkernelsPass.cpp
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2017, The Android Open Source Project
+ *
+ * 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 "RemoveNonkernelsPass.h"
+
+#include "bcinfo/MetadataExtractor.h"
+
+#include "llvm/ADT/StringSet.h"
+#include "llvm/IR/Attributes.h"
+#include "llvm/IR/Constants.h"
+#include "llvm/IR/Module.h"
+#include "llvm/IR/PassManager.h"
+#include "llvm/Pass.h"
+#include "llvm/Support/Debug.h"
+
+#define DEBUG_TYPE "rs2spirv-remove"
+
+using namespace llvm;
+
+namespace rs2spirv {
+
+namespace {
+
+class RemoveNonkernelsPass : public ModulePass {
+ bcinfo::MetadataExtractor &ME;
+
+public:
+ static char ID;
+ explicit RemoveNonkernelsPass(bcinfo::MetadataExtractor &Extractor)
+ : ModulePass(ID), ME(Extractor) {}
+
+ const char *getPassName() const override { return "RemoveNonkernelsPass"; }
+
+ bool runOnModule(Module &M) override {
+ DEBUG(dbgs() << "RemoveNonkernelsPass\n");
+ DEBUG(M.dump());
+
+ const size_t RSKernelNum = ME.getExportForEachSignatureCount();
+ const char **RSKernelNames = ME.getExportForEachNameList();
+ if (RSKernelNum == 0)
+ DEBUG(dbgs() << "RemoveNonkernelsPass detected no kernel\n");
+
+ StringSet<> KNames;
+ for (size_t i = 0; i < RSKernelNum; ++i)
+ KNames.insert(RSKernelNames[i]);
+
+ std::vector<Function *> Functions;
+ for (auto &F : M.functions()) {
+ Functions.push_back(&F);
+ }
+
+ for (auto &F : Functions) {
+ if (F->isDeclaration())
+ continue;
+
+ const StringRef FName = F->getName();
+
+ if (KNames.count(FName) != 0)
+ continue; // Skip kernels.
+
+ F->replaceAllUsesWith(UndefValue::get((Type *)F->getType()));
+ F->eraseFromParent();
+
+ DEBUG(dbgs() << "Removed:\t" << FName << '\n');
+ }
+
+ // Return true, as the pass modifies module.
+ DEBUG(M.dump());
+ DEBUG(dbgs() << "Done removal\n");
+
+ return true;
+ }
+};
+}
+
+char RemoveNonkernelsPass::ID = 0;
+
+ModulePass *createRemoveNonkernelsPass(bcinfo::MetadataExtractor &ME) {
+ return new RemoveNonkernelsPass(ME);
+}
+
+} // namespace rs2spirv
diff --git a/rsov/compiler/RemoveNonkernelsPass.h b/rsov/compiler/RemoveNonkernelsPass.h
new file mode 100644
index 0000000..ec2a561
--- /dev/null
+++ b/rsov/compiler/RemoveNonkernelsPass.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2017, The Android Open Source Project
+ *
+ * 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.
+ */
+
+#ifndef RS2SPIRV_REMOVE_NONKERNELS_PASS_H
+#define RS2SPIRV_REMOVE_NONKERNELS_PASS_H
+
+namespace llvm {
+class ModulePass;
+}
+
+namespace bcinfo {
+class MetadataExtractor;
+}
+
+namespace rs2spirv {
+
+llvm::ModulePass *
+createRemoveNonkernelsPass(bcinfo::MetadataExtractor &Extractor);
+
+} // namespace rs2spirv
+
+#endif
diff --git a/rsov/compiler/tests/single_kernel/mixed.ll b/rsov/compiler/tests/single_kernel/mixed.ll
new file mode 100644
index 0000000..7000ceb
--- /dev/null
+++ b/rsov/compiler/tests/single_kernel/mixed.ll
@@ -0,0 +1,66 @@
+; RUN: rs2spirv_lit_driver.sh %s | FileCheck %s
+; CHECK: OpEntryPoint GLCompute %__rsov_entry_inc "inc" %gl_GlobalInvocationID
+; CHECK-NOT: an_invokable
+
+target datalayout = "e-p:32:32-i64:64-v128:64:128-n32-S64"
+target triple = "armv7-none-linux-gnueabi"
+
+@.str = private unnamed_addr constant [24 x i8] c"test_root_output FAILED\00", align 1
+
+; Function Attrs: nounwind
+define void @an_invokable(float %i) local_unnamed_addr #0 {
+entry:
+ %call = tail call fastcc float @sum(float %i, float 2.000000e+00)
+ %conv = fptosi float %call to i32
+ tail call void @_Z7rsDebugPKci(i8* getelementptr inbounds ([24 x i8], [24 x i8]* @.str, i32 0, i32 0), i32 %conv) #4
+ ret void
+}
+
+declare void @_Z7rsDebugPKci(i8*, i32) local_unnamed_addr #1
+
+; Function Attrs: norecurse nounwind readnone
+define internal fastcc float @sum(float %i, float %j) unnamed_addr #2 {
+entry:
+ %add = fadd float %i, %j
+ ret float %add
+}
+
+; Function Attrs: norecurse nounwind readnone
+define float @inc(float %i) local_unnamed_addr #2 {
+entry:
+ %call = tail call fastcc float @sum(float %i, float 1.000000e+00)
+ ret float %call
+}
+
+; Function Attrs: noinline nounwind
+define void @.helper_an_invokable({ float }* nocapture) local_unnamed_addr #3 {
+entry:
+ %1 = getelementptr inbounds { float }, { float }* %0, i32 0, i32 0
+ %2 = load float, float* %1, align 4
+ tail call void @an_invokable(float %2)
+ ret void
+}
+
+attributes #0 = { nounwind "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "stack-protector-buffer-size"="0" "stackrealign" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "stack-protector-buffer-size"="0" "stackrealign" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #2 = { norecurse nounwind readnone "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "stack-protector-buffer-size"="0" "stackrealign" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #3 = { noinline nounwind }
+attributes #4 = { nounwind }
+
+!llvm.module.flags = !{!0, !1}
+!llvm.ident = !{!2}
+!\23pragma = !{!3, !4}
+!\23rs_export_func = !{!5}
+!\23rs_export_foreach_name = !{!6, !7}
+!\23rs_export_foreach = !{!8, !9}
+
+!0 = !{i32 1, !"wchar_size", i32 4}
+!1 = !{i32 1, !"min_enum_size", i32 4}
+!2 = !{!"Android clang version 3.8.275480 (based on LLVM 3.8.275480)"}
+!3 = !{!"version", !"1"}
+!4 = !{!"java_package_name", !"rs2spirv"}
+!5 = !{!".helper_an_invokable"}
+!6 = !{!"root"}
+!7 = !{!"inc"}
+!8 = !{!"0"}
+!9 = !{!"35"}