]>
Commit | Line | Data |
---|---|---|
54a0048b SL |
1 | // Copyright 2012-2015 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 | //! Declare various LLVM values. | |
11 | //! | |
12 | //! Prefer using functions and methods from this module rather than calling LLVM | |
13 | //! functions directly. These functions do some additional work to ensure we do | |
14 | //! the right thing given the preconceptions of trans. | |
15 | //! | |
16 | //! Some useful guidelines: | |
17 | //! | |
18 | //! * Use declare_* family of methods if you are declaring, but are not | |
19 | //! interested in defining the ValueRef they return. | |
20 | //! * Use define_* family of methods when you might be defining the ValueRef. | |
21 | //! * When in doubt, define. | |
476ff2be | 22 | |
54a0048b | 23 | use llvm::{self, ValueRef}; |
5bcae85e | 24 | use llvm::AttributePlace::Function; |
54a0048b | 25 | use rustc::ty; |
8bb4bdeb | 26 | use rustc::session::config::Sanitizer; |
54a0048b SL |
27 | use abi::{Abi, FnType}; |
28 | use attributes; | |
29 | use context::CrateContext; | |
476ff2be | 30 | use common; |
54a0048b SL |
31 | use type_::Type; |
32 | use value::Value; | |
33 | ||
34 | use std::ffi::CString; | |
35 | ||
36 | ||
37 | /// Declare a global value. | |
38 | /// | |
39 | /// If there’s a value with the same name already declared, the function will | |
40 | /// return its ValueRef instead. | |
41 | pub fn declare_global(ccx: &CrateContext, name: &str, ty: Type) -> llvm::ValueRef { | |
42 | debug!("declare_global(name={:?})", name); | |
43 | let namebuf = CString::new(name).unwrap_or_else(|_|{ | |
44 | bug!("name {:?} contains an interior null byte", name) | |
45 | }); | |
46 | unsafe { | |
5bcae85e | 47 | llvm::LLVMRustGetOrInsertGlobal(ccx.llmod(), namebuf.as_ptr(), ty.to_ref()) |
54a0048b SL |
48 | } |
49 | } | |
50 | ||
51 | ||
52 | /// Declare a function. | |
53 | /// | |
54 | /// If there’s a value with the same name already declared, the function will | |
55 | /// update the declaration and return existing ValueRef instead. | |
56 | fn declare_raw_fn(ccx: &CrateContext, name: &str, callconv: llvm::CallConv, ty: Type) -> ValueRef { | |
57 | debug!("declare_raw_fn(name={:?}, ty={:?})", name, ty); | |
58 | let namebuf = CString::new(name).unwrap_or_else(|_|{ | |
59 | bug!("name {:?} contains an interior null byte", name) | |
60 | }); | |
61 | let llfn = unsafe { | |
5bcae85e | 62 | llvm::LLVMRustGetOrInsertFunction(ccx.llmod(), namebuf.as_ptr(), ty.to_ref()) |
54a0048b SL |
63 | }; |
64 | ||
65 | llvm::SetFunctionCallConv(llfn, callconv); | |
66 | // Function addresses in Rust are never significant, allowing functions to | |
67 | // be merged. | |
68 | llvm::SetUnnamedAddr(llfn, true); | |
69 | ||
70 | if ccx.tcx().sess.opts.cg.no_redzone | |
71 | .unwrap_or(ccx.tcx().sess.target.target.options.disable_redzone) { | |
5bcae85e | 72 | llvm::Attribute::NoRedZone.apply_llfn(Function, llfn); |
54a0048b SL |
73 | } |
74 | ||
8bb4bdeb XL |
75 | if let Some(ref sanitizer) = ccx.tcx().sess.opts.debugging_opts.sanitizer { |
76 | match *sanitizer { | |
77 | Sanitizer::Address => { | |
78 | llvm::Attribute::SanitizeAddress.apply_llfn(Function, llfn); | |
79 | }, | |
80 | Sanitizer::Memory => { | |
81 | llvm::Attribute::SanitizeMemory.apply_llfn(Function, llfn); | |
82 | }, | |
83 | Sanitizer::Thread => { | |
84 | llvm::Attribute::SanitizeThread.apply_llfn(Function, llfn); | |
85 | }, | |
86 | _ => {} | |
87 | } | |
88 | } | |
89 | ||
a7813a04 XL |
90 | match ccx.tcx().sess.opts.cg.opt_level.as_ref().map(String::as_ref) { |
91 | Some("s") => { | |
5bcae85e | 92 | llvm::Attribute::OptimizeForSize.apply_llfn(Function, llfn); |
a7813a04 XL |
93 | }, |
94 | Some("z") => { | |
5bcae85e SL |
95 | llvm::Attribute::MinSize.apply_llfn(Function, llfn); |
96 | llvm::Attribute::OptimizeForSize.apply_llfn(Function, llfn); | |
a7813a04 XL |
97 | }, |
98 | _ => {}, | |
99 | } | |
100 | ||
54a0048b SL |
101 | llfn |
102 | } | |
103 | ||
104 | ||
105 | /// Declare a C ABI function. | |
106 | /// | |
107 | /// Only use this for foreign function ABIs and glue. For Rust functions use | |
108 | /// `declare_fn` instead. | |
109 | /// | |
110 | /// If there’s a value with the same name already declared, the function will | |
111 | /// update the declaration and return existing ValueRef instead. | |
112 | pub fn declare_cfn(ccx: &CrateContext, name: &str, fn_type: Type) -> ValueRef { | |
113 | declare_raw_fn(ccx, name, llvm::CCallConv, fn_type) | |
114 | } | |
115 | ||
116 | ||
117 | /// Declare a Rust function. | |
118 | /// | |
119 | /// If there’s a value with the same name already declared, the function will | |
120 | /// update the declaration and return existing ValueRef instead. | |
121 | pub fn declare_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, name: &str, | |
122 | fn_type: ty::Ty<'tcx>) -> ValueRef { | |
123 | debug!("declare_rust_fn(name={:?}, fn_type={:?})", name, fn_type); | |
8bb4bdeb XL |
124 | let sig = common::ty_fn_sig(ccx, fn_type); |
125 | let sig = ccx.tcx().erase_late_bound_regions_and_normalize(&sig); | |
54a0048b SL |
126 | debug!("declare_rust_fn (after region erasure) sig={:?}", sig); |
127 | ||
8bb4bdeb | 128 | let fty = FnType::new(ccx, sig, &[]); |
54a0048b SL |
129 | let llfn = declare_raw_fn(ccx, name, fty.cconv, fty.llvm_type(ccx)); |
130 | ||
5bcae85e | 131 | // FIXME(canndrew): This is_never should really be an is_uninhabited |
476ff2be | 132 | if sig.output().is_never() { |
5bcae85e | 133 | llvm::Attribute::NoReturn.apply_llfn(Function, llfn); |
54a0048b SL |
134 | } |
135 | ||
8bb4bdeb | 136 | if sig.abi != Abi::Rust && sig.abi != Abi::RustCall { |
54a0048b SL |
137 | attributes::unwind(llfn, false); |
138 | } | |
139 | ||
140 | fty.apply_attrs_llfn(llfn); | |
141 | ||
142 | llfn | |
143 | } | |
144 | ||
145 | ||
146 | /// Declare a global with an intention to define it. | |
147 | /// | |
148 | /// Use this function when you intend to define a global. This function will | |
149 | /// return None if the name already has a definition associated with it. In that | |
150 | /// case an error should be reported to the user, because it usually happens due | |
151 | /// to user’s fault (e.g. misuse of #[no_mangle] or #[export_name] attributes). | |
152 | pub fn define_global(ccx: &CrateContext, name: &str, ty: Type) -> Option<ValueRef> { | |
153 | if get_defined_value(ccx, name).is_some() { | |
154 | None | |
155 | } else { | |
156 | Some(declare_global(ccx, name, ty)) | |
157 | } | |
158 | } | |
159 | ||
54a0048b SL |
160 | /// Declare a Rust function with an intention to define it. |
161 | /// | |
162 | /// Use this function when you intend to define a function. This function will | |
163 | /// return panic if the name already has a definition associated with it. This | |
164 | /// can happen with #[no_mangle] or #[export_name], for example. | |
5bcae85e SL |
165 | pub fn define_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, |
166 | name: &str, | |
167 | fn_type: ty::Ty<'tcx>) -> ValueRef { | |
54a0048b SL |
168 | if get_defined_value(ccx, name).is_some() { |
169 | ccx.sess().fatal(&format!("symbol `{}` already defined", name)) | |
170 | } else { | |
5bcae85e | 171 | declare_fn(ccx, name, fn_type) |
54a0048b SL |
172 | } |
173 | } | |
174 | ||
5bcae85e SL |
175 | /// Declare a Rust function with an intention to define it. |
176 | /// | |
177 | /// Use this function when you intend to define a function. This function will | |
178 | /// return panic if the name already has a definition associated with it. This | |
179 | /// can happen with #[no_mangle] or #[export_name], for example. | |
180 | pub fn define_internal_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, | |
181 | name: &str, | |
182 | fn_type: ty::Ty<'tcx>) -> ValueRef { | |
183 | let llfn = define_fn(ccx, name, fn_type); | |
9e0c209e | 184 | unsafe { llvm::LLVMRustSetLinkage(llfn, llvm::Linkage::InternalLinkage) }; |
5bcae85e SL |
185 | llfn |
186 | } | |
187 | ||
54a0048b SL |
188 | |
189 | /// Get declared value by name. | |
190 | pub fn get_declared_value(ccx: &CrateContext, name: &str) -> Option<ValueRef> { | |
191 | debug!("get_declared_value(name={:?})", name); | |
192 | let namebuf = CString::new(name).unwrap_or_else(|_|{ | |
193 | bug!("name {:?} contains an interior null byte", name) | |
194 | }); | |
5bcae85e | 195 | let val = unsafe { llvm::LLVMRustGetNamedValue(ccx.llmod(), namebuf.as_ptr()) }; |
54a0048b SL |
196 | if val.is_null() { |
197 | debug!("get_declared_value: {:?} value is null", name); | |
198 | None | |
199 | } else { | |
200 | debug!("get_declared_value: {:?} => {:?}", name, Value(val)); | |
201 | Some(val) | |
202 | } | |
203 | } | |
204 | ||
205 | /// Get defined or externally defined (AvailableExternally linkage) value by | |
206 | /// name. | |
207 | pub fn get_defined_value(ccx: &CrateContext, name: &str) -> Option<ValueRef> { | |
208 | get_declared_value(ccx, name).and_then(|val|{ | |
209 | let declaration = unsafe { | |
210 | llvm::LLVMIsDeclaration(val) != 0 | |
211 | }; | |
212 | if !declaration { | |
213 | Some(val) | |
214 | } else { | |
215 | None | |
216 | } | |
217 | }) | |
218 | } |