1 //! Code that is useful in various codegen modules.
3 use crate::consts
::{self, const_alloc_to_llvm}
;
4 pub use crate::context
::CodegenCx
;
5 use crate::llvm
::{self, BasicBlock, Bool, ConstantInt, False, OperandBundleDef, True}
;
6 use crate::type_
::Type
;
7 use crate::type_of
::LayoutLlvmExt
;
8 use crate::value
::Value
;
10 use rustc_ast
::Mutability
;
11 use rustc_codegen_ssa
::mir
::place
::PlaceRef
;
12 use rustc_codegen_ssa
::traits
::*;
13 use rustc_middle
::bug
;
14 use rustc_middle
::mir
::interpret
::{Allocation, GlobalAlloc, Scalar}
;
15 use rustc_middle
::ty
::{layout::TyAndLayout, ScalarInt}
;
16 use rustc_span
::symbol
::Symbol
;
17 use rustc_target
::abi
::{self, AddressSpace, HasDataLayout, LayoutOf, Pointer, Size}
;
19 use libc
::{c_char, c_uint}
;
23 * A note on nomenclature of linking: "extern", "foreign", and "upcall".
25 * An "extern" is an LLVM symbol we wind up emitting an undefined external
26 * reference to. This means "we don't have the thing in this compilation unit,
27 * please make sure you link it in at runtime". This could be a reference to
28 * C code found in a C library, or rust code found in a rust crate.
30 * Most "externs" are implicitly declared (automatically) as a result of a
31 * user declaring an extern _module_ dependency; this causes the rust driver
32 * to locate an extern crate, scan its compilation metadata, and emit extern
33 * declarations for any symbols used by the declaring crate.
35 * A "foreign" is an extern that references C (or other non-rust ABI) code.
36 * There is no metadata to scan for extern references so in these cases either
37 * a header-digester like bindgen, or manual function prototypes, have to
38 * serve as declarators. So these are usually given explicitly as prototype
39 * declarations, in rust code, with ABI attributes on them noting which ABI to
42 * An "upcall" is a foreign call generated by the compiler (not corresponding
43 * to any user-written call in the code) into the runtime library, to perform
44 * some helper task such as bringing a task to life, allocating memory, etc.
48 /// A structure representing an active landing pad for the duration of a basic
51 /// Each `Block` may contain an instance of this, indicating whether the block
52 /// is part of a landing pad or not. This is used to make decision about whether
53 /// to emit `invoke` instructions (e.g., in a landing pad we don't continue to
54 /// use `invoke`) and also about various function call metadata.
56 /// For GNU exceptions (`landingpad` + `resume` instructions) this structure is
57 /// just a bunch of `None` instances (not too interesting), but for MSVC
58 /// exceptions (`cleanuppad` + `cleanupret` instructions) this contains data.
59 /// When inside of a landing pad, each function call in LLVM IR needs to be
60 /// annotated with which landing pad it's a part of. This is accomplished via
61 /// the `OperandBundleDef` value created for MSVC landing pads.
62 pub struct Funclet
<'ll
> {
63 cleanuppad
: &'ll Value
,
64 operand
: OperandBundleDef
<'ll
>,
68 pub fn new(cleanuppad
: &'ll Value
) -> Self {
69 Funclet { cleanuppad, operand: OperandBundleDef::new("funclet", &[cleanuppad]) }
72 pub fn cleanuppad(&self) -> &'ll Value
{
76 pub fn bundle(&self) -> &OperandBundleDef
<'ll
> {
81 impl BackendTypes
for CodegenCx
<'ll
, 'tcx
> {
82 type Value
= &'ll Value
;
83 // FIXME(eddyb) replace this with a `Function` "subclass" of `Value`.
84 type Function
= &'ll Value
;
86 type BasicBlock
= &'ll BasicBlock
;
87 type Type
= &'ll Type
;
88 type Funclet
= Funclet
<'ll
>;
90 type DIScope
= &'ll llvm
::debuginfo
::DIScope
;
91 type DILocation
= &'ll llvm
::debuginfo
::DILocation
;
92 type DIVariable
= &'ll llvm
::debuginfo
::DIVariable
;
95 impl CodegenCx
<'ll
, 'tcx
> {
96 pub fn const_array(&self, ty
: &'ll Type
, elts
: &[&'ll Value
]) -> &'ll Value
{
97 unsafe { llvm::LLVMConstArray(ty, elts.as_ptr(), elts.len() as c_uint) }
100 pub fn const_vector(&self, elts
: &[&'ll Value
]) -> &'ll Value
{
101 unsafe { llvm::LLVMConstVector(elts.as_ptr(), elts.len() as c_uint) }
104 pub fn const_bytes(&self, bytes
: &[u8]) -> &'ll Value
{
105 bytes_in_context(self.llcx
, bytes
)
108 fn const_cstr(&self, s
: Symbol
, null_terminated
: bool
) -> &'ll Value
{
110 if let Some(&llval
) = self.const_cstr_cache
.borrow().get(&s
) {
114 let s_str
= s
.as_str();
115 let sc
= llvm
::LLVMConstStringInContext(
117 s_str
.as_ptr() as *const c_char
,
118 s_str
.len() as c_uint
,
119 !null_terminated
as Bool
,
121 let sym
= self.generate_local_symbol_name("str");
122 let g
= self.define_global(&sym
[..], self.val_ty(sc
)).unwrap_or_else(|| {
123 bug
!("symbol `{}` is already defined", sym
);
125 llvm
::LLVMSetInitializer(g
, sc
);
126 llvm
::LLVMSetGlobalConstant(g
, True
);
127 llvm
::LLVMRustSetLinkage(g
, llvm
::Linkage
::InternalLinkage
);
129 self.const_cstr_cache
.borrow_mut().insert(s
, g
);
134 pub fn const_get_elt(&self, v
: &'ll Value
, idx
: u64) -> &'ll Value
{
136 assert_eq
!(idx
as c_uint
as u64, idx
);
137 let us
= &[idx
as c_uint
];
138 let r
= llvm
::LLVMConstExtractValue(v
, us
.as_ptr(), us
.len() as c_uint
);
140 debug
!("const_get_elt(v={:?}, idx={}, r={:?})", v
, idx
, r
);
147 impl ConstMethods
<'tcx
> for CodegenCx
<'ll
, 'tcx
> {
148 fn const_null(&self, t
: &'ll Type
) -> &'ll Value
{
149 unsafe { llvm::LLVMConstNull(t) }
152 fn const_undef(&self, t
: &'ll Type
) -> &'ll Value
{
153 unsafe { llvm::LLVMGetUndef(t) }
156 fn const_int(&self, t
: &'ll Type
, i
: i64) -> &'ll Value
{
157 unsafe { llvm::LLVMConstInt(t, i as u64, True) }
160 fn const_uint(&self, t
: &'ll Type
, i
: u64) -> &'ll Value
{
161 unsafe { llvm::LLVMConstInt(t, i, False) }
164 fn const_uint_big(&self, t
: &'ll Type
, u
: u128
) -> &'ll Value
{
166 let words
= [u
as u64, (u
>> 64) as u64];
167 llvm
::LLVMConstIntOfArbitraryPrecision(t
, 2, words
.as_ptr())
171 fn const_bool(&self, val
: bool
) -> &'ll Value
{
172 self.const_uint(self.type_i1(), val
as u64)
175 fn const_i32(&self, i
: i32) -> &'ll Value
{
176 self.const_int(self.type_i32(), i
as i64)
179 fn const_u32(&self, i
: u32) -> &'ll Value
{
180 self.const_uint(self.type_i32(), i
as u64)
183 fn const_u64(&self, i
: u64) -> &'ll Value
{
184 self.const_uint(self.type_i64(), i
)
187 fn const_usize(&self, i
: u64) -> &'ll Value
{
188 let bit_size
= self.data_layout().pointer_size
.bits();
190 // make sure it doesn't overflow
191 assert
!(i
< (1 << bit_size
));
194 self.const_uint(self.isize_ty
, i
)
197 fn const_u8(&self, i
: u8) -> &'ll Value
{
198 self.const_uint(self.type_i8(), i
as u64)
201 fn const_real(&self, t
: &'ll Type
, val
: f64) -> &'ll Value
{
202 unsafe { llvm::LLVMConstReal(t, val) }
205 fn const_str(&self, s
: Symbol
) -> (&'ll Value
, &'ll Value
) {
206 let len
= s
.as_str().len();
207 let cs
= consts
::ptrcast(
208 self.const_cstr(s
, false),
209 self.type_ptr_to(self.layout_of(self.tcx
.types
.str_
).llvm_type(self)),
211 (cs
, self.const_usize(len
as u64))
214 fn const_struct(&self, elts
: &[&'ll Value
], packed
: bool
) -> &'ll Value
{
215 struct_in_context(self.llcx
, elts
, packed
)
218 fn const_to_opt_uint(&self, v
: &'ll Value
) -> Option
<u64> {
219 try_as_const_integral(v
).map(|v
| unsafe { llvm::LLVMConstIntGetZExtValue(v) }
)
222 fn const_to_opt_u128(&self, v
: &'ll Value
, sign_ext
: bool
) -> Option
<u128
> {
223 try_as_const_integral(v
).and_then(|v
| unsafe {
224 let (mut lo
, mut hi
) = (0u64, 0u64);
225 let success
= llvm
::LLVMRustConstInt128Get(v
, sign_ext
, &mut hi
, &mut lo
);
226 success
.then_some(hi_lo_to_u128(lo
, hi
))
230 fn scalar_to_backend(&self, cv
: Scalar
, layout
: &abi
::Scalar
, llty
: &'ll Type
) -> &'ll Value
{
231 let bitsize
= if layout
.is_bool() { 1 }
else { layout.value.size(self).bits() }
;
233 Scalar
::Int(ScalarInt
::ZST
) => {
234 assert_eq
!(0, layout
.value
.size(self).bytes());
235 self.const_undef(self.type_ix(0))
237 Scalar
::Int(int
) => {
238 let data
= int
.assert_bits(layout
.value
.size(self));
239 let llval
= self.const_uint_big(self.type_ix(bitsize
), data
);
240 if layout
.value
== Pointer
{
241 unsafe { llvm::LLVMConstIntToPtr(llval, llty) }
243 self.const_bitcast(llval
, llty
)
246 Scalar
::Ptr(ptr
, _size
) => {
247 let (alloc_id
, offset
) = ptr
.into_parts();
248 let (base_addr
, base_addr_space
) = match self.tcx
.global_alloc(alloc_id
) {
249 GlobalAlloc
::Memory(alloc
) => {
250 let init
= const_alloc_to_llvm(self, alloc
);
251 let value
= match alloc
.mutability
{
252 Mutability
::Mut
=> self.static_addr_of_mut(init
, alloc
.align
, None
),
253 _
=> self.static_addr_of(init
, alloc
.align
, None
),
255 if !self.sess().fewer_names() {
256 llvm
::set_value_name(value
, format
!("{:?}", alloc_id
).as_bytes());
258 (value
, AddressSpace
::DATA
)
260 GlobalAlloc
::Function(fn_instance
) => (
261 self.get_fn_addr(fn_instance
.polymorphize(self.tcx
)),
262 self.data_layout().instruction_address_space
,
264 GlobalAlloc
::Static(def_id
) => {
265 assert
!(self.tcx
.is_static(def_id
));
266 assert
!(!self.tcx
.is_thread_local_static(def_id
));
267 (self.get_static(def_id
), AddressSpace
::DATA
)
271 llvm
::LLVMConstInBoundsGEP(
272 self.const_bitcast(base_addr
, self.type_i8p_ext(base_addr_space
)),
273 &self.const_usize(offset
.bytes()),
277 if layout
.value
!= Pointer
{
278 unsafe { llvm::LLVMConstPtrToInt(llval, llty) }
280 self.const_bitcast(llval
, llty
)
286 fn const_data_from_alloc(&self, alloc
: &Allocation
) -> Self::Value
{
287 const_alloc_to_llvm(self, alloc
)
292 layout
: TyAndLayout
<'tcx
>,
295 ) -> PlaceRef
<'tcx
, &'ll Value
> {
296 assert_eq
!(alloc
.align
, layout
.align
.abi
);
297 let llty
= self.type_ptr_to(layout
.llvm_type(self));
298 let llval
= if layout
.size
== Size
::ZERO
{
299 let llval
= self.const_usize(alloc
.align
.bytes());
300 unsafe { llvm::LLVMConstIntToPtr(llval, llty) }
302 let init
= const_alloc_to_llvm(self, alloc
);
303 let base_addr
= self.static_addr_of(init
, alloc
.align
, None
);
306 llvm
::LLVMConstInBoundsGEP(
307 self.const_bitcast(base_addr
, self.type_i8p()),
308 &self.const_usize(offset
.bytes()),
312 self.const_bitcast(llval
, llty
)
314 PlaceRef
::new_sized(llval
, layout
)
317 fn const_ptrcast(&self, val
: &'ll Value
, ty
: &'ll Type
) -> &'ll Value
{
318 consts
::ptrcast(val
, ty
)
322 /// Get the [LLVM type][Type] of a [`Value`].
323 pub fn val_ty(v
: &Value
) -> &Type
{
324 unsafe { llvm::LLVMTypeOf(v) }
327 pub fn bytes_in_context(llcx
: &'ll llvm
::Context
, bytes
: &[u8]) -> &'ll Value
{
329 let ptr
= bytes
.as_ptr() as *const c_char
;
330 llvm
::LLVMConstStringInContext(llcx
, ptr
, bytes
.len() as c_uint
, True
)
334 pub fn struct_in_context(llcx
: &'a llvm
::Context
, elts
: &[&'a Value
], packed
: bool
) -> &'a Value
{
336 llvm
::LLVMConstStructInContext(llcx
, elts
.as_ptr(), elts
.len() as c_uint
, packed
as Bool
)
341 fn hi_lo_to_u128(lo
: u64, hi
: u64) -> u128
{
342 ((hi
as u128
) << 64) | (lo
as u128
)
345 fn try_as_const_integral(v
: &Value
) -> Option
<&ConstantInt
> {
346 unsafe { llvm::LLVMIsAConstantInt(v) }