]> git.lizzy.rs Git - rust.git/blobdiff - src/librustc_codegen_llvm/intrinsic.rs
Rollup merge of #75485 - RalfJung:pin, r=nagisa
[rust.git] / src / librustc_codegen_llvm / intrinsic.rs
index 728af7b0a8cd177323e7def9bd8db33893379b75..14aec1ff5e19e66e633f8e1115692ecc75fa3023 100644 (file)
@@ -13,7 +13,7 @@
 use rustc_codegen_ssa::base::{compare_simd_types, to_immediate, wants_msvc_seh};
 use rustc_codegen_ssa::common::span_invalid_monomorphization_error;
 use rustc_codegen_ssa::common::{IntPredicate, TypeKind};
-use rustc_codegen_ssa::coverageinfo::ExprKind;
+use rustc_codegen_ssa::coverageinfo;
 use rustc_codegen_ssa::glue;
 use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue};
 use rustc_codegen_ssa::mir::place::PlaceRef;
@@ -93,64 +93,64 @@ fn is_codegen_intrinsic(
         let mut is_codegen_intrinsic = true;
         // Set `is_codegen_intrinsic` to `false` to bypass `codegen_intrinsic_call()`.
 
-        if self.tcx.sess.opts.debugging_opts.instrument_coverage {
-            // If the intrinsic is from the local MIR, add the coverage information to the Codegen
-            // context, to be encoded into the local crate's coverage map.
-            if caller_instance.def_id().is_local() {
-                // FIXME(richkadel): Make sure to add coverage analysis tests on a crate with
-                // external crate dependencies, where:
-                //   1. Both binary and dependent crates are compiled with `-Zinstrument-coverage`
-                //   2. Only binary is compiled with `-Zinstrument-coverage`
-                //   3. Only dependent crates are compiled with `-Zinstrument-coverage`
-                match intrinsic {
-                    sym::count_code_region => {
-                        use coverage::count_code_region_args::*;
-                        self.add_counter_region(
-                            caller_instance,
-                            op_to_u64(&args[FUNCTION_SOURCE_HASH]),
-                            op_to_u32(&args[COUNTER_ID]),
-                            op_to_u32(&args[START_BYTE_POS]),
-                            op_to_u32(&args[END_BYTE_POS]),
-                        );
-                    }
-                    sym::coverage_counter_add | sym::coverage_counter_subtract => {
-                        use coverage::coverage_counter_expression_args::*;
-                        self.add_counter_expression_region(
-                            caller_instance,
-                            op_to_u32(&args[EXPRESSION_ID]),
-                            op_to_u32(&args[LEFT_ID]),
-                            if intrinsic == sym::coverage_counter_add {
-                                ExprKind::Add
-                            } else {
-                                ExprKind::Subtract
-                            },
-                            op_to_u32(&args[RIGHT_ID]),
-                            op_to_u32(&args[START_BYTE_POS]),
-                            op_to_u32(&args[END_BYTE_POS]),
-                        );
-                    }
-                    sym::coverage_unreachable => {
-                        use coverage::coverage_unreachable_args::*;
-                        self.add_unreachable_region(
-                            caller_instance,
-                            op_to_u32(&args[START_BYTE_POS]),
-                            op_to_u32(&args[END_BYTE_POS]),
-                        );
-                    }
-                    _ => {}
-                }
+        // FIXME(richkadel): Make sure to add coverage analysis tests on a crate with
+        // external crate dependencies, where:
+        //   1. Both binary and dependent crates are compiled with `-Zinstrument-coverage`
+        //   2. Only binary is compiled with `-Zinstrument-coverage`
+        //   3. Only dependent crates are compiled with `-Zinstrument-coverage`
+        match intrinsic {
+            sym::count_code_region => {
+                use coverage::count_code_region_args::*;
+                self.add_counter_region(
+                    caller_instance,
+                    op_to_u64(&args[FUNCTION_SOURCE_HASH]),
+                    op_to_u32(&args[COUNTER_ID]),
+                    coverageinfo::Region::new(
+                        op_to_str_slice(&args[FILE_NAME]),
+                        op_to_u32(&args[START_LINE]),
+                        op_to_u32(&args[START_COL]),
+                        op_to_u32(&args[END_LINE]),
+                        op_to_u32(&args[END_COL]),
+                    ),
+                );
             }
-
-            // Only the `count_code_region` coverage intrinsic is translated into an actual LLVM
-            // intrinsic call (local or not); otherwise, set `is_codegen_intrinsic` to `false`.
-            match intrinsic {
-                sym::coverage_counter_add
-                | sym::coverage_counter_subtract
-                | sym::coverage_unreachable => {
-                    is_codegen_intrinsic = false;
-                }
-                _ => {}
+            sym::coverage_counter_add | sym::coverage_counter_subtract => {
+                is_codegen_intrinsic = false;
+                use coverage::coverage_counter_expression_args::*;
+                self.add_counter_expression_region(
+                    caller_instance,
+                    op_to_u32(&args[EXPRESSION_ID]),
+                    op_to_u32(&args[LEFT_ID]),
+                    if intrinsic == sym::coverage_counter_add {
+                        coverageinfo::ExprKind::Add
+                    } else {
+                        coverageinfo::ExprKind::Subtract
+                    },
+                    op_to_u32(&args[RIGHT_ID]),
+                    coverageinfo::Region::new(
+                        op_to_str_slice(&args[FILE_NAME]),
+                        op_to_u32(&args[START_LINE]),
+                        op_to_u32(&args[START_COL]),
+                        op_to_u32(&args[END_LINE]),
+                        op_to_u32(&args[END_COL]),
+                    ),
+                );
             }
+            sym::coverage_unreachable => {
+                is_codegen_intrinsic = false;
+                use coverage::coverage_unreachable_args::*;
+                self.add_unreachable_region(
+                    caller_instance,
+                    coverageinfo::Region::new(
+                        op_to_str_slice(&args[FILE_NAME]),
+                        op_to_u32(&args[START_LINE]),
+                        op_to_u32(&args[START_COL]),
+                        op_to_u32(&args[END_LINE]),
+                        op_to_u32(&args[END_COL]),
+                    ),
+                );
+            }
+            _ => {}
         }
         is_codegen_intrinsic
     }
@@ -215,22 +215,19 @@ fn codegen_intrinsic_call(
                 self.call(llfn, &[], None)
             }
             sym::count_code_region => {
-                // FIXME(richkadel): The current implementation assumes the MIR for the given
-                // caller_instance represents a single function. Validate and/or correct if inlining
-                // and/or monomorphization invalidates these assumptions.
-                let coverageinfo = tcx.coverageinfo(caller_instance.def_id());
-                let mangled_fn = tcx.symbol_name(caller_instance);
-                let (mangled_fn_name, _len_val) = self.const_str(Symbol::intern(mangled_fn.name));
-                let num_counters = self.const_u32(coverageinfo.num_counters);
                 use coverage::count_code_region_args::*;
+                let coverageinfo = tcx.coverageinfo(caller_instance.def_id());
+
+                let fn_name = self.create_pgo_func_name_var(caller_instance);
                 let hash = args[FUNCTION_SOURCE_HASH].immediate();
+                let num_counters = self.const_u32(coverageinfo.num_counters);
                 let index = args[COUNTER_ID].immediate();
                 debug!(
                     "translating Rust intrinsic `count_code_region()` to LLVM intrinsic: \
-                    instrprof.increment(fn_name={}, hash={:?}, num_counters={:?}, index={:?})",
-                    mangled_fn.name, hash, num_counters, index,
+                    instrprof.increment(fn_name={:?}, hash={:?}, num_counters={:?}, index={:?})",
+                    fn_name, hash, num_counters, index,
                 );
-                self.instrprof_increment(mangled_fn_name, hash, num_counters, index)
+                self.instrprof_increment(fn_name, hash, num_counters, index)
             }
             sym::va_start => self.va_start(args[0].immediate()),
             sym::va_end => self.va_end(args[0].immediate()),
@@ -634,22 +631,19 @@ fn codegen_intrinsic_call(
             }
 
             sym::float_to_int_unchecked => {
-                let float_width = match float_type_width(arg_tys[0]) {
-                    Some(width) => width,
-                    None => {
-                        span_invalid_monomorphization_error(
-                            tcx.sess,
-                            span,
-                            &format!(
-                                "invalid monomorphization of `float_to_int_unchecked` \
+                if float_type_width(arg_tys[0]).is_none() {
+                    span_invalid_monomorphization_error(
+                        tcx.sess,
+                        span,
+                        &format!(
+                            "invalid monomorphization of `float_to_int_unchecked` \
                                   intrinsic: expected basic float type, \
                                   found `{}`",
-                                arg_tys[0]
-                            ),
-                        );
-                        return;
-                    }
-                };
+                            arg_tys[0]
+                        ),
+                    );
+                    return;
+                }
                 let (width, signed) = match int_type_width_signed(ret_ty, self.cx) {
                     Some(pair) => pair,
                     None => {
@@ -666,48 +660,11 @@ fn codegen_intrinsic_call(
                         return;
                     }
                 };
-
-                // The LLVM backend can reorder and speculate `fptosi` and
-                // `fptoui`, so on WebAssembly the codegen for this instruction
-                // is quite heavyweight. To avoid this heavyweight codegen we
-                // instead use the raw wasm intrinsics which will lower to one
-                // instruction in WebAssembly (`iNN.trunc_fMM_{s,u}`). This one
-                // instruction will trap if the operand is out of bounds, but
-                // that's ok since this intrinsic is UB if the operands are out
-                // of bounds, so the behavior can be different on WebAssembly
-                // than other targets.
-                //
-                // Note, however, that when the `nontrapping-fptoint` feature is
-                // enabled in LLVM then LLVM will lower `fptosi` to
-                // `iNN.trunc_sat_fMM_{s,u}`, so if that's the case we don't
-                // bother with intrinsics.
-                let mut result = None;
-                if self.sess().target.target.arch == "wasm32"
-                    && !self.sess().target_features.contains(&sym::nontrapping_dash_fptoint)
-                {
-                    let name = match (width, float_width, signed) {
-                        (32, 32, true) => Some("llvm.wasm.trunc.signed.i32.f32"),
-                        (32, 64, true) => Some("llvm.wasm.trunc.signed.i32.f64"),
-                        (64, 32, true) => Some("llvm.wasm.trunc.signed.i64.f32"),
-                        (64, 64, true) => Some("llvm.wasm.trunc.signed.i64.f64"),
-                        (32, 32, false) => Some("llvm.wasm.trunc.unsigned.i32.f32"),
-                        (32, 64, false) => Some("llvm.wasm.trunc.unsigned.i32.f64"),
-                        (64, 32, false) => Some("llvm.wasm.trunc.unsigned.i64.f32"),
-                        (64, 64, false) => Some("llvm.wasm.trunc.unsigned.i64.f64"),
-                        _ => None,
-                    };
-                    if let Some(name) = name {
-                        let intrinsic = self.get_intrinsic(name);
-                        result = Some(self.call(intrinsic, &[args[0].immediate()], None));
-                    }
+                if signed {
+                    self.fptosi(args[0].immediate(), self.cx.type_ix(width))
+                } else {
+                    self.fptoui(args[0].immediate(), self.cx.type_ix(width))
                 }
-                result.unwrap_or_else(|| {
-                    if signed {
-                        self.fptosi(args[0].immediate(), self.cx.type_ix(width))
-                    } else {
-                        self.fptoui(args[0].immediate(), self.cx.type_ix(width))
-                    }
-                })
             }
 
             sym::discriminant_value => {
@@ -2283,6 +2240,10 @@ fn float_type_width(ty: Ty<'_>) -> Option<u64> {
     }
 }
 
+fn op_to_str_slice<'tcx>(op: &Operand<'tcx>) -> &'tcx str {
+    Operand::value_from_const(op).try_to_str_slice().expect("Value is &str")
+}
+
 fn op_to_u32<'tcx>(op: &Operand<'tcx>) -> u32 {
     Operand::scalar_from_const(op).to_u32().expect("Scalar is u32")
 }