GitOrigin-RevId: a23605c9e2
release-0.6
@@ -128,8 +128,11 @@ else() | |||
set(CMAKE_CXX_FLAGS_DEBUG "-O0 -g") | |||
if(ANDROID) | |||
set(CMAKE_CXX_FLAGS_RELEASE "-Ofast -DNDEBUG") | |||
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-Ofast -DNDEBUG -g") | |||
else() | |||
set(CMAKE_CXX_FLAGS_RELEASE "-O3 -DNDEBUG") | |||
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O3 -DNDEBUG -g") | |||
endif() | |||
endif() | |||
@@ -29,6 +29,13 @@ | |||
#define megdnn_likely(v) __builtin_expect(bool(v), 1) | |||
#define megdnn_unlikely(v) __builtin_expect(bool(v), 0) | |||
#if !defined(__clang__) && MEGDNN_ARMV7 && !defined(NDEBUG) | |||
//! Thumb2 limit code length | |||
#define MEGDNN_ALWAYS_INLINE | |||
#else | |||
#define MEGDNN_ALWAYS_INLINE inline __attribute__((__always_inline__)) | |||
#endif | |||
#define MEGDNN_DEPRECATED __attribute__((deprecated)) | |||
#define MEGDNN_PACKED __attribute__((packed)) | |||
#define MEGDNN_CONSTEXPR constexpr | |||
@@ -10,6 +10,7 @@ | |||
* implied. | |||
*/ | |||
#pragma once | |||
#include "megdnn/arch.h" | |||
#include "src/arm_common/conv_bias/intrinsic_helper.h" | |||
#include "src/arm_common/conv_bias/opr_impl.h" | |||
#include "src/arm_common/elemwise_op.h" | |||
@@ -17,7 +18,6 @@ | |||
#include "src/common/unroll_macro.h" | |||
#include "src/common/utils.h" | |||
#include "src/fallback/conv_bias/common.h" | |||
namespace megdnn { | |||
namespace arm_common { | |||
namespace { | |||
@@ -32,13 +32,13 @@ namespace { | |||
template <int src_idx, int weight_idx, int c_dim, typename Func, int stride, | |||
typename T, typename T2, typename T3> | |||
struct ShiftCalHelper { | |||
static void impl(T& c, T2& src, T3& weight); | |||
static MEGDNN_ALWAYS_INLINE void impl(T& c, T2& src, T3& weight); | |||
}; | |||
template <int src_idx, int weight_idx, typename Func, int stride, typename T, | |||
typename T2, typename T3> | |||
struct ShiftCalHelper<src_idx, weight_idx, 2, Func, stride, T, T2, T3> { | |||
static void impl(T& c, T2& src, T3& weight) { | |||
static MEGDNN_ALWAYS_INLINE void impl(T& c, T2& src, T3& weight) { | |||
#define cb(step) \ | |||
c[0][step] = Func::template impl<(step * stride + src_idx) % 4>( \ | |||
c[0][step], weight[0][weight_idx], \ | |||
@@ -54,7 +54,7 @@ struct ShiftCalHelper<src_idx, weight_idx, 2, Func, stride, T, T2, T3> { | |||
template <int src_idx, int weight_idx, typename Func, int stride, typename T, | |||
typename T2, typename T3> | |||
struct ShiftCalHelper<src_idx, weight_idx, 1, Func, stride, T, T2, T3> { | |||
static void impl(T& c, T2& src, T3& weight) { | |||
static MEGDNN_ALWAYS_INLINE void impl(T& c, T2& src, T3& weight) { | |||
#define cb(step) \ | |||
c[0][step] = Func::template impl<(step * stride + src_idx) % 4>( \ | |||
c[0][step], weight[0][weight_idx], \ | |||
@@ -67,7 +67,7 @@ struct ShiftCalHelper<src_idx, weight_idx, 1, Func, stride, T, T2, T3> { | |||
template <int src_idx, int weight_idx, int c_dim, typename FUNC, int stride, | |||
typename T, typename T2, typename T3> | |||
inline void cal_helper(T& c, T2& src, T3& weight) { | |||
MEGDNN_ALWAYS_INLINE void cal_helper(T& c, T2& src, T3& weight) { | |||
ShiftCalHelper<src_idx, weight_idx, c_dim, FUNC, stride, T, T2, T3>::impl( | |||
c, src, weight); | |||
}; | |||
@@ -11,6 +11,7 @@ | |||
* implied. | |||
*/ | |||
#include "megdnn/arch.h" | |||
#include "src/arm_common/conv_bias/fp32/f32_direct_stride1_nchw44_kern.h" | |||
#include "src/arm_common/conv_bias/intrinsic_helper.h" | |||
#include "src/arm_common/elemwise_op.h" | |||
@@ -26,13 +27,13 @@ namespace { | |||
template <int src_idx, int weight_idx, int c_dim, typename Func, int ow_block, | |||
typename T, typename T2, typename T3, typename T4> | |||
struct ShiftCalHelper { | |||
static void impl(T& c, T2& src, T3& weight); | |||
static MEGDNN_ALWAYS_INLINE void impl(T& c, T2& src, T3& weight); | |||
}; | |||
template <int src_idx, int weight_idx, typename Func, typename T, typename T2, | |||
typename T3, typename T4> | |||
struct ShiftCalHelper<src_idx, weight_idx, 2, Func, 8, T, T2, T3, T4> { | |||
static void impl(T& c, T2& src, T3& weight) { | |||
static MEGDNN_ALWAYS_INLINE void impl(T& c, T2& src, T3& weight) { | |||
#define cb(step, lane) \ | |||
c[0][step] = Func::template impl<lane>(c[0][step], weight[0][lane], \ | |||
src[(step + src_idx) % 8]); \ | |||
@@ -49,7 +50,7 @@ struct ShiftCalHelper<src_idx, weight_idx, 2, Func, 8, T, T2, T3, T4> { | |||
template <int src_idx, int weight_idx, typename Func, typename T, typename T2, | |||
typename T3, typename T4> | |||
struct ShiftCalHelper<src_idx, weight_idx, 2, Func, 4, T, T2, T3, T4> { | |||
static void impl(T& c, T2& src, T3& weight) { | |||
static MEGDNN_ALWAYS_INLINE void impl(T& c, T2& src, T3& weight) { | |||
#define cb(step, lane) \ | |||
c[0][step] = Func::template impl<lane>(c[0][step], weight[0][lane], \ | |||
src[(step + src_idx) % 4]); \ | |||
@@ -66,7 +67,7 @@ struct ShiftCalHelper<src_idx, weight_idx, 2, Func, 4, T, T2, T3, T4> { | |||
template <int src_idx, int weight_idx, typename Func, typename T, typename T2, | |||
typename T3, typename T4> | |||
struct ShiftCalHelper<src_idx, weight_idx, 1, Func, 8, T, T2, T3, T4> { | |||
static void impl(T& c, T2& src, T3& weight) { | |||
static MEGDNN_ALWAYS_INLINE void impl(T& c, T2& src, T3& weight) { | |||
#define cb(step, lane) \ | |||
c[0][step] = Func::template impl<lane>(c[0][step], weight[0][lane], \ | |||
src[(step + src_idx) % 8]); | |||
@@ -81,7 +82,7 @@ struct ShiftCalHelper<src_idx, weight_idx, 1, Func, 8, T, T2, T3, T4> { | |||
template <int src_idx, int weight_idx, typename Func, typename T, typename T2, | |||
typename T3, typename T4> | |||
struct ShiftCalHelper<src_idx, weight_idx, 1, Func, 4, T, T2, T3, T4> { | |||
static void impl(T& c, T2& src, T3& weight) { | |||
static MEGDNN_ALWAYS_INLINE void impl(T& c, T2& src, T3& weight) { | |||
#define cb(step, lane) \ | |||
c[0][step] = Func::template impl<lane>(c[0][step], weight[0][lane], \ | |||
src[(step + src_idx) % 4]); | |||
@@ -96,7 +97,7 @@ struct ShiftCalHelper<src_idx, weight_idx, 1, Func, 4, T, T2, T3, T4> { | |||
template <int src_idx, int weight_idx, int c_dim, typename FUNC, int ow_block, | |||
typename T, typename T2, typename T3> | |||
inline void cal_helper(T& c, T2& src, T3& weight) { | |||
MEGDNN_ALWAYS_INLINE void cal_helper(T& c, T2& src, T3& weight) { | |||
ShiftCalHelper<src_idx, weight_idx, c_dim, FUNC, ow_block, T, T2, T3, | |||
int>::impl(c, src, weight); | |||
}; | |||
@@ -11,6 +11,7 @@ | |||
* implied. | |||
*/ | |||
#include "megdnn/arch.h" | |||
#include "src/arm_common/conv_bias/fp32/f32_direct_stride2_nchw44_kern.h" | |||
#include "src/arm_common/conv_bias/intrinsic_helper.h" | |||
#include "src/arm_common/elemwise_op.h" | |||
@@ -26,13 +27,13 @@ namespace { | |||
template <int src_idx, int weight_idx, int c_dim, typename Func, int ow_block, | |||
typename T, typename T2, typename T3, typename T4> | |||
struct ShiftCalHelper { | |||
static void impl(T& c, T2& src, T3& weight); | |||
static MEGDNN_ALWAYS_INLINE void impl(T& c, T2& src, T3& weight); | |||
}; | |||
template <int src_idx, int weight_idx, typename Func, typename T, typename T2, | |||
typename T3, typename T4> | |||
struct ShiftCalHelper<src_idx, weight_idx, 2, Func, 8, T, T2, T3, T4> { | |||
static void impl(T& c, T2& src, T3& weight) { | |||
static MEGDNN_ALWAYS_INLINE void impl(T& c, T2& src, T3& weight) { | |||
#define cb(step, lane) \ | |||
c[0][step] = Func::template impl<lane>(c[0][step], weight[0][lane], \ | |||
src[(step + src_idx) % 8]); \ | |||
@@ -49,7 +50,7 @@ struct ShiftCalHelper<src_idx, weight_idx, 2, Func, 8, T, T2, T3, T4> { | |||
template <int src_idx, int weight_idx, typename Func, typename T, typename T2, | |||
typename T3, typename T4> | |||
struct ShiftCalHelper<src_idx, weight_idx, 2, Func, 4, T, T2, T3, T4> { | |||
static void impl(T& c, T2& src, T3& weight) { | |||
static MEGDNN_ALWAYS_INLINE void impl(T& c, T2& src, T3& weight) { | |||
#define cb(step, lane) \ | |||
c[0][step] = Func::template impl<lane>(c[0][step], weight[0][lane], \ | |||
src[(step + src_idx) % 4]); \ | |||
@@ -66,7 +67,7 @@ struct ShiftCalHelper<src_idx, weight_idx, 2, Func, 4, T, T2, T3, T4> { | |||
template <int src_idx, int weight_idx, typename Func, typename T, typename T2, | |||
typename T3, typename T4> | |||
struct ShiftCalHelper<src_idx, weight_idx, 1, Func, 8, T, T2, T3, T4> { | |||
static void impl(T& c, T2& src, T3& weight) { | |||
static MEGDNN_ALWAYS_INLINE void impl(T& c, T2& src, T3& weight) { | |||
#define cb(step, lane) \ | |||
c[0][step] = Func::template impl<lane>(c[0][step], weight[0][lane], \ | |||
src[(step + src_idx) % 8]); | |||
@@ -81,7 +82,7 @@ struct ShiftCalHelper<src_idx, weight_idx, 1, Func, 8, T, T2, T3, T4> { | |||
template <int src_idx, int weight_idx, typename Func, typename T, typename T2, | |||
typename T3, typename T4> | |||
struct ShiftCalHelper<src_idx, weight_idx, 1, Func, 4, T, T2, T3, T4> { | |||
static void impl(T& c, T2& src, T3& weight) { | |||
static MEGDNN_ALWAYS_INLINE void impl(T& c, T2& src, T3& weight) { | |||
#define cb(step, lane) \ | |||
c[0][step] = Func::template impl<lane>(c[0][step], weight[0][lane], \ | |||
src[(step + src_idx) % 4]); | |||
@@ -96,7 +97,7 @@ struct ShiftCalHelper<src_idx, weight_idx, 1, Func, 4, T, T2, T3, T4> { | |||
template <int src_idx, int weight_idx, int c_dim, typename FUNC, int ow_block, | |||
typename T, typename T2, typename T3> | |||
inline void cal_helper(T& c, T2& src, T3& weight) { | |||
MEGDNN_ALWAYS_INLINE void cal_helper(T& c, T2& src, T3& weight) { | |||
ShiftCalHelper<src_idx, weight_idx, c_dim, FUNC, ow_block, T, T2, T3, | |||
int>::impl(c, src, weight); | |||
}; | |||
@@ -462,9 +463,10 @@ inline void odd_even_split_iw8_even(float* sptr_base, const float* sptr, | |||
vst1q_f32(sptr_base + odd_offset + 2 * ic_step, temp[5]); | |||
vst1q_f32(sptr_base + odd_offset + 3 * ic_step, temp[7]); | |||
} | |||
void odd_even_split_iw8_odd(float* sptr_base, const float* sptr, | |||
const int odd_start, const int src_idx, | |||
const int iw_idx) { | |||
inline void odd_even_split_iw8_odd(float* sptr_base, const float* sptr, | |||
const int odd_start, const int src_idx, | |||
const int iw_idx) { | |||
constexpr int ic_step = 4; | |||
const int src_offset = src_idx * ic_step; | |||
const int even_offset = (iw_idx + 1) / 2 * ic_step; | |||
@@ -5,11 +5,13 @@ | |||
* | |||
* Unless required by applicable law or agreed to in writing, | |||
* software distributed under the License is distributed on an | |||
* "AS IS" BASIS, WITHOUT ARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
* "AS IS" BASIS, WITHOUT ARRANTIES OR CONDITIONS OF ANY KIND, either express or | |||
* implied. | |||
*/ | |||
#pragma once | |||
#ifdef __ARM_FEATURE_DOTPROD | |||
#include "megdnn/arch.h" | |||
#include "src/arm_common/conv_bias/intrinsic_helper.h" | |||
#include "src/arm_common/elemwise_op.h" | |||
#include "src/arm_common/intrinsic_helper.h" | |||
@@ -27,8 +29,8 @@ constexpr int filter_next_col = | |||
IC_PACK_SIZE * OC_PACK_SIZE; //! [OC/4, IC/4, FH, FW, 4OC, 4IC] | |||
template <int row, BiasMode bias_mode> | |||
inline void init_ocx_ow8(int32x4_t c[][8], const int32_t* bias_ptr, | |||
int oc_step) { | |||
MEGDNN_ALWAYS_INLINE void init_ocx_ow8(int32x4_t c[][8], | |||
const int32_t* bias_ptr, int oc_step) { | |||
static_assert(row == 1 || row == 2 || row == 3, "Invalid OC number."); | |||
if (bias_mode == BiasMode::BROADCAST_CHANNEL_BIAS) { | |||
#define BIAS_INIT(step, i) c[i][step] = vld1q_s32(bias_ptr + i * oc_step); | |||
@@ -90,12 +92,13 @@ inline void init_ocx_ow8(int32x4_t c[][8], const int32_t* bias_ptr, | |||
template <int row, int ow_remain, typename Op, typename T> | |||
struct StoreOCxOWx { | |||
static void impl(int32x4_t res[][8], const Op& op, T* dst_ptr, | |||
const int ld_dst_oc); | |||
static MEGDNN_ALWAYS_INLINE void impl(int32x4_t res[][8], const Op& op, | |||
T* dst_ptr, const int ld_dst_oc); | |||
}; | |||
template <int ow_remain, typename Op, typename T> | |||
struct StoreOCxOWx<1, ow_remain, Op, T> { | |||
static void impl(int32x4_t res[][8], const Op& op, T* dst_ptr, | |||
const int ld_dst_oc) { | |||
MEGDNN_MARK_USED_VAR(ld_dst_oc); | |||
@@ -128,8 +131,8 @@ struct StoreOCxOWx<1, ow_remain, Op, T> { | |||
template <int ow_remain, typename Op, typename T> | |||
struct StoreOCxOWx<2, ow_remain, Op, T> { | |||
static void impl(int32x4_t res[][8], const Op& op, T* dst_ptr, | |||
const int ld_dst_oc) { | |||
static MEGDNN_ALWAYS_INLINE void impl(int32x4_t res[][8], const Op& op, | |||
T* dst_ptr, const int ld_dst_oc) { | |||
switch (ow_remain) { | |||
case 8: | |||
UNROLL_CALL_RAW(4, cb22); | |||
@@ -159,8 +162,8 @@ struct StoreOCxOWx<2, ow_remain, Op, T> { | |||
template <int ow_remain, typename Op, typename T> | |||
struct StoreOCxOWx<3, ow_remain, Op, T> { | |||
static void impl(int32x4_t res[][8], const Op& op, T* dst_ptr, | |||
const int ld_dst_oc) { | |||
static MEGDNN_ALWAYS_INLINE void impl(int32x4_t res[][8], const Op& op, | |||
T* dst_ptr, const int ld_dst_oc) { | |||
switch (ow_remain) { | |||
case 8: | |||
UNROLL_CALL_RAW(4, cb32); | |||
@@ -196,15 +199,16 @@ struct StoreOCxOWx<3, ow_remain, Op, T> { | |||
#undef cb32 | |||
template <int row, int ow_remain, typename Op, typename T> | |||
inline void store_ocx_owx_remain_static(int32x4_t res[][8], const Op& op, | |||
T* dst_ptr, const int ld_dst_oc) { | |||
MEGDNN_ALWAYS_INLINE void store_ocx_owx_remain_static(int32x4_t res[][8], | |||
const Op& op, T* dst_ptr, | |||
const int ld_dst_oc) { | |||
StoreOCxOWx<row, ow_remain, Op, T>::impl(res, op, dst_ptr, ld_dst_oc); | |||
} | |||
template <int res_row, int src_row, int src_start_idx, int weight_idx, | |||
typename FUNC, typename T, typename T2, typename T3> | |||
struct ShiftCalHelper { | |||
static void impl(T& res, T2& src, T3& weight) { | |||
static MEGDNN_ALWAYS_INLINE void impl(T& res, T2& src, T3& weight) { | |||
#define cb(step) \ | |||
res[res_row][step] = FUNC::template impl<((src_start_idx + step) % 4)>( \ | |||
res[res_row][step], weight[weight_idx], \ | |||
@@ -216,7 +220,7 @@ struct ShiftCalHelper { | |||
template <int res_row, int src_row, int src_start_idx, int weight_idx, | |||
typename FUNC, typename T, typename T2, typename T3> | |||
inline void cal_helper(T& res, T2& src, T3& weight) { | |||
MEGDNN_ALWAYS_INLINE void cal_helper(T& res, T2& src, T3& weight) { | |||
ShiftCalHelper<res_row, src_row, src_start_idx, weight_idx, FUNC, T, T2, | |||
T3>::impl(res, src, weight); | |||
}; | |||
@@ -428,4 +432,4 @@ struct KernNeonSdotNCHW44<dst_type, 2, bias_mode, Op, ow_remain, filter_size, | |||
#endif | |||
//vim: syntax=cpp.doxygen | |||
// vim: syntax=cpp.doxygen |
@@ -10,6 +10,7 @@ | |||
* implied. | |||
*/ | |||
#pragma once | |||
#include "megdnn/arch.h" | |||
#include "src/arm_common/conv_bias/intrinsic_helper.h" | |||
#include "src/arm_common/conv_bias/opr_impl.h" | |||
#include "src/arm_common/elemwise_op.h" | |||
@@ -37,13 +38,13 @@ namespace { | |||
template <int src_idx, int weight_idx, int c_dim, typename Func, int stride, | |||
typename T, typename T2, typename T3, typename T4> | |||
struct ShiftCalHelper { | |||
static void impl(T& c, T2& src, T3& weight, T4& temp); | |||
static void impl(T& c, T2& src, T3& weight); | |||
static MEGDNN_ALWAYS_INLINE void impl(T& c, T2& src, T3& weight, T4& temp); | |||
static MEGDNN_ALWAYS_INLINE void impl(T& c, T2& src, T3& weight); | |||
}; | |||
template <int src_idx, int weight_idx, typename Func, typename T, typename T2, | |||
typename T3, typename T4> | |||
struct ShiftCalHelper<src_idx, weight_idx, 2, Func, 2, T, T2, T3, T4> { | |||
static void impl(T& c, T2& src, T3& weight, T4& temp) { | |||
static MEGDNN_ALWAYS_INLINE void impl(T& c, T2& src, T3& weight, T4& temp) { | |||
c[0][0] = Func::impl(src[0 + src_idx], weight[0][weight_idx], c[0][0], | |||
temp[0]); | |||
c[1][0] = Func::impl(src[0 + src_idx], weight[1][weight_idx], c[1][0], | |||
@@ -61,7 +62,7 @@ struct ShiftCalHelper<src_idx, weight_idx, 2, Func, 2, T, T2, T3, T4> { | |||
c[1][3] = Func::impl(src[3 + src_idx], weight[1][weight_idx], c[1][3], | |||
temp[3]); | |||
} | |||
static void impl(T& c, T2& src, T3& weight) { | |||
static MEGDNN_ALWAYS_INLINE void impl(T& c, T2& src, T3& weight) { | |||
c[0][0] = Func::impl(src[0 + src_idx], weight[0][weight_idx], c[0][0]); | |||
c[1][0] = Func::impl(src[0 + src_idx], weight[1][weight_idx], c[1][0]); | |||
c[0][1] = Func::impl(src[1 + src_idx], weight[0][weight_idx], c[0][1]); | |||
@@ -75,7 +76,7 @@ struct ShiftCalHelper<src_idx, weight_idx, 2, Func, 2, T, T2, T3, T4> { | |||
template <int src_idx, int weight_idx, typename Func, typename T, typename T2, | |||
typename T3, typename T4> | |||
struct ShiftCalHelper<src_idx, weight_idx, 1, Func, 2, T, T2, T3, T4> { | |||
static void impl(T& c, T2& src, T3& weight, T4& temp) { | |||
static MEGDNN_ALWAYS_INLINE void impl(T& c, T2& src, T3& weight, T4& temp) { | |||
c[0][0] = Func::impl(src[0 + src_idx], weight[0][weight_idx], c[0][0], | |||
temp[0]); | |||
c[0][1] = Func::impl(src[1 + src_idx], weight[0][weight_idx], c[0][1], | |||
@@ -85,7 +86,7 @@ struct ShiftCalHelper<src_idx, weight_idx, 1, Func, 2, T, T2, T3, T4> { | |||
c[0][3] = Func::impl(src[3 + src_idx], weight[0][weight_idx], c[0][3], | |||
temp[2]); | |||
} | |||
static void impl(T& c, T2& src, T3& weight) { | |||
static MEGDNN_ALWAYS_INLINE void impl(T& c, T2& src, T3& weight) { | |||
c[0][0] = Func::impl(src[0 + src_idx], weight[0][weight_idx], c[0][0]); | |||
c[0][1] = Func::impl(src[1 + src_idx], weight[0][weight_idx], c[0][1]); | |||
c[0][2] = Func::impl(src[2 + src_idx], weight[0][weight_idx], c[0][2]); | |||
@@ -96,7 +97,7 @@ struct ShiftCalHelper<src_idx, weight_idx, 1, Func, 2, T, T2, T3, T4> { | |||
template <int src_idx, int weight_idx, typename Func, typename T, typename T2, | |||
typename T3, typename T4> | |||
struct ShiftCalHelper<src_idx, weight_idx, 2, Func, 1, T, T2, T3, T4> { | |||
static void impl(T& c, T2& src, T3& weight, T4& temp) { | |||
static MEGDNN_ALWAYS_INLINE void impl(T& c, T2& src, T3& weight, T4& temp) { | |||
c[0][0] = Func::impl(src[(0 + src_idx) % 8], weight[0][weight_idx], | |||
c[0][0], temp[0]); | |||
c[1][0] = Func::impl(src[(0 + src_idx) % 8], weight[1][weight_idx], | |||
@@ -131,12 +132,12 @@ struct ShiftCalHelper<src_idx, weight_idx, 2, Func, 1, T, T2, T3, T4> { | |||
c[1][7] = Func::impl(src[(7 + src_idx) % 8], weight[1][weight_idx], | |||
c[1][7], temp[3]); | |||
} | |||
static void impl(T&, T2&, T3&); | |||
static MEGDNN_ALWAYS_INLINE void impl(T&, T2&, T3&); | |||
}; | |||
template <int src_idx, int weight_idx, typename Func, typename T, typename T2, | |||
typename T3, typename T4> | |||
struct ShiftCalHelper<src_idx, weight_idx, 1, Func, 1, T, T2, T3, T4> { | |||
static void impl(T& c, T2& src, T3& weight, T4& temp) { | |||
static MEGDNN_ALWAYS_INLINE void impl(T& c, T2& src, T3& weight, T4& temp) { | |||
c[0][0] = Func::impl(src[(0 + src_idx) % 8], weight[0][weight_idx], | |||
c[0][0], temp[0]); | |||
c[0][1] = Func::impl(src[(1 + src_idx) % 8], weight[0][weight_idx], | |||
@@ -154,18 +155,18 @@ struct ShiftCalHelper<src_idx, weight_idx, 1, Func, 1, T, T2, T3, T4> { | |||
c[0][7] = Func::impl(src[(7 + src_idx) % 8], weight[0][weight_idx], | |||
c[0][7], temp[3]); | |||
} | |||
static void impl(T&, T2&, T3&); | |||
static MEGDNN_ALWAYS_INLINE void impl(T&, T2&, T3&); | |||
}; | |||
template <int src_idx, int weight_idx, int c_dim, typename FUNC, int stride, | |||
typename T, typename T2, typename T3, typename T4> | |||
inline void cal_helper(T& c, T2& src, T3& weight, T4& temp) { | |||
MEGDNN_ALWAYS_INLINE void cal_helper(T& c, T2& src, T3& weight, T4& temp) { | |||
ShiftCalHelper<src_idx, weight_idx, c_dim, FUNC, stride, T, T2, T3, | |||
T4>::impl(c, src, weight, temp); | |||
} | |||
template <int src_idx, int weight_idx, int c_dim, typename FUNC, int stride, | |||
typename T, typename T2, typename T3> | |||
inline void cal_helper(T& c, T2& src, T3& weight) { | |||
MEGDNN_ALWAYS_INLINE void cal_helper(T& c, T2& src, T3& weight) { | |||
ShiftCalHelper<src_idx, weight_idx, c_dim, FUNC, stride, T, T2, T3, | |||
int>::impl(c, src, weight); | |||
}; | |||
@@ -703,8 +704,9 @@ struct KerNeonXXs2NchwNchw44<bias_mode, Op, remain_w, 7, oc_block, 1> { | |||
enum PACK_MODE { NO_PAD = 0, FIRST_PAD = 1, LAST_PAD = 2 }; | |||
template <PACK_MODE mode> | |||
inline void pack_src_one_line(const int8_t* inptr, int8_t* outptr, int left_pad, | |||
int right_pad, const int iw) { | |||
MEGDNN_ALWAYS_INLINE void pack_src_one_line(const int8_t* inptr, int8_t* outptr, | |||
int left_pad, int right_pad, | |||
const int iw) { | |||
const int8_t* src_row_0 = inptr; | |||
const int8_t* src_row_1 = inptr + iw; | |||
constexpr int combine_row = 2; | |||
@@ -1235,6 +1237,7 @@ struct ConvDiectStrideInt8NchwNchw44<bias_mode, Op, filter_size, 1> { | |||
} | |||
} | |||
} | |||
if (oc_remain > 0) { | |||
size_t oc_idx = oc_end; | |||
const size_t weight_offset = oc_idx * ic * fh * fw; | |||
@@ -1284,4 +1287,5 @@ static void conv_direct_int8_nchw_nchw44(const int8_t* src, | |||
} // namespace | |||
} // namespace arm_common | |||
} // namespace megdnn | |||
// vim: syntax=cpp.doxygen | |||
// vim: syntax=cpp.doxygen |
@@ -15,18 +15,20 @@ | |||
#include "src/arm_common/simd_macro/marm_neon.h" | |||
#include "src/common/unroll_macro.h" | |||
#include "src/fallback/conv_bias/common.h" | |||
#define __ai inline __attribute__((__always_inline__)) | |||
namespace megdnn { | |||
namespace { | |||
////////////////////Store_OC4_OW8_Remain///////////////////////// | |||
template <int ow_remain, typename Op> | |||
struct Store_OC4_OW8_Remain { | |||
static void impl(int32x4_t c[8], const Op& op, int8_t* dst_ptr); | |||
static __ai void impl(int32x4_t c[8], const Op& op, int8_t* dst_ptr); | |||
}; | |||
template <typename Op> | |||
struct Store_OC4_OW8_Remain<0, Op> { | |||
static void impl(int32x4_t c[8], const Op& op, int8_t* dst_ptr) { | |||
static __ai void impl(int32x4_t c[8], const Op& op, int8_t* dst_ptr) { | |||
op({{c[0], c[1]}}, reinterpret_cast<dt_qint8*>(dst_ptr)); | |||
op({{c[2], c[3]}}, reinterpret_cast<dt_qint8*>(dst_ptr + 8)); | |||
op({{c[4], c[5]}}, reinterpret_cast<dt_qint8*>(dst_ptr + 16)); | |||
@@ -36,7 +38,7 @@ struct Store_OC4_OW8_Remain<0, Op> { | |||
template <typename Op> | |||
struct Store_OC4_OW8_Remain<7, Op> { | |||
static void impl(int32x4_t c[8], const Op& op, int8_t* dst_ptr) { | |||
static __ai void impl(int32x4_t c[8], const Op& op, int8_t* dst_ptr) { | |||
op({{c[0], c[1]}}, reinterpret_cast<dt_qint8*>(dst_ptr)); | |||
op({{c[2], c[3]}}, reinterpret_cast<dt_qint8*>(dst_ptr + 8)); | |||
op({{c[4], c[5]}}, reinterpret_cast<dt_qint8*>(dst_ptr + 16)); | |||
@@ -45,7 +47,7 @@ struct Store_OC4_OW8_Remain<7, Op> { | |||
}; | |||
template <typename Op> | |||
struct Store_OC4_OW8_Remain<6, Op> { | |||
static void impl(int32x4_t c[8], const Op& op, int8_t* dst_ptr) { | |||
static __ai void impl(int32x4_t c[8], const Op& op, int8_t* dst_ptr) { | |||
op({{c[0], c[1]}}, reinterpret_cast<dt_qint8*>(dst_ptr)); | |||
op({{c[2], c[3]}}, reinterpret_cast<dt_qint8*>(dst_ptr + 8)); | |||
op({{c[4], c[5]}}, reinterpret_cast<dt_qint8*>(dst_ptr + 16)); | |||
@@ -53,7 +55,7 @@ struct Store_OC4_OW8_Remain<6, Op> { | |||
}; | |||
template <typename Op> | |||
struct Store_OC4_OW8_Remain<5, Op> { | |||
static void impl(int32x4_t c[8], const Op& op, int8_t* dst_ptr) { | |||
static __ai void impl(int32x4_t c[8], const Op& op, int8_t* dst_ptr) { | |||
op({{c[0], c[1]}}, reinterpret_cast<dt_qint8*>(dst_ptr)); | |||
op({{c[2], c[3]}}, reinterpret_cast<dt_qint8*>(dst_ptr + 8)); | |||
op(c[4], reinterpret_cast<dt_qint8*>(dst_ptr + 16)); | |||
@@ -61,46 +63,46 @@ struct Store_OC4_OW8_Remain<5, Op> { | |||
}; | |||
template <typename Op> | |||
struct Store_OC4_OW8_Remain<4, Op> { | |||
static void impl(int32x4_t c[8], const Op& op, int8_t* dst_ptr) { | |||
static __ai void impl(int32x4_t c[8], const Op& op, int8_t* dst_ptr) { | |||
op({{c[0], c[1]}}, reinterpret_cast<dt_qint8*>(dst_ptr)); | |||
op({{c[2], c[3]}}, reinterpret_cast<dt_qint8*>(dst_ptr + 8)); | |||
} | |||
}; | |||
template <typename Op> | |||
struct Store_OC4_OW8_Remain<3, Op> { | |||
static void impl(int32x4_t c[8], const Op& op, int8_t* dst_ptr) { | |||
static __ai void impl(int32x4_t c[8], const Op& op, int8_t* dst_ptr) { | |||
op({{c[0], c[1]}}, reinterpret_cast<dt_qint8*>(dst_ptr)); | |||
op(c[2], reinterpret_cast<dt_qint8*>(dst_ptr + 8)); | |||
} | |||
}; | |||
template <typename Op> | |||
struct Store_OC4_OW8_Remain<2, Op> { | |||
static void impl(int32x4_t c[8], const Op& op, int8_t* dst_ptr) { | |||
static __ai void impl(int32x4_t c[8], const Op& op, int8_t* dst_ptr) { | |||
op({{c[0], c[1]}}, reinterpret_cast<dt_qint8*>(dst_ptr)); | |||
} | |||
}; | |||
template <typename Op> | |||
struct Store_OC4_OW8_Remain<1, Op> { | |||
static void impl(int32x4_t c[8], const Op& op, int8_t* dst_ptr) { | |||
static __ai void impl(int32x4_t c[8], const Op& op, int8_t* dst_ptr) { | |||
op(c[0], reinterpret_cast<dt_qint8*>(dst_ptr)); | |||
} | |||
}; | |||
template <int ow_remain, typename Op> | |||
inline void store_oc4_ow8_remain_static(int32x4_t c[8], const Op& op, | |||
int8_t* dst_ptr) { | |||
__ai void store_oc4_ow8_remain_static(int32x4_t c[8], const Op& op, | |||
int8_t* dst_ptr) { | |||
Store_OC4_OW8_Remain<ow_remain, Op>::impl(c, op, dst_ptr); | |||
} | |||
template <int c_dim, int ow_remain, typename Op, typename T> | |||
struct StoreOcxOw4Remain { | |||
static void impl(T& c, const Op& op, int8_t* dst_ptr, int ld_dst_oc); | |||
static __ai void impl(T& c, const Op& op, int8_t* dst_ptr, int ld_dst_oc); | |||
}; | |||
template <typename Op, typename T> | |||
struct StoreOcxOw4Remain<2, 0, Op, T> { | |||
static void impl(int32x4_t c[2][4], const Op& op, int8_t* dst_ptr, | |||
int ld_dst_oc) { | |||
static __ai void impl(int32x4_t c[2][4], const Op& op, int8_t* dst_ptr, | |||
int ld_dst_oc) { | |||
op({{c[0][0], c[0][1]}}, reinterpret_cast<dt_qint8*>(dst_ptr)); | |||
op({{c[0][2], c[0][3]}}, reinterpret_cast<dt_qint8*>(dst_ptr + 8)); | |||
@@ -113,7 +115,7 @@ struct StoreOcxOw4Remain<2, 0, Op, T> { | |||
template <typename Op, typename T> | |||
struct StoreOcxOw4Remain<2, 3, Op, T> { | |||
static void impl(T& c, const Op& op, int8_t* dst_ptr, int ld_dst_oc) { | |||
static __ai void impl(T& c, const Op& op, int8_t* dst_ptr, int ld_dst_oc) { | |||
op({{c[0][0], c[0][1]}}, reinterpret_cast<dt_qint8*>(dst_ptr)); | |||
op(c[0][2], reinterpret_cast<dt_qint8*>(dst_ptr + 8)); | |||
@@ -124,7 +126,7 @@ struct StoreOcxOw4Remain<2, 3, Op, T> { | |||
}; | |||
template <typename Op, typename T> | |||
struct StoreOcxOw4Remain<2, 2, Op, T> { | |||
static void impl(T& c, const Op& op, int8_t* dst_ptr, int ld_dst_oc) { | |||
static __ai void impl(T& c, const Op& op, int8_t* dst_ptr, int ld_dst_oc) { | |||
op({{c[0][0], c[0][1]}}, reinterpret_cast<dt_qint8*>(dst_ptr)); | |||
op({{c[1][0], c[1][1]}}, | |||
reinterpret_cast<dt_qint8*>(dst_ptr + ld_dst_oc)); | |||
@@ -132,7 +134,7 @@ struct StoreOcxOw4Remain<2, 2, Op, T> { | |||
}; | |||
template <typename Op, typename T> | |||
struct StoreOcxOw4Remain<2, 1, Op, T> { | |||
static void impl(T& c, const Op& op, int8_t* dst_ptr, int ld_dst_oc) { | |||
static __ai void impl(T& c, const Op& op, int8_t* dst_ptr, int ld_dst_oc) { | |||
op(c[0][0], reinterpret_cast<dt_qint8*>(dst_ptr)); | |||
op(c[1][0], reinterpret_cast<dt_qint8*>(dst_ptr + ld_dst_oc)); | |||
} | |||
@@ -140,8 +142,8 @@ struct StoreOcxOw4Remain<2, 1, Op, T> { | |||
template <typename Op, typename T> | |||
struct StoreOcxOw4Remain<1, 0, Op, T> { | |||
static void impl(int32x4_t c[2][4], const Op& op, int8_t* dst_ptr, | |||
int ld_dst_oc) { | |||
static __ai void impl(int32x4_t c[2][4], const Op& op, int8_t* dst_ptr, | |||
int ld_dst_oc) { | |||
MEGDNN_MARK_USED_VAR(ld_dst_oc); | |||
op({{c[0][0], c[0][1]}}, reinterpret_cast<dt_qint8*>(dst_ptr)); | |||
op({{c[0][2], c[0][3]}}, reinterpret_cast<dt_qint8*>(dst_ptr + 8)); | |||
@@ -150,7 +152,7 @@ struct StoreOcxOw4Remain<1, 0, Op, T> { | |||
template <typename Op, typename T> | |||
struct StoreOcxOw4Remain<1, 3, Op, T> { | |||
static void impl(T& c, const Op& op, int8_t* dst_ptr, int ld_dst_oc) { | |||
static __ai void impl(T& c, const Op& op, int8_t* dst_ptr, int ld_dst_oc) { | |||
MEGDNN_MARK_USED_VAR(ld_dst_oc); | |||
op({{c[0][0], c[0][1]}}, reinterpret_cast<dt_qint8*>(dst_ptr)); | |||
op(c[0][2], reinterpret_cast<dt_qint8*>(dst_ptr + 8)); | |||
@@ -158,33 +160,33 @@ struct StoreOcxOw4Remain<1, 3, Op, T> { | |||
}; | |||
template <typename Op, typename T> | |||
struct StoreOcxOw4Remain<1, 2, Op, T> { | |||
static void impl(T& c, const Op& op, int8_t* dst_ptr, int ld_dst_oc) { | |||
static __ai void impl(T& c, const Op& op, int8_t* dst_ptr, int ld_dst_oc) { | |||
MEGDNN_MARK_USED_VAR(ld_dst_oc); | |||
op({{c[0][0], c[0][1]}}, reinterpret_cast<dt_qint8*>(dst_ptr)); | |||
} | |||
}; | |||
template <typename Op, typename T> | |||
struct StoreOcxOw4Remain<1, 1, Op, T> { | |||
static void impl(T& c, const Op& op, int8_t* dst_ptr, int ld_dst_oc) { | |||
static __ai void impl(T& c, const Op& op, int8_t* dst_ptr, int ld_dst_oc) { | |||
MEGDNN_MARK_USED_VAR(ld_dst_oc); | |||
op(c[0][0], reinterpret_cast<dt_qint8*>(dst_ptr)); | |||
} | |||
}; | |||
template <int c_dim, int ow_remain, typename Op, typename T> | |||
inline void store_ocx_ow4_remain_static(T& c, const Op& op, int8_t* dst_ptr, | |||
int ld_dst_oc) { | |||
__ai void store_ocx_ow4_remain_static(T& c, const Op& op, int8_t* dst_ptr, | |||
int ld_dst_oc) { | |||
StoreOcxOw4Remain<c_dim, ow_remain, Op, T>::impl(c, op, dst_ptr, ld_dst_oc); | |||
} | |||
////////////////////Store_OCX_OW8_Remain///////////////////////// | |||
template <int c_dim, int ow_remain, typename Op, typename T, typename T2, | |||
typename T3> | |||
struct StoreOcxOw8Remain { | |||
static void impl(T& c, const Op& op, T2 dst_ptr, int ld_dst_oc); | |||
static __ai void impl(T& c, const Op& op, T2 dst_ptr, int ld_dst_oc); | |||
}; | |||
template <typename Op, typename T, typename T2, typename T3> | |||
struct StoreOcxOw8Remain<2, 0, Op, T, T2, T3> { | |||
static void impl(T& c, const Op& op, T2 dst_ptr, int ld_dst_oc) { | |||
static __ai void impl(T& c, const Op& op, T2 dst_ptr, int ld_dst_oc) { | |||
op({{c[0][0], c[0][1]}}, reinterpret_cast<T3>(dst_ptr)); | |||
op({{c[0][2], c[0][3]}}, reinterpret_cast<T3>(dst_ptr + 8)); | |||
op({{c[0][4], c[0][5]}}, reinterpret_cast<T3>(dst_ptr + 16)); | |||
@@ -200,7 +202,7 @@ struct StoreOcxOw8Remain<2, 0, Op, T, T2, T3> { | |||
}; | |||
template <typename Op, typename T, typename T2, typename T3> | |||
struct StoreOcxOw8Remain<2, 8, Op, T, T2, T3> { | |||
static void impl(T& c, const Op& op, T2 dst_ptr, int ld_dst_oc) { | |||
static __ai void impl(T& c, const Op& op, T2 dst_ptr, int ld_dst_oc) { | |||
op({{c[0][0], c[0][1]}}, reinterpret_cast<T3>(dst_ptr)); | |||
op({{c[0][2], c[0][3]}}, reinterpret_cast<T3>(dst_ptr + 8)); | |||
op({{c[0][4], c[0][5]}}, reinterpret_cast<T3>(dst_ptr + 16)); | |||
@@ -216,7 +218,7 @@ struct StoreOcxOw8Remain<2, 8, Op, T, T2, T3> { | |||
}; | |||
template <typename Op, typename T, typename T2, typename T3> | |||
struct StoreOcxOw8Remain<2, 7, Op, T, T2, T3> { | |||
static void impl(T& c, const Op& op, T2 dst_ptr, int ld_dst_oc) { | |||
static __ai void impl(T& c, const Op& op, T2 dst_ptr, int ld_dst_oc) { | |||
op({{c[0][0], c[0][1]}}, reinterpret_cast<T3>(dst_ptr)); | |||
op({{c[0][2], c[0][3]}}, reinterpret_cast<T3>(dst_ptr + 8)); | |||
op({{c[0][4], c[0][5]}}, reinterpret_cast<T3>(dst_ptr + 16)); | |||
@@ -231,7 +233,7 @@ struct StoreOcxOw8Remain<2, 7, Op, T, T2, T3> { | |||
}; | |||
template <typename Op, typename T, typename T2, typename T3> | |||
struct StoreOcxOw8Remain<2, 6, Op, T, T2, T3> { | |||
static void impl(T& c, const Op& op, T2 dst_ptr, int ld_dst_oc) { | |||
static __ai void impl(T& c, const Op& op, T2 dst_ptr, int ld_dst_oc) { | |||
op({{c[0][0], c[0][1]}}, reinterpret_cast<T3>(dst_ptr)); | |||
op({{c[0][2], c[0][3]}}, reinterpret_cast<T3>(dst_ptr + 8)); | |||
op({{c[0][4], c[0][5]}}, reinterpret_cast<T3>(dst_ptr + 16)); | |||
@@ -244,7 +246,7 @@ struct StoreOcxOw8Remain<2, 6, Op, T, T2, T3> { | |||
}; | |||
template <typename Op, typename T, typename T2, typename T3> | |||
struct StoreOcxOw8Remain<2, 5, Op, T, T2, T3> { | |||
static void impl(T& c, const Op& op, T2 dst_ptr, int ld_dst_oc) { | |||
static __ai void impl(T& c, const Op& op, T2 dst_ptr, int ld_dst_oc) { | |||
op({{c[0][0], c[0][1]}}, reinterpret_cast<T3>(dst_ptr)); | |||
op({{c[0][2], c[0][3]}}, reinterpret_cast<T3>(dst_ptr + 8)); | |||
op(c[0][4], reinterpret_cast<T3>(dst_ptr + 16)); | |||
@@ -256,7 +258,7 @@ struct StoreOcxOw8Remain<2, 5, Op, T, T2, T3> { | |||
}; | |||
template <typename Op, typename T, typename T2, typename T3> | |||
struct StoreOcxOw8Remain<2, 4, Op, T, T2, T3> { | |||
static void impl(T& c, const Op& op, T2 dst_ptr, int ld_dst_oc) { | |||
static __ai void impl(T& c, const Op& op, T2 dst_ptr, int ld_dst_oc) { | |||
op({{c[0][0], c[0][1]}}, reinterpret_cast<T3>(dst_ptr)); | |||
op({{c[0][2], c[0][3]}}, reinterpret_cast<T3>(dst_ptr + 8)); | |||
@@ -266,7 +268,7 @@ struct StoreOcxOw8Remain<2, 4, Op, T, T2, T3> { | |||
}; | |||
template <typename Op, typename T, typename T2, typename T3> | |||
struct StoreOcxOw8Remain<2, 3, Op, T, T2, T3> { | |||
static void impl(T& c, const Op& op, T2 dst_ptr, int ld_dst_oc) { | |||
static __ai void impl(T& c, const Op& op, T2 dst_ptr, int ld_dst_oc) { | |||
op({{c[0][0], c[0][1]}}, reinterpret_cast<T3>(dst_ptr)); | |||
op(c[0][2], reinterpret_cast<T3>(dst_ptr + 8)); | |||
@@ -276,14 +278,14 @@ struct StoreOcxOw8Remain<2, 3, Op, T, T2, T3> { | |||
}; | |||
template <typename Op, typename T, typename T2, typename T3> | |||
struct StoreOcxOw8Remain<2, 2, Op, T, T2, T3> { | |||
static void impl(T& c, const Op& op, T2 dst_ptr, int ld_dst_oc) { | |||
static __ai void impl(T& c, const Op& op, T2 dst_ptr, int ld_dst_oc) { | |||
op({{c[0][0], c[0][1]}}, reinterpret_cast<T3>(dst_ptr)); | |||
op({{c[1][0], c[1][1]}}, reinterpret_cast<T3>(dst_ptr + ld_dst_oc)); | |||
} | |||
}; | |||
template <typename Op, typename T, typename T2, typename T3> | |||
struct StoreOcxOw8Remain<2, 1, Op, T, T2, T3> { | |||
static void impl(T& c, const Op& op, T2 dst_ptr, int ld_dst_oc) { | |||
static __ai void impl(T& c, const Op& op, T2 dst_ptr, int ld_dst_oc) { | |||
op(c[0][0], reinterpret_cast<T3>(dst_ptr)); | |||
op(c[1][0], reinterpret_cast<T3>(dst_ptr + ld_dst_oc)); | |||
} | |||
@@ -291,7 +293,7 @@ struct StoreOcxOw8Remain<2, 1, Op, T, T2, T3> { | |||
template <typename Op, typename T, typename T2, typename T3> | |||
struct StoreOcxOw8Remain<1, 0, Op, T, T2, T3> { | |||
static void impl(T& c, const Op& op, T2 dst_ptr, int) { | |||
static __ai void impl(T& c, const Op& op, T2 dst_ptr, int) { | |||
op({{c[0][0], c[0][1]}}, reinterpret_cast<T3>(dst_ptr)); | |||
op({{c[0][2], c[0][3]}}, reinterpret_cast<T3>(dst_ptr + 8)); | |||
op({{c[0][4], c[0][5]}}, reinterpret_cast<T3>(dst_ptr + 16)); | |||
@@ -300,7 +302,7 @@ struct StoreOcxOw8Remain<1, 0, Op, T, T2, T3> { | |||
}; | |||
template <typename Op, typename T, typename T2, typename T3> | |||
struct StoreOcxOw8Remain<1, 8, Op, T, T2, T3> { | |||
static void impl(T& c, const Op& op, T2 dst_ptr, int) { | |||
static __ai void impl(T& c, const Op& op, T2 dst_ptr, int) { | |||
op({{c[0][0], c[0][1]}}, reinterpret_cast<T3>(dst_ptr)); | |||
op({{c[0][2], c[0][3]}}, reinterpret_cast<T3>(dst_ptr + 8)); | |||
op({{c[0][4], c[0][5]}}, reinterpret_cast<T3>(dst_ptr + 16)); | |||
@@ -310,7 +312,7 @@ struct StoreOcxOw8Remain<1, 8, Op, T, T2, T3> { | |||
template <typename Op, typename T, typename T2, typename T3> | |||
struct StoreOcxOw8Remain<1, 7, Op, T, T2, T3> { | |||
static void impl(T& c, const Op& op, T2 dst_ptr, int) { | |||
static __ai void impl(T& c, const Op& op, T2 dst_ptr, int) { | |||
op({{c[0][0], c[0][1]}}, reinterpret_cast<T3>(dst_ptr)); | |||
op({{c[0][2], c[0][3]}}, reinterpret_cast<T3>(dst_ptr + 8)); | |||
op({{c[0][4], c[0][5]}}, reinterpret_cast<T3>(dst_ptr + 16)); | |||
@@ -319,7 +321,7 @@ struct StoreOcxOw8Remain<1, 7, Op, T, T2, T3> { | |||
}; | |||
template <typename Op, typename T, typename T2, typename T3> | |||
struct StoreOcxOw8Remain<1, 6, Op, T, T2, T3> { | |||
static void impl(T& c, const Op& op, T2 dst_ptr, int) { | |||
static __ai void impl(T& c, const Op& op, T2 dst_ptr, int) { | |||
op({{c[0][0], c[0][1]}}, reinterpret_cast<T3>(dst_ptr)); | |||
op({{c[0][2], c[0][3]}}, reinterpret_cast<T3>(dst_ptr + 8)); | |||
op({{c[0][4], c[0][5]}}, reinterpret_cast<T3>(dst_ptr + 16)); | |||
@@ -327,7 +329,7 @@ struct StoreOcxOw8Remain<1, 6, Op, T, T2, T3> { | |||
}; | |||
template <typename Op, typename T, typename T2, typename T3> | |||
struct StoreOcxOw8Remain<1, 5, Op, T, T2, T3> { | |||
static void impl(T& c, const Op& op, T2 dst_ptr, int) { | |||
static __ai void impl(T& c, const Op& op, T2 dst_ptr, int) { | |||
op({{c[0][0], c[0][1]}}, reinterpret_cast<T3>(dst_ptr)); | |||
op({{c[0][2], c[0][3]}}, reinterpret_cast<T3>(dst_ptr + 8)); | |||
op(c[0][4], reinterpret_cast<T3>(dst_ptr + 16)); | |||
@@ -335,41 +337,41 @@ struct StoreOcxOw8Remain<1, 5, Op, T, T2, T3> { | |||
}; | |||
template <typename Op, typename T, typename T2, typename T3> | |||
struct StoreOcxOw8Remain<1, 4, Op, T, T2, T3> { | |||
static void impl(T& c, const Op& op, T2 dst_ptr, int) { | |||
static __ai void impl(T& c, const Op& op, T2 dst_ptr, int) { | |||
op({{c[0][0], c[0][1]}}, reinterpret_cast<T3>(dst_ptr)); | |||
op({{c[0][2], c[0][3]}}, reinterpret_cast<T3>(dst_ptr + 8)); | |||
} | |||
}; | |||
template <typename Op, typename T, typename T2, typename T3> | |||
struct StoreOcxOw8Remain<1, 3, Op, T, T2, T3> { | |||
static void impl(T& c, const Op& op, T2 dst_ptr, int) { | |||
static __ai void impl(T& c, const Op& op, T2 dst_ptr, int) { | |||
op({{c[0][0], c[0][1]}}, reinterpret_cast<T3>(dst_ptr)); | |||
op(c[0][2], reinterpret_cast<T3>(dst_ptr + 8)); | |||
} | |||
}; | |||
template <typename Op, typename T, typename T2, typename T3> | |||
struct StoreOcxOw8Remain<1, 2, Op, T, T2, T3> { | |||
static void impl(T& c, const Op& op, T2 dst_ptr, int) { | |||
static __ai void impl(T& c, const Op& op, T2 dst_ptr, int) { | |||
op({{c[0][0], c[0][1]}}, reinterpret_cast<T3>(dst_ptr)); | |||
} | |||
}; | |||
template <typename Op, typename T, typename T2, typename T3> | |||
struct StoreOcxOw8Remain<1, 1, Op, T, T2, T3> { | |||
static void impl(T& c, const Op& op, T2 dst_ptr, int) { | |||
static __ai void impl(T& c, const Op& op, T2 dst_ptr, int) { | |||
op(c[0][0], reinterpret_cast<T3>(dst_ptr)); | |||
} | |||
}; | |||
template <int c_dim, int ow_remain, typename Op, typename T, typename T2> | |||
inline void store_ocx_ow8_remain_static(T& c, const Op& op, T2 dst_ptr, | |||
int ld_dst_oc) { | |||
__ai void store_ocx_ow8_remain_static(T& c, const Op& op, T2 dst_ptr, | |||
int ld_dst_oc) { | |||
StoreOcxOw8Remain<c_dim, ow_remain, Op, T, T2, T2>::impl(c, op, dst_ptr, | |||
ld_dst_oc); | |||
} | |||
template <int c_dim, int ow_remain, typename Op, typename T3, typename T, | |||
typename T2> | |||
inline void store_ocx_ow8_remain_static_dt(T& c, const Op& op, T2 dst_ptr, | |||
int ld_dst_oc) { | |||
__ai void store_ocx_ow8_remain_static_dt(T& c, const Op& op, T2 dst_ptr, | |||
int ld_dst_oc) { | |||
StoreOcxOw8Remain<c_dim, ow_remain, Op, T, T2, T3>::impl(c, op, dst_ptr, | |||
ld_dst_oc); | |||
} | |||
@@ -377,14 +379,14 @@ inline void store_ocx_ow8_remain_static_dt(T& c, const Op& op, T2 dst_ptr, | |||
template <int ow_remain, typename Op> | |||
struct Store_OC8_OW8_Remain { | |||
static void impl(int32x4_t c[2][8], const Op& op, int8_t* dst_ptr, | |||
int ld_dst_oc); | |||
static __ai void impl(int32x4_t c[2][8], const Op& op, int8_t* dst_ptr, | |||
int ld_dst_oc); | |||
}; | |||
template <typename Op> | |||
struct Store_OC8_OW8_Remain<0, Op> { | |||
static void impl(int32x4_t c[2][8], const Op& op, int8_t* dst_ptr, | |||
int ld_dst_oc) { | |||
static __ai void impl(int32x4_t c[2][8], const Op& op, int8_t* dst_ptr, | |||
int ld_dst_oc) { | |||
op({{c[0][0], c[0][1]}}, reinterpret_cast<dt_qint8*>(dst_ptr)); | |||
op({{c[0][2], c[0][3]}}, reinterpret_cast<dt_qint8*>(dst_ptr + 8)); | |||
op({{c[0][4], c[0][5]}}, reinterpret_cast<dt_qint8*>(dst_ptr + 16)); | |||
@@ -403,8 +405,8 @@ struct Store_OC8_OW8_Remain<0, Op> { | |||
template <typename Op> | |||
struct Store_OC8_OW8_Remain<7, Op> { | |||
static void impl(int32x4_t c[2][8], const Op& op, int8_t* dst_ptr, | |||
int ld_dst_oc) { | |||
static __ai void impl(int32x4_t c[2][8], const Op& op, int8_t* dst_ptr, | |||
int ld_dst_oc) { | |||
op({{c[0][0], c[0][1]}}, reinterpret_cast<dt_qint8*>(dst_ptr)); | |||
op({{c[0][2], c[0][3]}}, reinterpret_cast<dt_qint8*>(dst_ptr + 8)); | |||
op({{c[0][4], c[0][5]}}, reinterpret_cast<dt_qint8*>(dst_ptr + 16)); | |||
@@ -422,8 +424,8 @@ struct Store_OC8_OW8_Remain<7, Op> { | |||
template <typename Op> | |||
struct Store_OC8_OW8_Remain<6, Op> { | |||
static void impl(int32x4_t c[2][8], const Op& op, int8_t* dst_ptr, | |||
int ld_dst_oc) { | |||
static __ai void impl(int32x4_t c[2][8], const Op& op, int8_t* dst_ptr, | |||
int ld_dst_oc) { | |||
op({{c[0][0], c[0][1]}}, reinterpret_cast<dt_qint8*>(dst_ptr)); | |||
op({{c[0][2], c[0][3]}}, reinterpret_cast<dt_qint8*>(dst_ptr + 8)); | |||
op({{c[0][4], c[0][5]}}, reinterpret_cast<dt_qint8*>(dst_ptr + 16)); | |||
@@ -439,8 +441,8 @@ struct Store_OC8_OW8_Remain<6, Op> { | |||
template <typename Op> | |||
struct Store_OC8_OW8_Remain<5, Op> { | |||
static void impl(int32x4_t c[2][8], const Op& op, int8_t* dst_ptr, | |||
int ld_dst_oc) { | |||
static __ai void impl(int32x4_t c[2][8], const Op& op, int8_t* dst_ptr, | |||
int ld_dst_oc) { | |||
op({{c[0][0], c[0][1]}}, reinterpret_cast<dt_qint8*>(dst_ptr)); | |||
op({{c[0][2], c[0][3]}}, reinterpret_cast<dt_qint8*>(dst_ptr + 8)); | |||
op(c[0][4], reinterpret_cast<dt_qint8*>(dst_ptr + 16)); | |||
@@ -455,8 +457,8 @@ struct Store_OC8_OW8_Remain<5, Op> { | |||
template <typename Op> | |||
struct Store_OC8_OW8_Remain<4, Op> { | |||
static void impl(int32x4_t c[2][8], const Op& op, int8_t* dst_ptr, | |||
int ld_dst_oc) { | |||
static __ai void impl(int32x4_t c[2][8], const Op& op, int8_t* dst_ptr, | |||
int ld_dst_oc) { | |||
op({{c[0][0], c[0][1]}}, reinterpret_cast<dt_qint8*>(dst_ptr)); | |||
op({{c[0][2], c[0][3]}}, reinterpret_cast<dt_qint8*>(dst_ptr + 8)); | |||
@@ -469,8 +471,8 @@ struct Store_OC8_OW8_Remain<4, Op> { | |||
template <typename Op> | |||
struct Store_OC8_OW8_Remain<3, Op> { | |||
static void impl(int32x4_t c[2][8], const Op& op, int8_t* dst_ptr, | |||
int ld_dst_oc) { | |||
static __ai void impl(int32x4_t c[2][8], const Op& op, int8_t* dst_ptr, | |||
int ld_dst_oc) { | |||
op({{c[0][0], c[0][1]}}, reinterpret_cast<dt_qint8*>(dst_ptr)); | |||
op(c[0][2], reinterpret_cast<dt_qint8*>(dst_ptr + 8)); | |||
@@ -481,8 +483,8 @@ struct Store_OC8_OW8_Remain<3, Op> { | |||
}; | |||
template <typename Op> | |||
struct Store_OC8_OW8_Remain<2, Op> { | |||
static void impl(int32x4_t c[2][8], const Op& op, int8_t* dst_ptr, | |||
int ld_dst_oc) { | |||
static __ai void impl(int32x4_t c[2][8], const Op& op, int8_t* dst_ptr, | |||
int ld_dst_oc) { | |||
op({{c[0][0], c[0][1]}}, reinterpret_cast<dt_qint8*>(dst_ptr)); | |||
op({{c[1][0], c[1][1]}}, | |||
reinterpret_cast<dt_qint8*>(dst_ptr + ld_dst_oc)); | |||
@@ -490,8 +492,8 @@ struct Store_OC8_OW8_Remain<2, Op> { | |||
}; | |||
template <typename Op> | |||
struct Store_OC8_OW8_Remain<1, Op> { | |||
static void impl(int32x4_t c[2][8], const Op& op, int8_t* dst_ptr, | |||
int ld_dst_oc) { | |||
static __ai void impl(int32x4_t c[2][8], const Op& op, int8_t* dst_ptr, | |||
int ld_dst_oc) { | |||
op(c[0][0], reinterpret_cast<dt_qint8*>(dst_ptr)); | |||
op(c[1][0], reinterpret_cast<dt_qint8*>(dst_ptr + ld_dst_oc)); | |||
} | |||
@@ -500,14 +502,14 @@ struct Store_OC8_OW8_Remain<1, Op> { | |||
/////////// | |||
template <int ow_remain, typename Op, typename T, typename T2> | |||
inline void store_oc8_ow8_remain_static(T& c, const Op& op, T2 dst_ptr, | |||
int ld_dst_oc) { | |||
__ai void store_oc8_ow8_remain_static(T& c, const Op& op, T2 dst_ptr, | |||
int ld_dst_oc) { | |||
Store_OC8_OW8_Remain<ow_remain, Op>::impl(c, op, dst_ptr, ld_dst_oc); | |||
} | |||
////////////////////////////////////// | |||
template <BiasMode bias_mode> | |||
inline void init_oc4_ow8(int32x4_t c[8], const int32_t* bias_ptr) { | |||
__ai void init_oc4_ow8(int32x4_t c[8], const int32_t* bias_ptr) { | |||
if (bias_mode == BiasMode::BROADCAST_CHANNEL_BIAS) { | |||
#define BAIS_INIT(step) c[step] = vld1q_s32(bias_ptr); | |||
UNROLL_CALL_RAW(8, BAIS_INIT); | |||
@@ -520,8 +522,8 @@ inline void init_oc4_ow8(int32x4_t c[8], const int32_t* bias_ptr) { | |||
} | |||
template <BiasMode bias_mode> | |||
inline void init_oc8_ow8(int32x4_t c[2][8], const int32_t* bias_ptr, | |||
int oc_step) { | |||
__ai void init_oc8_ow8(int32x4_t c[2][8], const int32_t* bias_ptr, | |||
int oc_step) { | |||
if (bias_mode == BiasMode::BROADCAST_CHANNEL_BIAS) { | |||
#define BAIS_INIT(step) \ | |||
c[0][step] = vld1q_s32(bias_ptr); \ | |||
@@ -539,28 +541,28 @@ inline void init_oc8_ow8(int32x4_t c[2][8], const int32_t* bias_ptr, | |||
/////////////////////////init_ocx_ow8//////////////////// | |||
inline float32x4_t neon_vdupq_n(float val) { | |||
__ai float32x4_t neon_vdupq_n(float val) { | |||
return vdupq_n_f32(val); | |||
} | |||
inline int32x4_t neon_vdupq_n(int val) { | |||
__ai int32x4_t neon_vdupq_n(int val) { | |||
return vdupq_n_s32(val); | |||
} | |||
inline float32x4_t neon_vld1q(const float* ptr) { | |||
__ai float32x4_t neon_vld1q(const float* ptr) { | |||
return vld1q_f32(ptr); | |||
} | |||
inline int32x4_t neon_vld1q(const int* ptr) { | |||
__ai int32x4_t neon_vld1q(const int* ptr) { | |||
return vld1q_s32(ptr); | |||
} | |||
template <int c_dim, BiasMode bias_mode, int ow_block, typename T, typename T2> | |||
struct InitOcxOw8 { | |||
static void impl(T& c, const T2* bias_ptr, int oc_step); | |||
static __ai void impl(T& c, const T2* bias_ptr, int oc_step); | |||
}; | |||
template <typename T, typename T2> | |||
struct InitOcxOw8<2, BiasMode::NO_BIAS, 8, T, T2> { | |||
static void impl(T& c, const T2*, int) { | |||
static __ai void impl(T& c, const T2*, int) { | |||
#define BAIS_INIT(step) \ | |||
c[0][step] = neon_vdupq_n(static_cast<T2>(0)); \ | |||
c[1][step] = neon_vdupq_n(static_cast<T2>(0)); | |||
@@ -570,7 +572,7 @@ struct InitOcxOw8<2, BiasMode::NO_BIAS, 8, T, T2> { | |||
}; | |||
template <typename T, typename T2> | |||
struct InitOcxOw8<2, BiasMode::NO_BIAS, 4, T, T2> { | |||
static void impl(T& c, const T2*, int) { | |||
static __ai void impl(T& c, const T2*, int) { | |||
#define BAIS_INIT(step) \ | |||
c[0][step] = neon_vdupq_n(static_cast<T2>(0)); \ | |||
c[1][step] = neon_vdupq_n(static_cast<T2>(0)); | |||
@@ -580,7 +582,7 @@ struct InitOcxOw8<2, BiasMode::NO_BIAS, 4, T, T2> { | |||
}; | |||
template <typename T, typename T2> | |||
struct InitOcxOw8<2, BiasMode::BROADCAST_CHANNEL_BIAS, 8, T, T2> { | |||
static void impl(T& c, const T2* bias_ptr, int oc_step) { | |||
static __ai void impl(T& c, const T2* bias_ptr, int oc_step) { | |||
#define BAIS_INIT(step) \ | |||
c[0][step] = neon_vld1q(bias_ptr); \ | |||
c[1][step] = neon_vld1q(bias_ptr + oc_step); | |||
@@ -590,7 +592,7 @@ struct InitOcxOw8<2, BiasMode::BROADCAST_CHANNEL_BIAS, 8, T, T2> { | |||
}; | |||
template <typename T, typename T2> | |||
struct InitOcxOw8<2, BiasMode::BROADCAST_CHANNEL_BIAS, 4, T, T2> { | |||
static void impl(T& c, const T2* bias_ptr, int oc_step) { | |||
static __ai void impl(T& c, const T2* bias_ptr, int oc_step) { | |||
#define BAIS_INIT(step) \ | |||
c[0][step] = neon_vld1q(bias_ptr); \ | |||
c[1][step] = neon_vld1q(bias_ptr + oc_step); | |||
@@ -600,7 +602,7 @@ struct InitOcxOw8<2, BiasMode::BROADCAST_CHANNEL_BIAS, 4, T, T2> { | |||
}; | |||
template <typename T, typename T2> | |||
struct InitOcxOw8<2, BiasMode::BIAS, 8, T, T2> { | |||
static void impl(T& c, const T2* bias_ptr, int oc_step) { | |||
static __ai void impl(T& c, const T2* bias_ptr, int oc_step) { | |||
constexpr int simd_len = 4; | |||
#define BAIS_INIT(step) \ | |||
c[0][step] = neon_vld1q(bias_ptr + step * simd_len); \ | |||
@@ -611,7 +613,7 @@ struct InitOcxOw8<2, BiasMode::BIAS, 8, T, T2> { | |||
}; | |||
template <typename T, typename T2> | |||
struct InitOcxOw8<2, BiasMode::BIAS, 4, T, T2> { | |||
static void impl(T& c, const T2* bias_ptr, int oc_step) { | |||
static __ai void impl(T& c, const T2* bias_ptr, int oc_step) { | |||
constexpr int simd_len = 4; | |||
#define BAIS_INIT(step) \ | |||
c[0][step] = neon_vld1q(bias_ptr + step * simd_len); \ | |||
@@ -623,7 +625,7 @@ struct InitOcxOw8<2, BiasMode::BIAS, 4, T, T2> { | |||
template <typename T, typename T2> | |||
struct InitOcxOw8<1, BiasMode::NO_BIAS, 8, T, T2> { | |||
static void impl(T& c, const T2*, int) { | |||
static __ai void impl(T& c, const T2*, int) { | |||
#define BAIS_INIT(step) c[0][step] = neon_vdupq_n(static_cast<T2>(0)); | |||
UNROLL_CALL_RAW(8, BAIS_INIT); | |||
#undef BAIS_INIT | |||
@@ -631,7 +633,7 @@ struct InitOcxOw8<1, BiasMode::NO_BIAS, 8, T, T2> { | |||
}; | |||
template <typename T, typename T2> | |||
struct InitOcxOw8<1, BiasMode::NO_BIAS, 4, T, T2> { | |||
static void impl(T& c, const T2*, int) { | |||
static __ai void impl(T& c, const T2*, int) { | |||
#define BAIS_INIT(step) c[0][step] = neon_vdupq_n(static_cast<T2>(0)); | |||
UNROLL_CALL_RAW(4, BAIS_INIT); | |||
#undef BAIS_INIT | |||
@@ -639,7 +641,7 @@ struct InitOcxOw8<1, BiasMode::NO_BIAS, 4, T, T2> { | |||
}; | |||
template <typename T, typename T2> | |||
struct InitOcxOw8<1, BiasMode::BROADCAST_CHANNEL_BIAS, 8, T, T2> { | |||
static void impl(T& c, const T2* bias_ptr, int) { | |||
static __ai void impl(T& c, const T2* bias_ptr, int) { | |||
#define BAIS_INIT(step) c[0][step] = neon_vld1q(bias_ptr); | |||
UNROLL_CALL_RAW(8, BAIS_INIT); | |||
#undef BAIS_INIT | |||
@@ -647,7 +649,7 @@ struct InitOcxOw8<1, BiasMode::BROADCAST_CHANNEL_BIAS, 8, T, T2> { | |||
}; | |||
template <typename T, typename T2> | |||
struct InitOcxOw8<1, BiasMode::BROADCAST_CHANNEL_BIAS, 4, T, T2> { | |||
static void impl(T& c, const T2* bias_ptr, int) { | |||
static __ai void impl(T& c, const T2* bias_ptr, int) { | |||
#define BAIS_INIT(step) c[0][step] = neon_vld1q(bias_ptr); | |||
UNROLL_CALL_RAW(4, BAIS_INIT); | |||
#undef BAIS_INIT | |||
@@ -655,7 +657,7 @@ struct InitOcxOw8<1, BiasMode::BROADCAST_CHANNEL_BIAS, 4, T, T2> { | |||
}; | |||
template <typename T, typename T2> | |||
struct InitOcxOw8<1, BiasMode::BIAS, 8, T, T2> { | |||
static void impl(T& c, const T2* bias_ptr, int) { | |||
static __ai void impl(T& c, const T2* bias_ptr, int) { | |||
constexpr int simd_len = 4; | |||
#define BAIS_INIT(step) c[0][step] = neon_vld1q(bias_ptr + step * simd_len); | |||
UNROLL_CALL_RAW(8, BAIS_INIT); | |||
@@ -664,7 +666,7 @@ struct InitOcxOw8<1, BiasMode::BIAS, 8, T, T2> { | |||
}; | |||
template <typename T, typename T2> | |||
struct InitOcxOw8<1, BiasMode::BIAS, 4, T, T2> { | |||
static void impl(T& c, const T2* bias_ptr, int) { | |||
static __ai void impl(T& c, const T2* bias_ptr, int) { | |||
constexpr int simd_len = 4; | |||
#define BAIS_INIT(step) c[0][step] = neon_vld1q(bias_ptr + step * simd_len); | |||
UNROLL_CALL_RAW(4, BAIS_INIT); | |||
@@ -673,18 +675,18 @@ struct InitOcxOw8<1, BiasMode::BIAS, 4, T, T2> { | |||
}; | |||
template <int c_dim, BiasMode bias_mode, int ow_block, typename T, typename T2> | |||
inline void init_ocx_ow8(T& c, const T2* bias_ptr, int oc_step) { | |||
__ai void init_ocx_ow8(T& c, const T2* bias_ptr, int oc_step) { | |||
InitOcxOw8<c_dim, bias_mode, ow_block, T, T2>::impl(c, bias_ptr, oc_step); | |||
} | |||
/////////////////////init_ocx_ow4///////////////////// | |||
template <int c_dim, BiasMode bias_mode, typename T> | |||
struct InitOcxOw4 { | |||
static void impl(T& c, const int32_t* bias_ptr, int oc_step); | |||
static __ai void impl(T& c, const int32_t* bias_ptr, int oc_step); | |||
}; | |||
template <BiasMode bias_mode, typename T> | |||
struct InitOcxOw4<2, bias_mode, T> { | |||
static void impl(T& c, const int32_t* bias_ptr, int oc_step) { | |||
static __ai void impl(T& c, const int32_t* bias_ptr, int oc_step) { | |||
if (bias_mode == BiasMode::BROADCAST_CHANNEL_BIAS) { | |||
#define BAIS_INIT(step) \ | |||
c[0][step] = vld1q_s32(bias_ptr); \ | |||
@@ -703,7 +705,7 @@ struct InitOcxOw4<2, bias_mode, T> { | |||
template <BiasMode bias_mode, typename T> | |||
struct InitOcxOw4<1, bias_mode, T> { | |||
static void impl(T& c, const int32_t* bias_ptr, int oc_step) { | |||
static __ai void impl(T& c, const int32_t* bias_ptr, int oc_step) { | |||
MEGDNN_MARK_USED_VAR(oc_step); | |||
if (bias_mode == BiasMode::BROADCAST_CHANNEL_BIAS) { | |||
#define BAIS_INIT(step) c[0][step] = vld1q_s32(bias_ptr); | |||
@@ -718,12 +720,12 @@ struct InitOcxOw4<1, bias_mode, T> { | |||
}; | |||
template <int c_dim, BiasMode bias_mode, typename T> | |||
inline void init_ocx_ow4(T& c, const int32_t* bias_ptr, int oc_step) { | |||
__ai void init_ocx_ow4(T& c, const int32_t* bias_ptr, int oc_step) { | |||
InitOcxOw4<c_dim, bias_mode, T>::impl(c, bias_ptr, oc_step); | |||
} | |||
/////////////////////////////////////// | |||
} // namespace | |||
} // namespace megdnn | |||
#undef __ai | |||
// vim: syntax=cpp.doxygen |
@@ -13,13 +13,14 @@ | |||
#include "src/arm_common/neon_struct.h" | |||
#include "src/arm_common/simd_macro/marm_neon.h" | |||
#include "src/common/unroll_macro.h" | |||
#define __ai inline __attribute__((__always_inline__)) | |||
namespace megdnn { | |||
namespace { | |||
template <int weight_number, int base_offset, int ptr_step, int oc_block, | |||
typename Func, typename T, typename T2, typename... XT> | |||
struct LoadHelper { | |||
static void impl(T& weight, T2 ptr, int oc_offset, XT... args); | |||
static __ai void impl(T& weight, T2 ptr, int oc_offset, XT... args); | |||
}; | |||
#define WEIGHT_CB(step) \ | |||
@@ -29,7 +30,7 @@ struct LoadHelper { | |||
template <int base_offset, int ptr_step, typename Func, typename T, \ | |||
typename T2, typename... XT> \ | |||
struct LoadHelper<step, base_offset, ptr_step, 0, Func, T, T2, XT...> { \ | |||
static void impl(T& src, T2 ptr, int, XT... args) { \ | |||
static __ai void impl(T& src, T2 ptr, int, XT... args) { \ | |||
UNROLL_CALL_RAW(step, WEIGHT_CB); \ | |||
} \ | |||
} | |||
@@ -62,7 +63,7 @@ LOAD_HELPER(16); | |||
template <int base_offset, int ptr_step, typename Func, typename T, \ | |||
typename T2> \ | |||
struct LoadHelper<step, base_offset, ptr_step, 1, Func, T, T2> { \ | |||
static void impl(T& src, T2 ptr, int) { \ | |||
static __ai void impl(T& src, T2 ptr, int) { \ | |||
UNROLL_CALL_RAW(step, WEIGHT_CB); \ | |||
} \ | |||
} | |||
@@ -89,7 +90,7 @@ LOAD_HELPER(9); | |||
template <int base_offset, int ptr_step, typename Func, typename T, \ | |||
typename T2> \ | |||
struct LoadHelper<step, base_offset, ptr_step, 2, Func, T, T2> { \ | |||
static void impl(T& src, T2 ptr, int oc_offset) { \ | |||
static __ai void impl(T& src, T2 ptr, int oc_offset) { \ | |||
UNROLL_CALL_RAW(step, WEIGHT_CB); \ | |||
} \ | |||
} | |||
@@ -108,19 +109,19 @@ LOAD_HELPER(8); | |||
template <int weight_number, int base_offset, int ptr_step, int c_dim, | |||
typename Func, typename T, typename T2> | |||
inline void load_helper(T& weight, T2 ptr, int oc_offset) { | |||
__ai void load_helper(T& weight, T2 ptr, int oc_offset) { | |||
LoadHelper<weight_number, base_offset, ptr_step, c_dim, Func, T, T2>::impl( | |||
weight, ptr, oc_offset); | |||
} | |||
template <int weight_number, int base_offset, int ptr_step, int c_dim, | |||
typename Func, typename T, typename T2, typename... XT> | |||
inline void load_helper_x(T& weight, T2 ptr, int oc_offset, XT... args) { | |||
__ai void load_helper_x(T& weight, T2 ptr, int oc_offset, XT... args) { | |||
LoadHelper<weight_number, base_offset, ptr_step, c_dim, Func, T, T2, | |||
XT...>::impl(weight, ptr, oc_offset, args...); | |||
} | |||
} // namespace | |||
} // namespace megdnn | |||
#undef __ai | |||
// vim: syntax=cpp.doxygen |
@@ -11,59 +11,68 @@ | |||
*/ | |||
#pragma once | |||
#include "src/arm_common/simd_macro/marm_neon.h" | |||
#define __ai inline __attribute__((__always_inline__)) | |||
namespace megdnn { | |||
namespace { | |||
struct Vdotq_s32_h { | |||
static int32x4_t impl(int8x16_t& a, int8x16_t& b, int32x4_t& c, | |||
int16x8_t& temp) { | |||
static __ai int32x4_t impl(int8x16_t& a, int8x16_t& b, int32x4_t& c, | |||
int16x8_t& temp) { | |||
return vdotq_s32_h(a, b, c, temp); | |||
} | |||
}; | |||
struct Vdot2_s32_h { | |||
static int32x4_t impl(int8x8_t a, int8x8_t b, int32x4_t c, int16x8_t temp) { | |||
static __ai int32x4_t impl(int8x8_t a, int8x8_t b, int32x4_t c, | |||
int16x8_t temp) { | |||
return vdot2_s32_h(a, b, c, temp); | |||
} | |||
}; | |||
struct Vmlal_s16 { | |||
static int32x4_t impl(int16x8_t a, int16x8_t b, int32x4_t c) { | |||
static __ai int32x4_t impl(int16x8_t a, int16x8_t b, int32x4_t c) { | |||
return vmlal_s16(c, vget_low_s16(a), vget_low_s16(b)); | |||
} | |||
}; | |||
struct Vld1q_s8 { | |||
static int8x16_t impl(const int8_t* ptr) { return vld1q_s8(ptr); } | |||
static __ai int8x16_t impl(const int8_t* ptr) { return vld1q_s8(ptr); } | |||
}; | |||
struct Vld1q_f32 { | |||
static float32x4_t impl(const float32_t* ptr) { return vld1q_f32(ptr); } | |||
static __ai float32x4_t impl(const float32_t* ptr) { | |||
return vld1q_f32(ptr); | |||
} | |||
}; | |||
struct Vld1_s8 { | |||
static int8x8_t impl(const int8_t* ptr) { return vld1_s8(ptr); } | |||
static __ai int8x8_t impl(const int8_t* ptr) { return vld1_s8(ptr); } | |||
}; | |||
struct Vldq_dup_4s8_8s16 { | |||
static int16x8_t impl(const int8_t* ptr) { return vldq_dup_4s8_8s16(ptr); } | |||
static __ai int16x8_t impl(const int8_t* ptr) { | |||
return vldq_dup_4s8_8s16(ptr); | |||
} | |||
}; | |||
struct Vldq_tbl_low_s8 { | |||
static int8x8_t impl(const int8_t* ptr, uint8x16_t idx) { | |||
static __ai int8x8_t impl(const int8_t* ptr, uint8x16_t idx) { | |||
return vldq_tbl_low_s8(ptr, idx); | |||
} | |||
}; | |||
struct Vld1_dup_s8_s16 { | |||
static int16x8_t impl(const int8_t* ptr) { return vld1_dup_s8_s16(ptr); } | |||
static __ai int16x8_t impl(const int8_t* ptr) { | |||
return vld1_dup_s8_s16(ptr); | |||
} | |||
}; | |||
struct Vfmaq_laneq_f32 { | |||
template <const int lane> | |||
static float32x4_t impl(float32x4_t a, float32x4_t b, float32x4_t v) { | |||
static __ai float32x4_t impl(float32x4_t a, float32x4_t b, float32x4_t v) { | |||
return vfmaq_laneq_f32(a, b, v, lane); | |||
} | |||
}; | |||
#if __ARM_FEATURE_DOTPROD | |||
struct Vdotq_laneq_s32 { | |||
template <const int lane> | |||
static int32x4_t impl(int32x4_t a, int8x16_t b, int8x16_t v) { | |||
static __ai int32x4_t impl(int32x4_t a, int8x16_t b, int8x16_t v) { | |||
return vdotq_laneq_s32(a, b, v, lane); | |||
} | |||
}; | |||
@@ -72,4 +81,5 @@ struct Vdotq_laneq_s32 { | |||
} // namespace | |||
} // namespace megdnn | |||
#undef __ai | |||
// vim: syntax=cpp.doxygen |
@@ -20,7 +20,9 @@ | |||
#pragma GCC diagnostic push | |||
#pragma GCC diagnostic ignored "-Wpragmas" | |||
#pragma GCC diagnostic ignored "-Wattributes" | |||
#define __ai static inline __attribute__((__always_inline__, __nodebug__)) | |||
#define __ai \ | |||
static inline \ | |||
__attribute__((__gnu_inline__, __always_inline__, __nodebug__)) | |||
#if __ARM_FEATURE_FP16_VECTOR_ARITHMETIC && !MEGDNN_DISABLE_FLOAT16 | |||
#define MEGDNN_INC_ARM_FP16(_x) _x | |||
@@ -299,16 +301,20 @@ __ai uint32x2_t vdot2_u8(uint8x8_t a, uint8x8_t b) { | |||
#endif // __ARM_FEATURE_DOTPROD | |||
#if __GNUC__ < 8 | |||
#undef vld1q_f32_x2 | |||
__ai float32x4x2_t vld1q_f32_x2(const float* p) { | |||
return {{vld1q_f32(p), vld1q_f32(p + 4)}}; | |||
} | |||
#endif | |||
#if __GNUC__ < 9 | |||
#undef vst1q_f32_x2 | |||
__ai void vst1q_f32_x2(const float* p, float32x4x2_t v) { | |||
vst1q_f32(const_cast<float*>(p), v.val[0]); | |||
vst1q_f32(const_cast<float*>(p) + 4, v.val[1]); | |||
} | |||
#endif | |||
__ai int8x16_t vtranslq_s8(int8x8_t a) { | |||
int8x16_t ret; | |||
@@ -472,18 +478,18 @@ __ai int8x16_t vqtbl1q_s8(int8x16_t& a, uint8x16_t& idx) { | |||
namespace { | |||
template <int lane> | |||
struct Vdup_laneq_s16_armv7 { | |||
static int16x4_t impl(int16x8_t vec); | |||
__ai int16x4_t impl(int16x8_t vec); | |||
}; | |||
#define cb(step) \ | |||
template <> \ | |||
struct Vdup_laneq_s16_armv7<step + 4> { \ | |||
static int16x4_t impl(int16x8_t vec) { \ | |||
__ai int16x4_t impl(int16x8_t vec) { \ | |||
return vdup_lane_s16(vget_high_s16(vec), step); \ | |||
} \ | |||
}; \ | |||
template <> \ | |||
struct Vdup_laneq_s16_armv7<step> { \ | |||
static int16x4_t impl(int16x8_t vec) { \ | |||
__ai int16x4_t impl(int16x8_t vec) { \ | |||
return vdup_lane_s16(vget_low_s16(vec), step); \ | |||
} \ | |||
}; | |||
@@ -495,30 +501,30 @@ UNROLL_CALL_RAW(4, cb); | |||
namespace { | |||
template <int lane> | |||
struct Vfmaq_laneq_f32_armv7 { | |||
static float32x4_t impl(float32x4_t a, float32x4_t b, float32x4_t v); | |||
__ai float32x4_t impl(float32x4_t a, float32x4_t b, float32x4_t v); | |||
}; | |||
template <> | |||
struct Vfmaq_laneq_f32_armv7<0> { | |||
static float32x4_t impl(float32x4_t a, float32x4_t b, float32x4_t v) { | |||
__ai float32x4_t impl(float32x4_t a, float32x4_t b, float32x4_t v) { | |||
return vmlaq_lane_f32(a, b, vget_low_f32(v), 0); | |||
} | |||
}; | |||
template <> | |||
struct Vfmaq_laneq_f32_armv7<1> { | |||
static float32x4_t impl(float32x4_t a, float32x4_t b, float32x4_t v) { | |||
__ai float32x4_t impl(float32x4_t a, float32x4_t b, float32x4_t v) { | |||
return vmlaq_lane_f32(a, b, vget_low_f32(v), 1); | |||
} | |||
}; | |||
template <> | |||
struct Vfmaq_laneq_f32_armv7<2> { | |||
static float32x4_t impl(float32x4_t a, float32x4_t b, float32x4_t v) { | |||
__ai float32x4_t impl(float32x4_t a, float32x4_t b, float32x4_t v) { | |||
return vmlaq_lane_f32(a, b, vget_high_f32(v), 0); | |||
} | |||
}; | |||
template <> | |||
struct Vfmaq_laneq_f32_armv7<3> { | |||
static float32x4_t impl(float32x4_t a, float32x4_t b, float32x4_t v) { | |||
__ai float32x4_t impl(float32x4_t a, float32x4_t b, float32x4_t v) { | |||
return vmlaq_lane_f32(a, b, vget_high_f32(v), 1); | |||
} | |||
}; | |||
@@ -527,37 +533,98 @@ struct Vfmaq_laneq_f32_armv7<3> { | |||
Vfmaq_laneq_f32_armv7<lane>::impl(a, b, v) | |||
#if __ARM_FEATURE_DOTPROD | |||
namespace { | |||
template <int lane> | |||
struct Vdotq_laneq_s32_armv7 { | |||
static int32x4_t impl(int32x4_t a, int8x16_t b, int8x16_t v); | |||
__ai int32x4_t impl(int32x4_t a, int8x16_t b, int8x16_t v); | |||
}; | |||
template <> | |||
struct Vdotq_laneq_s32_armv7<0> { | |||
static int32x4_t impl(int32x4_t a, int8x16_t b, int8x16_t v) { | |||
__ai int32x4_t impl(int32x4_t a, int8x16_t b, int8x16_t v) { | |||
return vdotq_lane_s32(a, b, vget_low_s32(v), 0); | |||
} | |||
}; | |||
template <> | |||
struct Vdotq_laneq_s32_armv7<1> { | |||
static int32x4_t impl(int32x4_t a, int8x16_t b, int8x16_t v) { | |||
__ai int32x4_t impl(int32x4_t a, int8x16_t b, int8x16_t v) { | |||
return vdotq_lane_s32(a, b, vget_low_s32(v), 1); | |||
} | |||
}; | |||
template <> | |||
struct Vdotq_laneq_s32_armv7<2> { | |||
static int32x4_t impl(int32x4_t a, int8x16_t b, int8x16_t v) { | |||
__ai int32x4_t impl(int32x4_t a, int8x16_t b, int8x16_t v) { | |||
return vdotq_lane_s32(a, b, vget_high_s32(v), 0); | |||
} | |||
}; | |||
template <> | |||
struct Vdotq_laneq_s32_armv7<3> { | |||
static int32x4_t impl(int32x4_t a, int8x16_t b, int8x16_t v) { | |||
__ai int32x4_t impl(int32x4_t a, int8x16_t b, int8x16_t v) { | |||
return vdotq_lane_s32(a, b, vget_high_f32(v), 1); | |||
} | |||
}; | |||
#define vdotq_laneq_s32(a, b, v, lane) \ | |||
Vdotq_laneq_s32_armv7<lane>::impl(a, b, v) | |||
} // namespace | |||
#endif | |||
#endif | |||
//! GCC split fmla with lane to dup+fmla when version < 9 | |||
//! https://gcc.gnu.org/bugzilla/show_bug.cgi?id=89101 | |||
#if !defined(__clang__) && __GNUC__ < 9 | |||
#if MEGDNN_AARCH64 | |||
namespace { | |||
template <int lane> | |||
struct Vfmaq_laneq_f32_armv8 { | |||
__ai float32x4_t impl(float32x4_t a, float32x4_t b, float32x4_t v); | |||
}; | |||
template <> | |||
struct Vfmaq_laneq_f32_armv8<0> { | |||
__ai float32x4_t impl(float32x4_t a, float32x4_t b, float32x4_t v) { | |||
asm volatile("fmla %0.4s, %1.4s, %2.s[0]\n" | |||
: "+w"(a) | |||
: "w"(b), "w"(v) | |||
:); | |||
return a; | |||
} | |||
}; | |||
template <> | |||
struct Vfmaq_laneq_f32_armv8<1> { | |||
__ai float32x4_t impl(float32x4_t a, float32x4_t b, float32x4_t v) { | |||
asm volatile("fmla %0.4s, %1.4s, %2.s[1]\n" | |||
: "+w"(a) | |||
: "w"(b), "w"(v) | |||
:); | |||
return a; | |||
} | |||
}; | |||
template <> | |||
struct Vfmaq_laneq_f32_armv8<2> { | |||
__ai float32x4_t impl(float32x4_t a, float32x4_t b, float32x4_t v) { | |||
asm volatile("fmla %0.4s, %1.4s, %2.s[2]\n" | |||
: "+w"(a) | |||
: "w"(b), "w"(v) | |||
:); | |||
return a; | |||
} | |||
}; | |||
template <> | |||
struct Vfmaq_laneq_f32_armv8<3> { | |||
__ai float32x4_t impl(float32x4_t a, float32x4_t b, float32x4_t v) { | |||
asm volatile("fmla %0.4s, %1.4s, %2.s[3]\n" | |||
: "+w"(a) | |||
: "w"(b), "w"(v) | |||
:); | |||
return a; | |||
} | |||
}; | |||
} // namespace | |||
#undef vfmaq_laneq_f32 | |||
#define vfmaq_laneq_f32(a, b, v, lane) \ | |||
Vfmaq_laneq_f32_armv8<lane>::impl(a, b, v) | |||
#endif | |||
#endif | |||
@@ -77,7 +77,7 @@ std::vector<conv_bias::TestArg> get_nchw44_conv_bias_args( | |||
bool only_no_bias = false) { | |||
using namespace conv_bias; | |||
using NLMode = param::ConvBias::NonlineMode; | |||
std::vector<TestArg> args; | |||
auto pack = [&](size_t n, size_t oc, size_t ic, size_t h, size_t w, | |||
@@ -172,11 +172,11 @@ std::vector<conv_bias::TestArg> get_nchw44_conv_bias_args( | |||
bias_mode.emplace_back(megdnn::BiasMode::NO_BIAS); | |||
} | |||
if (support_full_bias) { | |||
bias_mode.emplace_back(megdnn::BiasMode::BIAS); | |||
bias_mode.emplace_back(megdnn::BiasMode::BIAS); | |||
} | |||
for (auto bias : bias_mode) | |||
for (auto nlmode : nonlinemode) | |||
for (size_t n : {1,2}) | |||
for (size_t n : {1, 2}) | |||
for (size_t kernel : kernel_vec) | |||
for (size_t oc : {4, 12}) | |||
for (size_t ic : {1, 3, 4, 12}) | |||
@@ -364,8 +364,8 @@ TEST_F(ARM_COMMON_MULTI_THREADS, CONVBIAS_DIRECT_FP32_SMALL_GROUP) { | |||
} | |||
TEST_F(ARM_COMMON_MULTI_THREADS, CONVBIAS_DIRECT_FP32_NCHW44_S1_K7) { | |||
check_conv_bias(get_nchw44_conv_bias_args({7}, 1, false, true, true, | |||
false, false, false), | |||
check_conv_bias(get_nchw44_conv_bias_args({7}, 1, false, true, true, false, | |||
false, false), | |||
handle(), "F32_CONV_NCHW44_DIRECT"); | |||
} | |||
@@ -403,10 +403,12 @@ TEST_F(ARM_COMMON_MULTI_THREADS, CONVBIAS_DIRECT_FP32_STR2_SMALL_GROUP) { | |||
check_conv_bias(get_conv_bias_args({2, 3, 5, 7}, 2, false, false, false), | |||
handle(), "F32STRD2_SMALL_GROUP"); | |||
} | |||
TEST_F(ARM_COMMON_MULTI_THREADS, CONVBIAS_NCHW_NCHW44_F32) { | |||
TEST_F(ARM_COMMON_MULTI_THREADS, CONVBIAS_NCHW_NCHW44_F32_S2) { | |||
check_conv_bias(get_nchw44_conv_bias_args({2, 3, 5, 7}, 2, false, false, | |||
false, true), | |||
handle(), "F32_CONV_NCHW_NCHW44"); | |||
} | |||
TEST_F(ARM_COMMON_MULTI_THREADS, CONVBIAS_NCHW_NCHW44_F32_S1) { | |||
check_conv_bias(get_nchw44_conv_bias_args({2, 3, 5, 7}, 1, false, false, | |||
false, true), | |||
handle(), "F32_CONV_NCHW_NCHW44"); | |||
@@ -566,13 +568,15 @@ TEST_F(ARM_COMMON_MULTI_THREADS, CONV_BIAS_QS8_CHANNEL_WISE_DIRECT2_NCHW44) { | |||
handle(), "S8_CHAN_WISE_STRD2_NCHW44"); | |||
} | |||
TEST_F(ARM_COMMON_MULTI_THREADS, CONV_BIAS_INT8_NCHW_NCHW44) { | |||
TEST_F(ARM_COMMON_MULTI_THREADS, CONV_BIAS_INT8_NCHW_NCHW44_S1) { | |||
checker_conv_bias_qint8x8x8( | |||
get_nchw44_conv_bias_args({2, 3, 5, 7}, 2, false, false, false, | |||
get_nchw44_conv_bias_args({2, 3, 5, 7}, 1, false, false, false, | |||
true), | |||
handle(), "S8_CONV_NCHW_NCHW44"); | |||
} | |||
TEST_F(ARM_COMMON_MULTI_THREADS, CONV_BIAS_INT8_NCHW_NCHW44_S2) { | |||
checker_conv_bias_qint8x8x8( | |||
get_nchw44_conv_bias_args({2, 3, 5, 7}, 1, false, false, false, | |||
get_nchw44_conv_bias_args({2, 3, 5, 7}, 2, false, false, false, | |||
true), | |||
handle(), "S8_CONV_NCHW_NCHW44"); | |||
} | |||
@@ -1820,7 +1824,7 @@ TEST_F(ARM_COMMON_MULTI_THREADS, CONV_BIAS_IM2COLMATMUL_INT8x8x32) { | |||
TEST_F(ARM_COMMON_MULTI_THREADS, CONV_BIAS_IM2COL_S1_MK4_PACK_F32) { | |||
using namespace conv_bias; | |||
std::vector<conv_bias::TestArg> args = get_nchw44_conv_bias_args( | |||
{2, 4, 7}, 1, false, false, false, false, false, true,true); | |||
{2, 4, 7}, 1, false, false, false, false, false, true, true); | |||
#if MEGDNN_AARCH64 | |||
check_conv_bias(args, handle(), "IM2COLMATMUL:AARCH64_F32_MK4_K8X12X1"); | |||
#elif MEGDNN_ARMV7 | |||
@@ -1841,7 +1845,7 @@ TEST_F(ARM_COMMON_MULTI_THREADS, CONV_BIAS_IM2COL_S2_MK4_PACK_F32) { | |||
TEST_F(ARM_COMMON_MULTI_THREADS, CONV_BIAS_IM2COL_S2_MK4_PACK_F32_FUSE) { | |||
using namespace conv_bias; | |||
std::vector<conv_bias::TestArg> args = get_nchw44_conv_bias_args( | |||
{3}, 2, false, false, false, false, false, true, true,false); | |||
{3}, 2, false, false, false, false, false, true, true, false); | |||
#if MEGDNN_AARCH64 | |||
check_conv_bias(args, handle(), "IM2COLMATMUL:AARCH64_F32_MK4_K8X12X1"); | |||
#elif MEGDNN_ARMV7 | |||
@@ -0,0 +1,6 @@ | |||
set(ARM_CROSS_BUILD_ARCH aarch64) | |||
set(CMAKE_C_COMPILER "aarch64-none-linux-gnu-gcc") | |||
set(CMAKE_CXX_COMPILER "aarch64-none-linux-gnu-g++") | |||
set(CMAKE_C_FLAGS "-Werror=unused-parameter -Wno-psabi") | |||
set(CMAKE_CXX_FLAGS "-Werror=unused-parameter -Wno-psabi") | |||
set(CMAKE_STRIP "aarch64-none-linux-gnu-strip") |