[Mlir-commits] [mlir] 6d57866 - [mlir][spirv] Support import/export Functions and GlobalVariables
Lei Zhang
llvmlistbot at llvm.org
Wed May 24 17:09:31 PDT 2023
Author: Md Abdullah Shahneous Bari
Date: 2023-05-24T17:08:46-07:00
New Revision: 6d578669f30695d7d05db19bf980b4aac5af325c
URL: https://github.com/llvm/llvm-project/commit/6d578669f30695d7d05db19bf980b4aac5af325c
DIFF: https://github.com/llvm/llvm-project/commit/6d578669f30695d7d05db19bf980b4aac5af325c.diff
LOG: [mlir][spirv] Support import/export Functions and GlobalVariables
"LinkageAttributes" decoration allow a SPIR-V module to import
external functions and global variables, or export functions or
global variables for other SPIR-V modules to link against and use.
Import/export capability is extremely important when using outside
libraries (e.g., intrinsic libraries).
Added decorations:
- LinkageAttributes
Reviewed By: antiagainst
Differential Revision: https://reviews.llvm.org/D148749
Added:
mlir/test/Dialect/SPIRV/IR/function-decorations.mlir
mlir/test/Target/SPIRV/function-decorations.mlir
Modified:
mlir/include/mlir/Dialect/SPIRV/IR/SPIRVAttributes.td
mlir/include/mlir/Dialect/SPIRV/IR/SPIRVStructureOps.td
mlir/lib/Dialect/SPIRV/IR/SPIRVOps.cpp
mlir/lib/Target/SPIRV/Deserialization/Deserializer.cpp
mlir/lib/Target/SPIRV/Serialization/SerializeOps.cpp
mlir/lib/Target/SPIRV/Serialization/Serializer.cpp
mlir/test/Dialect/SPIRV/IR/structure-ops.mlir
mlir/test/Target/SPIRV/decorations.mlir
mlir/test/Target/SPIRV/global-variable.mlir
Removed:
################################################################################
diff --git a/mlir/include/mlir/Dialect/SPIRV/IR/SPIRVAttributes.td b/mlir/include/mlir/Dialect/SPIRV/IR/SPIRVAttributes.td
index 7e51150f55576..259a96651abb3 100644
--- a/mlir/include/mlir/Dialect/SPIRV/IR/SPIRVAttributes.td
+++ b/mlir/include/mlir/Dialect/SPIRV/IR/SPIRVAttributes.td
@@ -46,6 +46,14 @@ def SPIRV_ExtensionArrayAttr : TypedArrayAttrBase<
def SPIRV_CapabilityArrayAttr : TypedArrayAttrBase<
SPIRV_CapabilityAttr, "SPIR-V capability array attribute">;
+def SPIRV_LinkageAttributesAttr : SPIRV_Attr<"LinkageAttributes", "linkage_attributes"> {
+ let parameters = (ins
+ "std::string":$linkage_name,
+ "mlir::spirv::LinkageTypeAttr":$linkage_type
+ );
+ let assemblyFormat = "`<` struct(params) `>`";
+}
+
// Description of cooperative matrix operations supported on the
// target. Represents `VkCooperativeMatrixPropertiesNV`. See
// https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkCooperativeMatrixPropertiesNV.html
diff --git a/mlir/include/mlir/Dialect/SPIRV/IR/SPIRVStructureOps.td b/mlir/include/mlir/Dialect/SPIRV/IR/SPIRVStructureOps.td
index a7ca0147c029e..9075239335ec7 100644
--- a/mlir/include/mlir/Dialect/SPIRV/IR/SPIRVStructureOps.td
+++ b/mlir/include/mlir/Dialect/SPIRV/IR/SPIRVStructureOps.td
@@ -15,6 +15,7 @@
#ifndef MLIR_DIALECT_SPIRV_IR_STRUCTURE_OPS
#define MLIR_DIALECT_SPIRV_IR_STRUCTURE_OPS
+include "mlir/Dialect/SPIRV/IR/SPIRVAttributes.td"
include "mlir/Dialect/SPIRV/IR/SPIRVBase.td"
include "mlir/IR/BuiltinAttributeInterfaces.td"
include "mlir/IR/FunctionInterfaces.td"
@@ -294,7 +295,8 @@ def SPIRV_FuncOp : SPIRV_Op<"func", [
OptionalAttr<DictArrayAttr>:$arg_attrs,
OptionalAttr<DictArrayAttr>:$res_attrs,
StrAttr:$sym_name,
- SPIRV_FunctionControlAttr:$function_control
+ SPIRV_FunctionControlAttr:$function_control,
+ OptionalAttr<SPIRV_LinkageAttributesAttr>:$linkage_attributes
);
let results = (outs);
@@ -385,7 +387,8 @@ def SPIRV_GlobalVariableOp : SPIRV_Op<"GlobalVariable", [InModuleScope, Symbol]>
OptionalAttr<I32Attr>:$location,
OptionalAttr<I32Attr>:$binding,
OptionalAttr<I32Attr>:$descriptor_set,
- OptionalAttr<StrAttr>:$builtin
+ OptionalAttr<StrAttr>:$builtin,
+ OptionalAttr<SPIRV_LinkageAttributesAttr>:$linkage_attributes
);
let results = (outs);
diff --git a/mlir/lib/Dialect/SPIRV/IR/SPIRVOps.cpp b/mlir/lib/Dialect/SPIRV/IR/SPIRVOps.cpp
index a51ca20572387..2828108072352 100644
--- a/mlir/lib/Dialect/SPIRV/IR/SPIRVOps.cpp
+++ b/mlir/lib/Dialect/SPIRV/IR/SPIRVOps.cpp
@@ -3522,8 +3522,17 @@ LogicalResult spirv::ModuleOp::verifyRegions() {
}
entryPoints[key] = entryPointOp;
} else if (auto funcOp = dyn_cast<spirv::FuncOp>(op)) {
- if (funcOp.isExternal())
- return op.emitError("'spirv.module' cannot contain external functions");
+ // If the function is external and does not have 'Import'
+ // linkage_attributes(LinkageAttributes), throw an error. 'Import'
+ // LinkageAttributes is used to import external functions.
+ auto linkageAttr = funcOp.getLinkageAttributes();
+ auto hasImportLinkage =
+ linkageAttr && (linkageAttr.value().getLinkageType().getValue() ==
+ spirv::LinkageType::Import);
+ if (funcOp.isExternal() && !hasImportLinkage)
+ return op.emitError(
+ "'spirv.module' cannot contain external functions "
+ "without 'Import' linkage_attributes (LinkageAttributes)");
// TODO: move this check to spirv.func.
for (auto &block : funcOp)
diff --git a/mlir/lib/Target/SPIRV/Deserialization/Deserializer.cpp b/mlir/lib/Target/SPIRV/Deserialization/Deserializer.cpp
index 1724808f0ba8e..a0b8faa7e5eab 100644
--- a/mlir/lib/Target/SPIRV/Deserialization/Deserializer.cpp
+++ b/mlir/lib/Target/SPIRV/Deserialization/Deserializer.cpp
@@ -267,6 +267,27 @@ LogicalResult spirv::Deserializer::processDecoration(ArrayRef<uint32_t> words) {
}
typeDecorations[words[0]] = words[2];
break;
+ case spirv::Decoration::LinkageAttributes: {
+ if (words.size() < 4) {
+ return emitError(unknownLoc, "OpDecorate with ")
+ << decorationName
+ << " needs at least 1 string and 1 integer literal";
+ }
+ // LinkageAttributes has two parameters ["linkageName", linkageType]
+ // e.g., OpDecorate %imported_func LinkageAttributes "outside.func" Import
+ // "linkageName" is a stringliteral encoded as uint32_t,
+ // hence the size of name is variable length which results in words.size()
+ // being variable length, words.size() = 3 + strlen(name)/4 + 1 or
+ // 3 + ceildiv(strlen(name), 4).
+ unsigned wordIndex = 2;
+ auto linkageName = spirv::decodeStringLiteral(words, wordIndex).str();
+ auto linkageTypeAttr = opBuilder.getAttr<::mlir::spirv::LinkageTypeAttr>(
+ static_cast<::mlir::spirv::LinkageType>(words[wordIndex++]));
+ auto linkageAttr = opBuilder.getAttr<::mlir::spirv::LinkageAttributesAttr>(
+ linkageName, linkageTypeAttr);
+ decorations[words[0]].set(symbol, linkageAttr.dyn_cast<Attribute>());
+ break;
+ }
case spirv::Decoration::Aliased:
case spirv::Decoration::Block:
case spirv::Decoration::BufferBlock:
@@ -380,6 +401,12 @@ spirv::Deserializer::processFunction(ArrayRef<uint32_t> operands) {
std::string fnName = getFunctionSymbol(fnID);
auto funcOp = opBuilder.create<spirv::FuncOp>(
unknownLoc, fnName, functionType, fnControl.value());
+ // Processing other function attributes.
+ if (decorations.count(fnID)) {
+ for (auto attr : decorations[fnID].getAttrs()) {
+ funcOp->setAttr(attr.getName(), attr.getValue());
+ }
+ }
curFunction = funcMap[fnID] = funcOp;
auto *entryBlock = funcOp.addEntryBlock();
LLVM_DEBUG({
@@ -430,6 +457,16 @@ spirv::Deserializer::processFunction(ArrayRef<uint32_t> operands) {
}
}
+ // entryBlock is needed to access the arguments, Once that is done, we can
+ // erase the block for functions with 'Import' LinkageAttributes, since these
+ // are essentially function declarations, so they have no body.
+ auto linkageAttr = funcOp.getLinkageAttributes();
+ auto hasImportLinkage =
+ linkageAttr && (linkageAttr.value().getLinkageType().getValue() ==
+ spirv::LinkageType::Import);
+ if (hasImportLinkage)
+ funcOp.eraseBody();
+
// RAII guard to reset the insertion point to the module's region after
// deserializing the body of this function.
OpBuilder::InsertionGuard moduleInsertionGuard(opBuilder);
diff --git a/mlir/lib/Target/SPIRV/Serialization/SerializeOps.cpp b/mlir/lib/Target/SPIRV/Serialization/SerializeOps.cpp
index f3e8a4b84e892..582f02f37456f 100644
--- a/mlir/lib/Target/SPIRV/Serialization/SerializeOps.cpp
+++ b/mlir/lib/Target/SPIRV/Serialization/SerializeOps.cpp
@@ -18,6 +18,7 @@
#include "mlir/Support/LogicalResult.h"
#include "mlir/Target/SPIRV/SPIRVBinaryUtils.h"
#include "llvm/ADT/DepthFirstIterator.h"
+#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/Debug.h"
#define DEBUG_TYPE "spirv-serialization"
@@ -208,52 +209,101 @@ LogicalResult Serializer::processFuncOp(spirv::FuncOp op) {
if (failed(processName(funcID, op.getName()))) {
return failure();
}
+ // Handle external functions with linkage_attributes(LinkageAttributes)
+ //
diff erently.
+ auto linkageAttr = op.getLinkageAttributes();
+ auto hasImportLinkage =
+ linkageAttr && (linkageAttr.value().getLinkageType().getValue() ==
+ spirv::LinkageType::Import);
+ if (op.isExternal() && !hasImportLinkage) {
+ return op.emitError(
+ "'spirv.module' cannot contain external functions "
+ "without 'Import' linkage_attributes (LinkageAttributes)");
+ } else if (op.isExternal() && hasImportLinkage) {
+ // Add an entry block to set up the block arguments
+ // to match the signature of the function.
+ // This is to generate OpFunctionParameter for functions with
+ // LinkageAttributes.
+ // WARNING: This operation has side-effect, it essentially adds a body
+ // to the func. Hence, making it not external anymore (isExternal()
+ // is going to return false for this function from now on)
+ // Hence, we'll remove the body once we are done with the serialization.
+ op.addEntryBlock();
+ for (auto arg : op.getArguments()) {
+ uint32_t argTypeID = 0;
+ if (failed(processType(op.getLoc(), arg.getType(), argTypeID))) {
+ return failure();
+ }
+ auto argValueID = getNextID();
+ valueIDMap[arg] = argValueID;
+ encodeInstructionInto(functionHeader, spirv::Opcode::OpFunctionParameter,
+ {argTypeID, argValueID});
+ }
+ // Don't need to process the added block, there is nothing to process,
+ // the fake body was added just to get the arguments, remove the body,
+ // since it's use is done.
+ op.eraseBody();
+ } else {
+ // Declare the parameters.
+ for (auto arg : op.getArguments()) {
+ uint32_t argTypeID = 0;
+ if (failed(processType(op.getLoc(), arg.getType(), argTypeID))) {
+ return failure();
+ }
+ auto argValueID = getNextID();
+ valueIDMap[arg] = argValueID;
+ encodeInstructionInto(functionHeader, spirv::Opcode::OpFunctionParameter,
+ {argTypeID, argValueID});
+ }
- // Declare the parameters.
- for (auto arg : op.getArguments()) {
- uint32_t argTypeID = 0;
- if (failed(processType(op.getLoc(), arg.getType(), argTypeID))) {
+ // Some instructions (e.g., OpVariable) in a function must be in the first
+ // block in the function. These instructions will be put in
+ // functionHeader. Thus, we put the label in functionHeader first, and
+ // omit it from the first block. OpLabel only needs to be added for
+ // functions with body (including empty body). Since, we added a fake body
+ // for functions with 'Import' Linkage attributes, these functions are
+ // essentially function delcaration, so they should not have OpLabel and a
+ // terminating instruction. That's why we skipped it for those functions.
+ encodeInstructionInto(functionHeader, spirv::Opcode::OpLabel,
+ {getOrCreateBlockID(&op.front())});
+ if (failed(processBlock(&op.front(), /*omitLabel=*/true)))
+ return failure();
+ if (failed(visitInPrettyBlockOrder(
+ &op.front(), [&](Block *block) { return processBlock(block); },
+ /*skipHeader=*/true))) {
return failure();
}
- auto argValueID = getNextID();
- valueIDMap[arg] = argValueID;
- encodeInstructionInto(functionHeader, spirv::Opcode::OpFunctionParameter,
- {argTypeID, argValueID});
- }
-
- // Process the body.
- if (op.isExternal()) {
- return op.emitError("external function is unhandled");
- }
-
- // Some instructions (e.g., OpVariable) in a function must be in the first
- // block in the function. These instructions will be put in functionHeader.
- // Thus, we put the label in functionHeader first, and omit it from the first
- // block.
- encodeInstructionInto(functionHeader, spirv::Opcode::OpLabel,
- {getOrCreateBlockID(&op.front())});
- if (failed(processBlock(&op.front(), /*omitLabel=*/true)))
- return failure();
- if (failed(visitInPrettyBlockOrder(
- &op.front(), [&](Block *block) { return processBlock(block); },
- /*skipHeader=*/true))) {
- return failure();
- }
- // There might be OpPhi instructions who have value references needing to fix.
- for (const auto &deferredValue : deferredPhiValues) {
- Value value = deferredValue.first;
- uint32_t id = getValueID(value);
- LLVM_DEBUG(llvm::dbgs() << "[phi] fix reference of value " << value
- << " to id = " << id << '\n');
- assert(id && "OpPhi references undefined value!");
- for (size_t offset : deferredValue.second)
- functionBody[offset] = id;
+ // There might be OpPhi instructions who have value references needing to
+ // fix.
+ for (const auto &deferredValue : deferredPhiValues) {
+ Value value = deferredValue.first;
+ uint32_t id = getValueID(value);
+ LLVM_DEBUG(llvm::dbgs() << "[phi] fix reference of value " << value
+ << " to id = " << id << '\n');
+ assert(id && "OpPhi references undefined value!");
+ for (size_t offset : deferredValue.second)
+ functionBody[offset] = id;
+ }
+ deferredPhiValues.clear();
}
- deferredPhiValues.clear();
-
LLVM_DEBUG(llvm::dbgs() << "-- completed function '" << op.getName()
<< "' --\n");
+ // Insert Decorations based on Function Attributes.
+ // Only attributes we should be considering for decoration are the
+ // ::mlir::spirv::Decoration attributes.
+
+ for (auto attr : op->getAttrs()) {
+ // Only generate OpDecorate op for spirv::Decoration attributes.
+ auto isValidDecoration = mlir::spirv::symbolizeEnum<spirv::Decoration>(
+ llvm::convertToCamelFromSnakeCase(attr.getName().strref(),
+ /*capitalizeFirst=*/true));
+ if (isValidDecoration != std::nullopt) {
+ if (failed(processDecoration(op.getLoc(), funcID, attr))) {
+ return failure();
+ }
+ }
+ }
// Insert OpFunctionEnd.
encodeInstructionInto(functionBody, spirv::Opcode::OpFunctionEnd, {});
diff --git a/mlir/lib/Target/SPIRV/Serialization/Serializer.cpp b/mlir/lib/Target/SPIRV/Serialization/Serializer.cpp
index b1c5dfd5e6bc9..9089ebc84fa60 100644
--- a/mlir/lib/Target/SPIRV/Serialization/Serializer.cpp
+++ b/mlir/lib/Target/SPIRV/Serialization/Serializer.cpp
@@ -208,7 +208,8 @@ void Serializer::processMemoryModel() {
LogicalResult Serializer::processDecoration(Location loc, uint32_t resultID,
NamedAttribute attr) {
auto attrName = attr.getName().strref();
- auto decorationName = llvm::convertToCamelFromSnakeCase(attrName, true);
+ auto decorationName =
+ llvm::convertToCamelFromSnakeCase(attrName, /*capitalizeFirst=*/true);
auto decoration = spirv::symbolizeDecoration(decorationName);
if (!decoration) {
return emitError(
@@ -218,6 +219,18 @@ LogicalResult Serializer::processDecoration(Location loc, uint32_t resultID,
}
SmallVector<uint32_t, 1> args;
switch (*decoration) {
+ case spirv::Decoration::LinkageAttributes: {
+ // Get the value of the Linkage Attributes
+ // e.g., LinkageAttributes=["linkageName", linkageType].
+ auto linkageAttr = attr.getValue().dyn_cast<spirv::LinkageAttributesAttr>();
+ auto linkageName = linkageAttr.getLinkageName();
+ auto linkageType = linkageAttr.getLinkageType().getValue();
+ // Encode the Linkage Name (string literal to uint32_t).
+ spirv::encodeStringLiteralInto(args, linkageName);
+ // Encode LinkageType & Add the Linkagetype to the args.
+ args.push_back(static_cast<uint32_t>(linkageType));
+ break;
+ }
case spirv::Decoration::Binding:
case spirv::Decoration::DescriptorSet:
case spirv::Decoration::Location:
diff --git a/mlir/test/Dialect/SPIRV/IR/function-decorations.mlir b/mlir/test/Dialect/SPIRV/IR/function-decorations.mlir
new file mode 100644
index 0000000000000..2e39421df13cc
--- /dev/null
+++ b/mlir/test/Dialect/SPIRV/IR/function-decorations.mlir
@@ -0,0 +1,19 @@
+// RUN: mlir-opt -split-input-file -verify-diagnostics %s | FileCheck %s
+
+spirv.module Logical GLSL450 requires #spirv.vce<v1.0, [Shader, Linkage], []> {
+ spirv.func @linkage_attr_test_kernel() "DontInline" attributes {} {
+ %uchar_0 = spirv.Constant 0 : i8
+ %ushort_1 = spirv.Constant 1 : i16
+ %uint_0 = spirv.Constant 0 : i32
+ spirv.FunctionCall @outside.func.with.linkage(%uchar_0):(i8) -> ()
+ spirv.Return
+ }
+ // CHECK: linkage_attributes = #spirv.linkage_attributes<linkage_name = outside.func, linkage_type = <Import>>
+ spirv.func @outside.func.with.linkage(%arg0 : i8) -> () "Pure" attributes {
+ linkage_attributes=#spirv.linkage_attributes<
+ linkage_name="outside.func",
+ linkage_type=<Import>
+ >
+ }
+ spirv.func @inside.func() -> () "Pure" attributes {} {spirv.Return}
+}
diff --git a/mlir/test/Dialect/SPIRV/IR/structure-ops.mlir b/mlir/test/Dialect/SPIRV/IR/structure-ops.mlir
index 17305f9c1f1c8..174485f71d21d 100644
--- a/mlir/test/Dialect/SPIRV/IR/structure-ops.mlir
+++ b/mlir/test/Dialect/SPIRV/IR/structure-ops.mlir
@@ -270,6 +270,26 @@ spirv.func @baz(%arg: i32) "DontInline" attributes {
// -----
+spirv.module Logical GLSL450 requires #spirv.vce<v1.0, [Shader, Linkage], []> {
+ // CHECK: linkage_attributes = #spirv.linkage_attributes<linkage_name = outside.func, linkage_type = <Import>>
+ spirv.func @outside.func.with.linkage(%arg0 : i8) -> () "Pure" attributes {
+ linkage_attributes=#spirv.linkage_attributes<
+ linkage_name="outside.func",
+ linkage_type=<Import>
+ >
+ }
+ spirv.func @inside.func() -> () "Pure" attributes {} {spirv.Return}
+}
+// -----
+
+spirv.module Logical GLSL450 requires #spirv.vce<v1.0, [Shader, Linkage], []> {
+ // expected-error @+1 {{'spirv.module' cannot contain external functions without 'Import' linkage_attributes (LinkageAttributes)}}
+ spirv.func @outside.func.without.linkage(%arg0 : i8) -> () "Pure"
+ spirv.func @inside.func() -> () "Pure" attributes {} {spirv.Return}
+}
+
+// -----
+
// expected-error @+1 {{expected function_control attribute specified as string}}
spirv.func @missing_function_control() { spirv.Return }
@@ -360,6 +380,19 @@ module {
spirv.GlobalVariable @var0 : !spirv.ptr<f32, Input>
}
+// -----
+
+spirv.module Logical GLSL450 requires #spirv.vce<v1.0, [Shader, Linkage], []> {
+ // CHECK: linkage_attributes = #spirv.linkage_attributes<linkage_name = outSideGlobalVar1, linkage_type = <Import>>
+ spirv.GlobalVariable @var1 {
+ linkage_attributes=#spirv.linkage_attributes<
+ linkage_name="outSideGlobalVar1",
+ linkage_type=<Import>
+ >
+ } : !spirv.ptr<f32, Private>
+}
+
+
// -----
spirv.module Logical GLSL450 {
diff --git a/mlir/test/Target/SPIRV/decorations.mlir b/mlir/test/Target/SPIRV/decorations.mlir
index a52b0f52eb033..aadf64c340b34 100644
--- a/mlir/test/Target/SPIRV/decorations.mlir
+++ b/mlir/test/Target/SPIRV/decorations.mlir
@@ -55,4 +55,14 @@ spirv.module Logical GLSL450 requires #spirv.vce<v1.0, [Shader], []> {
// CHECK: relaxed_precision
spirv.GlobalVariable @var {location = 0 : i32, relaxed_precision} : !spirv.ptr<vector<4xf32>, Output>
}
+// -----
+spirv.module Logical GLSL450 requires #spirv.vce<v1.0, [Shader, Linkage], []> {
+ // CHECK: linkage_attributes = #spirv.linkage_attributes<linkage_name = outSideGlobalVar1, linkage_type = <Import>>
+ spirv.GlobalVariable @var1 {
+ linkage_attributes=#spirv.linkage_attributes<
+ linkage_name="outSideGlobalVar1",
+ linkage_type=<Import>
+ >
+ } : !spirv.ptr<f32, Private>
+}
diff --git a/mlir/test/Target/SPIRV/function-decorations.mlir b/mlir/test/Target/SPIRV/function-decorations.mlir
new file mode 100644
index 0000000000000..b0f6705df9ca4
--- /dev/null
+++ b/mlir/test/Target/SPIRV/function-decorations.mlir
@@ -0,0 +1,19 @@
+// RUN: mlir-translate -no-implicit-module -test-spirv-roundtrip %s | FileCheck %s
+
+spirv.module Logical GLSL450 requires #spirv.vce<v1.0, [Shader, Linkage], []> {
+ spirv.func @linkage_attr_test_kernel() "DontInline" attributes {} {
+ %uchar_0 = spirv.Constant 0 : i8
+ %ushort_1 = spirv.Constant 1 : i16
+ %uint_0 = spirv.Constant 0 : i32
+ spirv.FunctionCall @outside.func.with.linkage(%uchar_0):(i8) -> ()
+ spirv.Return
+ }
+ // CHECK: linkage_attributes = #spirv.linkage_attributes<linkage_name = outside.func, linkage_type = <Import>>
+ spirv.func @outside.func.with.linkage(%arg0 : i8) -> () "Pure" attributes {
+ linkage_attributes=#spirv.linkage_attributes<
+ linkage_name="outside.func",
+ linkage_type=<Import>
+ >
+ }
+ spirv.func @inside.func() -> () "Pure" attributes {} {spirv.Return}
+}
diff --git a/mlir/test/Target/SPIRV/global-variable.mlir b/mlir/test/Target/SPIRV/global-variable.mlir
index 48bd80559dd67..66d0782c205c7 100644
--- a/mlir/test/Target/SPIRV/global-variable.mlir
+++ b/mlir/test/Target/SPIRV/global-variable.mlir
@@ -34,3 +34,15 @@ spirv.module Logical GLSL450 requires #spirv.vce<v1.0, [Shader], []> {
spirv.Return
}
}
+
+// -----
+
+spirv.module Logical GLSL450 requires #spirv.vce<v1.0, [Shader, Linkage], []> {
+ // CHECK: linkage_attributes = #spirv.linkage_attributes<linkage_name = outSideGlobalVar1, linkage_type = <Import>>
+ spirv.GlobalVariable @var1 {
+ linkage_attributes=#spirv.linkage_attributes<
+ linkage_name="outSideGlobalVar1",
+ linkage_type=<Import>
+ >
+ } : !spirv.ptr<f32, Private>
+}
More information about the Mlir-commits
mailing list