clang API Documentation
00001 //===----- CGCUDANV.cpp - Interface to NVIDIA CUDA Runtime ----------------===// 00002 // 00003 // The LLVM Compiler Infrastructure 00004 // 00005 // This file is distributed under the University of Illinois Open Source 00006 // License. See LICENSE.TXT for details. 00007 // 00008 //===----------------------------------------------------------------------===// 00009 // 00010 // This provides a class for CUDA code generation targeting the NVIDIA CUDA 00011 // runtime library. 00012 // 00013 //===----------------------------------------------------------------------===// 00014 00015 #include "CGCUDARuntime.h" 00016 #include "CodeGenFunction.h" 00017 #include "CodeGenModule.h" 00018 #include "clang/AST/Decl.h" 00019 #include "llvm/IR/BasicBlock.h" 00020 #include "llvm/IR/CallSite.h" 00021 #include "llvm/IR/Constants.h" 00022 #include "llvm/IR/DerivedTypes.h" 00023 #include <vector> 00024 00025 using namespace clang; 00026 using namespace CodeGen; 00027 00028 namespace { 00029 00030 class CGNVCUDARuntime : public CGCUDARuntime { 00031 00032 private: 00033 llvm::Type *IntTy, *SizeTy; 00034 llvm::PointerType *CharPtrTy, *VoidPtrTy; 00035 00036 llvm::Constant *getSetupArgumentFn() const; 00037 llvm::Constant *getLaunchFn() const; 00038 00039 public: 00040 CGNVCUDARuntime(CodeGenModule &CGM); 00041 00042 void EmitDeviceStubBody(CodeGenFunction &CGF, FunctionArgList &Args) override; 00043 }; 00044 00045 } 00046 00047 CGNVCUDARuntime::CGNVCUDARuntime(CodeGenModule &CGM) : CGCUDARuntime(CGM) { 00048 CodeGen::CodeGenTypes &Types = CGM.getTypes(); 00049 ASTContext &Ctx = CGM.getContext(); 00050 00051 IntTy = Types.ConvertType(Ctx.IntTy); 00052 SizeTy = Types.ConvertType(Ctx.getSizeType()); 00053 00054 CharPtrTy = llvm::PointerType::getUnqual(Types.ConvertType(Ctx.CharTy)); 00055 VoidPtrTy = cast<llvm::PointerType>(Types.ConvertType(Ctx.VoidPtrTy)); 00056 } 00057 00058 llvm::Constant *CGNVCUDARuntime::getSetupArgumentFn() const { 00059 // cudaError_t cudaSetupArgument(void *, size_t, size_t) 00060 std::vector<llvm::Type*> Params; 00061 Params.push_back(VoidPtrTy); 00062 Params.push_back(SizeTy); 00063 Params.push_back(SizeTy); 00064 return CGM.CreateRuntimeFunction(llvm::FunctionType::get(IntTy, 00065 Params, false), 00066 "cudaSetupArgument"); 00067 } 00068 00069 llvm::Constant *CGNVCUDARuntime::getLaunchFn() const { 00070 // cudaError_t cudaLaunch(char *) 00071 std::vector<llvm::Type*> Params; 00072 Params.push_back(CharPtrTy); 00073 return CGM.CreateRuntimeFunction(llvm::FunctionType::get(IntTy, 00074 Params, false), 00075 "cudaLaunch"); 00076 } 00077 00078 void CGNVCUDARuntime::EmitDeviceStubBody(CodeGenFunction &CGF, 00079 FunctionArgList &Args) { 00080 // Build the argument value list and the argument stack struct type. 00081 SmallVector<llvm::Value *, 16> ArgValues; 00082 std::vector<llvm::Type *> ArgTypes; 00083 for (FunctionArgList::const_iterator I = Args.begin(), E = Args.end(); 00084 I != E; ++I) { 00085 llvm::Value *V = CGF.GetAddrOfLocalVar(*I); 00086 ArgValues.push_back(V); 00087 assert(isa<llvm::PointerType>(V->getType()) && "Arg type not PointerType"); 00088 ArgTypes.push_back(cast<llvm::PointerType>(V->getType())->getElementType()); 00089 } 00090 llvm::StructType *ArgStackTy = llvm::StructType::get( 00091 CGF.getLLVMContext(), ArgTypes); 00092 00093 llvm::BasicBlock *EndBlock = CGF.createBasicBlock("setup.end"); 00094 00095 // Emit the calls to cudaSetupArgument 00096 llvm::Constant *cudaSetupArgFn = getSetupArgumentFn(); 00097 for (unsigned I = 0, E = Args.size(); I != E; ++I) { 00098 llvm::Value *Args[3]; 00099 llvm::BasicBlock *NextBlock = CGF.createBasicBlock("setup.next"); 00100 Args[0] = CGF.Builder.CreatePointerCast(ArgValues[I], VoidPtrTy); 00101 Args[1] = CGF.Builder.CreateIntCast( 00102 llvm::ConstantExpr::getSizeOf(ArgTypes[I]), 00103 SizeTy, false); 00104 Args[2] = CGF.Builder.CreateIntCast( 00105 llvm::ConstantExpr::getOffsetOf(ArgStackTy, I), 00106 SizeTy, false); 00107 llvm::CallSite CS = CGF.EmitRuntimeCallOrInvoke(cudaSetupArgFn, Args); 00108 llvm::Constant *Zero = llvm::ConstantInt::get(IntTy, 0); 00109 llvm::Value *CSZero = CGF.Builder.CreateICmpEQ(CS.getInstruction(), Zero); 00110 CGF.Builder.CreateCondBr(CSZero, NextBlock, EndBlock); 00111 CGF.EmitBlock(NextBlock); 00112 } 00113 00114 // Emit the call to cudaLaunch 00115 llvm::Constant *cudaLaunchFn = getLaunchFn(); 00116 llvm::Value *Arg = CGF.Builder.CreatePointerCast(CGF.CurFn, CharPtrTy); 00117 CGF.EmitRuntimeCallOrInvoke(cudaLaunchFn, Arg); 00118 CGF.EmitBranch(EndBlock); 00119 00120 CGF.EmitBlock(EndBlock); 00121 } 00122 00123 CGCUDARuntime *CodeGen::CreateNVCUDARuntime(CodeGenModule &CGM) { 00124 return new CGNVCUDARuntime(CGM); 00125 }