<commit_before>// Copyright 2020 The IREE Authors
//
// Licensed under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

#include "iree/vm/list.h"

#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <string.h>

#include "iree/base/tracing.h"

// Size of each iree_vm_value_type_t in bytes.
static const iree_host_size_t kValueTypeSizes[7] = {
    0,  // IREE_VM_VALUE_TYPE_NONE
    1,  // IREE_VM_VALUE_TYPE_I8
    2,  // IREE_VM_VALUE_TYPE_I16
    4,  // IREE_VM_VALUE_TYPE_I32
    8,  // IREE_VM_VALUE_TYPE_I64
    4,  // IREE_VM_VALUE_TYPE_F32
    8,  // IREE_VM_VALUE_TYPE_F64
};
static_assert(IREE_VM_VALUE_TYPE_COUNT ==
                  (sizeof(kValueTypeSizes) / sizeof(kValueTypeSizes[0])),
              "Enum mismatch");

// Defines how the iree_vm_list_t storage is allocated and what elements are
// interpreted as.
typedef enum iree_vm_list_storage_mode_e {
  // Each element is a primitive value and stored as a dense array.
  IREE_VM_LIST_STORAGE_MODE_VALUE = 0,
  // Each element is an iree_vm_ref_t of some type.
  IREE_VM_LIST_STORAGE_MODE_REF,
  // Each element is a variant of any type (possibly all different).
  IREE_VM_LIST_STORAGE_MODE_VARIANT,
} iree_vm_list_storage_mode_t;

// A list able to hold either flat primitive elements or ref values.
struct iree_vm_list_t {
  iree_vm_ref_object_t ref_object;
  iree_allocator_t allocator;

  // Current capacity of the list storage, in elements.
  iree_host_size_t capacity;
  // Current count of elements in the list.
  iree_host_size_t count;

  // Element type stored within the list.
  iree_vm_type_def_t element_type;
  // Size of each element in the storage in bytes.
  iree_host_size_t element_size;

  // Storage mode defining how the storage array is managed.
  iree_vm_list_storage_mode_t storage_mode;
  // A flat dense array of elements in the type defined by storage_mode.
  // For certain storage modes, such as IREE_VM_STORAGE_MODE_REF, special
  // lifetime management and cleanup logic is required.
  void* storage;
};

static iree_vm_ref_type_descriptor_t iree_vm_list_descriptor = {0};

IREE_VM_DEFINE_TYPE_ADAPTERS(iree_vm_list, iree_vm_list_t);

static void iree_vm_list_reset_range(iree_vm_list_t* list,
                                     iree_host_size_t offset,
                                     iree_host_size_t length) {
  switch (list->storage_mode) {
    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 < 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 < 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;
    }
  }
}

IREE_API_EXPORT iree_host_size_t iree_vm_list_storage_size(
    const iree_vm_type_def_t* element_type, iree_host_size_t capacity) {
  iree_host_size_t element_size = sizeof(iree_vm_variant_t);
  if (element_type) {
    if (iree_vm_type_def_is_value(element_type)) {
      element_size = kValueTypeSizes[element_type->value_type];
    } else if (iree_vm_type_def_is_ref(element_type)) {
      element_size = sizeof(iree_vm_ref_t);
    } else {
      element_size = sizeof(iree_vm_variant_t);
    }
  }
  return iree_host_align(sizeof(iree_vm_list_t), 8) +
         iree_host_align(capacity * element_size, 8);
}

IREE_API_EXPORT iree_status_t iree_vm_list_initialize(
    iree_byte_span_t storage, const iree_vm_type_def_t* element_type,
    iree_host_size_t capacity, iree_vm_list_t** out_list) {
  IREE_TRACE_ZONE_BEGIN(z0);

  iree_vm_list_storage_mode_t storage_mode = IREE_VM_LIST_STORAGE_MODE_VARIANT;
  iree_host_size_t element_size = sizeof(iree_vm_variant_t);
  if (element_type) {
    if (iree_vm_type_def_is_value(element_type)) {
      storage_mode = IREE_VM_LIST_STORAGE_MODE_VALUE;
      element_size = kValueTypeSizes[element_type->value_type];
    } else if (iree_vm_type_def_is_ref(element_type)) {
      storage_mode = IREE_VM_LIST_STORAGE_MODE_REF;
      element_size = sizeof(iree_vm_ref_t);
    } else {
      storage_mode = IREE_VM_LIST_STORAGE_MODE_VARIANT;
      element_size = sizeof(iree_vm_variant_t);
    }
  }

  iree_host_size_t storage_offset = iree_host_align(sizeof(iree_vm_list_t), 8);
  iree_host_size_t required_storage_size =
      storage_offset + iree_host_align(capacity * element_size, 8);
  if (storage.data_length < required_storage_size) {
    return iree_make_status(
        IREE_STATUS_OUT_OF_RANGE,
        "storage buffer underflow: provided=%zu < required=%zu",
        storage.data_length, required_storage_size);
  }
  memset(storage.data, 0, required_storage_size);

  iree_vm_list_t* list = (iree_vm_list_t*)storage.data;
  iree_atomic_ref_count_init(&list->ref_object.counter);
  if (element_type) {
    list->element_type = *element_type;
  }
  list->element_size = element_size;
  list->storage_mode = storage_mode;
  list->capacity = capacity;
  list->storage = storage.data + storage_offset;

  *out_list = list;
  IREE_TRACE_ZONE_END(z0);
  return iree_ok_status();
}

IREE_API_EXPORT void iree_vm_list_deinitialize(iree_vm_list_t* list) {
  IREE_ASSERT_ARGUMENT(list);
  IREE_TRACE_ZONE_BEGIN(z0);

  iree_atomic_ref_count_abort_if_uses(&list->ref_object.counter);
  iree_vm_list_reset_range(list, 0, list->count);
  list->count = 0;

  IREE_TRACE_ZONE_END(z0);
}

IREE_API_EXPORT iree_status_t iree_vm_list_create(
    const iree_vm_type_def_t* element_type, iree_host_size_t initial_capacity,
    iree_allocator_t allocator, iree_vm_list_t** out_list) {
  IREE_ASSERT_ARGUMENT(out_list);
  IREE_TRACE_ZONE_BEGIN(z0);

  iree_vm_list_t* list = NULL;
  IREE_RETURN_AND_END_ZONE_IF_ERROR(
      z0, iree_allocator_malloc(allocator, sizeof(*list), (void**)&list));
  memset(list, 0, sizeof(*list));
  iree_atomic_ref_count_init(&list->ref_object.counter);
  list->allocator = allocator;
  if (element_type) {
    list->element_type = *element_type;
  }

  if (iree_vm_type_def_is_value(&list->element_type) && element_type) {
    list->storage_mode = IREE_VM_LIST_STORAGE_MODE_VALUE;
    list->element_size = kValueTypeSizes[element_type->value_type];
  } else if (iree_vm_type_def_is_ref(&list->element_type)) {
    list->storage_mode = IREE_VM_LIST_STORAGE_MODE_REF;
    list->element_size = sizeof(iree_vm_ref_t);
  } else {
    list->storage_mode = IREE_VM_LIST_STORAGE_MODE_VARIANT;
    list->element_size = sizeof(iree_vm_variant_t);
  }

  iree_status_t status = iree_vm_list_reserve(list, initial_capacity);

  if (iree_status_is_ok(status)) {
    *out_list = list;
  } else {
    iree_allocator_free(allocator, list);
  }
  IREE_TRACE_ZONE_END(z0);
  return status;
}

static void iree_vm_list_destroy(void* ptr) {
  IREE_TRACE_ZONE_BEGIN(z0);
<commit_msg>Shrink iree_vm_value_type_t -> size table from 56B to 4B.<commit_after>// Copyright 2020 The IREE Authors
//
// Licensed under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

#include "iree/vm/list.h"

#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <string.h>

#include "iree/base/tracing.h"

static uint8_t iree_vm_value_type_size(iree_vm_value_type_t type) {
  // Size of each iree_vm_value_type_t in bytes. We bitpack these so that we
  // can do a simple shift and mask to get the size.
  const uint32_t kValueTypeSizes = (0u << 0) |   // IREE_VM_VALUE_TYPE_NONE
                                   (1u << 4) |   // IREE_VM_VALUE_TYPE_I8
                                   (2u << 8) |   // IREE_VM_VALUE_TYPE_I16
                                   (4u << 12) |  // IREE_VM_VALUE_TYPE_I32
                                   (8u << 16) |  // IREE_VM_VALUE_TYPE_I64
                                   (4u << 20) |  // IREE_VM_VALUE_TYPE_F32
                                   (8u << 24) |  // IREE_VM_VALUE_TYPE_F64
                                   (0u << 28);   // unused
  return (kValueTypeSizes >> ((type & 0x7) * 4)) & 0xF;
}

// Defines how the iree_vm_list_t storage is allocated and what elements are
// interpreted as.
typedef enum iree_vm_list_storage_mode_e {
  // Each element is a primitive value and stored as a dense array.
  IREE_VM_LIST_STORAGE_MODE_VALUE = 0,
  // Each element is an iree_vm_ref_t of some type.
  IREE_VM_LIST_STORAGE_MODE_REF,
  // Each element is a variant of any type (possibly all different).
  IREE_VM_LIST_STORAGE_MODE_VARIANT,
} iree_vm_list_storage_mode_t;

// A list able to hold either flat primitive elements or ref values.
struct iree_vm_list_t {
  iree_vm_ref_object_t ref_object;
  iree_allocator_t allocator;

  // Current capacity of the list storage, in elements.
  iree_host_size_t capacity;
  // Current count of elements in the list.
  iree_host_size_t count;

  // Element type stored within the list.
  iree_vm_type_def_t element_type;
  // Size of each element in the storage in bytes.
  iree_host_size_t element_size;

  // Storage mode defining how the storage array is managed.
  iree_vm_list_storage_mode_t storage_mode;
  // A flat dense array of elements in the type defined by storage_mode.
  // For certain storage modes, such as IREE_VM_STORAGE_MODE_REF, special
  // lifetime management and cleanup logic is required.
  void* storage;
};

static iree_vm_ref_type_descriptor_t iree_vm_list_descriptor = {0};

IREE_VM_DEFINE_TYPE_ADAPTERS(iree_vm_list, iree_vm_list_t);

static void iree_vm_list_reset_range(iree_vm_list_t* list,
                                     iree_host_size_t offset,
                                     iree_host_size_t length) {
  switch (list->storage_mode) {
    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 < 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 < 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;
    }
  }
}

IREE_API_EXPORT iree_host_size_t iree_vm_list_storage_size(
    const iree_vm_type_def_t* element_type, iree_host_size_t capacity) {
  iree_host_size_t element_size = sizeof(iree_vm_variant_t);
  if (element_type) {
    if (iree_vm_type_def_is_value(element_type)) {
      element_size = iree_vm_value_type_size(element_type->value_type);
    } else if (iree_vm_type_def_is_ref(element_type)) {
      element_size = sizeof(iree_vm_ref_t);
    } else {
      element_size = sizeof(iree_vm_variant_t);
    }
  }
  return iree_host_align(sizeof(iree_vm_list_t), 8) +
         iree_host_align(capacity * element_size, 8);
}

IREE_API_EXPORT iree_status_t iree_vm_list_initialize(
    iree_byte_span_t storage, const iree_vm_type_def_t* element_type,
    iree_host_size_t capacity, iree_vm_list_t** out_list) {
  IREE_TRACE_ZONE_BEGIN(z0);

  iree_vm_list_storage_mode_t storage_mode = IREE_VM_LIST_STORAGE_MODE_VARIANT;
  iree_host_size_t element_size = sizeof(iree_vm_variant_t);
  if (element_type) {
    if (iree_vm_type_def_is_value(element_type)) {
      storage_mode = IREE_VM_LIST_STORAGE_MODE_VALUE;
      element_size = iree_vm_value_type_size(element_type->value_type);
    } else if (iree_vm_type_def_is_ref(element_type)) {
      storage_mode = IREE_VM_LIST_STORAGE_MODE_REF;
      element_size = sizeof(iree_vm_ref_t);
    } else {
      storage_mode = IREE_VM_LIST_STORAGE_MODE_VARIANT;
      element_size = sizeof(iree_vm_variant_t);
    }
  }

  iree_host_size_t storage_offset = iree_host_align(sizeof(iree_vm_list_t), 8);
  iree_host_size_t required_storage_size =
      storage_offset + iree_host_align(capacity * element_size, 8);
  if (storage.data_length < required_storage_size) {
    return iree_make_status(
        IREE_STATUS_OUT_OF_RANGE,
        "storage buffer underflow: provided=%zu < required=%zu",
        storage.data_length, required_storage_size);
  }
  memset(storage.data, 0, required_storage_size);

  iree_vm_list_t* list = (iree_vm_list_t*)storage.data;
  iree_atomic_ref_count_init(&list->ref_object.counter);
  if (element_type) {
    list->element_type = *element_type;
  }
  list->element_size = element_size;
  list->storage_mode = storage_mode;
  list->capacity = capacity;
  list->storage = storage.data + storage_offset;

  *out_list = list;
  IREE_TRACE_ZONE_END(z0);
  return iree_ok_status();
}

IREE_API_EXPORT void iree_vm_list_deinitialize(iree_vm_list_t* list) {
  IREE_ASSERT_ARGUMENT(list);
  IREE_TRACE_ZONE_BEGIN(z0);

  iree_atomic_ref_count_abort_if_uses(&list->ref_object.counter);
  iree_vm_list_reset_range(list, 0, list->count);
  list->count = 0;

  IREE_TRACE_ZONE_END(z0);
}

IREE_API_EXPORT iree_status_t iree_vm_list_create(
    const iree_vm_type_def_t* element_type, iree_host_size_t initial_capacity,
    iree_allocator_t allocator, iree_vm_list_t** out_list) {
  IREE_ASSERT_ARGUMENT(out_list);
  IREE_TRACE_ZONE_BEGIN(z0);

  iree_vm_list_t* list = NULL;
  IREE_RETURN_AND_END_ZONE_IF_ERROR(
      z0, iree_allocator_malloc(allocator, sizeof(*list), (void**)&list));
  memset(list, 0, sizeof(*list));
  iree_atomic_ref_count_init(&list->ref_object.counter);
  list->allocator = allocator;
  if (element_type) {
    list->element_type = *element_type;
  }

  if (iree_vm_type_def_is_value(&list->element_type) && element_type) {
    list->storage_mode = IREE_VM_LIST_STORAGE_MODE_VALUE;
    list->element_size = iree_vm_value_type_size(element_type->value_type);
  } else if (iree_vm_type_def_is_ref(&list->element_type)) {
    list->storage_mode = IREE_VM_LIST_STORAGE_MODE_REF;
    list->element_size = sizeof(iree_vm_ref_t);
  } else {
    list->storage_mode = IREE_VM_LIST_STORAGE_MODE_VARIANT;
    list->element_size = sizeof(iree_vm_variant_t);
  }

  iree_status_t status = iree_vm_list_reserve(list, initial_capacity);

  if (iree_status_is_ok(status)) {
    *out_list = list;
  } else {
    iree_allocator_free(allocator, list);
  }
  IREE_TRACE_ZONE_END(z0);
  return status;
}

static void iree_vm_list_destroy(void* ptr) {
  IREE_TRACE_ZONE_BEGIN(z0);

{'fraction_non_alphanumeric': 0.09222891956704907, 'fraction_numerical': 0.0077775617343962666, 'mean_word_length': 3.918712145361811, 'pattern_counts': {'":': 0, '<': 35, '<?xml version=': 0, '>': 72, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 11, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3165141', 'n_tokens_mistral': 5953, 'n_tokens_neox': 5841, 'n_words': 1000}