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: 37 SerializationTest() { createModuleOp(); } 38 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 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 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 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 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