1

What I'm trying to do

I'm trying to convert a buffer of type [Int] to [[Int]]. Since arrays are not super easy to return in C, I'm creating a new empty array and passing the pointer into a void function that is supposed to fill the address space with Integers from the buffer.

Afterwards, the matrices are supposed to get added and the result written into a result buffer.

The problem

For some reason, it can't find my function. I'm kind of new to c++ so excuse me when it's something simple I'm overlooking here. The function is not part of a class. So technically it should be in the same namespace?

#include <metal_stdlib>
using namespace metal;



void createMatrix(device int **arr, int count, int buff[]) {
    for(int i = 0; i < count; i++)
     for(int j = 0; j < count; j++)
        arr[j][i] = buff[i + j];
}


kernel void addition_compute_function(constant int *arr1        [[ buffer(0) ]],
                                      constant int *arr2        [[ buffer(1) ]],
                                      device   int *resultArray [[ buffer(2) ]],
                                               uint   index [[ thread_position_in_grid ]]) {



    int array1[6][6] = {{0}};
    createMatrix(**array1, 6, *arr1); // ERROR: No matching function for call to 'createMatrix'
    
    int array2[6][6] = {{0}};
    createMatrix(**array2, 6, *arr2); // ERROR: No matching function for call to 'createMatrix'

    for (int i = 1; i <= 6; i++){
            resultArray[i][index] = array1[i][index] + array2[i][index]; // ERROR: Subscripted value is not an array, pointer, or vector
    }

}

What I tried

Most questions regarding this error are concerning methods of a class getting called after an object is initialized. This isn't the case here, so no dice thus far in researching the problem.

Edit, incorporated feedback

#include <metal_stdlib>
using namespace metal;



void createMatrix(device int (*arr)[6], int count,constant int* buff) {
    for(int i = 0; i < count; i++)
     for(int j = 0; j < count; j++)
        arr[j][i] = buff[i + j];
}


kernel void addition_compute_function(constant int *arr1        [[ buffer(0) ]],
                                      constant int *arr2        [[ buffer(1) ]],
                                      device   int *resultArray [[ buffer(2) ]],
                                               uint   index [[ thread_position_in_grid ]]) {



    int array1[6][6] = {{0}};
    createMatrix(array1, 6, arr1); //ERROR: No matching function for call to 'createMatrix'
    
    int array2[6][6] = {{0}};
    createMatrix(array2, 6, arr2); //ERROR: No matching function for call to 'createMatrix'

    int tempResultArray[6][6] = {{0}};
    
    // I want to do some stuff here I find the 2d array form more convientient to work with, therefore the back and forth
    for (int i = 1; i <= 6; i++){
            tempResultArray[i][index] = array1[i][index] + array2[i][index];
    }
    
    for (int i = 1; i <= 6; i++){
        for (int j = 1; j <= 6; j++){
            resultArray[i+j] = tempResultArray[i][j];
            
    }
}

Edit2

I gave up, nothing worked. I can't find the reason the function was is not recognized. I don't even know if it's the way I'm calling the function/populating the parameters, or if the namespace is wrong. Documentation for this behavior is lacking. Ended up hardcoding the function to create a 2d array from 1d array and vice versa.

blkpingu
  • 1,556
  • 1
  • 18
  • 41

3 Answers3

1

Like this

void createMatrix(int (*arr)[6], int count, int* buff)

and you call it like this

createMatrix(array1, 6, arr1);

2D arrays and double pointers are not the same thing at all.

I've no idea about your final loop. Obviously if resultArray is a 1D array, then you cannot do resultArray[x][y] on it.

john
  • 85,011
  • 4
  • 57
  • 81
  • it doesnt like that - `void createMatrix(int (*arr)[6], int count, int* buff) // ERROR: Pointer type must have explicit address space qualifier`. Also, if I want to create a 2d array from a 1d array, shouldn't `arr` be int `(*arr)[6][6]`? I'm using it like in this example (option 2): https://stackoverflow.com/a/11656585/5476399 – blkpingu Jul 27 '22 at 21:18
  • I made an edit with your answer. Still no dice though, same errors as before. I added some Address Space Qualifiers to the method header of `createMatrix` though. Somehow Metal really overqualified these. I can't tell if they are the problem or not. Most people here don't seem familiar with them either so I can't really tell if they are right or not. Without them I get `Pointer type must have explicit address space qualifier` on the `createMatrix` method header. – blkpingu Jul 27 '22 at 21:47
  • @blkpingu You probably don't realise it but you are not working with standard C++. These `[[ ... ]]` constructs you are using are called attributes, but none of the attributes you have used are standard. There's no such thing in standard C++ as an address space qualifier (explicit or otherwise). Now unfortunately I have no idea what variation on C++ you are using, or whether you really need to be doing that. – john Jul 28 '22 at 05:14
1

Any variable that is a pointer or reference must be declared with one of the address space attributes.

This is the correct implementation of your function:

void createMatrix(device int (*arr)[6][6], int count, constant int* buff) {
    for(int i = 0; i < count; i++)
        for(int j = 0; j < count; j++)
            (*arr)[j][i] = buff[i + j];
}

Kernel:

device int (*array1)[6][6] = {{0}};
createMatrix(array1, 6, arr1);
Hamid Yusifli
  • 9,688
  • 2
  • 24
  • 48
1

In addition to @john's answer I'd suggest allocating the memory statically beforehand otherwise this will segvault.

Try this:

int array1[6][6] = {0}; // this is the static allocation (not sure if your need 'device' here)
createArray(&array1, 6, arr1);

Not this:

// this will only set the address to 0x0 and if dereferenced in the function segvaults
device int (*array1)[6][6] = {{0}}; 
gueldi
  • 11
  • 2