brintos

brintos / llvm-project-archived public Read only

0
0
Text · 9.2 KiB · ffe815b Raw
291 lines · cpp
1//===- DeserializationTest.cpp - SPIR-V Deserialization Tests -------------===//2//3// Part of the LLVM 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-exception6//7//===----------------------------------------------------------------------===//8//9// The purpose of this file is to provide negative deserialization tests.10// For positive deserialization tests, please use serialization and11// deserialization for roundtripping.12//13//===----------------------------------------------------------------------===//14 15#include "mlir/Target/SPIRV/Deserialization.h"16#include "mlir/Dialect/SPIRV/IR/SPIRVDialect.h"17#include "mlir/Dialect/SPIRV/IR/SPIRVOps.h"18#include "mlir/IR/Diagnostics.h"19#include "mlir/IR/MLIRContext.h"20#include "mlir/Target/SPIRV/SPIRVBinaryUtils.h"21#include "gmock/gmock.h"22 23#include <memory>24 25using namespace mlir;26 27using ::testing::StrEq;28 29//===----------------------------------------------------------------------===//30// Test Fixture31//===----------------------------------------------------------------------===//32 33/// A deserialization test fixture providing minimal SPIR-V building and34/// diagnostic checking utilities.35class DeserializationTest : public ::testing::Test {36protected:37  DeserializationTest() {38    context.getOrLoadDialect<mlir::spirv::SPIRVDialect>();39    // Register a diagnostic handler to capture the diagnostic so that we can40    // check it later.41    context.getDiagEngine().registerHandler([&](Diagnostic &diag) {42      diagnostic = std::make_unique<Diagnostic>(std::move(diag));43    });44  }45 46  /// Performs deserialization and returns the constructed spirv.module op.47  OwningOpRef<spirv::ModuleOp> deserialize() {48    return spirv::deserialize(binary, &context);49  }50 51  /// Checks there is a diagnostic generated with the given `errorMessage`.52  void expectDiagnostic(StringRef errorMessage) {53    ASSERT_NE(nullptr, diagnostic.get());54 55    // TODO: check error location too.56    EXPECT_THAT(diagnostic->str(), StrEq(std::string(errorMessage)));57  }58 59  //===--------------------------------------------------------------------===//60  // SPIR-V builder methods61  //===--------------------------------------------------------------------===//62 63  /// Adds the SPIR-V module header to `binary`.64  void addHeader() {65    spirv::appendModuleHeader(binary, spirv::Version::V_1_0, /*idBound=*/0);66  }67 68  /// Adds the SPIR-V instruction into `binary`.69  void addInstruction(spirv::Opcode op, ArrayRef<uint32_t> operands) {70    uint32_t wordCount = 1 + operands.size();71    binary.push_back(spirv::getPrefixedOpcode(wordCount, op));72    binary.append(operands.begin(), operands.end());73  }74 75  uint32_t addVoidType() {76    auto id = nextID++;77    addInstruction(spirv::Opcode::OpTypeVoid, {id});78    return id;79  }80 81  uint32_t addIntType(uint32_t bitwidth) {82    auto id = nextID++;83    addInstruction(spirv::Opcode::OpTypeInt, {id, bitwidth, /*signedness=*/1});84    return id;85  }86 87  uint32_t addStructType(ArrayRef<uint32_t> memberTypes) {88    auto id = nextID++;89    SmallVector<uint32_t, 2> words;90    words.push_back(id);91    words.append(memberTypes.begin(), memberTypes.end());92    addInstruction(spirv::Opcode::OpTypeStruct, words);93    return id;94  }95 96  uint32_t addFunctionType(uint32_t retType, ArrayRef<uint32_t> paramTypes) {97    auto id = nextID++;98    SmallVector<uint32_t, 4> operands;99    operands.push_back(id);100    operands.push_back(retType);101    operands.append(paramTypes.begin(), paramTypes.end());102    addInstruction(spirv::Opcode::OpTypeFunction, operands);103    return id;104  }105 106  uint32_t addFunction(uint32_t retType, uint32_t fnType) {107    auto id = nextID++;108    addInstruction(spirv::Opcode::OpFunction,109                   {retType, id,110                    static_cast<uint32_t>(spirv::FunctionControl::None),111                    fnType});112    return id;113  }114 115  void addFunctionEnd() { addInstruction(spirv::Opcode::OpFunctionEnd, {}); }116 117  void addReturn() { addInstruction(spirv::Opcode::OpReturn, {}); }118 119protected:120  SmallVector<uint32_t, 5> binary;121  uint32_t nextID = 1;122  MLIRContext context;123  std::unique_ptr<Diagnostic> diagnostic;124};125 126//===----------------------------------------------------------------------===//127// Basics128//===----------------------------------------------------------------------===//129 130TEST_F(DeserializationTest, EmptyModuleFailure) {131  ASSERT_FALSE(deserialize());132  expectDiagnostic("SPIR-V binary module must have a 5-word header");133}134 135TEST_F(DeserializationTest, WrongMagicNumberFailure) {136  addHeader();137  binary.front() = 0xdeadbeef; // Change to a wrong magic number138  ASSERT_FALSE(deserialize());139  expectDiagnostic("incorrect magic number");140}141 142TEST_F(DeserializationTest, OnlyHeaderSuccess) {143  addHeader();144  EXPECT_TRUE(deserialize());145}146 147TEST_F(DeserializationTest, ZeroWordCountFailure) {148  addHeader();149  binary.push_back(0); // OpNop with zero word count150 151  ASSERT_FALSE(deserialize());152  expectDiagnostic("word count cannot be zero");153}154 155TEST_F(DeserializationTest, InsufficientWordFailure) {156  addHeader();157  binary.push_back((2u << 16) |158                   static_cast<uint32_t>(spirv::Opcode::OpTypeVoid));159  // Missing word for type <id>.160 161  ASSERT_FALSE(deserialize());162  expectDiagnostic("insufficient words for the last instruction");163}164 165//===----------------------------------------------------------------------===//166// Types167//===----------------------------------------------------------------------===//168 169TEST_F(DeserializationTest, IntTypeMissingSignednessFailure) {170  addHeader();171  addInstruction(spirv::Opcode::OpTypeInt, {nextID++, 32});172 173  ASSERT_FALSE(deserialize());174  expectDiagnostic("OpTypeInt must have bitwidth and signedness parameters");175}176 177//===----------------------------------------------------------------------===//178// StructType179//===----------------------------------------------------------------------===//180 181TEST_F(DeserializationTest, OpMemberNameSuccess) {182  addHeader();183  SmallVector<uint32_t, 5> typeDecl;184  std::swap(typeDecl, binary);185 186  auto int32Type = addIntType(32);187  auto structType = addStructType({int32Type, int32Type});188  std::swap(typeDecl, binary);189 190  SmallVector<uint32_t, 5> operands1 = {structType, 0};191  spirv::encodeStringLiteralInto(operands1, "i1");192  addInstruction(spirv::Opcode::OpMemberName, operands1);193 194  SmallVector<uint32_t, 5> operands2 = {structType, 1};195  spirv::encodeStringLiteralInto(operands2, "i2");196  addInstruction(spirv::Opcode::OpMemberName, operands2);197 198  binary.append(typeDecl.begin(), typeDecl.end());199  EXPECT_TRUE(deserialize());200}201 202TEST_F(DeserializationTest, OpMemberNameMissingOperands) {203  addHeader();204  SmallVector<uint32_t, 5> typeDecl;205  std::swap(typeDecl, binary);206 207  auto int32Type = addIntType(32);208  auto int64Type = addIntType(64);209  auto structType = addStructType({int32Type, int64Type});210  std::swap(typeDecl, binary);211 212  SmallVector<uint32_t, 5> operands1 = {structType};213  addInstruction(spirv::Opcode::OpMemberName, operands1);214 215  binary.append(typeDecl.begin(), typeDecl.end());216  ASSERT_FALSE(deserialize());217  expectDiagnostic("OpMemberName must have at least 3 operands");218}219 220TEST_F(DeserializationTest, OpMemberNameExcessOperands) {221  addHeader();222  SmallVector<uint32_t, 5> typeDecl;223  std::swap(typeDecl, binary);224 225  auto int32Type = addIntType(32);226  auto structType = addStructType({int32Type});227  std::swap(typeDecl, binary);228 229  SmallVector<uint32_t, 5> operands = {structType, 0};230  spirv::encodeStringLiteralInto(operands, "int32");231  operands.push_back(42);232  addInstruction(spirv::Opcode::OpMemberName, operands);233 234  binary.append(typeDecl.begin(), typeDecl.end());235  ASSERT_FALSE(deserialize());236  expectDiagnostic("unexpected trailing words in OpMemberName instruction");237}238 239//===----------------------------------------------------------------------===//240// Functions241//===----------------------------------------------------------------------===//242 243TEST_F(DeserializationTest, FunctionMissingEndFailure) {244  addHeader();245  auto voidType = addVoidType();246  auto fnType = addFunctionType(voidType, {});247  addFunction(voidType, fnType);248  // Missing OpFunctionEnd.249 250  ASSERT_FALSE(deserialize());251  expectDiagnostic("expected OpFunctionEnd instruction");252}253 254TEST_F(DeserializationTest, FunctionMissingParameterFailure) {255  addHeader();256  auto voidType = addVoidType();257  auto i32Type = addIntType(32);258  auto fnType = addFunctionType(voidType, {i32Type});259  addFunction(voidType, fnType);260  // Missing OpFunctionParameter.261 262  ASSERT_FALSE(deserialize());263  expectDiagnostic("expected OpFunctionParameter instruction");264}265 266TEST_F(DeserializationTest, FunctionMissingLabelForFirstBlockFailure) {267  addHeader();268  auto voidType = addVoidType();269  auto fnType = addFunctionType(voidType, {});270  addFunction(voidType, fnType);271  // Missing OpLabel.272  addReturn();273  addFunctionEnd();274 275  ASSERT_FALSE(deserialize());276  expectDiagnostic("a basic block must start with OpLabel");277}278 279TEST_F(DeserializationTest, FunctionMalformedLabelFailure) {280  addHeader();281  auto voidType = addVoidType();282  auto fnType = addFunctionType(voidType, {});283  addFunction(voidType, fnType);284  addInstruction(spirv::Opcode::OpLabel, {}); // Malformed OpLabel285  addReturn();286  addFunctionEnd();287 288  ASSERT_FALSE(deserialize());289  expectDiagnostic("OpLabel should only have result <id>");290}291