blob: 5291970333eb69a1645cd028c87eacfeb950e5f2 [file] [log] [blame]
// RUN: iree-opt -split-input-file -iree-hal-link-executables %s | FileCheck %s
#vmvx_target = #hal.executable.target<"vmvx", "vmvx-bytecode-fb">
#executable_layout = #hal.executable.layout<push_constants = 1, sets = [
#hal.descriptor_set.layout<0, bindings = [
#hal.descriptor_set.binding<0, storage_buffer>,
#hal.descriptor_set.binding<1, storage_buffer>
]>
]>
hal.executable private @dispatch_0 {
hal.executable.variant @vmvx, target = #vmvx_target {
hal.executable.entry_point @dispatch_0 ordinal(0) layout(#executable_layout)
builtin.module {
vm.module @module {
vm.func @dispatch_0() {
vm.return
}
vm.export @dispatch_0
}
}
}
}
hal.executable private @dispatch_1 {
hal.executable.variant @vmvx, target = #vmvx_target {
hal.executable.entry_point @dispatch_1 ordinal(0) layout(#executable_layout)
builtin.module {
vm.module @module {
vm.func @dispatch_1() {
vm.return
}
vm.export @dispatch_1
}
}
}
}
hal.executable private @dispatch_2 {
hal.executable.variant @vmvx, target = #vmvx_target {
hal.executable.entry_point @dispatch_2 ordinal(0) layout(#executable_layout)
builtin.module {
vm.module @module {
vm.func @dispatch_2() {
vm.return
}
vm.export @dispatch_2
}
}
}
}
func @basic_linking() -> () {
%device = hal.ex.shared_device : !hal.device
%cmd = hal.command_buffer.create device(%device : !hal.device) mode("OneShot") categories("Transfer|Dispatch") : !hal.command_buffer
%c1 = arith.constant 1 : index
hal.command_buffer.dispatch.symbol<%cmd : !hal.command_buffer> target(@dispatch_0::@vmvx::@dispatch_0) workgroups([%c1, %c1, %c1])
hal.command_buffer.dispatch.symbol<%cmd : !hal.command_buffer> target(@dispatch_1::@vmvx::@dispatch_1) workgroups([%c1, %c1, %c1])
hal.command_buffer.dispatch.symbol<%cmd : !hal.command_buffer> target(@dispatch_2::@vmvx::@dispatch_2) workgroups([%c1, %c1, %c1])
return
}
util.initializer {
%device = hal.ex.shared_device : !hal.device
%cmd = hal.command_buffer.create device(%device : !hal.device) mode("OneShot") categories("Transfer|Dispatch") : !hal.command_buffer
%c1 = arith.constant 1 : index
hal.command_buffer.dispatch.symbol<%cmd : !hal.command_buffer> target(@dispatch_0::@vmvx::@dispatch_0) workgroups([%c1, %c1, %c1])
hal.command_buffer.dispatch.symbol<%cmd : !hal.command_buffer> target(@dispatch_1::@vmvx::@dispatch_1) workgroups([%c1, %c1, %c1])
hal.command_buffer.dispatch.symbol<%cmd : !hal.command_buffer> target(@dispatch_2::@vmvx::@dispatch_2) workgroups([%c1, %c1, %c1])
util.initializer.return
}
// All executables (including their interfaces and entry points) should be
// linked together into a single executable.
// CHECK-NOT: hal.executable private @dispatch_0
// CHECK-NOT: hal.executable private @dispatch_1
// CHECK-NOT: hal.executable private @dispatch_2
// CHECK: hal.executable private @vmvx_linked {
// CHECK-NEXT: hal.executable.variant public @vmvx_bytecode_fb, target = #executable_target_vmvx_bytecode_fb {
// CHECK-NEXT: hal.executable.entry_point public @dispatch_0 ordinal(0)
// CHECK-NEXT: hal.executable.entry_point public @dispatch_1 ordinal(1)
// CHECK-NEXT: hal.executable.entry_point public @dispatch_2 ordinal(2)
// CHECK-NEXT: module {
// CHECK-NEXT: vm.module public @linked_module {
// CHECK-NEXT: vm.func @dispatch_0() {
// CHECK-NEXT: vm.return
// CHECK-NEXT: }
// CHECK-NEXT: vm.export @dispatch_0
// CHECK-NEXT: vm.func @dispatch_1() {
// CHECK-NEXT: vm.return
// CHECK-NEXT: }
// CHECK-NEXT: vm.export @dispatch_1
// CHECK-NEXT: vm.func @dispatch_2() {
// CHECK-NEXT: vm.return
// CHECK-NEXT: }
// CHECK-NEXT: vm.export @dispatch_2
// CHECK-NEXT: }
// CHECK-NEXT: }
// CHECK-NEXT: }
// CHECK-NEXT: }
//
// CHECK: func @basic_linking() {
// CHECK: hal.command_buffer.dispatch.symbol<%cmd : !hal.command_buffer> target(@vmvx_linked::@vmvx_bytecode_fb::@dispatch_0) workgroups([%c1, %c1, %c1])
// CHECK-NEXT: hal.command_buffer.dispatch.symbol<%cmd : !hal.command_buffer> target(@vmvx_linked::@vmvx_bytecode_fb::@dispatch_1) workgroups([%c1, %c1, %c1])
// CHECK-NEXT: hal.command_buffer.dispatch.symbol<%cmd : !hal.command_buffer> target(@vmvx_linked::@vmvx_bytecode_fb::@dispatch_2) workgroups([%c1, %c1, %c1])
// CHECK-NEXT: return
// CHECK-NEXT: }
//
// CHECK: util.initializer {
// CHECK: hal.command_buffer.dispatch.symbol<%cmd : !hal.command_buffer> target(@vmvx_linked::@vmvx_bytecode_fb::@dispatch_0) workgroups([%c1, %c1, %c1])
// CHECK-NEXT: hal.command_buffer.dispatch.symbol<%cmd : !hal.command_buffer> target(@vmvx_linked::@vmvx_bytecode_fb::@dispatch_1) workgroups([%c1, %c1, %c1])
// CHECK-NEXT: hal.command_buffer.dispatch.symbol<%cmd : !hal.command_buffer> target(@vmvx_linked::@vmvx_bytecode_fb::@dispatch_2) workgroups([%c1, %c1, %c1])
// CHECK-NEXT: util.initializer.return
// CHECK-NEXT: }
// -----
#cuda_target = #hal.executable.target<"cuda", "cuda-nvptx-fb">
#vmvx_target = #hal.executable.target<"vmvx", "vmvx-bytecode-fb">
#executable_layout = #hal.executable.layout<push_constants = 1, sets = [
#hal.descriptor_set.layout<0, bindings = [
#hal.descriptor_set.binding<0, storage_buffer>,
#hal.descriptor_set.binding<1, storage_buffer>
]>
]>
hal.executable private @dispatch_0 {
hal.executable.variant @vmvx, target = #vmvx_target {
hal.executable.entry_point @dispatch_0 ordinal(0) layout(#executable_layout)
builtin.module {
vm.module @module {
vm.func @dispatch_0() {
vm.return
}
vm.export @dispatch_0
}
}
}
hal.executable.variant @cuda, target = #cuda_target {
builtin.module {
}
}
}
hal.executable private @dispatch_1 {
hal.executable.variant @vmvx, target = #vmvx_target {
hal.executable.entry_point @dispatch_1 ordinal(0) layout(#executable_layout)
builtin.module {
vm.module @module {
vm.func @dispatch_1() {
vm.return
}
vm.export @dispatch_1
}
}
}
hal.executable.variant @cuda, target = #cuda_target {
builtin.module {
}
}
}
func @other_targets() -> () {
%device = hal.ex.shared_device : !hal.device
%cmd = hal.command_buffer.create device(%device : !hal.device) mode("OneShot") categories("Transfer|Dispatch") : !hal.command_buffer
hal.device.switch<%device : !hal.device>
#hal.device.match.executable.format<"vmvx-bytecode-fb"> {
%c1 = arith.constant 1 : index
hal.command_buffer.dispatch.symbol<%cmd : !hal.command_buffer> target(@dispatch_0::@vmvx::@dispatch_0) workgroups([%c1, %c1, %c1])
hal.command_buffer.dispatch.symbol<%cmd : !hal.command_buffer> target(@dispatch_1::@vmvx::@dispatch_1) workgroups([%c1, %c1, %c1])
hal.return
},
#hal.device.match.executable.format<"cuda-nvptx-fb"> {
%c1 = arith.constant 1 : index
hal.command_buffer.dispatch.symbol<%cmd : !hal.command_buffer> target(@dispatch_0::@otherdispatch::@dispatch_0) workgroups([%c1, %c1, %c1])
hal.command_buffer.dispatch.symbol<%cmd : !hal.command_buffer> target(@dispatch_1::@otherdispatch::@dispatch_1) workgroups([%c1, %c1, %c1])
hal.return
}
return
}
// VMVX target should be pulled out from both executables leaving the originals
// untouched.
// CHECK: hal.executable private @vmvx_linked {
// CHECK-NEXT: hal.executable.variant public @vmvx_bytecode_fb, target = #executable_target_vmvx_bytecode_fb {
// CHECK-NEXT: hal.executable.entry_point public @dispatch_0 ordinal(0)
// CHECK-NEXT: hal.executable.entry_point public @dispatch_1 ordinal(1)
// CHECK-NEXT: module {
// CHECK-NEXT: vm.module public @linked_module {
// CHECK-NEXT: vm.func @dispatch_0() {
// CHECK-NEXT: vm.return
// CHECK-NEXT: }
// CHECK-NEXT: vm.export @dispatch_0
// CHECK-NEXT: vm.func @dispatch_1() {
// CHECK-NEXT: vm.return
// CHECK-NEXT: }
// CHECK-NEXT: vm.export @dispatch_1
// CHECK-NEXT: }
// CHECK-NEXT: }
// CHECK-NEXT: }
// CHECK-NEXT: }
//
// @dispatch_0/1 should remain, with just @cuda
// CHECK: hal.executable private @dispatch_0 {
// CHECK: hal.executable.variant public @cuda, target = #executable_target_cuda
// CHECK: hal.executable private @dispatch_1 {
// CHECK: hal.executable.variant public @cuda, target = #executable_target_cuda
//
// CHECK: func @other_targets() {
// CHECK: hal.device.switch<%device : !hal.device>
// CHECK-NEXT: #hal.device.match.executable.format<"vmvx-bytecode-fb"> {
// CHECK-NEXT: %c1 = arith.constant 1 : index
// CHECK-NEXT: hal.command_buffer.dispatch.symbol<%cmd : !hal.command_buffer> target(@vmvx_linked::@vmvx_bytecode_fb::@dispatch_0) workgroups([%c1, %c1, %c1])
// CHECK-NEXT: hal.command_buffer.dispatch.symbol<%cmd : !hal.command_buffer> target(@vmvx_linked::@vmvx_bytecode_fb::@dispatch_1) workgroups([%c1, %c1, %c1])
// CHECK-NEXT: hal.return
// CHECK-NEXT: },
// CHECK-NEXT: #hal.device.match.executable.format<"cuda-nvptx-fb"> {
// CHECK-NEXT: %c1 = arith.constant 1 : index
// CHECK-NEXT: hal.command_buffer.dispatch.symbol<%cmd : !hal.command_buffer> target(@dispatch_0::@otherdispatch::@dispatch_0) workgroups([%c1, %c1, %c1])
// CHECK-NEXT: hal.command_buffer.dispatch.symbol<%cmd : !hal.command_buffer> target(@dispatch_1::@otherdispatch::@dispatch_1) workgroups([%c1, %c1, %c1])
// CHECK-NEXT: hal.return
// CHECK-NEXT: }
// CHECK-NEXT: return
// CHECK-NEXT: }
// -----
#vmvx_target = #hal.executable.target<"vmvx", "vmvx-bytecode-fb">
#executable_layout = #hal.executable.layout<push_constants = 1, sets = [
#hal.descriptor_set.layout<0, bindings = [
#hal.descriptor_set.binding<0, storage_buffer>,
#hal.descriptor_set.binding<1, storage_buffer>
]>
]>
hal.executable private @dispatch_0 {
hal.executable.variant @vmvx, target = #vmvx_target {
hal.executable.entry_point @dispatch_0 ordinal(0) layout(#executable_layout)
builtin.module {
vm.module @module {
vm.rodata public @rodata_a dense<[0]> : tensor<1xi32>
vm.rodata public @rodata_b dense<[0]> : tensor<1xi32>
vm.rodata public @rodata_b_0 dense<[0]> : tensor<1xi32>
vm.rodata public @rodata_c dense<[0]> : tensor<1xi32>
vm.rodata private @rodata_d dense<[0]> : tensor<1xi32>
vm.rodata private @rodata_e dense<[0]> : tensor<1xi32>
%buf_a = vm.const.ref.rodata @rodata_a : !vm.buffer
%buf_b = vm.const.ref.rodata @rodata_b : !vm.buffer
%buf_b_0 = vm.const.ref.rodata @rodata_b_0 : !vm.buffer
%buf_c = vm.const.ref.rodata @rodata_c : !vm.buffer
%buf_d = vm.const.ref.rodata @rodata_d : !vm.buffer
%buf_e = vm.const.ref.rodata @rodata_e : !vm.buffer
}
}
}
}
hal.executable private @dispatch_1 {
hal.executable.variant @vmvx, target = #vmvx_target {
hal.executable.entry_point @dispatch_1 ordinal(0) layout(#executable_layout)
builtin.module {
vm.module @module {
// Conflict with a public symbol, this should be renamed when linked.
vm.rodata private @rodata_b dense<[1]> : tensor<1xi32>
// Conflict and reuses the same naming scheme for conflicts.
vm.rodata private @rodata_b_0 dense<[1]> : tensor<1xi32>
// Conflict with a private symbol, this should be renamed when linked.
vm.rodata private @rodata_d dense<[1]> : tensor<1xi32>
// Conflict with a private symbol, the other symbol should be renamed.
vm.rodata public @rodata_e dense<[1]> : tensor<1xi32>
// No conflict.
vm.rodata public @rodata_f dense<[1]> : tensor<1xi32>
%buf_b = vm.const.ref.rodata @rodata_b : !vm.buffer
%buf_b_0 = vm.const.ref.rodata @rodata_b_0 : !vm.buffer
%buf_d = vm.const.ref.rodata @rodata_d : !vm.buffer
%buf_e = vm.const.ref.rodata @rodata_e : !vm.buffer
%buf_f = vm.const.ref.rodata @rodata_f : !vm.buffer
}
}
}
}
// Public symbols should keep their names, private symbols can be renamed to
// resolve conflicts.
// References to renamed symbols should be updated.
//
// CHECK-NOT: hal.executable private @dispatch_0
// CHECK-NOT: hal.executable private @dispatch_1
// CHECK: hal.executable private @vmvx_linked {
// CHECK: hal.executable.variant public @vmvx_bytecode_fb, target = #executable_target_vmvx_bytecode_fb {
// CHECK: module {
// CHECK-NEXT: vm.module public @linked_module {
// CHECK-NEXT: vm.rodata public @rodata_a dense<0> : tensor<1xi32>
// CHECK-NEXT: vm.rodata public @rodata_b dense<0> : tensor<1xi32>
// CHECK-NEXT: vm.rodata public @rodata_b_0 dense<0> : tensor<1xi32>
// CHECK-NEXT: vm.rodata public @rodata_c dense<0> : tensor<1xi32>
// CHECK-NEXT: vm.rodata private @rodata_d dense<0> : tensor<1xi32>
// CHECK-NEXT: vm.rodata private @rodata_e_0 dense<0> : tensor<1xi32>
// CHECK-NEXT: %[[BUF_rodata_a:.+]] = vm.const.ref.rodata @rodata_a : !vm.buffer
// CHECK-NEXT: %[[BUF_rodata_b:.+]] = vm.const.ref.rodata @rodata_b : !vm.buffer
// CHECK-NEXT: %[[BUF_rodata_b_0:.+]] = vm.const.ref.rodata @rodata_b_0 : !vm.buffer
// CHECK-NEXT: %[[BUF_rodata_c:.+]] = vm.const.ref.rodata @rodata_c : !vm.buffer
// CHECK-NEXT: %[[BUF_rodata_d:.+]] = vm.const.ref.rodata @rodata_d : !vm.buffer
// CHECK-NEXT: %[[BUF_rodata_e_0:.+]] = vm.const.ref.rodata @rodata_e_0 : !vm.buffer
// CHECK-NEXT: vm.rodata private @rodata_b_1 dense<1> : tensor<1xi32>
// CHECK-NEXT: vm.rodata private @rodata_b_0_0 dense<1> : tensor<1xi32>
// CHECK-NEXT: vm.rodata private @rodata_d_0 dense<1> : tensor<1xi32>
// CHECK-NEXT: vm.rodata public @rodata_e dense<1> : tensor<1xi32>
// CHECK-NEXT: vm.rodata public @rodata_f dense<1> : tensor<1xi32>
// CHECK-NEXT: %[[BUF_rodata_b_1:.+]] = vm.const.ref.rodata @rodata_b_1 : !vm.buffer
// CHECK-NEXT: %[[BUF_rodata_b_0_0:.+]] = vm.const.ref.rodata @rodata_b_0_0 : !vm.buffer
// CHECK-NEXT: %[[BUF_rodata_d_0:.+]] = vm.const.ref.rodata @rodata_d_0 : !vm.buffer
// CHECK-NEXT: %[[BUF_rodata_e:.+]] = vm.const.ref.rodata @rodata_e : !vm.buffer
// CHECK-NEXT: %[[BUF_rodata_f:.+]] = vm.const.ref.rodata @rodata_f : !vm.buffer