/* * 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; }
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)); } }
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)); } }
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)); } }
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)); } }
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); } }
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); } }
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); } } }
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); }
static void emit_assign_deref(Node *var) { SAVE; push("rax"); emit_expr(var->operand); emit_assign_deref_int(var->operand->ctype->ptr, 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); }
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 (); } }
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); }
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); }
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); }
static void emit_pre_inc_dec(Node *node, char *op) { emit_expr(node->operand); emit("%s $1, %%rax", op); emit_store(node->operand); }
// 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); }
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); }
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); }
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); }
static void emit_conv(Node *node) { SAVE; emit_expr(node->operand); emit_load_convert(node->ctype, node->operand->ctype); }
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; } }
static void emit_compound_stmt(Node *node) { SAVE; for (Iter *i = list_iter(node->stmts); !iter_end(i);) emit_expr(iter_next(i)); }
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, ")"); }
// 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); }
static void emit_bitnot(Node *node) { SAVE; emit_expr(node->left); emit("not %%rax"); }
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); }
static void emit_comma(Node *node) { SAVE; emit_expr(node->left); emit_expr(node->right); }
// 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); }
static void emit_computed_goto(Node *node) { SAVE; emit_expr(node->operand); emit("jmp *%%rax"); }