1 use std
::convert
::TryFrom
;
2 use std
::convert
::TryInto
;
5 use gccjit
::{Block, CType, RValue, Type, ToRValue}
;
6 use rustc_codegen_ssa
::mir
::place
::PlaceRef
;
7 use rustc_codegen_ssa
::traits
::{
14 use rustc_middle
::mir
::Mutability
;
15 use rustc_middle
::ty
::ScalarInt
;
16 use rustc_middle
::ty
::layout
::{TyAndLayout, LayoutOf}
;
17 use rustc_middle
::mir
::interpret
::{Allocation, GlobalAlloc, Scalar}
;
18 use rustc_span
::Symbol
;
19 use rustc_target
::abi
::{self, HasDataLayout, Pointer, Size}
;
21 use crate::consts
::const_alloc_to_gcc
;
22 use crate::context
::CodegenCx
;
23 use crate::type_of
::LayoutGccExt
;
25 impl<'gcc
, 'tcx
> CodegenCx
<'gcc
, 'tcx
> {
26 pub fn const_bytes(&self, bytes
: &[u8]) -> RValue
<'gcc
> {
27 bytes_in_context(self, bytes
)
30 fn const_cstr(&self, symbol
: Symbol
, _null_terminated
: bool
) -> LValue
<'gcc
> {
31 // TODO(antoyo): handle null_terminated.
32 if let Some(&value
) = self.const_cstr_cache
.borrow().get(&symbol
) {
36 let global
= self.global_string(&*symbol
.as_str());
38 self.const_cstr_cache
.borrow_mut().insert(symbol
, global
);
42 fn global_string(&self, string
: &str) -> LValue
<'gcc
> {
43 // TODO(antoyo): handle non-null-terminated strings.
44 let string
= self.context
.new_string_literal(&*string
);
45 let sym
= self.generate_local_symbol_name("str");
46 let global
= self.declare_private_global(&sym
, self.val_ty(string
));
47 global
.global_set_initializer_value(string
);
49 // TODO(antoyo): set linkage.
52 pub fn inttoptr(&self, block
: Block
<'gcc
>, value
: RValue
<'gcc
>, dest_ty
: Type
<'gcc
>) -> RValue
<'gcc
> {
53 let func
= block
.get_function();
54 let local
= func
.new_local(None
, value
.get_type(), "intLocal");
55 block
.add_assignment(None
, local
, value
);
56 let value_address
= local
.get_address(None
);
58 let ptr
= self.context
.new_cast(None
, value_address
, dest_ty
.make_pointer());
59 ptr
.dereference(None
).to_rvalue()
62 pub fn ptrtoint(&self, block
: Block
<'gcc
>, value
: RValue
<'gcc
>, dest_ty
: Type
<'gcc
>) -> RValue
<'gcc
> {
63 // TODO(antoyo): when libgccjit allow casting from pointer to int, remove this.
64 let func
= block
.get_function();
65 let local
= func
.new_local(None
, value
.get_type(), "ptrLocal");
66 block
.add_assignment(None
, local
, value
);
67 let ptr_address
= local
.get_address(None
);
69 let ptr
= self.context
.new_cast(None
, ptr_address
, dest_ty
.make_pointer());
70 ptr
.dereference(None
).to_rvalue()
74 pub fn bytes_in_context
<'gcc
, 'tcx
>(cx
: &CodegenCx
<'gcc
, 'tcx
>, bytes
: &[u8]) -> RValue
<'gcc
> {
75 let context
= &cx
.context
;
76 let byte_type
= context
.new_type
::<u8>();
77 let typ
= context
.new_array_type(None
, byte_type
, bytes
.len() as i32);
78 let elements
: Vec
<_
> =
80 .map(|&byte
| context
.new_rvalue_from_int(byte_type
, byte
as i32))
82 context
.new_rvalue_from_array(None
, typ
, &elements
)
85 pub fn type_is_pointer
<'gcc
>(typ
: Type
<'gcc
>) -> bool
{
86 typ
.get_pointee().is_some()
89 impl<'gcc
, 'tcx
> ConstMethods
<'tcx
> for CodegenCx
<'gcc
, 'tcx
> {
90 fn const_null(&self, typ
: Type
<'gcc
>) -> RValue
<'gcc
> {
91 if type_is_pointer(typ
) {
92 self.context
.new_null(typ
)
95 self.const_int(typ
, 0)
99 fn const_undef(&self, typ
: Type
<'gcc
>) -> RValue
<'gcc
> {
100 let local
= self.current_func
.borrow().expect("func")
101 .new_local(None
, typ
, "undefined");
102 if typ
.is_struct().is_some() {
103 // NOTE: hack to workaround a limitation of the rustc API: see comment on
104 // CodegenCx.structs_as_pointer
105 let pointer
= local
.get_address(None
);
106 self.structs_as_pointer
.borrow_mut().insert(pointer
);
114 fn const_int(&self, typ
: Type
<'gcc
>, int
: i64) -> RValue
<'gcc
> {
115 self.context
.new_rvalue_from_long(typ
, i64::try_from(int
).expect("i64::try_from"))
118 fn const_uint(&self, typ
: Type
<'gcc
>, int
: u64) -> RValue
<'gcc
> {
119 self.context
.new_rvalue_from_long(typ
, u64::try_from(int
).expect("u64::try_from") as i64)
122 fn const_uint_big(&self, typ
: Type
<'gcc
>, num
: u128
) -> RValue
<'gcc
> {
123 let num64
: Result
<i64, _
> = num
.try_into();
124 if let Ok(num
) = num64
{
125 // FIXME(antoyo): workaround for a bug where libgccjit is expecting a constant.
126 // The operations >> 64 and | low are making the normal case a non-constant.
127 return self.context
.new_rvalue_from_long(typ
, num
as i64);
131 // FIXME(antoyo): use a new function new_rvalue_from_unsigned_long()?
132 let low
= self.context
.new_rvalue_from_long(self.u64_type
, num
as u64 as i64);
133 let high
= self.context
.new_rvalue_from_long(typ
, (num
>> 64) as u64 as i64);
135 let sixty_four
= self.context
.new_rvalue_from_long(typ
, 64);
136 (high
<< sixty_four
) | self.context
.new_cast(None
, low
, typ
)
138 else if typ
.is_i128(self) {
139 let num
= self.context
.new_rvalue_from_long(self.u64_type
, num
as u64 as i64);
140 self.context
.new_cast(None
, num
, typ
)
143 self.context
.new_rvalue_from_long(typ
, num
as u64 as i64)
147 fn const_bool(&self, val
: bool
) -> RValue
<'gcc
> {
148 self.const_uint(self.type_i1(), val
as u64)
151 fn const_i32(&self, i
: i32) -> RValue
<'gcc
> {
152 self.const_int(self.type_i32(), i
as i64)
155 fn const_u32(&self, i
: u32) -> RValue
<'gcc
> {
156 self.const_uint(self.type_u32(), i
as u64)
159 fn const_u64(&self, i
: u64) -> RValue
<'gcc
> {
160 self.const_uint(self.type_u64(), i
)
163 fn const_usize(&self, i
: u64) -> RValue
<'gcc
> {
164 let bit_size
= self.data_layout().pointer_size
.bits();
166 // make sure it doesn't overflow
167 assert
!(i
< (1 << bit_size
));
170 self.const_uint(self.usize_type
, i
)
173 fn const_u8(&self, _i
: u8) -> RValue
<'gcc
> {
177 fn const_real(&self, _t
: Type
<'gcc
>, _val
: f64) -> RValue
<'gcc
> {
181 fn const_str(&self, s
: Symbol
) -> (RValue
<'gcc
>, RValue
<'gcc
>) {
182 let len
= s
.as_str().len();
183 let cs
= self.const_ptrcast(self.const_cstr(s
, false).get_address(None
),
184 self.type_ptr_to(self.layout_of(self.tcx
.types
.str_
).gcc_type(self, true)),
186 (cs
, self.const_usize(len
as u64))
189 fn const_struct(&self, values
: &[RValue
<'gcc
>], packed
: bool
) -> RValue
<'gcc
> {
190 let fields
: Vec
<_
> = values
.iter()
191 .map(|value
| value
.get_type())
193 // TODO(antoyo): cache the type? It's anonymous, so probably not.
194 let typ
= self.type_struct(&fields
, packed
);
195 let struct_type
= typ
.is_struct().expect("struct type");
196 self.context
.new_rvalue_from_struct(None
, struct_type
, values
)
199 fn const_to_opt_uint(&self, _v
: RValue
<'gcc
>) -> Option
<u64> {
204 fn const_to_opt_u128(&self, _v
: RValue
<'gcc
>, _sign_ext
: bool
) -> Option
<u128
> {
209 fn scalar_to_backend(&self, cv
: Scalar
, layout
: abi
::Scalar
, ty
: Type
<'gcc
>) -> RValue
<'gcc
> {
210 let bitsize
= if layout
.is_bool() { 1 }
else { layout.value.size(self).bits() }
;
212 Scalar
::Int(ScalarInt
::ZST
) => {
213 assert_eq
!(0, layout
.value
.size(self).bytes());
214 self.const_undef(self.type_ix(0))
216 Scalar
::Int(int
) => {
217 let data
= int
.assert_bits(layout
.value
.size(self));
219 // FIXME(antoyo): there's some issues with using the u128 code that follows, so hard-code
220 // the paths for floating-point values.
221 if ty
== self.float_type
{
222 return self.context
.new_rvalue_from_double(ty
, f32::from_bits(data
as u32) as f64);
224 else if ty
== self.double_type
{
225 return self.context
.new_rvalue_from_double(ty
, f64::from_bits(data
as u64));
228 let value
= self.const_uint_big(self.type_ix(bitsize
), data
);
229 if layout
.value
== Pointer
{
230 self.inttoptr(self.current_block
.borrow().expect("block"), value
, ty
)
232 self.const_bitcast(value
, ty
)
235 Scalar
::Ptr(ptr
, _size
) => {
236 let (alloc_id
, offset
) = ptr
.into_parts();
238 match self.tcx
.global_alloc(alloc_id
) {
239 GlobalAlloc
::Memory(alloc
) => {
240 let init
= const_alloc_to_gcc(self, alloc
);
242 match alloc
.mutability
{
243 Mutability
::Mut
=> self.static_addr_of_mut(init
, alloc
.align
, None
),
244 _
=> self.static_addr_of(init
, alloc
.align
, None
),
246 if !self.sess().fewer_names() {
247 // TODO(antoyo): set value name.
251 GlobalAlloc
::Function(fn_instance
) => {
252 self.get_fn_addr(fn_instance
)
254 GlobalAlloc
::Static(def_id
) => {
255 assert
!(self.tcx
.is_static(def_id
));
256 self.get_static(def_id
).get_address(None
)
259 let ptr_type
= base_addr
.get_type();
260 let base_addr
= self.const_bitcast(base_addr
, self.usize_type
);
261 let offset
= self.context
.new_rvalue_from_long(self.usize_type
, offset
.bytes() as i64);
262 let ptr
= self.const_bitcast(base_addr
+ offset
, ptr_type
);
263 if layout
.value
!= Pointer
{
264 self.const_bitcast(ptr
.dereference(None
).to_rvalue(), ty
)
267 self.const_bitcast(ptr
, ty
)
273 fn const_data_from_alloc(&self, alloc
: &Allocation
) -> Self::Value
{
274 const_alloc_to_gcc(self, alloc
)
277 fn from_const_alloc(&self, layout
: TyAndLayout
<'tcx
>, alloc
: &Allocation
, offset
: Size
) -> PlaceRef
<'tcx
, RValue
<'gcc
>> {
278 assert_eq
!(alloc
.align
, layout
.align
.abi
);
279 let ty
= self.type_ptr_to(layout
.gcc_type(self, true));
281 if layout
.size
== Size
::ZERO
{
282 let value
= self.const_usize(alloc
.align
.bytes());
283 self.context
.new_cast(None
, value
, ty
)
286 let init
= const_alloc_to_gcc(self, alloc
);
287 let base_addr
= self.static_addr_of(init
, alloc
.align
, None
);
289 let array
= self.const_bitcast(base_addr
, self.type_i8p());
290 let value
= self.context
.new_array_access(None
, array
, self.const_usize(offset
.bytes())).get_address(None
);
291 self.const_bitcast(value
, ty
)
293 PlaceRef
::new_sized(value
, layout
)
296 fn const_ptrcast(&self, val
: RValue
<'gcc
>, ty
: Type
<'gcc
>) -> RValue
<'gcc
> {
297 self.context
.new_cast(None
, val
, ty
)
301 pub trait SignType
<'gcc
, 'tcx
> {
302 fn is_signed(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
;
303 fn is_unsigned(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
;
304 fn to_signed(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> Type
<'gcc
>;
305 fn to_unsigned(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> Type
<'gcc
>;
308 impl<'gcc
, 'tcx
> SignType
<'gcc
, 'tcx
> for Type
<'gcc
> {
309 fn is_signed(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
{
310 self.is_i8(cx
) || self.is_i16(cx
) || self.is_i32(cx
) || self.is_i64(cx
) || self.is_i128(cx
)
313 fn is_unsigned(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
{
314 self.is_u8(cx
) || self.is_u16(cx
) || self.is_u32(cx
) || self.is_u64(cx
) || self.is_u128(cx
)
317 fn to_signed(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> Type
<'gcc
> {
321 else if self.is_u16(cx
) {
324 else if self.is_u32(cx
) {
327 else if self.is_u64(cx
) {
330 else if self.is_u128(cx
) {
338 fn to_unsigned(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> Type
<'gcc
> {
342 else if self.is_i16(cx
) {
345 else if self.is_i32(cx
) {
348 else if self.is_i64(cx
) {
351 else if self.is_i128(cx
) {
360 pub trait TypeReflection
<'gcc
, 'tcx
> {
361 fn is_uchar(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
;
362 fn is_ushort(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
;
363 fn is_uint(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
;
364 fn is_ulong(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
;
365 fn is_ulonglong(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
;
367 fn is_i8(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
;
368 fn is_u8(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
;
369 fn is_i16(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
;
370 fn is_u16(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
;
371 fn is_i32(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
;
372 fn is_u32(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
;
373 fn is_i64(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
;
374 fn is_u64(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
;
375 fn is_i128(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
;
376 fn is_u128(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
;
378 fn is_f32(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
;
379 fn is_f64(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
;
382 impl<'gcc
, 'tcx
> TypeReflection
<'gcc
, 'tcx
> for Type
<'gcc
> {
383 fn is_uchar(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
{
384 self.unqualified() == cx
.u8_type
387 fn is_ushort(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
{
388 self.unqualified() == cx
.u16_type
391 fn is_uint(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
{
392 self.unqualified() == cx
.uint_type
395 fn is_ulong(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
{
396 self.unqualified() == cx
.ulong_type
399 fn is_ulonglong(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
{
400 self.unqualified() == cx
.ulonglong_type
403 fn is_i8(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
{
404 self.unqualified() == cx
.i8_type
407 fn is_u8(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
{
408 self.unqualified() == cx
.u8_type
411 fn is_i16(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
{
412 self.unqualified() == cx
.i16_type
415 fn is_u16(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
{
416 self.unqualified() == cx
.u16_type
419 fn is_i32(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
{
420 self.unqualified() == cx
.i32_type
423 fn is_u32(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
{
424 self.unqualified() == cx
.u32_type
427 fn is_i64(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
{
428 self.unqualified() == cx
.i64_type
431 fn is_u64(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
{
432 self.unqualified() == cx
.u64_type
435 fn is_i128(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
{
436 self.unqualified() == cx
.context
.new_c_type(CType
::Int128t
)
439 fn is_u128(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
{
440 self.unqualified() == cx
.context
.new_c_type(CType
::UInt128t
)
443 fn is_f32(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
{
444 self.unqualified() == cx
.context
.new_type
::<f32>()
447 fn is_f64(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
{
448 self.unqualified() == cx
.context
.new_type
::<f64>()