#How can I port this C code to Zig?

1 messages · Page 1 of 1 (latest)

snow bone
#

I have this C code I would like to try out in Zig.

while (1) {
    __m128i xmm_str1 = _mm_loadu_si128((__m128i*)(str1 + i));
    __m128i xmm_str2 = _mm_loadu_si128((__m128i*)(str2 + i));
    uint32_t result = _mm_cmpistri(xmm_str1, xmm_str2, 0b11000);
    i += result;
    if (result != 16) return i; // Found a mismatch
}

Unfortunately, the _mm_cmpistri C intrinsic is not yet supported by Zig, so I have to come up with another way to do _mm_cmpistri. I tried to do this with inline assembly. Here is what I have so far:

pub fn mm_cmpistri(noalias str1: []const u8, noalias str2: []const u8) u32 {
    return asm ("pcmpistri %[str1], %[str2], 0b11000" // I just hardcoded the flags I want
        : [out] "=x" (-> u32),
        : [str1] "x" (@as(@Vector(16, u8), str1[0..16].*)),
          [str2] "x" (@as(@Vector(16, u8), str2[0..16].*)),
    );
}

Unfortunately, I am not sure how to get the data written to the ECX register out and return it. I also keep getting an error that says error: <inline asm>:1:12: invalid operand for instruction. Is there any cheatsheet for inline assembly that could help me figure stuff like this out?

kind elbow
snow bone
#

I tried this but I still haven't gotten it to compile. Does anyone know if this is a bug or if there is a way to accomplish this?

pub fn mm_cmpistri(noalias str1: []const u8, noalias str2: []const u8) u32 {
    return asm ("pcmpistri %[a], %[b], 0b11000"
        : [ret] "={ecx}" (-> u32),
        : [a] "x" (@as(@Vector(16, u8), str1[0..16].*)),
          [b] "x" (@as(@Vector(16, u8), str2[0..16].*)),
        : "cc"
    );
}
kind elbow
#

@snow bone you had the operand order wrong, here's a neat proper implementation:

const std = @import("std");

pub const CmpFlags = packed struct(u8) {
    pub const ComparisonMode = enum(u2) {
        unsigned_byte = 0,
        unsigned_word = 1,
        signed_byte   = 2,
        signed_word   = 3,
    };
    pub const AggregationMode = enum(u2) {
        any_bytes_equal = 0,
        ranges = 1,
        all_bytes_equal = 2,
        substring = 3,
    };
    pub const Polarity = enum(u2) {
        positive = 0,
        negative = 1,
        masked_positive = 2,
        masked_negative = 3,
    };
    pub const OutputMode = enum(u1) {
        lsb = 0,
        msb = 1,
    };
    cmp: ComparisonMode = .unsigned_byte,
    agg: AggregationMode = .any_bytes_equal,
    pol: Polarity = .positive,
    out: OutputMode = .lsb,
    zero: u1 = 0,
};

inline fn cmpistri(a: @Vector(16, u8), b: @Vector(16, u8), comptime imm: []const u8) u5 {
    return @intCast(u5, asm ("pcmpistri $" ++ imm ++ ", %[b], %[a]"
        : [ret] "={ecx}" (-> u8),
        : [a] "x" (a),
          [b] "x" (b),
        : "cc"
    ));
}

pub inline fn vectorCompareStrings(str1: @Vector(16, u8), str2: @Vector(16, u8), comptime flags: CmpFlags) u5 {
    comptime var tmp: [3]u8 = undefined;
    const s = comptime std.fmt.bufPrint(&tmp, "{d}", .{@bitCast(u8, flags)}) catch unreachable;
    return cmpistri(str1, str2, s);
}

test {
    const s1: [16]u8 = "aaaaaaaaaaaaaaaa".*;
    const s2: [16]u8 = "aaaaaaaaaaaaaaba".*;
    try std.testing.expectEqual(@as(u5, 14), vectorCompareStrings(s1, s2, .{.agg = .all_bytes_equal, .pol = .negative}));
    try std.testing.expectEqual(@as(u5, 16), vectorCompareStrings(s1, s1, .{.agg = .all_bytes_equal, .pol = .negative}));
}
snow bone
#

Oh my gosh, I was so frustrated I couldn't get it to work yesterday. I did try reversing the arguments but it still didn't work. It was the '$' before the number. I didn't put a '$' before the constant............ that's why I couldn't get it to work for hours

kind elbow
#

been there :)
happy you got it to work

#

you can react to your thread with ✅ to mark it as solved

snow bone
#

This didn't work 😦

kind elbow
#

yeah

#

this works

snow bone
#

Oh, maybe the first thing I tried has to be done by a bot with privileges?

kind elbow
#

yeah

#

insert obligatory remark about light mode here

kind elbow
snow bone
#

Lol. I typically use an e-ink display fyi

kind elbow
#

ah

snow bone
#

Light mode works way better than dark mode on such devices and it doesn't emit light so it is not hard to look at

kind elbow
#

yeah, I'm in agreement (I've used dark websites on my e reader shudders)