1 use gccjit::LValue;
2 use gccjit::{RValue, Type, ToRValue};
3 use rustc_codegen_ssa::traits::{
4 BaseTypeMethods,
5 ConstMethods,
6 MiscMethods,
7 StaticMethods,
8 };
9 use rustc_middle::mir::Mutability;
10 use rustc_middle::ty::layout::{LayoutOf};
11 use rustc_middle::mir::interpret::{ConstAllocation, GlobalAlloc, Scalar};
12 use rustc_target::abi::{self, HasDataLayout, Pointer};
13
14 use crate::consts::const_alloc_to_gcc;
15 use crate::context::CodegenCx;
16 use crate::type_of::LayoutGccExt;
17
18 impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
const_bytes(&self, bytes: &[u8]) -> RValue<'gcc>19 pub fn const_bytes(&self, bytes: &[u8]) -> RValue<'gcc> {
20 bytes_in_context(self, bytes)
21 }
22
global_string(&self, string: &str) -> LValue<'gcc>23 fn global_string(&self, string: &str) -> LValue<'gcc> {
24 // TODO(antoyo): handle non-null-terminated strings.
25 let string = self.context.new_string_literal(&*string);
26 let sym = self.generate_local_symbol_name("str");
27 let global = self.declare_private_global(&sym, self.val_ty(string));
28 global.global_set_initializer_rvalue(string);
29 global
30 // TODO(antoyo): set linkage.
31 }
32 }
33
bytes_in_context<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, bytes: &[u8]) -> RValue<'gcc>34 pub fn bytes_in_context<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, bytes: &[u8]) -> RValue<'gcc> {
35 let context = &cx.context;
36 let byte_type = context.new_type::<u8>();
37 let typ = context.new_array_type(None, byte_type, bytes.len() as u64);
38 let elements: Vec<_> =
39 bytes.iter()
40 .map(|&byte| context.new_rvalue_from_int(byte_type, byte as i32))
41 .collect();
42 context.new_array_constructor(None, typ, &elements)
43 }
44
type_is_pointer(typ: Type<'_>) -> bool45 pub fn type_is_pointer(typ: Type<'_>) -> bool {
46 typ.get_pointee().is_some()
47 }
48
49 impl<'gcc, 'tcx> ConstMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
const_null(&self, typ: Type<'gcc>) -> RValue<'gcc>50 fn const_null(&self, typ: Type<'gcc>) -> RValue<'gcc> {
51 if type_is_pointer(typ) {
52 self.context.new_null(typ)
53 }
54 else {
55 self.const_int(typ, 0)
56 }
57 }
58
const_undef(&self, typ: Type<'gcc>) -> RValue<'gcc>59 fn const_undef(&self, typ: Type<'gcc>) -> RValue<'gcc> {
60 let local = self.current_func.borrow().expect("func")
61 .new_local(None, typ, "undefined");
62 if typ.is_struct().is_some() {
63 // NOTE: hack to workaround a limitation of the rustc API: see comment on
64 // CodegenCx.structs_as_pointer
65 let pointer = local.get_address(None);
66 self.structs_as_pointer.borrow_mut().insert(pointer);
67 pointer
68 }
69 else {
70 local.to_rvalue()
71 }
72 }
73
const_poison(&self, typ: Type<'gcc>) -> RValue<'gcc>74 fn const_poison(&self, typ: Type<'gcc>) -> RValue<'gcc> {
75 // No distinction between undef and poison.
76 self.const_undef(typ)
77 }
78
const_int(&self, typ: Type<'gcc>, int: i64) -> RValue<'gcc>79 fn const_int(&self, typ: Type<'gcc>, int: i64) -> RValue<'gcc> {
80 self.gcc_int(typ, int)
81 }
82
const_uint(&self, typ: Type<'gcc>, int: u64) -> RValue<'gcc>83 fn const_uint(&self, typ: Type<'gcc>, int: u64) -> RValue<'gcc> {
84 self.gcc_uint(typ, int)
85 }
86
const_uint_big(&self, typ: Type<'gcc>, num: u128) -> RValue<'gcc>87 fn const_uint_big(&self, typ: Type<'gcc>, num: u128) -> RValue<'gcc> {
88 self.gcc_uint_big(typ, num)
89 }
90
const_bool(&self, val: bool) -> RValue<'gcc>91 fn const_bool(&self, val: bool) -> RValue<'gcc> {
92 self.const_uint(self.type_i1(), val as u64)
93 }
94
const_i16(&self, i: i16) -> RValue<'gcc>95 fn const_i16(&self, i: i16) -> RValue<'gcc> {
96 self.const_int(self.type_i16(), i as i64)
97 }
98
const_i32(&self, i: i32) -> RValue<'gcc>99 fn const_i32(&self, i: i32) -> RValue<'gcc> {
100 self.const_int(self.type_i32(), i as i64)
101 }
102
const_u32(&self, i: u32) -> RValue<'gcc>103 fn const_u32(&self, i: u32) -> RValue<'gcc> {
104 self.const_uint(self.type_u32(), i as u64)
105 }
106
const_u64(&self, i: u64) -> RValue<'gcc>107 fn const_u64(&self, i: u64) -> RValue<'gcc> {
108 self.const_uint(self.type_u64(), i)
109 }
110
const_u128(&self, i: u128) -> RValue<'gcc>111 fn const_u128(&self, i: u128) -> RValue<'gcc> {
112 self.const_uint_big(self.type_u128(), i)
113 }
114
const_usize(&self, i: u64) -> RValue<'gcc>115 fn const_usize(&self, i: u64) -> RValue<'gcc> {
116 let bit_size = self.data_layout().pointer_size.bits();
117 if bit_size < 64 {
118 // make sure it doesn't overflow
119 assert!(i < (1 << bit_size));
120 }
121
122 self.const_uint(self.usize_type, i)
123 }
124
const_u8(&self, i: u8) -> RValue<'gcc>125 fn const_u8(&self, i: u8) -> RValue<'gcc> {
126 self.const_uint(self.type_u8(), i as u64)
127 }
128
const_real(&self, typ: Type<'gcc>, val: f64) -> RValue<'gcc>129 fn const_real(&self, typ: Type<'gcc>, val: f64) -> RValue<'gcc> {
130 self.context.new_rvalue_from_double(typ, val)
131 }
132
const_str(&self, s: &str) -> (RValue<'gcc>, RValue<'gcc>)133 fn const_str(&self, s: &str) -> (RValue<'gcc>, RValue<'gcc>) {
134 let str_global = *self
135 .const_str_cache
136 .borrow_mut()
137 .raw_entry_mut()
138 .from_key(s)
139 .or_insert_with(|| (s.to_owned(), self.global_string(s)))
140 .1;
141 let len = s.len();
142 let cs = self.const_ptrcast(str_global.get_address(None),
143 self.type_ptr_to(self.layout_of(self.tcx.types.str_).gcc_type(self)),
144 );
145 (cs, self.const_usize(len as u64))
146 }
147
const_struct(&self, values: &[RValue<'gcc>], packed: bool) -> RValue<'gcc>148 fn const_struct(&self, values: &[RValue<'gcc>], packed: bool) -> RValue<'gcc> {
149 let fields: Vec<_> = values.iter()
150 .map(|value| value.get_type())
151 .collect();
152 // TODO(antoyo): cache the type? It's anonymous, so probably not.
153 let typ = self.type_struct(&fields, packed);
154 let struct_type = typ.is_struct().expect("struct type");
155 self.context.new_struct_constructor(None, struct_type.as_type(), None, values)
156 }
157
const_to_opt_uint(&self, _v: RValue<'gcc>) -> Option<u64>158 fn const_to_opt_uint(&self, _v: RValue<'gcc>) -> Option<u64> {
159 // TODO(antoyo)
160 None
161 }
162
const_to_opt_u128(&self, _v: RValue<'gcc>, _sign_ext: bool) -> Option<u128>163 fn const_to_opt_u128(&self, _v: RValue<'gcc>, _sign_ext: bool) -> Option<u128> {
164 // TODO(antoyo)
165 None
166 }
167
scalar_to_backend(&self, cv: Scalar, layout: abi::Scalar, ty: Type<'gcc>) -> RValue<'gcc>168 fn scalar_to_backend(&self, cv: Scalar, layout: abi::Scalar, ty: Type<'gcc>) -> RValue<'gcc> {
169 let bitsize = if layout.is_bool() { 1 } else { layout.size(self).bits() };
170 match cv {
171 Scalar::Int(int) => {
172 let data = int.assert_bits(layout.size(self));
173
174 // FIXME(antoyo): there's some issues with using the u128 code that follows, so hard-code
175 // the paths for floating-point values.
176 if ty == self.float_type {
177 return self.context.new_rvalue_from_double(ty, f32::from_bits(data as u32) as f64);
178 }
179 else if ty == self.double_type {
180 return self.context.new_rvalue_from_double(ty, f64::from_bits(data as u64));
181 }
182
183 let value = self.const_uint_big(self.type_ix(bitsize), data);
184 let bytesize = layout.size(self).bytes();
185 if bitsize > 1 && ty.is_integral() && bytesize as u32 == ty.get_size() {
186 // NOTE: since the intrinsic _xabort is called with a bitcast, which
187 // is non-const, but expects a constant, do a normal cast instead of a bitcast.
188 // FIXME(antoyo): fix bitcast to work in constant contexts.
189 // TODO(antoyo): perhaps only use bitcast for pointers?
190 self.context.new_cast(None, value, ty)
191 }
192 else {
193 // TODO(bjorn3): assert size is correct
194 self.const_bitcast(value, ty)
195 }
196 }
197 Scalar::Ptr(ptr, _size) => {
198 let (alloc_id, offset) = ptr.into_parts();
199 let base_addr =
200 match self.tcx.global_alloc(alloc_id) {
201 GlobalAlloc::Memory(alloc) => {
202 let init = const_alloc_to_gcc(self, alloc);
203 let alloc = alloc.inner();
204 let value =
205 match alloc.mutability {
206 Mutability::Mut => self.static_addr_of_mut(init, alloc.align, None),
207 _ => self.static_addr_of(init, alloc.align, None),
208 };
209 if !self.sess().fewer_names() {
210 // TODO(antoyo): set value name.
211 }
212 value
213 },
214 GlobalAlloc::Function(fn_instance) => {
215 self.get_fn_addr(fn_instance)
216 },
217 GlobalAlloc::VTable(ty, trait_ref) => {
218 let alloc = self.tcx.global_alloc(self.tcx.vtable_allocation((ty, trait_ref))).unwrap_memory();
219 let init = const_alloc_to_gcc(self, alloc);
220 self.static_addr_of(init, alloc.inner().align, None)
221 }
222 GlobalAlloc::Static(def_id) => {
223 assert!(self.tcx.is_static(def_id));
224 self.get_static(def_id).get_address(None)
225 },
226 };
227 let ptr_type = base_addr.get_type();
228 let base_addr = self.const_bitcast(base_addr, self.usize_type);
229 let offset = self.context.new_rvalue_from_long(self.usize_type, offset.bytes() as i64);
230 let ptr = self.const_bitcast(base_addr + offset, ptr_type);
231 if !matches!(layout.primitive(), Pointer(_)) {
232 self.const_bitcast(ptr.dereference(None).to_rvalue(), ty)
233 }
234 else {
235 self.const_bitcast(ptr, ty)
236 }
237 }
238 }
239 }
240
const_data_from_alloc(&self, alloc: ConstAllocation<'tcx>) -> Self::Value241 fn const_data_from_alloc(&self, alloc: ConstAllocation<'tcx>) -> Self::Value {
242 const_alloc_to_gcc(self, alloc)
243 }
244
const_ptrcast(&self, val: RValue<'gcc>, ty: Type<'gcc>) -> RValue<'gcc>245 fn const_ptrcast(&self, val: RValue<'gcc>, ty: Type<'gcc>) -> RValue<'gcc> {
246 self.context.new_cast(None, val, ty)
247 }
248
const_bitcast(&self, value: RValue<'gcc>, typ: Type<'gcc>) -> RValue<'gcc>249 fn const_bitcast(&self, value: RValue<'gcc>, typ: Type<'gcc>) -> RValue<'gcc> {
250 if value.get_type() == self.bool_type.make_pointer() {
251 if let Some(pointee) = typ.get_pointee() {
252 if pointee.dyncast_vector().is_some() {
253 panic!()
254 }
255 }
256 }
257 // NOTE: since bitcast makes a value non-constant, don't bitcast if not necessary as some
258 // SIMD builtins require a constant value.
259 self.bitcast_if_needed(value, typ)
260 }
261
const_ptr_byte_offset(&self, base_addr: Self::Value, offset: abi::Size) -> Self::Value262 fn const_ptr_byte_offset(&self, base_addr: Self::Value, offset: abi::Size) -> Self::Value {
263 self.context.new_array_access(None, base_addr, self.const_usize(offset.bytes())).get_address(None)
264 }
265 }
266
267 pub trait SignType<'gcc, 'tcx> {
is_signed(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool268 fn is_signed(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool;
is_unsigned(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool269 fn is_unsigned(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool;
to_signed(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Type<'gcc>270 fn to_signed(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Type<'gcc>;
to_unsigned(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Type<'gcc>271 fn to_unsigned(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Type<'gcc>;
272 }
273
274 impl<'gcc, 'tcx> SignType<'gcc, 'tcx> for Type<'gcc> {
is_signed(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool275 fn is_signed(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool {
276 self.is_i8(cx) || self.is_i16(cx) || self.is_i32(cx) || self.is_i64(cx) || self.is_i128(cx)
277 }
278
is_unsigned(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool279 fn is_unsigned(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool {
280 self.is_u8(cx) || self.is_u16(cx) || self.is_u32(cx) || self.is_u64(cx) || self.is_u128(cx)
281 }
282
to_signed(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Type<'gcc>283 fn to_signed(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Type<'gcc> {
284 if self.is_u8(cx) {
285 cx.i8_type
286 }
287 else if self.is_u16(cx) {
288 cx.i16_type
289 }
290 else if self.is_u32(cx) {
291 cx.i32_type
292 }
293 else if self.is_u64(cx) {
294 cx.i64_type
295 }
296 else if self.is_u128(cx) {
297 cx.i128_type
298 }
299 else if self.is_uchar(cx) {
300 cx.char_type
301 }
302 else if self.is_ushort(cx) {
303 cx.short_type
304 }
305 else if self.is_uint(cx) {
306 cx.int_type
307 }
308 else if self.is_ulong(cx) {
309 cx.long_type
310 }
311 else if self.is_ulonglong(cx) {
312 cx.longlong_type
313 }
314 else {
315 self.clone()
316 }
317 }
318
to_unsigned(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Type<'gcc>319 fn to_unsigned(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Type<'gcc> {
320 if self.is_i8(cx) {
321 cx.u8_type
322 }
323 else if self.is_i16(cx) {
324 cx.u16_type
325 }
326 else if self.is_i32(cx) {
327 cx.u32_type
328 }
329 else if self.is_i64(cx) {
330 cx.u64_type
331 }
332 else if self.is_i128(cx) {
333 cx.u128_type
334 }
335 else if self.is_char(cx) {
336 cx.uchar_type
337 }
338 else if self.is_short(cx) {
339 cx.ushort_type
340 }
341 else if self.is_int(cx) {
342 cx.uint_type
343 }
344 else if self.is_long(cx) {
345 cx.ulong_type
346 }
347 else if self.is_longlong(cx) {
348 cx.ulonglong_type
349 }
350 else {
351 self.clone()
352 }
353 }
354 }
355
356 pub trait TypeReflection<'gcc, 'tcx> {
is_uchar(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool357 fn is_uchar(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool;
is_ushort(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool358 fn is_ushort(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool;
is_uint(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool359 fn is_uint(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool;
is_ulong(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool360 fn is_ulong(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool;
is_ulonglong(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool361 fn is_ulonglong(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool;
is_char(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool362 fn is_char(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool;
is_short(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool363 fn is_short(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool;
is_int(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool364 fn is_int(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool;
is_long(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool365 fn is_long(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool;
is_longlong(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool366 fn is_longlong(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool;
367
is_i8(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool368 fn is_i8(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool;
is_u8(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool369 fn is_u8(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool;
is_i16(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool370 fn is_i16(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool;
is_u16(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool371 fn is_u16(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool;
is_i32(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool372 fn is_i32(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool;
is_u32(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool373 fn is_u32(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool;
is_i64(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool374 fn is_i64(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool;
is_u64(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool375 fn is_u64(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool;
is_i128(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool376 fn is_i128(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool;
is_u128(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool377 fn is_u128(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool;
378
is_f32(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool379 fn is_f32(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool;
is_f64(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool380 fn is_f64(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool;
381
is_vector(&self) -> bool382 fn is_vector(&self) -> bool;
383 }
384
385 impl<'gcc, 'tcx> TypeReflection<'gcc, 'tcx> for Type<'gcc> {
is_uchar(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool386 fn is_uchar(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool {
387 self.unqualified() == cx.uchar_type
388 }
389
is_ushort(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool390 fn is_ushort(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool {
391 self.unqualified() == cx.ushort_type
392 }
393
is_uint(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool394 fn is_uint(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool {
395 self.unqualified() == cx.uint_type
396 }
397
is_ulong(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool398 fn is_ulong(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool {
399 self.unqualified() == cx.ulong_type
400 }
401
is_ulonglong(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool402 fn is_ulonglong(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool {
403 self.unqualified() == cx.ulonglong_type
404 }
405
is_char(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool406 fn is_char(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool {
407 self.unqualified() == cx.char_type
408 }
409
is_short(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool410 fn is_short(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool {
411 self.unqualified() == cx.short_type
412 }
413
is_int(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool414 fn is_int(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool {
415 self.unqualified() == cx.int_type
416 }
417
is_long(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool418 fn is_long(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool {
419 self.unqualified() == cx.long_type
420 }
421
is_longlong(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool422 fn is_longlong(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool {
423 self.unqualified() == cx.longlong_type
424 }
425
is_i8(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool426 fn is_i8(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool {
427 self.unqualified() == cx.i8_type
428 }
429
is_u8(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool430 fn is_u8(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool {
431 self.unqualified() == cx.u8_type
432 }
433
is_i16(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool434 fn is_i16(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool {
435 self.unqualified() == cx.i16_type
436 }
437
is_u16(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool438 fn is_u16(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool {
439 self.unqualified() == cx.u16_type
440 }
441
is_i32(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool442 fn is_i32(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool {
443 self.unqualified() == cx.i32_type
444 }
445
is_u32(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool446 fn is_u32(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool {
447 self.unqualified() == cx.u32_type
448 }
449
is_i64(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool450 fn is_i64(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool {
451 self.unqualified() == cx.i64_type
452 }
453
is_u64(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool454 fn is_u64(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool {
455 self.unqualified() == cx.u64_type
456 }
457
is_i128(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool458 fn is_i128(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool {
459 self.unqualified() == cx.i128_type.unqualified()
460 }
461
is_u128(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool462 fn is_u128(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool {
463 self.unqualified() == cx.u128_type.unqualified()
464 }
465
is_f32(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool466 fn is_f32(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool {
467 self.unqualified() == cx.context.new_type::<f32>()
468 }
469
is_f64(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool470 fn is_f64(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool {
471 self.unqualified() == cx.context.new_type::<f64>()
472 }
473
is_vector(&self) -> bool474 fn is_vector(&self) -> bool {
475 let mut typ = self.clone();
476 loop {
477 if typ.dyncast_vector().is_some() {
478 return true;
479 }
480
481 let old_type = typ;
482 typ = typ.unqualified();
483 if old_type == typ {
484 break;
485 }
486 }
487
488 false
489 }
490 }
491