]> git.lizzy.rs Git - rust.git/blob - src/librustc/middle/trans/build.rs
Remove 'Local Variable' comments
[rust.git] / src / librustc / middle / trans / build.rs
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.
4 //
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.
10
11 use lib::llvm::llvm;
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};
15 use lib;
16 use middle::trans::common::*;
17 use syntax::codemap::span;
18
19 use core::hashmap::HashMap;
20 use core::libc::{c_uint, c_ulonglong, c_char};
21
22 pub fn terminate(cx: block, _: &str) {
23     cx.terminated = true;
24 }
25
26 pub fn check_not_terminated(cx: block) {
27     if cx.terminated {
28         fail!(~"already terminated!");
29     }
30 }
31
32 pub fn B(cx: block) -> BuilderRef {
33     unsafe {
34         let b = cx.fcx.ccx.builder.B;
35         llvm::LLVMPositionBuilderAtEnd(b, cx.llbb);
36         return b;
37     }
38 }
39
40 pub fn count_insn(cx: block, category: &str) {
41     if cx.ccx().sess.count_llvm_insns() {
42
43         let h = cx.ccx().stats.llvm_insns;
44         let v = &*cx.ccx().stats.llvm_insn_ctxt;
45
46         // Build version of path with cycles removed.
47
48         // Pass 1: scan table mapping str -> rightmost pos.
49         let mut mm = HashMap::new();
50         let len = vec::len(*v);
51         let mut i = 0u;
52         while i < len {
53             mm.insert(copy v[i], i);
54             i += 1u;
55         }
56
57
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.
61         let mut s = ~".";
62         i = 0u;
63         while i < len {
64             i = *mm.get(&v[i]);
65             s += ~"/";
66             s += v[i];
67             i += 1u;
68         }
69
70         s += ~"/";
71         s += category;
72
73         let n = match h.find(&s) {
74           Some(&n) => n,
75           _ => 0u
76         };
77         h.insert(s, n+1u);
78     }
79 }
80
81
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.
89
90 pub fn RetVoid(cx: block) {
91     unsafe {
92         if cx.unreachable { return; }
93         check_not_terminated(cx);
94         terminate(cx, "RetVoid");
95         count_insn(cx, "retvoid");
96         llvm::LLVMBuildRetVoid(B(cx));
97     }
98 }
99
100 pub fn Ret(cx: block, V: ValueRef) {
101     unsafe {
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);
107     }
108 }
109
110 pub fn AggregateRet(cx: block, RetVals: &[ValueRef]) {
111     if cx.unreachable { return; }
112     check_not_terminated(cx);
113     terminate(cx, "AggregateRet");
114     unsafe {
115         llvm::LLVMBuildAggregateRet(B(cx), vec::raw::to_ptr(RetVals),
116                                     RetVals.len() as c_uint);
117     }
118 }
119
120 pub fn Br(cx: block, Dest: BasicBlockRef) {
121     unsafe {
122         if cx.unreachable { return; }
123         check_not_terminated(cx);
124         terminate(cx, "Br");
125         count_insn(cx, "br");
126         llvm::LLVMBuildBr(B(cx), Dest);
127     }
128 }
129
130 pub fn CondBr(cx: block, If: ValueRef, Then: BasicBlockRef,
131               Else: BasicBlockRef) {
132     unsafe {
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);
138     }
139 }
140
141 pub fn Switch(cx: block, V: ValueRef, Else: BasicBlockRef, NumCases: uint)
142     -> ValueRef {
143     unsafe {
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);
148     }
149 }
150
151 pub fn AddCase(S: ValueRef, OnVal: ValueRef, Dest: BasicBlockRef) {
152     unsafe {
153         if llvm::LLVMIsUndef(S) == lib::llvm::True { return; }
154         llvm::LLVMAddCase(S, OnVal, Dest);
155     }
156 }
157
158 pub fn IndirectBr(cx: block, Addr: ValueRef, NumDests: uint) {
159     unsafe {
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);
165     }
166 }
167
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 {
171     unsafe {
172         static cnull: uint = 0u;
173         return cast::transmute(&cnull);
174     }
175 }
176
177 pub fn Invoke(cx: block,
178               Fn: ValueRef,
179               Args: &[ValueRef],
180               Then: BasicBlockRef,
181               Catch: BasicBlockRef)
182            -> ValueRef {
183     if cx.unreachable {
184         return C_null(T_i8());
185     }
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,
191                                                    *a).to_owned()),
192                         ~", "));
193     unsafe {
194         count_insn(cx, "invoke");
195         llvm::LLVMBuildInvoke(B(cx),
196                               Fn,
197                               vec::raw::to_ptr(Args),
198                               Args.len() as c_uint,
199                               Then,
200                               Catch,
201                               noname())
202     }
203 }
204
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");
210     unsafe {
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);
216     }
217 }
218
219 pub fn Unreachable(cx: block) {
220     unsafe {
221         if cx.unreachable { return; }
222         cx.unreachable = true;
223         if !cx.terminated {
224             count_insn(cx, "unreachable");
225             llvm::LLVMBuildUnreachable(B(cx));
226         }
227     }
228 }
229
230 pub fn _Undef(val: ValueRef) -> ValueRef {
231     unsafe {
232         return llvm::LLVMGetUndef(val_ty(val));
233     }
234 }
235
236 /* Arithmetic */
237 pub fn Add(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
238     unsafe {
239         if cx.unreachable { return _Undef(LHS); }
240         count_insn(cx, "add");
241         return llvm::LLVMBuildAdd(B(cx), LHS, RHS, noname());
242     }
243 }
244
245 pub fn NSWAdd(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
246     unsafe {
247         if cx.unreachable { return _Undef(LHS); }
248         count_insn(cx, "nswadd");
249         return llvm::LLVMBuildNSWAdd(B(cx), LHS, RHS, noname());
250     }
251 }
252
253 pub fn NUWAdd(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
254     unsafe {
255         if cx.unreachable { return _Undef(LHS); }
256         count_insn(cx, "nuwadd");
257         return llvm::LLVMBuildNUWAdd(B(cx), LHS, RHS, noname());
258     }
259 }
260
261 pub fn FAdd(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
262     unsafe {
263         if cx.unreachable { return _Undef(LHS); }
264         count_insn(cx, "fadd");
265         return llvm::LLVMBuildFAdd(B(cx), LHS, RHS, noname());
266     }
267 }
268
269 pub fn Sub(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
270     unsafe {
271         if cx.unreachable { return _Undef(LHS); }
272         count_insn(cx, "sub");
273         return llvm::LLVMBuildSub(B(cx), LHS, RHS, noname());
274     }
275 }
276
277 pub fn NSWSub(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
278     unsafe {
279         if cx.unreachable { return _Undef(LHS); }
280         count_insn(cx, "nwsub");
281         return llvm::LLVMBuildNSWSub(B(cx), LHS, RHS, noname());
282     }
283 }
284
285 pub fn NUWSub(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
286     unsafe {
287         if cx.unreachable { return _Undef(LHS); }
288         count_insn(cx, "nuwsub");
289         return llvm::LLVMBuildNUWSub(B(cx), LHS, RHS, noname());
290     }
291 }
292
293 pub fn FSub(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
294     unsafe {
295         if cx.unreachable { return _Undef(LHS); }
296         count_insn(cx, "sub");
297         return llvm::LLVMBuildFSub(B(cx), LHS, RHS, noname());
298     }
299 }
300
301 pub fn Mul(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
302     unsafe {
303         if cx.unreachable { return _Undef(LHS); }
304         count_insn(cx, "mul");
305         return llvm::LLVMBuildMul(B(cx), LHS, RHS, noname());
306     }
307 }
308
309 pub fn NSWMul(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
310     unsafe {
311         if cx.unreachable { return _Undef(LHS); }
312         count_insn(cx, "nswmul");
313         return llvm::LLVMBuildNSWMul(B(cx), LHS, RHS, noname());
314     }
315 }
316
317 pub fn NUWMul(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
318     unsafe {
319         if cx.unreachable { return _Undef(LHS); }
320         count_insn(cx, "nuwmul");
321         return llvm::LLVMBuildNUWMul(B(cx), LHS, RHS, noname());
322     }
323 }
324
325 pub fn FMul(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
326     unsafe {
327         if cx.unreachable { return _Undef(LHS); }
328         count_insn(cx, "fmul");
329         return llvm::LLVMBuildFMul(B(cx), LHS, RHS, noname());
330     }
331 }
332
333 pub fn UDiv(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
334     unsafe {
335         if cx.unreachable { return _Undef(LHS); }
336         count_insn(cx, "udiv");
337         return llvm::LLVMBuildUDiv(B(cx), LHS, RHS, noname());
338     }
339 }
340
341 pub fn SDiv(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
342     unsafe {
343         if cx.unreachable { return _Undef(LHS); }
344         count_insn(cx, "sdiv");
345         return llvm::LLVMBuildSDiv(B(cx), LHS, RHS, noname());
346     }
347 }
348
349 pub fn ExactSDiv(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
350     unsafe {
351         if cx.unreachable { return _Undef(LHS); }
352         count_insn(cx, "extractsdiv");
353         return llvm::LLVMBuildExactSDiv(B(cx), LHS, RHS, noname());
354     }
355 }
356
357 pub fn FDiv(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
358     unsafe {
359         if cx.unreachable { return _Undef(LHS); }
360         count_insn(cx, "fdiv");
361         return llvm::LLVMBuildFDiv(B(cx), LHS, RHS, noname());
362     }
363 }
364
365 pub fn URem(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
366     unsafe {
367         if cx.unreachable { return _Undef(LHS); }
368         count_insn(cx, "urem");
369         return llvm::LLVMBuildURem(B(cx), LHS, RHS, noname());
370     }
371 }
372
373 pub fn SRem(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
374     unsafe {
375         if cx.unreachable { return _Undef(LHS); }
376         count_insn(cx, "srem");
377         return llvm::LLVMBuildSRem(B(cx), LHS, RHS, noname());
378     }
379 }
380
381 pub fn FRem(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
382     unsafe {
383         if cx.unreachable { return _Undef(LHS); }
384         count_insn(cx, "frem");
385         return llvm::LLVMBuildFRem(B(cx), LHS, RHS, noname());
386     }
387 }
388
389 pub fn Shl(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
390     unsafe {
391         if cx.unreachable { return _Undef(LHS); }
392         count_insn(cx, "shl");
393         return llvm::LLVMBuildShl(B(cx), LHS, RHS, noname());
394     }
395 }
396
397 pub fn LShr(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
398     unsafe {
399         if cx.unreachable { return _Undef(LHS); }
400         count_insn(cx, "lshr");
401         return llvm::LLVMBuildLShr(B(cx), LHS, RHS, noname());
402     }
403 }
404
405 pub fn AShr(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
406     unsafe {
407         if cx.unreachable { return _Undef(LHS); }
408         count_insn(cx, "ashr");
409         return llvm::LLVMBuildAShr(B(cx), LHS, RHS, noname());
410     }
411 }
412
413 pub fn And(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
414     unsafe {
415         if cx.unreachable { return _Undef(LHS); }
416         count_insn(cx, "and");
417         return llvm::LLVMBuildAnd(B(cx), LHS, RHS, noname());
418     }
419 }
420
421 pub fn Or(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
422     unsafe {
423         if cx.unreachable { return _Undef(LHS); }
424         count_insn(cx, "or");
425         return llvm::LLVMBuildOr(B(cx), LHS, RHS, noname());
426     }
427 }
428
429 pub fn Xor(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
430     unsafe {
431         if cx.unreachable { return _Undef(LHS); }
432         count_insn(cx, "xor");
433         return llvm::LLVMBuildXor(B(cx), LHS, RHS, noname());
434     }
435 }
436
437 pub fn BinOp(cx: block, Op: Opcode, LHS: ValueRef, RHS: ValueRef)
438           -> ValueRef {
439     unsafe {
440         if cx.unreachable { return _Undef(LHS); }
441         count_insn(cx, "binop");
442         return llvm::LLVMBuildBinOp(B(cx), Op, LHS, RHS, noname());
443     }
444 }
445
446 pub fn Neg(cx: block, V: ValueRef) -> ValueRef {
447     unsafe {
448         if cx.unreachable { return _Undef(V); }
449         count_insn(cx, "neg");
450         return llvm::LLVMBuildNeg(B(cx), V, noname());
451     }
452 }
453
454 pub fn NSWNeg(cx: block, V: ValueRef) -> ValueRef {
455     unsafe {
456         if cx.unreachable { return _Undef(V); }
457         count_insn(cx, "nswneg");
458         return llvm::LLVMBuildNSWNeg(B(cx), V, noname());
459     }
460 }
461
462 pub fn NUWNeg(cx: block, V: ValueRef) -> ValueRef {
463     unsafe {
464         if cx.unreachable { return _Undef(V); }
465         count_insn(cx, "nuwneg");
466         return llvm::LLVMBuildNUWNeg(B(cx), V, noname());
467     }
468 }
469 pub fn FNeg(cx: block, V: ValueRef) -> ValueRef {
470     unsafe {
471         if cx.unreachable { return _Undef(V); }
472         count_insn(cx, "fneg");
473         return llvm::LLVMBuildFNeg(B(cx), V, noname());
474     }
475 }
476
477 pub fn Not(cx: block, V: ValueRef) -> ValueRef {
478     unsafe {
479         if cx.unreachable { return _Undef(V); }
480         count_insn(cx, "not");
481         return llvm::LLVMBuildNot(B(cx), V, noname());
482     }
483 }
484
485 /* Memory */
486 pub fn Malloc(cx: block, Ty: TypeRef) -> ValueRef {
487     unsafe {
488         if cx.unreachable { return llvm::LLVMGetUndef(T_ptr(T_i8())); }
489         count_insn(cx, "malloc");
490         return llvm::LLVMBuildMalloc(B(cx), Ty, noname());
491     }
492 }
493
494 pub fn ArrayMalloc(cx: block, Ty: TypeRef, Val: ValueRef) -> ValueRef {
495     unsafe {
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());
499     }
500 }
501
502 pub fn Alloca(cx: block, Ty: TypeRef) -> ValueRef {
503     unsafe {
504         if cx.unreachable { return llvm::LLVMGetUndef(T_ptr(Ty)); }
505         count_insn(cx, "alloca");
506         return llvm::LLVMBuildAlloca(B(cx), Ty, noname());
507     }
508 }
509
510 pub fn ArrayAlloca(cx: block, Ty: TypeRef, Val: ValueRef) -> ValueRef {
511     unsafe {
512         if cx.unreachable { return llvm::LLVMGetUndef(T_ptr(Ty)); }
513         count_insn(cx, "arrayalloca");
514         return llvm::LLVMBuildArrayAlloca(B(cx), Ty, Val, noname());
515     }
516 }
517
518 pub fn Free(cx: block, PointerVal: ValueRef) {
519     unsafe {
520         if cx.unreachable { return; }
521         count_insn(cx, "free");
522         llvm::LLVMBuildFree(B(cx), PointerVal);
523     }
524 }
525
526 pub fn Load(cx: block, PointerVal: ValueRef) -> ValueRef {
527     unsafe {
528         let ccx = cx.fcx.ccx;
529         if cx.unreachable {
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);
534         }
535         count_insn(cx, "load");
536         return llvm::LLVMBuildLoad(B(cx), PointerVal, noname());
537     }
538 }
539
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);
543
544     unsafe {
545         let t = llvm::LLVMGetElementType(llvm::LLVMTypeOf(PointerVal));
546         let min = llvm::LLVMConstInt(t, lo, signed);
547         let max = llvm::LLVMConstInt(t, hi, signed);
548
549
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));
553         }
554     }
555
556     value
557 }
558
559 pub fn Store(cx: block, Val: ValueRef, Ptr: ValueRef) {
560     unsafe {
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);
567     }
568 }
569
570 pub fn GEP(cx: block, Pointer: ValueRef, Indices: &[ValueRef]) -> ValueRef {
571     unsafe {
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());
576     }
577 }
578
579 // Simple wrapper around GEP that takes an array of ints and wraps them
580 // in C_i32()
581 //
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);
587 }
588
589 pub fn InBoundsGEP(cx: block, Pointer: ValueRef, Indices: &[ValueRef]) ->
590    ValueRef {
591     unsafe {
592         if cx.unreachable { return llvm::LLVMGetUndef(T_ptr(T_nil())); }
593         unsafe {
594             count_insn(cx, "inboundsgep");
595         return llvm::LLVMBuildInBoundsGEP(B(cx), Pointer,
596                                            vec::raw::to_ptr(Indices),
597                                            Indices.len() as c_uint,
598                                            noname());
599         }
600     }
601 }
602
603 pub fn StructGEP(cx: block, Pointer: ValueRef, Idx: uint) -> ValueRef {
604     unsafe {
605         if cx.unreachable { return llvm::LLVMGetUndef(T_ptr(T_nil())); }
606         count_insn(cx, "structgep");
607         return llvm::LLVMBuildStructGEP(B(cx),
608                                         Pointer,
609                                         Idx as c_uint,
610                                         noname());
611     }
612 }
613
614 pub fn GlobalString(cx: block, _Str: *c_char) -> ValueRef {
615     unsafe {
616         if cx.unreachable { return llvm::LLVMGetUndef(T_ptr(T_i8())); }
617         count_insn(cx, "globalstring");
618         return llvm::LLVMBuildGlobalString(B(cx), _Str, noname());
619     }
620 }
621
622 pub fn GlobalStringPtr(cx: block, _Str: *c_char) -> ValueRef {
623     unsafe {
624         if cx.unreachable { return llvm::LLVMGetUndef(T_ptr(T_i8())); }
625         count_insn(cx, "globalstringptr");
626         return llvm::LLVMBuildGlobalStringPtr(B(cx), _Str, noname());
627     }
628 }
629
630 /* Casts */
631 pub fn Trunc(cx: block, Val: ValueRef, DestTy: TypeRef) -> ValueRef {
632     unsafe {
633         if cx.unreachable { return llvm::LLVMGetUndef(DestTy); }
634         count_insn(cx, "trunc");
635         return llvm::LLVMBuildTrunc(B(cx), Val, DestTy, noname());
636     }
637 }
638
639 pub fn ZExt(cx: block, Val: ValueRef, DestTy: TypeRef) -> ValueRef {
640     unsafe {
641         if cx.unreachable { return llvm::LLVMGetUndef(DestTy); }
642         count_insn(cx, "zext");
643         return llvm::LLVMBuildZExt(B(cx), Val, DestTy, noname());
644     }
645 }
646
647 pub fn SExt(cx: block, Val: ValueRef, DestTy: TypeRef) -> ValueRef {
648     unsafe {
649         if cx.unreachable { return llvm::LLVMGetUndef(DestTy); }
650         count_insn(cx, "sext");
651         return llvm::LLVMBuildSExt(B(cx), Val, DestTy, noname());
652     }
653 }
654
655 pub fn FPToUI(cx: block, Val: ValueRef, DestTy: TypeRef) -> ValueRef {
656     unsafe {
657         if cx.unreachable { return llvm::LLVMGetUndef(DestTy); }
658         count_insn(cx, "fptoui");
659         return llvm::LLVMBuildFPToUI(B(cx), Val, DestTy, noname());
660     }
661 }
662
663 pub fn FPToSI(cx: block, Val: ValueRef, DestTy: TypeRef) -> ValueRef {
664     unsafe {
665         if cx.unreachable { return llvm::LLVMGetUndef(DestTy); }
666         count_insn(cx, "fptosi");
667         return llvm::LLVMBuildFPToSI(B(cx), Val, DestTy, noname());
668     }
669 }
670
671 pub fn UIToFP(cx: block, Val: ValueRef, DestTy: TypeRef) -> ValueRef {
672     unsafe {
673         if cx.unreachable { return llvm::LLVMGetUndef(DestTy); }
674         count_insn(cx, "uitofp");
675         return llvm::LLVMBuildUIToFP(B(cx), Val, DestTy, noname());
676     }
677 }
678
679 pub fn SIToFP(cx: block, Val: ValueRef, DestTy: TypeRef) -> ValueRef {
680     unsafe {
681         if cx.unreachable { return llvm::LLVMGetUndef(DestTy); }
682         count_insn(cx, "sitofp");
683         return llvm::LLVMBuildSIToFP(B(cx), Val, DestTy, noname());
684     }
685 }
686
687 pub fn FPTrunc(cx: block, Val: ValueRef, DestTy: TypeRef) -> ValueRef {
688     unsafe {
689         if cx.unreachable { return llvm::LLVMGetUndef(DestTy); }
690         count_insn(cx, "fptrunc");
691         return llvm::LLVMBuildFPTrunc(B(cx), Val, DestTy, noname());
692     }
693 }
694
695 pub fn FPExt(cx: block, Val: ValueRef, DestTy: TypeRef) -> ValueRef {
696     unsafe {
697         if cx.unreachable { return llvm::LLVMGetUndef(DestTy); }
698         count_insn(cx, "fpext");
699         return llvm::LLVMBuildFPExt(B(cx), Val, DestTy, noname());
700     }
701 }
702
703 pub fn PtrToInt(cx: block, Val: ValueRef, DestTy: TypeRef) -> ValueRef {
704     unsafe {
705         if cx.unreachable { return llvm::LLVMGetUndef(DestTy); }
706         count_insn(cx, "ptrtoint");
707         return llvm::LLVMBuildPtrToInt(B(cx), Val, DestTy, noname());
708     }
709 }
710
711 pub fn IntToPtr(cx: block, Val: ValueRef, DestTy: TypeRef) -> ValueRef {
712     unsafe {
713         if cx.unreachable { return llvm::LLVMGetUndef(DestTy); }
714         count_insn(cx, "inttoptr");
715         return llvm::LLVMBuildIntToPtr(B(cx), Val, DestTy, noname());
716     }
717 }
718
719 pub fn BitCast(cx: block, Val: ValueRef, DestTy: TypeRef) -> ValueRef {
720     unsafe {
721         if cx.unreachable { return llvm::LLVMGetUndef(DestTy); }
722         count_insn(cx, "bitcast");
723         return llvm::LLVMBuildBitCast(B(cx), Val, DestTy, noname());
724     }
725 }
726
727 pub fn ZExtOrBitCast(cx: block, Val: ValueRef, DestTy: TypeRef) -> ValueRef {
728     unsafe {
729         if cx.unreachable { return llvm::LLVMGetUndef(DestTy); }
730         count_insn(cx, "zextorbitcast");
731         return llvm::LLVMBuildZExtOrBitCast(B(cx), Val, DestTy, noname());
732     }
733 }
734
735 pub fn SExtOrBitCast(cx: block, Val: ValueRef, DestTy: TypeRef) -> ValueRef {
736     unsafe {
737         if cx.unreachable { return llvm::LLVMGetUndef(DestTy); }
738         count_insn(cx, "sextorbitcast");
739         return llvm::LLVMBuildSExtOrBitCast(B(cx), Val, DestTy, noname());
740     }
741 }
742
743 pub fn TruncOrBitCast(cx: block, Val: ValueRef, DestTy: TypeRef) -> ValueRef {
744     unsafe {
745         if cx.unreachable { return llvm::LLVMGetUndef(DestTy); }
746         count_insn(cx, "truncorbitcast");
747         return llvm::LLVMBuildTruncOrBitCast(B(cx), Val, DestTy, noname());
748     }
749 }
750
751 pub fn Cast(cx: block, Op: Opcode, Val: ValueRef, DestTy: TypeRef, _: *u8)
752      -> ValueRef {
753     unsafe {
754         if cx.unreachable { return llvm::LLVMGetUndef(DestTy); }
755         count_insn(cx, "cast");
756         return llvm::LLVMBuildCast(B(cx), Op, Val, DestTy, noname());
757     }
758 }
759
760 pub fn PointerCast(cx: block, Val: ValueRef, DestTy: TypeRef) -> ValueRef {
761     unsafe {
762         if cx.unreachable { return llvm::LLVMGetUndef(DestTy); }
763         count_insn(cx, "pointercast");
764         return llvm::LLVMBuildPointerCast(B(cx), Val, DestTy, noname());
765     }
766 }
767
768 pub fn IntCast(cx: block, Val: ValueRef, DestTy: TypeRef) -> ValueRef {
769     unsafe {
770         if cx.unreachable { return llvm::LLVMGetUndef(DestTy); }
771         count_insn(cx, "intcast");
772         return llvm::LLVMBuildIntCast(B(cx), Val, DestTy, noname());
773     }
774 }
775
776 pub fn FPCast(cx: block, Val: ValueRef, DestTy: TypeRef) -> ValueRef {
777     unsafe {
778         if cx.unreachable { return llvm::LLVMGetUndef(DestTy); }
779         count_insn(cx, "fpcast");
780         return llvm::LLVMBuildFPCast(B(cx), Val, DestTy, noname());
781     }
782 }
783
784
785 /* Comparisons */
786 pub fn ICmp(cx: block, Op: IntPredicate, LHS: ValueRef, RHS: ValueRef)
787      -> ValueRef {
788     unsafe {
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());
792     }
793 }
794
795 pub fn FCmp(cx: block, Op: RealPredicate, LHS: ValueRef, RHS: ValueRef)
796      -> ValueRef {
797     unsafe {
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());
801     }
802 }
803
804 /* Miscellaneous instructions */
805 pub fn EmptyPhi(cx: block, Ty: TypeRef) -> ValueRef {
806     unsafe {
807         if cx.unreachable { return llvm::LLVMGetUndef(Ty); }
808         count_insn(cx, "emptyphi");
809         return llvm::LLVMBuildPhi(B(cx), Ty, noname());
810     }
811 }
812
813 pub fn Phi(cx: block, Ty: TypeRef, vals: &[ValueRef], bbs: &[BasicBlockRef])
814     -> ValueRef {
815     unsafe {
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);
823         return phi;
824     }
825 }
826
827 pub fn AddIncomingToPhi(phi: ValueRef, val: ValueRef, bb: BasicBlockRef) {
828     unsafe {
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);
833     }
834 }
835
836 pub fn _UndefReturn(cx: block, Fn: ValueRef) -> ValueRef {
837     unsafe {
838         let ccx = cx.fcx.ccx;
839         let ty = val_ty(Fn);
840         let retty = if llvm::LLVMGetTypeKind(ty) == lib::llvm::Integer {
841             llvm::LLVMGetReturnType(ty) } else { ccx.int_type };
842             count_insn(cx, ~"");
843         return llvm::LLVMGetUndef(retty);
844     }
845 }
846
847 pub fn add_span_comment(bcx: block, sp: span, text: &str) {
848     let ccx = bcx.ccx();
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);
852         add_comment(bcx, s);
853     }
854 }
855
856 pub fn add_comment(bcx: block, text: &str) {
857     unsafe {
858         let ccx = bcx.ccx();
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,
867                                              False, False)
868                 })
869             });
870             Call(bcx, asm, ~[]);
871         }
872     }
873 }
874
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 {
879     unsafe {
880         count_insn(cx, "inlineasm");
881
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 };
886
887         let argtys = do inputs.map |v| {
888             debug!("Asm Input Type: %?", val_str(cx.ccx().tn, *v));
889             val_ty(*v)
890         };
891
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);
896
897         Call(cx, v, inputs)
898     }
899 }
900
901 pub fn Call(cx: block, Fn: ValueRef, Args: &[ValueRef]) -> ValueRef {
902     if cx.unreachable { return _UndefReturn(cx, Fn); }
903     unsafe {
904         count_insn(cx, "call");
905
906         debug!("Call(Fn=%s, Args=%?)",
907                val_str(cx.ccx().tn, Fn),
908                Args.map(|arg| val_str(cx.ccx().tn, *arg)));
909
910         do vec::as_imm_buf(Args) |ptr, len| {
911             llvm::LLVMBuildCall(B(cx), Fn, ptr, len as c_uint, noname())
912         }
913     }
914 }
915
916 pub fn FastCall(cx: block, Fn: ValueRef, Args: &[ValueRef]) -> ValueRef {
917     if cx.unreachable { return _UndefReturn(cx, Fn); }
918     unsafe {
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);
923         return v;
924     }
925 }
926
927 pub fn CallWithConv(cx: block, Fn: ValueRef, Args: &[ValueRef],
928                     Conv: CallConv) -> ValueRef {
929     if cx.unreachable { return _UndefReturn(cx, Fn); }
930     unsafe {
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);
935         return v;
936     }
937 }
938
939 pub fn Select(cx: block, If: ValueRef, Then: ValueRef, Else: ValueRef) ->
940    ValueRef {
941     unsafe {
942         if cx.unreachable { return _Undef(Then); }
943         count_insn(cx, "select");
944         return llvm::LLVMBuildSelect(B(cx), If, Then, Else, noname());
945     }
946 }
947
948 pub fn VAArg(cx: block, list: ValueRef, Ty: TypeRef) -> ValueRef {
949     unsafe {
950         if cx.unreachable { return llvm::LLVMGetUndef(Ty); }
951         count_insn(cx, "vaarg");
952         return llvm::LLVMBuildVAArg(B(cx), list, Ty, noname());
953     }
954 }
955
956 pub fn ExtractElement(cx: block, VecVal: ValueRef, Index: ValueRef) ->
957    ValueRef {
958     unsafe {
959         if cx.unreachable { return llvm::LLVMGetUndef(T_nil()); }
960         count_insn(cx, "extractelement");
961         return llvm::LLVMBuildExtractElement(B(cx), VecVal, Index, noname());
962     }
963 }
964
965 pub fn InsertElement(cx: block, VecVal: ValueRef, EltVal: ValueRef,
966                  Index: ValueRef) {
967     unsafe {
968         if cx.unreachable { return; }
969         count_insn(cx, "insertelement");
970         llvm::LLVMBuildInsertElement(B(cx), VecVal, EltVal, Index, noname());
971     }
972 }
973
974 pub fn ShuffleVector(cx: block, V1: ValueRef, V2: ValueRef,
975                      Mask: ValueRef) {
976     unsafe {
977         if cx.unreachable { return; }
978         count_insn(cx, "shufflevector");
979         llvm::LLVMBuildShuffleVector(B(cx), V1, V2, Mask, noname());
980     }
981 }
982
983 pub fn ExtractValue(cx: block, AggVal: ValueRef, Index: uint) -> ValueRef {
984     unsafe {
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());
989     }
990 }
991
992 pub fn InsertValue(cx: block, AggVal: ValueRef, EltVal: ValueRef,
993                    Index: uint) {
994     unsafe {
995         if cx.unreachable { return; }
996         count_insn(cx, "insertvalue");
997         llvm::LLVMBuildInsertValue(B(cx), AggVal, EltVal, Index as c_uint,
998                                    noname());
999     }
1000 }
1001
1002 pub fn IsNull(cx: block, Val: ValueRef) -> ValueRef {
1003     unsafe {
1004         if cx.unreachable { return llvm::LLVMGetUndef(T_i1()); }
1005         count_insn(cx, "isnull");
1006         return llvm::LLVMBuildIsNull(B(cx), Val, noname());
1007     }
1008 }
1009
1010 pub fn IsNotNull(cx: block, Val: ValueRef) -> ValueRef {
1011     unsafe {
1012         if cx.unreachable { return llvm::LLVMGetUndef(T_i1()); }
1013         count_insn(cx, "isnotnull");
1014         return llvm::LLVMBuildIsNotNull(B(cx), Val, noname());
1015     }
1016 }
1017
1018 pub fn PtrDiff(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
1019     unsafe {
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());
1024     }
1025 }
1026
1027 pub fn Trap(cx: block) {
1028     unsafe {
1029         if cx.unreachable { return; }
1030         let b = B(cx);
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)
1036         });
1037         assert!((T as int != 0));
1038         let Args: ~[ValueRef] = ~[];
1039         unsafe {
1040             count_insn(cx, "trap");
1041             llvm::LLVMBuildCall(b, T, vec::raw::to_ptr(Args),
1042                                 Args.len() as c_uint, noname());
1043         }
1044     }
1045 }
1046
1047 pub fn LandingPad(cx: block, Ty: TypeRef, PersFn: ValueRef,
1048                   NumClauses: uint) -> ValueRef {
1049     unsafe {
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());
1055     }
1056 }
1057
1058 pub fn SetCleanup(cx: block, LandingPad: ValueRef) {
1059     unsafe {
1060         count_insn(cx, "setcleanup");
1061         llvm::LLVMSetCleanup(LandingPad, lib::llvm::True);
1062     }
1063 }
1064
1065 pub fn Resume(cx: block, Exn: ValueRef) -> ValueRef {
1066     unsafe {
1067         check_not_terminated(cx);
1068         terminate(cx, "Resume");
1069         count_insn(cx, "resume");
1070         return llvm::LLVMBuildResume(B(cx), Exn);
1071     }
1072 }
1073
1074 // Atomic Operations
1075 pub fn AtomicCmpXchg(cx: block, dst: ValueRef,
1076                      cmp: ValueRef, src: ValueRef,
1077                      order: AtomicOrdering) -> ValueRef {
1078     unsafe {
1079         llvm::LLVMBuildAtomicCmpXchg(B(cx), dst, cmp, src, order)
1080     }
1081 }
1082 pub fn AtomicRMW(cx: block, op: AtomicBinOp,
1083                  dst: ValueRef, src: ValueRef,
1084                  order: AtomicOrdering) -> ValueRef {
1085     unsafe {
1086         llvm::LLVMBuildAtomicRMW(B(cx), op, dst, src, order)
1087     }
1088 }