1 // Copyright 2012 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
12 use lib::llvm::{CallConv, AtomicBinOp, AtomicOrdering, AsmDialect};
13 use lib::llvm::{Opcode, IntPredicate, RealPredicate, False};
14 use lib::llvm::{ValueRef, TypeRef, BasicBlockRef, BuilderRef, ModuleRef};
16 use middle::trans::common::*;
17 use syntax::codemap::span;
19 use core::hashmap::HashMap;
20 use core::libc::{c_uint, c_ulonglong, c_char};
22 pub fn terminate(cx: block, _: &str) {
26 pub fn check_not_terminated(cx: block) {
28 fail!(~"already terminated!");
32 pub fn B(cx: block) -> BuilderRef {
34 let b = cx.fcx.ccx.builder.B;
35 llvm::LLVMPositionBuilderAtEnd(b, cx.llbb);
40 pub fn count_insn(cx: block, category: &str) {
41 if cx.ccx().sess.count_llvm_insns() {
43 let h = cx.ccx().stats.llvm_insns;
44 let v = &*cx.ccx().stats.llvm_insn_ctxt;
46 // Build version of path with cycles removed.
48 // Pass 1: scan table mapping str -> rightmost pos.
49 let mut mm = HashMap::new();
50 let len = vec::len(*v);
53 mm.insert(copy v[i], i);
58 // Pass 2: concat strings for each elt, skipping
59 // forwards over any cycles by advancing to rightmost
60 // occurrence of each element in path.
73 let n = match h.find(&s) {
82 // The difference between a block being unreachable and being terminated is
83 // somewhat obscure, and has to do with error checking. When a block is
84 // terminated, we're saying that trying to add any further statements in the
85 // block is an error. On the other hand, if something is unreachable, that
86 // means that the block was terminated in some way that we don't want to check
87 // for (fail/break/return statements, call to diverging functions, etc), and
88 // further instructions to the block should simply be ignored.
90 pub fn RetVoid(cx: block) {
92 if cx.unreachable { return; }
93 check_not_terminated(cx);
94 terminate(cx, "RetVoid");
95 count_insn(cx, "retvoid");
96 llvm::LLVMBuildRetVoid(B(cx));
100 pub fn Ret(cx: block, V: ValueRef) {
102 if cx.unreachable { return; }
103 check_not_terminated(cx);
104 terminate(cx, "Ret");
105 count_insn(cx, "ret");
106 llvm::LLVMBuildRet(B(cx), V);
110 pub fn AggregateRet(cx: block, RetVals: &[ValueRef]) {
111 if cx.unreachable { return; }
112 check_not_terminated(cx);
113 terminate(cx, "AggregateRet");
115 llvm::LLVMBuildAggregateRet(B(cx), vec::raw::to_ptr(RetVals),
116 RetVals.len() as c_uint);
120 pub fn Br(cx: block, Dest: BasicBlockRef) {
122 if cx.unreachable { return; }
123 check_not_terminated(cx);
125 count_insn(cx, "br");
126 llvm::LLVMBuildBr(B(cx), Dest);
130 pub fn CondBr(cx: block, If: ValueRef, Then: BasicBlockRef,
131 Else: BasicBlockRef) {
133 if cx.unreachable { return; }
134 check_not_terminated(cx);
135 terminate(cx, "CondBr");
136 count_insn(cx, "condbr");
137 llvm::LLVMBuildCondBr(B(cx), If, Then, Else);
141 pub fn Switch(cx: block, V: ValueRef, Else: BasicBlockRef, NumCases: uint)
144 if cx.unreachable { return _Undef(V); }
145 check_not_terminated(cx);
146 terminate(cx, "Switch");
147 return llvm::LLVMBuildSwitch(B(cx), V, Else, NumCases as c_uint);
151 pub fn AddCase(S: ValueRef, OnVal: ValueRef, Dest: BasicBlockRef) {
153 if llvm::LLVMIsUndef(S) == lib::llvm::True { return; }
154 llvm::LLVMAddCase(S, OnVal, Dest);
158 pub fn IndirectBr(cx: block, Addr: ValueRef, NumDests: uint) {
160 if cx.unreachable { return; }
161 check_not_terminated(cx);
162 terminate(cx, "IndirectBr");
163 count_insn(cx, "indirectbr");
164 llvm::LLVMBuildIndirectBr(B(cx), Addr, NumDests as c_uint);
168 // This is a really awful way to get a zero-length c-string, but better (and a
169 // lot more efficient) than doing str::as_c_str("", ...) every time.
170 pub fn noname() -> *c_char {
172 static cnull: uint = 0u;
173 return cast::transmute(&cnull);
177 pub fn Invoke(cx: block,
181 Catch: BasicBlockRef)
184 return C_null(T_i8());
186 check_not_terminated(cx);
187 terminate(cx, "Invoke");
188 debug!("Invoke(%s with arguments (%s))",
189 val_str(cx.ccx().tn, Fn),
190 str::connect(vec::map(Args, |a| val_str(cx.ccx().tn,
194 count_insn(cx, "invoke");
195 llvm::LLVMBuildInvoke(B(cx),
197 vec::raw::to_ptr(Args),
198 Args.len() as c_uint,
205 pub fn FastInvoke(cx: block, Fn: ValueRef, Args: &[ValueRef],
206 Then: BasicBlockRef, Catch: BasicBlockRef) {
207 if cx.unreachable { return; }
208 check_not_terminated(cx);
209 terminate(cx, "FastInvoke");
211 count_insn(cx, "fastinvoke");
212 let v = llvm::LLVMBuildInvoke(B(cx), Fn, vec::raw::to_ptr(Args),
213 Args.len() as c_uint,
214 Then, Catch, noname());
215 lib::llvm::SetInstructionCallConv(v, lib::llvm::FastCallConv);
219 pub fn Unreachable(cx: block) {
221 if cx.unreachable { return; }
222 cx.unreachable = true;
224 count_insn(cx, "unreachable");
225 llvm::LLVMBuildUnreachable(B(cx));
230 pub fn _Undef(val: ValueRef) -> ValueRef {
232 return llvm::LLVMGetUndef(val_ty(val));
237 pub fn Add(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
239 if cx.unreachable { return _Undef(LHS); }
240 count_insn(cx, "add");
241 return llvm::LLVMBuildAdd(B(cx), LHS, RHS, noname());
245 pub fn NSWAdd(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
247 if cx.unreachable { return _Undef(LHS); }
248 count_insn(cx, "nswadd");
249 return llvm::LLVMBuildNSWAdd(B(cx), LHS, RHS, noname());
253 pub fn NUWAdd(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
255 if cx.unreachable { return _Undef(LHS); }
256 count_insn(cx, "nuwadd");
257 return llvm::LLVMBuildNUWAdd(B(cx), LHS, RHS, noname());
261 pub fn FAdd(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
263 if cx.unreachable { return _Undef(LHS); }
264 count_insn(cx, "fadd");
265 return llvm::LLVMBuildFAdd(B(cx), LHS, RHS, noname());
269 pub fn Sub(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
271 if cx.unreachable { return _Undef(LHS); }
272 count_insn(cx, "sub");
273 return llvm::LLVMBuildSub(B(cx), LHS, RHS, noname());
277 pub fn NSWSub(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
279 if cx.unreachable { return _Undef(LHS); }
280 count_insn(cx, "nwsub");
281 return llvm::LLVMBuildNSWSub(B(cx), LHS, RHS, noname());
285 pub fn NUWSub(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
287 if cx.unreachable { return _Undef(LHS); }
288 count_insn(cx, "nuwsub");
289 return llvm::LLVMBuildNUWSub(B(cx), LHS, RHS, noname());
293 pub fn FSub(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
295 if cx.unreachable { return _Undef(LHS); }
296 count_insn(cx, "sub");
297 return llvm::LLVMBuildFSub(B(cx), LHS, RHS, noname());
301 pub fn Mul(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
303 if cx.unreachable { return _Undef(LHS); }
304 count_insn(cx, "mul");
305 return llvm::LLVMBuildMul(B(cx), LHS, RHS, noname());
309 pub fn NSWMul(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
311 if cx.unreachable { return _Undef(LHS); }
312 count_insn(cx, "nswmul");
313 return llvm::LLVMBuildNSWMul(B(cx), LHS, RHS, noname());
317 pub fn NUWMul(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
319 if cx.unreachable { return _Undef(LHS); }
320 count_insn(cx, "nuwmul");
321 return llvm::LLVMBuildNUWMul(B(cx), LHS, RHS, noname());
325 pub fn FMul(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
327 if cx.unreachable { return _Undef(LHS); }
328 count_insn(cx, "fmul");
329 return llvm::LLVMBuildFMul(B(cx), LHS, RHS, noname());
333 pub fn UDiv(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
335 if cx.unreachable { return _Undef(LHS); }
336 count_insn(cx, "udiv");
337 return llvm::LLVMBuildUDiv(B(cx), LHS, RHS, noname());
341 pub fn SDiv(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
343 if cx.unreachable { return _Undef(LHS); }
344 count_insn(cx, "sdiv");
345 return llvm::LLVMBuildSDiv(B(cx), LHS, RHS, noname());
349 pub fn ExactSDiv(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
351 if cx.unreachable { return _Undef(LHS); }
352 count_insn(cx, "extractsdiv");
353 return llvm::LLVMBuildExactSDiv(B(cx), LHS, RHS, noname());
357 pub fn FDiv(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
359 if cx.unreachable { return _Undef(LHS); }
360 count_insn(cx, "fdiv");
361 return llvm::LLVMBuildFDiv(B(cx), LHS, RHS, noname());
365 pub fn URem(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
367 if cx.unreachable { return _Undef(LHS); }
368 count_insn(cx, "urem");
369 return llvm::LLVMBuildURem(B(cx), LHS, RHS, noname());
373 pub fn SRem(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
375 if cx.unreachable { return _Undef(LHS); }
376 count_insn(cx, "srem");
377 return llvm::LLVMBuildSRem(B(cx), LHS, RHS, noname());
381 pub fn FRem(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
383 if cx.unreachable { return _Undef(LHS); }
384 count_insn(cx, "frem");
385 return llvm::LLVMBuildFRem(B(cx), LHS, RHS, noname());
389 pub fn Shl(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
391 if cx.unreachable { return _Undef(LHS); }
392 count_insn(cx, "shl");
393 return llvm::LLVMBuildShl(B(cx), LHS, RHS, noname());
397 pub fn LShr(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
399 if cx.unreachable { return _Undef(LHS); }
400 count_insn(cx, "lshr");
401 return llvm::LLVMBuildLShr(B(cx), LHS, RHS, noname());
405 pub fn AShr(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
407 if cx.unreachable { return _Undef(LHS); }
408 count_insn(cx, "ashr");
409 return llvm::LLVMBuildAShr(B(cx), LHS, RHS, noname());
413 pub fn And(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
415 if cx.unreachable { return _Undef(LHS); }
416 count_insn(cx, "and");
417 return llvm::LLVMBuildAnd(B(cx), LHS, RHS, noname());
421 pub fn Or(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
423 if cx.unreachable { return _Undef(LHS); }
424 count_insn(cx, "or");
425 return llvm::LLVMBuildOr(B(cx), LHS, RHS, noname());
429 pub fn Xor(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
431 if cx.unreachable { return _Undef(LHS); }
432 count_insn(cx, "xor");
433 return llvm::LLVMBuildXor(B(cx), LHS, RHS, noname());
437 pub fn BinOp(cx: block, Op: Opcode, LHS: ValueRef, RHS: ValueRef)
440 if cx.unreachable { return _Undef(LHS); }
441 count_insn(cx, "binop");
442 return llvm::LLVMBuildBinOp(B(cx), Op, LHS, RHS, noname());
446 pub fn Neg(cx: block, V: ValueRef) -> ValueRef {
448 if cx.unreachable { return _Undef(V); }
449 count_insn(cx, "neg");
450 return llvm::LLVMBuildNeg(B(cx), V, noname());
454 pub fn NSWNeg(cx: block, V: ValueRef) -> ValueRef {
456 if cx.unreachable { return _Undef(V); }
457 count_insn(cx, "nswneg");
458 return llvm::LLVMBuildNSWNeg(B(cx), V, noname());
462 pub fn NUWNeg(cx: block, V: ValueRef) -> ValueRef {
464 if cx.unreachable { return _Undef(V); }
465 count_insn(cx, "nuwneg");
466 return llvm::LLVMBuildNUWNeg(B(cx), V, noname());
469 pub fn FNeg(cx: block, V: ValueRef) -> ValueRef {
471 if cx.unreachable { return _Undef(V); }
472 count_insn(cx, "fneg");
473 return llvm::LLVMBuildFNeg(B(cx), V, noname());
477 pub fn Not(cx: block, V: ValueRef) -> ValueRef {
479 if cx.unreachable { return _Undef(V); }
480 count_insn(cx, "not");
481 return llvm::LLVMBuildNot(B(cx), V, noname());
486 pub fn Malloc(cx: block, Ty: TypeRef) -> ValueRef {
488 if cx.unreachable { return llvm::LLVMGetUndef(T_ptr(T_i8())); }
489 count_insn(cx, "malloc");
490 return llvm::LLVMBuildMalloc(B(cx), Ty, noname());
494 pub fn ArrayMalloc(cx: block, Ty: TypeRef, Val: ValueRef) -> ValueRef {
496 if cx.unreachable { return llvm::LLVMGetUndef(T_ptr(T_i8())); }
497 count_insn(cx, "arraymalloc");
498 return llvm::LLVMBuildArrayMalloc(B(cx), Ty, Val, noname());
502 pub fn Alloca(cx: block, Ty: TypeRef) -> ValueRef {
504 if cx.unreachable { return llvm::LLVMGetUndef(T_ptr(Ty)); }
505 count_insn(cx, "alloca");
506 return llvm::LLVMBuildAlloca(B(cx), Ty, noname());
510 pub fn ArrayAlloca(cx: block, Ty: TypeRef, Val: ValueRef) -> ValueRef {
512 if cx.unreachable { return llvm::LLVMGetUndef(T_ptr(Ty)); }
513 count_insn(cx, "arrayalloca");
514 return llvm::LLVMBuildArrayAlloca(B(cx), Ty, Val, noname());
518 pub fn Free(cx: block, PointerVal: ValueRef) {
520 if cx.unreachable { return; }
521 count_insn(cx, "free");
522 llvm::LLVMBuildFree(B(cx), PointerVal);
526 pub fn Load(cx: block, PointerVal: ValueRef) -> ValueRef {
528 let ccx = cx.fcx.ccx;
530 let ty = val_ty(PointerVal);
531 let eltty = if llvm::LLVMGetTypeKind(ty) == lib::llvm::Array {
532 llvm::LLVMGetElementType(ty) } else { ccx.int_type };
533 return llvm::LLVMGetUndef(eltty);
535 count_insn(cx, "load");
536 return llvm::LLVMBuildLoad(B(cx), PointerVal, noname());
540 pub fn LoadRangeAssert(cx: block, PointerVal: ValueRef, lo: c_ulonglong,
541 hi: c_ulonglong, signed: lib::llvm::Bool) -> ValueRef {
542 let value = Load(cx, PointerVal);
545 let t = llvm::LLVMGetElementType(llvm::LLVMTypeOf(PointerVal));
546 let min = llvm::LLVMConstInt(t, lo, signed);
547 let max = llvm::LLVMConstInt(t, hi, signed);
550 do vec::as_imm_buf([min, max]) |ptr, len| {
551 llvm::LLVMSetMetadata(value, lib::llvm::MD_range as c_uint,
552 llvm::LLVMMDNode(ptr, len as c_uint));
559 pub fn Store(cx: block, Val: ValueRef, Ptr: ValueRef) {
561 if cx.unreachable { return; }
562 debug!("Store %s -> %s",
563 val_str(cx.ccx().tn, Val),
564 val_str(cx.ccx().tn, Ptr));
565 count_insn(cx, "store");
566 llvm::LLVMBuildStore(B(cx), Val, Ptr);
570 pub fn GEP(cx: block, Pointer: ValueRef, Indices: &[ValueRef]) -> ValueRef {
572 if cx.unreachable { return llvm::LLVMGetUndef(T_ptr(T_nil())); }
573 count_insn(cx, "gep");
574 return llvm::LLVMBuildGEP(B(cx), Pointer, vec::raw::to_ptr(Indices),
575 Indices.len() as c_uint, noname());
579 // Simple wrapper around GEP that takes an array of ints and wraps them
582 // XXX: Use a small-vector optimization to avoid allocations here.
583 pub fn GEPi(cx: block, base: ValueRef, ixs: &[uint]) -> ValueRef {
584 let v = do vec::map(ixs) |i| { C_i32(*i as i32) };
585 count_insn(cx, "gepi");
586 return InBoundsGEP(cx, base, v);
589 pub fn InBoundsGEP(cx: block, Pointer: ValueRef, Indices: &[ValueRef]) ->
592 if cx.unreachable { return llvm::LLVMGetUndef(T_ptr(T_nil())); }
594 count_insn(cx, "inboundsgep");
595 return llvm::LLVMBuildInBoundsGEP(B(cx), Pointer,
596 vec::raw::to_ptr(Indices),
597 Indices.len() as c_uint,
603 pub fn StructGEP(cx: block, Pointer: ValueRef, Idx: uint) -> ValueRef {
605 if cx.unreachable { return llvm::LLVMGetUndef(T_ptr(T_nil())); }
606 count_insn(cx, "structgep");
607 return llvm::LLVMBuildStructGEP(B(cx),
614 pub fn GlobalString(cx: block, _Str: *c_char) -> ValueRef {
616 if cx.unreachable { return llvm::LLVMGetUndef(T_ptr(T_i8())); }
617 count_insn(cx, "globalstring");
618 return llvm::LLVMBuildGlobalString(B(cx), _Str, noname());
622 pub fn GlobalStringPtr(cx: block, _Str: *c_char) -> ValueRef {
624 if cx.unreachable { return llvm::LLVMGetUndef(T_ptr(T_i8())); }
625 count_insn(cx, "globalstringptr");
626 return llvm::LLVMBuildGlobalStringPtr(B(cx), _Str, noname());
631 pub fn Trunc(cx: block, Val: ValueRef, DestTy: TypeRef) -> ValueRef {
633 if cx.unreachable { return llvm::LLVMGetUndef(DestTy); }
634 count_insn(cx, "trunc");
635 return llvm::LLVMBuildTrunc(B(cx), Val, DestTy, noname());
639 pub fn ZExt(cx: block, Val: ValueRef, DestTy: TypeRef) -> ValueRef {
641 if cx.unreachable { return llvm::LLVMGetUndef(DestTy); }
642 count_insn(cx, "zext");
643 return llvm::LLVMBuildZExt(B(cx), Val, DestTy, noname());
647 pub fn SExt(cx: block, Val: ValueRef, DestTy: TypeRef) -> ValueRef {
649 if cx.unreachable { return llvm::LLVMGetUndef(DestTy); }
650 count_insn(cx, "sext");
651 return llvm::LLVMBuildSExt(B(cx), Val, DestTy, noname());
655 pub fn FPToUI(cx: block, Val: ValueRef, DestTy: TypeRef) -> ValueRef {
657 if cx.unreachable { return llvm::LLVMGetUndef(DestTy); }
658 count_insn(cx, "fptoui");
659 return llvm::LLVMBuildFPToUI(B(cx), Val, DestTy, noname());
663 pub fn FPToSI(cx: block, Val: ValueRef, DestTy: TypeRef) -> ValueRef {
665 if cx.unreachable { return llvm::LLVMGetUndef(DestTy); }
666 count_insn(cx, "fptosi");
667 return llvm::LLVMBuildFPToSI(B(cx), Val, DestTy, noname());
671 pub fn UIToFP(cx: block, Val: ValueRef, DestTy: TypeRef) -> ValueRef {
673 if cx.unreachable { return llvm::LLVMGetUndef(DestTy); }
674 count_insn(cx, "uitofp");
675 return llvm::LLVMBuildUIToFP(B(cx), Val, DestTy, noname());
679 pub fn SIToFP(cx: block, Val: ValueRef, DestTy: TypeRef) -> ValueRef {
681 if cx.unreachable { return llvm::LLVMGetUndef(DestTy); }
682 count_insn(cx, "sitofp");
683 return llvm::LLVMBuildSIToFP(B(cx), Val, DestTy, noname());
687 pub fn FPTrunc(cx: block, Val: ValueRef, DestTy: TypeRef) -> ValueRef {
689 if cx.unreachable { return llvm::LLVMGetUndef(DestTy); }
690 count_insn(cx, "fptrunc");
691 return llvm::LLVMBuildFPTrunc(B(cx), Val, DestTy, noname());
695 pub fn FPExt(cx: block, Val: ValueRef, DestTy: TypeRef) -> ValueRef {
697 if cx.unreachable { return llvm::LLVMGetUndef(DestTy); }
698 count_insn(cx, "fpext");
699 return llvm::LLVMBuildFPExt(B(cx), Val, DestTy, noname());
703 pub fn PtrToInt(cx: block, Val: ValueRef, DestTy: TypeRef) -> ValueRef {
705 if cx.unreachable { return llvm::LLVMGetUndef(DestTy); }
706 count_insn(cx, "ptrtoint");
707 return llvm::LLVMBuildPtrToInt(B(cx), Val, DestTy, noname());
711 pub fn IntToPtr(cx: block, Val: ValueRef, DestTy: TypeRef) -> ValueRef {
713 if cx.unreachable { return llvm::LLVMGetUndef(DestTy); }
714 count_insn(cx, "inttoptr");
715 return llvm::LLVMBuildIntToPtr(B(cx), Val, DestTy, noname());
719 pub fn BitCast(cx: block, Val: ValueRef, DestTy: TypeRef) -> ValueRef {
721 if cx.unreachable { return llvm::LLVMGetUndef(DestTy); }
722 count_insn(cx, "bitcast");
723 return llvm::LLVMBuildBitCast(B(cx), Val, DestTy, noname());
727 pub fn ZExtOrBitCast(cx: block, Val: ValueRef, DestTy: TypeRef) -> ValueRef {
729 if cx.unreachable { return llvm::LLVMGetUndef(DestTy); }
730 count_insn(cx, "zextorbitcast");
731 return llvm::LLVMBuildZExtOrBitCast(B(cx), Val, DestTy, noname());
735 pub fn SExtOrBitCast(cx: block, Val: ValueRef, DestTy: TypeRef) -> ValueRef {
737 if cx.unreachable { return llvm::LLVMGetUndef(DestTy); }
738 count_insn(cx, "sextorbitcast");
739 return llvm::LLVMBuildSExtOrBitCast(B(cx), Val, DestTy, noname());
743 pub fn TruncOrBitCast(cx: block, Val: ValueRef, DestTy: TypeRef) -> ValueRef {
745 if cx.unreachable { return llvm::LLVMGetUndef(DestTy); }
746 count_insn(cx, "truncorbitcast");
747 return llvm::LLVMBuildTruncOrBitCast(B(cx), Val, DestTy, noname());
751 pub fn Cast(cx: block, Op: Opcode, Val: ValueRef, DestTy: TypeRef, _: *u8)
754 if cx.unreachable { return llvm::LLVMGetUndef(DestTy); }
755 count_insn(cx, "cast");
756 return llvm::LLVMBuildCast(B(cx), Op, Val, DestTy, noname());
760 pub fn PointerCast(cx: block, Val: ValueRef, DestTy: TypeRef) -> ValueRef {
762 if cx.unreachable { return llvm::LLVMGetUndef(DestTy); }
763 count_insn(cx, "pointercast");
764 return llvm::LLVMBuildPointerCast(B(cx), Val, DestTy, noname());
768 pub fn IntCast(cx: block, Val: ValueRef, DestTy: TypeRef) -> ValueRef {
770 if cx.unreachable { return llvm::LLVMGetUndef(DestTy); }
771 count_insn(cx, "intcast");
772 return llvm::LLVMBuildIntCast(B(cx), Val, DestTy, noname());
776 pub fn FPCast(cx: block, Val: ValueRef, DestTy: TypeRef) -> ValueRef {
778 if cx.unreachable { return llvm::LLVMGetUndef(DestTy); }
779 count_insn(cx, "fpcast");
780 return llvm::LLVMBuildFPCast(B(cx), Val, DestTy, noname());
786 pub fn ICmp(cx: block, Op: IntPredicate, LHS: ValueRef, RHS: ValueRef)
789 if cx.unreachable { return llvm::LLVMGetUndef(T_i1()); }
790 count_insn(cx, "icmp");
791 return llvm::LLVMBuildICmp(B(cx), Op as c_uint, LHS, RHS, noname());
795 pub fn FCmp(cx: block, Op: RealPredicate, LHS: ValueRef, RHS: ValueRef)
798 if cx.unreachable { return llvm::LLVMGetUndef(T_i1()); }
799 count_insn(cx, "fcmp");
800 return llvm::LLVMBuildFCmp(B(cx), Op as c_uint, LHS, RHS, noname());
804 /* Miscellaneous instructions */
805 pub fn EmptyPhi(cx: block, Ty: TypeRef) -> ValueRef {
807 if cx.unreachable { return llvm::LLVMGetUndef(Ty); }
808 count_insn(cx, "emptyphi");
809 return llvm::LLVMBuildPhi(B(cx), Ty, noname());
813 pub fn Phi(cx: block, Ty: TypeRef, vals: &[ValueRef], bbs: &[BasicBlockRef])
816 if cx.unreachable { return llvm::LLVMGetUndef(Ty); }
817 assert!(vals.len() == bbs.len());
818 let phi = EmptyPhi(cx, Ty);
819 count_insn(cx, "addincoming");
820 llvm::LLVMAddIncoming(phi, vec::raw::to_ptr(vals),
821 vec::raw::to_ptr(bbs),
822 vals.len() as c_uint);
827 pub fn AddIncomingToPhi(phi: ValueRef, val: ValueRef, bb: BasicBlockRef) {
829 if llvm::LLVMIsUndef(phi) == lib::llvm::True { return; }
830 let valptr = cast::transmute(&val);
831 let bbptr = cast::transmute(&bb);
832 llvm::LLVMAddIncoming(phi, valptr, bbptr, 1 as c_uint);
836 pub fn _UndefReturn(cx: block, Fn: ValueRef) -> ValueRef {
838 let ccx = cx.fcx.ccx;
840 let retty = if llvm::LLVMGetTypeKind(ty) == lib::llvm::Integer {
841 llvm::LLVMGetReturnType(ty) } else { ccx.int_type };
843 return llvm::LLVMGetUndef(retty);
847 pub fn add_span_comment(bcx: block, sp: span, text: &str) {
849 if !ccx.sess.no_asm_comments() {
850 let s = fmt!("%s (%s)", text, ccx.sess.codemap.span_to_str(sp));
851 debug!("%s", copy s);
856 pub fn add_comment(bcx: block, text: &str) {
859 if !ccx.sess.no_asm_comments() {
860 let sanitized = str::replace(text, ~"$", ~"");
861 let comment_text = ~"# " +
862 str::replace(sanitized, ~"\n", ~"\n\t# ");
863 let asm = str::as_c_str(comment_text, |c| {
864 str::as_c_str(~"", |e| {
865 count_insn(bcx, ~"inlineasm");
866 llvm::LLVMConstInlineAsm(T_fn(~[], T_void()), c, e,
875 pub fn InlineAsmCall(cx: block, asm: *c_char, cons: *c_char,
876 inputs: &[ValueRef], output: TypeRef,
877 volatile: bool, alignstack: bool,
878 dia: AsmDialect) -> ValueRef {
880 count_insn(cx, "inlineasm");
882 let volatile = if volatile { lib::llvm::True }
883 else { lib::llvm::False };
884 let alignstack = if alignstack { lib::llvm::True }
885 else { lib::llvm::False };
887 let argtys = do inputs.map |v| {
888 debug!("Asm Input Type: %?", val_str(cx.ccx().tn, *v));
892 debug!("Asm Output Type: %?", ty_str(cx.ccx().tn, output));
893 let llfty = T_fn(argtys, output);
894 let v = llvm::LLVMInlineAsm(llfty, asm, cons, volatile,
895 alignstack, dia as c_uint);
901 pub fn Call(cx: block, Fn: ValueRef, Args: &[ValueRef]) -> ValueRef {
902 if cx.unreachable { return _UndefReturn(cx, Fn); }
904 count_insn(cx, "call");
906 debug!("Call(Fn=%s, Args=%?)",
907 val_str(cx.ccx().tn, Fn),
908 Args.map(|arg| val_str(cx.ccx().tn, *arg)));
910 do vec::as_imm_buf(Args) |ptr, len| {
911 llvm::LLVMBuildCall(B(cx), Fn, ptr, len as c_uint, noname())
916 pub fn FastCall(cx: block, Fn: ValueRef, Args: &[ValueRef]) -> ValueRef {
917 if cx.unreachable { return _UndefReturn(cx, Fn); }
919 count_insn(cx, "fastcall");
920 let v = llvm::LLVMBuildCall(B(cx), Fn, vec::raw::to_ptr(Args),
921 Args.len() as c_uint, noname());
922 lib::llvm::SetInstructionCallConv(v, lib::llvm::FastCallConv);
927 pub fn CallWithConv(cx: block, Fn: ValueRef, Args: &[ValueRef],
928 Conv: CallConv) -> ValueRef {
929 if cx.unreachable { return _UndefReturn(cx, Fn); }
931 count_insn(cx, "callwithconv");
932 let v = llvm::LLVMBuildCall(B(cx), Fn, vec::raw::to_ptr(Args),
933 Args.len() as c_uint, noname());
934 lib::llvm::SetInstructionCallConv(v, Conv);
939 pub fn Select(cx: block, If: ValueRef, Then: ValueRef, Else: ValueRef) ->
942 if cx.unreachable { return _Undef(Then); }
943 count_insn(cx, "select");
944 return llvm::LLVMBuildSelect(B(cx), If, Then, Else, noname());
948 pub fn VAArg(cx: block, list: ValueRef, Ty: TypeRef) -> ValueRef {
950 if cx.unreachable { return llvm::LLVMGetUndef(Ty); }
951 count_insn(cx, "vaarg");
952 return llvm::LLVMBuildVAArg(B(cx), list, Ty, noname());
956 pub fn ExtractElement(cx: block, VecVal: ValueRef, Index: ValueRef) ->
959 if cx.unreachable { return llvm::LLVMGetUndef(T_nil()); }
960 count_insn(cx, "extractelement");
961 return llvm::LLVMBuildExtractElement(B(cx), VecVal, Index, noname());
965 pub fn InsertElement(cx: block, VecVal: ValueRef, EltVal: ValueRef,
968 if cx.unreachable { return; }
969 count_insn(cx, "insertelement");
970 llvm::LLVMBuildInsertElement(B(cx), VecVal, EltVal, Index, noname());
974 pub fn ShuffleVector(cx: block, V1: ValueRef, V2: ValueRef,
977 if cx.unreachable { return; }
978 count_insn(cx, "shufflevector");
979 llvm::LLVMBuildShuffleVector(B(cx), V1, V2, Mask, noname());
983 pub fn ExtractValue(cx: block, AggVal: ValueRef, Index: uint) -> ValueRef {
985 if cx.unreachable { return llvm::LLVMGetUndef(T_nil()); }
986 count_insn(cx, "extractvalue");
987 return llvm::LLVMBuildExtractValue(
988 B(cx), AggVal, Index as c_uint, noname());
992 pub fn InsertValue(cx: block, AggVal: ValueRef, EltVal: ValueRef,
995 if cx.unreachable { return; }
996 count_insn(cx, "insertvalue");
997 llvm::LLVMBuildInsertValue(B(cx), AggVal, EltVal, Index as c_uint,
1002 pub fn IsNull(cx: block, Val: ValueRef) -> ValueRef {
1004 if cx.unreachable { return llvm::LLVMGetUndef(T_i1()); }
1005 count_insn(cx, "isnull");
1006 return llvm::LLVMBuildIsNull(B(cx), Val, noname());
1010 pub fn IsNotNull(cx: block, Val: ValueRef) -> ValueRef {
1012 if cx.unreachable { return llvm::LLVMGetUndef(T_i1()); }
1013 count_insn(cx, "isnotnull");
1014 return llvm::LLVMBuildIsNotNull(B(cx), Val, noname());
1018 pub fn PtrDiff(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
1020 let ccx = cx.fcx.ccx;
1021 if cx.unreachable { return llvm::LLVMGetUndef(ccx.int_type); }
1022 count_insn(cx, "ptrdiff");
1023 return llvm::LLVMBuildPtrDiff(B(cx), LHS, RHS, noname());
1027 pub fn Trap(cx: block) {
1029 if cx.unreachable { return; }
1031 let BB: BasicBlockRef = llvm::LLVMGetInsertBlock(b);
1032 let FN: ValueRef = llvm::LLVMGetBasicBlockParent(BB);
1033 let M: ModuleRef = llvm::LLVMGetGlobalParent(FN);
1034 let T: ValueRef = str::as_c_str(~"llvm.trap", |buf| {
1035 llvm::LLVMGetNamedFunction(M, buf)
1037 assert!((T as int != 0));
1038 let Args: ~[ValueRef] = ~[];
1040 count_insn(cx, "trap");
1041 llvm::LLVMBuildCall(b, T, vec::raw::to_ptr(Args),
1042 Args.len() as c_uint, noname());
1047 pub fn LandingPad(cx: block, Ty: TypeRef, PersFn: ValueRef,
1048 NumClauses: uint) -> ValueRef {
1050 check_not_terminated(cx);
1051 assert!(!cx.unreachable);
1052 count_insn(cx, "landingpad");
1053 return llvm::LLVMBuildLandingPad(B(cx), Ty, PersFn,
1054 NumClauses as c_uint, noname());
1058 pub fn SetCleanup(cx: block, LandingPad: ValueRef) {
1060 count_insn(cx, "setcleanup");
1061 llvm::LLVMSetCleanup(LandingPad, lib::llvm::True);
1065 pub fn Resume(cx: block, Exn: ValueRef) -> ValueRef {
1067 check_not_terminated(cx);
1068 terminate(cx, "Resume");
1069 count_insn(cx, "resume");
1070 return llvm::LLVMBuildResume(B(cx), Exn);
1074 // Atomic Operations
1075 pub fn AtomicCmpXchg(cx: block, dst: ValueRef,
1076 cmp: ValueRef, src: ValueRef,
1077 order: AtomicOrdering) -> ValueRef {
1079 llvm::LLVMBuildAtomicCmpXchg(B(cx), dst, cmp, src, order)
1082 pub fn AtomicRMW(cx: block, op: AtomicBinOp,
1083 dst: ValueRef, src: ValueRef,
1084 order: AtomicOrdering) -> ValueRef {
1086 llvm::LLVMBuildAtomicRMW(B(cx), op, dst, src, order)