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
::ScalarInt
;
13 use rustc_middle
::ty
::layout
::{TyAndLayout, LayoutOf}
;
14 use rustc_middle
::mir
::interpret
::{ConstAllocation, GlobalAlloc, Scalar}
;
15 use rustc_span
::Symbol
;
16 use rustc_target
::abi
::{self, HasDataLayout, Pointer, Size}
;
18 use crate::consts
::const_alloc_to_gcc
;
19 use crate::context
::CodegenCx
;
20 use crate::type_of
::LayoutGccExt
;
22 impl<'gcc
, 'tcx
> CodegenCx
<'gcc
, 'tcx
> {
23 pub fn const_bytes(&self, bytes
: &[u8]) -> RValue
<'gcc
> {
24 bytes_in_context(self, bytes
)
27 fn global_string(&self, string
: &str) -> LValue
<'gcc
> {
28 // TODO(antoyo): handle non-null-terminated strings.
29 let string
= self.context
.new_string_literal(&*string
);
30 let sym
= self.generate_local_symbol_name("str");
31 let global
= self.declare_private_global(&sym
, self.val_ty(string
));
32 global
.global_set_initializer_rvalue(string
);
34 // TODO(antoyo): set linkage.
38 pub fn bytes_in_context
<'gcc
, 'tcx
>(cx
: &CodegenCx
<'gcc
, 'tcx
>, bytes
: &[u8]) -> RValue
<'gcc
> {
39 let context
= &cx
.context
;
40 let byte_type
= context
.new_type
::<u8>();
41 let typ
= context
.new_array_type(None
, byte_type
, bytes
.len() as i32);
42 let elements
: Vec
<_
> =
44 .map(|&byte
| context
.new_rvalue_from_int(byte_type
, byte
as i32))
46 context
.new_array_constructor(None
, typ
, &elements
)
49 pub fn type_is_pointer
<'gcc
>(typ
: Type
<'gcc
>) -> bool
{
50 typ
.get_pointee().is_some()
53 impl<'gcc
, 'tcx
> ConstMethods
<'tcx
> for CodegenCx
<'gcc
, 'tcx
> {
54 fn const_null(&self, typ
: Type
<'gcc
>) -> RValue
<'gcc
> {
55 if type_is_pointer(typ
) {
56 self.context
.new_null(typ
)
59 self.const_int(typ
, 0)
63 fn const_undef(&self, typ
: Type
<'gcc
>) -> RValue
<'gcc
> {
64 let local
= self.current_func
.borrow().expect("func")
65 .new_local(None
, typ
, "undefined");
66 if typ
.is_struct().is_some() {
67 // NOTE: hack to workaround a limitation of the rustc API: see comment on
68 // CodegenCx.structs_as_pointer
69 let pointer
= local
.get_address(None
);
70 self.structs_as_pointer
.borrow_mut().insert(pointer
);
78 fn const_int(&self, typ
: Type
<'gcc
>, int
: i64) -> RValue
<'gcc
> {
79 self.gcc_int(typ
, int
)
82 fn const_uint(&self, typ
: Type
<'gcc
>, int
: u64) -> RValue
<'gcc
> {
83 self.gcc_uint(typ
, int
)
86 fn const_uint_big(&self, typ
: Type
<'gcc
>, num
: u128
) -> RValue
<'gcc
> {
87 self.gcc_uint_big(typ
, num
)
90 fn const_bool(&self, val
: bool
) -> RValue
<'gcc
> {
91 self.const_uint(self.type_i1(), val
as u64)
94 fn const_i16(&self, i
: i16) -> RValue
<'gcc
> {
95 self.const_int(self.type_i16(), i
as i64)
98 fn const_i32(&self, i
: i32) -> RValue
<'gcc
> {
99 self.const_int(self.type_i32(), i
as i64)
102 fn const_u32(&self, i
: u32) -> RValue
<'gcc
> {
103 self.const_uint(self.type_u32(), i
as u64)
106 fn const_u64(&self, i
: u64) -> RValue
<'gcc
> {
107 self.const_uint(self.type_u64(), i
)
110 fn const_usize(&self, i
: u64) -> RValue
<'gcc
> {
111 let bit_size
= self.data_layout().pointer_size
.bits();
113 // make sure it doesn't overflow
114 assert
!(i
< (1 << bit_size
));
117 self.const_uint(self.usize_type
, i
)
120 fn const_u8(&self, _i
: u8) -> RValue
<'gcc
> {
124 fn const_real(&self, typ
: Type
<'gcc
>, val
: f64) -> RValue
<'gcc
> {
125 self.context
.new_rvalue_from_double(typ
, val
)
128 fn const_str(&self, s
: Symbol
) -> (RValue
<'gcc
>, RValue
<'gcc
>) {
129 let s_str
= s
.as_str();
130 let str_global
= *self.const_str_cache
.borrow_mut().entry(s
).or_insert_with(|| {
131 self.global_string(s_str
)
133 let len
= s_str
.len();
134 let cs
= self.const_ptrcast(str_global
.get_address(None
),
135 self.type_ptr_to(self.layout_of(self.tcx
.types
.str_
).gcc_type(self, true)),
137 (cs
, self.const_usize(len
as u64))
140 fn const_struct(&self, values
: &[RValue
<'gcc
>], packed
: bool
) -> RValue
<'gcc
> {
141 let fields
: Vec
<_
> = values
.iter()
142 .map(|value
| value
.get_type())
144 // TODO(antoyo): cache the type? It's anonymous, so probably not.
145 let typ
= self.type_struct(&fields
, packed
);
146 let struct_type
= typ
.is_struct().expect("struct type");
147 self.context
.new_struct_constructor(None
, struct_type
.as_type(), None
, values
)
150 fn const_to_opt_uint(&self, _v
: RValue
<'gcc
>) -> Option
<u64> {
155 fn const_to_opt_u128(&self, _v
: RValue
<'gcc
>, _sign_ext
: bool
) -> Option
<u128
> {
160 fn scalar_to_backend(&self, cv
: Scalar
, layout
: abi
::Scalar
, ty
: Type
<'gcc
>) -> RValue
<'gcc
> {
161 let bitsize
= if layout
.is_bool() { 1 }
else { layout.size(self).bits() }
;
163 Scalar
::Int(ScalarInt
::ZST
) => {
164 assert_eq
!(0, layout
.size(self).bytes());
165 self.const_undef(self.type_ix(0))
167 Scalar
::Int(int
) => {
168 let data
= int
.assert_bits(layout
.size(self));
170 // FIXME(antoyo): there's some issues with using the u128 code that follows, so hard-code
171 // the paths for floating-point values.
172 if ty
== self.float_type
{
173 return self.context
.new_rvalue_from_double(ty
, f32::from_bits(data
as u32) as f64);
175 else if ty
== self.double_type
{
176 return self.context
.new_rvalue_from_double(ty
, f64::from_bits(data
as u64));
179 let value
= self.const_uint_big(self.type_ix(bitsize
), data
);
180 // TODO(bjorn3): assert size is correct
181 self.const_bitcast(value
, ty
)
183 Scalar
::Ptr(ptr
, _size
) => {
184 let (alloc_id
, offset
) = ptr
.into_parts();
186 match self.tcx
.global_alloc(alloc_id
) {
187 GlobalAlloc
::Memory(alloc
) => {
188 let init
= const_alloc_to_gcc(self, alloc
);
189 let alloc
= alloc
.inner();
191 match alloc
.mutability
{
192 Mutability
::Mut
=> self.static_addr_of_mut(init
, alloc
.align
, None
),
193 _
=> self.static_addr_of(init
, alloc
.align
, None
),
195 if !self.sess().fewer_names() {
196 // TODO(antoyo): set value name.
200 GlobalAlloc
::Function(fn_instance
) => {
201 self.get_fn_addr(fn_instance
)
203 GlobalAlloc
::Static(def_id
) => {
204 assert
!(self.tcx
.is_static(def_id
));
205 self.get_static(def_id
).get_address(None
)
208 let ptr_type
= base_addr
.get_type();
209 let base_addr
= self.const_bitcast(base_addr
, self.usize_type
);
210 let offset
= self.context
.new_rvalue_from_long(self.usize_type
, offset
.bytes() as i64);
211 let ptr
= self.const_bitcast(base_addr
+ offset
, ptr_type
);
212 if layout
.primitive() != Pointer
{
213 self.const_bitcast(ptr
.dereference(None
).to_rvalue(), ty
)
216 self.const_bitcast(ptr
, ty
)
222 fn const_data_from_alloc(&self, alloc
: ConstAllocation
<'tcx
>) -> Self::Value
{
223 const_alloc_to_gcc(self, alloc
)
226 fn from_const_alloc(&self, layout
: TyAndLayout
<'tcx
>, alloc
: ConstAllocation
<'tcx
>, offset
: Size
) -> PlaceRef
<'tcx
, RValue
<'gcc
>> {
227 assert_eq
!(alloc
.inner().align
, layout
.align
.abi
);
228 let ty
= self.type_ptr_to(layout
.gcc_type(self, true));
230 if layout
.size
== Size
::ZERO
{
231 let value
= self.const_usize(alloc
.inner().align
.bytes());
232 self.context
.new_cast(None
, value
, ty
)
235 let init
= const_alloc_to_gcc(self, alloc
);
236 let base_addr
= self.static_addr_of(init
, alloc
.inner().align
, None
);
238 let array
= self.const_bitcast(base_addr
, self.type_i8p());
239 let value
= self.context
.new_array_access(None
, array
, self.const_usize(offset
.bytes())).get_address(None
);
240 self.const_bitcast(value
, ty
)
242 PlaceRef
::new_sized(value
, layout
)
245 fn const_ptrcast(&self, val
: RValue
<'gcc
>, ty
: Type
<'gcc
>) -> RValue
<'gcc
> {
246 self.context
.new_cast(None
, val
, ty
)
250 pub trait SignType
<'gcc
, 'tcx
> {
251 fn is_signed(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
;
252 fn is_unsigned(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
;
253 fn to_signed(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> Type
<'gcc
>;
254 fn to_unsigned(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> Type
<'gcc
>;
257 impl<'gcc
, 'tcx
> SignType
<'gcc
, 'tcx
> for Type
<'gcc
> {
258 fn is_signed(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
{
259 self.is_i8(cx
) || self.is_i16(cx
) || self.is_i32(cx
) || self.is_i64(cx
) || self.is_i128(cx
)
262 fn is_unsigned(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
{
263 self.is_u8(cx
) || self.is_u16(cx
) || self.is_u32(cx
) || self.is_u64(cx
) || self.is_u128(cx
)
266 fn to_signed(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> Type
<'gcc
> {
270 else if self.is_u16(cx
) {
273 else if self.is_u32(cx
) {
276 else if self.is_u64(cx
) {
279 else if self.is_u128(cx
) {
282 else if self.is_uchar(cx
) {
285 else if self.is_ushort(cx
) {
288 else if self.is_uint(cx
) {
291 else if self.is_ulong(cx
) {
294 else if self.is_ulonglong(cx
) {
302 fn to_unsigned(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> Type
<'gcc
> {
306 else if self.is_i16(cx
) {
309 else if self.is_i32(cx
) {
312 else if self.is_i64(cx
) {
315 else if self.is_i128(cx
) {
318 else if self.is_char(cx
) {
321 else if self.is_short(cx
) {
324 else if self.is_int(cx
) {
327 else if self.is_long(cx
) {
330 else if self.is_longlong(cx
) {
339 pub trait TypeReflection
<'gcc
, 'tcx
> {
340 fn is_uchar(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
;
341 fn is_ushort(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
;
342 fn is_uint(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
;
343 fn is_ulong(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
;
344 fn is_ulonglong(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
;
345 fn is_char(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
;
346 fn is_short(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
;
347 fn is_int(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
;
348 fn is_long(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
;
349 fn is_longlong(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
;
351 fn is_i8(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
;
352 fn is_u8(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
;
353 fn is_i16(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
;
354 fn is_u16(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
;
355 fn is_i32(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
;
356 fn is_u32(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
;
357 fn is_i64(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
;
358 fn is_u64(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
;
359 fn is_i128(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
;
360 fn is_u128(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
;
362 fn is_f32(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
;
363 fn is_f64(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
;
365 fn is_vector(&self) -> bool
;
368 impl<'gcc
, 'tcx
> TypeReflection
<'gcc
, 'tcx
> for Type
<'gcc
> {
369 fn is_uchar(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
{
370 self.unqualified() == cx
.uchar_type
373 fn is_ushort(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
{
374 self.unqualified() == cx
.ushort_type
377 fn is_uint(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
{
378 self.unqualified() == cx
.uint_type
381 fn is_ulong(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
{
382 self.unqualified() == cx
.ulong_type
385 fn is_ulonglong(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
{
386 self.unqualified() == cx
.ulonglong_type
389 fn is_char(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
{
390 self.unqualified() == cx
.char_type
393 fn is_short(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
{
394 self.unqualified() == cx
.short_type
397 fn is_int(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
{
398 self.unqualified() == cx
.int_type
401 fn is_long(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
{
402 self.unqualified() == cx
.long_type
405 fn is_longlong(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
{
406 self.unqualified() == cx
.longlong_type
409 fn is_i8(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
{
410 self.unqualified() == cx
.i8_type
413 fn is_u8(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
{
414 self.unqualified() == cx
.u8_type
417 fn is_i16(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
{
418 self.unqualified() == cx
.i16_type
421 fn is_u16(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
{
422 self.unqualified() == cx
.u16_type
425 fn is_i32(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
{
426 self.unqualified() == cx
.i32_type
429 fn is_u32(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
{
430 self.unqualified() == cx
.u32_type
433 fn is_i64(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
{
434 self.unqualified() == cx
.i64_type
437 fn is_u64(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
{
438 self.unqualified() == cx
.u64_type
441 fn is_i128(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
{
442 self.unqualified() == cx
.i128_type
.unqualified()
445 fn is_u128(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
{
446 self.unqualified() == cx
.u128_type
.unqualified()
449 fn is_f32(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
{
450 self.unqualified() == cx
.context
.new_type
::<f32>()
453 fn is_f64(&self, cx
: &CodegenCx
<'gcc
, 'tcx
>) -> bool
{
454 self.unqualified() == cx
.context
.new_type
::<f64>()
457 fn is_vector(&self) -> bool
{
458 let mut typ
= self.clone();
460 if typ
.dyncast_vector().is_some() {
465 typ
= typ
.unqualified();