Skip to content

Commit ea453f7

Browse files
committed
Simplify implementation of Rust intrinsics by using type parameters in the cache
1 parent 14863ea commit ea453f7

File tree

8 files changed

+484
-828
lines changed

8 files changed

+484
-828
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: 51 additions & 132 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,
@@ -484,73 +483,31 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
484483
fn checked_binop(
485484
&mut self,
486485
oop: OverflowOp,
487-
ty: Ty<'_>,
486+
ty: Ty<'tcx>,
488487
lhs: Self::Value,
489488
rhs: Self::Value,
490489
) -> (Self::Value, Self::Value) {
491-
use rustc_middle::ty::IntTy::*;
492-
use rustc_middle::ty::UintTy::*;
493-
use rustc_middle::ty::{Int, Uint};
494-
495-
let new_kind = match ty.kind() {
496-
Int(t @ Isize) => Int(t.normalize(self.tcx.sess.target.pointer_width)),
497-
Uint(t @ Usize) => Uint(t.normalize(self.tcx.sess.target.pointer_width)),
498-
t @ (Uint(_) | Int(_)) => *t,
499-
_ => panic!("tried to get overflow intrinsic for op applied to non-int type"),
490+
let (size, signed) = ty.int_size_and_signed(self.tcx);
491+
let width = size.bits();
492+
493+
if oop == OverflowOp::Sub && !signed {
494+
// Emit sub and icmp instead of llvm.usub.with.overflow. LLVM considers these
495+
// to be the canonical form. It will attempt to reform llvm.usub.with.overflow
496+
// in the backend if profitable.
497+
let sub = self.sub(lhs, rhs);
498+
let cmp = self.icmp(IntPredicate::IntULT, lhs, rhs);
499+
return (sub, cmp);
500+
}
501+
502+
let oop_str = match oop {
503+
OverflowOp::Add => "add",
504+
OverflowOp::Sub => "sub",
505+
OverflowOp::Mul => "mul",
500506
};
501507

502-
let name = match oop {
503-
OverflowOp::Add => match new_kind {
504-
Int(I8) => "llvm.sadd.with.overflow.i8",
505-
Int(I16) => "llvm.sadd.with.overflow.i16",
506-
Int(I32) => "llvm.sadd.with.overflow.i32",
507-
Int(I64) => "llvm.sadd.with.overflow.i64",
508-
Int(I128) => "llvm.sadd.with.overflow.i128",
509-
510-
Uint(U8) => "llvm.uadd.with.overflow.i8",
511-
Uint(U16) => "llvm.uadd.with.overflow.i16",
512-
Uint(U32) => "llvm.uadd.with.overflow.i32",
513-
Uint(U64) => "llvm.uadd.with.overflow.i64",
514-
Uint(U128) => "llvm.uadd.with.overflow.i128",
515-
516-
_ => unreachable!(),
517-
},
518-
OverflowOp::Sub => match new_kind {
519-
Int(I8) => "llvm.ssub.with.overflow.i8",
520-
Int(I16) => "llvm.ssub.with.overflow.i16",
521-
Int(I32) => "llvm.ssub.with.overflow.i32",
522-
Int(I64) => "llvm.ssub.with.overflow.i64",
523-
Int(I128) => "llvm.ssub.with.overflow.i128",
524-
525-
Uint(_) => {
526-
// Emit sub and icmp instead of llvm.usub.with.overflow. LLVM considers these
527-
// to be the canonical form. It will attempt to reform llvm.usub.with.overflow
528-
// in the backend if profitable.
529-
let sub = self.sub(lhs, rhs);
530-
let cmp = self.icmp(IntPredicate::IntULT, lhs, rhs);
531-
return (sub, cmp);
532-
}
533-
534-
_ => unreachable!(),
535-
},
536-
OverflowOp::Mul => match new_kind {
537-
Int(I8) => "llvm.smul.with.overflow.i8",
538-
Int(I16) => "llvm.smul.with.overflow.i16",
539-
Int(I32) => "llvm.smul.with.overflow.i32",
540-
Int(I64) => "llvm.smul.with.overflow.i64",
541-
Int(I128) => "llvm.smul.with.overflow.i128",
542-
543-
Uint(U8) => "llvm.umul.with.overflow.i8",
544-
Uint(U16) => "llvm.umul.with.overflow.i16",
545-
Uint(U32) => "llvm.umul.with.overflow.i32",
546-
Uint(U64) => "llvm.umul.with.overflow.i64",
547-
Uint(U128) => "llvm.umul.with.overflow.i128",
548-
549-
_ => unreachable!(),
550-
},
551-
};
508+
let name = format!("llvm.{}{oop_str}.with.overflow", if signed { 's' } else { 'u' });
552509

553-
let res = self.call_intrinsic(name, &[lhs, rhs]);
510+
let res = self.call_intrinsic(&name, &[self.type_ix(width)], &[lhs, rhs]);
554511
(self.extract_value(res, 0), self.extract_value(res, 1))
555512
}
556513

@@ -954,11 +911,11 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
954911
}
955912

956913
fn fptoui_sat(&mut self, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value {
957-
self.fptoint_sat(false, val, dest_ty)
914+
self.call_intrinsic("llvm.fptoui.sat", &[dest_ty, self.val_ty(val)], &[val])
958915
}
959916

960917
fn fptosi_sat(&mut self, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value {
961-
self.fptoint_sat(true, val, dest_ty)
918+
self.call_intrinsic("llvm.fptosi.sat", &[dest_ty, self.val_ty(val)], &[val])
962919
}
963920

964921
fn fptoui(&mut self, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value {
@@ -981,15 +938,12 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
981938
if self.cx.type_kind(src_ty) != TypeKind::Vector {
982939
let float_width = self.cx.float_width(src_ty);
983940
let int_width = self.cx.int_width(dest_ty);
984-
let name = match (int_width, float_width) {
985-
(32, 32) => Some("llvm.wasm.trunc.unsigned.i32.f32"),
986-
(32, 64) => Some("llvm.wasm.trunc.unsigned.i32.f64"),
987-
(64, 32) => Some("llvm.wasm.trunc.unsigned.i64.f32"),
988-
(64, 64) => Some("llvm.wasm.trunc.unsigned.i64.f64"),
989-
_ => None,
990-
};
991-
if let Some(name) = name {
992-
return self.call_intrinsic(name, &[val]);
941+
if matches!((int_width, float_width), (32 | 64, 32 | 64)) {
942+
return self.call_intrinsic(
943+
"llvm.wasm.trunc.unsigned",
944+
&[dest_ty, src_ty],
945+
&[val],
946+
);
993947
}
994948
}
995949
}
@@ -1003,15 +957,12 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
1003957
if self.cx.type_kind(src_ty) != TypeKind::Vector {
1004958
let float_width = self.cx.float_width(src_ty);
1005959
let int_width = self.cx.int_width(dest_ty);
1006-
let name = match (int_width, float_width) {
1007-
(32, 32) => Some("llvm.wasm.trunc.signed.i32.f32"),
1008-
(32, 64) => Some("llvm.wasm.trunc.signed.i32.f64"),
1009-
(64, 32) => Some("llvm.wasm.trunc.signed.i64.f32"),
1010-
(64, 64) => Some("llvm.wasm.trunc.signed.i64.f64"),
1011-
_ => None,
1012-
};
1013-
if let Some(name) = name {
1014-
return self.call_intrinsic(name, &[val]);
960+
if matches!((int_width, float_width), (32 | 64, 32 | 64)) {
961+
return self.call_intrinsic(
962+
"llvm.wasm.trunc.signed",
963+
&[dest_ty, src_ty],
964+
&[val],
965+
);
1015966
}
1016967
}
1017968
}
@@ -1084,22 +1035,10 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
10841035
return None;
10851036
}
10861037

1087-
let name = match (ty.is_signed(), ty.primitive_size(self.tcx).bits()) {
1088-
(true, 8) => "llvm.scmp.i8.i8",
1089-
(true, 16) => "llvm.scmp.i8.i16",
1090-
(true, 32) => "llvm.scmp.i8.i32",
1091-
(true, 64) => "llvm.scmp.i8.i64",
1092-
(true, 128) => "llvm.scmp.i8.i128",
1093-
1094-
(false, 8) => "llvm.ucmp.i8.i8",
1095-
(false, 16) => "llvm.ucmp.i8.i16",
1096-
(false, 32) => "llvm.ucmp.i8.i32",
1097-
(false, 64) => "llvm.ucmp.i8.i64",
1098-
(false, 128) => "llvm.ucmp.i8.i128",
1038+
let size = ty.primitive_size(self.tcx);
1039+
let name = if ty.is_signed() { "llvm.scmp" } else { "llvm.ucmp" };
10991040

1100-
_ => bug!("three-way compare unsupported for type {ty:?}"),
1101-
};
1102-
Some(self.call_intrinsic(name, &[lhs, rhs]))
1041+
Some(self.call_intrinsic(&name, &[self.type_i8(), self.type_ix(size.bits())], &[lhs, rhs]))
11031042
}
11041043

11051044
/* Miscellaneous instructions */
@@ -1385,11 +1324,11 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
13851324
}
13861325

13871326
fn lifetime_start(&mut self, ptr: &'ll Value, size: Size) {
1388-
self.call_lifetime_intrinsic("llvm.lifetime.start.p0i8", ptr, size);
1327+
self.call_lifetime_intrinsic("llvm.lifetime.start", ptr, size);
13891328
}
13901329

13911330
fn lifetime_end(&mut self, ptr: &'ll Value, size: Size) {
1392-
self.call_lifetime_intrinsic("llvm.lifetime.end.p0i8", ptr, size);
1331+
self.call_lifetime_intrinsic("llvm.lifetime.end", ptr, size);
13931332
}
13941333

13951334
fn call(
@@ -1454,7 +1393,7 @@ impl<'ll> StaticBuilderMethods for Builder<'_, 'll, '_> {
14541393
// Forward to the `get_static` method of `CodegenCx`
14551394
let global = self.cx().get_static(def_id);
14561395
if self.cx().tcx.is_thread_local_static(def_id) {
1457-
let pointer = self.call_intrinsic("llvm.threadlocal.address", &[global]);
1396+
let pointer = self.call_intrinsic("llvm.threadlocal.address", &[], &[global]);
14581397
// Cast to default address space if globals are in a different addrspace
14591398
self.pointercast(pointer, self.type_ptr())
14601399
} else {
@@ -1649,8 +1588,13 @@ impl<'a, 'll, CX: Borrow<SCx<'ll>>> GenericBuilder<'a, 'll, CX> {
16491588
}
16501589

16511590
impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
1652-
pub(crate) fn call_intrinsic(&mut self, intrinsic: &str, args: &[&'ll Value]) -> &'ll Value {
1653-
let (ty, f) = self.cx.get_intrinsic(intrinsic);
1591+
pub(crate) fn call_intrinsic(
1592+
&mut self,
1593+
base_name: &str,
1594+
type_params: &[&'ll Type],
1595+
args: &[&'ll Value],
1596+
) -> &'ll Value {
1597+
let (ty, f) = self.cx.get_intrinsic(base_name, type_params);
16541598
self.call(ty, None, None, f, args, None, None)
16551599
}
16561600

@@ -1664,7 +1608,7 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
16641608
return;
16651609
}
16661610

1667-
self.call_intrinsic(intrinsic, &[self.cx.const_u64(size), ptr]);
1611+
self.call_intrinsic(intrinsic, &[self.type_ptr()], &[self.cx.const_u64(size), ptr]);
16681612
}
16691613
}
16701614
impl<'a, 'll, CX: Borrow<SCx<'ll>>> GenericBuilder<'a, 'll, CX> {
@@ -1689,31 +1633,6 @@ impl<'a, 'll, CX: Borrow<SCx<'ll>>> GenericBuilder<'a, 'll, CX> {
16891633
}
16901634
}
16911635
impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
1692-
fn fptoint_sat(&mut self, signed: bool, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value {
1693-
let src_ty = self.cx.val_ty(val);
1694-
let (float_ty, int_ty, vector_length) = if self.cx.type_kind(src_ty) == TypeKind::Vector {
1695-
assert_eq!(self.cx.vector_length(src_ty), self.cx.vector_length(dest_ty));
1696-
(
1697-
self.cx.element_type(src_ty),
1698-
self.cx.element_type(dest_ty),
1699-
Some(self.cx.vector_length(src_ty)),
1700-
)
1701-
} else {
1702-
(src_ty, dest_ty, None)
1703-
};
1704-
let float_width = self.cx.float_width(float_ty);
1705-
let int_width = self.cx.int_width(int_ty);
1706-
1707-
let instr = if signed { "fptosi" } else { "fptoui" };
1708-
let name = if let Some(vector_length) = vector_length {
1709-
format!("llvm.{instr}.sat.v{vector_length}i{int_width}.v{vector_length}f{float_width}")
1710-
} else {
1711-
format!("llvm.{instr}.sat.i{int_width}.f{float_width}")
1712-
};
1713-
let f = self.declare_cfn(&name, llvm::UnnamedAddr::No, self.type_func(&[src_ty], dest_ty));
1714-
self.call(self.type_func(&[src_ty], dest_ty), None, None, f, &[val], None, None)
1715-
}
1716-
17171636
pub(crate) fn landing_pad(
17181637
&mut self,
17191638
ty: &'ll Type,
@@ -1819,7 +1738,7 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
18191738
// llvm.type.test intrinsic. The LowerTypeTests link-time optimization pass replaces
18201739
// calls to this intrinsic with code to test type membership.
18211740
let typeid = self.get_metadata_value(typeid_metadata);
1822-
let cond = self.call_intrinsic("llvm.type.test", &[llfn, typeid]);
1741+
let cond = self.call_intrinsic("llvm.type.test", &[], &[llfn, typeid]);
18231742
let bb_pass = self.append_sibling_block("type_test.pass");
18241743
let bb_fail = self.append_sibling_block("type_test.fail");
18251744
self.cond_br(cond, bb_pass, bb_fail);
@@ -1887,7 +1806,7 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
18871806
num_counters: &'ll Value,
18881807
index: &'ll Value,
18891808
) {
1890-
self.call_intrinsic("llvm.instrprof.increment", &[fn_name, hash, num_counters, index]);
1809+
self.call_intrinsic("llvm.instrprof.increment", &[], &[fn_name, hash, num_counters, index]);
18911810
}
18921811

18931812
/// Emits a call to `llvm.instrprof.mcdc.parameters`.
@@ -1906,7 +1825,7 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
19061825
hash: &'ll Value,
19071826
bitmap_bits: &'ll Value,
19081827
) {
1909-
self.call_intrinsic("llvm.instrprof.mcdc.parameters", &[fn_name, hash, bitmap_bits]);
1828+
self.call_intrinsic("llvm.instrprof.mcdc.parameters", &[], &[fn_name, hash, bitmap_bits]);
19101829
}
19111830

19121831
#[instrument(level = "debug", skip(self))]
@@ -1918,7 +1837,7 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
19181837
mcdc_temp: &'ll Value,
19191838
) {
19201839
let args = &[fn_name, hash, bitmap_index, mcdc_temp];
1921-
self.call_intrinsic("llvm.instrprof.mcdc.tvbitmap.update", args);
1840+
self.call_intrinsic("llvm.instrprof.mcdc.tvbitmap.update", &[], args);
19221841
}
19231842

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

0 commit comments

Comments
 (0)