Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Add optimized_to_const intrinsic #96604

Closed
wants to merge 2 commits into from

Conversation

nbdd0121
Copy link
Contributor

@nbdd0121 nbdd0121 commented May 1, 2022

This PR adds an optimized_to_const that is roughly equivalent to GCC's __builtin_constant_p -- returns true if the argument is folded to const and false is not.

Example::

#![feature(core_intrinsics)]

use core::intrinsics::optimized_to_const;

fn is_zero(x: &[u8]) -> bool {
    x.iter().all(|x| *x == 0)
}

#[inline(always)]
fn is_definitely_zero<const N: usize>(x: &[u8; N]) -> bool {
    if optimized_to_const(x) {
        is_zero(x)
    } else {
        false
    }
}

pub fn foo() -> bool {
    is_definitely_zero(&[0; 32])
}

pub fn bar() -> bool {
    is_definitely_zero(&[1; 32])
}

pub fn baz(v: &[u8; 32]) -> bool {
    is_definitely_zero(v)
}

This code snippet generates:

Disassembly of section .text.example::foo:

0000000000000000 <example::foo>:
   0:	b0 01                	mov    $0x1,%al
   2:	c3                   	retq   

Disassembly of section .text.example::bar:

0000000000000000 <example::bar>:
   0:	31 c0                	xor    %eax,%eax
   2:	c3                   	retq   

Disassembly of section .text.example::baz:

0000000000000000 <example::baz>:
   0:	31 c0                	xor    %eax,%eax
   2:	c3                   	retq   

cc @scottmcm @Mark-Simulacrum

r? @ghost

@rustbot rustbot added T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-libs Relevant to the library team, which will review and decide on the PR/issue. labels May 1, 2022
@nbdd0121
Copy link
Contributor Author

nbdd0121 commented May 1, 2022

Unfortunately LLVM currently seems to have problem generating optimal code: if array size is raised to 64, then foo will still generate code that does some compute and eventually return true (because LLVM can't fold is_zero despite constant input).

I tried another coding style

#[inline(always)]
fn is_definitely_zero2<const N: usize>(x: &[u8; N]) -> bool {
    let zero = is_zero(x);
    if optimized_to_const(&zero) {
        zero
    } else {
        false
    }
}

This works similarly if size is 32, but if size is 64, then in this case it's even worse: both foo and baz will generate code now that does all compute and unconditionally return false. Run opt on the generated & optimized LLVM assembly for the second time will remove all the unwanted computation and replace with a single false return, though.

@the8472
Copy link
Member

the8472 commented May 1, 2022

If it has already been folded to a const at that point, could it be turned into a const fn returning the value as const?

@the8472
Copy link
Member

the8472 commented May 21, 2022

I meant would something like this be possible?

const fn precompute(x: u64) -> Option<u32> {
   return match x {
     1 => // special case
     2 => // special case
     _ => None
   }
}



fn foo(x: u64)  -> u32 {
   let precomputed = const { precompute(optimized_or_default(&x, u64::MAX)) }
   // magic happens here -------------------------------------^
   if let Some(p) = precomputed {
      return p;
   }
   // runtime impl 
}

Actually, thinking about it, this looks a lot like const_eval_select, except that it would also apply to const-optimizations in non-const contexts?

@bors
Copy link
Contributor

bors commented Jul 22, 2022

☔ The latest upstream changes (presumably #99420) made this pull request unmergeable. Please resolve the merge conflicts.

@bors bors added the S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. label Jul 22, 2022
@Dylan-DPC
Copy link
Member

Closing this as it has been inactive for a long time. Feel free to open a new pr if required

@Dylan-DPC Dylan-DPC closed this Jan 15, 2023
@Dylan-DPC Dylan-DPC added S-inactive Status: Inactive and waiting on the author. This is often applied to closed PRs. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Jan 15, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-inactive Status: Inactive and waiting on the author. This is often applied to closed PRs. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-libs Relevant to the library team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants