Skip to content

Commit ebd5bee

Browse files
committed
Add support for non native integer types in some operations
1 parent 66ae0b2 commit ebd5bee

File tree

9 files changed

+625
-160
lines changed

9 files changed

+625
-160
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,4 @@ gimple*
1818
res
1919
test-backend
2020
gcc_path
21+
benchmarks

Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,10 @@ path = "tests/lib.rs"
1414
harness = false
1515

1616
[dependencies]
17-
#gccjit = { git = "https://github.com/antoyo/gccjit.rs" }
17+
gccjit = { git = "https://github.com/antoyo/gccjit.rs" }
1818

1919
# Local copy.
20-
gccjit = { path = "../gccjit.rs" }
20+
#gccjit = { path = "../gccjit.rs" }
2121

2222
target-lexicon = "0.10.0"
2323

src/builder.rs

Lines changed: 17 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -468,40 +468,32 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
468468
}
469469
}
470470

471-
fn add(&mut self, a: RValue<'gcc>, mut b: RValue<'gcc>) -> RValue<'gcc> {
472-
// FIXME(antoyo): this should not be required.
473-
if format!("{:?}", a.get_type()) != format!("{:?}", b.get_type()) {
474-
b = self.context.new_cast(None, b, a.get_type());
475-
}
476-
a + b
471+
fn add(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
472+
self.gcc_add(a, b)
477473
}
478474

479475
fn fadd(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
480476
a + b
481477
}
482478

483-
fn sub(&mut self, a: RValue<'gcc>, mut b: RValue<'gcc>) -> RValue<'gcc> {
484-
if a.get_type() != b.get_type() {
485-
b = self.context.new_cast(None, b, a.get_type());
486-
}
487-
a - b
479+
fn sub(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
480+
self.gcc_sub(a, b)
488481
}
489482

490483
fn fsub(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
491484
a - b
492485
}
493486

494487
fn mul(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
495-
a * b
488+
self.gcc_mul(a, b)
496489
}
497490

498491
fn fmul(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
499492
a * b
500493
}
501494

502495
fn udiv(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
503-
// TODO(antoyo): convert the arguments to unsigned?
504-
a / b
496+
self.gcc_udiv(a, b)
505497
}
506498

507499
fn exactudiv(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
@@ -529,7 +521,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
529521
}
530522

531523
fn urem(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
532-
a % b
524+
self.gcc_urem(a, b)
533525
}
534526

535527
fn srem(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
@@ -549,40 +541,11 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
549541
}
550542

551543
fn shl(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
552-
// FIXME(antoyo): remove the casts when libgccjit can shift an unsigned number by an unsigned number.
553-
let a_type = a.get_type();
554-
let b_type = b.get_type();
555-
if a_type.is_unsigned(self) && b_type.is_signed(self) {
556-
let a = self.context.new_cast(None, a, b_type);
557-
let result = a << b;
558-
self.context.new_cast(None, result, a_type)
559-
}
560-
else if a_type.is_signed(self) && b_type.is_unsigned(self) {
561-
let b = self.context.new_cast(None, b, a_type);
562-
a << b
563-
}
564-
else {
565-
a << b
566-
}
544+
self.gcc_shl(a, b)
567545
}
568546

569547
fn lshr(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
570-
// FIXME(antoyo): remove the casts when libgccjit can shift an unsigned number by an unsigned number.
571-
// TODO(antoyo): cast to unsigned to do a logical shift if that does not work.
572-
let a_type = a.get_type();
573-
let b_type = b.get_type();
574-
if a_type.is_unsigned(self) && b_type.is_signed(self) {
575-
let a = self.context.new_cast(None, a, b_type);
576-
let result = a >> b;
577-
self.context.new_cast(None, result, a_type)
578-
}
579-
else if a_type.is_signed(self) && b_type.is_unsigned(self) {
580-
let b = self.context.new_cast(None, b, a_type);
581-
a >> b
582-
}
583-
else {
584-
a >> b
585-
}
548+
self.gcc_lshr(a, b)
586549
}
587550

588551
fn ashr(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
@@ -604,41 +567,28 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
604567
}
605568
}
606569

607-
fn and(&mut self, a: RValue<'gcc>, mut b: RValue<'gcc>) -> RValue<'gcc> {
608-
if a.get_type() != b.get_type() {
609-
b = self.context.new_cast(None, b, a.get_type());
610-
}
611-
a & b
570+
fn and(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
571+
self.gcc_and(a, b)
612572
}
613573

614-
fn or(&mut self, a: RValue<'gcc>, mut b: RValue<'gcc>) -> RValue<'gcc> {
615-
if a.get_type() != b.get_type() {
616-
b = self.context.new_cast(None, b, a.get_type());
617-
}
618-
a | b
574+
fn or(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
575+
self.gcc_or(a, b)
619576
}
620577

621578
fn xor(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
622579
a ^ b
623580
}
624581

625582
fn neg(&mut self, a: RValue<'gcc>) -> RValue<'gcc> {
626-
self.cx.context.new_unary_op(None, UnaryOp::Minus, a.get_type(), a)
583+
self.gcc_neg(a)
627584
}
628585

629586
fn fneg(&mut self, a: RValue<'gcc>) -> RValue<'gcc> {
630587
self.cx.context.new_unary_op(None, UnaryOp::Minus, a.get_type(), a)
631588
}
632589

633590
fn not(&mut self, a: RValue<'gcc>) -> RValue<'gcc> {
634-
let operation =
635-
if a.get_type().is_bool() {
636-
UnaryOp::LogicalNegate
637-
}
638-
else {
639-
UnaryOp::BitwiseNegate
640-
};
641-
self.cx.context.new_unary_op(None, operation, a.get_type(), a)
591+
self.gcc_not(a)
642592
}
643593

644594
fn unchecked_sadd(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
@@ -1049,40 +999,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
1049999

10501000
fn intcast(&mut self, value: RValue<'gcc>, dest_typ: Type<'gcc>, _is_signed: bool) -> RValue<'gcc> {
10511001
// NOTE: is_signed is for value, not dest_typ.
1052-
if self.supports_native_int_type(dest_typ) && self.supports_native_int_type(value.get_type()) {
1053-
self.cx.context.new_cast(None, value, dest_typ)
1054-
}
1055-
else {
1056-
let value_type = value.get_type();
1057-
let src_size = self.cx.int_type_size(value_type);
1058-
let src_element_size = self.cx.int_type_element_size(value_type);
1059-
let dest_size = self.cx.int_type_size(dest_typ);
1060-
let factor = (dest_size / src_size) as usize;
1061-
let array_type = self.context.new_array_type(None, value_type, factor as i32);
1062-
1063-
if src_size < dest_size {
1064-
// TODO: initialize to -1 if negative.
1065-
let mut values = vec![self.context.new_rvalue_zero(value_type); factor];
1066-
// TODO: take endianness into account.
1067-
values[factor - 1] = value;
1068-
let array_value = self.context.new_rvalue_from_array(None, array_type, &values);
1069-
self.cx.context.new_bitcast(None, array_value, dest_typ)
1070-
}
1071-
else {
1072-
let mut current_size = 0;
1073-
// TODO: take endianness into account.
1074-
let mut current_index = src_size / src_element_size - 1;
1075-
let mut values = vec![];
1076-
while current_size < dest_size {
1077-
values.push(self.context.new_array_access(None, value, self.context.new_rvalue_from_int(self.int_type, current_index as i32)).to_rvalue());
1078-
current_size += src_element_size;
1079-
current_index -= 1;
1080-
}
1081-
let array_value = self.context.new_rvalue_from_array(None, array_type, &values);
1082-
// FIXME: that's not working since we can cast from u8 to struct u128.
1083-
self.cx.context.new_bitcast(None, array_value, dest_typ)
1084-
}
1085-
}
1002+
self.gcc_int_cast(value, dest_typ)
10861003
}
10871004

10881005
fn pointercast(&mut self, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> {
@@ -1424,7 +1341,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
14241341
// Fix the code in codegen_ssa::base::from_immediate.
14251342
return value;
14261343
}
1427-
self.context.new_cast(None, value, dest_typ)
1344+
self.gcc_int_cast(value, dest_typ)
14281345
}
14291346

14301347
fn cx(&self) -> &CodegenCx<'gcc, 'tcx> {

src/common.rs

Lines changed: 3 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,3 @@
1-
use std::convert::TryFrom;
2-
use std::convert::TryInto;
3-
41
use gccjit::LValue;
52
use gccjit::{Block, CType, RValue, Type, ToRValue};
63
use rustc_codegen_ssa::mir::place::PlaceRef;
@@ -112,36 +109,15 @@ impl<'gcc, 'tcx> ConstMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
112109
}
113110

114111
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"))
112+
self.gcc_int(typ, int)
116113
}
117114

118115
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)
116+
self.gcc_uint(typ, int)
120117
}
121118

122119
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);
128-
}
129-
130-
if num >> 64 != 0 {
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);
134-
135-
let sixty_four = self.context.new_rvalue_from_long(typ, 64);
136-
(high << sixty_four) | self.context.new_cast(None, low, typ)
137-
}
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)
141-
}
142-
else {
143-
self.context.new_rvalue_from_long(typ, num as u64 as i64)
144-
}
120+
self.gcc_uint_big(typ, num)
145121
}
146122

147123
fn const_bool(&self, val: bool) -> RValue<'gcc> {

src/context.rs

Lines changed: 33 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,12 @@ pub struct FuncSig<'gcc> {
3636
pub return_type: Type<'gcc>,
3737
}
3838

39+
#[derive(Clone)]
3940
pub struct IntType<'gcc> {
40-
bits: u8,
41-
element_size: u8,
42-
typ: Type<'gcc>,
43-
signed: bool,
41+
pub bits: u8,
42+
pub element_size: u8,
43+
pub typ: Type<'gcc>,
44+
pub signed: bool,
4445
}
4546

4647
pub struct CodegenCx<'gcc, 'tcx> {
@@ -169,6 +170,12 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
169170

170171
let mut native_int_types = vec![];
171172

173+
native_int_types.push(IntType {
174+
bits: 128,
175+
element_size: 128,
176+
signed: true,
177+
typ: i128_type,
178+
});
172179
native_int_types.push(IntType {
173180
bits: 64,
174181
element_size: 64,
@@ -333,36 +340,47 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
333340
false
334341
}
335342

336-
pub fn int_type_size(&self, typ: Type<'gcc>) -> u8 {
337-
for native_type in &self.native_int_types {
338-
if native_type.typ.is_compatible_with(typ) {
339-
return native_type.bits;
340-
}
343+
pub fn supports_native_int_type_or_bool(&self, typ: Type<'gcc>) -> bool {
344+
self.supports_native_int_type(typ) || typ == self.bool_type
345+
}
346+
347+
pub fn is_int_type_or_bool(&self, typ: Type<'gcc>) -> bool {
348+
if self.supports_native_int_type(typ) || typ == self.bool_type {
349+
return true;
341350
}
342351
for non_native_type in &self.non_native_int_types {
343352
if non_native_type.typ.is_compatible_with(typ) {
344-
return non_native_type.bits;
353+
return true;
345354
}
346355
}
347-
348-
panic!("{:?} not an integer type", typ);
356+
false
349357
}
350358

351-
pub fn int_type_element_size(&self, typ: Type<'gcc>) -> u8 {
359+
pub fn get_int_type(&self, typ: Type<'gcc>) -> IntType<'gcc> {
352360
for native_type in &self.native_int_types {
353361
if native_type.typ.is_compatible_with(typ) {
354-
return native_type.bits;
362+
return native_type.clone();
355363
}
356364
}
357365
for non_native_type in &self.non_native_int_types {
358366
if non_native_type.typ.is_compatible_with(typ) {
359-
return non_native_type.bits;
367+
return non_native_type.clone();
360368
}
361369
}
362370

363371
panic!("{:?} not an integer type", typ);
364372
}
365373

374+
pub fn get_unsigned_int_type_by_size(&self, size: u8) -> IntType<'gcc> {
375+
for native_type in &self.native_int_types {
376+
if native_type.bits == size && !native_type.signed {
377+
return native_type.clone();
378+
}
379+
}
380+
381+
panic!("no native type of size {} found", size);
382+
}
383+
366384
pub fn sess(&self) -> &Session {
367385
&self.tcx.sess
368386
}

0 commit comments

Comments
 (0)