]> git.lizzy.rs Git - rust.git/blob - src/librustc_codegen_ssa/common.rs
8c53129abc315ebd601030ef0f2227dce2ca7937
[rust.git] / src / librustc_codegen_ssa / common.rs
1 // Copyright 2018 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 #![allow(non_camel_case_types, non_snake_case)]
11
12 use rustc::ty::{self, Ty, TyCtxt};
13 use syntax_pos::{DUMMY_SP, Span};
14
15 use rustc::hir::def_id::DefId;
16 use rustc::middle::lang_items::LangItem;
17 use base;
18 use traits::*;
19
20 use rustc::hir;
21 use traits::BuilderMethods;
22
23 pub fn type_needs_drop<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty: Ty<'tcx>) -> bool {
24     ty.needs_drop(tcx, ty::ParamEnv::reveal_all())
25 }
26
27 pub fn type_is_sized<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty: Ty<'tcx>) -> bool {
28     ty.is_sized(tcx.at(DUMMY_SP), ty::ParamEnv::reveal_all())
29 }
30
31 pub fn type_is_freeze<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty: Ty<'tcx>) -> bool {
32     ty.is_freeze(tcx, ty::ParamEnv::reveal_all(), DUMMY_SP)
33 }
34
35 pub enum IntPredicate {
36     IntEQ,
37     IntNE,
38     IntUGT,
39     IntUGE,
40     IntULT,
41     IntULE,
42     IntSGT,
43     IntSGE,
44     IntSLT,
45     IntSLE
46 }
47
48
49 #[allow(dead_code)]
50 pub enum RealPredicate {
51     RealPredicateFalse,
52     RealOEQ,
53     RealOGT,
54     RealOGE,
55     RealOLT,
56     RealOLE,
57     RealONE,
58     RealORD,
59     RealUNO,
60     RealUEQ,
61     RealUGT,
62     RealUGE,
63     RealULT,
64     RealULE,
65     RealUNE,
66     RealPredicateTrue
67 }
68
69 pub enum AtomicRmwBinOp {
70     AtomicXchg,
71     AtomicAdd,
72     AtomicSub,
73     AtomicAnd,
74     AtomicNand,
75     AtomicOr,
76     AtomicXor,
77     AtomicMax,
78     AtomicMin,
79     AtomicUMax,
80     AtomicUMin
81 }
82
83 pub enum AtomicOrdering {
84     #[allow(dead_code)]
85     NotAtomic,
86     Unordered,
87     Monotonic,
88     // Consume,  // Not specified yet.
89     Acquire,
90     Release,
91     AcquireRelease,
92     SequentiallyConsistent,
93 }
94
95 pub enum SynchronizationScope {
96     // FIXME: figure out if this variant is needed at all.
97     #[allow(dead_code)]
98     Other,
99     SingleThread,
100     CrossThread,
101 }
102
103 #[derive(Copy, Clone, PartialEq, Debug)]
104 pub enum TypeKind {
105     Void,
106     Half,
107     Float,
108     Double,
109     X86_FP80,
110     FP128,
111     PPC_FP128,
112     Label,
113     Integer,
114     Function,
115     Struct,
116     Array,
117     Pointer,
118     Vector,
119     Metadata,
120     X86_MMX,
121     Token,
122 }
123
124 // FIXME(mw): Anything that is produced via DepGraph::with_task() must implement
125 //            the HashStable trait. Normally DepGraph::with_task() calls are
126 //            hidden behind queries, but CGU creation is a special case in two
127 //            ways: (1) it's not a query and (2) CGU are output nodes, so their
128 //            Fingerprints are not actually needed. It remains to be clarified
129 //            how exactly this case will be handled in the red/green system but
130 //            for now we content ourselves with providing a no-op HashStable
131 //            implementation for CGUs.
132 mod temp_stable_hash_impls {
133     use rustc_data_structures::stable_hasher::{StableHasherResult, StableHasher,
134                                                HashStable};
135     use ModuleCodegen;
136
137     impl<HCX, M> HashStable<HCX> for ModuleCodegen<M> {
138         fn hash_stable<W: StableHasherResult>(&self,
139                                               _: &mut HCX,
140                                               _: &mut StableHasher<W>) {
141             // do nothing
142         }
143     }
144 }
145
146 pub fn langcall(tcx: TyCtxt,
147                 span: Option<Span>,
148                 msg: &str,
149                 li: LangItem)
150                 -> DefId {
151     tcx.lang_items().require(li).unwrap_or_else(|s| {
152         let msg = format!("{} {}", msg, s);
153         match span {
154             Some(span) => tcx.sess.span_fatal(span, &msg[..]),
155             None => tcx.sess.fatal(&msg[..]),
156         }
157     })
158 }
159
160 // To avoid UB from LLVM, these two functions mask RHS with an
161 // appropriate mask unconditionally (i.e. the fallback behavior for
162 // all shifts). For 32- and 64-bit types, this matches the semantics
163 // of Java. (See related discussion on #1877 and #10183.)
164
165 pub fn build_unchecked_lshift<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>(
166     bx: &mut Bx,
167     lhs: Bx::Value,
168     rhs: Bx::Value
169 ) -> Bx::Value {
170     let rhs = base::cast_shift_expr_rhs(bx, hir::BinOpKind::Shl, lhs, rhs);
171     // #1877, #10183: Ensure that input is always valid
172     let rhs = shift_mask_rhs(bx, rhs);
173     bx.shl(lhs, rhs)
174 }
175
176 pub fn build_unchecked_rshift<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>(
177     bx: &mut Bx,
178     lhs_t: Ty<'tcx>,
179     lhs: Bx::Value,
180     rhs: Bx::Value
181 ) -> Bx::Value {
182     let rhs = base::cast_shift_expr_rhs(bx, hir::BinOpKind::Shr, lhs, rhs);
183     // #1877, #10183: Ensure that input is always valid
184     let rhs = shift_mask_rhs(bx, rhs);
185     let is_signed = lhs_t.is_signed();
186     if is_signed {
187         bx.ashr(lhs, rhs)
188     } else {
189         bx.lshr(lhs, rhs)
190     }
191 }
192
193 fn shift_mask_rhs<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>(
194     bx: &mut Bx,
195     rhs: Bx::Value
196 ) -> Bx::Value {
197     let rhs_llty = bx.val_ty(rhs);
198     let shift_val = shift_mask_val(bx, rhs_llty, rhs_llty, false);
199     bx.and(rhs, shift_val)
200 }
201
202 pub fn shift_mask_val<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>(
203     bx: &mut Bx,
204     llty: Bx::Type,
205     mask_llty: Bx::Type,
206     invert: bool
207 ) -> Bx::Value {
208     let kind = bx.type_kind(llty);
209     match kind {
210         TypeKind::Integer => {
211             // i8/u8 can shift by at most 7, i16/u16 by at most 15, etc.
212             let val = bx.int_width(llty) - 1;
213             if invert {
214                 bx.const_int(mask_llty, !val as i64)
215             } else {
216                 bx.const_uint(mask_llty, val)
217             }
218         },
219         TypeKind::Vector => {
220             let mask = shift_mask_val(
221                 bx,
222                 bx.element_type(llty),
223                 bx.element_type(mask_llty),
224                 invert
225             );
226             bx.vector_splat(bx.vector_length(mask_llty), mask)
227         },
228         _ => bug!("shift_mask_val: expected Integer or Vector, found {:?}", kind),
229     }
230 }