aboutsummaryrefslogtreecommitdiff
path: root/src/llvmopencl/Flatten.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/llvmopencl/Flatten.cc')
-rw-r--r--src/llvmopencl/Flatten.cc158
1 files changed, 158 insertions, 0 deletions
diff --git a/src/llvmopencl/Flatten.cc b/src/llvmopencl/Flatten.cc
new file mode 100644
index 0000000..2e01f2a
--- /dev/null
+++ b/src/llvmopencl/Flatten.cc
@@ -0,0 +1,158 @@
+// LLVM module pass to inline required functions (those accessing
+// per-workgroup variables) into the kernel.
+//
+// Copyright (c) 2011 Universidad Rey Juan Carlos
+// Copyright (c) 2013-2014, Texas Instruments Incorporated - http://www.ti.com/
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "Flatten.h"
+using namespace pocl;
+
+extern cl::opt<std::string> KernelName;
+
+char Flatten::ID = 0;
+static RegisterPass<Flatten> X("flatten", "Kernel function flattening pass");
+
+static const char *workgroup_variables[] = {
+ "_local_id_x", "_local_id_y", "_local_id_z",
+ "_local_size_x", "_local_size_y", "_local_size_z",
+ "_work_dim",
+ "_num_groups_x", "_num_groups_y", "_num_groups_z",
+ "_group_id_x", "_group_id_y", "_group_id_z",
+ "_global_offset_x", "_global_offset_y", "_global_offset_z",
+ NULL};
+
+//#define DEBUG_FLATTEN
+
+#define INLINE_ALL_NON_KERNEL
+
+#ifdef INLINE_ALL_NON_KERNEL
+
+bool
+Flatten::runOnModule(Module &M)
+{
+ bool changed = false;
+ for (llvm::Module::iterator i = M.begin(), e = M.end(); i != e; ++i)
+ {
+ llvm::Function *f = i;
+ if (f->isDeclaration()) continue;
+ if (KernelName == f->getName() ||
+ (KernelName == "" && pocl::Workgroup::isKernelToProcess(*f)))
+ {
+#ifdef LLVM_3_1
+ f->removeFnAttr(Attribute::AlwaysInline);
+ f->addFnAttr(Attribute::NoInline);
+#elif defined LLVM_3_2
+ AttrBuilder b;
+ f->removeFnAttr(Attributes::get(M.getContext(), b.addAttribute(Attributes::AlwaysInline)));
+ f->addFnAttr(Attributes::NoInline);
+#else
+ AttributeSet attrs;
+ f->removeAttributes(
+ AttributeSet::FunctionIndex,
+ attrs.addAttribute(M.getContext(), AttributeSet::FunctionIndex, Attribute::AlwaysInline));
+
+ f->addFnAttr(Attribute::NoInline);
+#endif
+
+ f->setLinkage(llvm::GlobalValue::ExternalLinkage);
+ changed = true;
+#ifdef DEBUG_FLATTEN
+ std::cerr << "### NoInline for " << f->getName().str() << std::endl;
+#endif
+ }
+ else
+ {
+#ifdef LLVM_3_1
+ f->removeFnAttr(Attribute::NoInline);
+ f->addFnAttr(Attribute::AlwaysInline);
+#elif defined LLVM_3_2
+ AttrBuilder b;
+ f->removeFnAttr(Attributes::get(M.getContext(), b.addAttribute(Attributes::NoInline)));
+ f->addFnAttr(Attributes::AlwaysInline);
+#else
+ AttributeSet attrs;
+ f->removeAttributes(
+ AttributeSet::FunctionIndex,
+ attrs.addAttribute(M.getContext(), AttributeSet::FunctionIndex, Attribute::NoInline));
+ f->addFnAttr(Attribute::AlwaysInline);
+#endif
+
+ f->setLinkage(llvm::GlobalValue::InternalLinkage);
+ changed = true;
+#ifdef DEBUG_FLATTEN
+ std::cerr << "### AlwaysInline for " << f->getName().str() << std::endl;
+#endif
+ }
+ }
+ return changed;
+}
+
+#else
+
+bool
+Flatten::runOnModule(Module &M)
+{
+ SmallPtrSet<Function *, 8> functions_to_inline;
+ SmallVector<Value *, 8> pending;
+
+ const char **s = workgroup_variables;
+ while (*s != NULL) {
+ GlobalVariable *gv = M.getGlobalVariable(*s);
+ if (gv != NULL)
+ pending.push_back(gv);
+
+ ++s;
+ }
+
+ while (!pending.empty()) {
+ Value *v = pending.back();
+ pending.pop_back();
+
+ for (Value::use_iterator i = v->use_begin(), e = v->use_end();
+ i != e; ++i) {
+ if (Instruction *ci = dyn_cast<Instruction>(*i)) {
+ // Prevent infinite looping on recursive functions
+ // (though OpenCL does not allow this?)
+ Function *f = ci->getParent()->getParent();;
+ assert((f != NULL) &&
+ "Per-workgroup global variable used on function with no parent!");
+ if (functions_to_inline.count(f))
+ continue;
+
+ functions_to_inline.insert(f);
+ pending.push_back(f);
+ }
+ }
+ }
+
+ for (SmallPtrSet<Function *, 8>::iterator i = functions_to_inline.begin(),
+ e = functions_to_inline.end();
+ i != e; ++i) {
+ (*i)->removeFnAttr(Attribute::NoInline);
+ (*i)->addFnAttr(Attribute::AlwaysInline);
+ }
+
+ return true;
+}
+
+#endif
+
+