[polly] r276863 - GPGPU: Add basic support for kernel launches

Tobias Grosser via llvm-commits llvm-commits at lists.llvm.org
Wed Jul 27 06:20:17 PDT 2016


Author: grosser
Date: Wed Jul 27 08:20:16 2016
New Revision: 276863

URL: http://llvm.org/viewvc/llvm-project?rev=276863&view=rev
Log:
GPGPU: Add basic support for kernel launches

Modified:
    polly/trunk/lib/CodeGen/PPCGCodeGeneration.cpp
    polly/trunk/test/GPGPU/double-parallel-loop.ll
    polly/trunk/test/GPGPU/host-control-flow.ll
    polly/trunk/tools/GPURuntime/GPUJIT.c
    polly/trunk/tools/GPURuntime/GPUJIT.h

Modified: polly/trunk/lib/CodeGen/PPCGCodeGeneration.cpp
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/CodeGen/PPCGCodeGeneration.cpp?rev=276863&r1=276862&r2=276863&view=diff
==============================================================================
--- polly/trunk/lib/CodeGen/PPCGCodeGeneration.cpp (original)
+++ polly/trunk/lib/CodeGen/PPCGCodeGeneration.cpp Wed Jul 27 08:20:16 2016
@@ -204,6 +204,29 @@ private:
   /// @returns A set of values referenced by the kernel.
   SetVector<Value *> getReferencesInKernel(ppcg_kernel *Kernel);
 
+  /// Compute the sizes of the execution grid for a given kernel.
+  ///
+  /// @param Kernel The kernel to compute grid sizes for.
+  ///
+  /// @returns A tuple with grid sizes for X and Y dimension
+  std::tuple<Value *, Value *> getGridSizes(ppcg_kernel *Kernel);
+
+  /// Compute the sizes of the thread blocks for a given kernel.
+  ///
+  /// @param Kernel The kernel to compute thread block sizes for.
+  ///
+  /// @returns A tuple with thread block sizes for X, Y, and Z dimensions.
+  std::tuple<Value *, Value *, Value *> getBlockSizes(ppcg_kernel *Kernel);
+
+  /// Create kernel launch parameters.
+  ///
+  /// @param Kernel The kernel to create parameters for.
+  /// @param F      The kernel function that has been created.
+  ///
+  /// @returns A stack allocated array with pointers to the parameter
+  ///          values that are passed to the kernel.
+  Value *createLaunchParameters(ppcg_kernel *Kernel, Function *F);
+
   /// Create GPU kernel.
   ///
   /// Code generate the kernel described by @p KernelStmt.
@@ -296,6 +319,13 @@ private:
   /// @returns A pointer to the newly initialized context.
   Value *createCallInitContext();
 
+  /// Create a call to get the device pointer for a kernel allocation.
+  ///
+  /// @param Allocation The Polly GPU allocation
+  ///
+  /// @returns The device parameter corresponding to this allocation.
+  Value *createCallGetDevicePtr(Value *Allocation);
+
   /// Create a call to free the GPU context.
   ///
   /// @param Context A pointer to an initialized GPU context.
@@ -339,6 +369,21 @@ private:
   ///
   /// @param GPUKernel THe kernel to free.
   void createCallFreeKernel(Value *GPUKernel);
+
+  /// Create a call to launch a GPU kernel.
+  ///
+  /// @param GPUKernel  The kernel to launch.
+  /// @param GridDimX   The size of the first grid dimension.
+  /// @param GridDimY   The size of the second grid dimension.
+  /// @param GridBlockX The size of the first block dimension.
+  /// @param GridBlockY The size of the second block dimension.
+  /// @param GridBlockZ The size of the third block dimension.
+  /// @param Paramters  A pointer to an array that contains itself pointers to
+  ///                   the parameter values passed for each kernel argument.
+  void createCallLaunchKernel(Value *GPUKernel, Value *GridDimX,
+                              Value *GridDimY, Value *BlockDimX,
+                              Value *BlockDimY, Value *BlockDimZ,
+                              Value *Parameters);
 };
 
 void GPUNodeBuilder::initializeAfterRTH() {
@@ -393,6 +438,50 @@ Value *GPUNodeBuilder::createCallGetKern
   return Builder.CreateCall(F, {Buffer, Entry});
 }
 
+Value *GPUNodeBuilder::createCallGetDevicePtr(Value *Allocation) {
+  const char *Name = "polly_getDevicePtr";
+  Module *M = Builder.GetInsertBlock()->getParent()->getParent();
+  Function *F = M->getFunction(Name);
+
+  // If F is not available, declare it.
+  if (!F) {
+    GlobalValue::LinkageTypes Linkage = Function::ExternalLinkage;
+    std::vector<Type *> Args;
+    Args.push_back(Builder.getInt8PtrTy());
+    FunctionType *Ty = FunctionType::get(Builder.getInt8PtrTy(), Args, false);
+    F = Function::Create(Ty, Linkage, Name, M);
+  }
+
+  return Builder.CreateCall(F, {Allocation});
+}
+
+void GPUNodeBuilder::createCallLaunchKernel(Value *GPUKernel, Value *GridDimX,
+                                            Value *GridDimY, Value *BlockDimX,
+                                            Value *BlockDimY, Value *BlockDimZ,
+                                            Value *Parameters) {
+  const char *Name = "polly_launchKernel";
+  Module *M = Builder.GetInsertBlock()->getParent()->getParent();
+  Function *F = M->getFunction(Name);
+
+  // If F is not available, declare it.
+  if (!F) {
+    GlobalValue::LinkageTypes Linkage = Function::ExternalLinkage;
+    std::vector<Type *> Args;
+    Args.push_back(Builder.getInt8PtrTy());
+    Args.push_back(Builder.getInt32Ty());
+    Args.push_back(Builder.getInt32Ty());
+    Args.push_back(Builder.getInt32Ty());
+    Args.push_back(Builder.getInt32Ty());
+    Args.push_back(Builder.getInt32Ty());
+    Args.push_back(Builder.getInt8PtrTy());
+    FunctionType *Ty = FunctionType::get(Builder.getVoidTy(), Args, false);
+    F = Function::Create(Ty, Linkage, Name, M);
+  }
+
+  Builder.CreateCall(F, {GPUKernel, GridDimX, GridDimY, BlockDimX, BlockDimY,
+                         BlockDimZ, Parameters});
+}
+
 void GPUNodeBuilder::createCallFreeKernel(Value *GPUKernel) {
   const char *Name = "polly_freeKernel";
   Module *M = Builder.GetInsertBlock()->getParent()->getParent();
@@ -755,6 +844,77 @@ void GPUNodeBuilder::clearLoops(Function
   }
 }
 
+std::tuple<Value *, Value *> GPUNodeBuilder::getGridSizes(ppcg_kernel *Kernel) {
+  std::vector<Value *> Sizes;
+  isl_ast_build *Context = isl_ast_build_from_context(S.getContext());
+
+  for (long i = 0; i < Kernel->n_grid; i++) {
+    isl_pw_aff *Size = isl_multi_pw_aff_get_pw_aff(Kernel->grid_size, i);
+    isl_ast_expr *GridSize = isl_ast_build_expr_from_pw_aff(Context, Size);
+    Value *Res = ExprBuilder.create(GridSize);
+    Res = Builder.CreateTrunc(Res, Builder.getInt32Ty());
+    Sizes.push_back(Res);
+  }
+  isl_ast_build_free(Context);
+
+  for (long i = Kernel->n_grid; i < 3; i++)
+    Sizes.push_back(ConstantInt::get(Builder.getInt32Ty(), 1));
+
+  return std::make_tuple(Sizes[0], Sizes[1]);
+}
+
+std::tuple<Value *, Value *, Value *>
+GPUNodeBuilder::getBlockSizes(ppcg_kernel *Kernel) {
+  std::vector<Value *> Sizes;
+
+  for (long i = 0; i < Kernel->n_block; i++) {
+    Value *Res = ConstantInt::get(Builder.getInt32Ty(), Kernel->block_dim[i]);
+    Sizes.push_back(Res);
+  }
+
+  for (long i = Kernel->n_block; i < 3; i++)
+    Sizes.push_back(ConstantInt::get(Builder.getInt32Ty(), 1));
+
+  return std::make_tuple(Sizes[0], Sizes[1], Sizes[2]);
+}
+
+Value *GPUNodeBuilder::createLaunchParameters(ppcg_kernel *Kernel,
+                                              Function *F) {
+  Type *ArrayTy = ArrayType::get(Builder.getInt8PtrTy(), F->getNumOperands());
+
+  BasicBlock *EntryBlock =
+      &Builder.GetInsertBlock()->getParent()->getEntryBlock();
+  std::string Launch = "polly_launch_" + std::to_string(Kernel->id);
+  Instruction *Parameters =
+      new AllocaInst(ArrayTy, Launch + "_params", EntryBlock->getTerminator());
+
+  int Index = 0;
+  for (long i = 0; i < Prog->n_array; i++) {
+    if (!ppcg_kernel_requires_array_argument(Kernel, i))
+      continue;
+
+    isl_id *Id = isl_space_get_tuple_id(Prog->array[i].space, isl_dim_set);
+    const ScopArrayInfo *SAI = ScopArrayInfo::getFromId(Id);
+
+    Value *DevArray = DeviceAllocations[(ScopArrayInfo *)SAI];
+    DevArray = createCallGetDevicePtr(DevArray);
+    Instruction *Param = new AllocaInst(
+        Builder.getInt8PtrTy(), Launch + "_param_" + std::to_string(Index),
+        EntryBlock->getTerminator());
+    Builder.CreateStore(DevArray, Param);
+    Value *Slot = Builder.CreateGEP(Parameters,
+                                    {Builder.getInt64(0), Builder.getInt64(i)});
+    Value *ParamTyped =
+        Builder.CreatePointerCast(Param, Builder.getInt8PtrTy());
+    Builder.CreateStore(ParamTyped, Slot);
+    Index++;
+  }
+
+  auto Location = EntryBlock->getTerminator();
+  return new BitCastInst(Parameters, Builder.getInt8PtrTy(),
+                         Launch + "_params_i8ptr", Location);
+}
+
 void GPUNodeBuilder::createKernel(__isl_take isl_ast_node *KernelStmt) {
   isl_id *Id = isl_ast_node_get_annotation(KernelStmt);
   ppcg_kernel *Kernel = (ppcg_kernel *)isl_id_get_user(Id);
@@ -805,11 +965,22 @@ void GPUNodeBuilder::createKernel(__isl_
     S.invalidateScopArrayInfo(BasePtr, ScopArrayInfo::MK_Array);
   LocalArrays.clear();
 
+  Value *Parameters = createLaunchParameters(Kernel, F);
+
   std::string ASMString = finalizeKernelFunction();
   std::string Name = "kernel_" + std::to_string(Kernel->id);
   Value *KernelString = Builder.CreateGlobalStringPtr(ASMString, Name);
   Value *NameString = Builder.CreateGlobalStringPtr(Name, Name + "_name");
   Value *GPUKernel = createCallGetKernel(KernelString, NameString);
+
+  Value *GridDimX, *GridDimY;
+  std::tie(GridDimX, GridDimY) = getGridSizes(Kernel);
+
+  Value *BlockDimX, *BlockDimY, *BlockDimZ;
+  std::tie(BlockDimX, BlockDimY, BlockDimZ) = getBlockSizes(Kernel);
+
+  createCallLaunchKernel(GPUKernel, GridDimX, GridDimY, BlockDimX, BlockDimY,
+                         BlockDimZ, Parameters);
   createCallFreeKernel(GPUKernel);
 }
 

Modified: polly/trunk/test/GPGPU/double-parallel-loop.ll
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/test/GPGPU/double-parallel-loop.ll?rev=276863&r1=276862&r2=276863&view=diff
==============================================================================
--- polly/trunk/test/GPGPU/double-parallel-loop.ll (original)
+++ polly/trunk/test/GPGPU/double-parallel-loop.ll Wed Jul 27 08:20:16 2016
@@ -96,7 +96,13 @@
 ; IR-NEXT:    %p_dev_array_MemRef_A = call i8* @polly_allocateMemoryForDevice(i64 4194304)
 ; IR-NEXT:    [[HostPtr:%.*]] = bitcast [1024 x float]* %A to i8*
 ; IR-NEXT:    call void @polly_copyFromHostToDevice(i8* [[HostPtr]], i8* %p_dev_array_MemRef_A, i64 4194304)
+; IR-NEXT:    [[DevPtr:%.*]]  = call i8* @polly_getDevicePtr(i8* %p_dev_array_MemRef_A)
+; IR-NEXT:    store i8* [[DevPtr]], i8** %polly_launch_0_param_0
+; IR-NEXT:    [[ParamSlot:%.*]] = getelementptr [0 x i8*], [0 x i8*]* %polly_launch_0_params, i64 0, i64 0
+; IR-NEXT:    [[ParamTyped:%.*]] = bitcast i8** %polly_launch_0_param_0 to i8*
+; IR-NEXT:    store i8* [[ParamTyped]], i8** [[ParamSlot]]
 ; IR-NEXT:    call i8* @polly_getKernel
+; IR-NEXT:    call void @polly_launchKernel(i8* %5, i32 32, i32 32, i32 32, i32 16, i32 1, i8* %polly_launch_0_params_i8ptr)
 ; IR-NEXT:    call void @polly_freeKernel
 ; IR-NEXT:    [[HostPtr2:%.*]] = bitcast [1024 x float]* %A to i8*
 ; IR-NEXT:    call void @polly_copyFromDeviceToHost(i8* %p_dev_array_MemRef_A, i8* [[HostPtr2]], i64 4194304)

Modified: polly/trunk/test/GPGPU/host-control-flow.ll
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/test/GPGPU/host-control-flow.ll?rev=276863&r1=276862&r2=276863&view=diff
==============================================================================
--- polly/trunk/test/GPGPU/host-control-flow.ll (original)
+++ polly/trunk/test/GPGPU/host-control-flow.ll Wed Jul 27 08:20:16 2016
@@ -30,8 +30,10 @@
 
 ; IR-LABEL: polly.loop_header:                                ; preds = %polly.loop_header, %polly.loop_preheader
 ; IR-NEXT:   %polly.indvar = phi i64 [ 0, %polly.loop_preheader ], [ %polly.indvar_next, %polly.loop_header ]
-; IR-NEXT: call i8* @polly_getKernel
-; IR-NEXT: call void @polly_freeKernel
+; ...
+; IR: call i8* @polly_getKernel
+; ...
+; IR: call void @polly_freeKernel
 ; IR-NEXT:   %polly.indvar_next = add nsw i64 %polly.indvar, 1
 ; IR-NEXT:   %polly.loop_cond = icmp sle i64 %polly.indvar, 98
 ; IR-NEXT:   br i1 %polly.loop_cond, label %polly.loop_header, label %polly.loop_exit

Modified: polly/trunk/tools/GPURuntime/GPUJIT.c
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/tools/GPURuntime/GPUJIT.c?rev=276863&r1=276862&r2=276863&view=diff
==============================================================================
--- polly/trunk/tools/GPURuntime/GPUJIT.c (original)
+++ polly/trunk/tools/GPURuntime/GPUJIT.c Wed Jul 27 08:20:16 2016
@@ -54,18 +54,12 @@ static void *HandleCudaRT;
 typedef CUresult CUDAAPI CuMemAllocFcnTy(CUdeviceptr *, size_t);
 static CuMemAllocFcnTy *CuMemAllocFcnPtr;
 
-typedef CUresult CUDAAPI CuFuncSetBlockShapeFcnTy(CUfunction, int, int, int);
-static CuFuncSetBlockShapeFcnTy *CuFuncSetBlockShapeFcnPtr;
-
-typedef CUresult CUDAAPI CuParamSetvFcnTy(CUfunction, int, void *,
-                                          unsigned int);
-static CuParamSetvFcnTy *CuParamSetvFcnPtr;
-
-typedef CUresult CUDAAPI CuParamSetSizeFcnTy(CUfunction, unsigned int);
-static CuParamSetSizeFcnTy *CuParamSetSizeFcnPtr;
-
-typedef CUresult CUDAAPI CuLaunchGridFcnTy(CUfunction, int, int);
-static CuLaunchGridFcnTy *CuLaunchGridFcnPtr;
+typedef CUresult CUDAAPI CuLaunchKernelFcnTy(
+    CUfunction f, unsigned int gridDimX, unsigned int gridDimY,
+    unsigned int gridDimZ, unsigned int blockDimX, unsigned int blockDimY,
+    unsigned int blockDimZ, unsigned int sharedMemBytes, CUstream hStream,
+    void **kernelParams, void **extra);
+static CuLaunchKernelFcnTy *CuLaunchKernelFcnPtr;
 
 typedef CUresult CUDAAPI CuMemcpyDtoHFcnTy(void *, CUdeviceptr, size_t);
 static CuMemcpyDtoHFcnTy *CuMemcpyDtoHFcnPtr;
@@ -178,17 +172,8 @@ static int initialDeviceAPIs() {
    * of this kind of cast may not be emitted by clang and new versions of gcc
    * as it is valid on POSIX 2008.
    */
-  CuFuncSetBlockShapeFcnPtr = (CuFuncSetBlockShapeFcnTy *)getAPIHandle(
-      HandleCuda, "cuFuncSetBlockShape");
-
-  CuParamSetvFcnPtr =
-      (CuParamSetvFcnTy *)getAPIHandle(HandleCuda, "cuParamSetv");
-
-  CuParamSetSizeFcnPtr =
-      (CuParamSetSizeFcnTy *)getAPIHandle(HandleCuda, "cuParamSetSize");
-
-  CuLaunchGridFcnPtr =
-      (CuLaunchGridFcnTy *)getAPIHandle(HandleCuda, "cuLaunchGrid");
+  CuLaunchKernelFcnPtr =
+      (CuLaunchKernelFcnTy *)getAPIHandle(HandleCuda, "cuLaunchKernel");
 
   CuMemAllocFcnPtr =
       (CuMemAllocFcnTy *)getAPIHandle(HandleCuda, "cuMemAlloc_v2");
@@ -407,29 +392,25 @@ void polly_copyFromDeviceToHost(PollyGPU
   }
 }
 
-void polly_setKernelParameters(PollyGPUFunction *Kernel, int BlockWidth,
-                               int BlockHeight, PollyGPUDevicePtr *DevData) {
+void polly_launchKernel(PollyGPUFunction *Kernel, unsigned int GridDimX,
+                        unsigned int GridDimY, unsigned int BlockDimX,
+                        unsigned int BlockDimY, unsigned int BlockDimZ,
+                        void **Parameters) {
   dump_function();
 
-  int ParamOffset = 0;
-
-  CuFuncSetBlockShapeFcnPtr(Kernel->Cuda, BlockWidth, BlockHeight, 1);
-  CuParamSetvFcnPtr(Kernel->Cuda, ParamOffset, &(DevData->Cuda),
-                    sizeof(DevData->Cuda));
-  ParamOffset += sizeof(DevData->Cuda);
-  CuParamSetSizeFcnPtr(Kernel->Cuda, ParamOffset);
-}
-
-void polly_launchKernel(PollyGPUFunction *Kernel, int GridWidth,
-                        int GridHeight) {
-  dump_function();
+  unsigned GridDimZ = 1;
+  unsigned int SharedMemBytes = CU_SHARED_MEM_CONFIG_DEFAULT_BANK_SIZE;
+  CUstream Stream = 0;
+  void **Extra = 0;
 
-  if (CuLaunchGridFcnPtr(Kernel->Cuda, GridWidth, GridHeight) != CUDA_SUCCESS) {
+  CUresult Res;
+  Res = CuLaunchKernelFcnPtr(Kernel->Cuda, GridDimX, GridDimY, GridDimZ,
+                             BlockDimX, BlockDimY, BlockDimZ, SharedMemBytes,
+                             Stream, Parameters, Extra);
+  if (Res != CUDA_SUCCESS) {
     fprintf(stdout, "Launching CUDA kernel failed.\n");
     exit(-1);
   }
-  CudaThreadSynchronizeFcnPtr();
-  debug_print("CUDA kernel launched.\n");
 }
 
 void polly_freeDeviceMemory(PollyGPUDevicePtr *Allocation) {
@@ -458,6 +439,12 @@ PollyGPUDevicePtr *polly_allocateMemoryF
   return DevData;
 }
 
+void *polly_getDevicePtr(PollyGPUDevicePtr *Allocation) {
+  dump_function();
+
+  return (void *)Allocation->Cuda;
+}
+
 void polly_freeContext(PollyGPUContext *Context) {
   dump_function();
 

Modified: polly/trunk/tools/GPURuntime/GPUJIT.h
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/tools/GPURuntime/GPUJIT.h?rev=276863&r1=276862&r2=276863&view=diff
==============================================================================
--- polly/trunk/tools/GPURuntime/GPUJIT.h (original)
+++ polly/trunk/tools/GPURuntime/GPUJIT.h Wed Jul 27 08:20:16 2016
@@ -49,17 +49,25 @@
  *   PollyGPUDevicePtr *DevArray;
  *   int *HostData;
  *   int MemSize;
- *   int BlockWidth = 16;
- *   int BlockHeight = 16;
- *   int GridWidth = 8;
- *   int GridHeight = 8;
+ *
+ *   int GridX = 8;
+ *   int GridY = 8;
+ *
+ *   int BlockX = 16;
+ *   int BlockY = 16;
+ *   int BlockZ = 1;
  *
  *   MemSize = 256*64*sizeof(int);
  *   Context = polly_initContext();
  *   DevArray = polly_allocateMemoryForDevice(MemSize);
  *   Kernel = polly_getKernel(KernelString, KernelName);
- *   polly_setKernelParameters(Kernel, BlockWidth, BlockHeight, DevData);
- *   polly_launchKernel(Kernel, GridWidth, GridHeight);
+ *
+ *   void *Params[1];
+ *   void *DevPtr = polly_getDevicePtr(DevArray)
+ *   Params[0] = &DevPtr;
+ *
+ *   polly_launchKernel(Kernel, GridX, GridY, BlockX, BlockY, BlockZ, Params);
+ *
  *   polly_copyFromDeviceToHost(HostData, DevData, MemSize);
  *   polly_freeKernel(Kernel);
  *   polly_freeDeviceMemory(DevArray);
@@ -80,10 +88,10 @@ void polly_copyFromHostToDevice(void *Ho
                                 long MemSize);
 void polly_copyFromDeviceToHost(PollyGPUDevicePtr *DevData, void *HostData,
                                 long MemSize);
-void polly_setKernelParameters(PollyGPUFunction *Kernel, int BlockWidth,
-                               int BlockHeight, PollyGPUDevicePtr *DevData);
-void polly_launchKernel(PollyGPUFunction *Kernel, int GridWidth,
-                        int GridHeight);
+void polly_launchKernel(PollyGPUFunction *Kernel, unsigned int GridDimX,
+                        unsigned int GridDimY, unsigned int BlockSizeX,
+                        unsigned int BlockSizeY, unsigned int BlockSizeZ,
+                        void **Parameters);
 void polly_freeDeviceMemory(PollyGPUDevicePtr *Allocation);
 void polly_freeContext(PollyGPUContext *Context);
 #endif /* GPUJIT_H_ */




More information about the llvm-commits mailing list