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

Test variadic functions #1

Open
bjorn3 opened this issue Mar 23, 2022 · 4 comments
Open

Test variadic functions #1

bjorn3 opened this issue Mar 23, 2022 · 4 comments
Labels
enhancement New feature or request help wanted Extra attention is needed test-request Add a test to the suite for this

Comments

@bjorn3
Copy link
Contributor

bjorn3 commented Mar 23, 2022

Most platforms implement them by passing variadic arguments the same way as non-variadic arguments. As I understand it AArch64 macOS however forces the variadic arguments to always be passed on the stack even if there are still free registers.

@Gankra
Copy link
Owner

Gankra commented Mar 23, 2022

Ooh fun, good tip!

@Gankra
Copy link
Owner

Gankra commented Jun 30, 2024

We're way closer to this being possible with #20 landed, but variadics are specifically a feature I punted on shipping in the first version. It would be helpful to have a few sketches of test inputs we'd want to express. I've generally avoided messing with variadics in my career, so I don't have a sense of like, how it's normally used.

That said with the new ValTree abstraction we have the ability for both sides to pre-agree on the values/types passed at compile time (used to allow us to test untagged unions, and even self-referential types which therefore have variable field counts... which is kinda what varargs are).

@Gankra Gankra added help wanted Extra attention is needed enhancement New feature or request test-request Add a test to the suite for this labels Jun 30, 2024
@Gankra
Copy link
Owner

Gankra commented Jul 1, 2024

Rough sketch of an idea here...

The following syntax could be supported:

fn "my_func" {
  inputs {
     _ "f32"
     _ "i32"
     _ "..." {
         _ "f32"
         _ "u64"   
     }
  }
}

The new syntax is here:

     _ "..." {
         _ "f32"
         _ "u64"   
     }

We would take "argument with type ..." to mean varargs, and expect the body of a union decl to follow.

The idea here is that this would let you specify the set of possible types you want to test the varargs with.

We wouldn't actually create a TyIdx for this, but we would embed a UnionTy in the function arg.

In the ValueTree, when we encounter such an argument:

abi-cafe/src/abis/vals.rs

Lines 120 to 130 in dd37470

.map(|arg| {
let mut vals = vec![];
let arg_name = arg.name.to_string();
generators.build_values(types, arg.ty, &mut vals, arg_name.clone())?;
Ok(ArgValues {
ty: arg.ty,
arg_name,
vals,
})
})
.collect::<Result<Vec<_>, GenerateError>>()?;

We would then apply an expansion from one arg to N args as follows in the above code:

if let ArgKind::Varargs(varargs_union) = arg.kind {
    // Burn a Value to compute the length of the varargs length, uniformly in 0..8 (arbitrary)
    let mut varargs_len_generator = generators.next();
    let mut varargs_len = varargs_len_generator.generate_index(8);
    let mut sub_args = vec![];
    for sub_arg_idx in sub_args.len() {
        // Burn another Value to compute the the type of the vararg
        let tag_generator = generators.next(ty_idx, path.clone());
        let active_variant_idx = tag_generator.generate_idx(varargs_union.fields.len());

        // Now generate a (sub)arg with the selected type
        if let Some(field) = varargs_union.fields.get(active_variant_idx) {
            let mut vals = vec![];
            let arg_name = format!("{}{sub_arg_idx}", arg.name.to_string());
            generators.build_values(types, arg.ty, &mut vals, arg_name.clone())?;
            sub_args.push(ArgValues {
                ty: field.ty,
                arg_name,
                vals,
            });
        }
    }
    Ok(sub_args)
}

It's tempting here to "evaporate" the varargs completely but for various reasons we'll probably just want to make it so anyone who wants to look at args needs to deal with them potentially being a list of arguments. Also more code will need to shift to treating the ValueTree's accounting of the function args as canonical, as opposed to the one from the kdl-script type system. Right now it's kinda arbitrary/inconsistent in the code, i think.

@Gankra
Copy link
Owner

Gankra commented Jul 1, 2024

The benefits of doing the expansion in the ValueTree and remembering the "real" signature are that:

  • The length and type of each varargs can be randomized per varargs, and per ValueGeneratorKind. This means passing --gen-vals=random17 would generate completely different lists from --gen-vals=random35 (but reproducible)
  • When reporting/analyzing, we won't be confused about what args are what (or rather, we have the opportunity to indicate this is varargs[2] or w/e)
  • We have the option to either generate either the varargs version of the signature or the hardcoded version of the signature (since some abis support varargs punning with normal functions, for some godforsaken reason)
    • I'm not sure how exactly we'd apply this option, but, nice to think about

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request help wanted Extra attention is needed test-request Add a test to the suite for this
Projects
None yet
Development

No branches or pull requests

2 participants