blob: 0e3d388745761d441f09d0a043f6e50a79ee447c [file] [log] [blame]
// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// clang-format off
// NOLINTNEXTLINE
// TODO(thomasraoux): Set the right path to vulkan wrapper shared library. The
// test won't run until this is done.
// RUN: test-simple-jit-vulkan -vulkan-wrapper=$(dirname %s)/../../../../llvm/llvm-project/mlir/tools/libvulkan-runtime-wrappers.so 2>&1 | IreeFileCheck %s
// clang-format on
#include <string>
#include "experimental/ModelBuilder/ModelBuilder.h"
#include "experimental/ModelBuilder/ModelRunner.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/InitLLVM.h"
#include "mlir/Dialect/SPIRV/TargetAndABI.h"
#include "mlir/IR/Builders.h"
#include "mlir/IR/MLIRContext.h"
#include "mlir/IR/OperationSupport.h"
#include "mlir/Parser.h"
#include "mlir/ExecutionEngine/RunnerUtils.h"
#include "iree/base/initializer.h"
static llvm::cl::opt<std::string> vulkanWrapper(
"vulkan-wrapper", llvm::cl::desc("Vulkan wrapper library"),
llvm::cl::value_desc("filename"), llvm::cl::init("-"));
using namespace mlir; // NOLINT
template <unsigned vecSize>
void testVectorAdd1d() {
MLIRContext context;
ModelBuilder modelBuilder;
constexpr int workgroupSize = 32;
auto typeA = modelBuilder.getMemRefType(vecSize, modelBuilder.f32);
auto typeB = modelBuilder.getMemRefType(vecSize, modelBuilder.f32);
auto typeC = modelBuilder.getMemRefType(vecSize, modelBuilder.f32);
gpu::GPUFuncOp kernelFunc;
{
// create the GPU module.
auto kernelModule = modelBuilder.makeGPUModule("kernels");
// create kernel
kernelFunc = modelBuilder.makeGPUKernel("kernel_add", kernelModule,
{workgroupSize, 1, 1},
{typeA, typeB, typeC});
OpBuilder b(&kernelFunc.body());
ScopedContext scope(b, kernelFunc.getLoc());
StdIndexedValue A(kernelFunc.getArgument(0)), B(kernelFunc.getArgument(1)),
C(kernelFunc.getArgument(2));
auto ThreadIndex = b.create<gpu::ThreadIdOp>(
modelBuilder.loc, b.getIndexType(), b.getStringAttr("x"));
auto BlockIndex = b.create<gpu::BlockIdOp>(
modelBuilder.loc, b.getIndexType(), b.getStringAttr("x"));
auto GroupSize = b.create<gpu::BlockDimOp>(
modelBuilder.loc, b.getIndexType(), b.getStringAttr("x"));
Value Index = b.create<AddIOp>(
modelBuilder.loc, ThreadIndex,
b.create<MulIOp>(modelBuilder.loc, BlockIndex, GroupSize));
C(Index) = A(Index) + B(Index);
b.create<gpu::ReturnOp>(kernelFunc.getLoc());
}
const std::string funcName("add_dispatch");
{
// Add host side code, simple dispatch:
auto f =
modelBuilder.makeFunction(funcName, {}, {typeA, typeB, typeC},
MLIRFuncOpConfig().setEmitCInterface(true));
OpBuilder b(&f.getBody());
ScopedContext scope(b, f.getLoc());
auto wgx = std_constant_index(workgroupSize);
auto one = std_constant_index(1);
auto dispatchSizeX = std_constant_index(vecSize / workgroupSize);
assert(vecSize % workgroupSize == 0);
b.create<gpu::LaunchFuncOp>(
f.getLoc(), kernelFunc, gpu::KernelDim3{dispatchSizeX, one, one},
gpu::KernelDim3{wgx, one, one},
ValueRange({f.getArgument(0), f.getArgument(1), f.getArgument(2)}));
std_ret();
}
// 2. Compile the function, pass in runtime support library
// to the execution engine for vector.print.
ModelRunner runner(modelBuilder.getModuleRef(),
ModelRunner::Target::GPUTarget);
runner.compile(CompilationOptions(), {vulkanWrapper});
// 3. Allocate data within data structures that interoperate with the MLIR ABI
// conventions used by codegen.
auto oneInit = [](unsigned idx, float *ptr) { ptr[idx] = 1.0f; };
auto incInit = [](unsigned idx, float *ptr) { ptr[idx] = 1.0f + idx; };
auto zeroInit = [](unsigned idx, float *ptr) { ptr[idx] = 0.0f; };
auto A = makeInitializedStridedMemRefDescriptor<float, 1>({vecSize}, oneInit);
auto B = makeInitializedStridedMemRefDescriptor<float, 1>({vecSize}, incInit);
auto C =
makeInitializedStridedMemRefDescriptor<float, 1>({vecSize}, zeroInit);
// 4. Call the funcOp named `funcName`.
auto err = runner.invoke(funcName, A, B, C);
if (err) llvm_unreachable("Error running function.");
// 5. Print out the output buffer.
::impl::printMemRef(*C);
}
int main(int argc, char **argv) {
iree::Initializer::RunInitializers();
// Allow LLVM setup through command line and parse the
// test specific option for a runtime support library.
llvm::InitLLVM y(argc, argv);
llvm::cl::ParseCommandLineOptions(argc, argv, "TestSimpleJITVulkan\n");
// clang-format off
// CHECK: [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
// CHECK: 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30,
// CHECK: 31, 32, 33]
testVectorAdd1d<32>();
// CHECK: [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
// CHECK: 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30,
// CHECK: 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44,
// CHECK: 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58,
// CHECK: 59, 60, 61, 62, 63, 64, 65]
testVectorAdd1d<64>();
}