xls icon indicating copy to clipboard operation
xls copied to clipboard

Parameteric function with full specialization fails to compile

Open sandwichmaker opened this issue 2 years ago • 3 comments

fn array_subnormals_to_zero_using_map<N:u32, EXP_SZ:u32, FRAC_SZ:u32>(
                            terms : apfloat::APFloat<EXP_SZ, FRAC_SZ>[N])
-> apfloat::APFloat<EXP_SZ, FRAC_SZ>[N] {
    map(terms, apfloat::subnormals_to_zero<EXP_SZ, FRAC_SZ>)
}

fails with

0019:                             terms : apfloat::APFloat<EXP_SZ, FRAC_SZ>[N])
0020: -> apfloat::APFloat<EXP_SZ, FRAC_SZ>[N] {
0021:     map(terms, apfloat::subnormals_to_zero<EXP_SZ, FRAC_SZ>)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^ ParseError: Expected '(', got ')': Expected a '(' after parametrics for function invocation.
0022: }
0023: 

however

fn array_subnormals_to_zero_using_map<N:u32, EXP_SZ:u32, FRAC_SZ:u32>(
                            terms : apfloat::APFloat<EXP_SZ, FRAC_SZ>[N])
-> apfloat::APFloat<EXP_SZ, FRAC_SZ>[N] {
    map(terms, apfloat::subnormals_to_zero)
}

compiles fine.

sandwichmaker avatar Jul 12 '23 21:07 sandwichmaker

Just to note what's going on, the parser doesn't support reference to an instantiated parametric function like that, so as a workaround you'd need to make a wrapper that has the full instantiation. It seems fortunate that the implicit instantiation works right though, so that probably is what you want here and the bug is filed more for completeness? LMK if I'm getting that wrong.

cdleary avatar Jul 13 '23 03:07 cdleary

I believe I have a case where automatic deduction of parameters is not going to work.

Here is variant one, where the parser complains about the parametrics

import apfloat
import std 

fn foo<N:u32, K:u32,
       IN_EXP_SZ:u32, IN_FRAC_SZ:u32,
       OUT_FRAC_SZ:u32, OUT_SZ:u32 = {OUT_FRAC_SZ + u32:1 + K + u32:1 + std::clog2(N)}>(
       x : apfloat::APFloat<IN_EXP_SZ, IN_FRAC_SZ>) -> sN[OUT_SZ] {
          sN[OUT_SZ] : [sN[OUT_SZ]:0, ...]
       }

fn bar<N:u32, K:u32,
       IN_EXP_SZ:u32, IN_FRAC_SZ:u32,
       OUT_EXP_SZ:u32, OUT_FRAC_SZ:u32>(
       terms : apfloat::APFloat<IN_EXP_SZ, IN_FRAC_SZ>[N]) -> bool {
    let x = map(terms, foo<N, K, IN_EXP_SZ, IN_FRAC_SZ, OUT_FRAC_SZ>)
    //let x = map(terms, foo);
    false
}
                       
pub fn main() -> bool{
    const N = u32:10;
    const K = u32:5;
    const IN_EXP_SZ = u32:1;
    const IN_FRAC_SZ = u32:2;
    const OUT_FRAC_SZ = u32:3;
    const OUT_SZ = u32:3;
    type Float = apfloat::APFloat<IN_EXP_SZ, IN_FRAC_SZ>;
    let one = apfloat::one<IN_EXP_SZ, IN_FRAC_SZ>(u1:1);
    let terms = Float[N] : [one, ...];
    bar(terms)
}

with

0014:        OUT_EXP_SZ:u32, OUT_FRAC_SZ:u32>(
0015:        terms : apfloat::APFloat<IN_EXP_SZ, IN_FRAC_SZ>[N]) -> bool {
0016:     let x = map(terms, foo<N, K, IN_EXP_SZ, IN_FRAC_SZ, OUT_FRAC_SZ>)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^ ParseError: Expected '(', got ')': Expected a '(' after parametrics for function invocation.
0017:     //let x = map(terms, foo);
0018:     false

and here is variant 2

mport apfloat
import std 

fn foo<N:u32, K:u32,
       IN_EXP_SZ:u32, IN_FRAC_SZ:u32,
       OUT_FRAC_SZ:u32, OUT_SZ:u32 = {OUT_FRAC_SZ + u32:1 + K + u32:1 + std::clog2(N)}>(
       x : apfloat::APFloat<IN_EXP_SZ, IN_FRAC_SZ>) -> sN[OUT_SZ] {
          sN[OUT_SZ] : [sN[OUT_SZ]:0, ...]
       }

fn bar<N:u32, K:u32,
       IN_EXP_SZ:u32, IN_FRAC_SZ:u32,
       OUT_EXP_SZ:u32, OUT_FRAC_SZ:u32>(
       terms : apfloat::APFloat<IN_EXP_SZ, IN_FRAC_SZ>[N]) -> bool {
    // let x = map(terms, foo<N, K, IN_EXP_SZ, IN_FRAC_SZ, OUT_FRAC_SZ>)
    let x = map(terms, foo);
    false
}
                       
pub fn main() -> bool{
    const N = u32:10;
    const K = u32:5;
    const IN_EXP_SZ = u32:1;
    const IN_FRAC_SZ = u32:2;
    const OUT_FRAC_SZ = u32:3;
    const OUT_SZ = u32:3;
    type Float = apfloat::APFloat<IN_EXP_SZ, IN_FRAC_SZ>;
    let one = apfloat::one<IN_EXP_SZ, IN_FRAC_SZ>(u1:1);
    let terms = Float[N] : [one, ...];
    bar(terms)
}

where the parser now complains that not all the parameters were specified.

0015:        terms : apfloat::APFloat<IN_EXP_SZ, IN_FRAC_SZ>[N]) -> bool {
0016:     // let x = map(terms, foo<N, K, IN_EXP_SZ, IN_FRAC_SZ, OUT_FRAC_SZ>)
0017:     let x = map(terms, foo);
~~~~~~~~~~~~~~~~~~~~~^----------^ TypeInferenceError: sN[OUT_SZ] Instantiated return type did not have all parametrics resolved.
0018:     false
0019: }

sandwichmaker avatar Jul 13 '23 03:07 sandwichmaker

Is there a way to :heavy_plus_sign: 1 an issue ? I just ran into the same thing.

hzeller avatar Jun 13 '24 21:06 hzeller

I had to make a number of changes to the example in variant 1 due to valid compile errors but the following does now work after https://github.com/google/xls/commit/28b4476ed8712f4e31a43898cde0274a7b4ac81f:

import apfloat;
import std;

fn foo
    <N: u32, K: u32, IN_EXP_SZ: u32, IN_FRAC_SZ: u32, OUT_FRAC_SZ: u32,
     OUT_SZ: u32 = {OUT_FRAC_SZ + u32:1 + K + u32:1 + std::clog2(N)}>
    (x: apfloat::APFloat<IN_EXP_SZ, IN_FRAC_SZ>) -> sN[OUT_SZ] {
    sN[OUT_SZ]:0
}

fn bar<N: u32, K: u32, IN_EXP_SZ: u32, IN_FRAC_SZ: u32, OUT_EXP_SZ: u32, OUT_FRAC_SZ: u32>
    (terms: apfloat::APFloat<IN_EXP_SZ, IN_FRAC_SZ>[N]) -> () {
    let x = map(terms, foo<N, K, IN_EXP_SZ, IN_FRAC_SZ, OUT_FRAC_SZ>);
    // let x = map(terms, foo);
}

pub fn main() -> () {
    const N = u32:10;
    const K = u32:5;
    const IN_EXP_SZ = u32:1;
    const IN_FRAC_SZ = u32:2;
    const OUT_EXP_SZ = u32:2;
    const OUT_FRAC_SZ = u32:3;
    const OUT_SZ = u32:3;
    type Float = apfloat::APFloat<IN_EXP_SZ, IN_FRAC_SZ>;
    let one = apfloat::one<IN_EXP_SZ, IN_FRAC_SZ>(u1:1);
    let terms = Float[N]:[one, ...];
    bar<N, K, IN_EXP_SZ, IN_FRAC_SZ, OUT_EXP_SZ, OUT_FRAC_SZ>(terms)
}

mikex-oss avatar Oct 24 '24 20:10 mikex-oss