Ejemplo n.º 1
0
/*
 * Icarus translated wait(<expr) <stmt> into
 *   begin
 *    while (<expr> !== 1'b1) @(<expr sensitivities>);
 *    <stmt>
 *   end
 * This routine looks for this pattern and turns it back into a
 * wait statement.
 */
static unsigned is_wait(ivl_scope_t scope, ivl_statement_t stmt)
{
      ivl_statement_t while_wait, wait, wait_stmt;
      ivl_expr_t while_expr, expr;
      const char *bits;
	/* We must have two block elements. */
      if (ivl_stmt_block_count(stmt) != 2) return 0;
	/* The first must be a while. */
      while_wait = ivl_stmt_block_stmt(stmt, 0);
      if (ivl_statement_type(while_wait) != IVL_ST_WHILE) return 0;
	/* That has a wait with a NOOP statement. */
      wait = ivl_stmt_sub_stmt(while_wait);
      if (ivl_statement_type(wait) != IVL_ST_WAIT) return 0;
      wait_stmt = ivl_stmt_sub_stmt(wait);
      if (ivl_statement_type(wait_stmt) != IVL_ST_NOOP) return 0;
	/* Check that the while condition has the correct form. */
      while_expr = ivl_stmt_cond_expr(while_wait);
      if (ivl_expr_type(while_expr) != IVL_EX_BINARY) return 0;
      if (ivl_expr_opcode(while_expr) != 'N') return 0;
	/* Has a second operator that is a constant 1'b1. */
      expr = ivl_expr_oper2(while_expr);
      if (ivl_expr_type(expr) != IVL_EX_NUMBER) return 0;
      if (ivl_expr_width(expr) != 1) return 0;
      bits = ivl_expr_bits(expr);
      if (*bits != '1') return 0;
// HERE: There is no easy way to verify that the @ sensitivity list
//       matches the first expression so we don't check for that yet.
	/* And finally the two statements that represent the wait must
	 * have the same line number as the block. */
      if ((ivl_stmt_lineno(stmt) != ivl_stmt_lineno(while_wait)) ||
          (ivl_stmt_lineno(stmt) != ivl_stmt_lineno(wait))) {
	    return 0;
      }

	/* The pattern matched so generate the appropriate code. */
      fprintf(vlog_out, "%*cwait(", get_indent(), ' ');
      emit_expr(scope, ivl_expr_oper1(while_expr), 0);
      fprintf(vlog_out, ")");
      emit_stmt_file_line(stmt);
      single_indent = 1;
      emit_stmt(scope, ivl_stmt_block_stmt(stmt, 1));
      return 1;
}
Ejemplo n.º 2
0
Archivo: gen.c Proyecto: irori/8cc
static void emit_addr(Node *node) {
    switch (node->type) {
    case AST_LVAR:
        ensure_lvar_init(node);
        emit("lea %d(%%rbp), %%rax", node->loff);
        break;
    case AST_GVAR:
        emit("lea %s(%%rip), %%rax", node->glabel);
        break;
    case AST_DEREF:
        emit_expr(node->operand);
        break;
    case AST_STRUCT_REF:
        emit_addr(node->struc);
        emit("add $%d, %%rax", node->ctype->offset);
        break;
    default:
        error("internal error: %s", a2s(node));
    }
}
Ejemplo n.º 3
0
Archivo: gen.c Proyecto: irori/8cc
static void emit_load_struct_ref(Node *struc, Ctype *field, int off) {
    SAVE;
    switch (struc->type) {
    case AST_LVAR:
        ensure_lvar_init(struc);
        emit_lload(field, "rbp", struc->loff + field->offset + off);
        break;
    case AST_GVAR:
        emit_gload(field, struc->varname, field->offset + off);
        break;
    case AST_STRUCT_REF:
        emit_load_struct_ref(struc->struc, field, struc->ctype->offset + off);
        break;
    case AST_DEREF:
        emit_expr(struc->operand);
        emit_lload(field, "rax", field->offset + off);
        break;
    default:
        error("internal error: %s", a2s(struc));
    }
}
Ejemplo n.º 4
0
Archivo: gen.c Proyecto: irori/8cc
static void emit_assign_struct_ref(Node *struc, Ctype *field, int off) {
    SAVE;
    switch (struc->type) {
    case AST_LVAR:
        ensure_lvar_init(struc);
        emit_lsave(field, struc->loff + field->offset + off);
        break;
    case AST_GVAR:
        emit_gsave(struc->varname, field, field->offset + off);
        break;
    case AST_STRUCT_REF:
        emit_assign_struct_ref(struc->struc, field, off + struc->ctype->offset);
        break;
    case AST_DEREF:
        push("rax");
        emit_expr(struc->operand);
        emit_assign_deref_int(field, field->offset + off);
        break;
    default:
        error("internal error: %s", a2s(struc));
    }
}
Ejemplo n.º 5
0
Archivo: gen.c Proyecto: 4ker/8cc
static void emit_addr(Node *node) {
    switch (node->kind) {
    case AST_LVAR:
        ensure_lvar_init(node);
        emit("lea %d(#rbp), #rax", node->loff);
        break;
    case AST_GVAR:
        emit("lea %s(#rip), #rax", node->glabel);
        break;
    case AST_DEREF:
        emit_expr(node->operand);
        break;
    case AST_STRUCT_REF:
        emit_addr(node->struc);
        emit("add $%d, #rax", node->ty->offset);
        break;
    case AST_FUNCDESG:
        emit("lea %s(#rip), #rax", node->fname);
        break;
    default:
        error("internal error: %s", node2s(node));
    }
}
Ejemplo n.º 6
0
static void emit_stmt_condit(ivl_scope_t scope, ivl_statement_t stmt)
{
      ivl_statement_t true_stmt = ivl_stmt_cond_true(stmt);
      ivl_statement_t false_stmt = ivl_stmt_cond_false(stmt);
      unsigned nest = 0;
      fprintf(vlog_out, "%*cif (", get_indent(), ' ');
      emit_expr(scope, ivl_stmt_cond_expr(stmt), 0);
      fprintf(vlog_out, ")");
      emit_stmt_file_line(stmt);
      if (true_stmt) {
	      /* If we have a false statement and the true statement is a
	       * condition that does not have a false clause then we need
	       * to add a begin/end pair to keep the else clause attached
	       * to this condition. */
	    if (false_stmt &&
	        (ivl_statement_type(true_stmt) == IVL_ST_CONDIT) &&
	        (! ivl_stmt_cond_false(true_stmt))) nest = 1;
	    if (nest) {
		  fprintf(vlog_out, " begin\n");
		  indent += indent_incr;
	    } else single_indent = 1;
	    emit_stmt(scope, true_stmt);
      } else {
	    fprintf(vlog_out, ";\n");
      }
      if (false_stmt) {
	    if (nest) {
		  assert(indent >= indent_incr);
		  indent -= indent_incr;
	    }
	    fprintf(vlog_out, "%*c", get_indent(), ' ');
	    if (nest) fprintf(vlog_out, "end ");
	    fprintf(vlog_out, "else");
	    single_indent = 1;
	    emit_stmt(scope, false_stmt);
      }
}
Ejemplo n.º 7
0
static void emit_select_name(ivl_scope_t scope, ivl_expr_t expr, unsigned wid)
{
	/* A select of a number is really a parameter select. */
      if (ivl_expr_type(expr) == IVL_EX_NUMBER) {
	      /* Look in the current scope. */
	    if (emit_param_name_in_scope(scope, expr)) return;
	      /* Now look in the enclosing module scope if this is not a
	       * module scope. */
	    if (ivl_scope_type(scope) != IVL_SCT_MODULE) {
		  if (emit_param_name_in_scope(get_module_scope(scope),
		                               expr)) return;
	    }
// HERE: For now we only look in the current and module scope for the
//       parameter that is being selected. We need to also look in other
//       scopes, but that involves a big search.
	    fprintf(vlog_out, "<missing>");
	    fprintf(stderr, "%s:%u: vlog95 error: Unable to find parameter "
	                    "for select expression \n",
	                    ivl_expr_file(expr), ivl_expr_lineno(expr));
	    vlog_errors += 1;
      } else {
	    emit_expr(scope, expr, wid);
      }
}
Ejemplo n.º 8
0
static void emit_expr_select(ivl_scope_t scope, ivl_expr_t expr, unsigned wid)
{
      ivl_expr_t sel_expr = ivl_expr_oper2(expr);
      ivl_expr_t sig_expr = ivl_expr_oper1(expr);
      ivl_select_type_t sel_type = ivl_expr_sel_type(expr);
      if (sel_expr) {
	    unsigned width = ivl_expr_width(expr);
	    ivl_expr_type_t type = ivl_expr_type(sig_expr);
	    assert(width > 0);
	      /* The compiler uses selects for some shifts. */
	    if (type != IVL_EX_NUMBER && type != IVL_EX_SIGNAL) {
		  fprintf(vlog_out, "(" );
		  emit_select_name(scope, sig_expr, wid);
		  fprintf(vlog_out, " >> " );
		  emit_scaled_expr(scope, sel_expr, 1, 0);
		  fprintf(vlog_out, ")" );
	    } else {
		    /* A constant/parameter must be zero based in 1364-1995
		     * so keep the compiler generated normalization. This
		     * does not always work for selects before the parameter
		     * since 1364-1995 does not support signed math. */
		  int msb = 1;
		  int lsb = 0;
		  if (type == IVL_EX_SIGNAL) {
			ivl_signal_t sig = ivl_expr_signal(sig_expr);
			msb = ivl_signal_msb(sig);
			lsb = ivl_signal_lsb(sig);
		  }
		    /* A bit select. */
		  if (width == 1) {
			emit_select_name(scope, sig_expr, wid);
			fprintf(vlog_out, "[");
			emit_scaled_expr(scope, sel_expr, msb, lsb);
			fprintf(vlog_out, "]");
		  } else {
			if (ivl_expr_type(sel_expr) == IVL_EX_NUMBER) {
				/* A constant part select. */
			      emit_select_name(scope, sig_expr, wid);
			      emit_scaled_range(scope, sel_expr, width,
			                        msb, lsb);
			} else {
				/* An indexed part select. */
			      assert(sel_type != IVL_SEL_OTHER);
			      emit_expr_ips(scope, sig_expr, sel_expr,
			                    sel_type, width, msb, lsb);
			}
		  }
	    }
      } else {
// HERE: Should this sign extend if the expression is signed?
	    emit_expr(scope, sig_expr, wid);
	      /* Select part of a signal when needed. */
	    if ((ivl_expr_type(sig_expr) == IVL_EX_SIGNAL) &&
	        (ivl_expr_width(expr) < ivl_expr_width(sig_expr))) {
		  ivl_signal_t sig = ivl_expr_signal(sig_expr);
		  int msb = ivl_signal_msb(sig);
		  int lsb = ivl_signal_lsb(sig);
		  int64_t value = lsb;
		  unsigned e_wid = ivl_expr_width(expr) - 1;
		  if (msb >= lsb) value += e_wid;
		  else value -= e_wid;
		  fprintf(vlog_out, "[%"PRId64":%u]", value, lsb);
	    }
      }
}
Ejemplo n.º 9
0
static void
output_fde (struct fde_entry *fde, struct cie_entry *cie,
	    bfd_boolean eh_frame, struct cfi_insn_data *first,
	    int align)
{
  symbolS *after_size_address, *end_address;
  expressionS exp;
  offsetT augmentation_size;
  enum dwarf2_format fmt = DWARF2_FORMAT (now_seg);
  int offset_size;
  int addr_size;

  after_size_address = symbol_temp_make ();
  end_address = symbol_temp_make ();

  exp.X_op = O_subtract;
  exp.X_add_symbol = end_address;
  exp.X_op_symbol = after_size_address;
  exp.X_add_number = 0;
  if (eh_frame || fmt == dwarf2_format_32bit)
    offset_size = 4;
  else
    {
      if (fmt == dwarf2_format_64bit)
	out_four (-1);
      offset_size = 8;
    }
  emit_expr (&exp, offset_size);		/* Length.  */
  symbol_set_value_now (after_size_address);

  if (eh_frame)
    {
      exp.X_op = O_subtract;
      exp.X_add_symbol = after_size_address;
      exp.X_op_symbol = cie->start_address;
      exp.X_add_number = 0;
      emit_expr (&exp, offset_size);		/* CIE offset.  */
    }
  else
    {
      TC_DWARF2_EMIT_OFFSET (cie->start_address, offset_size);
    }

  if (eh_frame)
    {
      exp.X_op = O_subtract;
      exp.X_add_number = 0;
#if CFI_DIFF_EXPR_OK
      exp.X_add_symbol = fde->start_address;
      exp.X_op_symbol = symbol_temp_new_now ();
      emit_expr (&exp, DWARF2_FDE_RELOC_SIZE);	/* Code offset.  */
#else
      exp.X_op = O_symbol;
      exp.X_add_symbol = fde->start_address;
#ifdef tc_cfi_emit_pcrel_expr
      tc_cfi_emit_pcrel_expr (&exp, DWARF2_FDE_RELOC_SIZE);	 /* Code offset.  */
#else
      emit_expr (&exp, DWARF2_FDE_RELOC_SIZE);	/* Code offset.  */
#endif
#endif
      addr_size = DWARF2_FDE_RELOC_SIZE;
    }
  else
    {
      exp.X_op = O_symbol;
      exp.X_add_symbol = fde->start_address;
      exp.X_add_number = 0;
      addr_size = DWARF2_ADDR_SIZE (stdoutput);
      emit_expr (&exp, addr_size);
    }

  exp.X_op = O_subtract;
  exp.X_add_symbol = fde->end_address;
  exp.X_op_symbol = fde->start_address;		/* Code length.  */
  exp.X_add_number = 0;
  emit_expr (&exp, addr_size);

  augmentation_size = encoding_size (fde->lsda_encoding);
  if (eh_frame)
    out_uleb128 (augmentation_size);		/* Augmentation size.  */

  if (fde->lsda_encoding != DW_EH_PE_omit)
    {
      exp = fde->lsda;
      if ((fde->lsda_encoding & 0x70) == DW_EH_PE_pcrel)
	{
#if CFI_DIFF_LSDA_OK
	  exp.X_op = O_subtract;
	  exp.X_op_symbol = symbol_temp_new_now ();
	  emit_expr (&exp, augmentation_size);
#elif defined (tc_cfi_emit_pcrel_expr)
	  tc_cfi_emit_pcrel_expr (&exp, augmentation_size);
#else
	  abort ();
#endif
	}
      else
	emit_expr (&exp, augmentation_size);
    }

  for (; first; first = first->next)
    if (CUR_SEG (first) == CUR_SEG (fde))
      output_cfi_insn (first);

  frag_align (align, DW_CFA_nop, 0);
  symbol_set_value_now (end_address);
}
Ejemplo n.º 10
0
Archivo: gen.c Proyecto: irori/8cc
static void emit_assign_deref(Node *var) {
    SAVE;
    push("rax");
    emit_expr(var->operand);
    emit_assign_deref_int(var->operand->ctype->ptr, 0);
}
Ejemplo n.º 11
0
// ccall(pointer, rettype, (argtypes...), args...)
static Value *emit_ccall(jl_value_t **args, size_t nargs, jl_codectx_t *ctx)
{
    JL_NARGSV(ccall, 3);
    jl_value_t *rt=NULL, *at=NULL;
    JL_GC_PUSH2(&rt, &at);

    native_sym_arg_t symarg = interpret_symbol_arg(args[1], ctx, "ccall");
    Value *jl_ptr=NULL;
    void *fptr = NULL;
    char *f_name = NULL, *f_lib = NULL;
    jl_ptr = symarg.jl_ptr;
    fptr = symarg.fptr;
    f_name = symarg.f_name;
    f_lib = symarg.f_lib;
    if (f_name == NULL && fptr == NULL && jl_ptr == NULL) {
        JL_GC_POP();
        emit_error("ccall: null function pointer", ctx);
        return literal_pointer_val(jl_nothing);
    }

    rt  = jl_interpret_toplevel_expr_in(ctx->module, args[2],
                                        &jl_tupleref(ctx->sp,0),
                                        jl_tuple_len(ctx->sp)/2);
    if (jl_is_tuple(rt)) {
        std::string msg = "in " + ctx->funcName +
            ": ccall: missing return type";
        jl_error(msg.c_str());
    }
    if (rt == (jl_value_t*)jl_pointer_type)
        jl_error("ccall: return type Ptr should have an element type, Ptr{T}");
    at  = jl_interpret_toplevel_expr_in(ctx->module, args[3],
                                        &jl_tupleref(ctx->sp,0),
                                        jl_tuple_len(ctx->sp)/2);

    JL_TYPECHK(ccall, type, rt);
    JL_TYPECHK(ccall, tuple, at);
    JL_TYPECHK(ccall, type, at);
    jl_tuple_t *tt = (jl_tuple_t*)at;
    std::vector<Type *> fargt(0);
    std::vector<Type *> fargt_sig(0);
    Type *lrt = julia_struct_to_llvm(rt);
    if (lrt == NULL) {
        JL_GC_POP();
        emit_error("ccall: return type doesn't correspond to a C type", ctx);
        return literal_pointer_val(jl_nothing);
    }
    size_t i;
    bool isVa = false;
    size_t nargt = jl_tuple_len(tt);
    std::vector<AttributeWithIndex> attrs;

    for(i=0; i < nargt; i++) {
        jl_value_t *tti = jl_tupleref(tt,i);
        if (tti == (jl_value_t*)jl_pointer_type)
            jl_error("ccall: argument type Ptr should have an element type, Ptr{T}");
        if (jl_is_vararg_type(tti)) {
            isVa = true;
            tti = jl_tparam0(tti);
        }
        if (jl_is_bitstype(tti)) {
            // see pull req #978. need to annotate signext/zeroext for
            // small integer arguments.
            jl_datatype_t *bt = (jl_datatype_t*)tti;
            if (bt->size < 4) {
                if (jl_signed_type == NULL) {
                    jl_signed_type = jl_get_global(jl_core_module,jl_symbol("Signed"));
                }
#ifdef LLVM32
                Attributes::AttrVal av;
                if (jl_signed_type && jl_subtype(tti, jl_signed_type, 0))
                    av = Attributes::SExt;
                else
                    av = Attributes::ZExt;
                attrs.push_back(AttributeWithIndex::get(getGlobalContext(), i+1,
                                                        ArrayRef<Attributes::AttrVal>(&av, 1)));
#else
                Attribute::AttrConst av;
                if (jl_signed_type && jl_subtype(tti, jl_signed_type, 0))
                    av = Attribute::SExt;
                else
                    av = Attribute::ZExt;
                attrs.push_back(AttributeWithIndex::get(i+1, av));
#endif
            }
        }
        Type *t = julia_struct_to_llvm(tti);
        if (t == NULL) {
            JL_GC_POP();
            std::stringstream msg;
            msg << "ccall: the type of argument ";
            msg << i+1;
            msg << " doesn't correspond to a C type";
            emit_error(msg.str(), ctx);
            return literal_pointer_val(jl_nothing);
        }
        fargt.push_back(t);
        if (!isVa)
            fargt_sig.push_back(t);
    }
    // check for calling convention specifier
    CallingConv::ID cc = CallingConv::C;
    jl_value_t *last = args[nargs];
    if (jl_is_expr(last)) {
        jl_sym_t *lhd = ((jl_expr_t*)last)->head;
        if (lhd == jl_symbol("stdcall")) {
            cc = CallingConv::X86_StdCall;
            nargs--;
        }
        else if (lhd == jl_symbol("cdecl")) {
            cc = CallingConv::C;
            nargs--;
        }
        else if (lhd == jl_symbol("fastcall")) {
            cc = CallingConv::X86_FastCall;
            nargs--;
        }
        else if (lhd == jl_symbol("thiscall")) {
            cc = CallingConv::X86_ThisCall;
            nargs--;
        }
    }
    
    if ((!isVa && jl_tuple_len(tt)  != (nargs-2)/2) ||
        ( isVa && jl_tuple_len(tt)-1 > (nargs-2)/2))
        jl_error("ccall: wrong number of arguments to C function");

    // some special functions
    if (fptr == &jl_array_ptr) {
        assert(lrt->isPointerTy());
        Value *ary = emit_expr(args[4], ctx);
        JL_GC_POP();
        return mark_julia_type(builder.CreateBitCast(emit_arrayptr(ary),lrt),
                               rt);
    }
    if (fptr == &jl_value_ptr) {
        assert(lrt->isPointerTy());
        jl_value_t *argi = args[4];
        bool addressOf = false;
        if (jl_is_expr(argi) && ((jl_expr_t*)argi)->head == amp_sym) {
            addressOf = true;
            argi = jl_exprarg(argi,0);
        }
        Value *ary = boxed(emit_expr(argi, ctx));
        JL_GC_POP();
        return mark_julia_type(
                builder.CreateBitCast(emit_nthptr_addr(ary, addressOf?1:0),lrt),
                rt);
    }

    // make LLVM function object for the target
    Value *llvmf;
    FunctionType *functype = FunctionType::get(lrt, fargt_sig, isVa);
    
    if (jl_ptr != NULL) {
        null_pointer_check(jl_ptr,ctx);
        Type *funcptype = PointerType::get(functype,0);
        llvmf = builder.CreateIntToPtr(jl_ptr, funcptype);
    }
    else if (fptr != NULL) {
        Type *funcptype = PointerType::get(functype,0);
        llvmf = literal_pointer_val(fptr, funcptype);
    }
    else {
        void *symaddr;
        if (f_lib != NULL)
            symaddr = add_library_sym(f_name, f_lib);
        else
            symaddr = sys::DynamicLibrary::SearchForAddressOfSymbol(f_name);
        if (symaddr == NULL) {
            JL_GC_POP();
            std::stringstream msg;
            msg << "ccall: could not find function ";
            msg << f_name;
            if (f_lib != NULL) {
                msg << " in library ";
                msg << f_lib;
            }
            emit_error(msg.str(), ctx);
            return literal_pointer_val(jl_nothing);
        }
        llvmf = jl_Module->getOrInsertFunction(f_name, functype);
    }

    // save place before arguments, for possible insertion of temp arg
    // area saving code.
    Value *saveloc=NULL;
    Value *stacksave=NULL;
    BasicBlock::InstListType &instList = builder.GetInsertBlock()->getInstList();
    Instruction *savespot;
    if (instList.empty()) {
        savespot = NULL;
    }
    else {
        // hey C++, there's this thing called pointers...
        Instruction &_savespot = builder.GetInsertBlock()->back();
        savespot = &_savespot;
    }

    // emit arguments
    Value *argvals[(nargs-3)/2];
    int last_depth = ctx->argDepth;
    int nargty = jl_tuple_len(tt);
    bool needTempSpace = false;
    for(i=4; i < nargs+1; i+=2) {
        int ai = (i-4)/2;
        jl_value_t *argi = args[i];
        bool addressOf = false;
        if (jl_is_expr(argi) && ((jl_expr_t*)argi)->head == amp_sym) {
            addressOf = true;
            argi = jl_exprarg(argi,0);
        }
        Type *largty;
        jl_value_t *jargty;
        if (isVa && ai >= nargty-1) {
            largty = fargt[nargty-1];
            jargty = jl_tparam0(jl_tupleref(tt,nargty-1));
        }
        else {
            largty = fargt[ai];
            jargty = jl_tupleref(tt,ai);
        }
        Value *arg;
        if (largty == jl_pvalue_llvmt ||
                largty->isStructTy()) {
            arg = emit_expr(argi, ctx, true);
        }
        else {
            arg = emit_unboxed(argi, ctx);
            if (jl_is_bitstype(expr_type(argi, ctx))) {
                if (addressOf)
                    arg = emit_unbox(largty->getContainedType(0), largty, arg);
                else
                    arg = emit_unbox(largty, PointerType::get(largty,0), arg);
            }
        }
        /*
#ifdef JL_GC_MARKSWEEP
        // make sure args are rooted
        if (largty->isPointerTy() &&
            (largty == jl_pvalue_llvmt ||
             !jl_is_bits_type(expr_type(args[i], ctx)))) {
            make_gcroot(boxed(arg), ctx);
        }
#endif
        */
        bool mightNeed=false;
        argvals[ai] = julia_to_native(largty, jargty, arg, argi, addressOf,
                                      ai+1, ctx, &mightNeed);
        needTempSpace |= mightNeed;
    }
    if (needTempSpace) {
        // save temp argument area stack pointer
        // TODO: inline this
        saveloc = CallInst::Create(save_arg_area_loc_func);
        stacksave = CallInst::Create(Intrinsic::getDeclaration(jl_Module,
                                                               Intrinsic::stacksave));
        if (savespot)
            instList.insertAfter(savespot, (Instruction*)saveloc);
        else
            instList.push_front((Instruction*)saveloc);
        instList.insertAfter((Instruction*)saveloc, (Instruction*)stacksave);
    }
    // the actual call
    Value *result = builder.CreateCall(llvmf,
                                       ArrayRef<Value*>(&argvals[0],(nargs-3)/2));
    if (cc != CallingConv::C)
        ((CallInst*)result)->setCallingConv(cc);

#ifdef LLVM32
    ((CallInst*)result)->setAttributes(AttrListPtr::get(getGlobalContext(), ArrayRef<AttributeWithIndex>(attrs)));
#else
    ((CallInst*)result)->setAttributes(AttrListPtr::get(attrs.data(),attrs.size()));
#endif
    if (needTempSpace) {
        // restore temp argument area stack pointer
        assert(saveloc != NULL);
        builder.CreateCall(restore_arg_area_loc_func, saveloc);
        assert(stacksave != NULL);
        builder.CreateCall(Intrinsic::getDeclaration(jl_Module,
                                                     Intrinsic::stackrestore),
                           stacksave);
    }
    ctx->argDepth = last_depth;
    if (0) { // Enable this to turn on SSPREQ (-fstack-protector) on the function containing this ccall
#ifdef LLVM32        
        ctx->f->addFnAttr(Attributes::StackProtectReq);
#else
        ctx->f->addFnAttr(Attribute::StackProtectReq);
#endif
    }

    JL_GC_POP();
    if (lrt == T_void)
        return literal_pointer_val((jl_value_t*)jl_nothing);
    if (lrt->isStructTy()) {
        //fprintf(stderr, "ccall rt: %s -> %s\n", f_name, ((jl_tag_type_t*)rt)->name->name->name);
        assert(jl_is_structtype(rt));
        Value *strct =
            builder.CreateCall(jlallocobj_func,
                               ConstantInt::get(T_size,
                                    sizeof(void*)+((jl_datatype_t*)rt)->size));
        builder.CreateStore(literal_pointer_val((jl_value_t*)rt),
                            emit_nthptr_addr(strct, (size_t)0));
        builder.CreateStore(result,
                            builder.CreateBitCast(
                                emit_nthptr_addr(strct, (size_t)1),
                                PointerType::get(lrt,0)));
        return mark_julia_type(strct, rt);
    }
    return mark_julia_type(result, rt);
}
Ejemplo n.º 12
0
static void
output_cfi_insn (struct cfi_insn_data *insn)
{
    offsetT offset;
    unsigned int regno;

    switch (insn->insn)
    {
    case DW_CFA_advance_loc:
    {
        symbolS *from = insn->u.ll.lab1;
        symbolS *to = insn->u.ll.lab2;

        if (symbol_get_frag (to) == symbol_get_frag (from))
        {
            addressT delta = S_GET_VALUE (to) - S_GET_VALUE (from);
            addressT scaled = delta / DWARF2_LINE_MIN_INSN_LENGTH;

            if (scaled <= 0x3F)
                out_one (DW_CFA_advance_loc + scaled);
            else if (delta <= 0xFF)
            {
                out_one (DW_CFA_advance_loc1);
                out_one (delta);
            }
            else if (delta <= 0xFFFF)
            {
                out_one (DW_CFA_advance_loc2);
                out_two (delta);
            }
            else
            {
                out_one (DW_CFA_advance_loc4);
                out_four (delta);
            }
        }
        else
        {
            expressionS exp;

            exp.X_op = O_subtract;
            exp.X_add_symbol = to;
            exp.X_op_symbol = from;
            exp.X_add_number = 0;

            /* The code in ehopt.c expects that one byte of the encoding
               is already allocated to the frag.  This comes from the way
               that it scans the .eh_frame section looking first for the
               .byte DW_CFA_advance_loc4.  */
            frag_more (1);

            frag_var (rs_cfa, 4, 0, DWARF2_LINE_MIN_INSN_LENGTH << 3,
                      make_expr_symbol (&exp), frag_now_fix () - 1,
                      (char *) frag_now);
        }
    }
    break;

    case DW_CFA_def_cfa:
        offset = insn->u.ri.offset;
        if (offset < 0)
        {
            out_one (DW_CFA_def_cfa_sf);
            out_uleb128 (insn->u.ri.reg);
            out_sleb128 (offset / DWARF2_CIE_DATA_ALIGNMENT);
        }
        else
        {
            out_one (DW_CFA_def_cfa);
            out_uleb128 (insn->u.ri.reg);
            out_uleb128 (offset);
        }
        break;

    case DW_CFA_def_cfa_register:
    case DW_CFA_undefined:
    case DW_CFA_same_value:
        out_one (insn->insn);
        out_uleb128 (insn->u.r);
        break;

    case DW_CFA_def_cfa_offset:
        offset = insn->u.i;
        if (offset < 0)
        {
            out_one (DW_CFA_def_cfa_offset_sf);
            out_sleb128 (offset / DWARF2_CIE_DATA_ALIGNMENT);
        }
        else
        {
            out_one (DW_CFA_def_cfa_offset);
            out_uleb128 (offset);
        }
        break;

    case DW_CFA_restore:
        regno = insn->u.r;
        if (regno <= 0x3F)
        {
            out_one (DW_CFA_restore + regno);
        }
        else
        {
            out_one (DW_CFA_restore_extended);
            out_uleb128 (regno);
        }
        break;

    case DW_CFA_offset:
        regno = insn->u.ri.reg;
        offset = insn->u.ri.offset / DWARF2_CIE_DATA_ALIGNMENT;
        if (offset < 0)
        {
            out_one (DW_CFA_offset_extended_sf);
            out_uleb128 (regno);
            out_sleb128 (offset);
        }
        else if (regno <= 0x3F)
        {
            out_one (DW_CFA_offset + regno);
            out_uleb128 (offset);
        }
        else
        {
            out_one (DW_CFA_offset_extended);
            out_uleb128 (regno);
            out_uleb128 (offset);
        }
        break;

    case DW_CFA_register:
        out_one (DW_CFA_register);
        out_uleb128 (insn->u.rr.reg1);
        out_uleb128 (insn->u.rr.reg2);
        break;

    case DW_CFA_remember_state:
    case DW_CFA_restore_state:
        out_one (insn->insn);
        break;

    case DW_CFA_GNU_window_save:
        out_one (DW_CFA_GNU_window_save);
        break;

    case CFI_escape:
    {
        struct cfi_escape_data *e;
        for (e = insn->u.esc; e ; e = e->next)
            emit_expr (&e->exp, 1);
        break;
    }

    default:
        abort ();
    }
}
Ejemplo n.º 13
0
static void
output_cie (struct cie_entry *cie)
{
    symbolS *after_size_address, *end_address;
    expressionS exp;
    struct cfi_insn_data *i;
    offsetT augmentation_size;

    cie->start_address = symbol_temp_new_now ();
    after_size_address = symbol_temp_make ();
    end_address = symbol_temp_make ();

    exp.X_op = O_subtract;
    exp.X_add_symbol = end_address;
    exp.X_op_symbol = after_size_address;
    exp.X_add_number = 0;

    emit_expr (&exp, 4);				/* Length.  */
    symbol_set_value_now (after_size_address);
    out_four (0);					/* CIE id.  */
    out_one (DW_CIE_VERSION);			/* Version.  */
    out_one ('z');				/* Augmentation.  */
    if (cie->per_encoding != DW_EH_PE_omit)
        out_one ('P');
    if (cie->lsda_encoding != DW_EH_PE_omit)
        out_one ('L');
    out_one ('R');
    if (cie->signal_frame)
        out_one ('S');
    out_one (0);
    out_uleb128 (DWARF2_LINE_MIN_INSN_LENGTH);	/* Code alignment.  */
    out_sleb128 (DWARF2_CIE_DATA_ALIGNMENT);	/* Data alignment.  */
    if (DW_CIE_VERSION == 1)			/* Return column.  */
        out_one (cie->return_column);
    else
        out_uleb128 (cie->return_column);
    augmentation_size = 1 + (cie->lsda_encoding != DW_EH_PE_omit);
    if (cie->per_encoding != DW_EH_PE_omit)
        augmentation_size += 1 + encoding_size (cie->per_encoding);
    out_uleb128 (augmentation_size);		/* Augmentation size.  */
    if (cie->per_encoding != DW_EH_PE_omit)
    {
        offsetT size = encoding_size (cie->per_encoding);
        out_one (cie->per_encoding);
        exp = cie->personality;
        if ((cie->per_encoding & 0x70) == DW_EH_PE_pcrel)
        {
#ifdef DIFF_EXPR_OK
            exp.X_op = O_subtract;
            exp.X_op_symbol = symbol_temp_new_now ();
            emit_expr (&exp, size);
#elif defined (tc_cfi_emit_pcrel_expr)
            tc_cfi_emit_pcrel_expr (&exp, size);
#else
            abort ();
#endif
        }
        else
            emit_expr (&exp, size);
    }
    if (cie->lsda_encoding != DW_EH_PE_omit)
        out_one (cie->lsda_encoding);
#if defined DIFF_EXPR_OK || defined tc_cfi_emit_pcrel_expr
    out_one (DW_EH_PE_pcrel | DW_EH_PE_sdata4);
#else
    out_one (DW_EH_PE_sdata4);
#endif

    if (cie->first)
        for (i = cie->first; i != cie->last; i = i->next)
            output_cfi_insn (i);

    frag_align (2, DW_CFA_nop, 0);
    symbol_set_value_now (end_address);
}
Ejemplo n.º 14
0
static void
out_debug_info (segT info_seg, segT abbrev_seg, segT line_seg, segT ranges_seg)
{
  char producer[128];
  const char *comp_dir;
  const char *dirname;
  expressionS exp;
  symbolS *info_end;
  char *p;
  int len;
  int sizeof_offset;

  sizeof_offset = out_header (info_seg, &exp);
  info_end = exp.X_add_symbol;

  /* DWARF version.  */
  out_two (DWARF2_VERSION);

  /* .debug_abbrev offset */
  TC_DWARF2_EMIT_OFFSET (section_symbol (abbrev_seg), sizeof_offset);

  /* Target address size.  */
  out_byte (sizeof_address);

  /* DW_TAG_compile_unit DIE abbrev */
  out_uleb128 (1);

  /* DW_AT_stmt_list */
  TC_DWARF2_EMIT_OFFSET (section_symbol (line_seg),
			 (DWARF2_FORMAT (line_seg) == dwarf2_format_32bit
			  ? 4 : 8));

  /* These two attributes are emitted if all of the code is contiguous.  */
  if (all_segs->next == NULL)
    {
      /* DW_AT_low_pc */
      exp.X_op = O_symbol;
      exp.X_add_symbol = all_segs->text_start;
      exp.X_add_number = 0;
      emit_expr (&exp, sizeof_address);

      /* DW_AT_high_pc */
      exp.X_op = O_symbol;
      exp.X_add_symbol = all_segs->text_end;
      exp.X_add_number = 0;
      emit_expr (&exp, sizeof_address);
    }
  else
    {
      /* This attribute is emitted if the code is disjoint.  */
      /* DW_AT_ranges.  */
      TC_DWARF2_EMIT_OFFSET (section_symbol (ranges_seg), sizeof_offset);
    }

  /* DW_AT_name.  We don't have the actual file name that was present
     on the command line, so assume files[1] is the main input file.
     We're not supposed to get called unless at least one line number
     entry was emitted, so this should always be defined.  */
  if (files_in_use == 0)
    abort ();
  if (files[1].dir)
    {
      dirname = remap_debug_filename (dirs[files[1].dir]);
      len = strlen (dirname);
#ifdef TE_VMS
      /* Already has trailing slash.  */
      p = frag_more (len);
      memcpy (p, dirname, len);
#else
      p = frag_more (len + 1);
      memcpy (p, dirname, len);
      INSERT_DIR_SEPARATOR (p, len);
#endif
    }
  len = strlen (files[1].filename) + 1;
  p = frag_more (len);
  memcpy (p, files[1].filename, len);

  /* DW_AT_comp_dir */
  comp_dir = remap_debug_filename (getpwd ());
  len = strlen (comp_dir) + 1;
  p = frag_more (len);
  memcpy (p, comp_dir, len);

  /* DW_AT_producer */
  sprintf (producer, "GNU AS %s", VERSION);
  len = strlen (producer) + 1;
  p = frag_more (len);
  memcpy (p, producer, len);

  /* DW_AT_language.  Yes, this is probably not really MIPS, but the
     dwarf2 draft has no standard code for assembler.  */
  out_two (DW_LANG_Mips_Assembler);

  symbol_set_value_now (info_end);
}
Ejemplo n.º 15
0
Archivo: gen.c Proyecto: irori/8cc
static void emit_deref(Node *node) {
    SAVE;
    emit_expr(node->operand);
    emit_lload(node->operand->ctype->ptr, "rax", 0);
    emit_load_convert(node->ctype, node->operand->ctype->ptr);
}
Ejemplo n.º 16
0
Archivo: gen.c Proyecto: irori/8cc
static void emit_pre_inc_dec(Node *node, char *op) {
    emit_expr(node->operand);
    emit("%s $1, %%rax", op);
    emit_store(node->operand);
}
Ejemplo n.º 17
0
// ccall(pointer, rettype, (argtypes...), args...)
static Value *emit_ccall(jl_value_t **args, size_t nargs, jl_codectx_t *ctx)
{
    JL_NARGSV(ccall, 3);
    jl_value_t *ptr=NULL, *rt=NULL, *at=NULL;
    JL_GC_PUSH(&ptr, &rt, &at);
    ptr = jl_interpret_toplevel_expr_in(ctx->module, args[1],
                                        &jl_tupleref(ctx->sp,0),
                                        jl_tuple_len(ctx->sp)/2);
    rt  = jl_interpret_toplevel_expr_in(ctx->module, args[2],
                                        &jl_tupleref(ctx->sp,0),
                                        jl_tuple_len(ctx->sp)/2);
    if (jl_is_tuple(rt)) {
        std::string msg = "in " + ctx->funcName +
            ": ccall: missing return type";
        jl_error(msg.c_str());
    }
    at  = jl_interpret_toplevel_expr_in(ctx->module, args[3],
                                        &jl_tupleref(ctx->sp,0),
                                        jl_tuple_len(ctx->sp)/2);
    void *fptr=NULL;
    char *f_name=NULL, *f_lib=NULL;
    if (jl_is_tuple(ptr) && jl_tuple_len(ptr)==1) {
        ptr = jl_tupleref(ptr,0);
    }
    if (jl_is_symbol(ptr))
        f_name = ((jl_sym_t*)ptr)->name;
    else if (jl_is_byte_string(ptr))
        f_name = jl_string_data(ptr);
    if (f_name != NULL) {
        // just symbol, default to JuliaDLHandle
#ifdef __WIN32__
        fptr = jl_dlsym_e(jl_dl_handle, f_name);
        if (!fptr) {
            fptr = jl_dlsym_e(jl_kernel32_handle, f_name);
            if (!fptr) {
                fptr = jl_dlsym_e(jl_ntdll_handle, f_name);
                if (!fptr) {
                    fptr = jl_dlsym_e(jl_crtdll_handle, f_name);
                    if (!fptr) {
                        fptr = jl_dlsym(jl_winsock_handle, f_name);
                    }
                }
            }
        }
        else {
            // available in process symbol table
            fptr = NULL;
        }
#else
        // will look in process symbol table
#endif
    }
    else if (jl_is_cpointer_type(jl_typeof(ptr))) {
        fptr = *(void**)jl_bits_data(ptr);
    }
    else if (jl_is_tuple(ptr) && jl_tuple_len(ptr)>1) {
        jl_value_t *t0 = jl_tupleref(ptr,0);
        jl_value_t *t1 = jl_tupleref(ptr,1);
        if (jl_is_symbol(t0))
            f_name = ((jl_sym_t*)t0)->name;
        else if (jl_is_byte_string(t0))
            f_name = jl_string_data(t0);
        else
            JL_TYPECHK(ccall, symbol, t0);
        if (jl_is_symbol(t1))
            f_lib = ((jl_sym_t*)t1)->name;
        else if (jl_is_byte_string(t1))
            f_lib = jl_string_data(t1);
        else
            JL_TYPECHK(ccall, symbol, t1);
    }
    else {
        JL_TYPECHK(ccall, pointer, ptr);
    }
    if (f_name == NULL && fptr == NULL) {
        JL_GC_POP();
        emit_error("ccall: null function pointer", ctx);
        return literal_pointer_val(jl_nothing);
    }
    JL_TYPECHK(ccall, type, rt);
    JL_TYPECHK(ccall, tuple, at);
    JL_TYPECHK(ccall, type, at);
    jl_tuple_t *tt = (jl_tuple_t*)at;
    std::vector<Type *> fargt(0);
    std::vector<Type *> fargt_sig(0);
    Type *lrt = julia_type_to_llvm(rt);
    if (lrt == NULL) {
        JL_GC_POP();
        return literal_pointer_val(jl_nothing);
    }
    size_t i;
    bool haspointers = false;
    bool isVa = false;
    for(i=0; i < jl_tuple_len(tt); i++) {
        jl_value_t *tti = jl_tupleref(tt,i);
        if (jl_is_seq_type(tti)) {
            isVa = true;
            tti = jl_tparam0(tti);
        }
        Type *t = julia_type_to_llvm(tti);
        if (t == NULL) {
            JL_GC_POP();
            return literal_pointer_val(jl_nothing);
        }
        fargt.push_back(t);
        if (!isVa)
            fargt_sig.push_back(t);
    }
    // check for calling convention specifier
    CallingConv::ID cc = CallingConv::C;
    jl_value_t *last = args[nargs];
    if (jl_is_expr(last)) {
        jl_sym_t *lhd = ((jl_expr_t*)last)->head;
        if (lhd == jl_symbol("stdcall")) {
            cc = CallingConv::X86_StdCall;
            nargs--;
        }
        else if (lhd == jl_symbol("cdecl")) {
            cc = CallingConv::C;
            nargs--;
        }
        else if (lhd == jl_symbol("fastcall")) {
            cc = CallingConv::X86_FastCall;
            nargs--;
        }
    }
    
    if ((!isVa && jl_tuple_len(tt)  != (nargs-2)/2) ||
        ( isVa && jl_tuple_len(tt)-1 > (nargs-2)/2))
        jl_error("ccall: wrong number of arguments to C function");

    // some special functions
    if (fptr == &jl_array_ptr) {
        Value *ary = emit_expr(args[4], ctx);
        JL_GC_POP();
        return mark_julia_type(builder.CreateBitCast(emit_arrayptr(ary),lrt),
                               rt);
    }

    // see if there are & arguments
    for(i=4; i < nargs+1; i+=2) {
        jl_value_t *argi = args[i];
        if (jl_is_expr(argi) && ((jl_expr_t*)argi)->head == amp_sym) {
            haspointers = true;
            break;
        }
    }

    // make LLVM function object for the target
    Constant *llvmf;
    FunctionType *functype = FunctionType::get(lrt, fargt_sig, isVa);
    
    if (fptr != NULL) {
        Type *funcptype = PointerType::get(functype,0);
        llvmf = ConstantExpr::getIntToPtr( 
            ConstantInt::get(funcptype, (uint64_t)fptr), 
            funcptype);
    }
    else {
        if (f_lib != NULL)
            add_library_sym(f_name, f_lib);
        llvmf = jl_Module->getOrInsertFunction(f_name, functype);
    }

    // save temp argument area stack pointer
    Value *saveloc=NULL;
    Value *stacksave=NULL;
    if (haspointers) {
        // TODO: inline this
        saveloc = builder.CreateCall(save_arg_area_loc_func);
        stacksave =
            builder.CreateCall(Intrinsic::getDeclaration(jl_Module,
                                                         Intrinsic::stacksave));
    }

    // emit arguments
    Value *argvals[(nargs-3)/2];
    int last_depth = ctx->argDepth;
    int nargty = jl_tuple_len(tt);
    for(i=4; i < nargs+1; i+=2) {
        int ai = (i-4)/2;
        jl_value_t *argi = args[i];
        bool addressOf = false;
        if (jl_is_expr(argi) && ((jl_expr_t*)argi)->head == amp_sym) {
            addressOf = true;
            argi = jl_exprarg(argi,0);
        }
        Type *largty;
        jl_value_t *jargty;
        if (isVa && ai >= nargty-1) {
            largty = fargt[nargty-1];
            jargty = jl_tparam0(jl_tupleref(tt,nargty-1));
        }
        else {
            largty = fargt[ai];
            jargty = jl_tupleref(tt,ai);
        }
        Value *arg;
        if (largty == jl_pvalue_llvmt) {
            arg = emit_expr(argi, ctx, true);
        }
        else {
            arg = emit_unboxed(argi, ctx);
            if (jl_is_bits_type(expr_type(argi, ctx))) {
                if (addressOf)
                    arg = emit_unbox(largty->getContainedType(0), largty, arg);
                else
                    arg = emit_unbox(largty, PointerType::get(largty,0), arg);
            }
        }
        /*
#ifdef JL_GC_MARKSWEEP
        // make sure args are rooted
        if (largty->isPointerTy() &&
            (largty == jl_pvalue_llvmt ||
             !jl_is_bits_type(expr_type(args[i], ctx)))) {
            make_gcroot(boxed(arg), ctx);
        }
#endif
        */
        argvals[ai] = julia_to_native(largty, jargty, arg, argi, addressOf,
                                      ai+1, ctx);
    }
    // the actual call
    Value *result = builder.CreateCall(llvmf,
                                       ArrayRef<Value*>(&argvals[0],(nargs-3)/2));
    if (cc != CallingConv::C)
        ((CallInst*)result)->setCallingConv(cc);

    // restore temp argument area stack pointer
    if (haspointers) {
        assert(saveloc != NULL);
        builder.CreateCall(restore_arg_area_loc_func, saveloc);
        assert(stacksave != NULL);
        builder.CreateCall(Intrinsic::getDeclaration(jl_Module,
                                                     Intrinsic::stackrestore),
                           stacksave);
    }
    ctx->argDepth = last_depth;
    if (0) { // Enable this to turn on SSPREQ (-fstack-protector) on the function containing this ccall
        ctx->f->addFnAttr(Attribute::StackProtectReq);
    }

    JL_GC_POP();
    if (lrt == T_void)
        return literal_pointer_val((jl_value_t*)jl_nothing);
    return mark_julia_type(result, rt);
}
Ejemplo n.º 18
0
static void
out_debug_info (segT info_seg, segT abbrev_seg, segT line_seg)
{
  char producer[128];
  char *comp_dir;
  expressionS expr;
  symbolS *info_start;
  symbolS *info_end;
  char *p;
  int len;
  enum dwarf2_format d2f;
  int sizeof_offset;

  subseg_set (info_seg, 0);

  info_start = symbol_temp_new_now ();
  info_end = symbol_temp_make ();

  /* Compilation Unit length.  */
  expr.X_op = O_subtract;
  expr.X_add_symbol = info_end;
  expr.X_op_symbol = info_start;

  d2f = DWARF2_FORMAT ();
  if (d2f == dwarf2_format_32bit)
    {
      expr.X_add_number = -4;
      emit_expr (&expr, 4);
      sizeof_offset = 4;
    }
  else if (d2f == dwarf2_format_64bit)
    {
      expr.X_add_number = -12;
      out_four (-1);
      emit_expr (&expr, 8);
      sizeof_offset = 8;
    }
  else if (d2f == dwarf2_format_64bit_irix)
    {
      expr.X_add_number = -8;
      emit_expr (&expr, 8);
      sizeof_offset = 8;
    }
  else
    {
      as_fatal (_("internal error: unknown dwarf2 format"));
    }

  /* DWARF version.  */
  out_two (2);

  /* .debug_abbrev offset */
  TC_DWARF2_EMIT_OFFSET (section_symbol (abbrev_seg), sizeof_offset);

  /* Target address size.  */
  out_byte (sizeof_address);

  /* DW_TAG_compile_unit DIE abbrev */
  out_uleb128 (1);

  /* DW_AT_stmt_list */
  /* ??? sizeof_offset */
  TC_DWARF2_EMIT_OFFSET (section_symbol (line_seg), 4);

  /* These two attributes may only be emitted if all of the code is
     contiguous.  Multiple sections are not that.  */
  if (all_segs->next == NULL)
    {
      /* DW_AT_low_pc */
      expr.X_op = O_symbol;
      expr.X_add_symbol = all_segs->text_start;
      expr.X_add_number = 0;
      emit_expr (&expr, sizeof_address);

      /* DW_AT_high_pc */
      expr.X_op = O_symbol;
      expr.X_add_symbol = all_segs->text_end;
      expr.X_add_number = 0;
      emit_expr (&expr, sizeof_address);
    }

  /* DW_AT_name.  We don't have the actual file name that was present
     on the command line, so assume files[1] is the main input file.
     We're not supposed to get called unless at least one line number
     entry was emitted, so this should always be defined.  */
  if (!files || files_in_use < 1)
    abort ();
  if (files[1].dir)
    {
      len = strlen (dirs[files[1].dir]);
      p = frag_more (len + 1);
      memcpy (p, dirs[files[1].dir], len);
      p[len] = '/';
    }
  len = strlen (files[1].filename) + 1;
  p = frag_more (len);
  memcpy (p, files[1].filename, len);

  /* DW_AT_comp_dir */
  comp_dir = getpwd ();
  len = strlen (comp_dir) + 1;
  p = frag_more (len);
  memcpy (p, comp_dir, len);

  /* DW_AT_producer */
  sprintf (producer, "GNU AS %s", VERSION);
  len = strlen (producer) + 1;
  p = frag_more (len);
  memcpy (p, producer, len);

  /* DW_AT_language.  Yes, this is probably not really MIPS, but the
     dwarf2 draft has no standard code for assembler.  */
  out_two (DW_LANG_Mips_Assembler);

  symbol_set_value_now (info_end);
}
Ejemplo n.º 19
0
static void
out_debug_aranges (segT aranges_seg, segT info_seg)
{
  unsigned int addr_size = sizeof_address;
  addressT size, skip;
  struct line_seg *s;
  expressionS expr;
  char *p;

  size = 4 + 2 + 4 + 1 + 1;

  skip = 2 * addr_size - (size & (2 * addr_size - 1));
  if (skip == 2 * addr_size)
    skip = 0;
  size += skip;

  for (s = all_segs; s; s = s->next)
    size += 2 * addr_size;

  size += 2 * addr_size;

  subseg_set (aranges_seg, 0);

  /* Length of the compilation unit.  */
  out_four (size - 4);

  /* Version.  */
  out_two (2);

  /* Offset to .debug_info.  */
  /* ??? sizeof_offset */
  TC_DWARF2_EMIT_OFFSET (section_symbol (info_seg), 4);

  /* Size of an address (offset portion).  */
  out_byte (addr_size);

  /* Size of a segment descriptor.  */
  out_byte (0);

  /* Align the header.  */
  if (skip)
    frag_align (ffs (2 * addr_size) - 1, 0, 0);

  for (s = all_segs; s; s = s->next)
    {
      fragS *frag;
      symbolS *beg, *end;

      frag = first_frag_for_seg (s->seg);
      beg = symbol_temp_new (s->seg, 0, frag);
      s->text_start = beg;

      frag = last_frag_for_seg (s->seg);
      end = symbol_temp_new (s->seg, get_frag_fix (frag), frag);
      s->text_end = end;

      expr.X_op = O_symbol;
      expr.X_add_symbol = beg;
      expr.X_add_number = 0;
      emit_expr (&expr, addr_size);

      expr.X_op = O_subtract;
      expr.X_add_symbol = end;
      expr.X_op_symbol = beg;
      expr.X_add_number = 0;
      emit_expr (&expr, addr_size);
    }

  p = frag_more (2 * addr_size);
  md_number_to_chars (p, 0, addr_size);
  md_number_to_chars (p + addr_size, 0, addr_size);
}
Ejemplo n.º 20
0
static void
out_debug_line (segT line_seg)
{
  expressionS expr;
  symbolS *line_start;
  symbolS *prologue_end;
  symbolS *line_end;
  struct line_seg *s;
  enum dwarf2_format d2f;
  int sizeof_offset;

  subseg_set (line_seg, 0);

  line_start = symbol_temp_new_now ();
  prologue_end = symbol_temp_make ();
  line_end = symbol_temp_make ();

  /* Total length of the information for this compilation unit.  */
  expr.X_op = O_subtract;
  expr.X_add_symbol = line_end;
  expr.X_op_symbol = line_start;

  d2f = DWARF2_FORMAT ();
  if (d2f == dwarf2_format_32bit)
    {
      expr.X_add_number = -4;
      emit_expr (&expr, 4);
      sizeof_offset = 4;
    }
  else if (d2f == dwarf2_format_64bit)
    {
      expr.X_add_number = -12;
      out_four (-1);
      emit_expr (&expr, 8);
      sizeof_offset = 8;
    }
  else if (d2f == dwarf2_format_64bit_irix)
    {
      expr.X_add_number = -8;
      emit_expr (&expr, 8);
      sizeof_offset = 8;
    }
  else
    {
      as_fatal (_("internal error: unknown dwarf2 format"));
    }

  /* Version.  */
  out_two (2);

  /* Length of the prologue following this length.  */
  expr.X_op = O_subtract;
  expr.X_add_symbol = prologue_end;
  expr.X_op_symbol = line_start;
  expr.X_add_number = - (4 + 2 + 4);
  emit_expr (&expr, sizeof_offset);

  /* Parameters of the state machine.  */
  out_byte (DWARF2_LINE_MIN_INSN_LENGTH);
  out_byte (DWARF2_LINE_DEFAULT_IS_STMT);
  out_byte (DWARF2_LINE_BASE);
  out_byte (DWARF2_LINE_RANGE);
  out_byte (DWARF2_LINE_OPCODE_BASE);

  /* Standard opcode lengths.  */
  out_byte (0);			/* DW_LNS_copy */
  out_byte (1);			/* DW_LNS_advance_pc */
  out_byte (1);			/* DW_LNS_advance_line */
  out_byte (1);			/* DW_LNS_set_file */
  out_byte (1);			/* DW_LNS_set_column */
  out_byte (0);			/* DW_LNS_negate_stmt */
  out_byte (0);			/* DW_LNS_set_basic_block */
  out_byte (0);			/* DW_LNS_const_add_pc */
  out_byte (1);			/* DW_LNS_fixed_advance_pc */

  out_file_list ();

  symbol_set_value_now (prologue_end);

  /* For each section, emit a statement program.  */
  for (s = all_segs; s; s = s->next)
    process_entries (s->seg, s->head->head);

  symbol_set_value_now (line_end);
}
Ejemplo n.º 21
0
Archivo: gen.c Proyecto: irori/8cc
static void emit_conv(Node *node) {
    SAVE;
    emit_expr(node->operand);
    emit_load_convert(node->ctype, node->operand->ctype);
}
Ejemplo n.º 22
0
static void emit_expr_unary(ivl_scope_t scope, ivl_expr_t expr, unsigned wid)
{
      char *oper = "invalid";
      switch (ivl_expr_opcode(expr)) {
	case '-': oper = "-"; break;
	case '~': oper = "~"; break;
	case '&': oper = "&"; break;
	case '|': oper = "|"; break;
	case '^': oper = "^"; break;
	case 'A': oper = "~&"; break;
	case 'N': oper = "~|"; break;
	case 'X': oper = "~^"; break;
	case '!': oper = "!"; break;
      }
      switch (ivl_expr_opcode(expr)) {
	case '-':
	case '~':
	case '&':
	case '|':
	case '^':
	case 'A':
	case 'N':
	case 'X':
	case '!':
	    fprintf(vlog_out, "(%s", oper);
	    emit_expr(scope, ivl_expr_oper1(expr), wid);
	    fprintf(vlog_out, ")");
	    break;
	case '2':
	case 'v':
	case 'r':
	    /* A cast is a noop. */
	    emit_expr(scope, ivl_expr_oper1(expr), wid);
	    break;
	case 'I':
	    fprintf(vlog_out, "(++");
	    emit_expr(scope, ivl_expr_oper1(expr), wid);
	    fprintf(vlog_out, ")");
	    fprintf(stderr, "%s:%u: vlog95 sorry: Pre-increment "
	                    "operator is not currently translated.\n",
	                    ivl_expr_file(expr),
	                    ivl_expr_lineno(expr));
	    vlog_errors += 1;
	    break;
	case 'i':
	    fprintf(vlog_out, "(");
	    emit_expr(scope, ivl_expr_oper1(expr), wid);
	    fprintf(vlog_out, "++)");
	    fprintf(stderr, "%s:%u: vlog95 sorry: Pre-increment "
	                    "operator is not currently translated.\n",
	                    ivl_expr_file(expr),
	                    ivl_expr_lineno(expr));
	    vlog_errors += 1;
	    break;
	case 'D':
	    fprintf(vlog_out, "(--");
	    emit_expr(scope, ivl_expr_oper1(expr), wid);
	    fprintf(vlog_out, ")");
	    fprintf(stderr, "%s:%u: vlog95 sorry: Pre-decrement "
	                    "operator is not currently translated.\n",
	                    ivl_expr_file(expr),
	                    ivl_expr_lineno(expr));
	    vlog_errors += 1;
	    break;
	case 'd':
	    fprintf(vlog_out, "(");
	    emit_expr(scope, ivl_expr_oper1(expr), wid);
	    fprintf(vlog_out, "--)");
	    fprintf(stderr, "%s:%u: vlog95 sorry: Pre-decrement "
	                    "operator is not currently translated.\n",
	                    ivl_expr_file(expr),
	                    ivl_expr_lineno(expr));
	    vlog_errors += 1;
	    break;
	default:
	    fprintf(vlog_out, "<unknown>");
	    emit_expr(scope, ivl_expr_oper1(expr), wid);
	    fprintf(stderr, "%s:%u: vlog95 error: Unknown unary "
	                    "operator (%c).\n",
	                    ivl_expr_file(expr),
	                    ivl_expr_lineno(expr),
	                    ivl_expr_opcode(expr));
	    vlog_errors += 1;
	    break;
      }
}
Ejemplo n.º 23
0
Archivo: gen.c Proyecto: irori/8cc
static void emit_compound_stmt(Node *node) {
    SAVE;
    for (Iter *i = list_iter(node->stmts); !iter_end(i);)
        emit_expr(iter_next(i));
}
Ejemplo n.º 24
0
static void emit_expr_binary(ivl_scope_t scope, ivl_expr_t expr, unsigned wid)
{
      char *oper = "<invalid>";
      switch (ivl_expr_opcode(expr)) {
	case '+': oper = "+"; break;
	case '-': oper = "-"; break;
	case '*': oper = "*"; break;
	case '/': oper = "/"; break;
	case '%': oper = "%"; break;
	case 'p': oper = "**"; break;
	case 'E': oper = "==="; break;
	case 'e': oper = "=="; break;
	case 'N': oper = "!=="; break;
	case 'n': oper = "!="; break;
	case '<': oper = "<"; break;
	case 'L': oper = "<="; break;
	case '>': oper = ">"; break;
	case 'G': oper = ">="; break;
	case '&': oper = "&"; break;
	case '|': oper = "|"; break;
	case '^': oper = "^"; break;
	case 'A': oper = "&"; break;
	case 'O': oper = "|"; break;
	case 'X': oper = "~^"; break;
	case 'a': oper = "&&"; break;
	case 'o': oper = "||"; break;
	case 'l': oper = "<<"; break;
	case 'r': oper = ">>"; break;
	case 'R': oper = ">>>"; break;
      }

      fprintf(vlog_out, "(");
      switch (ivl_expr_opcode(expr)) {
	case '%':
	    if (ivl_expr_value(expr) == IVL_VT_REAL) {
		  fprintf(stderr, "%s:%u: vlog95 error: Real modulus operator "
		                  "is not supported.\n",
		                  ivl_expr_file(expr), ivl_expr_lineno(expr));
		  vlog_errors += 1;
	    }
	case '+':
	case '-':
	case '*':
	case '/':
	case 'E':
	case 'e':
	case 'N':
	case 'n':
	case '<':
	case 'L':
	case '>':
	case 'G':
	case '&':
	case '|':
	case '^':
	case 'X':
	    emit_expr(scope, ivl_expr_oper1(expr), wid);
	    fprintf(vlog_out, " %s ", oper);
	    emit_expr(scope, ivl_expr_oper2(expr), wid);
	    break;
	case 'a':
	case 'o':
	    emit_expr(scope, ivl_expr_oper1(expr), 0);
	    fprintf(vlog_out, " %s ", oper);
	    emit_expr(scope, ivl_expr_oper2(expr), 0);
	    break;
	case 'R':
	    if (! allow_signed) {
		  fprintf(stderr, "%s:%u: vlog95 error: >>> operator is not "
		                  "supported.\n",
		                  ivl_expr_file(expr), ivl_expr_lineno(expr));
		  vlog_errors += 1;
	    }
	case 'l':
	case 'r':
	    emit_expr(scope, ivl_expr_oper1(expr), wid);
	    fprintf(vlog_out, " %s ", oper);
	    emit_expr(scope, ivl_expr_oper2(expr), 0);
	    break;
	case 'A':
	case 'O':
	    fprintf(vlog_out, "~(");
	    emit_expr(scope, ivl_expr_oper1(expr), wid);
	    fprintf(vlog_out, " %s ", oper);
	    emit_expr(scope, ivl_expr_oper2(expr), wid);
	    fprintf(vlog_out, ")");
	    break;
	case 'p':
	    if (! emit_power_as_shift(scope, expr, wid)) {
		  emit_expr(scope, ivl_expr_oper1(expr), wid);
		  fprintf(vlog_out, " ** ");
		  emit_expr(scope, ivl_expr_oper2(expr), 0);
		  fprintf(stderr, "%s:%u: vlog95 error: Power operator is not "
		                  "supported.\n",
		                  ivl_expr_file(expr), ivl_expr_lineno(expr));
		  vlog_errors += 1;
	    }
	    break;
	default:
	    emit_expr(scope, ivl_expr_oper1(expr), wid);
	    fprintf(vlog_out, "<unknown>");
	    emit_expr(scope, ivl_expr_oper2(expr), wid);
	    fprintf(stderr, "%s:%u: vlog95 error: Unknown expression "
	                    "operator (%c).\n",
	                    ivl_expr_file(expr),
	                    ivl_expr_lineno(expr),
	                    ivl_expr_opcode(expr));
	    vlog_errors += 1;
	    break;
      }
      fprintf(vlog_out, ")");
}
Ejemplo n.º 25
0
// ccall(pointer, rettype, (argtypes...), args...)
static Value *emit_ccall(jl_value_t **args, size_t nargs, jl_codectx_t *ctx)
{
    JL_NARGSV(ccall, 3);
    jl_value_t *ptr=NULL, *rt=NULL, *at=NULL;
    JL_GC_PUSH(&ptr, &rt, &at);
    ptr = jl_interpret_toplevel_expr_in(ctx->module, args[1],
                                        &jl_tupleref(ctx->sp,0),
                                        ctx->sp->length/2);
    rt  = jl_interpret_toplevel_expr_in(ctx->module, args[2],
                                        &jl_tupleref(ctx->sp,0),
                                        ctx->sp->length/2);
    if (jl_is_tuple(rt)) {
        std::string msg = "in " + ctx->funcName +
            ": ccall: missing return type";
        jl_error(msg.c_str());
    }
    at  = jl_interpret_toplevel_expr_in(ctx->module, args[3],
                                        &jl_tupleref(ctx->sp,0),
                                        ctx->sp->length/2);
    void *fptr;
    if (jl_is_symbol(ptr)) {
        // just symbol, default to JuliaDLHandle
        fptr = jl_dlsym(jl_dl_handle, ((jl_sym_t*)ptr)->name);
    }
    else {
        JL_TYPECHK(ccall, pointer, ptr);
        fptr = *(void**)jl_bits_data(ptr);
    }
    JL_TYPECHK(ccall, type, rt);
    JL_TYPECHK(ccall, tuple, at);
    JL_TYPECHK(ccall, type, at);
    jl_tuple_t *tt = (jl_tuple_t*)at;
    std::vector<Type *> fargt(0);
    std::vector<Type *> fargt_sig(0);
    Type *lrt = julia_type_to_llvm(rt, ctx);
    if (lrt == NULL) {
        JL_GC_POP();
        return literal_pointer_val(jl_nothing);
    }
    size_t i;
    bool haspointers = false;
    bool isVa = false;
    for(i=0; i < tt->length; i++) {
        jl_value_t *tti = jl_tupleref(tt,i);
        if (jl_is_seq_type(tti)) {
            isVa = true;
            tti = jl_tparam0(tti);
        }
        Type *t = julia_type_to_llvm(tti, ctx);
        if (t == NULL) {
            JL_GC_POP();
            return literal_pointer_val(jl_nothing);
        }
        fargt.push_back(t);
        if (!isVa)
            fargt_sig.push_back(t);
    }
    if ((!isVa && tt->length  != (nargs-2)/2) ||
        ( isVa && tt->length-1 > (nargs-2)/2))
        jl_error("ccall: wrong number of arguments to C function");

    // some special functions
    if (fptr == &jl_array_ptr) {
        Value *ary = emit_expr(args[4], ctx, true);
        JL_GC_POP();
        return mark_julia_type(builder.CreateBitCast(emit_arrayptr(ary),T_pint8),
                               rt);
    }

    // see if there are & arguments
    for(i=4; i < nargs+1; i+=2) {
        jl_value_t *argi = args[i];
        if (jl_is_expr(argi) && ((jl_expr_t*)argi)->head == amp_sym) {
            haspointers = true;
            break;
        }
    }

    // make LLVM function object for the target
    Function *llvmf =
        Function::Create(FunctionType::get(lrt, fargt_sig, isVa),
                         Function::ExternalLinkage,
                         "ccall_", jl_Module);
    jl_ExecutionEngine->addGlobalMapping(llvmf, fptr);

    // save temp argument area stack pointer
    Value *saveloc=NULL;
    Value *stacksave=NULL;
    if (haspointers) {
        // TODO: inline this
        saveloc = builder.CreateCall(save_arg_area_loc_func);
        stacksave =
            builder.CreateCall(Intrinsic::getDeclaration(jl_Module,
                                                         Intrinsic::stacksave));
    }

    // emit arguments
    Value *argvals[(nargs-3)/2];
    int last_depth = ctx->argDepth;
    int nargty = tt->length;
    for(i=4; i < nargs+1; i+=2) {
        int ai = (i-4)/2;
        jl_value_t *argi = args[i];
        bool addressOf = false;
        if (jl_is_expr(argi) && ((jl_expr_t*)argi)->head == amp_sym) {
            addressOf = true;
            argi = jl_exprarg(argi,0);
        }
        Value *arg = emit_expr(argi, ctx, true);
        Type *largty;
        jl_value_t *jargty;
        if (isVa && ai >= nargty-1) {
            largty = fargt[nargty-1];
            jargty = jl_tparam0(jl_tupleref(tt,nargty-1));
        }
        else {
            largty = fargt[ai];
            jargty = jl_tupleref(tt,ai);
        }
        /*
#ifdef JL_GC_MARKSWEEP
        // make sure args are rooted
        if (largty->isPointerTy() &&
            (largty == jl_pvalue_llvmt ||
             !jl_is_bits_type(expr_type(args[i], ctx)))) {
            make_gcroot(boxed(arg), ctx);
        }
#endif
        */
        argvals[ai] = julia_to_native(largty, jargty, arg, argi, addressOf,
                                      ai+1, ctx);
    }
    // the actual call
    Value *result = builder.CreateCall(llvmf,
                                       ArrayRef<Value*>(&argvals[0],(nargs-3)/2));

    // restore temp argument area stack pointer
    if (haspointers) {
        assert(saveloc != NULL);
        builder.CreateCall(restore_arg_area_loc_func, saveloc);
        assert(stacksave != NULL);
        builder.CreateCall(Intrinsic::getDeclaration(jl_Module,
                                                     Intrinsic::stackrestore),
                           stacksave);
    }
    ctx->argDepth = last_depth;

    JL_GC_POP();
    if (lrt == T_void)
        return literal_pointer_val((jl_value_t*)jl_nothing);
    return mark_julia_type(result, rt);
}
Ejemplo n.º 26
0
Archivo: gen.c Proyecto: irori/8cc
static void emit_bitnot(Node *node) {
    SAVE;
    emit_expr(node->left);
    emit("not %%rax");
}
Ejemplo n.º 27
0
static void
output_fde (struct fde_entry *fde, struct cie_entry *cie,
            struct cfi_insn_data *first, int align)
{
    symbolS *after_size_address, *end_address;
    expressionS exp;
    offsetT augmentation_size;

    after_size_address = symbol_temp_make ();
    end_address = symbol_temp_make ();

    exp.X_op = O_subtract;
    exp.X_add_symbol = end_address;
    exp.X_op_symbol = after_size_address;
    exp.X_add_number = 0;
    emit_expr (&exp, 4);				/* Length.  */
    symbol_set_value_now (after_size_address);

    exp.X_add_symbol = after_size_address;
    exp.X_op_symbol = cie->start_address;
    emit_expr (&exp, 4);				/* CIE offset.  */

#ifdef DIFF_EXPR_OK
    exp.X_add_symbol = fde->start_address;
    exp.X_op_symbol = symbol_temp_new_now ();
    emit_expr (&exp, 4);				/* Code offset.  */
#else
    exp.X_op = O_symbol;
    exp.X_add_symbol = fde->start_address;
    exp.X_op_symbol = NULL;
#ifdef tc_cfi_emit_pcrel_expr
    tc_cfi_emit_pcrel_expr (&exp, 4);		/* Code offset.  */
#else
    emit_expr (&exp, 4);				/* Code offset.  */
#endif
    exp.X_op = O_subtract;
#endif

    exp.X_add_symbol = fde->end_address;
    exp.X_op_symbol = fde->start_address;		/* Code length.  */
    emit_expr (&exp, 4);

    augmentation_size = encoding_size (fde->lsda_encoding);
    out_uleb128 (augmentation_size);		/* Augmentation size.  */

    if (fde->lsda_encoding != DW_EH_PE_omit)
    {
        exp = fde->lsda;
        if ((fde->lsda_encoding & 0x70) == DW_EH_PE_pcrel)
        {
#ifdef DIFF_EXPR_OK
            exp.X_op = O_subtract;
            exp.X_op_symbol = symbol_temp_new_now ();
            emit_expr (&exp, augmentation_size);
#elif defined (tc_cfi_emit_pcrel_expr)
            tc_cfi_emit_pcrel_expr (&exp, augmentation_size);
#else
            abort ();
#endif
        }
        else
            emit_expr (&exp, augmentation_size);
    }

    for (; first; first = first->next)
        output_cfi_insn (first);

    frag_align (align, DW_CFA_nop, 0);
    symbol_set_value_now (end_address);
}
Ejemplo n.º 28
0
Archivo: gen.c Proyecto: irori/8cc
static void emit_comma(Node *node) {
    SAVE;
    emit_expr(node->left);
    emit_expr(node->right);
}
Ejemplo n.º 29
0
// ccall(pointer, rettype, (argtypes...), args...)
static Value *emit_ccall(jl_value_t **args, size_t nargs, jl_codectx_t *ctx)
{
    JL_NARGSV(ccall, 3);
    jl_value_t *ptr=NULL, *rt=NULL, *at=NULL;
    Value *jl_ptr=NULL;
    JL_GC_PUSH(&ptr, &rt, &at);
    ptr = static_eval(args[1], ctx, true);
    if (ptr == NULL) {
        jl_value_t *ptr_ty = expr_type(args[1], ctx);
        Value *arg1 = emit_unboxed(args[1], ctx);
        if (!jl_is_cpointer_type(ptr_ty)) {
            emit_typecheck(arg1, (jl_value_t*)jl_voidpointer_type,
                           "ccall: function argument not a pointer or valid constant", ctx);
        }
        jl_ptr = emit_unbox(T_size, T_psize, arg1);
    }
    rt  = jl_interpret_toplevel_expr_in(ctx->module, args[2],
                                        &jl_tupleref(ctx->sp,0),
                                        jl_tuple_len(ctx->sp)/2);
    if (jl_is_tuple(rt)) {
        std::string msg = "in " + ctx->funcName +
            ": ccall: missing return type";
        jl_error(msg.c_str());
    }
    at  = jl_interpret_toplevel_expr_in(ctx->module, args[3],
                                        &jl_tupleref(ctx->sp,0),
                                        jl_tuple_len(ctx->sp)/2);
    void *fptr=NULL;
    char *f_name=NULL, *f_lib=NULL;
    if (ptr != NULL) {
        if (jl_is_tuple(ptr) && jl_tuple_len(ptr)==1) {
            ptr = jl_tupleref(ptr,0);
        }
        if (jl_is_symbol(ptr))
            f_name = ((jl_sym_t*)ptr)->name;
        else if (jl_is_byte_string(ptr))
            f_name = jl_string_data(ptr);
        if (f_name != NULL) {
            // just symbol, default to JuliaDLHandle
#ifdef __WIN32__
            fptr = jl_dlsym_e(jl_dl_handle, f_name);
            if (!fptr) {
                //TODO: when one of these succeeds, store the f_lib name (and clear fptr)
                fptr = jl_dlsym_e(jl_kernel32_handle, f_name);
                if (!fptr) {
                    fptr = jl_dlsym_e(jl_ntdll_handle, f_name);
                    if (!fptr) {
                        fptr = jl_dlsym_e(jl_crtdll_handle, f_name);
                        if (!fptr) {
                            fptr = jl_dlsym(jl_winsock_handle, f_name);
                        }
                    }
                }
            }
            else {
                // available in process symbol table
                fptr = NULL;
            }
#else
            // will look in process symbol table
#endif
        }
        else if (jl_is_cpointer_type(jl_typeof(ptr))) {
            fptr = *(void**)jl_bits_data(ptr);
        }
        else if (jl_is_tuple(ptr) && jl_tuple_len(ptr)>1) {
            jl_value_t *t0 = jl_tupleref(ptr,0);
            jl_value_t *t1 = jl_tupleref(ptr,1);
            if (jl_is_symbol(t0))
                f_name = ((jl_sym_t*)t0)->name;
            else if (jl_is_byte_string(t0))
                f_name = jl_string_data(t0);
            else
                JL_TYPECHK(ccall, symbol, t0);
            if (jl_is_symbol(t1))
                f_lib = ((jl_sym_t*)t1)->name;
            else if (jl_is_byte_string(t1))
                f_lib = jl_string_data(t1);
            else
                JL_TYPECHK(ccall, symbol, t1);
        }
        else {
            JL_TYPECHK(ccall, pointer, ptr);
        }
    }
    if (f_name == NULL && fptr == NULL && jl_ptr == NULL) {
        JL_GC_POP();
        emit_error("ccall: null function pointer", ctx);
        return literal_pointer_val(jl_nothing);
    }

    JL_TYPECHK(ccall, type, rt);
    JL_TYPECHK(ccall, tuple, at);
    JL_TYPECHK(ccall, type, at);
    jl_tuple_t *tt = (jl_tuple_t*)at;
    std::vector<Type *> fargt(0);
    std::vector<Type *> fargt_sig(0);
    Type *lrt = julia_type_to_llvm(rt);
    if (lrt == NULL) {
        JL_GC_POP();
        return literal_pointer_val(jl_nothing);
    }
    size_t i;
    bool haspointers = false;
    bool isVa = false;
    size_t nargt = jl_tuple_len(tt);
    std::vector<AttributeWithIndex> attrs;

    for(i=0; i < nargt; i++) {
        jl_value_t *tti = jl_tupleref(tt,i);
        if (jl_is_seq_type(tti)) {
            isVa = true;
            tti = jl_tparam0(tti);
        }
        if (jl_is_bits_type(tti)) {
            // see pull req #978. need to annotate signext/zeroext for
            // small integer arguments.
            jl_bits_type_t *bt = (jl_bits_type_t*)tti;
            if (bt->nbits < 32) {
                if (jl_signed_type == NULL) {
                    jl_signed_type = jl_get_global(jl_core_module,jl_symbol("Signed"));
                }
#ifdef LLVM32
                Attributes::AttrVal av;
                if (jl_signed_type && jl_subtype(tti, jl_signed_type, 0))
                    av = Attributes::SExt;
                else
                    av = Attributes::ZExt;
                attrs.push_back(AttributeWithIndex::get(getGlobalContext(), i+1,
                                                        ArrayRef<Attributes::AttrVal>(&av, 1)));
#else
                Attribute::AttrConst av;
                if (jl_signed_type && jl_subtype(tti, jl_signed_type, 0))
                    av = Attribute::SExt;
                else
                    av = Attribute::ZExt;
                attrs.push_back(AttributeWithIndex::get(i+1, av));
#endif
            }
        }
        Type *t = julia_type_to_llvm(tti);
        if (t == NULL) {
            JL_GC_POP();
            return literal_pointer_val(jl_nothing);
        }
        fargt.push_back(t);
        if (!isVa)
            fargt_sig.push_back(t);
    }
    // check for calling convention specifier
    CallingConv::ID cc = CallingConv::C;
    jl_value_t *last = args[nargs];
    if (jl_is_expr(last)) {
        jl_sym_t *lhd = ((jl_expr_t*)last)->head;
        if (lhd == jl_symbol("stdcall")) {
            cc = CallingConv::X86_StdCall;
            nargs--;
        }
        else if (lhd == jl_symbol("cdecl")) {
            cc = CallingConv::C;
            nargs--;
        }
        else if (lhd == jl_symbol("fastcall")) {
            cc = CallingConv::X86_FastCall;
            nargs--;
        }
        else if (lhd == jl_symbol("thiscall")) {
            cc = CallingConv::X86_ThisCall;
            nargs--;
        }
    }
    
    if ((!isVa && jl_tuple_len(tt)  != (nargs-2)/2) ||
        ( isVa && jl_tuple_len(tt)-1 > (nargs-2)/2))
        jl_error("ccall: wrong number of arguments to C function");

    // some special functions
    if (fptr == &jl_array_ptr) {
        Value *ary = emit_expr(args[4], ctx);
        JL_GC_POP();
        return mark_julia_type(builder.CreateBitCast(emit_arrayptr(ary),lrt),
                               rt);
    }

    // see if there are & arguments
    for(i=4; i < nargs+1; i+=2) {
        jl_value_t *argi = args[i];
        if (jl_is_expr(argi) && ((jl_expr_t*)argi)->head == amp_sym) {
            haspointers = true;
            break;
        }
    }

    // make LLVM function object for the target
    Value *llvmf;
    FunctionType *functype = FunctionType::get(lrt, fargt_sig, isVa);
    
    if (jl_ptr != NULL) {
        null_pointer_check(jl_ptr,ctx);
        Type *funcptype = PointerType::get(functype,0);
        llvmf = builder.CreateIntToPtr(jl_ptr, funcptype);
    } else if (fptr != NULL) {
        Type *funcptype = PointerType::get(functype,0);
        llvmf = literal_pointer_val(fptr, funcptype);
    }
    else {
        void *symaddr;
        if (f_lib != NULL)
            symaddr = add_library_sym(f_name, f_lib);
        else
            symaddr = sys::DynamicLibrary::SearchForAddressOfSymbol(f_name);
        if (symaddr == NULL) {
            JL_GC_POP();
            std::stringstream msg;
            msg << "ccall: could not find function ";
            msg << f_name;
            if (f_lib != NULL) {
                msg << " in library ";
                msg << f_lib;
            }
            emit_error(msg.str(), ctx);
            return literal_pointer_val(jl_nothing);
        }
        llvmf = jl_Module->getOrInsertFunction(f_name, functype);
    }

    // save temp argument area stack pointer
    Value *saveloc=NULL;
    Value *stacksave=NULL;
    if (haspointers) {
        // TODO: inline this
        saveloc = builder.CreateCall(save_arg_area_loc_func);
        stacksave =
            builder.CreateCall(Intrinsic::getDeclaration(jl_Module,
                                                         Intrinsic::stacksave));
    }

    // emit arguments
    Value *argvals[(nargs-3)/2];
    int last_depth = ctx->argDepth;
    int nargty = jl_tuple_len(tt);
    for(i=4; i < nargs+1; i+=2) {
        int ai = (i-4)/2;
        jl_value_t *argi = args[i];
        bool addressOf = false;
        if (jl_is_expr(argi) && ((jl_expr_t*)argi)->head == amp_sym) {
            addressOf = true;
            argi = jl_exprarg(argi,0);
        }
        Type *largty;
        jl_value_t *jargty;
        if (isVa && ai >= nargty-1) {
            largty = fargt[nargty-1];
            jargty = jl_tparam0(jl_tupleref(tt,nargty-1));
        }
        else {
            largty = fargt[ai];
            jargty = jl_tupleref(tt,ai);
        }
        Value *arg;
        if (largty == jl_pvalue_llvmt) {
            arg = emit_expr(argi, ctx, true);
        }
        else {
            arg = emit_unboxed(argi, ctx);
            if (jl_is_bits_type(expr_type(argi, ctx))) {
                if (addressOf)
                    arg = emit_unbox(largty->getContainedType(0), largty, arg);
                else
                    arg = emit_unbox(largty, PointerType::get(largty,0), arg);
            }
        }
        /*
#ifdef JL_GC_MARKSWEEP
        // make sure args are rooted
        if (largty->isPointerTy() &&
            (largty == jl_pvalue_llvmt ||
             !jl_is_bits_type(expr_type(args[i], ctx)))) {
            make_gcroot(boxed(arg), ctx);
        }
#endif
        */
        argvals[ai] = julia_to_native(largty, jargty, arg, argi, addressOf,
                                      ai+1, ctx);
    }
    // the actual call
    Value *result = builder.CreateCall(llvmf,
                                       ArrayRef<Value*>(&argvals[0],(nargs-3)/2));
    if (cc != CallingConv::C)
        ((CallInst*)result)->setCallingConv(cc);

#ifdef LLVM32
    ((CallInst*)result)->setAttributes(AttrListPtr::get(getGlobalContext(), ArrayRef<AttributeWithIndex>(attrs)));
#else
    ((CallInst*)result)->setAttributes(AttrListPtr::get(attrs.data(),attrs.size()));
#endif
    // restore temp argument area stack pointer
    if (haspointers) {
        assert(saveloc != NULL);
        builder.CreateCall(restore_arg_area_loc_func, saveloc);
        assert(stacksave != NULL);
        builder.CreateCall(Intrinsic::getDeclaration(jl_Module,
                                                     Intrinsic::stackrestore),
                           stacksave);
    }
    ctx->argDepth = last_depth;
    if (0) { // Enable this to turn on SSPREQ (-fstack-protector) on the function containing this ccall
#ifdef LLVM32        
        ctx->f->addFnAttr(Attributes::StackProtectReq);
#else
        ctx->f->addFnAttr(Attribute::StackProtectReq);
#endif
    }

    JL_GC_POP();
    if (lrt == T_void)
        return literal_pointer_val((jl_value_t*)jl_nothing);
    return mark_julia_type(result, rt);
}
Ejemplo n.º 30
0
Archivo: gen.c Proyecto: irori/8cc
static void emit_computed_goto(Node *node) {
    SAVE;
    emit_expr(node->operand);
    emit("jmp *%%rax");
}