import std::map::{hashmap, str_hash}; import libc::{c_uint, c_int}; import lib::llvm::llvm; import syntax::codemap; import codemap::span; import lib::llvm::{ValueRef, TypeRef, BasicBlockRef, BuilderRef, ModuleRef}; import lib::llvm::{Opcode, IntPredicate, RealPredicate, True, False, CallConv, TypeKind, AtomicBinOp, AtomicOrdering}; import common::*; import driver::session::session; fn B(cx: block) -> BuilderRef { let b = cx.fcx.ccx.builder.B; llvm::LLVMPositionBuilderAtEnd(b, cx.llbb); ret b; } fn count_insn(cx: block, category: ~str) { if cx.ccx().sess.count_llvm_insns() { let h = cx.ccx().stats.llvm_insns; let v = cx.ccx().stats.llvm_insn_ctxt; // Build version of path with cycles removed. // Pass 1: scan table mapping str -> rightmost pos. let mm = str_hash(); let len = vec::len(*v); let mut i = 0u; while i < len { mm.insert(copy v[i], i); i += 1u; } // Pass 2: concat strings for each elt, skipping // forwards over any cycles by advancing to rightmost // occurrence of each element in path. let mut s = ~"."; i = 0u; while i < len { let e = v[i]; i = mm.get(e); s += ~"/"; s += e; i += 1u; } s += ~"/"; s += category; let n = alt h.find(s) { some(n) { n } _ { 0u } }; h.insert(s, n+1u); } } // The difference between a block being unreachable and being terminated is // somewhat obscure, and has to do with error checking. When a block is // terminated, we're saying that trying to add any further statements in the // block is an error. On the other hand, if something is unreachable, that // means that the block was terminated in some way that we don't want to check // for (fail/break/ret statements, call to diverging functions, etc), and // further instructions to the block should simply be ignored. fn RetVoid(cx: block) { if cx.unreachable { ret; } assert (!cx.terminated); cx.terminated = true; count_insn(cx, ~"retvoid"); llvm::LLVMBuildRetVoid(B(cx)); } fn Ret(cx: block, V: ValueRef) { if cx.unreachable { ret; } assert (!cx.terminated); cx.terminated = true; count_insn(cx, ~"ret"); llvm::LLVMBuildRet(B(cx), V); } fn AggregateRet(cx: block, RetVals: ~[ValueRef]) { if cx.unreachable { ret; } assert (!cx.terminated); cx.terminated = true; unsafe { llvm::LLVMBuildAggregateRet(B(cx), vec::unsafe::to_ptr(RetVals), RetVals.len() as c_uint); } } fn Br(cx: block, Dest: BasicBlockRef) { if cx.unreachable { ret; } assert (!cx.terminated); cx.terminated = true; count_insn(cx, ~"br"); llvm::LLVMBuildBr(B(cx), Dest); } fn CondBr(cx: block, If: ValueRef, Then: BasicBlockRef, Else: BasicBlockRef) { if cx.unreachable { ret; } assert (!cx.terminated); cx.terminated = true; count_insn(cx, ~"condbr"); llvm::LLVMBuildCondBr(B(cx), If, Then, Else); } fn Switch(cx: block, V: ValueRef, Else: BasicBlockRef, NumCases: uint) -> ValueRef { if cx.unreachable { ret _Undef(V); } assert !cx.terminated; cx.terminated = true; ret llvm::LLVMBuildSwitch(B(cx), V, Else, NumCases as c_uint); } fn AddCase(S: ValueRef, OnVal: ValueRef, Dest: BasicBlockRef) { if llvm::LLVMIsUndef(S) == lib::llvm::True { ret; } llvm::LLVMAddCase(S, OnVal, Dest); } fn IndirectBr(cx: block, Addr: ValueRef, NumDests: uint) { if cx.unreachable { ret; } assert (!cx.terminated); cx.terminated = true; count_insn(cx, ~"indirectbr"); llvm::LLVMBuildIndirectBr(B(cx), Addr, NumDests as c_uint); } // This is a really awful way to get a zero-length c-string, but better (and a // lot more efficient) than doing str::as_c_str("", ...) every time. fn noname() -> *libc::c_char unsafe { const cnull: uint = 0u; ret unsafe::reinterpret_cast(ptr::addr_of(cnull)); } fn Invoke(cx: block, Fn: ValueRef, Args: ~[ValueRef], Then: BasicBlockRef, Catch: BasicBlockRef) { if cx.unreachable { ret; } assert (!cx.terminated); cx.terminated = true; #debug["Invoke(%s with arguments (%s))", val_str(cx.ccx().tn, Fn), str::connect(vec::map(Args, |a| val_str(cx.ccx().tn, a)), ~", ")]; unsafe { count_insn(cx, ~"invoke"); llvm::LLVMBuildInvoke(B(cx), Fn, vec::unsafe::to_ptr(Args), Args.len() as c_uint, Then, Catch, noname()); } } fn FastInvoke(cx: block, Fn: ValueRef, Args: ~[ValueRef], Then: BasicBlockRef, Catch: BasicBlockRef) { if cx.unreachable { ret; } assert (!cx.terminated); cx.terminated = true; unsafe { count_insn(cx, ~"fastinvoke"); let v = llvm::LLVMBuildInvoke(B(cx), Fn, vec::unsafe::to_ptr(Args), Args.len() as c_uint, Then, Catch, noname()); lib::llvm::SetInstructionCallConv(v, lib::llvm::FastCallConv); } } fn Unreachable(cx: block) { if cx.unreachable { ret; } cx.unreachable = true; if !cx.terminated { count_insn(cx, ~"unreachable"); llvm::LLVMBuildUnreachable(B(cx)); } } fn _Undef(val: ValueRef) -> ValueRef { ret llvm::LLVMGetUndef(val_ty(val)); } /* Arithmetic */ fn Add(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef { if cx.unreachable { ret _Undef(LHS); } count_insn(cx, ~"add"); ret llvm::LLVMBuildAdd(B(cx), LHS, RHS, noname()); } fn NSWAdd(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef { if cx.unreachable { ret _Undef(LHS); } count_insn(cx, ~"nswadd"); ret llvm::LLVMBuildNSWAdd(B(cx), LHS, RHS, noname()); } fn NUWAdd(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef { if cx.unreachable { ret _Undef(LHS); } count_insn(cx, ~"nuwadd"); ret llvm::LLVMBuildNUWAdd(B(cx), LHS, RHS, noname()); } fn FAdd(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef { if cx.unreachable { ret _Undef(LHS); } count_insn(cx, ~"fadd"); ret llvm::LLVMBuildFAdd(B(cx), LHS, RHS, noname()); } fn Sub(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef { if cx.unreachable { ret _Undef(LHS); } count_insn(cx, ~"sub"); ret llvm::LLVMBuildSub(B(cx), LHS, RHS, noname()); } fn NSWSub(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef { if cx.unreachable { ret _Undef(LHS); } count_insn(cx, ~"nwsub"); ret llvm::LLVMBuildNSWSub(B(cx), LHS, RHS, noname()); } fn NUWSub(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef { if cx.unreachable { ret _Undef(LHS); } count_insn(cx, ~"nuwsub"); ret llvm::LLVMBuildNUWSub(B(cx), LHS, RHS, noname()); } fn FSub(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef { if cx.unreachable { ret _Undef(LHS); } count_insn(cx, ~"sub"); ret llvm::LLVMBuildFSub(B(cx), LHS, RHS, noname()); } fn Mul(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef { if cx.unreachable { ret _Undef(LHS); } count_insn(cx, ~"mul"); ret llvm::LLVMBuildMul(B(cx), LHS, RHS, noname()); } fn NSWMul(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef { if cx.unreachable { ret _Undef(LHS); } count_insn(cx, ~"nswmul"); ret llvm::LLVMBuildNSWMul(B(cx), LHS, RHS, noname()); } fn NUWMul(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef { if cx.unreachable { ret _Undef(LHS); } count_insn(cx, ~"nuwmul"); ret llvm::LLVMBuildNUWMul(B(cx), LHS, RHS, noname()); } fn FMul(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef { if cx.unreachable { ret _Undef(LHS); } count_insn(cx, ~"fmul"); ret llvm::LLVMBuildFMul(B(cx), LHS, RHS, noname()); } fn UDiv(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef { if cx.unreachable { ret _Undef(LHS); } count_insn(cx, ~"udiv"); ret llvm::LLVMBuildUDiv(B(cx), LHS, RHS, noname()); } fn SDiv(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef { if cx.unreachable { ret _Undef(LHS); } count_insn(cx, ~"sdiv"); ret llvm::LLVMBuildSDiv(B(cx), LHS, RHS, noname()); } fn ExactSDiv(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef { if cx.unreachable { ret _Undef(LHS); } count_insn(cx, ~"extractsdiv"); ret llvm::LLVMBuildExactSDiv(B(cx), LHS, RHS, noname()); } fn FDiv(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef { if cx.unreachable { ret _Undef(LHS); } count_insn(cx, ~"fdiv"); ret llvm::LLVMBuildFDiv(B(cx), LHS, RHS, noname()); } fn URem(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef { if cx.unreachable { ret _Undef(LHS); } count_insn(cx, ~"urem"); ret llvm::LLVMBuildURem(B(cx), LHS, RHS, noname()); } fn SRem(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef { if cx.unreachable { ret _Undef(LHS); } count_insn(cx, ~"srem"); ret llvm::LLVMBuildSRem(B(cx), LHS, RHS, noname()); } fn FRem(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef { if cx.unreachable { ret _Undef(LHS); } count_insn(cx, ~"frem"); ret llvm::LLVMBuildFRem(B(cx), LHS, RHS, noname()); } fn Shl(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef { if cx.unreachable { ret _Undef(LHS); } count_insn(cx, ~"shl"); ret llvm::LLVMBuildShl(B(cx), LHS, RHS, noname()); } fn LShr(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef { if cx.unreachable { ret _Undef(LHS); } count_insn(cx, ~"lshr"); ret llvm::LLVMBuildLShr(B(cx), LHS, RHS, noname()); } fn AShr(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef { if cx.unreachable { ret _Undef(LHS); } count_insn(cx, ~"ashr"); ret llvm::LLVMBuildAShr(B(cx), LHS, RHS, noname()); } fn And(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef { if cx.unreachable { ret _Undef(LHS); } count_insn(cx, ~"and"); ret llvm::LLVMBuildAnd(B(cx), LHS, RHS, noname()); } fn Or(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef { if cx.unreachable { ret _Undef(LHS); } count_insn(cx, ~"or"); ret llvm::LLVMBuildOr(B(cx), LHS, RHS, noname()); } fn Xor(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef { if cx.unreachable { ret _Undef(LHS); } count_insn(cx, ~"xor"); ret llvm::LLVMBuildXor(B(cx), LHS, RHS, noname()); } fn BinOp(cx: block, Op: Opcode, LHS: ValueRef, RHS: ValueRef) -> ValueRef { if cx.unreachable { ret _Undef(LHS); } count_insn(cx, ~"binop"); ret llvm::LLVMBuildBinOp(B(cx), Op, LHS, RHS, noname()); } fn Neg(cx: block, V: ValueRef) -> ValueRef { if cx.unreachable { ret _Undef(V); } count_insn(cx, ~"neg"); ret llvm::LLVMBuildNeg(B(cx), V, noname()); } fn NSWNeg(cx: block, V: ValueRef) -> ValueRef { if cx.unreachable { ret _Undef(V); } count_insn(cx, ~"nswneg"); ret llvm::LLVMBuildNSWNeg(B(cx), V, noname()); } fn NUWNeg(cx: block, V: ValueRef) -> ValueRef { if cx.unreachable { ret _Undef(V); } count_insn(cx, ~"nuwneg"); ret llvm::LLVMBuildNUWNeg(B(cx), V, noname()); } fn FNeg(cx: block, V: ValueRef) -> ValueRef { if cx.unreachable { ret _Undef(V); } count_insn(cx, ~"fneg"); ret llvm::LLVMBuildFNeg(B(cx), V, noname()); } fn Not(cx: block, V: ValueRef) -> ValueRef { if cx.unreachable { ret _Undef(V); } count_insn(cx, ~"not"); ret llvm::LLVMBuildNot(B(cx), V, noname()); } /* Memory */ fn Malloc(cx: block, Ty: TypeRef) -> ValueRef { if cx.unreachable { ret llvm::LLVMGetUndef(T_ptr(T_i8())); } count_insn(cx, ~"malloc"); ret llvm::LLVMBuildMalloc(B(cx), Ty, noname()); } fn ArrayMalloc(cx: block, Ty: TypeRef, Val: ValueRef) -> ValueRef { if cx.unreachable { ret llvm::LLVMGetUndef(T_ptr(T_i8())); } count_insn(cx, ~"arraymalloc"); ret llvm::LLVMBuildArrayMalloc(B(cx), Ty, Val, noname()); } fn Alloca(cx: block, Ty: TypeRef) -> ValueRef { if cx.unreachable { ret llvm::LLVMGetUndef(T_ptr(Ty)); } count_insn(cx, ~"alloca"); ret llvm::LLVMBuildAlloca(B(cx), Ty, noname()); } fn ArrayAlloca(cx: block, Ty: TypeRef, Val: ValueRef) -> ValueRef { if cx.unreachable { ret llvm::LLVMGetUndef(T_ptr(Ty)); } count_insn(cx, ~"arrayalloca"); ret llvm::LLVMBuildArrayAlloca(B(cx), Ty, Val, noname()); } fn Free(cx: block, PointerVal: ValueRef) { if cx.unreachable { ret; } count_insn(cx, ~"free"); llvm::LLVMBuildFree(B(cx), PointerVal); } fn Load(cx: block, PointerVal: ValueRef) -> ValueRef { let ccx = cx.fcx.ccx; if cx.unreachable { let ty = val_ty(PointerVal); let eltty = if llvm::LLVMGetTypeKind(ty) == lib::llvm::Array { llvm::LLVMGetElementType(ty) } else { ccx.int_type }; ret llvm::LLVMGetUndef(eltty); } count_insn(cx, ~"load"); ret llvm::LLVMBuildLoad(B(cx), PointerVal, noname()); } fn Store(cx: block, Val: ValueRef, Ptr: ValueRef) { if cx.unreachable { ret; } #debug["Store %s -> %s", val_str(cx.ccx().tn, Val), val_str(cx.ccx().tn, Ptr)]; count_insn(cx, ~"store"); llvm::LLVMBuildStore(B(cx), Val, Ptr); } fn GEP(cx: block, Pointer: ValueRef, Indices: ~[ValueRef]) -> ValueRef { if cx.unreachable { ret llvm::LLVMGetUndef(T_ptr(T_nil())); } unsafe { count_insn(cx, ~"gep"); ret llvm::LLVMBuildGEP(B(cx), Pointer, vec::unsafe::to_ptr(Indices), Indices.len() as c_uint, noname()); } } // Simple wrapper around GEP that takes an array of ints and wraps them // in C_i32() fn GEPi(cx: block, base: ValueRef, ixs: ~[uint]) -> ValueRef { let mut v: ~[ValueRef] = ~[]; for vec::each(ixs) |i| { vec::push(v, C_i32(i as i32)); } count_insn(cx, ~"gepi"); ret InBoundsGEP(cx, base, v); } fn InBoundsGEP(cx: block, Pointer: ValueRef, Indices: ~[ValueRef]) -> ValueRef { if cx.unreachable { ret llvm::LLVMGetUndef(T_ptr(T_nil())); } unsafe { count_insn(cx, ~"inboundsgep"); ret llvm::LLVMBuildInBoundsGEP(B(cx), Pointer, vec::unsafe::to_ptr(Indices), Indices.len() as c_uint, noname()); } } fn StructGEP(cx: block, Pointer: ValueRef, Idx: uint) -> ValueRef { if cx.unreachable { ret llvm::LLVMGetUndef(T_ptr(T_nil())); } count_insn(cx, ~"structgep"); ret llvm::LLVMBuildStructGEP(B(cx), Pointer, Idx as c_uint, noname()); } fn GlobalString(cx: block, _Str: *libc::c_char) -> ValueRef { if cx.unreachable { ret llvm::LLVMGetUndef(T_ptr(T_i8())); } count_insn(cx, ~"globalstring"); ret llvm::LLVMBuildGlobalString(B(cx), _Str, noname()); } fn GlobalStringPtr(cx: block, _Str: *libc::c_char) -> ValueRef { if cx.unreachable { ret llvm::LLVMGetUndef(T_ptr(T_i8())); } count_insn(cx, ~"globalstringptr"); ret llvm::LLVMBuildGlobalStringPtr(B(cx), _Str, noname()); } /* Casts */ fn Trunc(cx: block, Val: ValueRef, DestTy: TypeRef) -> ValueRef { if cx.unreachable { ret llvm::LLVMGetUndef(DestTy); } count_insn(cx, ~"trunc"); ret llvm::LLVMBuildTrunc(B(cx), Val, DestTy, noname()); } fn ZExt(cx: block, Val: ValueRef, DestTy: TypeRef) -> ValueRef { if cx.unreachable { ret llvm::LLVMGetUndef(DestTy); } count_insn(cx, ~"zext"); ret llvm::LLVMBuildZExt(B(cx), Val, DestTy, noname()); } fn SExt(cx: block, Val: ValueRef, DestTy: TypeRef) -> ValueRef { if cx.unreachable { ret llvm::LLVMGetUndef(DestTy); } count_insn(cx, ~"sext"); ret llvm::LLVMBuildSExt(B(cx), Val, DestTy, noname()); } fn FPToUI(cx: block, Val: ValueRef, DestTy: TypeRef) -> ValueRef { if cx.unreachable { ret llvm::LLVMGetUndef(DestTy); } count_insn(cx, ~"fptoui"); ret llvm::LLVMBuildFPToUI(B(cx), Val, DestTy, noname()); } fn FPToSI(cx: block, Val: ValueRef, DestTy: TypeRef) -> ValueRef { if cx.unreachable { ret llvm::LLVMGetUndef(DestTy); } count_insn(cx, ~"fptosi"); ret llvm::LLVMBuildFPToSI(B(cx), Val, DestTy, noname()); } fn UIToFP(cx: block, Val: ValueRef, DestTy: TypeRef) -> ValueRef { if cx.unreachable { ret llvm::LLVMGetUndef(DestTy); } count_insn(cx, ~"uitofp"); ret llvm::LLVMBuildUIToFP(B(cx), Val, DestTy, noname()); } fn SIToFP(cx: block, Val: ValueRef, DestTy: TypeRef) -> ValueRef { if cx.unreachable { ret llvm::LLVMGetUndef(DestTy); } count_insn(cx, ~"sitofp"); ret llvm::LLVMBuildSIToFP(B(cx), Val, DestTy, noname()); } fn FPTrunc(cx: block, Val: ValueRef, DestTy: TypeRef) -> ValueRef { if cx.unreachable { ret llvm::LLVMGetUndef(DestTy); } count_insn(cx, ~"fptrunc"); ret llvm::LLVMBuildFPTrunc(B(cx), Val, DestTy, noname()); } fn FPExt(cx: block, Val: ValueRef, DestTy: TypeRef) -> ValueRef { if cx.unreachable { ret llvm::LLVMGetUndef(DestTy); } count_insn(cx, ~"fpext"); ret llvm::LLVMBuildFPExt(B(cx), Val, DestTy, noname()); } fn PtrToInt(cx: block, Val: ValueRef, DestTy: TypeRef) -> ValueRef { if cx.unreachable { ret llvm::LLVMGetUndef(DestTy); } count_insn(cx, ~"ptrtoint"); ret llvm::LLVMBuildPtrToInt(B(cx), Val, DestTy, noname()); } fn IntToPtr(cx: block, Val: ValueRef, DestTy: TypeRef) -> ValueRef { if cx.unreachable { ret llvm::LLVMGetUndef(DestTy); } count_insn(cx, ~"inttoptr"); ret llvm::LLVMBuildIntToPtr(B(cx), Val, DestTy, noname()); } fn BitCast(cx: block, Val: ValueRef, DestTy: TypeRef) -> ValueRef { if cx.unreachable { ret llvm::LLVMGetUndef(DestTy); } count_insn(cx, ~"bitcast"); ret llvm::LLVMBuildBitCast(B(cx), Val, DestTy, noname()); } fn ZExtOrBitCast(cx: block, Val: ValueRef, DestTy: TypeRef) -> ValueRef { if cx.unreachable { ret llvm::LLVMGetUndef(DestTy); } count_insn(cx, ~"zextorbitcast"); ret llvm::LLVMBuildZExtOrBitCast(B(cx), Val, DestTy, noname()); } fn SExtOrBitCast(cx: block, Val: ValueRef, DestTy: TypeRef) -> ValueRef { if cx.unreachable { ret llvm::LLVMGetUndef(DestTy); } count_insn(cx, ~"sextorbitcast"); ret llvm::LLVMBuildSExtOrBitCast(B(cx), Val, DestTy, noname()); } fn TruncOrBitCast(cx: block, Val: ValueRef, DestTy: TypeRef) -> ValueRef { if cx.unreachable { ret llvm::LLVMGetUndef(DestTy); } count_insn(cx, ~"truncorbitcast"); ret llvm::LLVMBuildTruncOrBitCast(B(cx), Val, DestTy, noname()); } fn Cast(cx: block, Op: Opcode, Val: ValueRef, DestTy: TypeRef, _Name: *u8) -> ValueRef { if cx.unreachable { ret llvm::LLVMGetUndef(DestTy); } count_insn(cx, ~"cast"); ret llvm::LLVMBuildCast(B(cx), Op, Val, DestTy, noname()); } fn PointerCast(cx: block, Val: ValueRef, DestTy: TypeRef) -> ValueRef { if cx.unreachable { ret llvm::LLVMGetUndef(DestTy); } count_insn(cx, ~"pointercast"); ret llvm::LLVMBuildPointerCast(B(cx), Val, DestTy, noname()); } fn IntCast(cx: block, Val: ValueRef, DestTy: TypeRef) -> ValueRef { if cx.unreachable { ret llvm::LLVMGetUndef(DestTy); } count_insn(cx, ~"intcast"); ret llvm::LLVMBuildIntCast(B(cx), Val, DestTy, noname()); } fn FPCast(cx: block, Val: ValueRef, DestTy: TypeRef) -> ValueRef { if cx.unreachable { ret llvm::LLVMGetUndef(DestTy); } count_insn(cx, ~"fpcast"); ret llvm::LLVMBuildFPCast(B(cx), Val, DestTy, noname()); } /* Comparisons */ fn ICmp(cx: block, Op: IntPredicate, LHS: ValueRef, RHS: ValueRef) -> ValueRef { if cx.unreachable { ret llvm::LLVMGetUndef(T_i1()); } count_insn(cx, ~"icmp"); ret llvm::LLVMBuildICmp(B(cx), Op as c_uint, LHS, RHS, noname()); } fn FCmp(cx: block, Op: RealPredicate, LHS: ValueRef, RHS: ValueRef) -> ValueRef { if cx.unreachable { ret llvm::LLVMGetUndef(T_i1()); } count_insn(cx, ~"fcmp"); ret llvm::LLVMBuildFCmp(B(cx), Op as c_uint, LHS, RHS, noname()); } /* Miscellaneous instructions */ fn EmptyPhi(cx: block, Ty: TypeRef) -> ValueRef { if cx.unreachable { ret llvm::LLVMGetUndef(Ty); } count_insn(cx, ~"emptyphi"); ret llvm::LLVMBuildPhi(B(cx), Ty, noname()); } fn Phi(cx: block, Ty: TypeRef, vals: ~[ValueRef], bbs: ~[BasicBlockRef]) -> ValueRef { if cx.unreachable { ret llvm::LLVMGetUndef(Ty); } assert vals.len() == bbs.len(); let phi = EmptyPhi(cx, Ty); unsafe { count_insn(cx, ~"addincoming"); llvm::LLVMAddIncoming(phi, vec::unsafe::to_ptr(vals), vec::unsafe::to_ptr(bbs), vals.len() as c_uint); ret phi; } } fn AddIncomingToPhi(phi: ValueRef, val: ValueRef, bb: BasicBlockRef) { if llvm::LLVMIsUndef(phi) == lib::llvm::True { ret; } unsafe { let valptr = unsafe::reinterpret_cast(ptr::addr_of(val)); let bbptr = unsafe::reinterpret_cast(ptr::addr_of(bb)); llvm::LLVMAddIncoming(phi, valptr, bbptr, 1 as c_uint); } } fn _UndefReturn(cx: block, Fn: ValueRef) -> ValueRef { let ccx = cx.fcx.ccx; let ty = val_ty(Fn); let retty = if llvm::LLVMGetTypeKind(ty) == lib::llvm::Integer { llvm::LLVMGetReturnType(ty) } else { ccx.int_type }; count_insn(cx, ~""); ret llvm::LLVMGetUndef(retty); } fn add_span_comment(bcx: block, sp: span, text: ~str) { let ccx = bcx.ccx(); if !ccx.sess.no_asm_comments() { let s = text + ~" (" + codemap::span_to_str(sp, ccx.sess.codemap) + ~")"; log(debug, s); add_comment(bcx, s); } } fn add_comment(bcx: block, text: ~str) { let ccx = bcx.ccx(); if !ccx.sess.no_asm_comments() { let sanitized = str::replace(text, ~"$", ~""); let comment_text = ~"# " + sanitized; let asm = str::as_c_str(comment_text, |c| { str::as_c_str(~"", |e| { count_insn(bcx, ~"inlineasm"); llvm::LLVMConstInlineAsm(T_fn(~[], T_void()), c, e, False, False) }) }); Call(bcx, asm, ~[]); } } fn Call(cx: block, Fn: ValueRef, Args: ~[ValueRef]) -> ValueRef { if cx.unreachable { ret _UndefReturn(cx, Fn); } unsafe { count_insn(cx, ~"call"); #debug["Call(Fn=%s, Args=%?)", val_str(cx.ccx().tn, Fn), Args.map(|arg| val_str(cx.ccx().tn, arg))]; ret llvm::LLVMBuildCall(B(cx), Fn, vec::unsafe::to_ptr(Args), Args.len() as c_uint, noname()); } } fn FastCall(cx: block, Fn: ValueRef, Args: ~[ValueRef]) -> ValueRef { if cx.unreachable { ret _UndefReturn(cx, Fn); } unsafe { count_insn(cx, ~"fastcall"); let v = llvm::LLVMBuildCall(B(cx), Fn, vec::unsafe::to_ptr(Args), Args.len() as c_uint, noname()); lib::llvm::SetInstructionCallConv(v, lib::llvm::FastCallConv); ret v; } } fn CallWithConv(cx: block, Fn: ValueRef, Args: ~[ValueRef], Conv: CallConv) -> ValueRef { if cx.unreachable { ret _UndefReturn(cx, Fn); } unsafe { count_insn(cx, ~"callwithconv"); let v = llvm::LLVMBuildCall(B(cx), Fn, vec::unsafe::to_ptr(Args), Args.len() as c_uint, noname()); lib::llvm::SetInstructionCallConv(v, Conv); ret v; } } fn Select(cx: block, If: ValueRef, Then: ValueRef, Else: ValueRef) -> ValueRef { if cx.unreachable { ret _Undef(Then); } count_insn(cx, ~"select"); ret llvm::LLVMBuildSelect(B(cx), If, Then, Else, noname()); } fn VAArg(cx: block, list: ValueRef, Ty: TypeRef) -> ValueRef { if cx.unreachable { ret llvm::LLVMGetUndef(Ty); } count_insn(cx, ~"vaarg"); ret llvm::LLVMBuildVAArg(B(cx), list, Ty, noname()); } fn ExtractElement(cx: block, VecVal: ValueRef, Index: ValueRef) -> ValueRef { if cx.unreachable { ret llvm::LLVMGetUndef(T_nil()); } count_insn(cx, ~"extractelement"); ret llvm::LLVMBuildExtractElement(B(cx), VecVal, Index, noname()); } fn InsertElement(cx: block, VecVal: ValueRef, EltVal: ValueRef, Index: ValueRef) { if cx.unreachable { ret; } count_insn(cx, ~"insertelement"); llvm::LLVMBuildInsertElement(B(cx), VecVal, EltVal, Index, noname()); } fn ShuffleVector(cx: block, V1: ValueRef, V2: ValueRef, Mask: ValueRef) { if cx.unreachable { ret; } count_insn(cx, ~"shufflevector"); llvm::LLVMBuildShuffleVector(B(cx), V1, V2, Mask, noname()); } fn ExtractValue(cx: block, AggVal: ValueRef, Index: uint) -> ValueRef { if cx.unreachable { ret llvm::LLVMGetUndef(T_nil()); } count_insn(cx, ~"extractvalue"); ret llvm::LLVMBuildExtractValue(B(cx), AggVal, Index as c_uint, noname()); } fn InsertValue(cx: block, AggVal: ValueRef, EltVal: ValueRef, Index: uint) { if cx.unreachable { ret; } count_insn(cx, ~"insertvalue"); llvm::LLVMBuildInsertValue(B(cx), AggVal, EltVal, Index as c_uint, noname()); } fn IsNull(cx: block, Val: ValueRef) -> ValueRef { if cx.unreachable { ret llvm::LLVMGetUndef(T_i1()); } count_insn(cx, ~"isnull"); ret llvm::LLVMBuildIsNull(B(cx), Val, noname()); } fn IsNotNull(cx: block, Val: ValueRef) -> ValueRef { if cx.unreachable { ret llvm::LLVMGetUndef(T_i1()); } count_insn(cx, ~"isnotnull"); ret llvm::LLVMBuildIsNotNull(B(cx), Val, noname()); } fn PtrDiff(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef { let ccx = cx.fcx.ccx; if cx.unreachable { ret llvm::LLVMGetUndef(ccx.int_type); } count_insn(cx, ~"ptrdiff"); ret llvm::LLVMBuildPtrDiff(B(cx), LHS, RHS, noname()); } fn Trap(cx: block) { if cx.unreachable { ret; } let b = B(cx); let BB: BasicBlockRef = llvm::LLVMGetInsertBlock(b); let FN: ValueRef = llvm::LLVMGetBasicBlockParent(BB); let M: ModuleRef = llvm::LLVMGetGlobalParent(FN); let T: ValueRef = str::as_c_str(~"llvm.trap", |buf| { llvm::LLVMGetNamedFunction(M, buf) }); assert (T as int != 0); let Args: ~[ValueRef] = ~[]; unsafe { count_insn(cx, ~"trap"); llvm::LLVMBuildCall(b, T, vec::unsafe::to_ptr(Args), Args.len() as c_uint, noname()); } } fn LandingPad(cx: block, Ty: TypeRef, PersFn: ValueRef, NumClauses: uint) -> ValueRef { assert !cx.terminated && !cx.unreachable; count_insn(cx, ~"landingpad"); ret llvm::LLVMBuildLandingPad(B(cx), Ty, PersFn, NumClauses as c_uint, noname()); } fn SetCleanup(cx: block, LandingPad: ValueRef) { count_insn(cx, ~"setcleanup"); llvm::LLVMSetCleanup(LandingPad, lib::llvm::True); } fn Resume(cx: block, Exn: ValueRef) -> ValueRef { assert (!cx.terminated); cx.terminated = true; count_insn(cx, ~"resume"); ret llvm::LLVMBuildResume(B(cx), Exn); } // Atomic Operations fn AtomicRMW(cx: block, op: AtomicBinOp, dst: ValueRef, src: ValueRef, order: AtomicOrdering) -> ValueRef { llvm::LLVMBuildAtomicRMW(B(cx), op, dst, src, order) } // // Local Variables: // mode: rust // fill-column: 78; // indent-tabs-mode: nil // c-basic-offset: 4 // buffer-file-coding-system: utf-8-unix // End: //