- The SPIR-V spec requires that OpConstantComposite must not reference spec constant operands. When a composite contains non-constant constitued, OpSpecConstantComposite should be emitted instead of OpConstantComposite - Avoid creating function pointer types when the SPV_INTEL_function_pointers extension is unavailable, falling back to i8 as the pointee type - Re-enable spirv-val validation in tests that previously failed due to this issue, and un-XFAIL the block_w_struct_return and global_block transcoding tests related to #60133 fixes #186756
64 lines
3.3 KiB
LLVM
64 lines
3.3 KiB
LLVM
; RUN: llc -O0 -mtriple=spirv32-unknown-unknown %s -o - | FileCheck %s --check-prefixes=CHECK-SPIRV,CHECK-SPIRV1_4
|
|
; RUNx: %if spirv-tools %{ llc -O0 -mtriple=spirv32-unknown-unknown %s -o - -filetype=obj | spirv-val %}
|
|
;; FIXME: spirv-val fails with OpConstantComposite expects i8*
|
|
|
|
;; There are no blocks in SPIR-V. Therefore they are translated into regular
|
|
;; functions. An LLVM module which uses blocks, also contains some auxiliary
|
|
;; block-specific instructions, which are redundant in SPIR-V and should be
|
|
;; removed
|
|
|
|
;; kernel void block_kernel(__global int* res) {
|
|
;; typedef int (^block_t)(int);
|
|
;; constant block_t b1 = ^(int i) { return i + 1; };
|
|
;; *res = b1(5);
|
|
;; }
|
|
|
|
; CHECK-SPIRV1_4-DAG: OpEntryPoint Kernel %[[#]] "block_kernel" %[[#InterfaceId1:]] %[[#InterfaceId2:]]
|
|
; CHECK-SPIRV1_4-DAG: OpName %[[#InterfaceId1]] "__block_literal_global"
|
|
; CHECK-SPIRV1_4-DAG: OpName %[[#InterfaceId2]] "block_kernel.b1"
|
|
; CHECK-SPIRV: OpName %[[#block_invoke:]] "_block_invoke"
|
|
; CHECK-SPIRV: %[[#int8:]] = OpTypeInt 8
|
|
; CHECK-SPIRV: %[[#int:]] = OpTypeInt 32
|
|
; CHECK-SPIRV: %[[#GenericInt8Ptr:]] = OpTypePointer Generic %[[#int8]]
|
|
; CHECK-SPIRV: %[[#BlockStruct:]] = OpTypeStruct %[[#int]] %[[#int]] %[[#GenericInt8Ptr]]
|
|
; CHECK-SPIRV: %[[#BlockStructPtr:]] = OpTypePointer Generic %[[#BlockStruct]]
|
|
; CHECK-SPIRV: %[[#five:]] = OpConstant %[[#int]] 5
|
|
; CHECK-SPIRV: %[[#block_invoke_type:]] = OpTypeFunction %[[#int]] %[[#BlockStructPtr]] %[[#int]]
|
|
|
|
; CHECK-SPIRV: %[[#]] = OpFunctionCall %[[#int]] %[[#block_invoke]] %[[#]] %[[#five]]
|
|
|
|
; CHECK-SPIRV: %[[#block_invoke]] = OpFunction %[[#int]] DontInline %[[#block_invoke_type]]
|
|
; CHECK-SPIRV-NEXT: %[[#]] = OpFunctionParameter %[[#BlockStructPtr]]
|
|
; CHECK-SPIRV-NEXT: %[[#]] = OpFunctionParameter %[[#int]]
|
|
|
|
%struct.__opencl_block_literal_generic = type { i32, i32, ptr addrspace(4) }
|
|
|
|
@block_kernel.b1 = internal addrspace(2) constant ptr addrspace(4) addrspacecast (ptr addrspace(1) @__block_literal_global to ptr addrspace(4)), align 4
|
|
@__block_literal_global = internal addrspace(1) constant { i32, i32, ptr addrspace(4) } { i32 12, i32 4, ptr addrspace(4) addrspacecast (ptr @_block_invoke to ptr addrspace(4)) }, align 4
|
|
|
|
define dso_local spir_kernel void @block_kernel(ptr addrspace(1) noundef %res) {
|
|
entry:
|
|
%res.addr = alloca ptr addrspace(1), align 4
|
|
store ptr addrspace(1) %res, ptr %res.addr, align 4
|
|
%call = call spir_func i32 @_block_invoke(ptr addrspace(4) noundef addrspacecast (ptr addrspace(1) @__block_literal_global to ptr addrspace(4)), i32 noundef 5)
|
|
%0 = load ptr addrspace(1), ptr %res.addr, align 4
|
|
store i32 %call, ptr addrspace(1) %0, align 4
|
|
ret void
|
|
}
|
|
|
|
define internal spir_func i32 @_block_invoke(ptr addrspace(4) noundef %.block_descriptor, i32 noundef %i) #0 {
|
|
entry:
|
|
%.block_descriptor.addr = alloca ptr addrspace(4), align 4
|
|
%i.addr = alloca i32, align 4
|
|
%block.addr = alloca ptr addrspace(4), align 4
|
|
store ptr addrspace(4) %.block_descriptor, ptr %.block_descriptor.addr, align 4
|
|
%block = bitcast ptr addrspace(4) %.block_descriptor to ptr addrspace(4)
|
|
store i32 %i, ptr %i.addr, align 4
|
|
store ptr addrspace(4) %block, ptr %block.addr, align 4
|
|
%0 = load i32, ptr %i.addr, align 4
|
|
%add = add nsw i32 %0, 1
|
|
ret i32 %add
|
|
}
|
|
|
|
attributes #0 = { noinline }
|