Beispiel #1
0
LLVMValueRef gen_int(compile_t* c, ast_t* ast)
{
  ast_t* type = ast_type(ast);

  gentype_t g;

  if(!gentype(c, type, &g))
    return NULL;

  __uint128_t value = ast_int(ast);

  uint64_t low, high;
#if !defined(HAVE_STRUCT_INT128)
  low = (uint64_t)value;
  high = (uint64_t)(value >> 64);
#else
  low = value.low;
  high = value.high;
#endif

  LLVMValueRef vlow = LLVMConstInt(c->i128, low, false);
  LLVMValueRef vhigh = LLVMConstInt(c->i128, high, false);
  LLVMValueRef shift = LLVMConstInt(c->i128, 64, false);
  vhigh = LLVMConstShl(vhigh, shift);
  vhigh = LLVMConstAdd(vhigh, vlow);

  if(g.primitive == c->i128)
    return vhigh;

  if((g.primitive == c->f32) || (g.primitive == c->f64))
    return LLVMConstUIToFP(vhigh, g.primitive);

  return LLVMConstTrunc(vhigh, g.primitive);
}
Beispiel #2
0
static bool tuple_access(ast_t* ast)
{
  // Left is a postfix expression, right is a lookup name.
  ast_t* left = ast_child(ast);
  ast_t* right = ast_sibling(left);
  ast_t* type = ast_type(left);

  if(is_typecheck_error(type))
    return false;

  // Change the lookup name to an integer index.
  if(!make_tuple_index(&right))
  {
    ast_error(right,
      "lookup on a tuple must take the form _X, where X is an integer");
    return false;
  }

  // Make sure our index is in bounds.
  type = ast_childidx(type, (size_t)ast_int(right));

  if(type == NULL)
  {
    ast_error(right, "tuple index is out of bounds");
    return false;
  }

  ast_setid(ast, TK_FLETREF);
  ast_settype(ast, type);
  ast_inheritflags(ast);
  return true;
}
Beispiel #3
0
static LLVMValueRef make_tupleelemptr(compile_t* c, LLVMValueRef l_value,
  ast_t* l_type, ast_t* right)
{
  pony_assert(ast_id(l_type) == TK_TUPLETYPE);
  int index = (int)ast_int(right)->low;

  return LLVMBuildExtractValue(c->builder, l_value, index, "");
}
Beispiel #4
0
static bool tuple_access(pass_opt_t* opt, ast_t* ast)
{
  // Left is a postfix expression, right is a lookup name.
  ast_t* left = ast_child(ast);
  ast_t* right = ast_sibling(left);
  ast_t* type = ast_type(left);

  if(is_typecheck_error(type))
    return false;

  // Change the lookup name to an integer index.
  if(!make_tuple_index(&right))
  {
    ast_error(opt->check.errors, right,
      "lookup on a tuple must take the form _X, where X is an integer");
    return false;
  }

  // Make sure our index is in bounds.  make_tuple_index automatically shifts
  // from one indexed to zero, so we have to use -1 and >= for our comparisons.
  size_t right_idx = (size_t)ast_int(right)->low;
  size_t tuple_size = ast_childcount(type);

  if (right_idx == (size_t)-1)
  {
    ast_error(opt->check.errors, right,
      "tuples are one indexed not zero indexed. Did you mean _1?");
    return false;
  }
  else if (right_idx >= tuple_size)
  {
    ast_error(opt->check.errors, right, "tuple index " __zu " is out of "
      "valid range. Valid range is [1, " __zu "]", right_idx, tuple_size);
    return false;
  }

  type = ast_childidx(type, right_idx);
  assert(type != NULL);

  ast_setid(ast, TK_FLETREF);
  ast_settype(ast, type);
  ast_inheritflags(ast);
  return true;
}
Beispiel #5
0
LLVMValueRef gen_int(compile_t* c, ast_t* ast)
{
  ast_t* type = ast_type(ast);
  reach_type_t* t = reach_type(c->reach, type);

  lexint_t* value = ast_int(ast);
  LLVMValueRef vlow = LLVMConstInt(c->i128, value->low, false);
  LLVMValueRef vhigh = LLVMConstInt(c->i128, value->high, false);
  LLVMValueRef shift = LLVMConstInt(c->i128, 64, false);
  vhigh = LLVMConstShl(vhigh, shift);
  vhigh = LLVMConstAdd(vhigh, vlow);

  if(t->primitive == c->i128)
    return vhigh;

  if((t->primitive == c->f32) || (t->primitive == c->f64))
    return LLVMConstUIToFP(vhigh, t->primitive);

  return LLVMConstTrunc(vhigh, t->primitive);
}
Beispiel #6
0
LLVMValueRef gen_int(compile_t* c, ast_t* ast)
{
  ast_t* type = deferred_reify(c->frame->reify, ast_type(ast), c->opt);
  reach_type_t* t = reach_type(c->reach, type);
  ast_free_unattached(type);
  compile_type_t* c_t = (compile_type_t*)t->c_type;

  lexint_t* value = ast_int(ast);
  LLVMValueRef vlow = LLVMConstInt(c->i128, value->low, false);
  LLVMValueRef vhigh = LLVMConstInt(c->i128, value->high, false);
  LLVMValueRef shift = LLVMConstInt(c->i128, 64, false);
  vhigh = LLVMConstShl(vhigh, shift);
  vhigh = LLVMConstAdd(vhigh, vlow);

  if(c_t->primitive == c->i128)
    return vhigh;

  if((c_t->primitive == c->f32) || (c_t->primitive == c->f64))
    return LLVMConstUIToFP(vhigh, c_t->primitive);

  return LLVMConstTrunc(vhigh, c_t->primitive);
}
Beispiel #7
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;
}
Beispiel #8
0
// Assign a UIF type from the given target type to the given AST
static bool uif_type_from_chain(pass_opt_t* opt, ast_t* literal,
  ast_t* target_type, lit_chain_t* chain, bool require_float,
  bool report_errors)
{
  assert(literal != NULL);
  assert(chain != NULL);

  lit_chain_t* chain_head = chain;
  while(chain_head->cardinality != CHAIN_CARD_BASE)
    chain_head = chain_head->next;

  if(chain_head->cached_type == NULL)
  {
    // This is the first time we've needed this type, find it
    if(!uif_type(opt, literal, target_type, chain_head, report_errors))
      return false;
  }

  if(require_float && !chain_head->valid_for_float)
  {
    if(report_errors)
      ast_error(literal, "Inferred possibly integer type %s for float literal",
        chain_head->name);

    return false;
  }

  if(ast_id(literal) == TK_INT && chain_head->cached_uif_index >= 0)
  {
    // Check for literals that are outside the range of their type.
    // Note we don't check for types bound to type parameters.
    int i = chain_head->cached_uif_index;

    if(_str_uif_types[i].limit_low != 0 || _str_uif_types[i].limit_high != 0)
    {
#ifdef PLATFORM_IS_VISUAL_STUDIO
      UnsignedInt128 limit(_str_uif_types[i].limit_high,
        _str_uif_types[i].limit_low);
#else
      __uint128_t limit = (((__uint128_t)_str_uif_types[i].limit_high) << 64) |
        _str_uif_types[i].limit_low;
#endif

      // There is a limit specified for this type, the literal must be smaller
      // than that.
      bool neg_plus_one = false;

      if(_str_uif_types[i].neg_plus_one)
      {
        // If the literal is immediately negated it can be equal to the given
        // limit. This is because of how the world chooses to encode negative
        // integers.
        // For example, the maximum value in an I8 is 127. But the minimum
        // value is -128.
        // We don't actually calculate the negative value here, but we have a
        // looser test if the literal is immediately negated.
        // We do not do this if the negation is not immediate, eg "-(128)".
        ast_t* parent = ast_parent(literal);
        assert(parent != NULL);
        ast_t* parent_type = ast_type(parent);

        if(parent_type != NULL && ast_id(parent_type) == TK_OPERATORLITERAL &&
          ast_child(parent) == literal &&
          ((lit_op_info_t*)ast_data(parent_type))->neg_plus_one)
          neg_plus_one = true;
      }

      __uint128_t actual = ast_int(literal);

      if((actual > limit) || (!neg_plus_one && actual == limit))
      {
        // Illegal value. Note that we report an error, but don't return an
        // error, so other errors may be found.
        ast_error(literal, "Literal value is out of range for type (%s)",
          chain_head->name);
      }
    }
  }

  ast_settype(literal, chain_head->cached_type);
  return true;
}
Beispiel #9
0
// Compare the 2 given signatures to see if they are exactly the same
static bool compare_signatures(ast_t* sig_a, ast_t* sig_b)
{
  if(sig_a == NULL && sig_b == NULL)
    return true;

  if(sig_a == NULL || sig_b == NULL)
    return false;

  token_id a_id = ast_id(sig_a);

  if(a_id != ast_id(sig_b))
    return false;

  switch(a_id)
  {
    case TK_BE:
    case TK_FUN:
    case TK_NEW:
    {
      // Check everything except body and docstring, ie first 6 children
      ast_t* a_child = ast_child(sig_a);
      ast_t* b_child = ast_child(sig_b);

      for(int i = 0; i < 6; i++)
      {
        if(a_child == NULL || b_child == NULL)
          return false;

        if(!compare_signatures(a_child, b_child))
          return false;

        a_child = ast_sibling(a_child);
        b_child = ast_sibling(b_child);
      }

      return true;
    }

    case TK_STRING:
    case TK_ID:
    {
      // Can't just use strcmp, string literals may contain \0s
      size_t a_len = ast_name_len(sig_a);
      size_t b_len = ast_name_len(sig_b);

      if(a_len != b_len)
        return false;

      const char* a_text = ast_name(sig_a);
      const char* b_text = ast_name(sig_b);

      for(size_t i = 0; i < a_len; i++)
      {
        if(a_text[i] != b_text[i])
          return false;
      }

      return true;
    }

    case TK_INT:     return lexint_cmp(ast_int(sig_a), ast_int(sig_b)) == 0;
    case TK_FLOAT:   return ast_float(sig_a) == ast_float(sig_b);

    case TK_NOMINAL:
      if(ast_data(sig_a) != ast_data(sig_b))
        return false;

      break;

    default:
      break;
  }

  ast_t* a_child = ast_child(sig_a);
  ast_t* b_child = ast_child(sig_b);

  while(a_child != NULL && b_child != NULL)
  {
    if(!compare_signatures(a_child, b_child))
      return false;

    a_child = ast_sibling(a_child);
    b_child = ast_sibling(b_child);
  }

  if(a_child != NULL || b_child != NULL)
    return false;

  return true;
}