]> git.lizzy.rs Git - rust.git/blob - src/librustc/middle/trans/build.rs
e04454d4a68d0233099381dca4f55ff45c8c0659
[rust.git] / src / librustc / middle / trans / build.rs
1 // Copyright 2012-2014 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 #![allow(dead_code)] // FFI wrappers
12 #![allow(non_snake_case_functions)]
13
14 use lib::llvm::llvm;
15 use lib::llvm::{CallConv, AtomicBinOp, AtomicOrdering, AsmDialect};
16 use lib::llvm::{Opcode, IntPredicate, RealPredicate};
17 use lib::llvm::{ValueRef, BasicBlockRef};
18 use lib;
19 use middle::trans::common::*;
20 use syntax::codemap::Span;
21
22 use middle::trans::builder::Builder;
23 use middle::trans::type_::Type;
24
25 use libc::{c_uint, c_ulonglong, c_char};
26
27 pub fn terminate(cx: &Block, _: &str) {
28     debug!("terminate({})", cx.to_str());
29     cx.terminated.set(true);
30 }
31
32 pub fn check_not_terminated(cx: &Block) {
33     if cx.terminated.get() {
34         fail!("already terminated!");
35     }
36 }
37
38 pub fn B<'a>(cx: &'a Block) -> Builder<'a> {
39     let b = cx.fcx.ccx.builder();
40     b.position_at_end(cx.llbb);
41     b
42 }
43
44 // The difference between a block being unreachable and being terminated is
45 // somewhat obscure, and has to do with error checking. When a block is
46 // terminated, we're saying that trying to add any further statements in the
47 // block is an error. On the other hand, if something is unreachable, that
48 // means that the block was terminated in some way that we don't want to check
49 // for (fail/break/return statements, call to diverging functions, etc), and
50 // further instructions to the block should simply be ignored.
51
52 pub fn RetVoid(cx: &Block) {
53     if cx.unreachable.get() { return; }
54     check_not_terminated(cx);
55     terminate(cx, "RetVoid");
56     B(cx).ret_void();
57 }
58
59 pub fn Ret(cx: &Block, v: ValueRef) {
60     if cx.unreachable.get() { return; }
61     check_not_terminated(cx);
62     terminate(cx, "Ret");
63     B(cx).ret(v);
64 }
65
66 pub fn AggregateRet(cx: &Block, ret_vals: &[ValueRef]) {
67     if cx.unreachable.get() { return; }
68     check_not_terminated(cx);
69     terminate(cx, "AggregateRet");
70     B(cx).aggregate_ret(ret_vals);
71 }
72
73 pub fn Br(cx: &Block, dest: BasicBlockRef) {
74     if cx.unreachable.get() { return; }
75     check_not_terminated(cx);
76     terminate(cx, "Br");
77     B(cx).br(dest);
78 }
79
80 pub fn CondBr(cx: &Block,
81               if_: ValueRef,
82               then: BasicBlockRef,
83               else_: BasicBlockRef) {
84     if cx.unreachable.get() { return; }
85     check_not_terminated(cx);
86     terminate(cx, "CondBr");
87     B(cx).cond_br(if_, then, else_);
88 }
89
90 pub fn Switch(cx: &Block, v: ValueRef, else_: BasicBlockRef, num_cases: uint)
91     -> ValueRef {
92     if cx.unreachable.get() { return _Undef(v); }
93     check_not_terminated(cx);
94     terminate(cx, "Switch");
95     B(cx).switch(v, else_, num_cases)
96 }
97
98 pub fn AddCase(s: ValueRef, on_val: ValueRef, dest: BasicBlockRef) {
99     unsafe {
100         if llvm::LLVMIsUndef(s) == lib::llvm::True { return; }
101         llvm::LLVMAddCase(s, on_val, dest);
102     }
103 }
104
105 pub fn IndirectBr(cx: &Block, addr: ValueRef, num_dests: uint) {
106     if cx.unreachable.get() { return; }
107     check_not_terminated(cx);
108     terminate(cx, "IndirectBr");
109     B(cx).indirect_br(addr, num_dests);
110 }
111
112 pub fn Invoke(cx: &Block,
113               fn_: ValueRef,
114               args: &[ValueRef],
115               then: BasicBlockRef,
116               catch: BasicBlockRef,
117               attributes: &[(uint, u64)])
118               -> ValueRef {
119     if cx.unreachable.get() {
120         return C_null(Type::i8(cx.ccx()));
121     }
122     check_not_terminated(cx);
123     terminate(cx, "Invoke");
124     debug!("Invoke({} with arguments ({}))",
125            cx.val_to_str(fn_),
126            args.iter().map(|a| cx.val_to_str(*a)).collect::<Vec<String>>().connect(", "));
127     B(cx).invoke(fn_, args, then, catch, attributes)
128 }
129
130 pub fn Unreachable(cx: &Block) {
131     if cx.unreachable.get() {
132         return
133     }
134     cx.unreachable.set(true);
135     if !cx.terminated.get() {
136         B(cx).unreachable();
137     }
138 }
139
140 pub fn _Undef(val: ValueRef) -> ValueRef {
141     unsafe {
142         return llvm::LLVMGetUndef(val_ty(val).to_ref());
143     }
144 }
145
146 /* Arithmetic */
147 pub fn Add(cx: &Block, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
148     if cx.unreachable.get() { return _Undef(lhs); }
149     B(cx).add(lhs, rhs)
150 }
151
152 pub fn NSWAdd(cx: &Block, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
153     if cx.unreachable.get() { return _Undef(lhs); }
154     B(cx).nswadd(lhs, rhs)
155 }
156
157 pub fn NUWAdd(cx: &Block, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
158     if cx.unreachable.get() { return _Undef(lhs); }
159     B(cx).nuwadd(lhs, rhs)
160 }
161
162 pub fn FAdd(cx: &Block, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
163     if cx.unreachable.get() { return _Undef(lhs); }
164     B(cx).fadd(lhs, rhs)
165 }
166
167 pub fn Sub(cx: &Block, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
168     if cx.unreachable.get() { return _Undef(lhs); }
169     B(cx).sub(lhs, rhs)
170 }
171
172 pub fn NSWSub(cx: &Block, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
173     if cx.unreachable.get() { return _Undef(lhs); }
174     B(cx).nswsub(lhs, rhs)
175 }
176
177 pub fn NUWSub(cx: &Block, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
178     if cx.unreachable.get() { return _Undef(lhs); }
179     B(cx).nuwsub(lhs, rhs)
180 }
181
182 pub fn FSub(cx: &Block, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
183     if cx.unreachable.get() { return _Undef(lhs); }
184     B(cx).fsub(lhs, rhs)
185 }
186
187 pub fn Mul(cx: &Block, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
188     if cx.unreachable.get() { return _Undef(lhs); }
189     B(cx).mul(lhs, rhs)
190 }
191
192 pub fn NSWMul(cx: &Block, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
193     if cx.unreachable.get() { return _Undef(lhs); }
194     B(cx).nswmul(lhs, rhs)
195 }
196
197 pub fn NUWMul(cx: &Block, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
198     if cx.unreachable.get() { return _Undef(lhs); }
199     B(cx).nuwmul(lhs, rhs)
200 }
201
202 pub fn FMul(cx: &Block, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
203     if cx.unreachable.get() { return _Undef(lhs); }
204     B(cx).fmul(lhs, rhs)
205 }
206
207 pub fn UDiv(cx: &Block, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
208     if cx.unreachable.get() { return _Undef(lhs); }
209     B(cx).udiv(lhs, rhs)
210 }
211
212 pub fn SDiv(cx: &Block, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
213     if cx.unreachable.get() { return _Undef(lhs); }
214     B(cx).sdiv(lhs, rhs)
215 }
216
217 pub fn ExactSDiv(cx: &Block, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
218     if cx.unreachable.get() { return _Undef(lhs); }
219     B(cx).exactsdiv(lhs, rhs)
220 }
221
222 pub fn FDiv(cx: &Block, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
223     if cx.unreachable.get() { return _Undef(lhs); }
224     B(cx).fdiv(lhs, rhs)
225 }
226
227 pub fn URem(cx: &Block, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
228     if cx.unreachable.get() { return _Undef(lhs); }
229     B(cx).urem(lhs, rhs)
230 }
231
232 pub fn SRem(cx: &Block, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
233     if cx.unreachable.get() { return _Undef(lhs); }
234     B(cx).srem(lhs, rhs)
235 }
236
237 pub fn FRem(cx: &Block, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
238     if cx.unreachable.get() { return _Undef(lhs); }
239     B(cx).frem(lhs, rhs)
240 }
241
242 pub fn Shl(cx: &Block, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
243     if cx.unreachable.get() { return _Undef(lhs); }
244     B(cx).shl(lhs, rhs)
245 }
246
247 pub fn LShr(cx: &Block, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
248     if cx.unreachable.get() { return _Undef(lhs); }
249     B(cx).lshr(lhs, rhs)
250 }
251
252 pub fn AShr(cx: &Block, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
253     if cx.unreachable.get() { return _Undef(lhs); }
254     B(cx).ashr(lhs, rhs)
255 }
256
257 pub fn And(cx: &Block, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
258     if cx.unreachable.get() { return _Undef(lhs); }
259     B(cx).and(lhs, rhs)
260 }
261
262 pub fn Or(cx: &Block, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
263     if cx.unreachable.get() { return _Undef(lhs); }
264     B(cx).or(lhs, rhs)
265 }
266
267 pub fn Xor(cx: &Block, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
268     if cx.unreachable.get() { return _Undef(lhs); }
269     B(cx).xor(lhs, rhs)
270 }
271
272 pub fn BinOp(cx: &Block, op: Opcode, lhs: ValueRef, rhs: ValueRef)
273           -> ValueRef {
274     if cx.unreachable.get() { return _Undef(lhs); }
275     B(cx).binop(op, lhs, rhs)
276 }
277
278 pub fn Neg(cx: &Block, v: ValueRef) -> ValueRef {
279     if cx.unreachable.get() { return _Undef(v); }
280     B(cx).neg(v)
281 }
282
283 pub fn NSWNeg(cx: &Block, v: ValueRef) -> ValueRef {
284     if cx.unreachable.get() { return _Undef(v); }
285     B(cx).nswneg(v)
286 }
287
288 pub fn NUWNeg(cx: &Block, v: ValueRef) -> ValueRef {
289     if cx.unreachable.get() { return _Undef(v); }
290     B(cx).nuwneg(v)
291 }
292 pub fn FNeg(cx: &Block, v: ValueRef) -> ValueRef {
293     if cx.unreachable.get() { return _Undef(v); }
294     B(cx).fneg(v)
295 }
296
297 pub fn Not(cx: &Block, v: ValueRef) -> ValueRef {
298     if cx.unreachable.get() { return _Undef(v); }
299     B(cx).not(v)
300 }
301
302 /* Memory */
303 pub fn Malloc(cx: &Block, ty: Type) -> ValueRef {
304     unsafe {
305         if cx.unreachable.get() {
306             return llvm::LLVMGetUndef(Type::i8p(cx.ccx()).to_ref());
307         }
308         B(cx).malloc(ty)
309     }
310 }
311
312 pub fn ArrayMalloc(cx: &Block, ty: Type, val: ValueRef) -> ValueRef {
313     unsafe {
314         if cx.unreachable.get() {
315             return llvm::LLVMGetUndef(Type::i8p(cx.ccx()).to_ref());
316         }
317         B(cx).array_malloc(ty, val)
318     }
319 }
320
321 pub fn Alloca(cx: &Block, ty: Type, name: &str) -> ValueRef {
322     unsafe {
323         if cx.unreachable.get() { return llvm::LLVMGetUndef(ty.ptr_to().to_ref()); }
324         AllocaFcx(cx.fcx, ty, name)
325     }
326 }
327
328 pub fn AllocaFcx(fcx: &FunctionContext, ty: Type, name: &str) -> ValueRef {
329     let b = fcx.ccx.builder();
330     b.position_before(fcx.alloca_insert_pt.get().unwrap());
331     b.alloca(ty, name)
332 }
333
334 pub fn ArrayAlloca(cx: &Block, ty: Type, val: ValueRef) -> ValueRef {
335     unsafe {
336         if cx.unreachable.get() { return llvm::LLVMGetUndef(ty.ptr_to().to_ref()); }
337         let b = cx.fcx.ccx.builder();
338         b.position_before(cx.fcx.alloca_insert_pt.get().unwrap());
339         b.array_alloca(ty, val)
340     }
341 }
342
343 pub fn Free(cx: &Block, pointer_val: ValueRef) {
344     if cx.unreachable.get() { return; }
345     B(cx).free(pointer_val)
346 }
347
348 pub fn Load(cx: &Block, pointer_val: ValueRef) -> ValueRef {
349     unsafe {
350         let ccx = cx.fcx.ccx;
351         if cx.unreachable.get() {
352             let ty = val_ty(pointer_val);
353             let eltty = if ty.kind() == lib::llvm::Array {
354                 ty.element_type()
355             } else {
356                 ccx.int_type
357             };
358             return llvm::LLVMGetUndef(eltty.to_ref());
359         }
360         B(cx).load(pointer_val)
361     }
362 }
363
364 pub fn VolatileLoad(cx: &Block, pointer_val: ValueRef) -> ValueRef {
365     unsafe {
366         if cx.unreachable.get() {
367             return llvm::LLVMGetUndef(Type::nil(cx.ccx()).to_ref());
368         }
369         B(cx).volatile_load(pointer_val)
370     }
371 }
372
373 pub fn AtomicLoad(cx: &Block, pointer_val: ValueRef, order: AtomicOrdering) -> ValueRef {
374     unsafe {
375         let ccx = cx.fcx.ccx;
376         if cx.unreachable.get() {
377             return llvm::LLVMGetUndef(ccx.int_type.to_ref());
378         }
379         B(cx).atomic_load(pointer_val, order)
380     }
381 }
382
383
384 pub fn LoadRangeAssert(cx: &Block, pointer_val: ValueRef, lo: c_ulonglong,
385                        hi: c_ulonglong, signed: lib::llvm::Bool) -> ValueRef {
386     if cx.unreachable.get() {
387         let ccx = cx.fcx.ccx;
388         let ty = val_ty(pointer_val);
389         let eltty = if ty.kind() == lib::llvm::Array {
390             ty.element_type()
391         } else {
392             ccx.int_type
393         };
394         unsafe {
395             llvm::LLVMGetUndef(eltty.to_ref())
396         }
397     } else {
398         B(cx).load_range_assert(pointer_val, lo, hi, signed)
399     }
400 }
401
402 pub fn Store(cx: &Block, val: ValueRef, ptr: ValueRef) {
403     if cx.unreachable.get() { return; }
404     B(cx).store(val, ptr)
405 }
406
407 pub fn VolatileStore(cx: &Block, val: ValueRef, ptr: ValueRef) {
408     if cx.unreachable.get() { return; }
409     B(cx).volatile_store(val, ptr)
410 }
411
412 pub fn AtomicStore(cx: &Block, val: ValueRef, ptr: ValueRef, order: AtomicOrdering) {
413     if cx.unreachable.get() { return; }
414     B(cx).atomic_store(val, ptr, order)
415 }
416
417 pub fn GEP(cx: &Block, pointer: ValueRef, indices: &[ValueRef]) -> ValueRef {
418     unsafe {
419         if cx.unreachable.get() {
420             return llvm::LLVMGetUndef(Type::nil(cx.ccx()).ptr_to().to_ref());
421         }
422         B(cx).gep(pointer, indices)
423     }
424 }
425
426 // Simple wrapper around GEP that takes an array of ints and wraps them
427 // in C_i32()
428 #[inline]
429 pub fn GEPi(cx: &Block, base: ValueRef, ixs: &[uint]) -> ValueRef {
430     unsafe {
431         if cx.unreachable.get() {
432             return llvm::LLVMGetUndef(Type::nil(cx.ccx()).ptr_to().to_ref());
433         }
434         B(cx).gepi(base, ixs)
435     }
436 }
437
438 pub fn InBoundsGEP(cx: &Block, pointer: ValueRef, indices: &[ValueRef]) -> ValueRef {
439     unsafe {
440         if cx.unreachable.get() {
441             return llvm::LLVMGetUndef(Type::nil(cx.ccx()).ptr_to().to_ref());
442         }
443         B(cx).inbounds_gep(pointer, indices)
444     }
445 }
446
447 pub fn StructGEP(cx: &Block, pointer: ValueRef, idx: uint) -> ValueRef {
448     unsafe {
449         if cx.unreachable.get() {
450             return llvm::LLVMGetUndef(Type::nil(cx.ccx()).ptr_to().to_ref());
451         }
452         B(cx).struct_gep(pointer, idx)
453     }
454 }
455
456 pub fn GlobalString(cx: &Block, _str: *c_char) -> ValueRef {
457     unsafe {
458         if cx.unreachable.get() {
459             return llvm::LLVMGetUndef(Type::i8p(cx.ccx()).to_ref());
460         }
461         B(cx).global_string(_str)
462     }
463 }
464
465 pub fn GlobalStringPtr(cx: &Block, _str: *c_char) -> ValueRef {
466     unsafe {
467         if cx.unreachable.get() {
468             return llvm::LLVMGetUndef(Type::i8p(cx.ccx()).to_ref());
469         }
470         B(cx).global_string_ptr(_str)
471     }
472 }
473
474 /* Casts */
475 pub fn Trunc(cx: &Block, val: ValueRef, dest_ty: Type) -> ValueRef {
476     unsafe {
477         if cx.unreachable.get() { return llvm::LLVMGetUndef(dest_ty.to_ref()); }
478         B(cx).trunc(val, dest_ty)
479     }
480 }
481
482 pub fn ZExt(cx: &Block, val: ValueRef, dest_ty: Type) -> ValueRef {
483     unsafe {
484         if cx.unreachable.get() { return llvm::LLVMGetUndef(dest_ty.to_ref()); }
485         B(cx).zext(val, dest_ty)
486     }
487 }
488
489 pub fn SExt(cx: &Block, val: ValueRef, dest_ty: Type) -> ValueRef {
490     unsafe {
491         if cx.unreachable.get() { return llvm::LLVMGetUndef(dest_ty.to_ref()); }
492         B(cx).sext(val, dest_ty)
493     }
494 }
495
496 pub fn FPToUI(cx: &Block, val: ValueRef, dest_ty: Type) -> ValueRef {
497     unsafe {
498         if cx.unreachable.get() { return llvm::LLVMGetUndef(dest_ty.to_ref()); }
499         B(cx).fptoui(val, dest_ty)
500     }
501 }
502
503 pub fn FPToSI(cx: &Block, val: ValueRef, dest_ty: Type) -> ValueRef {
504     unsafe {
505         if cx.unreachable.get() { return llvm::LLVMGetUndef(dest_ty.to_ref()); }
506         B(cx).fptosi(val, dest_ty)
507     }
508 }
509
510 pub fn UIToFP(cx: &Block, val: ValueRef, dest_ty: Type) -> ValueRef {
511     unsafe {
512         if cx.unreachable.get() { return llvm::LLVMGetUndef(dest_ty.to_ref()); }
513         B(cx).uitofp(val, dest_ty)
514     }
515 }
516
517 pub fn SIToFP(cx: &Block, val: ValueRef, dest_ty: Type) -> ValueRef {
518     unsafe {
519         if cx.unreachable.get() { return llvm::LLVMGetUndef(dest_ty.to_ref()); }
520         B(cx).sitofp(val, dest_ty)
521     }
522 }
523
524 pub fn FPTrunc(cx: &Block, val: ValueRef, dest_ty: Type) -> ValueRef {
525     unsafe {
526         if cx.unreachable.get() { return llvm::LLVMGetUndef(dest_ty.to_ref()); }
527         B(cx).fptrunc(val, dest_ty)
528     }
529 }
530
531 pub fn FPExt(cx: &Block, val: ValueRef, dest_ty: Type) -> ValueRef {
532     unsafe {
533         if cx.unreachable.get() { return llvm::LLVMGetUndef(dest_ty.to_ref()); }
534         B(cx).fpext(val, dest_ty)
535     }
536 }
537
538 pub fn PtrToInt(cx: &Block, val: ValueRef, dest_ty: Type) -> ValueRef {
539     unsafe {
540         if cx.unreachable.get() { return llvm::LLVMGetUndef(dest_ty.to_ref()); }
541         B(cx).ptrtoint(val, dest_ty)
542     }
543 }
544
545 pub fn IntToPtr(cx: &Block, val: ValueRef, dest_ty: Type) -> ValueRef {
546     unsafe {
547         if cx.unreachable.get() { return llvm::LLVMGetUndef(dest_ty.to_ref()); }
548         B(cx).inttoptr(val, dest_ty)
549     }
550 }
551
552 pub fn BitCast(cx: &Block, val: ValueRef, dest_ty: Type) -> ValueRef {
553     unsafe {
554         if cx.unreachable.get() { return llvm::LLVMGetUndef(dest_ty.to_ref()); }
555         B(cx).bitcast(val, dest_ty)
556     }
557 }
558
559 pub fn ZExtOrBitCast(cx: &Block, val: ValueRef, dest_ty: Type) -> ValueRef {
560     unsafe {
561         if cx.unreachable.get() { return llvm::LLVMGetUndef(dest_ty.to_ref()); }
562         B(cx).zext_or_bitcast(val, dest_ty)
563     }
564 }
565
566 pub fn SExtOrBitCast(cx: &Block, val: ValueRef, dest_ty: Type) -> ValueRef {
567     unsafe {
568         if cx.unreachable.get() { return llvm::LLVMGetUndef(dest_ty.to_ref()); }
569         B(cx).sext_or_bitcast(val, dest_ty)
570     }
571 }
572
573 pub fn TruncOrBitCast(cx: &Block, val: ValueRef, dest_ty: Type) -> ValueRef {
574     unsafe {
575         if cx.unreachable.get() { return llvm::LLVMGetUndef(dest_ty.to_ref()); }
576         B(cx).trunc_or_bitcast(val, dest_ty)
577     }
578 }
579
580 pub fn Cast(cx: &Block, op: Opcode, val: ValueRef, dest_ty: Type, _: *u8)
581      -> ValueRef {
582     unsafe {
583         if cx.unreachable.get() { return llvm::LLVMGetUndef(dest_ty.to_ref()); }
584         B(cx).cast(op, val, dest_ty)
585     }
586 }
587
588 pub fn PointerCast(cx: &Block, val: ValueRef, dest_ty: Type) -> ValueRef {
589     unsafe {
590         if cx.unreachable.get() { return llvm::LLVMGetUndef(dest_ty.to_ref()); }
591         B(cx).pointercast(val, dest_ty)
592     }
593 }
594
595 pub fn IntCast(cx: &Block, val: ValueRef, dest_ty: Type) -> ValueRef {
596     unsafe {
597         if cx.unreachable.get() { return llvm::LLVMGetUndef(dest_ty.to_ref()); }
598         B(cx).intcast(val, dest_ty)
599     }
600 }
601
602 pub fn FPCast(cx: &Block, val: ValueRef, dest_ty: Type) -> ValueRef {
603     unsafe {
604         if cx.unreachable.get() { return llvm::LLVMGetUndef(dest_ty.to_ref()); }
605         B(cx).fpcast(val, dest_ty)
606     }
607 }
608
609
610 /* Comparisons */
611 pub fn ICmp(cx: &Block, op: IntPredicate, lhs: ValueRef, rhs: ValueRef)
612      -> ValueRef {
613     unsafe {
614         if cx.unreachable.get() {
615             return llvm::LLVMGetUndef(Type::i1(cx.ccx()).to_ref());
616         }
617         B(cx).icmp(op, lhs, rhs)
618     }
619 }
620
621 pub fn FCmp(cx: &Block, op: RealPredicate, lhs: ValueRef, rhs: ValueRef)
622      -> ValueRef {
623     unsafe {
624         if cx.unreachable.get() {
625             return llvm::LLVMGetUndef(Type::i1(cx.ccx()).to_ref());
626         }
627         B(cx).fcmp(op, lhs, rhs)
628     }
629 }
630
631 /* Miscellaneous instructions */
632 pub fn EmptyPhi(cx: &Block, ty: Type) -> ValueRef {
633     unsafe {
634         if cx.unreachable.get() { return llvm::LLVMGetUndef(ty.to_ref()); }
635         B(cx).empty_phi(ty)
636     }
637 }
638
639 pub fn Phi(cx: &Block, ty: Type, vals: &[ValueRef], bbs: &[BasicBlockRef]) -> ValueRef {
640     unsafe {
641         if cx.unreachable.get() { return llvm::LLVMGetUndef(ty.to_ref()); }
642         B(cx).phi(ty, vals, bbs)
643     }
644 }
645
646 pub fn AddIncomingToPhi(phi: ValueRef, val: ValueRef, bb: BasicBlockRef) {
647     unsafe {
648         if llvm::LLVMIsUndef(phi) == lib::llvm::True { return; }
649         llvm::LLVMAddIncoming(phi, &val, &bb, 1 as c_uint);
650     }
651 }
652
653 pub fn _UndefReturn(cx: &Block, fn_: ValueRef) -> ValueRef {
654     unsafe {
655         let ccx = cx.fcx.ccx;
656         let ty = val_ty(fn_);
657         let retty = if ty.kind() == lib::llvm::Integer {
658             ty.return_type()
659         } else {
660             ccx.int_type
661         };
662         B(cx).count_insn("ret_undef");
663         llvm::LLVMGetUndef(retty.to_ref())
664     }
665 }
666
667 pub fn add_span_comment(cx: &Block, sp: Span, text: &str) {
668     B(cx).add_span_comment(sp, text)
669 }
670
671 pub fn add_comment(cx: &Block, text: &str) {
672     B(cx).add_comment(text)
673 }
674
675 pub fn InlineAsmCall(cx: &Block, asm: *c_char, cons: *c_char,
676                      inputs: &[ValueRef], output: Type,
677                      volatile: bool, alignstack: bool,
678                      dia: AsmDialect) -> ValueRef {
679     B(cx).inline_asm_call(asm, cons, inputs, output, volatile, alignstack, dia)
680 }
681
682 pub fn Call(cx: &Block, fn_: ValueRef, args: &[ValueRef],
683             attributes: &[(uint, u64)]) -> ValueRef {
684     if cx.unreachable.get() { return _UndefReturn(cx, fn_); }
685     B(cx).call(fn_, args, attributes)
686 }
687
688 pub fn CallWithConv(cx: &Block, fn_: ValueRef, args: &[ValueRef], conv: CallConv,
689                     attributes: &[(uint, u64)]) -> ValueRef {
690     if cx.unreachable.get() { return _UndefReturn(cx, fn_); }
691     B(cx).call_with_conv(fn_, args, conv, attributes)
692 }
693
694 pub fn AtomicFence(cx: &Block, order: AtomicOrdering) {
695     if cx.unreachable.get() { return; }
696     B(cx).atomic_fence(order)
697 }
698
699 pub fn Select(cx: &Block, if_: ValueRef, then: ValueRef, else_: ValueRef) -> ValueRef {
700     if cx.unreachable.get() { return _Undef(then); }
701     B(cx).select(if_, then, else_)
702 }
703
704 pub fn VAArg(cx: &Block, list: ValueRef, ty: Type) -> ValueRef {
705     unsafe {
706         if cx.unreachable.get() { return llvm::LLVMGetUndef(ty.to_ref()); }
707         B(cx).va_arg(list, ty)
708     }
709 }
710
711 pub fn ExtractElement(cx: &Block, vec_val: ValueRef, index: ValueRef) -> ValueRef {
712     unsafe {
713         if cx.unreachable.get() {
714             return llvm::LLVMGetUndef(Type::nil(cx.ccx()).to_ref());
715         }
716         B(cx).extract_element(vec_val, index)
717     }
718 }
719
720 pub fn InsertElement(cx: &Block, vec_val: ValueRef, elt_val: ValueRef,
721                      index: ValueRef) -> ValueRef {
722     unsafe {
723         if cx.unreachable.get() {
724             return llvm::LLVMGetUndef(Type::nil(cx.ccx()).to_ref());
725         }
726         B(cx).insert_element(vec_val, elt_val, index)
727     }
728 }
729
730 pub fn ShuffleVector(cx: &Block, v1: ValueRef, v2: ValueRef,
731                      mask: ValueRef) -> ValueRef {
732     unsafe {
733         if cx.unreachable.get() {
734             return llvm::LLVMGetUndef(Type::nil(cx.ccx()).to_ref());
735         }
736         B(cx).shuffle_vector(v1, v2, mask)
737     }
738 }
739
740 pub fn VectorSplat(cx: &Block, num_elts: uint, elt_val: ValueRef) -> ValueRef {
741     unsafe {
742         if cx.unreachable.get() {
743             return llvm::LLVMGetUndef(Type::nil(cx.ccx()).to_ref());
744         }
745         B(cx).vector_splat(num_elts, elt_val)
746     }
747 }
748
749 pub fn ExtractValue(cx: &Block, agg_val: ValueRef, index: uint) -> ValueRef {
750     unsafe {
751         if cx.unreachable.get() {
752             return llvm::LLVMGetUndef(Type::nil(cx.ccx()).to_ref());
753         }
754         B(cx).extract_value(agg_val, index)
755     }
756 }
757
758 pub fn InsertValue(cx: &Block, agg_val: ValueRef, elt_val: ValueRef, index: uint) -> ValueRef {
759     unsafe {
760         if cx.unreachable.get() {
761             return llvm::LLVMGetUndef(Type::nil(cx.ccx()).to_ref());
762         }
763         B(cx).insert_value(agg_val, elt_val, index)
764     }
765 }
766
767 pub fn IsNull(cx: &Block, val: ValueRef) -> ValueRef {
768     unsafe {
769         if cx.unreachable.get() {
770             return llvm::LLVMGetUndef(Type::i1(cx.ccx()).to_ref());
771         }
772         B(cx).is_null(val)
773     }
774 }
775
776 pub fn IsNotNull(cx: &Block, val: ValueRef) -> ValueRef {
777     unsafe {
778         if cx.unreachable.get() {
779             return llvm::LLVMGetUndef(Type::i1(cx.ccx()).to_ref());
780         }
781         B(cx).is_not_null(val)
782     }
783 }
784
785 pub fn PtrDiff(cx: &Block, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
786     unsafe {
787         let ccx = cx.fcx.ccx;
788         if cx.unreachable.get() { return llvm::LLVMGetUndef(ccx.int_type.to_ref()); }
789         B(cx).ptrdiff(lhs, rhs)
790     }
791 }
792
793 pub fn Trap(cx: &Block) {
794     if cx.unreachable.get() { return; }
795     B(cx).trap();
796 }
797
798 pub fn LandingPad(cx: &Block, ty: Type, pers_fn: ValueRef,
799                   num_clauses: uint) -> ValueRef {
800     check_not_terminated(cx);
801     assert!(!cx.unreachable.get());
802     B(cx).landing_pad(ty, pers_fn, num_clauses)
803 }
804
805 pub fn SetCleanup(cx: &Block, landing_pad: ValueRef) {
806     B(cx).set_cleanup(landing_pad)
807 }
808
809 pub fn Resume(cx: &Block, exn: ValueRef) -> ValueRef {
810     check_not_terminated(cx);
811     terminate(cx, "Resume");
812     B(cx).resume(exn)
813 }
814
815 // Atomic Operations
816 pub fn AtomicCmpXchg(cx: &Block, dst: ValueRef,
817                      cmp: ValueRef, src: ValueRef,
818                      order: AtomicOrdering,
819                      failure_order: AtomicOrdering) -> ValueRef {
820     B(cx).atomic_cmpxchg(dst, cmp, src, order, failure_order)
821 }
822 pub fn AtomicRMW(cx: &Block, op: AtomicBinOp,
823                  dst: ValueRef, src: ValueRef,
824                  order: AtomicOrdering) -> ValueRef {
825     B(cx).atomic_rmw(op, dst, src, order)
826 }