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

do not analyze functions with pointer if they're not called from comptime or used at runtime #18753

Open
mitchellh opened this issue Jan 30, 2024 · 2 comments
Labels
enhancement Solving this issue will likely involve adding new logic or components to the codebase. frontend Tokenization, parsing, AstGen, Sema, and Liveness.
Milestone

Comments

@mitchellh
Copy link
Contributor

mitchellh commented Jan 30, 2024

Zig Version

0.12.0-dev.2341+92211135f

Steps to Reproduce and Observed Behavior

const std = @import("std");

pub fn bad() void {
    @compileError("do not analyze me");
}

pub fn good() void {
    std.log.info("hello", .{});
}

pub fn callFirst(comptime funcs: anytype) void {
    funcs[0]();
}

pub fn main() !void {
    callFirst(.{ &good, &bad });
}

Expected Behavior

I'd like fn bad to not be analyzed, since the comptime code path:

  1. Doesn't call the function
  2. Doesn't emit runtime code to use the function pointer in any scenario

My real world use case is that I'm implementing a comptime function that chooses the best implementation of a function based on runtime-available CPU features. I'd like to pass it the function pointer for all possible implementations, but I don't want to include impossible implementations. For example, an ARM NEON implementation on x86_64.

This is me implementing #1018 myself using comptime.

@mitchellh mitchellh added the bug Observed behavior contradicts documented or intended behavior label Jan 30, 2024
@mitchellh
Copy link
Contributor Author

mitchellh commented Jan 30, 2024

This is my workaround code using @field as a way to avoid the analysis:

pub fn funcMap(
    comptime Func: type,
    comptime name: []const u8,
    v: ISA,
    comptime map: anytype,
) *const Func {
    switch (v) {
        inline else => |tag| {
            // If this tag isn't possible, compile no code for this case.
            if (comptime !possible(tag)) unreachable;

            // Find the entry for this tag and return the function.
            inline for (map) |entry| {
                if (entry[0] == tag) return @field(entry[1], name);
            } else unreachable;
        },
    }
}

Example usage (this works):

pub fn countFunc(v: isa.ISA) *const Count {
    return isa.funcMap(Count, "count", v, .{
        .{ .avx2, AVX2 },
        .{ .neon, Neon },
        .{ .scalar, Scalar },
    });
}

What I would prefer (does not work):

pub fn countFunc(v: isa.ISA) *const Count {
    // Could also omit the `Count` arg here pretty easily.
    return isa.funcMap(Count, v, .{
        .{ .avx2, &AVX2.count },
        .{ .neon, &Neon.count },
        .{ .scalar, &Scalar.count },
    });
}

The neon implementation would be completely omitted from non-aarch64 builds. (isa is my own custom file that implements runtime ISA detection and so on)

@Vexu Vexu added enhancement Solving this issue will likely involve adding new logic or components to the codebase. frontend Tokenization, parsing, AstGen, Sema, and Liveness. labels Jan 30, 2024
@Vexu Vexu added this to the 0.13.0 milestone Jan 30, 2024
@mitchellh
Copy link
Contributor Author

It was recommended in Discord to try to use function bodies instead of pointers. That works in trivial cases but crashes in some cases. I opened a new bug here: #18754

I'm fine closing this if that is the suggested path forward, though! I'm going to keep this open in case this behavior is desired even with &.

@andrewrk andrewrk removed the bug Observed behavior contradicts documented or intended behavior label Jan 30, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement Solving this issue will likely involve adding new logic or components to the codebase. frontend Tokenization, parsing, AstGen, Sema, and Liveness.
Projects
None yet
Development

No branches or pull requests

3 participants