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;
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
}
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()),
}
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 => {
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 => {
}
}
+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")
}