数据分散/数据收集
=========

#### Gather

#### \[h2\]功能说明

给定输入的张量和一个地址偏移张量，Gather指令根据偏移地址将输入张量按元素收集到结果张量中。

#### \[h2\]函数原型

tensor前n个数据计算：

template <typename T> 
\_\_aicore\_\_ inline void Gather(const LocalTensor<T>& dstLocal, const LocalTensor<T>& srcLocal, const LocalTensor<uint32\_t>& srcOffsetLocal, const uint32\_t srcBaseAddr, const uint32\_t count)

#### \[h2\]参数说明

**表1** 参数说明

| 参数名称 | 输入/输出 | 含义 |
| :-- | :-- | :-- |
| dstLocal | 输出 | 
目的操作数。

类型为[LocalTensor](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/cannkit-localtensor)，支持的TPosition为VECIN/VECCALC/VECOUT。

LocalTensor的起始地址需要32字节对齐。

Kirin9020系列处理器，支持的数据类型为：

前n个tensor：uint16\_t、int16\_t、uint32\_t、int32\_t、half、float32\_t

KirinX90系列处理器，支持的数据类型为：

前n个tensor：uint16\_t、int16\_t、uint32\_t、int32\_t、half、float32\_t

 |
| srcLocal | 输入 | 

源操作数。

类型为[LocalTensor](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/cannkit-localtensor)，支持的TPosition为VECIN/VECCALC/VECOUT。

LocalTensor的起始地址需要32字节对齐。

数据类型和dstLocal保持一致。

 |
| srcOffsetLocal | 输入 | 

每个元素在src中对应的地址偏移。

类型为[LocalTensor](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/cannkit-localtensor)，支持的TPosition为VECIN/VECCALC/VECOUT。

LocalTensor的起始地址需要32字节对齐。

该偏移量相对于src的起始基地址而言。单位为Bytes。地址偏移要大于等于0，取值应保证src元素类型位宽对齐，否则会导致非预期行为，同时需要保证偏移地址后不能超出UB大小数据的范围。

每个元素在src中对应的地址偏移，地址偏移要大于等于0。该偏移量是相对于src的基地址而言，每个数值的单位为Bytes，数据类型根据srcLocal数据类型决定，支持情况如下。

srcOffsetLocal支持数据类型：u32。

 |
| srcBaseAddr | 输入 | srcLocal的起始基地址，单位为Bytes。取值应保证src元素类型位宽对齐，否则会导致非预期行为。 |
| count | 输入 | 执行处理的数据个数，不得超过srcLocal和srcOffsetLocal的元素个数。 |

#### \[h2\]支持的型号

Kirin9020系列处理器

KirinX90系列处理器

#### \[h2\]约束说明

操作数地址偏移对齐要求请参见[通用约束](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/cannkit-general-constraints)。

#### \[h2\]调用示例

#include "kernel\_operator.h"
template <typename T>
class GatherTest {
public:
    \_\_aicore\_\_ inline GatherTest() {}
    \_\_aicore\_\_ inline void Init(\_\_gm\_\_ uint8\_t\* dstGm, \_\_gm\_\_ uint8\_t\* srcGm,
        \_\_gm\_\_ uint8\_t\* srcOffsetGm, const uint32\_t count)
    {
        m\_elementCount = count;
        m\_dstGlobal.SetGlobalBuffer((\_\_gm\_\_ T\*)dstGm);
        m\_srcGlobal.SetGlobalBuffer((\_\_gm\_\_ T\*)srcGm);
        m\_srcOffsetGlobal.SetGlobalBuffer((\_\_gm\_\_ uint32\_t\*)srcOffsetGm);
        m\_pipe.InitBuffer(m\_queIn, 2, m\_elementCount \* sizeof(uint32\_t));
        m\_pipe.InitBuffer(m\_queOut, 2, m\_elementCount \* sizeof(uint32\_t));
    }
    \_\_aicore\_\_ inline void Process()
    {
        CopyIn();
        Compute();
        CopyOut();
    }
private:
    \_\_aicore\_\_ inline void CopyIn()
    {
        AscendC::LocalTensor<T> srcLocal = m\_queIn.AllocTensor<T>();
        AscendC::DataCopy(srcLocal, m\_srcGlobal, m\_elementCount);
        m\_queIn.EnQue(srcLocal);
        AscendC::LocalTensor<uint32\_t> srcOffsetLocal = m\_queIn.AllocTensor<uint32\_t>();
        AscendC::DataCopy(srcOffsetLocal, m\_srcOffsetGlobal, m\_elementCount);
        m\_queIn.EnQue(srcOffsetLocal);
    }
    \_\_aicore\_\_ inline void Compute()
    {
        AscendC::LocalTensor<T> srcLocal = m\_queIn.DeQue<T>();
        AscendC::LocalTensor<uint32\_t> srcOffsetLocal = m\_queIn.DeQue<uint32\_t>();
        AscendC::LocalTensor<T> dstLocal = m\_queOut.AllocTensor<T>();
        srcLocal.SetSize(m\_elementCount);
        AscendC::Gather(dstLocal, srcLocal, srcOffsetLocal, (uint32\_t)0, m\_elementCount);
        m\_queIn.FreeTensor(srcLocal);
        m\_queIn.FreeTensor(srcOffsetLocal);
        m\_queOut.EnQue(dstLocal);
    }
    \_\_aicore\_\_ inline void CopyOut()
    {
        AscendC::LocalTensor<T> dstLocal = m\_queOut.DeQue<T>();
        AscendC::DataCopy(m\_dstGlobal, dstLocal, m\_elementCount);
        m\_queOut.FreeTensor(dstLocal);
    }
private:
    AscendC::TPipe m\_pipe;
    AscendC::TQue<AscendC::TPosition::VECIN, 1> m\_queCalc;
    AscendC::GlobalTensor<T> m\_valueGlobal;
    uint32\_t m\_concatRepeatTimes;
    uint32\_t m\_sortRepeatTimes;
    uint32\_t m\_extractRepeatTimes;
    uint32\_t m\_elementCount;
    AscendC::GlobalTensor<uint32\_t> m\_srcOffsetGlobal;
    AscendC::GlobalTensor<T> m\_srcGlobal;
    AscendC::GlobalTensor<T> m\_dstGlobal;
    AscendC::TQue<AscendC::TPosition::VECIN, 2> m\_queIn;
    AscendC::TQue<AscendC::TPosition::VECOUT, 2> m\_queOut;
}; // class GatherTest

extern "C" \_\_global\_\_ \_\_aicore\_\_ void kernel\_gather(GM\_ADDR dstGm, GM\_ADDR srcGm, GM\_ADDR srcOffsetGm)
{
    GatherTest<half> op;
    op.Init(dstGm, srcGm, srcOffsetGm, 128);
    op.Process();
}

结果示例：

输入数据srcOffsetLocal:
\[254 252 250 ... 4 2 0\]
输入数据srcLocal（128个half类型数据）:
\[0 1 2 ... 125 126 127\]
输出数据dstGlobal:
\[127 126 125 ... 2 1 0\]