Making iree_vm_list_resize work and switching ref cconv behavior (#4858)
The new C HAL module was the first user of this function - now there
are tests. The new shims also assumed that arguments were not retained
(as doing so requires cleanup) but the dispatch code was double-retaining
them. I'm surprised things worked as well as they did like that o_o
Fixes #4852.
diff --git a/iree/base/CMakeLists.txt b/iree/base/CMakeLists.txt
index a01db40..048bf22 100644
--- a/iree/base/CMakeLists.txt
+++ b/iree/base/CMakeLists.txt
@@ -266,8 +266,7 @@
DEPS
::core_headers
DEFINES
- # TODO(#2114): Change the mode to 2.
- "IREE_TRACING_MODE=1"
+ "IREE_TRACING_MODE=2"
PUBLIC
)
else()
diff --git a/iree/hal/local/arena.c b/iree/hal/local/arena.c
index 7b9529a..dabc746 100644
--- a/iree/hal/local/arena.c
+++ b/iree/hal/local/arena.c
@@ -52,6 +52,8 @@
iree_status_t iree_arena_block_pool_acquire(iree_arena_block_pool_t* block_pool,
iree_arena_block_t** out_block) {
+ IREE_TRACE_ZONE_BEGIN(z0);
+
iree_arena_block_t* block =
iree_atomic_arena_block_slist_pop(&block_pool->available_slist);
@@ -63,23 +65,28 @@
// that's fine - it's just one block and the contention means there's likely
// to be a need for more anyway.
uint8_t* block_base = NULL;
- IREE_RETURN_IF_ERROR(iree_allocator_malloc(block_pool->block_allocator,
- block_pool->total_block_size,
- (void**)&block_base));
+ IREE_RETURN_AND_END_ZONE_IF_ERROR(
+ z0, iree_allocator_malloc(block_pool->block_allocator,
+ block_pool->total_block_size,
+ (void**)&block_base));
block = (iree_arena_block_t*)(block_base + (block_pool->total_block_size -
sizeof(iree_arena_block_t)));
}
block->next = NULL;
*out_block = block;
+
+ IREE_TRACE_ZONE_END(z0);
return iree_ok_status();
}
void iree_arena_block_pool_release(iree_arena_block_pool_t* block_pool,
iree_arena_block_t* block_head,
iree_arena_block_t* block_tail) {
+ IREE_TRACE_ZONE_BEGIN(z0);
iree_atomic_arena_block_slist_concat(&block_pool->available_slist, block_head,
block_tail);
+ IREE_TRACE_ZONE_END(z0);
}
//===----------------------------------------------------------------------===//
diff --git a/iree/modules/hal/hal_module.c b/iree/modules/hal/hal_module.c
index 06c0baf..02f31fe 100644
--- a/iree/modules/hal/hal_module.c
+++ b/iree/modules/hal/hal_module.c
@@ -226,8 +226,8 @@
// Block and wait for the semaphore to be signaled (or fail).
status = iree_hal_semaphore_wait_with_deadline(semaphore, 1ull,
IREE_TIME_INFINITE_FUTURE);
+ iree_hal_semaphore_release(semaphore);
if (!iree_status_is_ok(status)) {
- iree_hal_semaphore_release(semaphore);
return status;
}
diff --git a/iree/tools/iree-benchmark-module-main.cc b/iree/tools/iree-benchmark-module-main.cc
index 0bc1825..b567c1d 100644
--- a/iree/tools/iree-benchmark-module-main.cc
+++ b/iree/tools/iree-benchmark-module-main.cc
@@ -125,21 +125,17 @@
// benchmarking.
class IREEBenchmark {
public:
- IREEBenchmark()
- : instance_(nullptr),
- device_(nullptr),
- hal_module_(nullptr),
- context_(nullptr),
- input_module_(nullptr){};
+ IREEBenchmark() = default;
+
~IREEBenchmark() {
IREE_TRACE_SCOPE0("IREEBenchmark::dtor");
// Order matters.
inputs_.reset();
+ iree_vm_context_release(context_);
iree_vm_module_release(hal_module_);
iree_vm_module_release(input_module_);
iree_hal_device_release(device_);
- iree_vm_context_release(context_);
iree_vm_instance_release(instance_);
};
@@ -247,11 +243,11 @@
}
std::string module_data_;
- iree_vm_instance_t* instance_;
- iree_hal_device_t* device_;
- iree_vm_module_t* hal_module_;
- iree_vm_context_t* context_;
- iree_vm_module_t* input_module_;
+ iree_vm_instance_t* instance_ = nullptr;
+ iree_hal_device_t* device_ = nullptr;
+ iree_vm_module_t* hal_module_ = nullptr;
+ iree_vm_context_t* context_ = nullptr;
+ iree_vm_module_t* input_module_ = nullptr;
iree::vm::ref<iree_vm_list_t> inputs_;
};
} // namespace
diff --git a/iree/vm/bytecode_dispatch.c b/iree/vm/bytecode_dispatch.c
index 86c6509..96292a0 100644
--- a/iree/vm/bytecode_dispatch.c
+++ b/iree/vm/bytecode_dispatch.c
@@ -402,8 +402,7 @@
} break;
case IREE_VM_CCONV_TYPE_REF: {
uint16_t src_reg = src_reg_list->registers[reg_i++];
- iree_vm_ref_retain_or_move(
- src_reg & IREE_REF_REGISTER_MOVE_BIT,
+ iree_vm_ref_assign(
&caller_registers.ref[src_reg & caller_registers.ref_mask],
(iree_vm_ref_t*)p);
p += sizeof(iree_vm_ref_t);
@@ -447,8 +446,7 @@
} break;
case IREE_VM_CCONV_TYPE_REF: {
uint16_t src_reg = src_reg_list->registers[reg_i++];
- iree_vm_ref_retain_or_move(
- src_reg & IREE_REF_REGISTER_MOVE_BIT,
+ iree_vm_ref_assign(
&caller_registers.ref[src_reg & caller_registers.ref_mask],
(iree_vm_ref_t*)p);
p += sizeof(iree_vm_ref_t);
diff --git a/iree/vm/list.c b/iree/vm/list.c
index 64fbdc8..24e3158 100644
--- a/iree/vm/list.c
+++ b/iree/vm/list.c
@@ -70,21 +70,27 @@
iree_host_size_t offset,
iree_host_size_t length) {
switch (list->storage_mode) {
- case IREE_VM_LIST_STORAGE_MODE_VALUE:
- // Nothing special, freeing the storage is all we need.
+ case IREE_VM_LIST_STORAGE_MODE_VALUE: {
+ void* base_ptr =
+ (void*)((uintptr_t)list->storage + offset * list->element_size);
+ memset(base_ptr, 0, length * list->element_size);
break;
+ }
case IREE_VM_LIST_STORAGE_MODE_REF: {
iree_vm_ref_t* ref_storage = (iree_vm_ref_t*)list->storage;
- for (iree_host_size_t i = offset; i < length; ++i) {
+ for (iree_host_size_t i = offset; i < offset + length; ++i) {
iree_vm_ref_release(&ref_storage[i]);
}
break;
}
case IREE_VM_LIST_STORAGE_MODE_VARIANT: {
iree_vm_variant_t* variant_storage = (iree_vm_variant_t*)list->storage;
- for (iree_host_size_t i = offset; i < length; ++i) {
+ for (iree_host_size_t i = offset; i < offset + length; ++i) {
if (iree_vm_type_def_is_ref(&variant_storage[i].type)) {
iree_vm_ref_release(&variant_storage[i].ref);
+ memset(&variant_storage[i].type, 0, sizeof(variant_storage[i].type));
+ } else {
+ memset(&variant_storage[i], 0, sizeof(variant_storage[i]));
}
}
break;
@@ -243,7 +249,7 @@
return iree_ok_status();
} else if (new_size < list->count) {
// Truncating.
- iree_vm_list_reset_range(list, new_size + 1, list->count - new_size);
+ iree_vm_list_reset_range(list, new_size, list->count - new_size);
list->count = new_size;
} else if (new_size > list->capacity) {
// Extending beyond capacity.
diff --git a/iree/vm/list_test.cc b/iree/vm/list_test.cc
index 4423cbc..3bad3ac 100644
--- a/iree/vm/list_test.cc
+++ b/iree/vm/list_test.cc
@@ -229,11 +229,161 @@
iree_vm_list_release(list);
}
-// TODO(benvanik): test resize value.
+// Tests the behavior of resize for truncation and extension on primitives.
+TEST_F(VMListTest, ResizeI32) {
+ iree_vm_type_def_t element_type =
+ iree_vm_type_def_make_value_type(IREE_VM_VALUE_TYPE_I32);
+ iree_host_size_t initial_capacity = 4;
+ iree_vm_list_t* list = nullptr;
+ IREE_ASSERT_OK(iree_vm_list_create(&element_type, initial_capacity,
+ iree_allocator_system(), &list));
+ EXPECT_LE(initial_capacity, iree_vm_list_capacity(list));
+ EXPECT_EQ(0, iree_vm_list_size(list));
-// TODO(benvanik): test resize ref.
+ // Extend and zero-initialize.
+ IREE_ASSERT_OK(iree_vm_list_resize(list, 5));
+ for (iree_host_size_t i = 0; i < 5; ++i) {
+ iree_vm_value_t value;
+ IREE_ASSERT_OK(
+ iree_vm_list_get_value_as(list, i, IREE_VM_VALUE_TYPE_I32, &value));
+ EXPECT_EQ(0, value.i32);
+ }
-// TODO(benvanik): test resize variant.
+ // Overwrite with [0, 5).
+ for (iree_host_size_t i = 0; i < 5; ++i) {
+ iree_vm_value_t value = iree_vm_value_make_i32((int32_t)i);
+ IREE_ASSERT_OK(iree_vm_list_set_value(list, i, &value));
+ }
+
+ // Truncate to [0, 2) and then extend again.
+ // This ensures that we test the primitive clearing path during cleanup:
+ // [int, int, int, int, int]
+ // |___________| <- truncation region
+ IREE_ASSERT_OK(iree_vm_list_resize(list, 2));
+ IREE_ASSERT_OK(iree_vm_list_resize(list, 5));
+
+ // Ensure that elements 2+ are zeroed after having been reset while 0 and 1
+ // are still valid as before.
+ for (iree_host_size_t i = 0; i < 2; ++i) {
+ iree_vm_value_t value;
+ IREE_ASSERT_OK(
+ iree_vm_list_get_value_as(list, i, IREE_VM_VALUE_TYPE_I32, &value));
+ EXPECT_EQ(i, value.i32);
+ }
+ for (iree_host_size_t i = 2; i < 5; ++i) {
+ iree_vm_value_t value;
+ IREE_ASSERT_OK(
+ iree_vm_list_get_value_as(list, i, IREE_VM_VALUE_TYPE_I32, &value));
+ EXPECT_EQ(0, value.i32);
+ }
+
+ iree_vm_list_release(list);
+}
+
+// Tests the behavior of resize for truncation and extension on refs.
+TEST_F(VMListTest, ResizeRef) {
+ iree_vm_type_def_t element_type =
+ iree_vm_type_def_make_ref_type(test_a_type_id());
+ iree_host_size_t initial_capacity = 4;
+ iree_vm_list_t* list = nullptr;
+ IREE_ASSERT_OK(iree_vm_list_create(&element_type, initial_capacity,
+ iree_allocator_system(), &list));
+ EXPECT_LE(initial_capacity, iree_vm_list_capacity(list));
+ EXPECT_EQ(0, iree_vm_list_size(list));
+
+ // Extend and zero-initialize.
+ IREE_ASSERT_OK(iree_vm_list_resize(list, 5));
+ for (iree_host_size_t i = 0; i < 5; ++i) {
+ iree_vm_ref_t ref_a{0};
+ IREE_ASSERT_OK(iree_vm_list_get_ref_assign(list, i, &ref_a));
+ EXPECT_TRUE(iree_vm_ref_is_null(&ref_a));
+ }
+
+ // Overwrite with [0, 5).
+ for (iree_host_size_t i = 0; i < 5; ++i) {
+ iree_vm_ref_t ref_a = MakeRef<A>((float)i);
+ IREE_ASSERT_OK(iree_vm_list_set_ref_move(list, i, &ref_a));
+ }
+
+ // Truncate to [0, 2) and then extend again.
+ // This ensures that we test the ref path during cleanup:
+ // [ref, ref, ref, ref, ref]
+ // |___________| <- truncation region
+ IREE_ASSERT_OK(iree_vm_list_resize(list, 2));
+ IREE_ASSERT_OK(iree_vm_list_resize(list, 5));
+
+ // Ensure that elements 2+ are reset after having been reset while 0 and 1
+ // are still valid as before.
+ for (iree_host_size_t i = 0; i < 2; ++i) {
+ iree_vm_ref_t ref_a{0};
+ IREE_ASSERT_OK(iree_vm_list_get_ref_retain(list, i, &ref_a));
+ EXPECT_TRUE(test_a_isa(ref_a));
+ auto* a = test_a_deref(ref_a);
+ EXPECT_EQ(i, a->data());
+ iree_vm_ref_release(&ref_a);
+ }
+ for (iree_host_size_t i = 2; i < 5; ++i) {
+ iree_vm_ref_t ref_a{0};
+ IREE_ASSERT_OK(iree_vm_list_get_ref_assign(list, i, &ref_a));
+ EXPECT_TRUE(iree_vm_ref_is_null(&ref_a));
+ }
+
+ iree_vm_list_release(list);
+}
+
+// Tests the behavior of resize for truncation and extension on variants.
+TEST_F(VMListTest, ResizeVariant) {
+ iree_vm_type_def_t element_type = iree_vm_type_def_make_variant_type();
+ iree_host_size_t initial_capacity = 4;
+ iree_vm_list_t* list = nullptr;
+ IREE_ASSERT_OK(iree_vm_list_create(&element_type, initial_capacity,
+ iree_allocator_system(), &list));
+ EXPECT_LE(initial_capacity, iree_vm_list_capacity(list));
+ EXPECT_EQ(0, iree_vm_list_size(list));
+
+ // Extend and zero-initialize.
+ IREE_ASSERT_OK(iree_vm_list_resize(list, 5));
+ for (iree_host_size_t i = 0; i < 5; ++i) {
+ iree_vm_variant_t value = iree_vm_variant_empty();
+ IREE_ASSERT_OK(iree_vm_list_get_variant(list, i, &value));
+ EXPECT_TRUE(iree_vm_variant_is_empty(value));
+ }
+
+ // Overwrite with [0, 5) in mixed types.
+ for (iree_host_size_t i = 0; i < 4; ++i) {
+ iree_vm_ref_t ref_a = MakeRef<A>((float)i);
+ IREE_ASSERT_OK(iree_vm_list_set_ref_move(list, i, &ref_a));
+ }
+ for (iree_host_size_t i = 4; i < 5; ++i) {
+ iree_vm_value_t value = iree_vm_value_make_i32((int32_t)i);
+ IREE_ASSERT_OK(iree_vm_list_set_value(list, i, &value));
+ }
+
+ // Truncate to [0, 2) and then extend again.
+ // This ensures that we test the variant path during cleanup:
+ // [ref, ref, ref, ref, int]
+ // |___________| <- truncation region
+ IREE_ASSERT_OK(iree_vm_list_resize(list, 2));
+ IREE_ASSERT_OK(iree_vm_list_resize(list, 5));
+
+ // Ensure that elements 2+ are reset after having been reset while 0 and 1
+ // are still valid as before.
+ for (iree_host_size_t i = 0; i < 2; ++i) {
+ iree_vm_ref_t ref_a{0};
+ IREE_ASSERT_OK(iree_vm_list_get_ref_retain(list, i, &ref_a));
+ EXPECT_TRUE(test_a_isa(ref_a));
+ auto* a = test_a_deref(ref_a);
+ EXPECT_EQ(i, a->data());
+ iree_vm_ref_release(&ref_a);
+ }
+ for (iree_host_size_t i = 2; i < 5; ++i) {
+ iree_vm_variant_t value = iree_vm_variant_empty();
+ IREE_ASSERT_OK(iree_vm_list_get_variant(list, i, &value));
+ EXPECT_TRUE(iree_vm_variant_is_empty(value));
+ }
+
+ iree_vm_list_release(list);
+}
// TODO(benvanik): test value get/set.
diff --git a/iree/vm/module.h b/iree/vm/module.h
index d8635e0..8eabc0a 100644
--- a/iree/vm/module.h
+++ b/iree/vm/module.h
@@ -192,9 +192,8 @@
// Argument buffer in the format described above.
// This is only read on beginning the function and need not live beyond that.
//
- // Refs contained will be moved into the target function or released if not
- // needed. Callers must ensure they move or retain arguments when populating
- // the arguments buffer.
+ // Refs contained are retained by the caller and callees must retain them if
+ // they need them to live beyond the call.
iree_byte_span_t arguments;
// Storage for the result buffer; assumed undefined and then populated with
diff --git a/iree/vm/module_abi_packing.h b/iree/vm/module_abi_packing.h
index 0b00b30..d679964 100644
--- a/iree/vm/module_abi_packing.h
+++ b/iree/vm/module_abi_packing.h
@@ -362,7 +362,7 @@
struct ParamUnpack<opaque_ref> {
using storage_type = opaque_ref;
static void Load(Status& status, params_ptr_t& ptr, storage_type& out_param) {
- iree_vm_ref_move(reinterpret_cast<iree_vm_ref_t*>(ptr), &out_param);
+ iree_vm_ref_retain(reinterpret_cast<iree_vm_ref_t*>(ptr), &out_param);
ptr += sizeof(iree_vm_ref_t);
}
};
@@ -376,7 +376,7 @@
auto* reg_ptr = reinterpret_cast<iree_vm_ref_t*>(ptr);
ptr += sizeof(iree_vm_ref_t);
if (reg_ptr->type == ref_type_descriptor<T>::get()->type) {
- out_param = vm::assign_ref(reinterpret_cast<T*>(reg_ptr->ptr));
+ out_param = vm::retain_ref(reinterpret_cast<T*>(reg_ptr->ptr));
memset(reg_ptr, 0, sizeof(*reg_ptr));
} else if (IREE_UNLIKELY(reg_ptr->type != IREE_VM_REF_TYPE_NULL)) {
status =
@@ -401,7 +401,7 @@
auto* reg_ptr = reinterpret_cast<iree_vm_ref_t*>(ptr);
ptr += sizeof(iree_vm_ref_t);
if (reg_ptr->type == ref_type_descriptor<T>::get()->type) {
- out_param = vm::assign_ref(reinterpret_cast<T*>(reg_ptr->ptr));
+ out_param = vm::retain_ref(reinterpret_cast<T*>(reg_ptr->ptr));
memset(reg_ptr, 0, sizeof(*reg_ptr));
} else if (IREE_UNLIKELY(reg_ptr->type != IREE_VM_REF_TYPE_NULL)) {
status =
diff --git a/iree/vm/type_def.h b/iree/vm/type_def.h
index 5592494..c3294d6 100644
--- a/iree/vm/type_def.h
+++ b/iree/vm/type_def.h
@@ -87,6 +87,7 @@
{ {IREE_VM_VALUE_TYPE_NONE, IREE_VM_REF_TYPE_NULL}, {0}, }
#define iree_vm_variant_is_value(v) iree_vm_type_def_is_value(&(v).type)
#define iree_vm_variant_is_ref(v) iree_vm_type_def_is_ref(&(v).type)
+#define iree_vm_variant_is_empty(v) iree_vm_type_def_is_variant(&(v).type)
#ifdef __cplusplus
} // extern "C"