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/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 }