From 4ee1602eab2cdc88172d4a98f927613ab64b4cf0 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Mon, 20 Jan 2025 00:00:44 -0800 Subject: [PATCH] Override `disjoint_or` in the LLVM backend --- compiler/rustc_codegen_llvm/src/builder.rs | 8 ++++++++ compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 3 +++ .../rustc_codegen_ssa/src/mir/intrinsic.rs | 5 +++++ .../rustc_codegen_ssa/src/traits/builder.rs | 5 +++++ tests/codegen/bigint-helpers.rs | 13 ++++++++++++ tests/codegen/intrinsics/disjoint_bitor.rs | 20 +++++++++++++++++++ 6 files changed, 54 insertions(+) create mode 100644 tests/codegen/bigint-helpers.rs create mode 100644 tests/codegen/intrinsics/disjoint_bitor.rs diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index 2d007416263..6e1eec4f0fc 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -421,6 +421,14 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { unchecked_umul(x, y) => LLVMBuildNUWMul, } + fn or_disjoint(&mut self, a: &'ll Value, b: &'ll Value) -> &'ll Value { + unsafe { + let or = llvm::LLVMBuildOr(self.llbuilder, a, b, UNNAMED); + llvm::LLVMSetIsDisjoint(or, True); + or + } + } + set_math_builder_methods! { fadd_fast(x, y) => (LLVMBuildFAdd, LLVMRustSetFastMath), fsub_fast(x, y) => (LLVMBuildFSub, LLVMRustSetFastMath), diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index cc7c5231aca..8d494b0fe62 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -1380,6 +1380,9 @@ unsafe extern "C" { pub fn LLVMBuildFNeg<'a>(B: &Builder<'a>, V: &'a Value, Name: *const c_char) -> &'a Value; pub fn LLVMBuildNot<'a>(B: &Builder<'a>, V: &'a Value, Name: *const c_char) -> &'a Value; + // Extra flags on arithmetic + pub fn LLVMSetIsDisjoint(Instr: &Value, IsDisjoint: Bool); + // Memory pub fn LLVMBuildAlloca<'a>(B: &Builder<'a>, Ty: &'a Type, Name: *const c_char) -> &'a Value; pub fn LLVMBuildArrayAlloca<'a>( diff --git a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs index 304ac4544ee..6e7fbe62c8d 100644 --- a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs +++ b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs @@ -225,6 +225,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { args[1].val.unaligned_volatile_store(bx, dst); return Ok(()); } + sym::disjoint_bitor => { + let a = args[0].immediate(); + let b = args[1].immediate(); + bx.or_disjoint(a, b) + } sym::exact_div => { let ty = arg_tys[0]; match int_type_width_signed(ty, bx.tcx()) { diff --git a/compiler/rustc_codegen_ssa/src/traits/builder.rs b/compiler/rustc_codegen_ssa/src/traits/builder.rs index bbf87a59942..b7dcf16fa2b 100644 --- a/compiler/rustc_codegen_ssa/src/traits/builder.rs +++ b/compiler/rustc_codegen_ssa/src/traits/builder.rs @@ -167,6 +167,11 @@ pub trait BuilderMethods<'a, 'tcx>: fn unchecked_umul(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value; fn and(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value; fn or(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value; + /// Defaults to [`Self::or`], but guarantees `(lhs & rhs) == 0` so some backends + /// can emit something more helpful for optimizations. + fn or_disjoint(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value { + self.or(lhs, rhs) + } fn xor(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value; fn neg(&mut self, v: Self::Value) -> Self::Value; fn fneg(&mut self, v: Self::Value) -> Self::Value; diff --git a/tests/codegen/bigint-helpers.rs b/tests/codegen/bigint-helpers.rs new file mode 100644 index 00000000000..355cccb8150 --- /dev/null +++ b/tests/codegen/bigint-helpers.rs @@ -0,0 +1,13 @@ +//@ compile-flags: -C opt-level=3 + +#![crate_type = "lib"] +#![feature(bigint_helper_methods)] + +// CHECK-LABEL: @u32_carrying_add +#[no_mangle] +pub fn u32_carrying_add(a: u32, b: u32, c: bool) -> (u32, bool) { + // CHECK: @llvm.uadd.with.overflow.i32 + // CHECK: @llvm.uadd.with.overflow.i32 + // CHECK: or disjoint i1 + u32::carrying_add(a, b, c) +} diff --git a/tests/codegen/intrinsics/disjoint_bitor.rs b/tests/codegen/intrinsics/disjoint_bitor.rs new file mode 100644 index 00000000000..be9954507b3 --- /dev/null +++ b/tests/codegen/intrinsics/disjoint_bitor.rs @@ -0,0 +1,20 @@ +//@ compile-flags: -C no-prepopulate-passes + +#![crate_type = "lib"] +#![feature(core_intrinsics)] + +use std::intrinsics::disjoint_bitor; + +// CHECK-LABEL: @disjoint_bitor_signed +#[no_mangle] +pub unsafe fn disjoint_bitor_signed(x: i32, y: i32) -> i32 { + // CHECK: or disjoint i32 %x, %y + disjoint_bitor(x, y) +} + +// CHECK-LABEL: @disjoint_bitor_unsigned +#[no_mangle] +pub unsafe fn disjoint_bitor_unsigned(x: u64, y: u64) -> u64 { + // CHECK: or disjoint i64 %x, %y + disjoint_bitor(x, y) +}