예제 #1
0
static bool check_tuple(compile_t* c, LLVMValueRef ptr, LLVMValueRef desc,
  ast_t* pattern_type, LLVMBasicBlockRef next_block)
{
  // First check cardinality.
  size_t size = ast_childcount(pattern_type);
  check_cardinality(c, desc, size, next_block);

  // If we get here, the match expression has the right cardinality.
  ast_t* pattern_child = ast_child(pattern_type);

  for(int i = 0; pattern_child != NULL; i++)
  {
    // Get the field offset and field descriptor from the tuple descriptor.
    LLVMValueRef field_info = gendesc_fieldinfo(c, desc, i);
    LLVMValueRef field_ptr = gendesc_fieldptr(c, ptr, field_info);
    LLVMValueRef field_desc = gendesc_fielddesc(c, field_info);

    // If we have a null descriptor, load the object.
    LLVMBasicBlockRef null_block = codegen_block(c, "null_desc");
    LLVMBasicBlockRef nonnull_block = codegen_block(c, "nonnull_desc");
    LLVMBasicBlockRef continue_block = codegen_block(c, "merge_desc");
    LLVMValueRef test = LLVMBuildIsNull(c->builder, field_desc, "");
    LLVMBuildCondBr(c->builder, test, null_block, nonnull_block);

    // Load the object, load its descriptor, and continue from there.
    LLVMPositionBuilderAtEnd(c->builder, null_block);
    LLVMTypeRef ptr_type = LLVMPointerType(c->object_ptr, 0);
    LLVMValueRef object_ptr = LLVMBuildIntToPtr(c->builder, field_ptr,
      ptr_type, "");
    LLVMValueRef object = LLVMBuildLoad(c->builder, object_ptr, "");
    LLVMValueRef object_desc = gendesc_fetch(c, object);
    object_ptr = gendesc_ptr_to_fields(c, object, object_desc);

    if(!check_type(c, object_ptr, object_desc, pattern_child, next_block))
      return false;

    LLVMBuildBr(c->builder, continue_block);

    // Continue with the pointer and descriptor.
    LLVMPositionBuilderAtEnd(c->builder, nonnull_block);

    if(!check_type(c, field_ptr, field_desc, pattern_child, next_block))
      return false;

    LLVMBuildBr(c->builder, continue_block);

    // Merge the two branches.
    LLVMPositionBuilderAtEnd(c->builder, continue_block);
    pattern_child = ast_sibling(pattern_child);
  }

  return true;
}
예제 #2
0
static bool dynamic_tuple_element(compile_t* c, LLVMValueRef ptr,
  LLVMValueRef desc, ast_t* pattern, LLVMBasicBlockRef next_block, int elem)
{
  // If we have a capture, generate the alloca now.
  switch(ast_id(pattern))
  {
    case TK_MATCH_CAPTURE:
      if(gen_localdecl(c, pattern) == NULL)
        return false;
      break;

    default: {}
  }

  // Get the field offset and field descriptor from the tuple descriptor.
  LLVMValueRef field_info = gendesc_fieldinfo(c, desc, elem);
  LLVMValueRef field_ptr = gendesc_fieldptr(c, ptr, field_info);
  LLVMValueRef field_desc = gendesc_fielddesc(c, field_info);

  // If we have a null descriptor, load the object.
  LLVMBasicBlockRef null_block = codegen_block(c, "null_desc");
  LLVMBasicBlockRef nonnull_block = codegen_block(c, "nonnull_desc");
  LLVMBasicBlockRef continue_block = codegen_block(c, "merge_desc");
  LLVMValueRef test = LLVMBuildIsNull(c->builder, field_desc, "");
  LLVMBuildCondBr(c->builder, test, null_block, nonnull_block);

  // Load the object, load its descriptor, and continue from there.
  LLVMPositionBuilderAtEnd(c->builder, null_block);
  LLVMTypeRef ptr_type = LLVMPointerType(c->object_ptr, 0);
  LLVMValueRef object_ptr = LLVMBuildIntToPtr(c->builder, field_ptr, ptr_type,
    "");
  LLVMValueRef object = LLVMBuildLoad(c->builder, object_ptr, "");
  LLVMValueRef object_desc = gendesc_fetch(c, object);

  if(!dynamic_match_object(c, object, object_desc, pattern, next_block))
    return false;

  LLVMBuildBr(c->builder, continue_block);

  // Continue with the pointer and descriptor.
  LLVMPositionBuilderAtEnd(c->builder, nonnull_block);

  if(!dynamic_match_ptr(c, field_ptr, field_desc, pattern, next_block))
    return false;

  LLVMBuildBr(c->builder, continue_block);

  // Merge the two branches.
  LLVMPositionBuilderAtEnd(c->builder, continue_block);
  return true;
}
예제 #3
0
파일: gentrace.c 프로젝트: Preetam/ponyc
static void trace_dynamic_tuple(compile_t* c, LLVMValueRef ctx,
  LLVMValueRef ptr, LLVMValueRef desc, ast_t* type, ast_t* orig, ast_t* tuple)
{
  // Build a "don't care" type of our cardinality.
  size_t cardinality = ast_childcount(type);
  ast_t* dontcare = ast_from(type, TK_TUPLETYPE);

  for(size_t i = 0; i < cardinality; i++)
    ast_append(dontcare, ast_from(type, TK_DONTCARE));

  // Replace our type in the tuple type with the "don't care" type.
  bool in_tuple = (tuple != NULL);

  if(in_tuple)
    ast_swap(type, dontcare);
  else
    tuple = dontcare;

  // If the original type is a subtype of the test type, then we are always
  // the correct cardinality. Otherwise, we need to dynamically check
  // cardinality.
  LLVMBasicBlockRef is_true = codegen_block(c, "");
  LLVMBasicBlockRef is_false = codegen_block(c, "");

  if(!is_subtype(orig, tuple, NULL))
  {
    LLVMValueRef dynamic_count = gendesc_fieldcount(c, desc);
    LLVMValueRef static_count = LLVMConstInt(c->i32, cardinality, false);
    LLVMValueRef test = LLVMBuildICmp(c->builder, LLVMIntEQ, static_count,
      dynamic_count, "");

    // Skip if not the right cardinality.
    LLVMBuildCondBr(c->builder, test, is_true, is_false);
  } else {
    LLVMBuildBr(c->builder, is_true);
  }

  LLVMPositionBuilderAtEnd(c->builder, is_true);

  size_t index = 0;
  ast_t* child = ast_child(type);
  ast_t* dc_child = ast_child(dontcare);

  while(child != NULL)
  {
    switch(trace_type(child))
    {
      case TRACE_PRIMITIVE:
        // Skip this element.
        break;

      case TRACE_ACTOR:
      case TRACE_KNOWN:
      case TRACE_UNKNOWN:
      case TRACE_KNOWN_VAL:
      case TRACE_UNKNOWN_VAL:
      case TRACE_TAG:
      case TRACE_TAG_OR_ACTOR:
      case TRACE_DYNAMIC:
      {
        // If we are (A, B), turn (_, _) into (A, _).
        ast_t* swap = ast_dup(child);
        ast_swap(dc_child, swap);

        // Create a next block.
        LLVMBasicBlockRef next_block = codegen_block(c, "");

        // Load the object from the tuple field.
        LLVMValueRef field_info = gendesc_fieldinfo(c, desc, index);
        LLVMValueRef object = gendesc_fieldload(c, ptr, field_info);

        // Trace dynamic, even if the tuple thinks the field isn't dynamic.
        trace_dynamic(c, ctx, object, swap, orig, tuple, next_block);

        // Continue into the next block.
        LLVMBuildBr(c->builder, next_block);
        LLVMPositionBuilderAtEnd(c->builder, next_block);

        // Restore (A, _) to (_, _).
        ast_swap(swap, dc_child);
        ast_free_unattached(swap);
        break;
      }

      case TRACE_TUPLE:
      {
        // If we are (A, B), turn (_, _) into (A, _).
        ast_t* swap = ast_dup(child);
        ast_swap(dc_child, swap);

        // Get a pointer to the unboxed tuple and it's descriptor.
        LLVMValueRef field_info = gendesc_fieldinfo(c, desc, index);
        LLVMValueRef field_ptr = gendesc_fieldptr(c, ptr, field_info);
        LLVMValueRef field_desc = gendesc_fielddesc(c, field_info);

        // Trace the tuple dynamically.
        trace_dynamic_tuple(c, ctx, field_ptr, field_desc, swap, orig, tuple);

        // Restore (A, _) to (_, _).
        ast_swap(swap, dc_child);
        ast_free_unattached(swap);
        break;
      }

      default: {}
    }

    index++;
    child = ast_sibling(child);
    dc_child = ast_sibling(dc_child);
  }

  // Restore the tuple type.
  if(in_tuple)
    ast_swap(dontcare, type);

  ast_free_unattached(dontcare);

  // Continue with other possible tracings.
  LLVMBuildBr(c->builder, is_false);
  LLVMPositionBuilderAtEnd(c->builder, is_false);
}