1 //===- SerializationTest.cpp - SPIR-V Serialization Tests -----------------===//
2 //
3 // Part of the MLIR Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file contains corner case tests for the SPIR-V serializer that are not
10 // covered by normal serialization and deserialization roundtripping.
11 //
12 //===----------------------------------------------------------------------===//
13
14 #include "mlir/Dialect/SPIRV/Serialization.h"
15 #include "mlir/Dialect/SPIRV/SPIRVBinaryUtils.h"
16 #include "mlir/Dialect/SPIRV/SPIRVDialect.h"
17 #include "mlir/Dialect/SPIRV/SPIRVOps.h"
18 #include "mlir/Dialect/SPIRV/SPIRVTypes.h"
19 #include "mlir/IR/Builders.h"
20 #include "mlir/IR/Location.h"
21 #include "mlir/IR/MLIRContext.h"
22 #include "llvm/ADT/DenseSet.h"
23 #include "llvm/ADT/STLExtras.h"
24 #include "llvm/ADT/Sequence.h"
25 #include "llvm/ADT/SmallVector.h"
26 #include "llvm/ADT/StringRef.h"
27 #include "gmock/gmock.h"
28
29 using namespace mlir;
30
31 //===----------------------------------------------------------------------===//
32 // Test Fixture
33 //===----------------------------------------------------------------------===//
34
35 class SerializationTest : public ::testing::Test {
36 protected:
SerializationTest()37 SerializationTest() { createModuleOp(); }
38
createModuleOp()39 void createModuleOp() {
40 Builder builder(&context);
41 OperationState state(UnknownLoc::get(&context),
42 spirv::ModuleOp::getOperationName());
43 state.addAttribute("addressing_model",
44 builder.getI32IntegerAttr(static_cast<uint32_t>(
45 spirv::AddressingModel::Logical)));
46 state.addAttribute("memory_model",
47 builder.getI32IntegerAttr(
48 static_cast<uint32_t>(spirv::MemoryModel::GLSL450)));
49 spirv::ModuleOp::build(&builder, state);
50 module = cast<spirv::ModuleOp>(Operation::create(state));
51 }
52
getFloatStructType()53 Type getFloatStructType() {
54 OpBuilder opBuilder(module.body());
55 llvm::SmallVector<Type, 1> elementTypes{opBuilder.getF32Type()};
56 llvm::SmallVector<spirv::StructType::LayoutInfo, 1> layoutInfo{0};
57 auto structType = spirv::StructType::get(elementTypes, layoutInfo);
58 return structType;
59 }
60
addGlobalVar(Type type,llvm::StringRef name)61 void addGlobalVar(Type type, llvm::StringRef name) {
62 OpBuilder opBuilder(module.body());
63 auto ptrType = spirv::PointerType::get(type, spirv::StorageClass::Uniform);
64 opBuilder.create<spirv::GlobalVariableOp>(
65 UnknownLoc::get(&context), TypeAttr::get(ptrType),
66 opBuilder.getStringAttr(name), nullptr);
67 }
68
findInstruction(llvm::function_ref<bool (spirv::Opcode opcode,ArrayRef<uint32_t> operands)> matchFn)69 bool findInstruction(llvm::function_ref<bool(spirv::Opcode opcode,
70 ArrayRef<uint32_t> operands)>
71 matchFn) {
72 auto binarySize = binary.size();
73 auto begin = binary.begin();
74 auto currOffset = spirv::kHeaderWordCount;
75
76 while (currOffset < binarySize) {
77 auto wordCount = binary[currOffset] >> 16;
78 if (!wordCount || (currOffset + wordCount > binarySize)) {
79 return false;
80 }
81 spirv::Opcode opcode =
82 static_cast<spirv::Opcode>(binary[currOffset] & 0xffff);
83
84 if (matchFn(opcode,
85 llvm::ArrayRef<uint32_t>(begin + currOffset + 1,
86 begin + currOffset + wordCount))) {
87 return true;
88 }
89 currOffset += wordCount;
90 }
91 return false;
92 }
93
94 protected:
95 MLIRContext context;
96 spirv::ModuleOp module;
97 SmallVector<uint32_t, 0> binary;
98 };
99
100 //===----------------------------------------------------------------------===//
101 // Block decoration
102 //===----------------------------------------------------------------------===//
103
TEST_F(SerializationTest,BlockDecorationTest)104 TEST_F(SerializationTest, BlockDecorationTest) {
105 auto structType = getFloatStructType();
106 addGlobalVar(structType, "var0");
107 ASSERT_TRUE(succeeded(spirv::serialize(module, binary)));
108 auto hasBlockDecoration = [](spirv::Opcode opcode,
109 ArrayRef<uint32_t> operands) -> bool {
110 if (opcode != spirv::Opcode::OpDecorate || operands.size() != 2)
111 return false;
112 return operands[1] == static_cast<uint32_t>(spirv::Decoration::Block);
113 };
114 EXPECT_TRUE(findInstruction(hasBlockDecoration));
115 }
116