Skip to content

Commit 5cedaa1

Browse files
committed
change implementation of rust intrinsics to use the new api
1 parent 2bdff9e commit 5cedaa1

File tree

6 files changed

+508
-1055
lines changed

6 files changed

+508
-1055
lines changed

compiler/rustc_codegen_llvm/src/abi.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -405,10 +405,10 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
405405
let actual_return_ty = self.llvm_return_type(cx);
406406
let actual_argument_tys = self.llvm_argument_types(cx);
407407

408-
if name.starts_with(b"llvm.")
409-
&& let Some((intrinsic, type_params)) = cx.parse_intrinsic_name(name)
410-
{
411-
let fn_ty = cx.intrinsic_type(intrinsic, &type_params);
408+
if name.starts_with(b"llvm.") {
409+
let Some((fn_ty, _)) = cx.get_intrinsic_from_name(name) else {
410+
todo!("Invalid LLVM intrinsic name `{}`", str::from_utf8(name).unwrap());
411+
};
412412

413413
let expected_return_ty = cx.get_return_type(fn_ty);
414414
let expected_argument_tys = cx.func_params_types(fn_ty);

compiler/rustc_codegen_llvm/src/builder.rs

Lines changed: 100 additions & 124 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,6 @@ impl<'a, 'll> SBuilder<'a, 'll> {
6767
) -> &'ll Value {
6868
debug!("call {:?} with args ({:?})", llfn, args);
6969

70-
let args = self.cast_arguments("call", llty, llfn, args);
7170
let funclet_bundle = funclet.map(|funclet| funclet.bundle());
7271
let mut bundles: SmallVec<[_; 2]> = SmallVec::new();
7372
if let Some(funclet_bundle) = funclet_bundle {
@@ -105,21 +104,7 @@ impl<'a, 'll, CX: Borrow<SCx<'ll>>> GenericBuilder<'a, 'll, CX> {
105104
let vector_type = self.cx.val_ty(val);
106105

107106
assert!(self.cx.type_kind(vector_type) == TypeKind::Vector);
108-
109-
let intrinsic = llvm::Intrinsic::lookup(b"llvm.x86.cast.vector.to.tile".as_ref()).unwrap();
110-
let (fn_ty, f) = self.cx.get_or_declare_intrinsic(intrinsic, &[vector_type]);
111-
unsafe {
112-
llvm::LLVMBuildCallWithOperandBundles(
113-
self.llbuilder,
114-
fn_ty,
115-
f,
116-
[val].as_ptr().cast(),
117-
1,
118-
[].as_ptr(),
119-
0,
120-
c"".as_ptr(),
121-
)
122-
}
107+
self.call_intrinsic("llvm.x86.cast.vector.to.tile", &[vector_type], &[val])
123108
}
124109

125110
pub(crate) fn cast_tile_to_vector(
@@ -130,20 +115,7 @@ impl<'a, 'll, CX: Borrow<SCx<'ll>>> GenericBuilder<'a, 'll, CX> {
130115
assert!(self.cx.val_ty(val) == self.cx.type_x86amx());
131116
assert!(self.cx.type_kind(vector_type) == TypeKind::Vector);
132117

133-
let intrinsic = llvm::Intrinsic::lookup(b"llvm.x86.cast.tile.to.vector").unwrap();
134-
let (fn_ty, f) = self.cx.get_or_declare_intrinsic(intrinsic, &[vector_type]);
135-
unsafe {
136-
llvm::LLVMBuildCallWithOperandBundles(
137-
self.llbuilder,
138-
fn_ty,
139-
f,
140-
[val].as_ptr().cast(),
141-
1,
142-
[].as_ptr(),
143-
0,
144-
c"".as_ptr(),
145-
)
146-
}
118+
self.call_intrinsic("llvm.x86.cast.tile.to.vector", &[vector_type], &[val])
147119
}
148120

149121
pub(crate) fn ret_void(&mut self) {
@@ -546,58 +518,32 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
546518
_ => panic!("tried to get overflow intrinsic for op applied to non-int type"),
547519
};
548520

549-
let name = match oop {
550-
OverflowOp::Add => match new_kind {
551-
Int(I8) => "llvm.sadd.with.overflow.i8",
552-
Int(I16) => "llvm.sadd.with.overflow.i16",
553-
Int(I32) => "llvm.sadd.with.overflow.i32",
554-
Int(I64) => "llvm.sadd.with.overflow.i64",
555-
Int(I128) => "llvm.sadd.with.overflow.i128",
556-
557-
Uint(U8) => "llvm.uadd.with.overflow.i8",
558-
Uint(U16) => "llvm.uadd.with.overflow.i16",
559-
Uint(U32) => "llvm.uadd.with.overflow.i32",
560-
Uint(U64) => "llvm.uadd.with.overflow.i64",
561-
Uint(U128) => "llvm.uadd.with.overflow.i128",
562-
563-
_ => unreachable!(),
564-
},
565-
OverflowOp::Sub => match new_kind {
566-
Int(I8) => "llvm.ssub.with.overflow.i8",
567-
Int(I16) => "llvm.ssub.with.overflow.i16",
568-
Int(I32) => "llvm.ssub.with.overflow.i32",
569-
Int(I64) => "llvm.ssub.with.overflow.i64",
570-
Int(I128) => "llvm.ssub.with.overflow.i128",
571-
572-
Uint(_) => {
573-
// Emit sub and icmp instead of llvm.usub.with.overflow. LLVM considers these
574-
// to be the canonical form. It will attempt to reform llvm.usub.with.overflow
575-
// in the backend if profitable.
576-
let sub = self.sub(lhs, rhs);
577-
let cmp = self.icmp(IntPredicate::IntULT, lhs, rhs);
578-
return (sub, cmp);
579-
}
521+
let (signed, width) = match new_kind {
522+
Int(t) => (true, t.bit_width().unwrap()),
523+
Uint(t) => (false, t.bit_width().unwrap()),
524+
_ => unreachable!(),
525+
};
580526

581-
_ => unreachable!(),
582-
},
583-
OverflowOp::Mul => match new_kind {
584-
Int(I8) => "llvm.smul.with.overflow.i8",
585-
Int(I16) => "llvm.smul.with.overflow.i16",
586-
Int(I32) => "llvm.smul.with.overflow.i32",
587-
Int(I64) => "llvm.smul.with.overflow.i64",
588-
Int(I128) => "llvm.smul.with.overflow.i128",
589-
590-
Uint(U8) => "llvm.umul.with.overflow.i8",
591-
Uint(U16) => "llvm.umul.with.overflow.i16",
592-
Uint(U32) => "llvm.umul.with.overflow.i32",
593-
Uint(U64) => "llvm.umul.with.overflow.i64",
594-
Uint(U128) => "llvm.umul.with.overflow.i128",
595-
596-
_ => unreachable!(),
597-
},
527+
if let OverflowOp::Sub = oop
528+
&& !signed
529+
{
530+
// Emit sub and icmp instead of llvm.usub.with.overflow. LLVM considers these
531+
// to be the canonical form. It will attempt to reform llvm.usub.with.overflow
532+
// in the backend if profitable.
533+
let sub = self.sub(lhs, rhs);
534+
let cmp = self.icmp(IntPredicate::IntULT, lhs, rhs);
535+
return (sub, cmp);
536+
}
537+
538+
let op = match oop {
539+
OverflowOp::Add => "add",
540+
OverflowOp::Sub => "sub",
541+
OverflowOp::Mul => "mul",
598542
};
599543

600-
let res = self.call_intrinsic(name, &[lhs, rhs]);
544+
let llvm_intrinsic = format!("llvm.{}{}.with.overflow", if signed { 's' } else { 'u' }, op);
545+
546+
let res = self.call_intrinsic(&llvm_intrinsic, &[self.type_ix(width)], &[lhs, rhs]);
601547
(self.extract_value(res, 0), self.extract_value(res, 1))
602548
}
603549

@@ -1028,15 +974,12 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
1028974
if self.cx.type_kind(src_ty) != TypeKind::Vector {
1029975
let float_width = self.cx.float_width(src_ty);
1030976
let int_width = self.cx.int_width(dest_ty);
1031-
let name = match (int_width, float_width) {
1032-
(32, 32) => Some("llvm.wasm.trunc.unsigned.i32.f32"),
1033-
(32, 64) => Some("llvm.wasm.trunc.unsigned.i32.f64"),
1034-
(64, 32) => Some("llvm.wasm.trunc.unsigned.i64.f32"),
1035-
(64, 64) => Some("llvm.wasm.trunc.unsigned.i64.f64"),
1036-
_ => None,
1037-
};
1038-
if let Some(name) = name {
1039-
return self.call_intrinsic(name, &[val]);
977+
if matches!((int_width, float_width), (32 | 64, 32 | 64)) {
978+
return self.call_intrinsic(
979+
"llvm.wasm.trunc.unsigned",
980+
&[dest_ty, src_ty],
981+
&[val],
982+
);
1040983
}
1041984
}
1042985
}
@@ -1050,15 +993,12 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
1050993
if self.cx.type_kind(src_ty) != TypeKind::Vector {
1051994
let float_width = self.cx.float_width(src_ty);
1052995
let int_width = self.cx.int_width(dest_ty);
1053-
let name = match (int_width, float_width) {
1054-
(32, 32) => Some("llvm.wasm.trunc.signed.i32.f32"),
1055-
(32, 64) => Some("llvm.wasm.trunc.signed.i32.f64"),
1056-
(64, 32) => Some("llvm.wasm.trunc.signed.i64.f32"),
1057-
(64, 64) => Some("llvm.wasm.trunc.signed.i64.f64"),
1058-
_ => None,
1059-
};
1060-
if let Some(name) = name {
1061-
return self.call_intrinsic(name, &[val]);
996+
if matches!((int_width, float_width), (32 | 64, 32 | 64)) {
997+
return self.call_intrinsic(
998+
"llvm.wasm.trunc.signed",
999+
&[dest_ty, src_ty],
1000+
&[val],
1001+
);
10621002
}
10631003
}
10641004
}
@@ -1131,22 +1071,9 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
11311071
return None;
11321072
}
11331073

1134-
let name = match (ty.is_signed(), ty.primitive_size(self.tcx).bits()) {
1135-
(true, 8) => "llvm.scmp.i8.i8",
1136-
(true, 16) => "llvm.scmp.i8.i16",
1137-
(true, 32) => "llvm.scmp.i8.i32",
1138-
(true, 64) => "llvm.scmp.i8.i64",
1139-
(true, 128) => "llvm.scmp.i8.i128",
1140-
1141-
(false, 8) => "llvm.ucmp.i8.i8",
1142-
(false, 16) => "llvm.ucmp.i8.i16",
1143-
(false, 32) => "llvm.ucmp.i8.i32",
1144-
(false, 64) => "llvm.ucmp.i8.i64",
1145-
(false, 128) => "llvm.ucmp.i8.i128",
1146-
1147-
_ => bug!("three-way compare unsupported for type {ty:?}"),
1148-
};
1149-
Some(self.call_intrinsic(name, &[lhs, rhs]))
1074+
let (width, signed) = ty.int_size_and_signed(self.tcx);
1075+
let llvm_intrinsic = format!("llvm.{}cmp", if signed { 's' } else { 'u' });
1076+
Some(self.call_intrinsic(&llvm_intrinsic, &[self.type_ix(width.bits())], &[lhs, rhs]))
11501077
}
11511078

11521079
/* Miscellaneous instructions */
@@ -1432,11 +1359,11 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
14321359
}
14331360

14341361
fn lifetime_start(&mut self, ptr: &'ll Value, size: Size) {
1435-
self.call_lifetime_intrinsic("llvm.lifetime.start.p0i8", ptr, size);
1362+
self.call_lifetime_intrinsic("llvm.lifetime.start", ptr, size);
14361363
}
14371364

14381365
fn lifetime_end(&mut self, ptr: &'ll Value, size: Size) {
1439-
self.call_lifetime_intrinsic("llvm.lifetime.end.p0i8", ptr, size);
1366+
self.call_lifetime_intrinsic("llvm.lifetime.end", ptr, size);
14401367
}
14411368

14421369
fn call(
@@ -1645,6 +1572,29 @@ impl<'a, 'll, CX: Borrow<SCx<'ll>>> GenericBuilder<'a, 'll, CX> {
16451572
ret.expect("LLVM does not have support for catchret")
16461573
}
16471574

1575+
pub(crate) fn call_intrinsic(
1576+
&mut self,
1577+
base_name: &str,
1578+
type_params: &[&'ll Type],
1579+
args: &[&'ll Value],
1580+
) -> &'ll Value {
1581+
let intrinsic = llvm::Intrinsic::lookup(base_name.as_bytes())
1582+
.unwrap_or_else(|| bug!("Intrinsic `{base_name}` not found"));
1583+
let (fn_ty, llfn) = self.cx.get_intrinsic(intrinsic, type_params);
1584+
unsafe {
1585+
llvm::LLVMBuildCallWithOperandBundles(
1586+
self.llbuilder,
1587+
fn_ty,
1588+
llfn,
1589+
args.as_ptr(),
1590+
args.len().try_into().unwrap(),
1591+
[].as_ptr(),
1592+
0,
1593+
c"".as_ptr(),
1594+
)
1595+
}
1596+
}
1597+
16481598
fn cast_arguments<'b>(
16491599
&mut self,
16501600
typ: &str,
@@ -1696,11 +1646,6 @@ impl<'a, 'll, CX: Borrow<SCx<'ll>>> GenericBuilder<'a, 'll, CX> {
16961646
}
16971647

16981648
impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
1699-
pub(crate) fn call_intrinsic(&mut self, intrinsic: &str, args: &[&'ll Value]) -> &'ll Value {
1700-
let (ty, f) = self.cx.get_intrinsic(intrinsic);
1701-
self.call(ty, None, None, f, args, None, None)
1702-
}
1703-
17041649
fn call_lifetime_intrinsic(&mut self, intrinsic: &str, ptr: &'ll Value, size: Size) {
17051650
let size = size.bytes();
17061651
if size == 0 {
@@ -1711,7 +1656,7 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
17111656
return;
17121657
}
17131658

1714-
self.call_intrinsic(intrinsic, &[self.cx.const_u64(size), ptr]);
1659+
self.call_intrinsic(intrinsic, &[self.type_ptr()], &[self.cx.const_u64(size), ptr]);
17151660
}
17161661
}
17171662
impl<'a, 'll, CX: Borrow<SCx<'ll>>> GenericBuilder<'a, 'll, CX> {
@@ -1736,6 +1681,37 @@ impl<'a, 'll, CX: Borrow<SCx<'ll>>> GenericBuilder<'a, 'll, CX> {
17361681
}
17371682
}
17381683
impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
1684+
pub(crate) fn memcmp(
1685+
&mut self,
1686+
ptr1: &'ll Value,
1687+
ptr2: &'ll Value,
1688+
num: &'ll Value,
1689+
) -> &'ll Value {
1690+
let llreturn_ty = match self.sess().target.arch.as_ref() {
1691+
"avr" | "msp430" => self.type_i16(),
1692+
_ => self.type_i32(),
1693+
};
1694+
let fn_ty =
1695+
self.type_func(&[self.type_ptr(), self.type_ptr(), self.type_isize()], llreturn_ty);
1696+
1697+
let llfn = self
1698+
.get_function("memcmp")
1699+
.unwrap_or_else(|| self.declare_cfn("memcmp", llvm::UnnamedAddr::No, fn_ty));
1700+
1701+
unsafe {
1702+
llvm::LLVMBuildCallWithOperandBundles(
1703+
self.llbuilder,
1704+
fn_ty,
1705+
llfn,
1706+
[ptr1, ptr2, num].as_ptr(),
1707+
3,
1708+
[].as_ptr(),
1709+
0,
1710+
c"".as_ptr(),
1711+
)
1712+
}
1713+
}
1714+
17391715
fn fptoint_sat(&mut self, signed: bool, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value {
17401716
let src_ty = self.cx.val_ty(val);
17411717
let (float_ty, int_ty, vector_length) = if self.cx.type_kind(src_ty) == TypeKind::Vector {
@@ -1958,7 +1934,7 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
19581934
num_counters: &'ll Value,
19591935
index: &'ll Value,
19601936
) {
1961-
self.call_intrinsic("llvm.instrprof.increment", &[fn_name, hash, num_counters, index]);
1937+
self.call_intrinsic("llvm.instrprof.increment", &[], &[fn_name, hash, num_counters, index]);
19621938
}
19631939

19641940
/// Emits a call to `llvm.instrprof.mcdc.parameters`.
@@ -1977,7 +1953,7 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
19771953
hash: &'ll Value,
19781954
bitmap_bits: &'ll Value,
19791955
) {
1980-
self.call_intrinsic("llvm.instrprof.mcdc.parameters", &[fn_name, hash, bitmap_bits]);
1956+
self.call_intrinsic("llvm.instrprof.mcdc.parameters", &[], &[fn_name, hash, bitmap_bits]);
19811957
}
19821958

19831959
#[instrument(level = "debug", skip(self))]
@@ -1989,7 +1965,7 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
19891965
mcdc_temp: &'ll Value,
19901966
) {
19911967
let args = &[fn_name, hash, bitmap_index, mcdc_temp];
1992-
self.call_intrinsic("llvm.instrprof.mcdc.tvbitmap.update", args);
1968+
self.call_intrinsic("llvm.instrprof.mcdc.tvbitmap.update", &[], args);
19931969
}
19941970

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

0 commit comments

Comments
 (0)