diff --git a/mlir/include/mlir/Dialect/SPIRV/IR/SPIRVBase.td b/mlir/include/mlir/Dialect/SPIRV/IR/SPIRVBase.td --- a/mlir/include/mlir/Dialect/SPIRV/IR/SPIRVBase.td +++ b/mlir/include/mlir/Dialect/SPIRV/IR/SPIRVBase.td @@ -4267,6 +4267,8 @@ def SPIRV_OC_OpUConvert : I32EnumAttrCase<"OpUConvert", 113>; def SPIRV_OC_OpSConvert : I32EnumAttrCase<"OpSConvert", 114>; def SPIRV_OC_OpFConvert : I32EnumAttrCase<"OpFConvert", 115>; +def SPIRV_OC_OpConvertPtrToU : I32EnumAttrCase<"OpConvertPtrToU", 117>; +def SPIRV_OC_OpConvertUToPtr : I32EnumAttrCase<"OpConvertUToPtr", 120>; def SPIRV_OC_OpPtrCastToGeneric : I32EnumAttrCase<"OpPtrCastToGeneric", 121>; def SPIRV_OC_OpGenericCastToPtr : I32EnumAttrCase<"OpGenericCastToPtr", 122>; def SPIRV_OC_OpGenericCastToPtrExplicit : I32EnumAttrCase<"OpGenericCastToPtrExplicit", 123>; @@ -4447,6 +4449,7 @@ SPIRV_OC_OpImage, SPIRV_OC_OpImageQuerySize, SPIRV_OC_OpConvertFToU, SPIRV_OC_OpConvertFToS, SPIRV_OC_OpConvertSToF, SPIRV_OC_OpConvertUToF, SPIRV_OC_OpUConvert, SPIRV_OC_OpSConvert, SPIRV_OC_OpFConvert, + SPIRV_OC_OpConvertPtrToU, SPIRV_OC_OpConvertUToPtr, SPIRV_OC_OpPtrCastToGeneric, SPIRV_OC_OpGenericCastToPtr, SPIRV_OC_OpGenericCastToPtrExplicit, SPIRV_OC_OpBitcast, SPIRV_OC_OpSNegate, SPIRV_OC_OpFNegate, SPIRV_OC_OpIAdd, SPIRV_OC_OpFAdd, SPIRV_OC_OpISub, diff --git a/mlir/include/mlir/Dialect/SPIRV/IR/SPIRVCastOps.td b/mlir/include/mlir/Dialect/SPIRV/IR/SPIRVCastOps.td --- a/mlir/include/mlir/Dialect/SPIRV/IR/SPIRVCastOps.td +++ b/mlir/include/mlir/Dialect/SPIRV/IR/SPIRVCastOps.td @@ -332,6 +332,118 @@ } // ----- + +def SPIRV_ConvertPtrToUOp : SPIRV_Op<"ConvertPtrToU", []> { + let summary = [{ + Bit pattern-preserving conversion of a pointer to + an unsigned scalar integer of possibly different bit width. + }]; + + let description = [{ + Result Type must be a scalar of integer type, whose Signedness operand is 0. + + Pointer must be a physical pointer type. If the bit width of Pointer is + smaller than that of Result Type, the conversion zero extends Pointer. + If the bit width of Pointer is larger than that of Result Type, + the conversion truncates Pointer. + + For same bit width Pointer and Result Type, this is the same as OpBitcast. + + + + ``` + ptr-to-u-convert-op ::= ssa-id `=` `spirv.ConvertPtrToUOp` ssa-use + `:` operand-type `to` result-type + ``` + + #### Example: + + ```mlir + %1 = spirv.ConvertPtrToU %0 : !spirv.ptr to i32 + ``` + }]; + + let availability = [ + MinVersion, + MaxVersion, + Extension<[]>, + Capability<[SPIRV_C_Addresses, SPIRV_C_PhysicalStorageBufferAddresses]> + ]; + + let arguments = (ins + SPIRV_AnyPtr:$pointer + ); + + let results = (outs + SPIRV_Integer:$result + ); + + let assemblyFormat = [{ + $pointer attr-dict `:` type($pointer) `to` type($result) + }]; + + let hasVerifier = 1; +} + + +// ----- + +def SPIRV_ConvertUToPtrOp : SPIRV_Op<"ConvertUToPtr", [UnsignedOp]> { + let summary = [{ + Bit pattern-preserving conversion of an unsigned scalar integer + to a pointer. + }]; + + let description = [{ + Result Type must be a physical pointer type. + + Integer Value must be a scalar of integer type, whose Signedness + operand is 0. If the bit width of Integer Value is smaller + than that of Result Type, the conversion zero extends Integer Value. + If the bit width of Integer Value is larger than that of Result Type, + the conversion truncates Integer Value. + + For same-width Integer Value and Result Type, this is the same as OpBitcast. + + + + ``` + u-to-ptr-convert-op ::= ssa-id `=` `spirv.ConvertUToPtr` ssa-use + `:` operand-type `to` result-type + ``` + + #### Example: + + ```mlir + %1 = spirv.ConvertUToPtr %0 : i32 to !spirv.ptr + ``` + }]; + + let availability = [ + MinVersion, + MaxVersion, + Extension<[]>, + Capability<[SPIRV_C_Addresses, SPIRV_C_PhysicalStorageBufferAddresses]> + ]; + + let arguments = (ins + SPIRV_Integer:$operand + ); + + let results = (outs + SPIRV_AnyPtr:$result + ); + + let assemblyFormat = [{ + $operand attr-dict `:` type($operand) `to` type($result) + }]; + + let hasVerifier = 1; +} + +// ----- + + def SPIRV_PtrCastToGenericOp : SPIRV_Op<"PtrCastToGeneric", [Pure]> { let summary = "Convert a pointer’s Storage Class to Generic."; diff --git a/mlir/lib/Dialect/SPIRV/IR/SPIRVOps.cpp b/mlir/lib/Dialect/SPIRV/IR/SPIRVOps.cpp --- a/mlir/lib/Dialect/SPIRV/IR/SPIRVOps.cpp +++ b/mlir/lib/Dialect/SPIRV/IR/SPIRVOps.cpp @@ -1557,6 +1557,48 @@ return success(); } +//===----------------------------------------------------------------------===// +// spirv.ConvertPtrToUOp +//===----------------------------------------------------------------------===// + +LogicalResult spirv::ConvertPtrToUOp::verify() { + auto operandType = getPointer().getType().cast(); + auto resultType = getResult().getType().cast(); + if (!resultType || !resultType.isSignlessInteger()) + return emitError("result must be a scalar type of unsigned integer"); + auto spirvModule = (*this)->getParentOfType(); + if (!spirvModule) + return success(); + auto addressingModel = spirvModule.getAddressingModel(); + if ((addressingModel == spirv::AddressingModel::Logical) || + (addressingModel == spirv::AddressingModel::PhysicalStorageBuffer64 && + operandType.getStorageClass() != + spirv::StorageClass::PhysicalStorageBuffer)) + return emitError("operand must be a physical pointer"); + return success(); +} + +//===----------------------------------------------------------------------===// +// spirv.ConvertUToPtrOp +//===----------------------------------------------------------------------===// + +LogicalResult spirv::ConvertUToPtrOp::verify() { + auto operandType = getOperand().getType().cast(); + auto resultType = getResult().getType().cast(); + if (!operandType || !operandType.isSignlessInteger()) + return emitError("result must be a scalar type of unsigned integer"); + auto spirvModule = (*this)->getParentOfType(); + if (!spirvModule) + return success(); + auto addressingModel = spirvModule.getAddressingModel(); + if ((addressingModel == spirv::AddressingModel::Logical) || + (addressingModel == spirv::AddressingModel::PhysicalStorageBuffer64 && + resultType.getStorageClass() != + spirv::StorageClass::PhysicalStorageBuffer)) + return emitError("result must be a physical pointer"); + return success(); +} + //===----------------------------------------------------------------------===// // spirv.PtrCastToGenericOp //===----------------------------------------------------------------------===// diff --git a/mlir/test/Dialect/SPIRV/IR/cast-ops.mlir b/mlir/test/Dialect/SPIRV/IR/cast-ops.mlir --- a/mlir/test/Dialect/SPIRV/IR/cast-ops.mlir +++ b/mlir/test/Dialect/SPIRV/IR/cast-ops.mlir @@ -363,3 +363,109 @@ %0 = spirv.GenericCastToPtrExplicit %arg0 : !spirv.ptr to !spirv.ptr, Workgroup> return } + +// ----- + +//===----------------------------------------------------------------------===// +// spirv.ConvertPtrToU +//===----------------------------------------------------------------------===// +spirv.module Physical64 OpenCL requires #spirv.vce { + spirv.func @covert_ptr_to_u(%arg0 : !spirv.ptr) "None" { + // CHECK: {{%.*}} = spirv.ConvertPtrToU {{%.*}} : !spirv.ptr to i32 + %0 = spirv.ConvertPtrToU %arg0 : !spirv.ptr to i32 + spirv.Return + } + spirv.func @covert_ptr_to_u_truncate(%arg0 : !spirv.ptr) "None" { + // CHECK: {{%.*}} = spirv.ConvertPtrToU {{%.*}} : !spirv.ptr to i32 + %0 = spirv.ConvertPtrToU %arg0 : !spirv.ptr to i32 + spirv.Return + } + spirv.func @covert_ptr_to_u_extend(%arg0 : !spirv.ptr) "None" { + // CHECK: {{%.*}} = spirv.ConvertPtrToU {{%.*}} : !spirv.ptr to i64 + %0 = spirv.ConvertPtrToU %arg0 : !spirv.ptr to i64 + spirv.Return + } +} + +// ----- + +spirv.module PhysicalStorageBuffer64 OpenCL requires #spirv.vce { + spirv.func @covert_ptr_to_u_PhysicalStorageBuffer(%arg0 : !spirv.ptr) "None" { + // CHECK: {{%.*}} = spirv.ConvertPtrToU {{%.*}} : !spirv.ptr to i32 + %0 = spirv.ConvertPtrToU %arg0 : !spirv.ptr to i32 + spirv.Return + } +} + +// ----- + +spirv.module PhysicalStorageBuffer64 OpenCL requires #spirv.vce { + spirv.func @covert_ptr_to_u_fail(%arg0 : !spirv.ptr) "None" { + // expected-error @+1 {{operand must be a physical pointer}} + %0 = spirv.ConvertPtrToU %arg0 : !spirv.ptr to i32 + spirv.Return + } +} + +// ----- + +spirv.module Logical GLSL450 requires #spirv.vce { + spirv.func @covert_ptr_to_u_fail_2(%arg0 : !spirv.ptr) "None" { + // expected-error @+1 {{operand must be a physical pointer}} + %0 = spirv.ConvertPtrToU %arg0 : !spirv.ptr to i32 + spirv.Return + } +} + +// ----- + +//===----------------------------------------------------------------------===// +// spirv.ConvertUToPtr +//===----------------------------------------------------------------------===// +spirv.module Physical64 OpenCL requires #spirv.vce { + spirv.func @covert_u_to_ptr(%arg0 : i32) "None" { + // CHECK: {{%.*}} = spirv.ConvertUToPtr {{%.*}} : i32 to !spirv.ptr + %0 = spirv.ConvertUToPtr %arg0 : i32 to !spirv.ptr + spirv.Return + } + spirv.func @covert_u_to_ptr_truncate(%arg0 : i64) "None" { + // CHECK: {{%.*}} = spirv.ConvertUToPtr {{%.*}} : i64 to !spirv.ptr + %0 = spirv.ConvertUToPtr %arg0 : i64 to !spirv.ptr + spirv.Return + } + spirv.func @covert_u_to_ptr_extend(%arg0 : i32) "None" { + // CHECK: {{%.*}} = spirv.ConvertUToPtr {{%.*}} : i32 to !spirv.ptr + %0 = spirv.ConvertUToPtr %arg0 : i32 to !spirv.ptr + spirv.Return + } +} + +// ----- + +spirv.module PhysicalStorageBuffer64 OpenCL requires #spirv.vce { + spirv.func @covert_u_to_ptr_PhysicalStorageBuffer(%arg0 : i32) "None" { + // CHECK: {{%.*}} = spirv.ConvertUToPtr {{%.*}} : i32 to !spirv.ptr + %0 = spirv.ConvertUToPtr %arg0 : i32 to !spirv.ptr + spirv.Return + } +} + +// ----- + +spirv.module PhysicalStorageBuffer64 OpenCL requires #spirv.vce { + spirv.func @covert_u_to_ptr_fail(%arg0 : i32) "None" { + // expected-error @+1 {{result must be a physical pointer}} + %0 = spirv.ConvertUToPtr %arg0 : i32 to !spirv.ptr + spirv.Return + } +} + +// ----- + +spirv.module Logical GLSL450 requires #spirv.vce { + spirv.func @covert_u_to_ptr_fail_2(%arg0 : i32) "None" { + // expected-error @+1 {{result must be a physical pointer}} + %0 = spirv.ConvertUToPtr %arg0 : i32 to !spirv.ptr + spirv.Return + } +} diff --git a/mlir/test/Target/SPIRV/cast-ops.mlir b/mlir/test/Target/SPIRV/cast-ops.mlir --- a/mlir/test/Target/SPIRV/cast-ops.mlir +++ b/mlir/test/Target/SPIRV/cast-ops.mlir @@ -91,3 +91,63 @@ spirv.Return } } + +// ----- + +spirv.module Physical64 OpenCL requires #spirv.vce { + spirv.func @covert_ptr_to_u(%arg0 : !spirv.ptr) "None" { + // CHECK: {{%.*}} = spirv.ConvertPtrToU {{%.*}} : !spirv.ptr to i32 + %0 = spirv.ConvertPtrToU %arg0 : !spirv.ptr to i32 + spirv.Return + } + spirv.func @covert_ptr_to_u_truncate(%arg0 : !spirv.ptr) "None" { + // CHECK: {{%.*}} = spirv.ConvertPtrToU {{%.*}} : !spirv.ptr to i32 + %0 = spirv.ConvertPtrToU %arg0 : !spirv.ptr to i32 + spirv.Return + } + spirv.func @covert_ptr_to_u_extend(%arg0 : !spirv.ptr) "None" { + // CHECK: {{%.*}} = spirv.ConvertPtrToU {{%.*}} : !spirv.ptr to i64 + %0 = spirv.ConvertPtrToU %arg0 : !spirv.ptr to i64 + spirv.Return + } +} + +// ----- + +spirv.module PhysicalStorageBuffer64 OpenCL requires #spirv.vce { + spirv.func @covert_ptr_to_u_PhysicalStorageBuffer(%arg0 : !spirv.ptr) "None" { + // CHECK: {{%.*}} = spirv.ConvertPtrToU {{%.*}} : !spirv.ptr to i32 + %0 = spirv.ConvertPtrToU %arg0 : !spirv.ptr to i32 + spirv.Return + } +} + +// ----- + +spirv.module Physical64 OpenCL requires #spirv.vce { + spirv.func @covert_u_to_ptr(%arg0 : i32) "None" { + // CHECK: {{%.*}} = spirv.ConvertUToPtr {{%.*}} : i32 to !spirv.ptr + %0 = spirv.ConvertUToPtr %arg0 : i32 to !spirv.ptr + spirv.Return + } + spirv.func @covert_u_to_ptr_truncate(%arg0 : i64) "None" { + // CHECK: {{%.*}} = spirv.ConvertUToPtr {{%.*}} : i64 to !spirv.ptr + %0 = spirv.ConvertUToPtr %arg0 : i64 to !spirv.ptr + spirv.Return + } + spirv.func @covert_u_to_ptr_extend(%arg0 : i32) "None" { + // CHECK: {{%.*}} = spirv.ConvertUToPtr {{%.*}} : i32 to !spirv.ptr + %0 = spirv.ConvertUToPtr %arg0 : i32 to !spirv.ptr + spirv.Return + } +} + +// ----- + +spirv.module PhysicalStorageBuffer64 OpenCL requires #spirv.vce { + spirv.func @covert_u_to_ptr_PhysicalStorageBuffer(%arg0 : i32) "None" { + // CHECK: {{%.*}} = spirv.ConvertUToPtr {{%.*}} : i32 to !spirv.ptr + %0 = spirv.ConvertUToPtr %arg0 : i32 to !spirv.ptr + spirv.Return + } +}