blob: 4d00ac67f4847888123e78f785f0d76421dfea69 [file]
// RUN: iree-opt --split-input-file --iree-hal-initialize-devices --cse %s | FileCheck %s
// Tests that #hal.device.ordinal<*> gets the device with the given ordinal.
// CHECK: util.global private @device_123 : !hal.device
util.global private @device_123 = #hal.device.ordinal<123> : !hal.device
// CHECK-NEXT: util.initializer
// CHECK-DAG: %[[DEVICE:.+]] = hal.devices.get %c123
// CHECK-DAG: %[[NULL_DEVICE:.+]] = util.null : !hal.device
// CHECK-DAG: %[[IS_NULL:.+]] = util.cmp.eq %[[DEVICE]], %[[NULL_DEVICE]]
// CHECK-NEXT: scf.if %[[IS_NULL]] {
// CHECK: util.status.check_ok %c18_i32, "HAL device `device_123` not found or unavailable: #hal.device.ordinal<123>"
// CHECK: util.global.store %[[DEVICE]], @device_123
// -----
// Tests that #hal.device.fallback<*> references the specified device global.
util.global private @device_base : !hal.device
// CHECK: util.global private @device_fallback : !hal.device
util.global private @device_fallback = #hal.device.fallback<@device_base> : !hal.device
// CHECK-NEXT: util.initializer
// CHECK-DAG: %[[DEVICE:.+]] = util.global.load @device_base : !hal.device
// CHECK-DAG: %[[IS_NULL:.+]] = util.cmp.eq %[[DEVICE]], %{{.+}}
// CHECK-NEXT: scf.if %[[IS_NULL]] {
// CHECK: util.status.check_ok %c18_i32, "HAL device `device_fallback` not found or unavailable: #hal.device.fallback<@device_base>"
// CHECK: util.global.store %[[DEVICE]], @device_fallback
// -----
// Tests that #hal.device.target<*> enumerates all devices and tries to match
// a particular target with the given ordinal. The ordinal allows for multiple
// devices of the same type to be differentiated.
// CHECK: util.global private @device_a : !hal.device
util.global private @device_a = #hal.device.target<"a", {
ordinal = 2 : index
}, [
#hal.executable.target<"backend0", "format0">,
#hal.executable.target<"backend1", "format1">
]> : !hal.device
// CHECK-NEXT: util.initializer
// CHECK-DAG: %[[NULL_DEVICE:.+]] = util.null : !hal.device
// CHECK-DAG: %[[DEVICE_COUNT:.+]] = hal.devices.count
// CHECK: %[[WHILE:.+]]:3 = scf.while (%arg0 = %c0, %arg1 = %c0, %arg2 = %[[NULL_DEVICE]])
// CHECK-DAG: %[[IS_DEVICE_NULL:.+]] = util.cmp.eq %arg2, %[[NULL_DEVICE]]
// CHECK-DAG: %[[IS_END:.+]] = arith.cmpi slt, %arg0, %[[DEVICE_COUNT]]
// CHECK-DAG: %[[CONTINUE:.+]] = arith.andi %[[IS_DEVICE_NULL]], %[[IS_END]]
// CHECK-NEXT: scf.condition(%[[CONTINUE]]) %arg0, %arg1, %arg2
// CHECK-NEXT: } do {
// CHECK-NEXT: ^bb0(%arg0: index, %arg1: index, %arg2: !hal.device)
// CHECK-DAG: %[[DEVICE_N:.+]] = hal.devices.get %arg0 : !hal.device
// NOTE: this is the fallback path for device matching unregistered targets.
// Real targets can have much more complex logic if they so choose.
// CHECK-DAG: %{{.+}}, %[[ID_MATCH:.+]] = hal.device.query<%[[DEVICE_N]] : !hal.device> key("hal.device.id" :: "a")
// CHECK-NEXT: %[[IS_DEVICE_MATCH:.+]] = scf.if %[[ID_MATCH]] -> (i1) {
// CHECK-DAG: %{{.+}}, %[[FORMAT0_MATCH:.+]] = hal.device.query<%[[DEVICE_N]] : !hal.device> key("hal.executable.format" :: "format0")
// CHECK-DAG: %{{.+}}, %[[FORMAT1_MATCH:.+]] = hal.device.query<%[[DEVICE_N]] : !hal.device> key("hal.executable.format" :: "format1")
// CHECK-DAG: %[[FORMAT_MATCH_OR:.+]] = arith.ori %[[FORMAT0_MATCH]], %[[FORMAT1_MATCH]]
// CHECK-DAG: scf.yield %[[FORMAT_MATCH_OR]]
// CHECK-NEXT: } else {
// CHECK-DAG: scf.yield %false
// Check that if the device matches this is the ordinal selected. If not the
// correct ordinal we'll skip it and continue to look for the next.
// CHECK-DAG: %[[IS_ORDINAL_MATCH:.+]] = arith.cmpi eq, %arg1, %c2
// CHECK-DAG: %[[NEXT_MATCH_ADVANCE:.+]] = arith.select %[[IS_DEVICE_MATCH]], %c1, %c0
// CHECK-DAG: %[[NEXT_MATCH_ORDINAL:.+]] = arith.addi %arg1, %[[NEXT_MATCH_ADVANCE]]
// CHECK-DAG: %[[IS_MATCH:.+]] = arith.andi %[[IS_DEVICE_MATCH]], %[[IS_ORDINAL_MATCH]]
// CHECK-DAG: %[[YIELD_DEVICE:.+]] = arith.select %[[IS_MATCH]], %[[DEVICE_N]], %[[NULL_DEVICE]]
// CHECK-DAG: %[[NEXT_I:.+]] = arith.addi %arg0, %c1
// CHECK-NEXT: scf.yield %[[NEXT_I]], %[[NEXT_MATCH_ORDINAL]], %[[YIELD_DEVICE]]
// Error out if no device was found because at least one match is required.
// CHECK-DAG: %[[IS_NULL:.+]] = util.cmp.eq %[[WHILE]]#2, %[[NULL_DEVICE]]
// CHECK-NEXT: scf.if %[[IS_NULL]] {
// CHECK: util.status.check_ok %c18_i32, "HAL device `device_a` not found or unavailable: #hal.device.target<{{.+}}>"
// CHECK: util.global.store %[[WHILE]]#2, @device_a
// -----
// Tests that #hal.device.select<*> expands to a chain of ifs.
util.global private @fallback : !hal.device
// CHECK: util.global private @selected : !hal.device
util.global private @selected = #hal.device.select<[
#hal.device.ordinal<2> : !hal.device,
#hal.device.ordinal<1> : !hal.device,
#hal.device.fallback<@fallback> : !hal.device
]> : !hal.device
// CHECK-NEXT: util.initializer
// CHECK-DAG: %[[NULL_DEVICE:.+]] = util.null : !hal.device
// CHECK-DAG: %[[DEVICE_2:.+]] = hal.devices.get %c2
// CHECK-DAG: %[[NOT_DEVICE_2:.+]] = util.cmp.eq %[[DEVICE_2]], %[[NULL_DEVICE]]
// CHECK-NEXT: %[[IF_0:.+]] = scf.if %[[NOT_DEVICE_2]]
// CHECK-DAG: %[[DEVICE_1:.+]] = hal.devices.get %c1
// CHECK-DAG: %[[NOT_DEVICE_1:.+]] = util.cmp.eq %[[DEVICE_1]], %[[NULL_DEVICE]]
// CHECK-NEXT: %[[IF_1:.+]] = scf.if %[[NOT_DEVICE_1]]
// CHECK-DAG: %[[DEVICE_FALLBACK:.+]] = util.global.load @fallback
// CHECK-NEXT: scf.yield %[[DEVICE_FALLBACK]]
// CHECK-NEXT: } else {
// CHECK-NEXT: scf.yield %[[DEVICE_1]]
// CHECK-NEXT: }
// CHECK-NEXT: scf.yield %[[IF_1]]
// CHECK-NEXT: } else {
// CHECK-NEXT: scf.yield %[[DEVICE_2]]
// CHECK-NEXT: }
// CHECK-DAG: %[[IS_NULL:.+]] = util.cmp.eq %[[IF_0]], %[[NULL_DEVICE]]
// CHECK-NEXT: scf.if %[[IS_NULL]] {
// CHECK: util.status.check_ok %c18_i32, "HAL device `selected` not found or unavailable: #hal.device.select<{{.+}}>"
// CHECK: util.global.store %[[IF_0]], @selected