Skip to content

Commit 9b01f48

Browse files
committed
Simplify implementation of Rust intrinsics by using type parameters the cache
1 parent 95d66be commit 9b01f48

File tree

8 files changed

+453
-822
lines changed

8 files changed

+453
-822
lines changed

compiler/rustc_codegen_gcc/src/builder.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -897,7 +897,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
897897
fn checked_binop(
898898
&mut self,
899899
oop: OverflowOp,
900-
typ: Ty<'_>,
900+
typ: Ty<'tcx>,
901901
lhs: Self::Value,
902902
rhs: Self::Value,
903903
) -> (Self::Value, Self::Value) {

compiler/rustc_codegen_llvm/src/builder.rs

Lines changed: 41 additions & 125 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ use rustc_codegen_ssa::mir::place::PlaceRef;
1414
use rustc_codegen_ssa::traits::*;
1515
use rustc_data_structures::small_c_str::SmallCStr;
1616
use rustc_hir::def_id::DefId;
17-
use rustc_middle::bug;
1817
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs;
1918
use rustc_middle::ty::layout::{
2019
FnAbiError, FnAbiOfHelpers, FnAbiRequest, HasTypingEnv, LayoutError, LayoutOfHelpers,
@@ -485,73 +484,28 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
485484
fn checked_binop(
486485
&mut self,
487486
oop: OverflowOp,
488-
ty: Ty<'_>,
487+
ty: Ty<'tcx>,
489488
lhs: Self::Value,
490489
rhs: Self::Value,
491490
) -> (Self::Value, Self::Value) {
492-
use rustc_middle::ty::IntTy::*;
493-
use rustc_middle::ty::UintTy::*;
494-
use rustc_middle::ty::{Int, Uint};
495-
496-
let new_kind = match ty.kind() {
497-
Int(t @ Isize) => Int(t.normalize(self.tcx.sess.target.pointer_width)),
498-
Uint(t @ Usize) => Uint(t.normalize(self.tcx.sess.target.pointer_width)),
499-
t @ (Uint(_) | Int(_)) => *t,
500-
_ => panic!("tried to get overflow intrinsic for op applied to non-int type"),
501-
};
491+
let (size, signed) = ty.int_size_and_signed(self.tcx);
492+
let width = size.bits();
502493

503-
let name = match oop {
504-
OverflowOp::Add => match new_kind {
505-
Int(I8) => "llvm.sadd.with.overflow.i8",
506-
Int(I16) => "llvm.sadd.with.overflow.i16",
507-
Int(I32) => "llvm.sadd.with.overflow.i32",
508-
Int(I64) => "llvm.sadd.with.overflow.i64",
509-
Int(I128) => "llvm.sadd.with.overflow.i128",
510-
511-
Uint(U8) => "llvm.uadd.with.overflow.i8",
512-
Uint(U16) => "llvm.uadd.with.overflow.i16",
513-
Uint(U32) => "llvm.uadd.with.overflow.i32",
514-
Uint(U64) => "llvm.uadd.with.overflow.i64",
515-
Uint(U128) => "llvm.uadd.with.overflow.i128",
516-
517-
_ => unreachable!(),
518-
},
519-
OverflowOp::Sub => match new_kind {
520-
Int(I8) => "llvm.ssub.with.overflow.i8",
521-
Int(I16) => "llvm.ssub.with.overflow.i16",
522-
Int(I32) => "llvm.ssub.with.overflow.i32",
523-
Int(I64) => "llvm.ssub.with.overflow.i64",
524-
Int(I128) => "llvm.ssub.with.overflow.i128",
525-
526-
Uint(_) => {
527-
// Emit sub and icmp instead of llvm.usub.with.overflow. LLVM considers these
528-
// to be the canonical form. It will attempt to reform llvm.usub.with.overflow
529-
// in the backend if profitable.
494+
if oop == OverflowOp::Sub && !signed {
530495
let sub = self.sub(lhs, rhs);
531496
let cmp = self.icmp(IntPredicate::IntULT, lhs, rhs);
532497
return (sub, cmp);
533498
}
534499

535-
_ => unreachable!(),
536-
},
537-
OverflowOp::Mul => match new_kind {
538-
Int(I8) => "llvm.smul.with.overflow.i8",
539-
Int(I16) => "llvm.smul.with.overflow.i16",
540-
Int(I32) => "llvm.smul.with.overflow.i32",
541-
Int(I64) => "llvm.smul.with.overflow.i64",
542-
Int(I128) => "llvm.smul.with.overflow.i128",
543-
544-
Uint(U8) => "llvm.umul.with.overflow.i8",
545-
Uint(U16) => "llvm.umul.with.overflow.i16",
546-
Uint(U32) => "llvm.umul.with.overflow.i32",
547-
Uint(U64) => "llvm.umul.with.overflow.i64",
548-
Uint(U128) => "llvm.umul.with.overflow.i128",
549-
550-
_ => unreachable!(),
551-
},
500+
let oop_str = match oop {
501+
OverflowOp::Add => "add",
502+
OverflowOp::Sub => "sub",
503+
OverflowOp::Mul => "mul",
552504
};
553505

554-
let res = self.call_intrinsic(name, &[lhs, rhs]);
506+
let name = format!("llvm.{}{oop_str}.with.overflow", if signed { 's' } else { 'u' });
507+
508+
let res = self.call_intrinsic(&name, &[self.type_ix(width)], &[lhs, rhs]);
555509
(self.extract_value(res, 0), self.extract_value(res, 1))
556510
}
557511

@@ -955,11 +909,11 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
955909
}
956910

957911
fn fptoui_sat(&mut self, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value {
958-
self.fptoint_sat(false, val, dest_ty)
912+
self.call_intrinsic("llvm.fptoui.sat", &[dest_ty, self.val_ty(val)], &[val])
959913
}
960914

961915
fn fptosi_sat(&mut self, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value {
962-
self.fptoint_sat(true, val, dest_ty)
916+
self.call_intrinsic("llvm.fptosi.sat", &[dest_ty, self.val_ty(val)], &[val])
963917
}
964918

965919
fn fptoui(&mut self, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value {
@@ -982,15 +936,12 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
982936
if self.cx.type_kind(src_ty) != TypeKind::Vector {
983937
let float_width = self.cx.float_width(src_ty);
984938
let int_width = self.cx.int_width(dest_ty);
985-
let name = match (int_width, float_width) {
986-
(32, 32) => Some("llvm.wasm.trunc.unsigned.i32.f32"),
987-
(32, 64) => Some("llvm.wasm.trunc.unsigned.i32.f64"),
988-
(64, 32) => Some("llvm.wasm.trunc.unsigned.i64.f32"),
989-
(64, 64) => Some("llvm.wasm.trunc.unsigned.i64.f64"),
990-
_ => None,
991-
};
992-
if let Some(name) = name {
993-
return self.call_intrinsic(name, &[val]);
939+
if matches!((int_width, float_width), (32 | 64, 32 | 64)) {
940+
return self.call_intrinsic(
941+
"llvm.wasm.trunc.unsigned",
942+
&[dest_ty, src_ty],
943+
&[val],
944+
);
994945
}
995946
}
996947
}
@@ -1004,15 +955,12 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
1004955
if self.cx.type_kind(src_ty) != TypeKind::Vector {
1005956
let float_width = self.cx.float_width(src_ty);
1006957
let int_width = self.cx.int_width(dest_ty);
1007-
let name = match (int_width, float_width) {
1008-
(32, 32) => Some("llvm.wasm.trunc.signed.i32.f32"),
1009-
(32, 64) => Some("llvm.wasm.trunc.signed.i32.f64"),
1010-
(64, 32) => Some("llvm.wasm.trunc.signed.i64.f32"),
1011-
(64, 64) => Some("llvm.wasm.trunc.signed.i64.f64"),
1012-
_ => None,
1013-
};
1014-
if let Some(name) = name {
1015-
return self.call_intrinsic(name, &[val]);
958+
if matches!((int_width, float_width), (32 | 64, 32 | 64)) {
959+
return self.call_intrinsic(
960+
"llvm.wasm.trunc.signed",
961+
&[dest_ty, src_ty],
962+
&[val],
963+
);
1016964
}
1017965
}
1018966
}
@@ -1085,22 +1033,10 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
10851033
return None;
10861034
}
10871035

1088-
let name = match (ty.is_signed(), ty.primitive_size(self.tcx).bits()) {
1089-
(true, 8) => "llvm.scmp.i8.i8",
1090-
(true, 16) => "llvm.scmp.i8.i16",
1091-
(true, 32) => "llvm.scmp.i8.i32",
1092-
(true, 64) => "llvm.scmp.i8.i64",
1093-
(true, 128) => "llvm.scmp.i8.i128",
1036+
let size = ty.primitive_size(self.tcx);
1037+
let name = if ty.is_signed() { "llvm.scmp" } else { "llvm.ucmp" };
10941038

1095-
(false, 8) => "llvm.ucmp.i8.i8",
1096-
(false, 16) => "llvm.ucmp.i8.i16",
1097-
(false, 32) => "llvm.ucmp.i8.i32",
1098-
(false, 64) => "llvm.ucmp.i8.i64",
1099-
(false, 128) => "llvm.ucmp.i8.i128",
1100-
1101-
_ => bug!("three-way compare unsupported for type {ty:?}"),
1102-
};
1103-
Some(self.call_intrinsic(name, &[lhs, rhs]))
1039+
Some(self.call_intrinsic(&name, &[self.type_i8(), self.type_ix(size.bits())], &[lhs, rhs]))
11041040
}
11051041

11061042
/* Miscellaneous instructions */
@@ -1386,11 +1322,11 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
13861322
}
13871323

13881324
fn lifetime_start(&mut self, ptr: &'ll Value, size: Size) {
1389-
self.call_lifetime_intrinsic("llvm.lifetime.start.p0i8", ptr, size);
1325+
self.call_lifetime_intrinsic("llvm.lifetime.start", ptr, size);
13901326
}
13911327

13921328
fn lifetime_end(&mut self, ptr: &'ll Value, size: Size) {
1393-
self.call_lifetime_intrinsic("llvm.lifetime.end.p0i8", ptr, size);
1329+
self.call_lifetime_intrinsic("llvm.lifetime.end", ptr, size);
13941330
}
13951331

13961332
fn call(
@@ -1605,8 +1541,13 @@ impl<'a, 'll, CX: Borrow<SCx<'ll>>> GenericBuilder<'a, 'll, CX> {
16051541
}
16061542

16071543
impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
1608-
pub(crate) fn call_intrinsic(&mut self, intrinsic: &str, args: &[&'ll Value]) -> &'ll Value {
1609-
let (ty, f) = self.cx.get_intrinsic(intrinsic);
1544+
pub(crate) fn call_intrinsic(
1545+
&mut self,
1546+
base_name: &str,
1547+
type_params: &[&'ll Type],
1548+
args: &[&'ll Value],
1549+
) -> &'ll Value {
1550+
let (ty, f) = self.cx.get_intrinsic(base_name, type_params);
16101551
self.call(ty, None, None, f, args, None, None)
16111552
}
16121553

@@ -1620,7 +1561,7 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
16201561
return;
16211562
}
16221563

1623-
self.call_intrinsic(intrinsic, &[self.cx.const_u64(size), ptr]);
1564+
self.call_intrinsic(intrinsic, &[self.type_ptr()], &[self.cx.const_u64(size), ptr]);
16241565
}
16251566
}
16261567
impl<'a, 'll, CX: Borrow<SCx<'ll>>> GenericBuilder<'a, 'll, CX> {
@@ -1645,31 +1586,6 @@ impl<'a, 'll, CX: Borrow<SCx<'ll>>> GenericBuilder<'a, 'll, CX> {
16451586
}
16461587
}
16471588
impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
1648-
fn fptoint_sat(&mut self, signed: bool, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value {
1649-
let src_ty = self.cx.val_ty(val);
1650-
let (float_ty, int_ty, vector_length) = if self.cx.type_kind(src_ty) == TypeKind::Vector {
1651-
assert_eq!(self.cx.vector_length(src_ty), self.cx.vector_length(dest_ty));
1652-
(
1653-
self.cx.element_type(src_ty),
1654-
self.cx.element_type(dest_ty),
1655-
Some(self.cx.vector_length(src_ty)),
1656-
)
1657-
} else {
1658-
(src_ty, dest_ty, None)
1659-
};
1660-
let float_width = self.cx.float_width(float_ty);
1661-
let int_width = self.cx.int_width(int_ty);
1662-
1663-
let instr = if signed { "fptosi" } else { "fptoui" };
1664-
let name = if let Some(vector_length) = vector_length {
1665-
format!("llvm.{instr}.sat.v{vector_length}i{int_width}.v{vector_length}f{float_width}")
1666-
} else {
1667-
format!("llvm.{instr}.sat.i{int_width}.f{float_width}")
1668-
};
1669-
let f = self.declare_cfn(&name, llvm::UnnamedAddr::No, self.type_func(&[src_ty], dest_ty));
1670-
self.call(self.type_func(&[src_ty], dest_ty), None, None, f, &[val], None, None)
1671-
}
1672-
16731589
fn trunc_int_to_i1_vector(&mut self, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value {
16741590
let vector_length = self.vector_length(dest_ty) as u64;
16751591
let int_width = cmp::max(vector_length.next_power_of_two(), 8);
@@ -1976,7 +1892,7 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
19761892
num_counters: &'ll Value,
19771893
index: &'ll Value,
19781894
) {
1979-
self.call_intrinsic("llvm.instrprof.increment", &[fn_name, hash, num_counters, index]);
1895+
self.call_intrinsic("llvm.instrprof.increment", &[], &[fn_name, hash, num_counters, index]);
19801896
}
19811897

19821898
/// Emits a call to `llvm.instrprof.mcdc.parameters`.
@@ -1995,7 +1911,7 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
19951911
hash: &'ll Value,
19961912
bitmap_bits: &'ll Value,
19971913
) {
1998-
self.call_intrinsic("llvm.instrprof.mcdc.parameters", &[fn_name, hash, bitmap_bits]);
1914+
self.call_intrinsic("llvm.instrprof.mcdc.parameters", &[], &[fn_name, hash, bitmap_bits]);
19991915
}
20001916

20011917
#[instrument(level = "debug", skip(self))]
@@ -2007,7 +1923,7 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
20071923
mcdc_temp: &'ll Value,
20081924
) {
20091925
let args = &[fn_name, hash, bitmap_index, mcdc_temp];
2010-
self.call_intrinsic("llvm.instrprof.mcdc.tvbitmap.update", args);
1926+
self.call_intrinsic("llvm.instrprof.mcdc.tvbitmap.update", &[], args);
20111927
}
20121928

20131929
#[instrument(level = "debug", skip(self))]

0 commit comments

Comments
 (0)