2 use gccjit
::{RValue, Type, ToRValue}
;
3 use rustc_codegen_ssa
::mir
::place
::PlaceRef
;
4 use rustc_codegen_ssa
::traits
::{
11 use rustc_middle
::mir
::Mutability
;
12 use rustc_middle
::ty
::layout
::{TyAndLayout, LayoutOf}
;
13 use rustc_middle
::mir
::interpret
::{ConstAllocation, GlobalAlloc, Scalar}
;
14 use rustc_target
::abi
::{self, HasDataLayout, Pointer, Size}
;
16 use crate::consts
::const_alloc_to_gcc
;
17 use crate::context
::CodegenCx
;
18 use crate::type_of
::LayoutGccExt
;
20 impl<'gcc
, 'tcx
> CodegenCx
<'gcc
, 'tcx
> {
21 pub fn const_bytes(&self, bytes
: &[u8]) -> RValue
<'gcc
> {
22 bytes_in_context(self, bytes
)
25 fn global_string(&self, string
: &str) -> LValue
<'gcc
> {
26 // TODO(antoyo): handle non-null-terminated strings.
27 let string
= self.context
.new_string_literal(&*string
);
28 let sym
= self.generate_local_symbol_name("str");
29 let global
= self.declare_private_global(&sym
, self.val_ty(string
));
30 global
.global_set_initializer_rvalue(string
);
32 // TODO(antoyo): set linkage.
36 pub fn bytes_in_context
<'gcc
, 'tcx
>(cx
: &CodegenCx
<'gcc
, 'tcx
>, bytes
: &[u8]) -> RValue
<'gcc
> {
37 let context
= &cx
.context
;
38 let byte_type
= context
.new_type
::<u8>();
39 let typ
= context
.new_array_type(None
, byte_type
, bytes
.len() as i32);
40 let elements
: Vec
<_
> =
42 .map(|&byte
| context
.new_rvalue_from_int(byte_type
, byte
as i32))
44 context
.new_array_constructor(None
, typ
, &elements
)
47 pub fn type_is_pointer
<'gcc
>(typ
: Type
<'gcc
>) -> bool
{
48 typ
.get_pointee().is_some()
51 impl<'gcc
, 'tcx
> ConstMethods
<'tcx
> for CodegenCx
<'gcc
, 'tcx
> {
52 fn const_null(&self, typ
: Type
<'gcc
>) -> RValue
<'gcc
> {
53 if type_is_pointer(typ
) {
54 self.context
.new_null(typ
)
57 self.const_int(typ
, 0)
61 fn const_undef(&self, typ
: Type
<'gcc
>) -> RValue
<'gcc
> {
62 let local
= self.current_func
.borrow().expect("func")
63 .new_local(None
, typ
, "undefined");
64 if typ
.is_struct().is_some() {
65 // NOTE: hack to workaround a limitation of the rustc API: see comment on
66 // CodegenCx.structs_as_pointer
67 let pointer
= local
.get_address(None
);
68 self.structs_as_pointer
.borrow_mut().insert(pointer
);
76 fn const_int(&self, typ
: Type
<'gcc
>, int
: i64) -> RValue
<'gcc
> {
77 self.gcc_int(typ
, int
)
80 fn const_uint(&self, typ
: Type
<'gcc
>, int
: u64) -> RValue
<'gcc
> {
81 self.gcc_uint(typ
, int
)
84 fn const_uint_big(&self, typ
: Type
<'gcc
>, num
: u128
) -> RValue
<'gcc
> {
85 self.gcc_uint_big(typ
, num
)
88 fn const_bool(&self, val
: bool
) -> RValue
<'gcc
> {
89 self.const_uint(self.type_i1(), val
as u64)
92 fn const_i16(&self, i
: i16) -> RValue
<'gcc
> {
93 self.const_int(self.type_i16(), i
as i64)
96 fn const_i32(&self, i
: i32) -> RValue
<'gcc
> {
97 self.const_int(self.type_i32(), i
as i64)
100 fn const_u32(&self, i
: u32) -> RValue
<'gcc
> {
101 self.const_uint(self.type_u32(), i
as u64)
104 fn const_u64(&self, i
: u64) -> RValue
<'gcc
> {
105 self.const_uint(self.type_u64(), i
)
108 fn const_usize(&self, i
: u64) -> RValue
<'gcc
> {
109 let bit_size
= self.data_layout().pointer_size
.bits();
111 // make sure it doesn't overflow
112 assert
!(i
< (1 << bit_size
));
115 self.const_uint(self.usize_type
, i
)
118 fn const_u8(&self, _i
: u8) -> RValue
<'gcc
> {
122 fn const_real(&self, typ
: Type
<'gcc
>, val
: f64) -> RValue
<'gcc
> {
123 self.context
.new_rvalue_from_double(typ
, val
)
126 fn const_str(&self, s
: &str) -> (RValue
<'gcc
>, RValue
<'gcc
>) {
127 let str_global
= *self
132 .or_insert_with(|| (s
.to_owned(), self.global_string(s
)))
135 let cs
= self.const_ptrcast(str_global
.get_address(None
),
136 self.type_ptr_to(self.layout_of(self.tcx
.types
.str_
).gcc_type(self, true)),
138 (cs
, self.const_usize(len
as u64))
141 fn const_struct(&self, values
: &[RValue
<'gcc
>], packed
: bool
) -> RValue
<'gcc
> {
142 let fields
: Vec
<_
> = values
.iter()
143 .map(|value
| value
.get_type())
145 // TODO(antoyo): cache the type? It's anonymous, so probably not.
146 let typ
= self.type_struct(&fields
, packed
);
147 let struct_type
= typ
.is_struct().expect("struct type");
148 self.context
.new_struct_constructor(None
, struct_type
.as_type(), None
, values
)
151 fn const_to_opt_uint(&self, _v
: RValue
<'gcc
>) -> Option
<u64> {
156 fn const_to_opt_u128(&self, _v
: RValue
<'gcc
>, _sign_ext
: bool
) -> Option
<u128
> {
161 fn scalar_to_backend(&self, cv
: Scalar
, layout
: abi
::Scalar
, ty
: Type
<'gcc
>) -> RValue
<'gcc
> {
162 let bitsize
= if layout
.is_bool() { 1 }
else { layout.size(self).bits() }
;
164 Scalar
::Int(int
) => {
165 let data
= int
.assert_bits(layout
.size(self));
167 // FIXME(antoyo): there's some issues with using the u128 code that follows, so hard-code
168 // the paths for floating-point values.
169 if ty
== self.float_type
{
170 return self.context
.new_rvalue_from_double(ty
, f32::from_bits(data
as u32) as f64);
172 else if ty
== self.double_type
{
173 return self.context
.new_rvalue_from_double(ty
, f64::from_bits(data
as u64));
176 let value
= self.const_uint_big(self.type_ix(bitsize
), data
);
177 // TODO(bjorn3): assert size is correct
178 self.const_bitcast(value
, ty
)
180 Scalar
::Ptr(ptr
, _size
) => {
181 let (alloc_id
, offset
) = ptr
.into_parts();
183 match self.tcx
.global_alloc(alloc_id
) {
184 GlobalAlloc
::Memory(alloc
) => {
185 let init
= const_alloc_to_gcc(self, alloc
);
186 let alloc
= alloc
.inner();
188 match alloc
.mutability
{
189 Mutability
::Mut
=> self.static_addr_of_mut(init
, alloc
.align
, None
),
190 _
=> self.static_addr_of(init
, alloc
.align
, None
),
192 if !self.sess().fewer_names() {
193 // TODO(antoyo): set value name.
197 GlobalAlloc
::Function(fn_instance
) => {
198 self.get_fn_addr(fn_instance
)
200 GlobalAlloc
::VTable(ty
, trait_ref
) => {
201 let alloc
= self.tcx
.global_alloc(self.tcx
.vtable_allocation((ty
, trait_ref
))).unwrap_memory();
202 let init
= const_alloc_to_gcc(self, alloc
);
203 self.static_addr_of(init
, alloc
.inner().align
, None
)
205 GlobalAlloc
::Static(def_id
) => {
206 assert
!(self.tcx
.is_static(def_id
));
207 self.get_static(def_id
).get_address(None
)
210 let ptr_type
= base_addr
.get_type();
211 let base_addr
= self.const_bitcast(base_addr
, self.usize_type
);
212 let offset
= self.context
.new_rvalue_from_long(self.usize_type
, offset
.bytes() as i64);
213 let ptr
= self.const_bitcast(base_addr
+ offset
, ptr_type
);
214 if layout
.primitive() != Pointer
{
215 self.const_bitcast(ptr
.dereference(None
).to_rvalue(), ty
)
218 self.const_bitcast(ptr
, ty
)
224 fn const_data_from_alloc(&self, alloc
: ConstAllocation
<'tcx
>) -> Self::Value
{
225 const_alloc_to_gcc(self, alloc
)
228 fn from_const_alloc(&self, layout
: TyAndLayout
<'tcx
>, alloc
: ConstAllocation
<'tcx
>, offset
: Size
) -> PlaceRef
<'tcx
, RValue
<'gcc
>> {
229 assert_eq
!(alloc
.inner().align
, layout
.align
.abi
);
230 let ty
= self.type_ptr_to(layout
.gcc_type(self, true));
232 if layout
.size
== Size
::ZERO
{
233 let value
= self.const_usize(alloc
.inner().align
.bytes());
234 self.context
.new_cast(None
, value
, ty
)
237 let init
= const_alloc_to_gcc(self, alloc
);
238 let base_addr
= self.static_addr_of(init
, alloc
.inner().align
, None
);
240 let array
= self.const_bitcast(base_addr
, self.type_i8p());
241 let value
= self.context
.new_array_access(None
, array
, self.const_usize(offset
.bytes())).get_address(None
);
242 self.const_bitcast(value
, ty
)
244 PlaceRef
::new_sized(value
, layout
)
247 fn const_ptrcast(&self, val
: RValue
<'gcc
>, ty
: Type
<'gcc
>) -> RValue
<'gcc
> {
248 self.context
.new_cast(None
, val
, ty
)
252 pub trait SignType
<'gcc
, 'tcx
> {
253 fn is_signed(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
;
254 fn is_unsigned(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
;
255 fn to_signed(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> Type
<'gcc
>;
256 fn to_unsigned(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> Type
<'gcc
>;
259 impl<'gcc
, 'tcx
> SignType
<'gcc
, 'tcx
> for Type
<'gcc
> {
260 fn is_signed(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
{
261 self.is_i8(cx
) || self.is_i16(cx
) || self.is_i32(cx
) || self.is_i64(cx
) || self.is_i128(cx
)
264 fn is_unsigned(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
{
265 self.is_u8(cx
) || self.is_u16(cx
) || self.is_u32(cx
) || self.is_u64(cx
) || self.is_u128(cx
)
268 fn to_signed(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> Type
<'gcc
> {
272 else if self.is_u16(cx
) {
275 else if self.is_u32(cx
) {
278 else if self.is_u64(cx
) {
281 else if self.is_u128(cx
) {
284 else if self.is_uchar(cx
) {
287 else if self.is_ushort(cx
) {
290 else if self.is_uint(cx
) {
293 else if self.is_ulong(cx
) {
296 else if self.is_ulonglong(cx
) {
304 fn to_unsigned(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> Type
<'gcc
> {
308 else if self.is_i16(cx
) {
311 else if self.is_i32(cx
) {
314 else if self.is_i64(cx
) {
317 else if self.is_i128(cx
) {
320 else if self.is_char(cx
) {
323 else if self.is_short(cx
) {
326 else if self.is_int(cx
) {
329 else if self.is_long(cx
) {
332 else if self.is_longlong(cx
) {
341 pub trait TypeReflection
<'gcc
, 'tcx
> {
342 fn is_uchar(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
;
343 fn is_ushort(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
;
344 fn is_uint(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
;
345 fn is_ulong(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
;
346 fn is_ulonglong(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
;
347 fn is_char(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
;
348 fn is_short(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
;
349 fn is_int(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
;
350 fn is_long(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
;
351 fn is_longlong(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
;
353 fn is_i8(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
;
354 fn is_u8(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
;
355 fn is_i16(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
;
356 fn is_u16(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
;
357 fn is_i32(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
;
358 fn is_u32(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
;
359 fn is_i64(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
;
360 fn is_u64(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
;
361 fn is_i128(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
;
362 fn is_u128(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
;
364 fn is_f32(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
;
365 fn is_f64(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
;
367 fn is_vector(&self) -> bool
;
370 impl<'gcc
, 'tcx
> TypeReflection
<'gcc
, 'tcx
> for Type
<'gcc
> {
371 fn is_uchar(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
{
372 self.unqualified() == cx
.uchar_type
375 fn is_ushort(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
{
376 self.unqualified() == cx
.ushort_type
379 fn is_uint(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
{
380 self.unqualified() == cx
.uint_type
383 fn is_ulong(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
{
384 self.unqualified() == cx
.ulong_type
387 fn is_ulonglong(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
{
388 self.unqualified() == cx
.ulonglong_type
391 fn is_char(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
{
392 self.unqualified() == cx
.char_type
395 fn is_short(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
{
396 self.unqualified() == cx
.short_type
399 fn is_int(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
{
400 self.unqualified() == cx
.int_type
403 fn is_long(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
{
404 self.unqualified() == cx
.long_type
407 fn is_longlong(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
{
408 self.unqualified() == cx
.longlong_type
411 fn is_i8(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
{
412 self.unqualified() == cx
.i8_type
415 fn is_u8(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
{
416 self.unqualified() == cx
.u8_type
419 fn is_i16(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
{
420 self.unqualified() == cx
.i16_type
423 fn is_u16(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
{
424 self.unqualified() == cx
.u16_type
427 fn is_i32(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
{
428 self.unqualified() == cx
.i32_type
431 fn is_u32(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
{
432 self.unqualified() == cx
.u32_type
435 fn is_i64(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
{
436 self.unqualified() == cx
.i64_type
439 fn is_u64(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
{
440 self.unqualified() == cx
.u64_type
443 fn is_i128(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
{
444 self.unqualified() == cx
.i128_type
.unqualified()
447 fn is_u128(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
{
448 self.unqualified() == cx
.u128_type
.unqualified()
451 fn is_f32(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
{
452 self.unqualified() == cx
.context
.new_type
::<f32>()
455 fn is_f64(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
{
456 self.unqualified() == cx
.context
.new_type
::<f64>()
459 fn is_vector(&self) -> bool
{
460 let mut typ
= self.clone();
462 if typ
.dyncast_vector().is_some() {
467 typ
= typ
.unqualified();