about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMatthias Krüger <matthias.krueger@famsik.de>2024-12-01 14:30:11 +0100
committerGitHub <noreply@github.com>2024-12-01 14:30:11 +0100
commit2f00feb6160927a84bd279d3f7de25b6d20de78a (patch)
tree94b5a8b2687b18e9dc6da2d4a7950dc27322277e
parent3d18c3c414f8fb5732ccb859a486f97173a38d83 (diff)
parent9836196e3cca6661e752c3acd8bc207f181736ed (diff)
downloadrust-2f00feb6160927a84bd279d3f7de25b6d20de78a.tar.gz
rust-2f00feb6160927a84bd279d3f7de25b6d20de78a.zip
Rollup merge of #133674 - scottmcm:chain-carrying-add, r=Amanieu
Fix chaining `carrying_add`s

Something about the MIR lowering for `||` ended up breaking this, but it's fixed by changing the code to use `|` instead.

I also added an assembly test to ensure it *keeps* being [`adc`](https://www.felixcloutier.com/x86/adc).

cc https://github.com/rust-lang/rust/issues/85532#issuecomment-2495119815, which noticed this.
-rw-r--r--library/core/src/num/uint_macros.rs2
-rw-r--r--tests/assembly/x86_64-bigint-add.rs33
2 files changed, 34 insertions, 1 deletions
diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs
index 90b986f4998..0ebd765b549 100644
--- a/library/core/src/num/uint_macros.rs
+++ b/library/core/src/num/uint_macros.rs
@@ -2354,7 +2354,7 @@ macro_rules! uint_impl {
             //   to generate optimal code for now, and LLVM doesn't have an equivalent intrinsic
             let (a, b) = self.overflowing_add(rhs);
             let (c, d) = a.overflowing_add(carry as $SelfT);
-            (c, b || d)
+            (c, b | d)
         }
 
         /// Calculates `self` + `rhs` with a signed `rhs`.
diff --git a/tests/assembly/x86_64-bigint-add.rs b/tests/assembly/x86_64-bigint-add.rs
new file mode 100644
index 00000000000..4bcb9732c64
--- /dev/null
+++ b/tests/assembly/x86_64-bigint-add.rs
@@ -0,0 +1,33 @@
+//@ only-x86_64
+//@ assembly-output: emit-asm
+//@ compile-flags: --crate-type=lib -O -C target-cpu=x86-64-v4
+//@ compile-flags: -C llvm-args=-x86-asm-syntax=intel
+
+#![no_std]
+#![feature(bigint_helper_methods)]
+
+// This checks that the `carrying_add` implementation successfully chains, to catch
+// issues like <https://github.com/rust-lang/rust/issues/85532#issuecomment-2495119815>
+
+// This forces the ABI to avoid the windows-vs-linux ABI differences.
+
+// CHECK-LABEL: bigint_chain_carrying_add:
+#[no_mangle]
+pub unsafe extern "sysv64" fn bigint_chain_carrying_add(
+    dest: *mut u64,
+    src1: *const u64,
+    src2: *const u64,
+    n: usize,
+    mut carry: bool,
+) -> bool {
+    // CHECK: mov [[TEMP:r..]], qword ptr [rsi + 8*[[IND:r..]] + 8]
+    // CHECK: adc [[TEMP]], qword ptr [rdx + 8*[[IND]] + 8]
+    // CHECK: mov qword ptr [rdi + 8*[[IND]] + 8], [[TEMP]]
+    // CHECK: mov [[TEMP]], qword ptr [rsi + 8*[[IND]] + 16]
+    // CHECK: adc [[TEMP]], qword ptr [rdx + 8*[[IND]] + 16]
+    // CHECK: mov qword ptr [rdi + 8*[[IND]] + 16], [[TEMP]]
+    for i in 0..n {
+        (*dest.add(i), carry) = u64::carrying_add(*src1.add(i), *src2.add(i), carry);
+    }
+    carry
+}