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

Vector element access #3575

Closed
wants to merge 5 commits into from
Closed

Vector element access #3575

wants to merge 5 commits into from

Conversation

andrewrk
Copy link
Member

@andrewrk andrewrk commented Nov 2, 2019

This is my re-implementation of the vector element access from #2945.

I went through all this trouble, but then I realized that I had already considered this when I typed up #903 (comment):

[ ] field access / pointer access / array access when the vector is of pointer type
[ ] compile error for trying to get a pointer to a vector element

Compile error for trying to get a pointer to a vector element? But why? In this PR you can see it works just fine.

Because, my friends, vectors can be vectors of pointers, in which case x[y] should produce a new vector with each pointer dereferenced, not access a single element.

So this was a waste of time. Element access of vectors can be implemented either as builtin functions @vectorElemLoad and @vectorElemStore, or even in userland, by bitcasting a vector to and from an array. But x[y] syntax is reserved for when you have a vector of pointers.

cc @shawnl
cc @dimenus

@andrewrk andrewrk closed this Nov 2, 2019
@andrewrk andrewrk mentioned this pull request Nov 2, 2019
@ghost
Copy link

ghost commented Nov 2, 2019

I'm confused, if x[y] "dereferences" a vector, what is y?

@andrewrk
Copy link
Member Author

andrewrk commented Nov 2, 2019

@dbandstra here's a test case that is expected to pass once #903 is closed:

const std = @import("std");
const expect = std.testing.expect;

test "vector of pointers" {
    var array0: [10]i32 = undefined;
    var array1: [10]i32 = undefined;
    var array2: [10]i32 = undefined;
    var array3: [10]i32 = undefined;

    const vector_of_ptrs: @Vector(4, [*]i32) = [_][*]i32{ &array0, &array1, &array2, &array3 };

    vector_of_ptrs[1] = 42;

    expect(array0[1] == 42);
    expect(array1[1] == 42);
    expect(array2[1] == 42);
    expect(array3[1] == 42);
}

Does that help clarify?

@ghost
Copy link

ghost commented Nov 2, 2019

Thanks I get it now. I had something like @Vector(4, *i32) in my head. I didn't consider a vector of pointers to arrays.

I guess .* syntax will also go "through" the vector? (Meaning you would need another builtin function to be able to dereference a pointer to a vector?)

@shawnl
Copy link
Contributor

shawnl commented Nov 2, 2019 via email

@andrewrk
Copy link
Member Author

andrewrk commented Nov 2, 2019

I guess .* syntax will also go "through" the vector? (Meaning you would need another builtin function to be able to dereference a pointer to a vector?)

Good question. Vectors of integers act like integers, allowing operations that work on the element type. Vectors of pointers act like pointers, allowing operations that work on the element type.

Just like .* on a **i32 dereferences the outer pointer first, .* on a *@Vector(X, *i32) dereferences the outer vector, not the element. However .* on a @Vector(X, *i32) will produce a new vector of type @Vector(X, i32).

What code would actually use this form of dereferencing? There is no hardware instruction for this type of thing either.

Vectors of pointers makes sense, and ability to dereference vectors of pointers follows naturally. One can do all the operations on a vector of elements that one can do on the elements themselves.

LLVM supports this as well. In theory hardware could support for this, although I do not know of any architectures that do this.

@shawnl
Copy link
Contributor

shawnl commented Nov 3, 2019

LLVM supports this as well. In theory hardware could support for this, although I do not know of any architectures that do this.

yes, you can do this with vectorgather and vectorscatter, and my patch has that (@gather and @scatter. Also for the more common case of vectorgather and vectorscatter from a single array, my patch supports a abbreviated syntax where you pass a vector of indexes as the array index. (index either of a vector or array, if vector it generates a shufflevector)

@andrewrk
Copy link
Member Author

andrewrk commented Nov 3, 2019

Corrected test case (note that the index is now a vector):

const std = @import("std");
const expect = std.testing.expect;

test "vector of pointers" {
    var array0: [10]i32 = undefined;
    var array1: [10]i32 = undefined;
    var array2: [10]i32 = undefined;
    var array3: [10]i32 = undefined;

    const vector_of_ptrs: @Vector(4, [*]i32) = [_][*]i32{ &array0, &array1, &array2, &array3 };
    const index: @Vector(4, u32) == [_]u32{5, 2, 3, 6};

    vector_of_ptrs[index] = [_]i32{11, 22, 33, 44};

    expect(array0[5] == 11);
    expect(array1[2] == 22);
    expect(array2[3] == 33);
    expect(array3[6] == 44);
}

@andrewrk andrewrk reopened this Nov 3, 2019
@shawnl
Copy link
Contributor

shawnl commented Nov 3, 2019

Here is a test case it fails:


export fn storev(ptr: [*]i32, x: i32) void {
    (ptr + 1).* = x;
}

test "store vector elements via comptime index" {
    const S = struct {
        fn doTheTest() void {
            var v: @Vector(4, i32) = [_]i32{ 1, 5, 3, undefined };

            v[2] = 42;
            expect(v[1] == 5);
            v[3] = -364;
            expect(v[2] == 42);
            expect(-364 == v[3]);

            storev(&v[0], 100);
            expect(v[1] == 100);
        }
    };

    S.doTheTest();
    comptime S.doTheTest();
}

There are two problems here: supporting the C ABI here, and doing pointer arithmetic on the passed pointer. (I am not sure if I understand the difference between [*] and * correctly in this test, so the test might be incorrect, but that doesn't effect what is being tested)

@dimenus
Copy link
Contributor

dimenus commented Nov 3, 2019

I'm not sure I like this dereference idea. It feels opaque and hard to read when passing through code. We could also just disallow indexing on vectors and expect the user to bitcast or provide builtins (as Andrew first suggested).

@shawnl
Copy link
Contributor

shawnl commented Nov 3, 2019

@dimenus accessing elements of vectors this way is extremely common in code, and it is the way C does it.

Andrew's dereference idea is ambiguous with my current proposed patch that turns vectors with vector indexes into a @Shuffle, that returns just the indexed elements. In short, it is ambiguous if the indexes refer to elements of the vector, or elements of the array's the vector points to (if they are all pointers and all support pointer arithmetic). Also, such an operation would be limited by the type system, as they would all have to be the same type, and the typical use-case of them all having the same base address is already covered by supporting array[index vector]. If the types are different you would want to compose a vector of sizeof() values, but again I know of no actual code that would do this, and you could always use @gather/@scatter directly. So I am against dereferencing vectors of pointers in this way.

@shawnl
Copy link
Contributor

shawnl commented Nov 5, 2019

Here is a test case based on @dimenus test cases, and I think it requires ResultLoc to work correctly.

const expect = @import("std").debug.expect;

const Vec4Obj = struct {
    data: @Vector(4, f32),
};

test "vector in a struct" {
    const S = struct {
        fn doTheTest() void {
            var foo = Vec4Obj {
                .data = [_]f32 { 1, 2, 3, 4},
            };
            expect(foo.data[2] == 3);
        }
    };
    S.doTheTest();
    comptime S.doTheTest();
}

shawnl added a commit to shawnl/zig that referenced this pull request Nov 5, 2019
<andrewrk> tomorrow, end of day, ziglang#3580 will be closed and ziglang#3575 will be
closed, and dimenus's examples will work (except for vector literals which
is not happening, see ziglang#208)
@andrewrk andrewrk closed this in cb8af1c Nov 5, 2019
@andrewrk andrewrk deleted the vector-element-access branch November 5, 2019 18:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants