Skip to content

Commit 1695bbf

Browse files
committed
change implementation of rust intrinsics
1 parent 2c12b4a commit 1695bbf

File tree

8 files changed

+382
-895
lines changed

8 files changed

+382
-895
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: 92 additions & 126 deletions
Original file line numberDiff line numberDiff line change
@@ -484,73 +484,30 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
484484
fn checked_binop(
485485
&mut self,
486486
oop: OverflowOp,
487-
ty: Ty<'_>,
487+
ty: Ty<'tcx>,
488488
lhs: Self::Value,
489489
rhs: Self::Value,
490490
) -> (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"),
500-
};
491+
let (width, signed) = ty.int_size_and_signed(self.tcx);
501492

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-
}
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+
}
533501

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-
},
502+
let op = match oop {
503+
OverflowOp::Add => "add",
504+
OverflowOp::Sub => "sub",
505+
OverflowOp::Mul => "mul",
551506
};
552507

553-
let res = self.call_intrinsic(name, &[lhs, rhs]);
508+
let llvm_intrinsic = format!("llvm.{}{op}.with.overflow", if signed { 's' } else { 'u' });
509+
510+
let res = self.call_intrinsic(&llvm_intrinsic, &[self.type_ix(width.bits())], &[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,15 @@ 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",
1099-
1038+
let (signed, llty) = match ty.kind() {
1039+
ty::Int(t) => (true, self.type_int_from_ty(*t)),
1040+
ty::Uint(t) => (false, self.type_uint_from_ty(*t)),
1041+
ty::Char => (false, self.type_i32()),
11001042
_ => bug!("three-way compare unsupported for type {ty:?}"),
11011043
};
1102-
Some(self.call_intrinsic(name, &[lhs, rhs]))
1044+
1045+
let llvm_intrinsic = format!("llvm.{}cmp", if signed { 's' } else { 'u' });
1046+
Some(self.call_intrinsic(&llvm_intrinsic, &[self.type_i8(), llty], &[lhs, rhs]))
11031047
}
11041048

11051049
/* Miscellaneous instructions */
@@ -1385,11 +1329,11 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
13851329
}
13861330

13871331
fn lifetime_start(&mut self, ptr: &'ll Value, size: Size) {
1388-
self.call_lifetime_intrinsic("llvm.lifetime.start.p0i8", ptr, size);
1332+
self.call_lifetime_intrinsic("llvm.lifetime.start", ptr, size);
13891333
}
13901334

13911335
fn lifetime_end(&mut self, ptr: &'ll Value, size: Size) {
1392-
self.call_lifetime_intrinsic("llvm.lifetime.end.p0i8", ptr, size);
1336+
self.call_lifetime_intrinsic("llvm.lifetime.end", ptr, size);
13931337
}
13941338

13951339
fn call(
@@ -1640,14 +1584,41 @@ impl<'a, 'll, CX: Borrow<SCx<'ll>>> GenericBuilder<'a, 'll, CX> {
16401584
pub(crate) fn va_arg(&mut self, list: &'ll Value, ty: &'ll Type) -> &'ll Value {
16411585
unsafe { llvm::LLVMBuildVAArg(self.llbuilder, list, ty, UNNAMED) }
16421586
}
1643-
}
16441587

1645-
impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
1646-
pub(crate) fn call_intrinsic(&mut self, intrinsic: &str, args: &[&'ll Value]) -> &'ll Value {
1647-
let (ty, f) = self.cx.get_intrinsic(intrinsic);
1648-
self.call(ty, None, None, f, args, None, None)
1588+
pub(crate) fn simple_call(
1589+
&mut self,
1590+
fn_ty: &'ll Type,
1591+
llfn: &'ll Value,
1592+
args: &[&'ll Value],
1593+
) -> &'ll Value {
1594+
let args = self.check_call("simple call", fn_ty, llfn, args);
1595+
1596+
unsafe {
1597+
llvm::LLVMBuildCall2(
1598+
self.llbuilder,
1599+
fn_ty,
1600+
llfn,
1601+
args.as_ptr(),
1602+
args.len() as _,
1603+
c"".as_ptr(),
1604+
)
1605+
}
1606+
}
1607+
1608+
pub(crate) fn call_intrinsic(
1609+
&mut self,
1610+
base_name: &str,
1611+
type_params: &[&'ll Type],
1612+
args: &[&'ll Value],
1613+
) -> &'ll Value {
1614+
let intrinsic = llvm::Intrinsic::lookup(base_name.as_bytes())
1615+
.unwrap_or_else(|| bug!("Intrinsic `{base_name}` not found"));
1616+
let (fn_ty, llfn) = self.cx.get_intrinsic(intrinsic, type_params);
1617+
self.simple_call(fn_ty, llfn, args)
16491618
}
1619+
}
16501620

1621+
impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
16511622
fn call_lifetime_intrinsic(&mut self, intrinsic: &str, ptr: &'ll Value, size: Size) {
16521623
let size = size.bytes();
16531624
if size == 0 {
@@ -1658,7 +1629,7 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
16581629
return;
16591630
}
16601631

1661-
self.call_intrinsic(intrinsic, &[self.cx.const_u64(size), ptr]);
1632+
self.call_intrinsic(intrinsic, &[self.type_ptr()], &[self.cx.const_u64(size), ptr]);
16621633
}
16631634
}
16641635
impl<'a, 'll, CX: Borrow<SCx<'ll>>> GenericBuilder<'a, 'll, CX> {
@@ -1683,29 +1654,24 @@ impl<'a, 'll, CX: Borrow<SCx<'ll>>> GenericBuilder<'a, 'll, CX> {
16831654
}
16841655
}
16851656
impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
1686-
fn fptoint_sat(&mut self, signed: bool, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value {
1687-
let src_ty = self.cx.val_ty(val);
1688-
let (float_ty, int_ty, vector_length) = if self.cx.type_kind(src_ty) == TypeKind::Vector {
1689-
assert_eq!(self.cx.vector_length(src_ty), self.cx.vector_length(dest_ty));
1690-
(
1691-
self.cx.element_type(src_ty),
1692-
self.cx.element_type(dest_ty),
1693-
Some(self.cx.vector_length(src_ty)),
1694-
)
1695-
} else {
1696-
(src_ty, dest_ty, None)
1657+
pub(crate) fn memcmp(
1658+
&mut self,
1659+
ptr1: &'ll Value,
1660+
ptr2: &'ll Value,
1661+
num: &'ll Value,
1662+
) -> &'ll Value {
1663+
let llreturn_ty = match self.sess().target.arch.as_ref() {
1664+
"avr" | "msp430" => self.type_i16(),
1665+
_ => self.type_i32(),
16971666
};
1698-
let float_width = self.cx.float_width(float_ty);
1699-
let int_width = self.cx.int_width(int_ty);
1667+
let fn_ty =
1668+
self.type_func(&[self.type_ptr(), self.type_ptr(), self.type_isize()], llreturn_ty);
17001669

1701-
let instr = if signed { "fptosi" } else { "fptoui" };
1702-
let name = if let Some(vector_length) = vector_length {
1703-
format!("llvm.{instr}.sat.v{vector_length}i{int_width}.v{vector_length}f{float_width}")
1704-
} else {
1705-
format!("llvm.{instr}.sat.i{int_width}.f{float_width}")
1706-
};
1707-
let f = self.declare_cfn(&name, llvm::UnnamedAddr::No, self.type_func(&[src_ty], dest_ty));
1708-
self.call(self.type_func(&[src_ty], dest_ty), None, None, f, &[val], None, None)
1670+
let llfn = self
1671+
.get_function("memcmp")
1672+
.unwrap_or_else(|| self.declare_cfn("memcmp", llvm::UnnamedAddr::No, fn_ty));
1673+
1674+
self.simple_call(fn_ty, llfn, &[ptr1, ptr2, num])
17091675
}
17101676

17111677
pub(crate) fn landing_pad(
@@ -1878,7 +1844,7 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
18781844
num_counters: &'ll Value,
18791845
index: &'ll Value,
18801846
) {
1881-
self.call_intrinsic("llvm.instrprof.increment", &[fn_name, hash, num_counters, index]);
1847+
self.call_intrinsic("llvm.instrprof.increment", &[], &[fn_name, hash, num_counters, index]);
18821848
}
18831849

18841850
/// Emits a call to `llvm.instrprof.mcdc.parameters`.
@@ -1897,7 +1863,7 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
18971863
hash: &'ll Value,
18981864
bitmap_bits: &'ll Value,
18991865
) {
1900-
self.call_intrinsic("llvm.instrprof.mcdc.parameters", &[fn_name, hash, bitmap_bits]);
1866+
self.call_intrinsic("llvm.instrprof.mcdc.parameters", &[], &[fn_name, hash, bitmap_bits]);
19011867
}
19021868

19031869
#[instrument(level = "debug", skip(self))]
@@ -1909,7 +1875,7 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
19091875
mcdc_temp: &'ll Value,
19101876
) {
19111877
let args = &[fn_name, hash, bitmap_index, mcdc_temp];
1912-
self.call_intrinsic("llvm.instrprof.mcdc.tvbitmap.update", args);
1878+
self.call_intrinsic("llvm.instrprof.mcdc.tvbitmap.update", &[], args);
19131879
}
19141880

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

0 commit comments

Comments
 (0)