clang API Documentation

CGCUDANV.cpp
Go to the documentation of this file.
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 }