1 #![allow(non_camel_case_types, non_snake_case)]
3 //! Code that is useful in various codegen modules.
5 use crate::llvm
::{self, True, False, Bool, BasicBlock, OperandBundleDef}
;
8 use crate::type_
::Type
;
9 use crate::type_of
::LayoutLlvmExt
;
10 use crate::value
::Value
;
11 use rustc_codegen_ssa
::traits
::*;
13 use crate::consts
::const_alloc_to_llvm
;
14 use rustc
::ty
::layout
::{HasDataLayout, LayoutOf, self, TyLayout, Size}
;
15 use rustc
::mir
::interpret
::{Scalar, AllocKind, Allocation}
;
16 use rustc_codegen_ssa
::mir
::place
::PlaceRef
;
18 use libc
::{c_uint, c_char}
;
20 use syntax
::symbol
::LocalInternedString
;
21 use syntax
::ast
::Mutability
;
23 pub use crate::context
::CodegenCx
;
26 * A note on nomenclature of linking: "extern", "foreign", and "upcall".
28 * An "extern" is an LLVM symbol we wind up emitting an undefined external
29 * reference to. This means "we don't have the thing in this compilation unit,
30 * please make sure you link it in at runtime". This could be a reference to
31 * C code found in a C library, or rust code found in a rust crate.
33 * Most "externs" are implicitly declared (automatically) as a result of a
34 * user declaring an extern _module_ dependency; this causes the rust driver
35 * to locate an extern crate, scan its compilation metadata, and emit extern
36 * declarations for any symbols used by the declaring crate.
38 * A "foreign" is an extern that references C (or other non-rust ABI) code.
39 * There is no metadata to scan for extern references so in these cases either
40 * a header-digester like bindgen, or manual function prototypes, have to
41 * serve as declarators. So these are usually given explicitly as prototype
42 * declarations, in rust code, with ABI attributes on them noting which ABI to
45 * An "upcall" is a foreign call generated by the compiler (not corresponding
46 * to any user-written call in the code) into the runtime library, to perform
47 * some helper task such as bringing a task to life, allocating memory, etc.
51 /// A structure representing an active landing pad for the duration of a basic
54 /// Each `Block` may contain an instance of this, indicating whether the block
55 /// is part of a landing pad or not. This is used to make decision about whether
56 /// to emit `invoke` instructions (e.g., in a landing pad we don't continue to
57 /// use `invoke`) and also about various function call metadata.
59 /// For GNU exceptions (`landingpad` + `resume` instructions) this structure is
60 /// just a bunch of `None` instances (not too interesting), but for MSVC
61 /// exceptions (`cleanuppad` + `cleanupret` instructions) this contains data.
62 /// When inside of a landing pad, each function call in LLVM IR needs to be
63 /// annotated with which landing pad it's a part of. This is accomplished via
64 /// the `OperandBundleDef` value created for MSVC landing pads.
65 pub struct Funclet
<'ll
> {
66 cleanuppad
: &'ll Value
,
67 operand
: OperandBundleDef
<'ll
>,
71 pub fn new(cleanuppad
: &'ll Value
) -> Self {
74 operand
: OperandBundleDef
::new("funclet", &[cleanuppad
]),
78 pub fn cleanuppad(&self) -> &'ll Value
{
82 pub fn bundle(&self) -> &OperandBundleDef
<'ll
> {
87 impl BackendTypes
for CodegenCx
<'ll
, 'tcx
> {
88 type Value
= &'ll Value
;
89 type BasicBlock
= &'ll BasicBlock
;
90 type Type
= &'ll Type
;
91 type Funclet
= Funclet
<'ll
>;
93 type DIScope
= &'ll llvm
::debuginfo
::DIScope
;
96 impl ConstMethods
<'tcx
> for CodegenCx
<'ll
, 'tcx
> {
97 fn const_null(&self, t
: &'ll Type
) -> &'ll Value
{
99 llvm
::LLVMConstNull(t
)
103 fn const_undef(&self, t
: &'ll Type
) -> &'ll Value
{
105 llvm
::LLVMGetUndef(t
)
109 fn const_int(&self, t
: &'ll Type
, i
: i64) -> &'ll Value
{
111 llvm
::LLVMConstInt(t
, i
as u64, True
)
115 fn const_uint(&self, t
: &'ll Type
, i
: u64) -> &'ll Value
{
117 llvm
::LLVMConstInt(t
, i
, False
)
121 fn const_uint_big(&self, t
: &'ll Type
, u
: u128
) -> &'ll Value
{
123 let words
= [u
as u64, (u
>> 64) as u64];
124 llvm
::LLVMConstIntOfArbitraryPrecision(t
, 2, words
.as_ptr())
128 fn const_bool(&self, val
: bool
) -> &'ll Value
{
129 self.const_uint(self.type_i1(), val
as u64)
132 fn const_i32(&self, i
: i32) -> &'ll Value
{
133 self.const_int(self.type_i32(), i
as i64)
136 fn const_u32(&self, i
: u32) -> &'ll Value
{
137 self.const_uint(self.type_i32(), i
as u64)
140 fn const_u64(&self, i
: u64) -> &'ll Value
{
141 self.const_uint(self.type_i64(), i
)
144 fn const_usize(&self, i
: u64) -> &'ll Value
{
145 let bit_size
= self.data_layout().pointer_size
.bits();
147 // make sure it doesn't overflow
148 assert
!(i
< (1<<bit_size
));
151 self.const_uint(self.isize_ty
, i
)
154 fn const_u8(&self, i
: u8) -> &'ll Value
{
155 self.const_uint(self.type_i8(), i
as u64)
160 s
: LocalInternedString
,
161 null_terminated
: bool
,
164 if let Some(&llval
) = self.const_cstr_cache
.borrow().get(&s
) {
168 let sc
= llvm
::LLVMConstStringInContext(self.llcx
,
169 s
.as_ptr() as *const c_char
,
171 !null_terminated
as Bool
);
172 let sym
= self.generate_local_symbol_name("str");
173 let g
= self.define_global(&sym
[..], self.val_ty(sc
)).unwrap_or_else(||{
174 bug
!("symbol `{}` is already defined", sym
);
176 llvm
::LLVMSetInitializer(g
, sc
);
177 llvm
::LLVMSetGlobalConstant(g
, True
);
178 llvm
::LLVMRustSetLinkage(g
, llvm
::Linkage
::InternalLinkage
);
180 self.const_cstr_cache
.borrow_mut().insert(s
, g
);
185 fn const_str_slice(&self, s
: LocalInternedString
) -> &'ll Value
{
187 let cs
= consts
::ptrcast(self.const_cstr(s
, false),
188 self.type_ptr_to(self.layout_of(self.tcx
.mk_str()).llvm_type(self)));
189 self.const_fat_ptr(cs
, self.const_usize(len
as u64))
197 assert_eq
!(abi
::FAT_PTR_ADDR
, 0);
198 assert_eq
!(abi
::FAT_PTR_EXTRA
, 1);
199 self.const_struct(&[ptr
, meta
], false)
207 struct_in_context(self.llcx
, elts
, packed
)
210 fn const_array(&self, ty
: &'ll Type
, elts
: &[&'ll Value
]) -> &'ll Value
{
212 return llvm
::LLVMConstArray(ty
, elts
.as_ptr(), elts
.len() as c_uint
);
216 fn const_vector(&self, elts
: &[&'ll Value
]) -> &'ll Value
{
218 return llvm
::LLVMConstVector(elts
.as_ptr(), elts
.len() as c_uint
);
222 fn const_bytes(&self, bytes
: &[u8]) -> &'ll Value
{
223 bytes_in_context(self.llcx
, bytes
)
226 fn const_get_elt(&self, v
: &'ll Value
, idx
: u64) -> &'ll Value
{
228 assert_eq
!(idx
as c_uint
as u64, idx
);
229 let us
= &[idx
as c_uint
];
230 let r
= llvm
::LLVMConstExtractValue(v
, us
.as_ptr(), us
.len() as c_uint
);
232 debug
!("const_get_elt(v={:?}, idx={}, r={:?})",
239 fn const_get_real(&self, v
: &'ll Value
) -> Option
<(f64, bool
)> {
241 if self.is_const_real(v
) {
242 let mut loses_info
: llvm
::Bool
= ::std
::mem
::uninitialized();
243 let r
= llvm
::LLVMConstRealGetDouble(v
, &mut loses_info
);
244 let loses_info
= if loses_info
== 1 { true }
else { false }
;
245 Some((r
, loses_info
))
252 fn const_to_uint(&self, v
: &'ll Value
) -> u64 {
254 llvm
::LLVMConstIntGetZExtValue(v
)
258 fn is_const_integral(&self, v
: &'ll Value
) -> bool
{
260 llvm
::LLVMIsAConstantInt(v
).is_some()
264 fn is_const_real(&self, v
: &'ll Value
) -> bool
{
266 llvm
::LLVMIsAConstantFP(v
).is_some()
270 fn const_to_opt_u128(&self, v
: &'ll Value
, sign_ext
: bool
) -> Option
<u128
> {
272 if self.is_const_integral(v
) {
273 let (mut lo
, mut hi
) = (0u64, 0u64);
274 let success
= llvm
::LLVMRustConstInt128Get(v
, sign_ext
,
277 Some(hi_lo_to_u128(lo
, hi
))
287 fn scalar_to_backend(
290 layout
: &layout
::Scalar
,
293 let bitsize
= if layout
.is_bool() { 1 }
else { layout.value.size(self).bits() }
;
295 Scalar
::Bits { size: 0, .. }
=> {
296 assert_eq
!(0, layout
.value
.size(self).bytes());
297 self.const_undef(self.type_ix(0))
299 Scalar
::Bits { bits, size }
=> {
300 assert_eq
!(size
as u64, layout
.value
.size(self).bytes());
301 let llval
= self.const_uint_big(self.type_ix(bitsize
), bits
);
302 if layout
.value
== layout
::Pointer
{
303 unsafe { llvm::LLVMConstIntToPtr(llval, llty) }
305 self.const_bitcast(llval
, llty
)
308 Scalar
::Ptr(ptr
) => {
309 let alloc_kind
= self.tcx
.alloc_map
.lock().get(ptr
.alloc_id
);
310 let base_addr
= match alloc_kind
{
311 Some(AllocKind
::Memory(alloc
)) => {
312 let init
= const_alloc_to_llvm(self, alloc
);
313 if alloc
.mutability
== Mutability
::Mutable
{
314 self.static_addr_of_mut(init
, alloc
.align
, None
)
316 self.static_addr_of(init
, alloc
.align
, None
)
319 Some(AllocKind
::Function(fn_instance
)) => {
320 self.get_fn(fn_instance
)
322 Some(AllocKind
::Static(def_id
)) => {
323 assert
!(self.tcx
.is_static(def_id
).is_some());
324 self.get_static(def_id
)
326 None
=> bug
!("missing allocation {:?}", ptr
.alloc_id
),
328 let llval
= unsafe { llvm
::LLVMConstInBoundsGEP(
329 self.const_bitcast(base_addr
, self.type_i8p()),
330 &self.const_usize(ptr
.offset
.bytes()),
333 if layout
.value
!= layout
::Pointer
{
334 unsafe { llvm::LLVMConstPtrToInt(llval, llty) }
336 self.const_bitcast(llval
, llty
)
344 layout
: TyLayout
<'tcx
>,
347 ) -> PlaceRef
<'tcx
, &'ll Value
> {
348 let init
= const_alloc_to_llvm(self, alloc
);
349 let base_addr
= self.static_addr_of(init
, layout
.align
.abi
, None
);
351 let llval
= unsafe { llvm
::LLVMConstInBoundsGEP(
352 self.const_bitcast(base_addr
, self.type_i8p()),
353 &self.const_usize(offset
.bytes()),
356 let llval
= self.const_bitcast(llval
, self.type_ptr_to(layout
.llvm_type(self)));
357 PlaceRef
::new_sized(llval
, layout
, alloc
.align
)
360 fn const_ptrcast(&self, val
: &'ll Value
, ty
: &'ll Type
) -> &'ll Value
{
361 consts
::ptrcast(val
, ty
)
365 pub fn val_ty(v
: &'ll Value
) -> &'ll Type
{
371 pub fn bytes_in_context(llcx
: &'ll llvm
::Context
, bytes
: &[u8]) -> &'ll Value
{
373 let ptr
= bytes
.as_ptr() as *const c_char
;
374 return llvm
::LLVMConstStringInContext(llcx
, ptr
, bytes
.len() as c_uint
, True
);
378 pub fn struct_in_context(
379 llcx
: &'a llvm
::Context
,
384 llvm
::LLVMConstStructInContext(llcx
,
385 elts
.as_ptr(), elts
.len() as c_uint
,
391 fn hi_lo_to_u128(lo
: u64, hi
: u64) -> u128
{
392 ((hi
as u128
) << 64) | (lo
as u128
)