1 //===- OCL20To12.cpp - Transform OCL 2.0 builtins to OCL 1.2 builtins -----===// 2 // 3 // The LLVM/SPIRV Translator 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 // Copyright (c) 2014 Advanced Micro Devices, Inc. All rights reserved. 9 // 10 // Permission is hereby granted, free of charge, to any person obtaining a 11 // copy of this software and associated documentation files (the "Software"), 12 // to deal with the Software without restriction, including without limitation 13 // the rights to use, copy, modify, merge, publish, distribute, sublicense, 14 // and/or sell copies of the Software, and to permit persons to whom the 15 // Software is furnished to do so, subject to the following conditions: 16 // 17 // Redistributions of source code must retain the above copyright notice, 18 // this list of conditions and the following disclaimers. 19 // Redistributions in binary form must reproduce the above copyright notice, 20 // this list of conditions and the following disclaimers in the documentation 21 // and/or other materials provided with the distribution. 22 // Neither the names of Advanced Micro Devices, Inc., nor the names of its 23 // contributors may be used to endorse or promote products derived from this 24 // Software without specific prior written permission. 25 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 26 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 27 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 28 // CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 29 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 30 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH 31 // THE SOFTWARE. 32 // 33 //===----------------------------------------------------------------------===// 34 // 35 // This file implements transform OCL 2.0 builtins to OCL 1.2 builtins. 36 // 37 //===----------------------------------------------------------------------===// 38 #define DEBUG_TYPE "ocl20to12" 39 40 #include "SPIRVInternal.h" 41 #include "OCLUtil.h" 42 #include "llvm/ADT/StringSwitch.h" 43 #include "llvm/IR/InstVisitor.h" 44 #include "llvm/IR/Instructions.h" 45 #include "llvm/IR/IRBuilder.h" 46 #include "llvm/IR/Verifier.h" 47 #include "llvm/Pass.h" 48 #include "llvm/PassSupport.h" 49 #include "llvm/Support/Debug.h" 50 #include "llvm/Support/ErrorHandling.h" 51 #include "llvm/Support/raw_ostream.h" 52 53 using namespace llvm; 54 using namespace SPIRV; 55 using namespace OCLUtil; 56 57 namespace SPIRV { 58 class OCL20To12: public ModulePass, 59 public InstVisitor<OCL20To12> { 60 public: 61 OCL20To12():ModulePass(ID), M(nullptr), Ctx(nullptr) { 62 initializeOCL20To12Pass(*PassRegistry::getPassRegistry()); 63 } 64 virtual bool runOnModule(Module &M); 65 virtual void visitCallInst(CallInst &CI); 66 67 /// Transform atomic_work_item_fence to mem_fence. 68 /// atomic_work_item_fence(flag, relaxed, work_group) => 69 /// mem_fence(flag) 70 void visitCallAtomicWorkItemFence(CallInst *CI); 71 72 static char ID; 73 private: 74 Module *M; 75 LLVMContext *Ctx; 76 }; 77 78 char OCL20To12::ID = 0; 79 80 bool 81 OCL20To12::runOnModule(Module& Module) { 82 M = &Module; 83 if (getOCLVersion(M) >= kOCLVer::CL20) 84 return false; 85 86 Ctx = &M->getContext(); 87 visit(*M); 88 89 DEBUG(dbgs() << "After OCL20To12:\n" << *M); 90 91 std::string Err; 92 raw_string_ostream ErrorOS(Err); 93 if (verifyModule(*M, &ErrorOS)){ 94 DEBUG(errs() << "Fails to verify module: " << ErrorOS.str()); 95 } 96 return true; 97 } 98 99 void 100 OCL20To12::visitCallInst(CallInst& CI) { 101 DEBUG(dbgs() << "[visistCallInst] " << CI << '\n'); 102 auto F = CI.getCalledFunction(); 103 if (!F) 104 return; 105 106 auto MangledName = F->getName(); 107 std::string DemangledName; 108 if (!oclIsBuiltin(MangledName, &DemangledName)) 109 return; 110 DEBUG(dbgs() << "DemangledName = " << DemangledName.c_str() << '\n'); 111 112 if (DemangledName == kOCLBuiltinName::AtomicWorkItemFence) { 113 visitCallAtomicWorkItemFence(&CI); 114 return; 115 } 116 } 117 118 void OCL20To12::visitCallAtomicWorkItemFence(CallInst* CI) { 119 auto Lit = getAtomicWorkItemFenceLiterals(CI); 120 if (std::get<1>(Lit) != OCLLegacyAtomicMemOrder || 121 std::get<2>(Lit) != OCLLegacyAtomicMemScope) 122 report_fatal_error("OCL 2.0 builtin atomic_work_item_fence used in 1.2", 123 false); 124 125 AttributeSet Attrs = CI->getCalledFunction()->getAttributes(); 126 mutateCallInstOCL(M, CI, [=](CallInst *, std::vector<Value *> &Args){ 127 Args.resize(1); 128 Args[0] = getInt32(M, std::get<0>(Lit)); 129 return kOCLBuiltinName::MemFence; 130 }, &Attrs); 131 } 132 133 } 134 135 INITIALIZE_PASS(OCL20To12, "ocl20to12", 136 "Translate OCL 2.0 builtins to OCL 1.2 builtins", false, false) 137 138 ModulePass *llvm::createOCL20To12() { 139 return new OCL20To12(); 140 } 141