示例#1
0
void genprim_string_deserialise(compile_t* c, reach_type_t* t)
{
  // Generate the deserisalise function.
  t->deserialise_fn = codegen_addfun(c, genname_serialise(t->name),
    c->trace_type);

  codegen_startfun(c, t->deserialise_fn, NULL, NULL);
  LLVMSetFunctionCallConv(t->deserialise_fn, LLVMCCallConv);

  LLVMValueRef ctx = LLVMGetParam(t->deserialise_fn, 0);
  LLVMValueRef arg = LLVMGetParam(t->deserialise_fn, 1);

  LLVMValueRef object = LLVMBuildBitCast(c->builder, arg, t->structure_ptr,
    "");
  gendeserialise_typeid(c, t, object);

  // Deserialise the string contents.
  LLVMValueRef alloc = field_value(c, object, 2);
  LLVMValueRef ptr_offset = field_value(c, object, 3);
  ptr_offset = LLVMBuildPtrToInt(c->builder, ptr_offset, c->intptr, "");

  LLVMValueRef args[3];
  args[0] = ctx;
  args[1] = ptr_offset;
  args[2] = alloc;
  LLVMValueRef ptr_addr = gencall_runtime(c, "pony_deserialise_block", args, 3,
    "");

  LLVMValueRef ptr = LLVMBuildStructGEP(c->builder, object, 3, "");
  LLVMBuildStore(c->builder, ptr_addr, ptr);

  LLVMBuildRetVoid(c->builder);
  codegen_finishfun(c);
}
示例#2
0
文件: gentype.c 项目: nunb/ponyc
static void make_dispatch(compile_t* c, gentype_t* g)
{
  // Do nothing if we're not an actor.
  if(g->underlying != TK_ACTOR)
    return;

  // Create a dispatch function.
  const char* dispatch_name = genname_dispatch(g->type_name);
  g->dispatch_fn = codegen_addfun(c, dispatch_name, c->dispatch_type);
  LLVMSetFunctionCallConv(g->dispatch_fn, LLVMCCallConv);
  codegen_startfun(c, g->dispatch_fn, false);

  LLVMBasicBlockRef unreachable = codegen_block(c, "unreachable");

  // Read the message ID.
  LLVMValueRef msg = LLVMGetParam(g->dispatch_fn, 2);
  LLVMValueRef id_ptr = LLVMBuildStructGEP(c->builder, msg, 1, "");
  LLVMValueRef id = LLVMBuildLoad(c->builder, id_ptr, "id");

  // Store a reference to the dispatch switch. When we build behaviours, we
  // will add cases to this switch statement based on message ID.
  g->dispatch_switch = LLVMBuildSwitch(c->builder, id, unreachable, 0);

  // Mark the default case as unreachable.
  LLVMPositionBuilderAtEnd(c->builder, unreachable);
  LLVMBuildUnreachable(c->builder);
  codegen_finishfun(c);
}
示例#3
0
文件: gentype.c 项目: nunb/ponyc
static bool trace_fields(compile_t* c, gentype_t* g, LLVMValueRef ctx,
  LLVMValueRef object, int extra)
{
  bool need_trace = false;

  for(int i = 0; i < g->field_count; i++)
  {
    LLVMValueRef field = LLVMBuildStructGEP(c->builder, object, i + extra, "");

    if(g->field_keys[i] != TK_EMBED)
    {
      // Call the trace function indirectly depending on rcaps.
      LLVMValueRef value = LLVMBuildLoad(c->builder, field, "");
      need_trace |= gentrace(c, ctx, value, g->fields[i]);
    } else {
      // Call the trace function directly without marking the field.
      const char* fun = genname_trace(genname_type(g->fields[i]));
      LLVMValueRef trace_fn = LLVMGetNamedFunction(c->module, fun);

      if(trace_fn != NULL)
      {
        LLVMValueRef args[2];
        args[0] = ctx;
        args[1] = LLVMBuildBitCast(c->builder, field, c->object_ptr, "");

        LLVMBuildCall(c->builder, trace_fn, args, 2, "");
        need_trace = true;
      }
    }
  }

  return need_trace;
}
示例#4
0
static void deserialise(compile_t* c, reach_type_t* t, LLVMValueRef ctx,
  LLVMValueRef object)
{
  // The contents have already been copied.
  int extra = 0;

  switch(t->underlying)
  {
    case TK_PRIMITIVE:
    case TK_CLASS:
    {
      gendeserialise_typeid(c, t, object);
      extra++;
      break;
    }

    case TK_ACTOR:
    {
      // Skip the actor pad.
      gendeserialise_typeid(c, t, object);
      extra += 2;
      break;
    }

    case TK_TUPLETYPE:
    {
      // Get the tuple primitive type.
      if(LLVMTypeOf(object) == t->structure_ptr)
      {
        gendeserialise_typeid(c, t, object);
        object = LLVMBuildStructGEP(c->builder, object, 1, "");
      }
      break;
    }

    default: {}
  }

  for(uint32_t i = 0; i < t->field_count; i++)
  {
    LLVMValueRef field = LLVMBuildStructGEP(c->builder, object, i + extra, "");
    gendeserialise_element(c, t->fields[i].type, t->fields[i].embed,
      ctx, field);
  }
}
示例#5
0
static void set_descriptor(compile_t* c, reach_type_t* t, LLVMValueRef value)
{
  if(t->underlying == TK_STRUCT)
    return;

  LLVMValueRef desc_ptr = LLVMBuildStructGEP(c->builder, value, 0, "");
  LLVMValueRef store = LLVMBuildStore(c->builder, t->desc, desc_ptr);
  const char id[] = "tbaa";
  LLVMSetMetadata(store, LLVMGetMDKindID(id, sizeof(id) - 1), c->tbaa_descptr);
}
示例#6
0
文件: genfun.c 项目: fydot/ponyc
static LLVMTypeRef send_message(compile_t* c, ast_t* fun, LLVMValueRef to,
  LLVMValueRef func, uint32_t index)
{
  // Get the parameter types.
  LLVMTypeRef f_type = LLVMGetElementType(LLVMTypeOf(func));
  int count = LLVMCountParamTypes(f_type) + 2;
  VLA(LLVMTypeRef, f_params, count);
  LLVMGetParamTypes(f_type, &f_params[2]);

  // The first one becomes the message size, the second the message ID.
  f_params[0] = c->i32;
  f_params[1] = c->i32;
  f_params[2] = c->void_ptr;
  LLVMTypeRef msg_type = LLVMStructTypeInContext(c->context, f_params, count,
    false);
  LLVMTypeRef msg_type_ptr = LLVMPointerType(msg_type, 0);

  // Allocate the message, setting its size and ID.
  size_t msg_size = LLVMABISizeOfType(c->target_data, msg_type);
  LLVMValueRef args[2];

  args[0] = LLVMConstInt(c->i32, pool_index(msg_size), false);
  args[1] = LLVMConstInt(c->i32, index, false);
  LLVMValueRef msg = gencall_runtime(c, "pony_alloc_msg", args, 2, "");
  LLVMValueRef msg_ptr = LLVMBuildBitCast(c->builder, msg, msg_type_ptr, "");

  // Trace while populating the message contents.
  LLVMValueRef start_trace = gencall_runtime(c, "pony_gc_send", NULL, 0, "");
  ast_t* params = ast_childidx(fun, 3);
  ast_t* param = ast_child(params);
  bool need_trace = false;

  for(int i = 3; i < count; i++)
  {
    LLVMValueRef arg = LLVMGetParam(func, i - 2);
    LLVMValueRef arg_ptr = LLVMBuildStructGEP(c->builder, msg_ptr, i, "");
    LLVMBuildStore(c->builder, arg, arg_ptr);

    need_trace |= gentrace(c, arg, ast_type(param));
    param = ast_sibling(param);
  }

  if(need_trace)
    gencall_runtime(c, "pony_send_done", NULL, 0, "");
  else
    LLVMInstructionEraseFromParent(start_trace);

  // Send the message.
  args[0] = LLVMBuildBitCast(c->builder, to, c->object_ptr, "");
  args[1] = msg;
  gencall_runtime(c, "pony_sendv", args, 2, "");

  // Return the type of the message.
  return msg_type_ptr;
}
示例#7
0
文件: gendesc.c 项目: npruehs/ponyc
LLVMValueRef gendesc_vtable(compile_t* c, LLVMValueRef object, size_t colour)
{
  LLVMValueRef desc = gendesc_fetch(c, object);
  LLVMValueRef vtable = LLVMBuildStructGEP(c->builder, desc, DESC_VTABLE, "");

  LLVMValueRef gep[2];
  gep[0] = LLVMConstInt(c->i32, 0, false);
  gep[1] = LLVMConstInt(c->i32, colour, false);

  LLVMValueRef func_ptr = LLVMBuildInBoundsGEP(c->builder, vtable, gep, 2, "");
  return LLVMBuildLoad(c->builder, func_ptr, "");
}
示例#8
0
文件: gendesc.c 项目: dleonard0/ponyc
static LLVMValueRef make_unbox_function(compile_t* c, gentype_t* g,
  const char* name)
{
  LLVMValueRef fun = LLVMGetNamedFunction(c->module, name);

  if(fun == NULL)
    return LLVMConstNull(c->void_ptr);

  // Create a new unboxing function that forwards to the real function.
  LLVMTypeRef f_type = LLVMGetElementType(LLVMTypeOf(fun));
  int count = LLVMCountParamTypes(f_type);

  // If it takes no arguments, it's a special number constructor. Don't put it
  // in the vtable.
  if(count == 0)
    return LLVMConstNull(c->void_ptr);

  size_t buf_size = count *sizeof(LLVMTypeRef);
  LLVMTypeRef* params = (LLVMTypeRef*)pool_alloc_size(buf_size);
  LLVMGetParamTypes(f_type, params);
  LLVMTypeRef ret_type = LLVMGetReturnType(f_type);

  // It's the same type, but it takes the boxed type instead of the primitive
  // type as the receiver.
  params[0] = g->structure_ptr;

  const char* unbox_name = genname_unbox(name);
  LLVMTypeRef unbox_type = LLVMFunctionType(ret_type, params, count, false);
  LLVMValueRef unbox_fun = codegen_addfun(c, unbox_name, unbox_type);
  codegen_startfun(c, unbox_fun, false);

  // Extract the primitive type from element 1 and call the real function.
  LLVMValueRef this_ptr = LLVMGetParam(unbox_fun, 0);
  LLVMValueRef primitive_ptr = LLVMBuildStructGEP(c->builder, this_ptr, 1, "");
  LLVMValueRef primitive = LLVMBuildLoad(c->builder, primitive_ptr, "");

  LLVMValueRef* args = (LLVMValueRef*)pool_alloc_size(buf_size);
  args[0] = primitive;

  for(int i = 1; i < count; i++)
    args[i] = LLVMGetParam(unbox_fun, i);

  LLVMValueRef result = codegen_call(c, fun, args, count);
  LLVMBuildRet(c->builder, result);
  codegen_finishfun(c);

  pool_free_size(buf_size, params);
  pool_free_size(buf_size, args);
  return LLVMConstBitCast(unbox_fun, c->void_ptr);
}
示例#9
0
文件: genfun.c 项目: jonas-l/ponyc
static void add_dispatch_case(compile_t* c, gentype_t* g, ast_t* fun,
  uint32_t index, LLVMValueRef handler, LLVMTypeRef type)
{
  // Add a case to the dispatch function to handle this message.
  codegen_startfun(c, g->dispatch_fn, false);
  LLVMBasicBlockRef block = codegen_block(c, "handler");
  LLVMValueRef id = LLVMConstInt(c->i32, index, false);
  LLVMAddCase(g->dispatch_switch, id, block);

  // Destructure the message.
  LLVMPositionBuilderAtEnd(c->builder, block);
  LLVMValueRef ctx = LLVMGetParam(g->dispatch_fn, 0);
  LLVMValueRef this_ptr = LLVMGetParam(g->dispatch_fn, 1);
  LLVMValueRef msg = LLVMBuildBitCast(c->builder,
    LLVMGetParam(g->dispatch_fn, 2), type, "");

  int count = LLVMCountParams(handler);
  size_t buf_size = count * sizeof(LLVMValueRef);
  LLVMValueRef* args = (LLVMValueRef*)pool_alloc_size(buf_size);
  args[0] = LLVMBuildBitCast(c->builder, this_ptr, g->use_type, "");

  // Trace the message.
  LLVMValueRef start_trace = gencall_runtime(c, "pony_gc_recv", &ctx, 1, "");
  ast_t* params = ast_childidx(fun, 3);
  ast_t* param = ast_child(params);
  bool need_trace = false;

  for(int i = 1; i < count; i++)
  {
    LLVMValueRef field = LLVMBuildStructGEP(c->builder, msg, i + 2, "");
    args[i] = LLVMBuildLoad(c->builder, field, "");

    need_trace |= gentrace(c, ctx, args[i], ast_type(param));
    param = ast_sibling(param);
  }

  if(need_trace)
  {
    gencall_runtime(c, "pony_recv_done", &ctx, 1, "");
  } else {
    LLVMInstructionEraseFromParent(start_trace);
  }

  // Call the handler.
  codegen_call(c, handler, args, count);
  LLVMBuildRetVoid(c->builder);
  codegen_finishfun(c);
  pool_free_size(buf_size, args);
}
示例#10
0
文件: gentype.c 项目: volth/ponyc
static bool trace_fields(compile_t* c, gentype_t* g, LLVMValueRef object,
  int extra)
{
  bool need_trace = false;

  for(int i = 0; i < g->field_count; i++)
  {
    LLVMValueRef field = LLVMBuildStructGEP(c->builder, object, i + extra,
      "");
    LLVMValueRef value = LLVMBuildLoad(c->builder, field, "");
    need_trace |= gentrace(c, value, g->fields[i]);
  }

  return need_trace;
}
示例#11
0
文件: gencall.c 项目: cyisfor/ponyc
LLVMValueRef gencall_allocstruct(compile_t* c, gentype_t* g)
{
  // Disable debug anchor
  dwarf_location(&c->dwarf, NULL);

  // We explicitly want a boxed version.
  // Get the size of the structure.
  size_t size = (size_t)LLVMABISizeOfType(c->target_data, g->structure);

  // Get the finaliser, if there is one.
  const char* final = genname_finalise(g->type_name);
  LLVMValueRef final_fun = LLVMGetNamedFunction(c->module, final);

  // Allocate the object.
  LLVMValueRef args[3];
  args[0] = codegen_ctx(c);

  LLVMValueRef result;

  if(final_fun == NULL)
  {
    if(size <= HEAP_MAX)
    {
      uint32_t index = ponyint_heap_index(size);
      args[1] = LLVMConstInt(c->i32, index, false);
      result = gencall_runtime(c, "pony_alloc_small", args, 2, "");
    } else {
      args[1] = LLVMConstInt(c->intptr, size, false);
      result = gencall_runtime(c, "pony_alloc_large", args, 2, "");
    }
  } else {
    args[1] = LLVMConstInt(c->intptr, size, false);
    args[2] = LLVMConstBitCast(final_fun, c->final_fn);
    result = gencall_runtime(c, "pony_alloc_final", args, 3, "");
  }

  result = LLVMBuildBitCast(c->builder, result, g->structure_ptr, "");

  // Set the descriptor.
  if(g->underlying != TK_STRUCT)
  {
    LLVMValueRef desc_ptr = LLVMBuildStructGEP(c->builder, result, 0, "");
    LLVMBuildStore(c->builder, g->desc, desc_ptr);
  }

  return result;
}
示例#12
0
static LLVMValueRef make_fieldptr(compile_t* c, LLVMValueRef l_value,
  ast_t* l_type, ast_t* right)
{
  pony_assert(ast_id(l_type) == TK_NOMINAL);
  pony_assert(ast_id(right) == TK_ID);

  ast_t* def;
  ast_t* field;
  uint32_t index;
  get_fieldinfo(l_type, right, &def, &field, &index);

  if(ast_id(def) != TK_STRUCT)
    index++;

  if(ast_id(def) == TK_ACTOR)
    index++;

  return LLVMBuildStructGEP(c->builder, l_value, index, "");
}
示例#13
0
static LLVMValueRef make_fieldptr(compile_t* c, LLVMValueRef l_value,
  ast_t* l_type, ast_t* right)
{
  switch(ast_id(l_type))
  {
    case TK_NOMINAL:
    {
      assert(ast_id(right) == TK_ID);

      ast_t* def = (ast_t*)ast_data(l_type);
      ast_t* field = ast_get(def, ast_name(right), NULL);
      int index = (int)ast_index(field);

      if(ast_id(def) != TK_STRUCT)
        index++;

      if(ast_id(def) == TK_ACTOR)
        index++;

      return LLVMBuildStructGEP(c->builder, l_value, index, "");
    }

    case TK_TUPLETYPE:
    {
      assert(ast_id(right) == TK_INT);
      int index = (int)ast_int(right)->low;

      return LLVMBuildExtractValue(c->builder, l_value, index, "");
    }

    case TK_ARROW:
      return make_fieldptr(c, l_value, ast_childidx(l_type, 1), right);

    default: {}
  }

  assert(0);
  return NULL;
}
示例#14
0
文件: gencall.c 项目: Theodus/ponyc
void gen_send_message(compile_t* c, reach_method_t* m, LLVMValueRef args[],
  ast_t* args_ast)
{
  // Allocate the message, setting its size and ID.
  compile_method_t* c_m = (compile_method_t*)m->c_method;
  size_t msg_size = (size_t)LLVMABISizeOfType(c->target_data, c_m->msg_type);
  LLVMTypeRef msg_type_ptr = LLVMPointerType(c_m->msg_type, 0);

  size_t params_buf_size = (m->param_count + 3) * sizeof(LLVMTypeRef);
  LLVMTypeRef* param_types =
    (LLVMTypeRef*)ponyint_pool_alloc_size(params_buf_size);
  LLVMGetStructElementTypes(c_m->msg_type, param_types);
  size_t args_buf_size = (m->param_count + 1) * sizeof(LLVMValueRef);
  LLVMValueRef* cast_args =
    (LLVMValueRef*)ponyint_pool_alloc_size(args_buf_size);
  size_t arg_types_buf_size = m->param_count * sizeof(ast_t*);
  ast_t** arg_types = (ast_t**)ponyint_pool_alloc_size(arg_types_buf_size);

  ast_t* arg_ast = ast_child(args_ast);

  deferred_reification_t* reify = c->frame->reify;

  for(size_t i = 0; i < m->param_count; i++)
  {
    arg_types[i] = deferred_reify(reify, ast_type(arg_ast), c->opt);
    cast_args[i+1] = gen_assign_cast(c, param_types[i+3], args[i+1],
      arg_types[i]);
    arg_ast = ast_sibling(arg_ast);
  }

  LLVMValueRef msg_args[5];

  msg_args[0] = LLVMConstInt(c->i32, ponyint_pool_index(msg_size), false);
  msg_args[1] = LLVMConstInt(c->i32, m->vtable_index, false);
  LLVMValueRef msg = gencall_runtime(c, "pony_alloc_msg", msg_args, 2, "");
  LLVMValueRef md = LLVMMDNodeInContext(c->context, NULL, 0);
  LLVMSetMetadataStr(msg, "pony.msgsend", md);
  LLVMValueRef msg_ptr = LLVMBuildBitCast(c->builder, msg, msg_type_ptr, "");

  for(unsigned int i = 0; i < m->param_count; i++)
  {
    LLVMValueRef arg_ptr = LLVMBuildStructGEP(c->builder, msg_ptr, i + 3, "");
    LLVMBuildStore(c->builder, cast_args[i+1], arg_ptr);
  }

  // Trace while populating the message contents.
  bool need_trace = false;

  for(size_t i = 0; i < m->param_count; i++)
  {
    if(gentrace_needed(c, arg_types[i], m->params[i].ast))
    {
      need_trace = true;
      break;
    }
  }

  LLVMValueRef ctx = codegen_ctx(c);

  if(need_trace)
  {
    LLVMValueRef gc = gencall_runtime(c, "pony_gc_send", &ctx, 1, "");
    LLVMSetMetadataStr(gc, "pony.msgsend", md);

    for(size_t i = 0; i < m->param_count; i++)
    {
      gentrace(c, ctx, args[i+1], cast_args[i+1], arg_types[i],
        m->params[i].ast);
    }

    gc = gencall_runtime(c, "pony_send_done", &ctx, 1, "");
    LLVMSetMetadataStr(gc, "pony.msgsend", md);
  }

  // Send the message.
  msg_args[0] = ctx;
  msg_args[1] = LLVMBuildBitCast(c->builder, args[0], c->object_ptr, "");
  msg_args[2] = msg;
  msg_args[3] = msg;
  msg_args[4] = LLVMConstInt(c->i1, 1, false);
  LLVMValueRef send;

  if(ast_id(m->fun->ast) == TK_NEW)
    send = gencall_runtime(c, "pony_sendv_single", msg_args, 5, "");
  else
    send = gencall_runtime(c, "pony_sendv", msg_args, 5, "");

  LLVMSetMetadataStr(send, "pony.msgsend", md);

  ponyint_pool_free_size(params_buf_size, param_types);
  ponyint_pool_free_size(args_buf_size, cast_args);

  for(size_t i = 0; i < m->param_count; i++)
    ast_free_unattached(arg_types[i]);

  ponyint_pool_free_size(arg_types_buf_size, arg_types);
}
示例#15
0
文件: genfun.c 项目: fydot/ponyc
static bool gen_field_init(compile_t* c, gentype_t* g)
{
  LLVMValueRef this_ptr = LLVMGetParam(codegen_fun(c), 0);

  ast_t* def = (ast_t*)ast_data(g->ast);
  ast_t* members = ast_childidx(def, 4);
  ast_t* member = ast_child(members);

  // Struct index of the current field.
  int index = 1;

  if(ast_id(def) == TK_ACTOR)
    index++;

  // Iterate through all fields.
  while(member != NULL)
  {
    switch(ast_id(member))
    {
      case TK_FVAR:
      case TK_FLET:
      {
        // Skip this field if it has no initialiser.
        AST_GET_CHILDREN(member, id, type, body);

        if(ast_id(body) != TK_NONE)
        {
          // Reify the initialiser.
          ast_t* this_type = set_cap_and_ephemeral(g->ast, TK_REF, TK_NONE);
          ast_t* var = lookup(NULL, NULL, this_type, ast_name(id));
          ast_free_unattached(this_type);

          assert(var != NULL);
          body = ast_childidx(var, 2);

          // Get the field pointer.
          dwarf_location(&c->dwarf, body);
          LLVMValueRef l_value = LLVMBuildStructGEP(c->builder, this_ptr,
            index, "");

          // Cast the initialiser to the field type.
          LLVMValueRef r_value = gen_expr(c, body);

          if(r_value == NULL)
            return false;

          LLVMTypeRef l_type = LLVMGetElementType(LLVMTypeOf(l_value));
          LLVMValueRef cast_value = gen_assign_cast(c, l_type, r_value,
            ast_type(body));

          if(cast_value == NULL)
            return false;

          // Store the result.
          LLVMBuildStore(c->builder, cast_value, l_value);
        }

        index++;
        break;
      }

      default: {}
    }

    member = ast_sibling(member);
  }

  return true;
}
示例#16
0
文件: gentype.c 项目: volth/ponyc
static bool make_trace(compile_t* c, gentype_t* g)
{
  // Do nothing if we have no fields.
  if(g->field_count == 0)
    return true;

  if(g->underlying == TK_CLASS)
  {
    // Special case the array trace function.
    AST_GET_CHILDREN(g->ast, pkg, id);
    const char* package = ast_name(pkg);
    const char* name = ast_name(id);

    if((package == c->str_1) && (name == c->str_Array))
    {
      genprim_array_trace(c, g);
      return true;
    }
  }

  // Create a trace function.
  const char* trace_name = genname_trace(g->type_name);
  LLVMValueRef trace_fn = codegen_addfun(c, trace_name, c->trace_type);

  codegen_startfun(c, trace_fn, false);
  LLVMSetFunctionCallConv(trace_fn, LLVMCCallConv);

  LLVMValueRef arg = LLVMGetParam(trace_fn, 0);
  LLVMValueRef object = LLVMBuildBitCast(c->builder, arg, g->structure_ptr,
    "object");

  // If we don't ever trace anything, delete this function.
  bool need_trace;

  if(g->underlying == TK_TUPLETYPE)
  {
    // Create another function that traces the tuple members.
    const char* trace_tuple_name = genname_tracetuple(g->type_name);
    LLVMTypeRef trace_tuple_type = LLVMFunctionType(c->void_type,
      &g->primitive, 1, false);
    LLVMValueRef trace_tuple_fn = codegen_addfun(c, trace_tuple_name,
      trace_tuple_type);

    codegen_startfun(c, trace_tuple_fn, false);
    LLVMSetFunctionCallConv(trace_tuple_fn, LLVMCCallConv);

    LLVMValueRef arg = LLVMGetParam(trace_tuple_fn, 0);
    need_trace = trace_elements(c, g, arg);

    LLVMBuildRetVoid(c->builder);
    codegen_finishfun(c);

    if(need_trace)
    {
      // Get the tuple primitive.
      LLVMValueRef tuple_ptr = LLVMBuildStructGEP(c->builder, object, 1, "");
      LLVMValueRef tuple = LLVMBuildLoad(c->builder, tuple_ptr, "");

      // Call the tuple trace function with the unboxed primitive type.
      LLVMBuildCall(c->builder, trace_tuple_fn, &tuple, 1, "");
    } else {
      LLVMDeleteFunction(trace_tuple_fn);
    }
  } else {
    int extra = 1;

    // Actors have a pad.
    if(g->underlying == TK_ACTOR)
      extra++;

    need_trace = trace_fields(c, g, object, extra);
  }

  LLVMBuildRetVoid(c->builder);
  codegen_finishfun(c);

  if(!need_trace)
    LLVMDeleteFunction(trace_fn);

  return true;
}
示例#17
0
文件: gentype.c 项目: Praetonus/ponyc
static bool make_trace(compile_t* c, reach_type_t* t)
{
  if(t->trace_fn == NULL)
    return true;

  if(t->underlying == TK_CLASS)
  {
    // Special case the array trace function.
    AST_GET_CHILDREN(t->ast, pkg, id);
    const char* package = ast_name(pkg);
    const char* name = ast_name(id);

    if((package == c->str_builtin) && (name == c->str_Array))
    {
      genprim_array_trace(c, t);
      return true;
    }
  }

  // Generate the trace function.
  codegen_startfun(c, t->trace_fn, NULL, NULL);
  LLVMSetFunctionCallConv(t->trace_fn, LLVMCCallConv);
  LLVMSetLinkage(t->trace_fn, LLVMExternalLinkage);

  LLVMValueRef ctx = LLVMGetParam(t->trace_fn, 0);
  LLVMValueRef arg = LLVMGetParam(t->trace_fn, 1);
  LLVMValueRef object = LLVMBuildBitCast(c->builder, arg, t->structure_ptr,
    "object");

  int extra = 0;

  // Non-structs have a type descriptor.
  if(t->underlying != TK_STRUCT)
    extra++;

  // Actors have a pad.
  if(t->underlying == TK_ACTOR)
    extra++;

  for(uint32_t i = 0; i < t->field_count; i++)
  {
    LLVMValueRef field = LLVMBuildStructGEP(c->builder, object, i + extra, "");

    if(!t->fields[i].embed)
    {
      // Call the trace function indirectly depending on rcaps.
      LLVMValueRef value = LLVMBuildLoad(c->builder, field, "");
      gentrace(c, ctx, value, t->fields[i].ast);
    } else {
      // Call the trace function directly without marking the field.
      LLVMValueRef trace_fn = t->fields[i].type->trace_fn;

      if(trace_fn != NULL)
      {
        LLVMValueRef args[2];
        args[0] = ctx;
        args[1] = LLVMBuildBitCast(c->builder, field, c->object_ptr, "");

        LLVMBuildCall(c->builder, trace_fn, args, 2, "");
      }
    }
  }

  LLVMBuildRetVoid(c->builder);
  codegen_finishfun(c);
  return true;
}
示例#18
0
文件: genexe.c 项目: volth/ponyc
static void gen_main(compile_t* c, gentype_t* main_g, gentype_t* env_g)
{
  LLVMTypeRef params[3];
  params[0] = c->i32;
  params[1] = LLVMPointerType(LLVMPointerType(c->i8, 0), 0);
  params[2] = LLVMPointerType(LLVMPointerType(c->i8, 0), 0);

  LLVMTypeRef ftype = LLVMFunctionType(c->i32, params, 3, false);
  LLVMValueRef func = LLVMAddFunction(c->module, "main", ftype);

  codegen_startfun(c, func, false);

  LLVMValueRef args[3];
  args[0] = LLVMGetParam(func, 0);
  LLVMSetValueName(args[0], "argc");

  args[1] = LLVMGetParam(func, 1);
  LLVMSetValueName(args[1], "argv");

  args[2] = LLVMGetParam(func, 2);
  LLVMSetValueName(args[1], "envp");

  // Initialise the pony runtime with argc and argv, getting a new argc.
  args[0] = gencall_runtime(c, "pony_init", args, 2, "argc");

  // Create the main actor and become it.
  LLVMValueRef main_actor = create_main(c, main_g);

  // Create an Env on the main actor's heap.
  const char* env_name = "Env";
  const char* env_create = genname_fun(env_name, "_create", NULL);

  LLVMValueRef env_args[4];
  env_args[0] = gencall_alloc(c, env_g);
  env_args[1] = LLVMBuildZExt(c->builder, args[0], c->i64, "");
  env_args[2] = args[1];
  env_args[3] = args[2];

  LLVMValueRef env = gencall_runtime(c, env_create, env_args, 4, "env");
  LLVMSetInstructionCallConv(env, GEN_CALLCONV);

  // Run primitive initialisers using the main actor's heap.
  primitive_call(c, stringtab("_init"), env);

  // Create a type for the message.
  LLVMTypeRef f_params[4];
  f_params[0] = c->i32;
  f_params[1] = c->i32;
  f_params[2] = c->void_ptr;
  f_params[3] = LLVMTypeOf(env);
  LLVMTypeRef msg_type = LLVMStructTypeInContext(c->context, f_params, 4,
    false);
  LLVMTypeRef msg_type_ptr = LLVMPointerType(msg_type, 0);

  // Allocate the message, setting its size and ID.
  uint32_t index = genfun_vtable_index(c, main_g, stringtab("create"), NULL);

  size_t msg_size = LLVMABISizeOfType(c->target_data, msg_type);
  args[0] = LLVMConstInt(c->i32, pool_index(msg_size), false);
  args[1] = LLVMConstInt(c->i32, index, false);
  LLVMValueRef msg = gencall_runtime(c, "pony_alloc_msg", args, 2, "");
  LLVMValueRef msg_ptr = LLVMBuildBitCast(c->builder, msg, msg_type_ptr, "");

  // Set the message contents.
  LLVMValueRef env_ptr = LLVMBuildStructGEP(c->builder, msg_ptr, 3, "");
  LLVMBuildStore(c->builder, env, env_ptr);

  // Trace the message.
  gencall_runtime(c, "pony_gc_send", NULL, 0, "");
  const char* env_trace = genname_trace(env_name);

  args[0] = LLVMBuildBitCast(c->builder, env, c->object_ptr, "");
  args[1] = LLVMGetNamedFunction(c->module, env_trace);
  gencall_runtime(c, "pony_traceobject", args, 2, "");
  gencall_runtime(c, "pony_send_done", NULL, 0, "");

  // Send the message.
  args[0] = main_actor;
  args[1] = msg;
  gencall_runtime(c, "pony_sendv", args, 2, "");

  // Start the runtime.
  LLVMValueRef zero = LLVMConstInt(c->i32, 0, false);
  LLVMValueRef rc = gencall_runtime(c, "pony_start", &zero, 1, "");

  // Run primitive finalisers. We create a new main actor as a context to run
  // the finalisers in, but we do not initialise or schedule it.
  LLVMValueRef final_actor = create_main(c, main_g);
  primitive_call(c, stringtab("_final"), NULL);
  args[0] = final_actor;
  gencall_runtime(c, "pony_destroy", args, 1, "");

  // Return the runtime exit code.
  LLVMBuildRet(c->builder, rc);

  codegen_finishfun(c);

  // External linkage for main().
  LLVMSetLinkage(func, LLVMExternalLinkage);
}
示例#19
0
/*
 * Create a function that deforms a tuple of type desc up to natts columns.
 */
LLVMValueRef
slot_compile_deform(LLVMJitContext *context, TupleDesc desc, int natts)
{
	char	   *funcname;

	LLVMModuleRef mod;
	LLVMBuilderRef b;

	LLVMTypeRef deform_sig;
	LLVMValueRef v_deform_fn;

	LLVMBasicBlockRef b_entry;
	LLVMBasicBlockRef b_adjust_unavail_cols;
	LLVMBasicBlockRef b_find_start;

	LLVMBasicBlockRef b_out;
	LLVMBasicBlockRef b_dead;
	LLVMBasicBlockRef *attcheckattnoblocks;
	LLVMBasicBlockRef *attstartblocks;
	LLVMBasicBlockRef *attisnullblocks;
	LLVMBasicBlockRef *attcheckalignblocks;
	LLVMBasicBlockRef *attalignblocks;
	LLVMBasicBlockRef *attstoreblocks;

	LLVMValueRef v_offp;

	LLVMValueRef v_tupdata_base;
	LLVMValueRef v_tts_values;
	LLVMValueRef v_tts_nulls;
	LLVMValueRef v_slotoffp;
	LLVMValueRef v_slowp;
	LLVMValueRef v_nvalidp;
	LLVMValueRef v_nvalid;
	LLVMValueRef v_maxatt;

	LLVMValueRef v_slot;

	LLVMValueRef v_tupleheaderp;
	LLVMValueRef v_tuplep;
	LLVMValueRef v_infomask1;
	LLVMValueRef v_infomask2;
	LLVMValueRef v_bits;

	LLVMValueRef v_hoff;

	LLVMValueRef v_hasnulls;

	/* last column (0 indexed) guaranteed to exist */
	int			guaranteed_column_number = -1;

	/* current known alignment */
	int			known_alignment = 0;

	/* if true, known_alignment describes definite offset of column */
	bool		attguaranteedalign = true;

	int			attnum;

	mod = llvm_mutable_module(context);

	funcname = llvm_expand_funcname(context, "deform");

	/*
	 * Check which columns do have to exist, so we don't have to check the
	 * rows natts unnecessarily.
	 */
	for (attnum = 0; attnum < desc->natts; attnum++)
	{
		Form_pg_attribute att = TupleDescAttr(desc, attnum);

		/*
		 * If the column is possibly missing, we can't rely on its (or
		 * subsequent) NOT NULL constraints to indicate minimum attributes in
		 * the tuple, so stop here.
		 */
		if (att->atthasmissing)
			break;

		/*
		 * Column is NOT NULL and there've been no preceding missing columns,
		 * it's guaranteed that all columns up to here exist at least in the
		 * NULL bitmap.
		 */
		if (att->attnotnull)
			guaranteed_column_number = attnum;
	}

	/* Create the signature and function */
	{
		LLVMTypeRef param_types[1];

		param_types[0] = l_ptr(StructTupleTableSlot);

		deform_sig = LLVMFunctionType(LLVMVoidType(), param_types,
									  lengthof(param_types), 0);
	}
	v_deform_fn = LLVMAddFunction(mod, funcname, deform_sig);
	LLVMSetLinkage(v_deform_fn, LLVMInternalLinkage);
	LLVMSetParamAlignment(LLVMGetParam(v_deform_fn, 0), MAXIMUM_ALIGNOF);
	llvm_copy_attributes(AttributeTemplate, v_deform_fn);

	b_entry =
		LLVMAppendBasicBlock(v_deform_fn, "entry");
	b_adjust_unavail_cols =
		LLVMAppendBasicBlock(v_deform_fn, "adjust_unavail_cols");
	b_find_start =
		LLVMAppendBasicBlock(v_deform_fn, "find_startblock");
	b_out =
		LLVMAppendBasicBlock(v_deform_fn, "outblock");
	b_dead =
		LLVMAppendBasicBlock(v_deform_fn, "deadblock");

	b = LLVMCreateBuilder();

	attcheckattnoblocks = palloc(sizeof(LLVMBasicBlockRef) * natts);
	attstartblocks = palloc(sizeof(LLVMBasicBlockRef) * natts);
	attisnullblocks = palloc(sizeof(LLVMBasicBlockRef) * natts);
	attcheckalignblocks = palloc(sizeof(LLVMBasicBlockRef) * natts);
	attalignblocks = palloc(sizeof(LLVMBasicBlockRef) * natts);
	attstoreblocks = palloc(sizeof(LLVMBasicBlockRef) * natts);

	known_alignment = 0;

	LLVMPositionBuilderAtEnd(b, b_entry);

	/* perform allocas first, llvm only converts those to registers */
	v_offp = LLVMBuildAlloca(b, TypeSizeT, "v_offp");

	v_slot = LLVMGetParam(v_deform_fn, 0);

	v_tts_values =
		l_load_struct_gep(b, v_slot, FIELDNO_TUPLETABLESLOT_VALUES,
						  "tts_values");
	v_tts_nulls =
		l_load_struct_gep(b, v_slot, FIELDNO_TUPLETABLESLOT_ISNULL,
						  "tts_ISNULL");

	v_slotoffp = LLVMBuildStructGEP(b, v_slot, FIELDNO_TUPLETABLESLOT_OFF, "");
	v_slowp = LLVMBuildStructGEP(b, v_slot, FIELDNO_TUPLETABLESLOT_SLOW, "");
	v_nvalidp = LLVMBuildStructGEP(b, v_slot, FIELDNO_TUPLETABLESLOT_NVALID, "");

	v_tupleheaderp =
		l_load_struct_gep(b, v_slot, FIELDNO_TUPLETABLESLOT_TUPLE,
						  "tupleheader");
	v_tuplep =
		l_load_struct_gep(b, v_tupleheaderp, FIELDNO_HEAPTUPLEDATA_DATA,
						  "tuple");
	v_bits =
		LLVMBuildBitCast(b,
						 LLVMBuildStructGEP(b, v_tuplep,
											FIELDNO_HEAPTUPLEHEADERDATA_BITS,
											""),
						 l_ptr(LLVMInt8Type()),
						 "t_bits");
	v_infomask1 =
		l_load_struct_gep(b, v_tuplep,
						  FIELDNO_HEAPTUPLEHEADERDATA_INFOMASK,
						  "infomask1");
	v_infomask2 =
		l_load_struct_gep(b,
						  v_tuplep, FIELDNO_HEAPTUPLEHEADERDATA_INFOMASK2,
						  "infomask2");

	/* t_infomask & HEAP_HASNULL */
	v_hasnulls =
		LLVMBuildICmp(b, LLVMIntNE,
					  LLVMBuildAnd(b,
								   l_int16_const(HEAP_HASNULL),
								   v_infomask1, ""),
					  l_int16_const(0),
					  "hasnulls");

	/* t_infomask2 & HEAP_NATTS_MASK */
	v_maxatt = LLVMBuildAnd(b,
							l_int16_const(HEAP_NATTS_MASK),
							v_infomask2,
							"maxatt");

	v_hoff =
		l_load_struct_gep(b, v_tuplep,
						  FIELDNO_HEAPTUPLEHEADERDATA_HOFF,
						  "t_hoff");

	v_tupdata_base =
		LLVMBuildGEP(b,
					 LLVMBuildBitCast(b,
									  v_tuplep,
									  l_ptr(LLVMInt8Type()),
									  ""),
					 &v_hoff, 1,
					 "v_tupdata_base");

	/*
	 * Load tuple start offset from slot. Will be reset below in case there's
	 * no existing deformed columns in slot.
	 */
	{
		LLVMValueRef v_off_start;

		v_off_start = LLVMBuildLoad(b, v_slotoffp, "v_slot_off");
		v_off_start = LLVMBuildZExt(b, v_off_start, TypeSizeT, "");
		LLVMBuildStore(b, v_off_start, v_offp);
	}

	/* build the basic block for each attribute, need them as jump target */
	for (attnum = 0; attnum < natts; attnum++)
	{
		attcheckattnoblocks[attnum] =
			l_bb_append_v(v_deform_fn, "block.attr.%d.attcheckattno", attnum);
		attstartblocks[attnum] =
			l_bb_append_v(v_deform_fn, "block.attr.%d.start", attnum);
		attisnullblocks[attnum] =
			l_bb_append_v(v_deform_fn, "block.attr.%d.attisnull", attnum);
		attcheckalignblocks[attnum] =
			l_bb_append_v(v_deform_fn, "block.attr.%d.attcheckalign", attnum);
		attalignblocks[attnum] =
			l_bb_append_v(v_deform_fn, "block.attr.%d.align", attnum);
		attstoreblocks[attnum] =
			l_bb_append_v(v_deform_fn, "block.attr.%d.store", attnum);
	}

	/*
	 * Check if's guaranteed the all the desired attributes are available in
	 * tuple. If so, we can start deforming. If not, need to make sure to
	 * fetch the missing columns.
	 */
	if ((natts - 1) <= guaranteed_column_number)
	{
		/* just skip through unnecessary blocks */
		LLVMBuildBr(b, b_adjust_unavail_cols);
		LLVMPositionBuilderAtEnd(b, b_adjust_unavail_cols);
		LLVMBuildBr(b, b_find_start);
	}
	else
	{
		LLVMValueRef v_params[3];

		/* branch if not all columns available */
		LLVMBuildCondBr(b,
						LLVMBuildICmp(b, LLVMIntULT,
									  v_maxatt,
									  l_int16_const(natts),
									  ""),
						b_adjust_unavail_cols,
						b_find_start);

		/* if not, memset tts_isnull of relevant cols to true */
		LLVMPositionBuilderAtEnd(b, b_adjust_unavail_cols);

		v_params[0] = v_slot;
		v_params[1] = LLVMBuildZExt(b, v_maxatt, LLVMInt32Type(), "");
		v_params[2] = l_int32_const(natts);
		LLVMBuildCall(b, llvm_get_decl(mod, FuncSlotGetmissingattrs),
					  v_params, lengthof(v_params), "");
		LLVMBuildBr(b, b_find_start);
	}

	LLVMPositionBuilderAtEnd(b, b_find_start);

	v_nvalid = LLVMBuildLoad(b, v_nvalidp, "");

	/*
	 * Build switch to go from nvalid to the right startblock.  Callers
	 * currently don't have the knowledge, but it'd be good for performance to
	 * avoid this check when it's known that the slot is empty (e.g. in scan
	 * nodes).
	 */
	if (true)
	{
		LLVMValueRef v_switch = LLVMBuildSwitch(b, v_nvalid,
												b_dead, natts);

		for (attnum = 0; attnum < natts; attnum++)
		{
			LLVMValueRef v_attno = l_int32_const(attnum);

			LLVMAddCase(v_switch, v_attno, attcheckattnoblocks[attnum]);
		}

	}
	else
	{
		/* jump from entry block to first block */
		LLVMBuildBr(b, attcheckattnoblocks[0]);
	}

	LLVMPositionBuilderAtEnd(b, b_dead);
	LLVMBuildUnreachable(b);

	/*
	 * Iterate over each attribute that needs to be deformed, build code to
	 * deform it.
	 */
	for (attnum = 0; attnum < natts; attnum++)
	{
		Form_pg_attribute att = TupleDescAttr(desc, attnum);
		LLVMValueRef v_incby;
		int			alignto;
		LLVMValueRef l_attno = l_int16_const(attnum);
		LLVMValueRef v_attdatap;
		LLVMValueRef v_resultp;

		/* build block checking whether we did all the necessary attributes */
		LLVMPositionBuilderAtEnd(b, attcheckattnoblocks[attnum]);

		/*
		 * If this is the first attribute, slot->tts_nvalid was 0. Therefore
		 * reset offset to 0 to, it be from a previous execution.
		 */
		if (attnum == 0)
		{
			LLVMBuildStore(b, l_sizet_const(0), v_offp);
		}

		/*
		 * Build check whether column is available (i.e. whether the tuple has
		 * that many columns stored). We can avoid the branch if we know
		 * there's a subsequent NOT NULL column.
		 */
		if (attnum <= guaranteed_column_number)
		{
			LLVMBuildBr(b, attstartblocks[attnum]);
		}
		else
		{
			LLVMValueRef v_islast;

			v_islast = LLVMBuildICmp(b, LLVMIntUGE,
									 l_attno,
									 v_maxatt,
									 "heap_natts");
			LLVMBuildCondBr(b, v_islast, b_out, attstartblocks[attnum]);
		}
		LLVMPositionBuilderAtEnd(b, attstartblocks[attnum]);

		/*
		 * Check for nulls if necessary. No need to take missing attributes
		 * into account, because in case they're present the heaptuple's natts
		 * would have indicated that a slot_getmissingattrs() is needed.
		 */
		if (!att->attnotnull)
		{
			LLVMBasicBlockRef b_ifnotnull;
			LLVMBasicBlockRef b_ifnull;
			LLVMBasicBlockRef b_next;
			LLVMValueRef v_attisnull;
			LLVMValueRef v_nullbyteno;
			LLVMValueRef v_nullbytemask;
			LLVMValueRef v_nullbyte;
			LLVMValueRef v_nullbit;

			b_ifnotnull = attcheckalignblocks[attnum];
			b_ifnull = attisnullblocks[attnum];

			if (attnum + 1 == natts)
				b_next = b_out;
			else
				b_next = attcheckattnoblocks[attnum + 1];

			v_nullbyteno = l_int32_const(attnum >> 3);
			v_nullbytemask = l_int8_const(1 << ((attnum) & 0x07));
			v_nullbyte = l_load_gep1(b, v_bits, v_nullbyteno, "attnullbyte");

			v_nullbit = LLVMBuildICmp(b,
									  LLVMIntEQ,
									  LLVMBuildAnd(b, v_nullbyte, v_nullbytemask, ""),
									  l_int8_const(0),
									  "attisnull");

			v_attisnull = LLVMBuildAnd(b, v_hasnulls, v_nullbit, "");

			LLVMBuildCondBr(b, v_attisnull, b_ifnull, b_ifnotnull);

			LLVMPositionBuilderAtEnd(b, b_ifnull);

			/* store null-byte */
			LLVMBuildStore(b,
						   l_int8_const(1),
						   LLVMBuildGEP(b, v_tts_nulls, &l_attno, 1, ""));
			/* store zero datum */
			LLVMBuildStore(b,
						   l_sizet_const(0),
						   LLVMBuildGEP(b, v_tts_values, &l_attno, 1, ""));

			LLVMBuildBr(b, b_next);
			attguaranteedalign = false;
		}
		else
		{
示例#20
0
文件: gendesc.c 项目: npruehs/ponyc
static LLVMValueRef make_unbox_function(compile_t* c, reach_type_t* t,
  reach_method_t* m)
{
  // Create a new unboxing function that forwards to the real function.
  LLVMTypeRef f_type = LLVMGetElementType(LLVMTypeOf(m->func));
  int count = LLVMCountParamTypes(f_type);

  // Leave space for a receiver if it's a constructor vtable entry.
  size_t buf_size = (count + 1) * sizeof(LLVMTypeRef);
  LLVMTypeRef* params = (LLVMTypeRef*)ponyint_pool_alloc_size(buf_size);
  LLVMGetParamTypes(f_type, params);
  LLVMTypeRef ret_type = LLVMGetReturnType(f_type);

  const char* unbox_name = genname_unbox(m->full_name);

  if(ast_id(m->r_fun) != TK_NEW)
  {
    // It's the same type, but it takes the boxed type instead of the primitive
    // type as the receiver.
    params[0] = t->structure_ptr;
  } else {
    // For a constructor, the unbox_fun has a receiver, even though the real
    // method does not.
    memmove(&params[1], &params[0], count * sizeof(LLVMTypeRef*));
    params[0] = t->structure_ptr;
    count++;
  }

  LLVMTypeRef unbox_type = LLVMFunctionType(ret_type, params, count, false);
  LLVMValueRef unbox_fun = codegen_addfun(c, unbox_name, unbox_type);
  codegen_startfun(c, unbox_fun, NULL, NULL);

  // Extract the primitive type from element 1 and call the real function.
  LLVMValueRef this_ptr = LLVMGetParam(unbox_fun, 0);
  LLVMValueRef primitive_ptr = LLVMBuildStructGEP(c->builder, this_ptr, 1, "");
  LLVMValueRef primitive = LLVMBuildLoad(c->builder, primitive_ptr, "");

  LLVMValueRef* args = (LLVMValueRef*)ponyint_pool_alloc_size(buf_size);

  if(ast_id(m->r_fun) != TK_NEW)
  {
    // If it's not a constructor, pass the extracted primitive as the receiver.
    args[0] = primitive;

    for(int i = 1; i < count; i++)
      args[i] = LLVMGetParam(unbox_fun, i);
  } else {
    count--;

    for(int i = 0; i < count; i++)
      args[i] = LLVMGetParam(unbox_fun, i + 1);
  }

  LLVMValueRef result = codegen_call(c, m->func, args, count);
  LLVMBuildRet(c->builder, result);
  codegen_finishfun(c);

  ponyint_pool_free_size(buf_size, params);
  ponyint_pool_free_size(buf_size, args);
  return LLVMConstBitCast(unbox_fun, c->void_ptr);
}
示例#21
0
文件: gendesc.c 项目: npruehs/ponyc
static LLVMValueRef desc_field(compile_t* c, LLVMValueRef desc, int index)
{
  LLVMValueRef ptr = LLVMBuildStructGEP(c->builder, desc, index, "");
  return LLVMBuildLoad(c->builder, ptr, "");
}
示例#22
0
文件: struct.c 项目: ksandstr/muidl
void decode_packed_struct_inline(
	struct llvm_ctx *ctx,
	LLVMValueRef dst,
	IDL_tree ctyp,
	LLVMValueRef first_mr,
	LLVMValueRef bit_offset)
{
	const struct packed_format *fmt = packed_format_of(ctyp);
	assert(fmt != NULL);
	char **names = NULL;
	T s_type = llvm_struct_type(ctx, &names, ctyp);
	int names_len = 0;
	while(names[names_len] != NULL) names_len++;
	assert(names_len == fmt->num_items);
	assert(LLVMCountStructElementTypes(s_type) == names_len);
	T types[MAX(names_len, 1)];
	LLVMGetStructElementTypes(s_type, types);
	int cur_word = 0;
	V wordval = NULL;
	for(int i=0; i<fmt->num_items; i++) {
		const struct packed_item *pi = fmt->items[i];
		int field_ix = strv_lookup(names, pi->name);
		if(field_ix < 0) {
			fprintf(stderr, "%s: not the way to go.\n", __func__);
			abort();
		}

		V start_mr = LLVMBuildAdd(ctx->builder, first_mr,
			CONST_INT(pi->word), tmp_f(ctx->pr, "%s.start.mr", pi->name));
		V dstptr = LLVMBuildStructGEP(ctx->builder, dst, field_ix,
			tmp_f(ctx->pr, "%s.start.ptr", pi->name));
		if(pi->dim > 1) {
			/* array types. TODO */
			fprintf(stderr, "%s: struct-member arrays not implemented\n",
				__func__);
			abort();
		} else if(IDL_NODE_TYPE(pi->type) == IDLN_TYPE_STRUCT) {
			decode_packed_struct(ctx, &dstptr, pi->type, start_mr,
				CONST_INT(pi->bit));
		} else if(IDL_NODE_TYPE(pi->type) == IDLN_TYPE_UNION) {
			fprintf(stderr, "%s: union-member types not implemented\n",
				__func__);
			abort();
		} else if(IS_LONGLONG_TYPE(pi->type)) {
			/* long long on a 32-bit architecture. can be #ifdef'd out for
			 * 64-bit targets, where it'd be just a value type.
			 */
			V dtmp = NULL;
			build_read_ipc_parameter(ctx, &dtmp, pi->type,
				start_mr);
			LLVMBuildStore(ctx->builder, dtmp, dstptr);
		} else if(is_value_type(pi->type)) {
			/* word-size and smaller items. */
			if(cur_word != pi->word || wordval == NULL) {
				cur_word = pi->word;
				V old_wv = wordval;
				wordval = build_ipc_input_val_ix(ctx, start_mr,
					tmp_f(ctx->pr, "st.word%d", pi->word));
				if(old_wv == NULL) {
					/* shift it down, since we start at an offset. */
					wordval = LLVMBuildLShr(ctx->builder, wordval,
						bit_offset, "st.bitoffs.shifted");
				}
			}
			V subval = LLVMBuildLShr(ctx->builder, wordval,
				CONST_INT(pi->bit),
				tmp_f(ctx->pr, "st.word%d.shr%d", pi->word, pi->bit));
			if(pi->len < BITS_PER_WORD) {
				subval = LLVMBuildAnd(ctx->builder, subval,
					CONST_WORD((1 << pi->len) - 1),
					tmp_f(ctx->pr, "st.word%d.s%d.m%d", pi->word, pi->bit,
						pi->len));
			}
			subval = LLVMBuildTruncOrBitCast(ctx->builder, subval,
				types[field_ix], "st.val.cast");
			LLVMBuildStore(ctx->builder, subval, dstptr);
		} else if(IS_MAPGRANT_TYPE(pi->type)) {
			/* two words, like peas in a pod */
			assert(pi->bit == 0);
			build_read_ipc_parameter(ctx, &dstptr, pi->type, start_mr);
		} else {
			NOTDEFINED(pi->type);
		}
	}
	g_strfreev(names);
}
示例#23
0
文件: struct.c 项目: ksandstr/muidl
LLVMValueRef encode_packed_struct_inline(
	struct llvm_ctx *ctx,
	LLVMValueRef first_mr_word,
	LLVMValueRef bit_offset,
	IDL_tree ctyp,
	LLVMValueRef src_base)
{
	const struct packed_format *fmt = packed_format_of(ctyp);
	assert(fmt != NULL);

	/* for sub-word items, bit_offset is required. for word and larger ones it
	 * is forbidden.
	 */
	assert(bit_offset == NULL || (fmt->num_bits < BITS_PER_WORD
		&& fmt->num_words == 1));
	assert(bit_offset != NULL || fmt->num_bits >= BITS_PER_WORD);

	char **names = NULL;
	T s_type = llvm_struct_type(ctx, &names, ctyp);
	int names_len = 0;
	while(names[names_len] != NULL) names_len++;
	assert(names_len == fmt->num_items);
	assert(LLVMCountStructElementTypes(s_type) == names_len);
	T types[MAX(names_len, 1)];
	LLVMGetStructElementTypes(s_type, types);
	V wordval = CONST_WORD(0);
	int cur_word = 0, wordval_fill = 0;
	for(int i=0; i<fmt->num_items; i++) {
		assert(wordval_fill <= BITS_PER_WORD);

		const struct packed_item *pi = fmt->items[i];
		assert(bit_offset == NULL || pi->word == 0);
		int field_ix = strv_lookup(names, pi->name);
		if(field_ix < 0) {
			fprintf(stderr, "%s: not the way to go.\n", __func__);
			abort();
		}

		V start_mr = NULL;
		if(bit_offset == NULL) {
			start_mr = LLVMBuildAdd(ctx->builder, first_mr_word,
				CONST_INT(pi->word), "word.ix");
		}

		/* flush previous word? */
		if(wordval_fill > 0 && cur_word != pi->word) {
			assert(bit_offset == NULL);
			V mr_ix = LLVMBuildAdd(ctx->builder, first_mr_word,
				CONST_INT(cur_word), tmp_f(ctx->pr, "flush.w%d.ix", cur_word));
			LLVMBuildStore(ctx->builder, wordval, UTCB_ADDR_VAL(ctx, mr_ix,
				tmp_f(ctx->pr, "flush.w%d.addr", cur_word)));
			wordval = CONST_WORD(0);
			wordval_fill = 0;
			cur_word = pi->word;
		}

		V valptr = LLVMBuildStructGEP(ctx->builder, src_base, field_ix,
			tmp_f(ctx->pr, "%s.start.ptr", pi->name));
		if(pi->dim > 1) {
			/* array types. TODO */
			fprintf(stderr, "%s: struct-member arrays not implemented\n",
				__func__);
			abort();
		} else if(IDL_NODE_TYPE(pi->type) == IDLN_TYPE_STRUCT) {
			if(pi->len < BITS_PER_WORD) {
				wordval = encode_packed_struct(ctx, wordval,
					CONST_INT(pi->bit), pi->type, valptr);
				wordval_fill = (wordval_fill + pi->len) % BITS_PER_WORD;
			} else {
				encode_packed_struct(ctx, start_mr, NULL, pi->type, valptr);
			}
		} else if(IDL_NODE_TYPE(pi->type) == IDLN_TYPE_UNION) {
			fprintf(stderr, "%s: union-member types not implemented\n",
				__func__);
			abort();
		} else if(IS_LONGLONG_TYPE(pi->type)) {
			assert(bit_offset == NULL);
			assert(pi->bit == 0 && wordval_fill == 0);
			V val = LLVMBuildLoad(ctx->builder, valptr, "longlong.fld");
			build_write_ipc_parameter(ctx, start_mr, pi->type, &val);
		} else if(is_value_type(pi->type)) {
			/* word-size and smaller items. */
			V val = LLVMBuildLoad(ctx->builder, valptr,
				tmp_f(ctx->pr, "fld.%s.val", pi->name));
			val = LLVMBuildZExtOrBitCast(ctx->builder, val, ctx->wordt,
				tmp_f(ctx->pr, "fld.%s.word", pi->name));
			V bitoffs = CONST_INT(pi->bit);
			V shifted = LLVMBuildShl(ctx->builder, val, bitoffs,
				tmp_f(ctx->pr, "fld.%s.shifted", pi->name));
			wordval = LLVMBuildOr(ctx->builder, shifted, wordval,
				tmp_f(ctx->pr, "word%d.%s.merged", cur_word, pi->name));
			wordval_fill += pi->len;
		} else if(IS_MAPGRANT_TYPE(pi->type)) {
			assert(bit_offset == NULL);
			assert(pi->bit == 0 && wordval_fill == 0);
			build_write_ipc_parameter(ctx, start_mr, pi->type, &valptr);
		} else {
			NOTDEFINED(pi->type);
		}
	}

	if(bit_offset == NULL && wordval_fill > 0) {
		/* flush final partial word if the last item was sub-word */
		V mr_ix = LLVMBuildAdd(ctx->builder, first_mr_word,
			CONST_INT(cur_word), tmp_f(ctx->pr, "flush.w%d.ix", cur_word));
		LLVMBuildStore(ctx->builder, wordval, UTCB_ADDR_VAL(ctx, mr_ix,
			tmp_f(ctx->pr, "flush.w%d.addr", cur_word)));
		wordval = NULL;
	} else if(bit_offset != NULL) {
		/* shift and merge */
		wordval = LLVMBuildOr(ctx->builder, first_mr_word,
			LLVMBuildShl(ctx->builder, wordval, bit_offset, "short.shifted"),
			"rv.merged");
	}

	g_strfreev(names);

	return wordval;
}
示例#24
0
文件: genexe.c 项目: enigma/ponyc
static void gen_main(compile_t* c, reach_type_t* t_main,
  reach_type_t* t_env)
{
  LLVMTypeRef params[3];
  params[0] = c->i32;
  params[1] = LLVMPointerType(LLVMPointerType(c->i8, 0), 0);
  params[2] = LLVMPointerType(LLVMPointerType(c->i8, 0), 0);

  LLVMTypeRef ftype = LLVMFunctionType(c->i32, params, 3, false);
  LLVMValueRef func = LLVMAddFunction(c->module, "main", ftype);

  codegen_startfun(c, func, NULL, NULL);

  LLVMValueRef args[4];
  args[0] = LLVMGetParam(func, 0);
  LLVMSetValueName(args[0], "argc");

  args[1] = LLVMGetParam(func, 1);
  LLVMSetValueName(args[1], "argv");

  args[2] = LLVMGetParam(func, 2);
  LLVMSetValueName(args[2], "envp");

  // Initialise the pony runtime with argc and argv, getting a new argc.
  args[0] = gencall_runtime(c, "pony_init", args, 2, "argc");

  // Create the main actor and become it.
  LLVMValueRef ctx = gencall_runtime(c, "pony_ctx", NULL, 0, "");
  codegen_setctx(c, ctx);
  LLVMValueRef main_actor = create_main(c, t_main, ctx);

  // Create an Env on the main actor's heap.
  reach_method_t* m = reach_method(t_env, TK_NONE, c->str__create, NULL);

  LLVMValueRef env_args[4];
  env_args[0] = gencall_alloc(c, t_env);
  env_args[1] = args[0];
  env_args[2] = LLVMBuildBitCast(c->builder, args[1], c->void_ptr, "");
  env_args[3] = LLVMBuildBitCast(c->builder, args[2], c->void_ptr, "");
  codegen_call(c, m->func, env_args, 4);
  LLVMValueRef env = env_args[0];

  // Run primitive initialisers using the main actor's heap.
  primitive_call(c, c->str__init);

  // Create a type for the message.
  LLVMTypeRef f_params[4];
  f_params[0] = c->i32;
  f_params[1] = c->i32;
  f_params[2] = c->void_ptr;
  f_params[3] = LLVMTypeOf(env);
  LLVMTypeRef msg_type = LLVMStructTypeInContext(c->context, f_params, 4,
    false);
  LLVMTypeRef msg_type_ptr = LLVMPointerType(msg_type, 0);

  // Allocate the message, setting its size and ID.
  uint32_t index = reach_vtable_index(t_main, c->str_create);
  size_t msg_size = (size_t)LLVMABISizeOfType(c->target_data, msg_type);
  args[0] = LLVMConstInt(c->i32, ponyint_pool_index(msg_size), false);
  args[1] = LLVMConstInt(c->i32, index, false);
  LLVMValueRef msg = gencall_runtime(c, "pony_alloc_msg", args, 2, "");
  LLVMValueRef msg_ptr = LLVMBuildBitCast(c->builder, msg, msg_type_ptr, "");

  // Set the message contents.
  LLVMValueRef env_ptr = LLVMBuildStructGEP(c->builder, msg_ptr, 3, "");
  LLVMBuildStore(c->builder, env, env_ptr);

  // Trace the message.
  args[0] = ctx;
  gencall_runtime(c, "pony_gc_send", args, 1, "");

  args[0] = ctx;
  args[1] = LLVMBuildBitCast(c->builder, env, c->object_ptr, "");
  args[2] = LLVMBuildBitCast(c->builder, t_env->desc, c->descriptor_ptr, "");
  args[3] = LLVMConstInt(c->i32, PONY_TRACE_IMMUTABLE, false);
  gencall_runtime(c, "pony_traceknown", args, 4, "");

  args[0] = ctx;
  gencall_runtime(c, "pony_send_done", args, 1, "");

  // Send the message.
  args[0] = ctx;
  args[1] = main_actor;
  args[2] = msg;
  gencall_runtime(c, "pony_sendv", args, 3, "");

  // Start the runtime.
  LLVMValueRef zero = LLVMConstInt(c->i32, 0, false);
  LLVMValueRef rc = gencall_runtime(c, "pony_start", &zero, 1, "");

  // Run primitive finalisers. We create a new main actor as a context to run
  // the finalisers in, but we do not initialise or schedule it.
  if(need_primitive_call(c, c->str__final))
  {
    LLVMValueRef final_actor = create_main(c, t_main, ctx);
    primitive_call(c, c->str__final);
    args[0] = final_actor;
    gencall_runtime(c, "ponyint_destroy", args, 1, "");
  }

  // Return the runtime exit code.
  LLVMBuildRet(c->builder, rc);

  codegen_finishfun(c);

  // External linkage for main().
  LLVMSetLinkage(func, LLVMExternalLinkage);
}
示例#25
0
static void serialise(compile_t* c, reach_type_t* t, LLVMValueRef ctx,
  LLVMValueRef object, LLVMValueRef offset)
{
  LLVMTypeRef structure = t->structure;
  int extra = 0;

  switch(t->underlying)
  {
    case TK_PRIMITIVE:
    {
      genserialise_typeid(c, t, offset);

      if(t->primitive != NULL)
      {
        LLVMValueRef field = LLVMBuildStructGEP(c->builder, object, 1, "");
        LLVMValueRef f_size = LLVMConstInt(c->intptr,
          LLVMOffsetOfElement(c->target_data, structure, 1), false);
        LLVMValueRef f_offset = LLVMBuildInBoundsGEP(c->builder, offset,
                                                     &f_size, 1, "");

        genserialise_element(c, t, false, ctx, field, f_offset);
      }
      return;
    }

    case TK_CLASS:
    {
      genserialise_typeid(c, t, offset);
      extra++;
      break;
    }

    case TK_ACTOR:
    {
      // Skip the actor pad.
      genserialise_typeid(c, t, offset);
      extra += 2;
      break;
    }

    case TK_TUPLETYPE:
    {
      // Get the tuple primitive type.
      if(LLVMTypeOf(object) == t->structure_ptr)
      {
        genserialise_typeid(c, t, offset);
        object = LLVMBuildStructGEP(c->builder, object, 1, "");
        LLVMValueRef size = LLVMConstInt(c->intptr,
          LLVMOffsetOfElement(c->target_data, structure, 1), false);
        offset = LLVMBuildInBoundsGEP(c->builder, offset, &size, 1, "");
      }

      structure = t->primitive;
      break;
    }

    default: {}
  }

  for(uint32_t i = 0; i < t->field_count; i++)
  {
    LLVMValueRef field = LLVMBuildStructGEP(c->builder, object, i + extra, "");
    LLVMValueRef f_size = LLVMConstInt(c->intptr,
      LLVMOffsetOfElement(c->target_data, structure, i + extra), false);
    LLVMValueRef f_offset = LLVMBuildInBoundsGEP(c->builder, offset, &f_size,
      1, "");

    genserialise_element(c, t->fields[i].type, t->fields[i].embed,
      ctx, field, f_offset);
  }
}
示例#26
0
void genprim_array_deserialise(compile_t* c, reach_type_t* t)
{
  // Generate the deserisalise function.
  t->deserialise_fn = codegen_addfun(c, genname_serialise(t->name),
    c->trace_type);

  codegen_startfun(c, t->deserialise_fn, NULL, NULL);
  LLVMSetFunctionCallConv(t->deserialise_fn, LLVMCCallConv);

  LLVMValueRef ctx = LLVMGetParam(t->deserialise_fn, 0);
  LLVMValueRef arg = LLVMGetParam(t->deserialise_fn, 1);

  LLVMValueRef object = LLVMBuildBitCast(c->builder, arg, t->structure_ptr,
    "");
  gendeserialise_typeid(c, t, object);

  // Deserialise the array contents.
  LLVMValueRef alloc = field_value(c, object, 2);
  LLVMValueRef ptr_offset = field_value(c, object, 3);
  ptr_offset = LLVMBuildPtrToInt(c->builder, ptr_offset, c->intptr, "");

  ast_t* typeargs = ast_childidx(t->ast, 2);
  ast_t* typearg = ast_child(typeargs);

  reach_type_t* t_elem = reach_type(c->reach, typearg);
  size_t abisize = (size_t)LLVMABISizeOfType(c->target_data, t_elem->use_type);
  LLVMValueRef l_size = LLVMConstInt(c->intptr, abisize, false);

  LLVMValueRef args[3];
  args[0] = ctx;
  args[1] = ptr_offset;
  args[2] = LLVMBuildMul(c->builder, alloc, l_size, "");
  LLVMValueRef ptr = gencall_runtime(c, "pony_deserialise_block", args, 3, "");

  LLVMValueRef ptr_loc = LLVMBuildStructGEP(c->builder, object, 3, "");
  LLVMBuildStore(c->builder, ptr, ptr_loc);

  if((t_elem->underlying == TK_PRIMITIVE) && (t_elem->primitive != NULL))
  {
    // Do nothing. A memcpy is sufficient.
  } else {
    LLVMValueRef size = field_value(c, object, 1);
    ptr = LLVMBuildBitCast(c->builder, ptr,
      LLVMPointerType(t_elem->use_type, 0), "");

    LLVMBasicBlockRef entry_block = LLVMGetInsertBlock(c->builder);
    LLVMBasicBlockRef cond_block = codegen_block(c, "cond");
    LLVMBasicBlockRef body_block = codegen_block(c, "body");
    LLVMBasicBlockRef post_block = codegen_block(c, "post");

    LLVMBuildBr(c->builder, cond_block);

    // While the index is less than the size, deserialise an element. The
    // initial index when coming from the entry block is zero.
    LLVMPositionBuilderAtEnd(c->builder, cond_block);
    LLVMValueRef phi = LLVMBuildPhi(c->builder, c->intptr, "");
    LLVMValueRef zero = LLVMConstInt(c->intptr, 0, false);
    LLVMAddIncoming(phi, &zero, &entry_block, 1);
    LLVMValueRef test = LLVMBuildICmp(c->builder, LLVMIntULT, phi, size, "");
    LLVMBuildCondBr(c->builder, test, body_block, post_block);

    // The phi node is the index. Get the element and deserialise it.
    LLVMPositionBuilderAtEnd(c->builder, body_block);
    LLVMValueRef elem_ptr = LLVMBuildGEP(c->builder, ptr, &phi, 1, "");
    gendeserialise_element(c, t_elem, false, ctx, elem_ptr);

    // Add one to the phi node and branch back to the cond block.
    LLVMValueRef one = LLVMConstInt(c->intptr, 1, false);
    LLVMValueRef inc = LLVMBuildAdd(c->builder, phi, one, "");
    body_block = LLVMGetInsertBlock(c->builder);
    LLVMAddIncoming(phi, &inc, &body_block, 1);
    LLVMBuildBr(c->builder, cond_block);

    LLVMPositionBuilderAtEnd(c->builder, post_block);
  }

  LLVMBuildRetVoid(c->builder);
  codegen_finishfun(c);
}
示例#27
0
static LLVMTypeRef send_message(compile_t* c, ast_t* params, LLVMValueRef to,
  LLVMValueRef func, uint32_t index)
{
  // Get the parameter types.
  LLVMTypeRef f_type = LLVMGetElementType(LLVMTypeOf(func));
  int count = LLVMCountParamTypes(f_type) + 2;

  size_t buf_size = count * sizeof(LLVMTypeRef);
  LLVMTypeRef* f_params = (LLVMTypeRef*)ponyint_pool_alloc_size(buf_size);
  LLVMGetParamTypes(f_type, &f_params[2]);

  // The first one becomes the message size, the second the message ID.
  f_params[0] = c->i32;
  f_params[1] = c->i32;
  f_params[2] = c->void_ptr;
  LLVMTypeRef msg_type = LLVMStructTypeInContext(c->context, f_params, count,
    false);
  LLVMTypeRef msg_type_ptr = LLVMPointerType(msg_type, 0);
  ponyint_pool_free_size(buf_size, f_params);

  // Allocate the message, setting its size and ID.
  size_t msg_size = (size_t)LLVMABISizeOfType(c->target_data, msg_type);
  LLVMValueRef args[3];

  args[0] = LLVMConstInt(c->i32, ponyint_pool_index(msg_size), false);
  args[1] = LLVMConstInt(c->i32, index, false);
  LLVMValueRef msg = gencall_runtime(c, "pony_alloc_msg", args, 2, "");
  LLVMValueRef msg_ptr = LLVMBuildBitCast(c->builder, msg, msg_type_ptr, "");

  for(int i = 3; i < count; i++)
  {
    LLVMValueRef arg = LLVMGetParam(func, i - 2);
    LLVMValueRef arg_ptr = LLVMBuildStructGEP(c->builder, msg_ptr, i, "");
    LLVMBuildStore(c->builder, arg, arg_ptr);
  }

  // Trace while populating the message contents.
  LLVMValueRef ctx = codegen_ctx(c);

  ast_t* param = ast_child(params);
  bool need_trace = false;

  while(param != NULL)
  {
    if(gentrace_needed(ast_type(param)))
    {
      need_trace = true;
      break;
    }

    param = ast_sibling(param);
  }

  if(need_trace)
  {
    gencall_runtime(c, "pony_gc_send", &ctx, 1, "");
    param = ast_child(params);

    for(int i = 3; i < count; i++)
    {
      LLVMValueRef arg = LLVMGetParam(func, i - 2);
      gentrace(c, ctx, arg, ast_type(param));
      param = ast_sibling(param);
    }

    gencall_runtime(c, "pony_send_done", &ctx, 1, "");
  }

  // Send the message.
  args[0] = ctx;
  args[1] = LLVMBuildBitCast(c->builder, to, c->object_ptr, "");
  args[2] = msg;
  gencall_runtime(c, "pony_sendv", args, 3, "");

  // Return the type of the message.
  return msg_type_ptr;
}
示例#28
0
文件: gendesc.c 项目: npruehs/ponyc
LLVMValueRef gendesc_fetch(compile_t* c, LLVMValueRef object)
{
  LLVMValueRef ptr = LLVMBuildStructGEP(c->builder, object, 0, "");
  return LLVMBuildLoad(c->builder, ptr, "");
}
示例#29
0
static LLVMValueRef field_value(compile_t* c, LLVMValueRef object, int index)
{
  LLVMValueRef field = LLVMBuildStructGEP(c->builder, object, index, "");
  return LLVMBuildLoad(c->builder, field, "");
}
示例#30
0
void gen_send_message(compile_t* c, reach_method_t* m, LLVMValueRef orig_args[],
  LLVMValueRef cast_args[], ast_t* args_ast)
{
  // Allocate the message, setting its size and ID.
  size_t msg_size = (size_t)LLVMABISizeOfType(c->target_data, m->msg_type);
  LLVMTypeRef msg_type_ptr = LLVMPointerType(m->msg_type, 0);

  LLVMValueRef msg_args[3];

  msg_args[0] = LLVMConstInt(c->i32, ponyint_pool_index(msg_size), false);
  msg_args[1] = LLVMConstInt(c->i32, m->vtable_index, false);
  LLVMValueRef msg = gencall_runtime(c, "pony_alloc_msg", msg_args, 2, "");
  LLVMValueRef msg_ptr = LLVMBuildBitCast(c->builder, msg, msg_type_ptr, "");

  for(unsigned int i = 0; i < m->param_count; i++)
  {
    LLVMValueRef arg_ptr = LLVMBuildStructGEP(c->builder, msg_ptr, i + 3, "");
    LLVMBuildStore(c->builder, cast_args[i+1], arg_ptr);
  }

  // Trace while populating the message contents.
  ast_t* params = ast_childidx(m->r_fun, 3);
  ast_t* param = ast_child(params);
  ast_t* arg_ast = ast_child(args_ast);
  bool need_trace = false;

  while(param != NULL)
  {
    if(gentrace_needed(c, ast_type(arg_ast), ast_type(param)))
    {
      need_trace = true;
      break;
    }

    param = ast_sibling(param);
    arg_ast = ast_sibling(arg_ast);
  }

  LLVMValueRef ctx = codegen_ctx(c);

  if(need_trace)
  {
    gencall_runtime(c, "pony_gc_send", &ctx, 1, "");
    param = ast_child(params);
    arg_ast = ast_child(args_ast);

    for(size_t i = 0; i < m->param_count; i++)
    {
      gentrace(c, ctx, orig_args[i+1], cast_args[i+1], ast_type(arg_ast),
        ast_type(param));
      param = ast_sibling(param);
      arg_ast = ast_sibling(arg_ast);
    }

    gencall_runtime(c, "pony_send_done", &ctx, 1, "");
  }

  // Send the message.
  msg_args[0] = ctx;
  msg_args[1] = LLVMBuildBitCast(c->builder, cast_args[0], c->object_ptr, "");
  msg_args[2] = msg;
  gencall_runtime(c, "pony_sendv", msg_args, 3, "");
}