Force LLVM to use CMOV for binary search
Since https://reviews.llvm.org/D118118, LLVM will no longer turn CMOVs into branches if it comes from a `select` marked with an `unpredictable` metadata attribute. This PR introduces `core::intrinsics::select_unpredictable` which emits such a `select` and uses it in the implementation of `binary_search_by`.
This commit is contained in:
parent
355efacf0d
commit
4f78f9fbb0
7 changed files with 107 additions and 1 deletions
|
@ -1353,6 +1353,16 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn set_unpredictable(&mut self, inst: &'ll Value) {
|
||||
unsafe {
|
||||
llvm::LLVMSetMetadata(
|
||||
inst,
|
||||
llvm::MD_unpredictable as c_uint,
|
||||
llvm::LLVMMDNodeInContext(self.cx.llcx, ptr::null(), 0),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn minnum(&mut self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value {
|
||||
unsafe { llvm::LLVMRustBuildMinNum(self.llbuilder, lhs, rhs) }
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ use rustc_codegen_ssa::base::{compare_simd_types, wants_msvc_seh, wants_wasm_eh}
|
|||
use rustc_codegen_ssa::common::{IntPredicate, TypeKind};
|
||||
use rustc_codegen_ssa::errors::{ExpectedPointerMutability, InvalidMonomorphization};
|
||||
use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue};
|
||||
use rustc_codegen_ssa::mir::place::PlaceRef;
|
||||
use rustc_codegen_ssa::mir::place::{PlaceRef, PlaceValue};
|
||||
use rustc_codegen_ssa::traits::*;
|
||||
use rustc_hir as hir;
|
||||
use rustc_middle::mir::BinOp;
|
||||
|
@ -203,6 +203,35 @@ impl<'ll, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'_, 'll, 'tcx> {
|
|||
}
|
||||
sym::unlikely => self
|
||||
.call_intrinsic("llvm.expect.i1", &[args[0].immediate(), self.const_bool(false)]),
|
||||
sym::select_unpredictable => {
|
||||
let cond = args[0].immediate();
|
||||
assert_eq!(args[1].layout, args[2].layout);
|
||||
let select = |bx: &mut Self, true_val, false_val| {
|
||||
let result = bx.select(cond, true_val, false_val);
|
||||
bx.set_unpredictable(&result);
|
||||
result
|
||||
};
|
||||
match (args[1].val, args[2].val) {
|
||||
(OperandValue::Ref(true_val), OperandValue::Ref(false_val)) => {
|
||||
assert!(true_val.llextra.is_none());
|
||||
assert!(false_val.llextra.is_none());
|
||||
assert_eq!(true_val.align, false_val.align);
|
||||
let ptr = select(self, true_val.llval, false_val.llval);
|
||||
let selected =
|
||||
OperandValue::Ref(PlaceValue::new_sized(ptr, true_val.align));
|
||||
selected.store(self, result);
|
||||
return Ok(());
|
||||
}
|
||||
(OperandValue::Immediate(_), OperandValue::Immediate(_))
|
||||
| (OperandValue::Pair(_, _), OperandValue::Pair(_, _)) => {
|
||||
let true_val = args[1].immediate_or_packed_pair(self);
|
||||
let false_val = args[2].immediate_or_packed_pair(self);
|
||||
select(self, true_val, false_val)
|
||||
}
|
||||
(OperandValue::ZeroSized, OperandValue::ZeroSized) => return Ok(()),
|
||||
_ => span_bug!(span, "Incompatible OperandValue for select_unpredictable"),
|
||||
}
|
||||
}
|
||||
sym::catch_unwind => {
|
||||
catch_unwind_intrinsic(
|
||||
self,
|
||||
|
|
|
@ -428,6 +428,7 @@ pub enum MetadataType {
|
|||
MD_nontemporal = 9,
|
||||
MD_mem_parallel_loop_access = 10,
|
||||
MD_nonnull = 11,
|
||||
MD_unpredictable = 15,
|
||||
MD_align = 17,
|
||||
MD_type = 19,
|
||||
MD_vcall_visibility = 28,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue