]> git.proxmox.com Git - rustc.git/blame - src/librustc_trans/declare.rs
New upstream version 1.20.0+dfsg1
[rustc.git] / src / librustc_trans / declare.rs
CommitLineData
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 23use llvm::{self, ValueRef};
5bcae85e 24use llvm::AttributePlace::Function;
54a0048b 25use rustc::ty;
8bb4bdeb 26use rustc::session::config::Sanitizer;
54a0048b
SL
27use abi::{Abi, FnType};
28use attributes;
29use context::CrateContext;
476ff2be 30use common;
54a0048b
SL
31use type_::Type;
32use value::Value;
33
34use 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.
41pub 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.
56fn 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.
112pub 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.
121pub 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).
152pub 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
165pub 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.
180pub 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.
190pub 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.
207pub 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}