How to stop zig from producing rv32c instructions?

I am using the baseline cpu model, however compressed instructions are still being produced, which are not compatible with my target. How can this be remedied?

I don’t know because I haven’t messed with it, but you should give Target.zig a closer read. It’s possible the “features” will tell you the correct -m flag to add to prevent this, or you will learn that Zig doesn’t have the ability to turn this off, in which case you could file an issue.

You could run this on your target machine:

zig build-exe -target native --show-builtin

You also could compare / diff the results of that with the target you use for (cross-)compiling.

So something like:

zig build-exe -target native --show-builtin > native

// on host machine
zig build-exe -target <cross-compile-target> --show-builtin > actual-target

// rsync user@host:projects/bla/native .
diff native actual-target
1 Like

This is the definition of the baseline rv32:

pub const baseline_rv32: CpuModel = .{
    .name = "baseline_rv32",
    .llvm_name = null,
    .features = featureSet(&[_]Feature{
        .@"32bit",
        .a,
        .c,
        .d,
        .i,
        .m,
    }),
}

So I think you just copy it, removing the .c.

3 Likes

In CLI, that’s -mcpu baseline-c. You can use + and - to add/remove CPU features respectively.

For example:

zig build-exe --show-builtin -target riscv32-linux -mcpu baseline-c
const std = @import("std");
/// Zig version. When writing code that supports multiple versions of Zig, prefer
/// feature detection (i.e. with `@hasDecl` or `@hasField`) over version checks.
pub const zig_version = std.SemanticVersion.parse(zig_version_string) catch unreachable;
pub const zig_version_string = "0.17.0-dev.1143+e0e145048";
pub const zig_backend = std.lang.CompilerBackend.stage2_llvm;

pub const output_mode: std.lang.OutputMode = .Exe;
pub const link_mode: std.lang.LinkMode = .static;
pub const unwind_tables: std.lang.UnwindTables = .async;
pub const is_test = false;
pub const single_threaded = false;
pub const abi: std.Target.Abi = .musl;
pub const cpu: std.Target.Cpu = .{
    .arch = .riscv32,
    .model = &std.Target.riscv.cpu.baseline_rv32,
    .features = std.Target.riscv.featureSet(&.{
        .@"32bit",
        .a,
        .d,
        .f,
        .i,
        .m,
        .zaamo,
        .zalrsc,
        .zca,
        .zicsr,
        .zmmul,
    }),
};
pub const os: std.Target.Os = .{
    .tag = .linux,
    .version_range = .{ .linux = .{
        .range = .{
            .min = .{
                .major = 5,
                .minor = 10,
                .patch = 0,
            },
            .max = .{
                .major = 7,
                .minor = 1,
                .patch = 9,
            },
        },
        .glibc = .{
            .major = 2,
            .minor = 33,
            .patch = 0,
        },
        .android = 29,
    }},
};
pub const target: std.Target = .{
    .cpu = cpu,
    .os = os,
    .abi = abi,
    .ofmt = object_format,
    .dynamic_linker = .init("/lib/ld-musl-riscv32.so.1"),
};
pub const object_format: std.Target.ObjectFormat = .elf;
pub const mode: std.lang.OptimizeMode = .Debug;
pub const link_libc = false;
pub const link_libcpp = false;
pub const have_error_return_tracing = true;
pub const valgrind_support = false;
pub const sanitize_thread = false;
pub const fuzz = false;
pub const position_independent_code = false;
pub const position_independent_executable = false;
pub const strip_debug_info = false;
pub const code_model: std.lang.CodeModel = .default;
pub const omit_frame_pointer = false;

There is also generic which is an empty feature set so you can explicitly add only the features you want.

8 Likes

Must admit, the fact that “baseline” isn’t just RV32I with no extensions is a little surprising to me. Granted, it’s probably not the most useful target, but it’s what you start adding to. I guess that’s generic.

My second guess would be baseline==RV32G as the spec says:

We have also defined an abbreviation “G” to represent the “IMAFDZicsr_Zifencei” base and extensions, as this is intended to represent our standard general-purpose ISA.

That’s close to what we have (“IMACD”) as “D” implies “F” and “F” implies “Zicsr”.