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/BasicBlock.h" 00020 #include "llvm/Constants.h" 00021 #include "llvm/DerivedTypes.h" 00022 #include "llvm/Support/CallSite.h" 00023 00024 #include <vector> 00025 00026 using namespace clang; 00027 using namespace CodeGen; 00028 00029 namespace { 00030 00031 class CGNVCUDARuntime : public CGCUDARuntime { 00032 00033 private: 00034 llvm::Type *IntTy, *SizeTy; 00035 llvm::PointerType *CharPtrTy, *VoidPtrTy; 00036 00037 llvm::Constant *getSetupArgumentFn() const; 00038 llvm::Constant *getLaunchFn() const; 00039 00040 public: 00041 CGNVCUDARuntime(CodeGenModule &CGM); 00042 00043 void EmitDeviceStubBody(CodeGenFunction &CGF, FunctionArgList &Args); 00044 }; 00045 00046 } 00047 00048 CGNVCUDARuntime::CGNVCUDARuntime(CodeGenModule &CGM) : CGCUDARuntime(CGM) { 00049 CodeGen::CodeGenTypes &Types = CGM.getTypes(); 00050 ASTContext &Ctx = CGM.getContext(); 00051 00052 IntTy = Types.ConvertType(Ctx.IntTy); 00053 SizeTy = Types.ConvertType(Ctx.getSizeType()); 00054 00055 CharPtrTy = llvm::PointerType::getUnqual(Types.ConvertType(Ctx.CharTy)); 00056 VoidPtrTy = cast<llvm::PointerType>(Types.ConvertType(Ctx.VoidPtrTy)); 00057 } 00058 00059 llvm::Constant *CGNVCUDARuntime::getSetupArgumentFn() const { 00060 // cudaError_t cudaSetupArgument(void *, size_t, size_t) 00061 std::vector<llvm::Type*> Params; 00062 Params.push_back(VoidPtrTy); 00063 Params.push_back(SizeTy); 00064 Params.push_back(SizeTy); 00065 return CGM.CreateRuntimeFunction(llvm::FunctionType::get(IntTy, 00066 Params, false), 00067 "cudaSetupArgument"); 00068 } 00069 00070 llvm::Constant *CGNVCUDARuntime::getLaunchFn() const { 00071 // cudaError_t cudaLaunch(char *) 00072 std::vector<llvm::Type*> Params; 00073 Params.push_back(CharPtrTy); 00074 return CGM.CreateRuntimeFunction(llvm::FunctionType::get(IntTy, 00075 Params, false), 00076 "cudaLaunch"); 00077 } 00078 00079 void CGNVCUDARuntime::EmitDeviceStubBody(CodeGenFunction &CGF, 00080 FunctionArgList &Args) { 00081 // Build the argument value list and the argument stack struct type. 00082 llvm::SmallVector<llvm::Value *, 16> ArgValues; 00083 std::vector<llvm::Type *> ArgTypes; 00084 for (FunctionArgList::const_iterator I = Args.begin(), E = Args.end(); 00085 I != E; ++I) { 00086 llvm::Value *V = CGF.GetAddrOfLocalVar(*I); 00087 ArgValues.push_back(V); 00088 assert(isa<llvm::PointerType>(V->getType()) && "Arg type not PointerType"); 00089 ArgTypes.push_back(cast<llvm::PointerType>(V->getType())->getElementType()); 00090 } 00091 llvm::StructType *ArgStackTy = llvm::StructType::get( 00092 CGF.getLLVMContext(), ArgTypes); 00093 00094 llvm::BasicBlock *EndBlock = CGF.createBasicBlock("setup.end"); 00095 00096 // Emit the calls to cudaSetupArgument 00097 llvm::Constant *cudaSetupArgFn = getSetupArgumentFn(); 00098 for (unsigned I = 0, E = Args.size(); I != E; ++I) { 00099 llvm::Value *Args[3]; 00100 llvm::BasicBlock *NextBlock = CGF.createBasicBlock("setup.next"); 00101 Args[0] = CGF.Builder.CreatePointerCast(ArgValues[I], VoidPtrTy); 00102 Args[1] = CGF.Builder.CreateIntCast( 00103 llvm::ConstantExpr::getSizeOf(ArgTypes[I]), 00104 SizeTy, false); 00105 Args[2] = CGF.Builder.CreateIntCast( 00106 llvm::ConstantExpr::getOffsetOf(ArgStackTy, I), 00107 SizeTy, false); 00108 llvm::CallSite CS = CGF.EmitCallOrInvoke(cudaSetupArgFn, Args); 00109 llvm::Constant *Zero = llvm::ConstantInt::get(IntTy, 0); 00110 llvm::Value *CSZero = CGF.Builder.CreateICmpEQ(CS.getInstruction(), Zero); 00111 CGF.Builder.CreateCondBr(CSZero, NextBlock, EndBlock); 00112 CGF.EmitBlock(NextBlock); 00113 } 00114 00115 // Emit the call to cudaLaunch 00116 llvm::Constant *cudaLaunchFn = getLaunchFn(); 00117 llvm::Value *Arg = CGF.Builder.CreatePointerCast(CGF.CurFn, CharPtrTy); 00118 CGF.EmitCallOrInvoke(cudaLaunchFn, Arg); 00119 CGF.EmitBranch(EndBlock); 00120 00121 CGF.EmitBlock(EndBlock); 00122 } 00123 00124 CGCUDARuntime *CodeGen::CreateNVCUDARuntime(CodeGenModule &CGM) { 00125 return new CGNVCUDARuntime(CGM); 00126 }