Skip to content

add sqrt from miri + tests#28

Open
ValorZard wants to merge 18 commits intorust-lang:mainfrom
ValorZard:add_sqrt
Open

add sqrt from miri + tests#28
ValorZard wants to merge 18 commits intorust-lang:mainfrom
ValorZard:add_sqrt

Conversation

@ValorZard
Copy link
Copy Markdown

@ValorZard
Copy link
Copy Markdown
Author

Think this is step 1 to getting this stuff const.
Wonder if we could do all the trig stuff next

@tgross35
Copy link
Copy Markdown
Contributor

Ideally we would have the fuzz tests for these too to get better coverage, in fuzz/ops.rs. Unfortunately we can't test against LLVM's apfloat here given it doesn't exist, but I think it would be reasonable enough to test against the host sqrt for the f16/f32/f64/f128 cases.

For the remaining semantics (x86, ppc, etc), I'm not sure what to do. Unless there is a reasonable way to test then I'd almost say it's better to panic than to have them untested, any thoughts Ralf?

tests/ieee.rs Outdated
}

#[test]
fn sqrt() {
Copy link
Copy Markdown
Member

@RalfJung RalfJung Mar 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now you're only testing Double, i.e., f64. Since this is all softfloats, you should be able to test f16, f32, f128 as well entirely on stable. Look around in the test file for any infrastructure for generic tests, I don't know what (if anything) exists in that regard.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, Double tests seem pretty common. Eh, I don't know how the tests here work. I'll leave this to @tgross35 :)

@RalfJung
Copy link
Copy Markdown
Member

For the remaining semantics (x86, ppc, etc), I'm not sure what to do. Unless there is a reasonable way to test then I'd almost say it's better to panic than to have them untested, any thoughts Ralf?

Not really, I don't know apfloat at all.^^ I like conservative panics.

src/lib.rs Outdated
// preserve zero sign
Category::Zero => self,
// propagate NaN
Category::NaN => self,
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

idk if it matters, but technically you're supposed to quiet signalling NaNs.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you mean by that?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the input is a signalling NaN, then IEEE 754 requires the result to be converted to a quiet NaN. On most CPUs that means the most significant bit of the significand field is 0 for signalling NaNs and 1 for quiet NaNs. On most CPUs they quiet a NaN by setting that bit to a 1, RISC-V instead returns the canonical NaN with positive sign, the most significant significand bit set and all other significand bits cleared.

However, Rust and LLVM allow input NaNs to be returned unmodified as well as a few other options -- see Rust's rules for NaNs.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

okay so i think returning self is fine then.
(Do you mind if i copy this comment and put it where NaN is?)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

okay so i think returning self is fine then. (Do you mind if i copy this comment and put it where NaN is?)

sure, go ahead. you'll probably want to change the linked part to instead have the link's url on a line by itself

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This crate otherwise does a good job of sticking to IEEE semantics and quietens sNaNs elsewhere. I think we should do the same here - it's easy enough, just use result_from_nan like the other ops.

What do you mean by that?

Welcome to the world of floating point 🙃.

Crash course: there are two kinds of NaN, signaling (pretty useless and extremely annoying, but part of the spec) and quiet (used pretty much everywhere; this is Rust's f32::NAN). IEEE 754 (usually) says that when you pass a sNaN to an operation, it should "quiet" the sNaN or turn it into a qNaN, then set the invalid op exception.

You can see the exceptions in Rust, via asm, or in C:

src/lib.rs Outdated
}
}

fn sqrt(self) -> Self {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IEEE sqrt can take rounding mode and raise the floating point exceptions, so technically this should return a StatusAnd. I think it's fine to always round to nearest and disregard exceptions, but please document this.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you can check the comment i added to see if its what you want

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Currently:

    /// Technically this should be StatusAnd<Self>, but since sqrt is exact for all supported formats,
    /// we can just round to the nearest, ignore exceptions, and return Self.

The reasoning isn't correct: exact means correctly rounded, it doesn't mean no rounding will occur. You can have exact results with any of the four rounding modes. Instead it should just say that we don't support this.

Please also note that this is public documentation so the first line should just say what the function is before jumping into its details. Also please quote code in `...`.

src/lib.rs Outdated
// preserve zero sign
Category::Zero => self,
// propagate NaN
Category::NaN => self,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This crate otherwise does a good job of sticking to IEEE semantics and quietens sNaNs elsewhere. I think we should do the same here - it's easy enough, just use result_from_nan like the other ops.

What do you mean by that?

Welcome to the world of floating point 🙃.

Crash course: there are two kinds of NaN, signaling (pretty useless and extremely annoying, but part of the spec) and quiet (used pretty much everywhere; this is Rust's f32::NAN). IEEE 754 (usually) says that when you pass a sNaN to an operation, it should "quiet" the sNaN or turn it into a qNaN, then set the invalid op exception.

You can see the exceptions in Rust, via asm, or in C:

src/lib.rs Outdated
}
}

fn sqrt(self) -> Self {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Currently:

    /// Technically this should be StatusAnd<Self>, but since sqrt is exact for all supported formats,
    /// we can just round to the nearest, ignore exceptions, and return Self.

The reasoning isn't correct: exact means correctly rounded, it doesn't mean no rounding will occur. You can have exact results with any of the four rounding modes. Instead it should just say that we don't support this.

Please also note that this is public documentation so the first line should just say what the function is before jumping into its details. Also please quote code in `...`.

@ValorZard
Copy link
Copy Markdown
Author

Think all comments were handled, though I'm still not sure what to put for the documentation of the sqrt function itself

@tgross35
Copy link
Copy Markdown
Contributor

tgross35 commented Apr 2, 2026

So, turns out it's actually very easy to support status and rounding modes. Replace the final add+shift with the following:

let mut status = Status::OK;

// A nonzero remainder indicates that we could continue processing sqrt if we had
// more precision, potentially indefinitely. We don't because we have enough bits
// to fill our significand already, and only need the one extra bit to determine
// rounding.
if rem != 0 {
    status = Status::INEXACT;

    match round {
        // If the LSB is 0, we should round down and this 1 gets cut off. If the LSB
        // is 1, it is either a tie (if all remaining bits would be 0) or something
        // that should be rounded up.
        //
        // Square roots are either exact or irrational, so a `1` in the extra bit
        // already implies an irrational result with more `1`s in the infinite
        // precision tail that should be rounded up, which this does. We are in a
        // `rem != 0` block but could technically add the `1` unconditionally, given
        // that a 0 in the extra bit would imply an exact result to be rounded down
        // (and the extra bit is just shifted out).
        Round::NearestTiesToEven => res += 1,
        // We know we have an inexact result that needs rounding up. If the round
        // bit is 1, adding 1 is sufficient and adding 2 does nothing extra (the
        // new LSB will get truncated). If the round bit is 0, we need to add
        // two anyway to affect the significand.
        Round::TowardPositive => res += 2,
        // By default, shifting will round down.
        Round::TowardNegative => (),
        // Same as negative since the result of sqrt is positive.
        Round::TowardZero => (),
        Round::NearestTiesToAway => unimplemented!("unsupported rounding mode"),
    };
}

// Remove the extra fractional bit.
res >>= 1;

// Build resulting value with res as mantissa and exp/2 as exponent
status.and(Self::from_u128(res).value.scalbn(exp / 2 - prec))

src/ieee.rs Outdated
// (Thanks @programmerjake for the comment)
Category::NaN => return IeeeDefaultExceptionHandling::result_from_nan(self).value,
// sqrt of negative number is NaN
_ if self.is_negative() => return Self::NAN,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use NAN.copy_Sign like we do elsewhere so the NaN gets the sign bit set on negative inputs. IEEE doesn't require this but it's common.

src/ieee.rs Outdated
// However, Rust and LLVM allow input NaNs to be returned unmodified as well as a few other options -- see Rust's rules for NaNs.
// https://doc.rust-lang.org/std/primitive.f32.html#nan-bit-patterns
// (Thanks @programmerjake for the comment)
Category::NaN => return IeeeDefaultExceptionHandling::result_from_nan(self).value,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The two possible exceptions for sqrt are INEXACT on negative inputs and INVALID for sNaN inputs. My patch handles the INEXACT portion, you'll just need to drop .value here to handle INVALID.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nope, it says to return INVALID on negative inputs. INEXACT would be returned for inputs where the rounded result is not the same as the infinitely precise result.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah sorry, completely messed up the first bit of that comment. INEXACT if it requires rounding, INVALID for both negative inputs (as you said) and sNaN.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is something like this fine?
Category::NaN => return IeeeDefaultExceptionHandling::result_from_nan(self).value.copy_sign(Self::NAN),

@tgross35
Copy link
Copy Markdown
Contributor

tgross35 commented Apr 2, 2026

Created a way to verify this on x86 hardware with a small bit of inline asm. Could you use this as the implementation to test against for the fuzzer? Please make sure to cfg correctly so you can still build on other arches, they can just do a .sqrt() fallback and not check for bitwise equality of NaN. https://gist.github.com/tgross35/7a3b35285497beeaacf3b699978e8cd2.

I ran this addition with my above patch exhaustively for f32 on my machine and it works correctly in all four rounding modes. You'll need the NaN fix.

@tgross35
Copy link
Copy Markdown
Contributor

tgross35 commented Apr 2, 2026

Updated to include an aarch64 implementation as well https://gist.github.com/tgross35/7a3b35285497beeaacf3b699978e8cd2

tests/ieee.rs Outdated
Comment on lines +835 to +836
#[test]
fn sqrt() {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Put this in tests/downstream.rs, which is where we have things that aren't a direct port of LLVM

/// IEEE-754R sqrt: Returns the correctly rounded square root of the current value
/// Note: we currently don't support raising any exceptions from sqrt, so the result is always exact and the status is always OK.
fn sqrt(self) -> Self {
unimplemented!()
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add a note like "sqrt is not implemented for these semantics"

src/ieee.rs Outdated
}
}

fn sqrt(self) -> Self {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, similar to the above, could you put this function body into a new src/downstream.rs file? To avoid conflicts when we make changes related to LLVM. Call the function ieee_sqrt to be clear about what it supports.

@ValorZard
Copy link
Copy Markdown
Author

ValorZard commented Apr 2, 2026

@tgross35 where is the round parameter coming from?
in
match round {

@tgross35
Copy link
Copy Markdown
Contributor

tgross35 commented Apr 2, 2026

Look at the function signature for other unary functions in the Float trait :)

@ValorZard
Copy link
Copy Markdown
Author

I'm still not totally sure how the fuzzer works, and the test i copied was taking a REALLY long time to run, so I decided to just run it on the CI/CD and hope for the best

@tgross35
Copy link
Copy Markdown
Contributor

tgross35 commented Apr 3, 2026

I'm realizing the fuzzer doesn't actually run on CI so I'm in the process of making that happen, please bear with the conflicts that might pop up (I'll let you know when it's all set).

the test i copied was taking a REALLY long time to run

From the one I sent? Not sure exactly how long you mean but it's at least ~5 minutes to exhaustively check all possible f32 values and it needs to repeat for each rounding mode, so it takes a while.

);
}
}
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah no I didn't mean to actually include this verbatim as a #[test], that's far too much to always run in CI. This implementation will need to be hooked up to the fuzzer, but hold off until I'm done with the changes there.

@ValorZard
Copy link
Copy Markdown
Author

@tgross35 is the fuzzer stuff setup yet?

@tgross35
Copy link
Copy Markdown
Contributor

tgross35 commented Apr 8, 2026

Sorry, still working on some things and probably need another day or two here. I'll ping when it's ready.

@tgross35
Copy link
Copy Markdown
Contributor

Okay, that took longer than expected. I wound up rewriting pretty much the whole fuzzer to support testing rounding modes and exceptions.

Once you rebase the todo list should be basically:

  • Add a new variant here, update the associated constant & methods
    pub enum Op {
  • Tie in the new variants here. You may need to add if F::KIND.supports_sqrt() guards (that method doesn't yet exist) to return None for PPC and other unsupported semantics
    let res = match op {
    Op::Neg => Status::OK.and(-a.to_ap()),
    Op::Add => a.to_ap().add_r(b.to_ap(), rm),
    Op::Sub => a.to_ap().sub_r(b.to_ap(), rm),
    Op::Mul => a.to_ap().mul_r(b.to_ap(), rm),
    Op::Div => a.to_ap().div_r(b.to_ap(), rm),
    // FIXME: rem disregards rounding mode
    Op::Rem => a.to_ap() % b.to_ap(),
    Op::MulAdd => a.to_ap().mul_add_r(b.to_ap(), c.to_ap(), rm),
    // FIXME: the below operations discard a status. We should turn them into
    // unidirectional operations.
    Op::FToI128ToF => {
    F::RustcApFloat::from_i128_r(a.to_ap().to_i128_r(128, rm, &mut false).value, rm)
    }
    Op::FToU128ToF => {
    F::RustcApFloat::from_u128_r(a.to_ap().to_u128_r(128, rm, &mut false).value, rm)
    }
    Op::FToSingleToF => FloatConvert::<F::RustcApFloat>::convert_r(
    FloatConvert::<ieee::Single>::convert_r(a.to_ap(), rm, &mut false).value,
    rm,
    &mut false,
    ),
    Op::FToDoubleToF => FloatConvert::<F::RustcApFloat>::convert_r(
    FloatConvert::<ieee::Double>::convert_r(a.to_ap(), rm, &mut false).value,
    rm,
    &mut false,
    ),
    };
    res.map(F::from_ap)
    }
    /// Execute the requested operation on the host with the given rounding mode, if possible. If
    /// the operation is not possible for whatever reason, return `None`.
    fn eval_host<F: HostFloat>(
    op: Op,
    rm: Round,
    a: F::UInt,
    b: F::UInt,
    c: F::UInt,
    ) -> Option<StatusAnd<F::UInt>> {
    let a = F::from_bits(a);
    let b = F::from_bits(b);
    let c = F::from_bits(c);
    let res = match op {
    Op::Neg => Status::OK.and(a.neg()),
    Op::Add => a.add_r(b, rm)?,
    Op::Sub => a.sub_r(b, rm)?,
    Op::Mul => a.mul_r(b, rm)?,
    Op::Div => a.div_r(b, rm)?,
    // FIXME: rem disregards rounding mode
    Op::Rem => Status::OK.and(a.rem(b)),
    Op::MulAdd => a.mul_add_r(b, c, rm)?,
    // FIXME: the below operations discard a status. We should turn them into
    // unidirectional operations.
    Op::FToI128ToF => F::from_i128_r(a.to_i128_r(rm)?.value, rm)?,
    Op::FToU128ToF => F::from_u128_r(a.to_u128_r(rm)?.value, rm)?,
    Op::FToSingleToF => F::from_single_r(a.to_single_r(rm)?.value, rm)?,
    Op::FToDoubleToF => F::from_double_r(a.to_double_r(rm)?.value, rm)?,
    };
  • Add a new op here
    pub trait HostFloat: Copy + Sized + fmt::Debug {
  • Add the relevant x86 asm to the f16/f32/f64 impls below (should look similar to the addsh/addss/addsd ops except you don't need the second operand)

I think you can then delete the additions to test_downstream since they should be covered here.

@tgross35
Copy link
Copy Markdown
Contributor

If #35 lands first then an x87_f80 implementation can be added as well, the op is fsqrt.

Note that the fuzzer still isn't running in CI, there are a couple of failures going on still and I want to see if bumping to a newer LLVM version fixes them. But running locally for a while is fine.

@tgross35
Copy link
Copy Markdown
Contributor

I think you can then delete the additions to test_downstream since they should be covered here.

Please do add/keep edge case tests though. This should cover e.g. sNaN vs NaN, inputs that wind up with various flags, simple examples of rounding mode, zeros and infinities, etc. This can be based on some of the things covered in test/ieee.rs.

@ValorZard
Copy link
Copy Markdown
Author

If #35 lands first then an x87_f80 implementation can be added as well, the op is fsqrt.

Note that the fuzzer still isn't running in CI, there are a couple of failures going on still and I want to see if bumping to a newer LLVM version fixes them. But running locally for a while is fine.

You forget that I can’t run the fuzzer locally since I’m on windows (though now that I think about it I guess I could try if WSL will work)

Otherwise, sounds good, will get to it tomorrow

@tgross35
Copy link
Copy Markdown
Contributor

Nope I remember, I meant I can run it for you if you can't get it set up :)

But yeah WSL works, I've done some of the work there.

@ValorZard
Copy link
Copy Markdown
Author

ValorZard commented Apr 14, 2026

@tgross35
On wsl got this error

root@Penelope:~/rustc_apfloat# # Create the corpus
just gen
# Build and run fuzzing
just fuzz
# Do the same thing but use more cores
just fuzz-parallel
# Print crashes. Can be run while fuzzing is ongoing.
just decode
mkdir -p "fuzz/runs/in"
echo > "fuzz/runs/in/empty"
cargo afl build -p rustc_apfloat-fuzz --release
   Compiling proc-macro2 v1.0.106
   Compiling unicode-ident v1.0.24
   Compiling quote v1.0.45
   Compiling utf8parse v0.2.2
   Compiling anstyle-query v1.1.5
   Compiling anstyle v1.0.14
   Compiling libc v0.2.185
   Compiling colorchoice v1.0.5
   Compiling is_terminal_polyfill v1.70.2
   Compiling autocfg v1.5.0
   Compiling home v0.5.12
   Compiling clap_lex v1.1.0
   Compiling strsim v0.11.1
   Compiling rustc_apfloat v0.2.3+llvm-038f7debfda0 (/root/rustc_apfloat)
   Compiling semver v1.0.28
   Compiling heck v0.5.0
   Compiling xdg v3.0.0
   Compiling rustc_apfloat-fuzz v0.2.3+llvm-038f7debfda0 (/root/rustc_apfloat/fuzz)
   Compiling smallvec v1.15.1
   Compiling bitflags v2.11.1
   Compiling anstyle-parse v1.0.0
   Compiling afl v0.15.24
   Compiling anstream v1.0.0
   Compiling rustc_version v0.4.1
   Compiling clap_builder v4.6.0
error: failed to run custom build command for `rustc_apfloat-fuzz v0.2.3+llvm-038f7debfda0 (/root/rustc_apfloat/fuzz)`

Caused by:
  process didn't exit successfully: `/root/rustc_apfloat/target/release/build/rustc_apfloat-fuzz-eb054ec7082b7eed/build-script-build` (exit status: 101)
  --- stdout
  cargo::rerun-if-changed=build.rs
  cargo::rerun-if-changed=cxx
  cargo::rerun-if-changed=src/apf_fuzz.cpp
  cargo::rustc-check-cfg=cfg(x86_sse2)
  cargo::rustc-cfg=x86_sse2

  --- stderr

  thread 'main' (34555) panicked at fuzz/build.rs:49:9:
  llvm dir `"/root/rustc_apfloat/target/llvm-downloads/llvm-project-038f7debfda0"` does not exist or cannot be reached. Perhaps you need to run etc/download-llvm.sh?
  note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
warning: build failed, waiting for other jobs to finish...
error: Recipe `fuzz-build` failed on line 26 with exit code 101
mkdir -p "fuzz/runs/in"
echo > "fuzz/runs/in/empty"
cargo afl build -p rustc_apfloat-fuzz --release
   Compiling quote v1.0.45
   Compiling num-traits v0.2.19
   Compiling libc v0.2.185
   Compiling rustc_apfloat-fuzz v0.2.3+llvm-038f7debfda0 (/root/rustc_apfloat/fuzz)
error: failed to run custom build command for `rustc_apfloat-fuzz v0.2.3+llvm-038f7debfda0 (/root/rustc_apfloat/fuzz)`

Caused by:
  process didn't exit successfully: `/root/rustc_apfloat/target/release/build/rustc_apfloat-fuzz-eb054ec7082b7eed/build-script-build` (exit status: 101)
  --- stdout
  cargo::rerun-if-changed=build.rs
  cargo::rerun-if-changed=cxx
  cargo::rerun-if-changed=src/apf_fuzz.cpp
  cargo::rustc-check-cfg=cfg(x86_sse2)
  cargo::rustc-cfg=x86_sse2

  --- stderr

  thread 'main' (34693) panicked at fuzz/build.rs:49:9:
  llvm dir `"/root/rustc_apfloat/target/llvm-downloads/llvm-project-038f7debfda0"` does not exist or cannot be reached. Perhaps you need to run etc/download-llvm.sh?
  note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
warning: build failed, waiting for other jobs to finish...
error: Recipe `fuzz-build` failed on line 26 with exit code 101
mkdir -p "fuzz/runs/in"
echo > "fuzz/runs/in/empty"
cargo afl build -p rustc_apfloat-fuzz --release
   Compiling num-traits v0.2.19
   Compiling libc v0.2.185
   Compiling rustc_apfloat-fuzz v0.2.3+llvm-038f7debfda0 (/root/rustc_apfloat/fuzz)
   Compiling syn v2.0.117
error: failed to run custom build command for `rustc_apfloat-fuzz v0.2.3+llvm-038f7debfda0 (/root/rustc_apfloat/fuzz)`

Caused by:
  process didn't exit successfully: `/root/rustc_apfloat/target/release/build/rustc_apfloat-fuzz-eb054ec7082b7eed/build-script-build` (exit status: 101)
  --- stdout
  cargo::rerun-if-changed=build.rs
  cargo::rerun-if-changed=cxx
  cargo::rerun-if-changed=src/apf_fuzz.cpp
  cargo::rustc-check-cfg=cfg(x86_sse2)
  cargo::rustc-cfg=x86_sse2

  --- stderr

  thread 'main' (34821) panicked at fuzz/build.rs:49:9:
  llvm dir `"/root/rustc_apfloat/target/llvm-downloads/llvm-project-038f7debfda0"` does not exist or cannot be reached. Perhaps you need to run etc/download-llvm.sh?
  note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
warning: build failed, waiting for other jobs to finish...
error: Recipe `fuzz-build` failed on line 26 with exit code 101
ls "fuzz/runs/out"/*/crashes/*
ls: cannot access 'fuzz/runs/out/*/crashes/*': No such file or directory
error: Recipe `decode` failed on line 58 with exit code 2
root@Penelope:~/rustc_apfloat#  etc/download-llvm.sh
++ cargo metadata --no-deps --format-version=1
++ jq -r '.packages | .[] | select(.name == "rustc_apfloat") | .version'
etc/download-llvm.sh: line 11: jq: command not found
+ version=
+ llvm_hash=
+ target_dir=target
+ out_dir=target/llvm-downloads
+ mkdir -p target/llvm-downloads
+ '[' -d target/llvm-downloads/llvm-project- ']'
+ tgz_url=https://codeload.github.com/llvm/llvm-project/tar.gz/
+ curl -sS https://codeload.github.com/llvm/llvm-project/tar.gz/
+ tar -C target/llvm-downloads -xz

gzip: stdin: not in gzip format
tar: Child returned status 1
tar: Error is not recoverable: exiting now
root@Penelope:~/rustc_apfloat#

Edit: Same issue with calling the fuzzer directly

root@Penelope:~/rustc_apfloat# # Build the fuzzing binary (`target/release/rustc_apfloat-fuzz`).
cargo afl build -p rustc_apfloat-fuzz --release
   Compiling clap_derive v4.6.0
   Compiling num-derive v0.4.2
   Compiling rustc_apfloat-fuzz v0.2.3+llvm-038f7debfda0 (/root/rustc_apfloat/fuzz)
   Compiling num-traits v0.2.19
   Compiling afl v0.15.24
error: failed to run custom build command for `rustc_apfloat-fuzz v0.2.3+llvm-038f7debfda0 (/root/rustc_apfloat/fuzz)`

Caused by:
  process didn't exit successfully: `/root/rustc_apfloat/target/release/build/rustc_apfloat-fuzz-eb054ec7082b7eed/build-script-build` (exit status: 101)
  --- stdout
  cargo::rerun-if-changed=build.rs
  cargo::rerun-if-changed=cxx
  cargo::rerun-if-changed=src/apf_fuzz.cpp
  cargo::rustc-check-cfg=cfg(x86_sse2)
  cargo::rustc-cfg=x86_sse2

  --- stderr

  thread 'main' (35694) panicked at fuzz/build.rs:49:9:
  llvm dir `"/root/rustc_apfloat/target/llvm-downloads/llvm-project-038f7debfda0"` does not exist or cannot be reached. Perhaps you need to run etc/download-llvm.sh?
  note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
warning: build failed, waiting for other jobs to finish...
root@Penelope:~/rustc_apfloat#

@tgross35
Copy link
Copy Markdown
Contributor

tgross35 commented Apr 14, 2026

llvm dir"/root/rustc_apfloat/target/llvm-downloads/llvm-project-038f7debfda0" does not exist or cannot be reached. Perhaps you need to run etc/download-llvm.sh?

🙂

I changed it so you can download LLVM separately rather than having the build script download the huge file every time.

@ValorZard
Copy link
Copy Markdown
Author

ValorZard commented Apr 14, 2026

llvm dir"/root/rustc_apfloat/target/llvm-downloads/llvm-project-038f7debfda0" does not exist or cannot be reached. Perhaps you need to run etc/download-llvm.sh?

🙂

I change it so you can download LLVM separately rather than having the build script download the huge file every time.

yeah no that script doesn't work

root@Penelope:~/rustc_apfloat#  etc/download-llvm.sh
++ cargo metadata --no-deps --format-version=1
++ jq -r '.packages | .[] | select(.name == "rustc_apfloat") | .version'
etc/download-llvm.sh: line 11: jq: command not found
+ version=
+ llvm_hash=
+ target_dir=target
+ out_dir=target/llvm-downloads
+ mkdir -p target/llvm-downloads
+ '[' -d target/llvm-downloads/llvm-project- ']'
+ tgz_url=https://codeload.github.com/llvm/llvm-project/tar.gz/
+ curl -sS https://codeload.github.com/llvm/llvm-project/tar.gz/
+ tar -C target/llvm-downloads -xz

gzip: stdin: not in gzip format
tar: Child returned status 1
tar: Error is not recoverable: exiting now
root@Penelope:~/rustc_apfloat#

EDIT: Nevermind, I had to install the jq command line thing

EDIT2: Okay after install jq, and then running the download script, I now get a different error:

root@Penelope:~/rustc_apfloat#  etc/download-llvm.sh
++ cargo metadata --no-deps --format-version=1
++ jq -r '.packages | .[] | select(.name == "rustc_apfloat") | .version'
+ version=0.2.3+llvm-038f7debfda0
+ llvm_hash=038f7debfda0
+ target_dir=target
+ out_dir=target/llvm-downloads
+ mkdir -p target/llvm-downloads
+ '[' -d target/llvm-downloads/llvm-project-038f7debfda0 ']'
+ tgz_url=https://codeload.github.com/llvm/llvm-project/tar.gz/038f7debfda0
+ curl -sS https://codeload.github.com/llvm/llvm-project/tar.gz/038f7debfda0
+ tar -C target/llvm-downloads -xz
root@Penelope:~/rustc_apfloat# # Create the corpus# Create the corpus
just gen
mkdir -p "fuzz/runs/in"
echo > "fuzz/runs/in/empty"
cargo afl build -p rustc_apfloat-fuzz --release
   Compiling rustc_apfloat-fuzz v0.2.3+llvm-038f7debfda0 (/root/rustc_apfloat/fuzz)
   Compiling clap v4.6.0
error: failed to run custom build command for `rustc_apfloat-fuzz v0.2.3+llvm-038f7debfda0 (/root/rustc_apfloat/fuzz)`

Caused by:
  process didn't exit successfully: `/root/rustc_apfloat/target/release/build/rustc_apfloat-fuzz-eb054ec7082b7eed/build-script-build` (exit status: 1)
  --- stdout
  cargo::rerun-if-changed=build.rs
  cargo::rerun-if-changed=cxx
  cargo::rerun-if-changed=src/apf_fuzz.cpp
  cargo::rustc-check-cfg=cfg(x86_sse2)
  cargo::rustc-cfg=x86_sse2
  + env -i "clang++" "-xc++" "-" "-std=c++17" "-g" "-fPIC" "-fno-exceptions" "-O3" "-march=native" "-I" "/root/rustc_apfloat/target/llvm-downloads/llvm-project-038f7debfda0/llvm/include" "-I" "/root/rustc_apfloat/target/llvm-downloads/llvm-project-038f7debfda0/llvm/lib/Support" "-I" "/root/rustc_apfloat/fuzz/cxx/include" "-DNDEBUG" "-DHAVE_UNISTD_H" "-DLLVM_ON_UNIX" "-DLLVM_ENABLE_THREADS=0" "--include" "/root/rustc_apfloat/fuzz/cxx/fuzz_unity_build.cpp" "--include" "/root/rustc_apfloat/fuzz/src/apf_fuzz.cpp" "-c" "-emit-llvm" "-o" "/root/rustc_apfloat/target/release/build/rustc_apfloat-fuzz-5d3285207d1a737e/out/cxx_apf_fuzz.bc"

  --- stderr
  Error: Os { code: 2, kind: NotFound, message: "No such file or directory" }
warning: build failed, waiting for other jobs to finish...
error: Recipe `fuzz-build` failed on line 26 with exit code 101
root@Penelope:~/rustc_apfloat#

@ValorZard
Copy link
Copy Markdown
Author

Weirdly enough, the llvm install script downloads it correctly
image
and the file it wants exists
image

So im not sure why the fuzz builder is complaining it can't find the file

@programmerjake
Copy link
Copy Markdown
Member

do you have clang++ installed?

@tgross35
Copy link
Copy Markdown
Contributor

etc/download-llvm.sh: line 11: jq: command not found

Whoops, that should have been more clear but I typoed -xux instead of -eux. Fixed in main.

For the rest: it's not saying it can't find the download, it's saying it can't find the program it's trying to launch (clang++). You need to install that, possibly also opt (or just llvm which should include everything)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants