Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
gaoqiong
MIGraphX
Commits
a33d6fa2
Unverified
Commit
a33d6fa2
authored
Nov 24, 2021
by
Paul Fultz II
Committed by
GitHub
Nov 24, 2021
Browse files
Check jit kernels files with clang-tidy (#1012)
* Check jit kernels files with clang-tidy
parent
4f9a0ce7
Changes
14
Hide whitespace changes
Inline
Side-by-side
Showing
14 changed files
with
148 additions
and
64 deletions
+148
-64
src/targets/gpu/CMakeLists.txt
src/targets/gpu/CMakeLists.txt
+22
-16
src/targets/gpu/compile_roialign.cpp
src/targets/gpu/compile_roialign.cpp
+14
-2
src/targets/gpu/kernels/include/migraphx/kernels/array.hpp
src/targets/gpu/kernels/include/migraphx/kernels/array.hpp
+10
-10
src/targets/gpu/kernels/include/migraphx/kernels/debug.hpp
src/targets/gpu/kernels/include/migraphx/kernels/debug.hpp
+12
-2
src/targets/gpu/kernels/include/migraphx/kernels/functional.hpp
...rgets/gpu/kernels/include/migraphx/kernels/functional.hpp
+1
-0
src/targets/gpu/kernels/include/migraphx/kernels/generic_constant.hpp
...gpu/kernels/include/migraphx/kernels/generic_constant.hpp
+33
-0
src/targets/gpu/kernels/include/migraphx/kernels/hip.hpp
src/targets/gpu/kernels/include/migraphx/kernels/hip.hpp
+11
-0
src/targets/gpu/kernels/include/migraphx/kernels/index.hpp
src/targets/gpu/kernels/include/migraphx/kernels/index.hpp
+4
-4
src/targets/gpu/kernels/include/migraphx/kernels/integral_constant.hpp
...pu/kernels/include/migraphx/kernels/integral_constant.hpp
+12
-10
src/targets/gpu/kernels/include/migraphx/kernels/preload.hpp
src/targets/gpu/kernels/include/migraphx/kernels/preload.hpp
+1
-3
src/targets/gpu/kernels/include/migraphx/kernels/print.hpp
src/targets/gpu/kernels/include/migraphx/kernels/print.hpp
+1
-1
src/targets/gpu/kernels/include/migraphx/kernels/roialign.hpp
...targets/gpu/kernels/include/migraphx/kernels/roialign.hpp
+25
-14
src/targets/gpu/kernels/include/migraphx/kernels/types.hpp
src/targets/gpu/kernels/include/migraphx/kernels/types.hpp
+1
-1
src/targets/gpu/kernels/include/migraphx/kernels/vec.hpp
src/targets/gpu/kernels/include/migraphx/kernels/vec.hpp
+1
-1
No files found.
src/targets/gpu/CMakeLists.txt
View file @
a33d6fa2
...
...
@@ -91,28 +91,34 @@ add_library(migraphx_device
device/unary_not.cpp
device/where.cpp
)
set_target_properties
(
migraphx_device PROPERTIES EXPORT_NAME device
)
rocm_set_soversion
(
migraphx_device
${
MIGRAPHX_SO_VERSION
}
)
rocm_clang_tidy_check
(
migraphx_device
)
target_compile_options
(
migraphx_device PRIVATE -std=c++17 -fno-gpu-rdc -Wno-unused-command-line-argument -Xclang -fallow-half-arguments-and-returns
)
target_link_libraries
(
migraphx_device migraphx hip::device -fno-gpu-rdc -Wno-invalid-command-line-argument -Wno-unused-command-line-argument
)
if
(
CMAKE_CXX_COMPILER MATCHES
".*hcc"
)
set
(
AMDGPU_TARGETS
"gfx803;gfx900;gfx906"
CACHE STRING
""
)
foreach
(
AMDGPU_TARGET
${
AMDGPU_TARGETS
}
)
target_compile_options
(
migraphx_device PRIVATE -amdgpu-target=
${
AMDGPU_TARGET
}
)
target_link_libraries
(
migraphx_device -amdgpu-target=
${
AMDGPU_TARGET
}
)
endforeach
()
else
()
target_compile_options
(
migraphx_device PRIVATE -Wno-cuda-compat
)
endif
()
add_library
(
compile_for_gpu INTERFACE
)
target_compile_options
(
compile_for_gpu INTERFACE -std=c++17 -fno-gpu-rdc -Wno-cuda-compat -Wno-unused-command-line-argument -Xclang -fallow-half-arguments-and-returns
)
target_link_libraries
(
compile_for_gpu INTERFACE hip::device -fno-gpu-rdc -Wno-invalid-command-line-argument -Wno-unused-command-line-argument
)
check_cxx_compiler_flag
(
"--cuda-host-only -fhip-lambda-host-device -x hip"
HAS_HIP_LAMBDA_HOST_DEVICE
)
if
(
HAS_HIP_LAMBDA_HOST_DEVICE
)
message
(
STATUS
"Enable -fhip-lambda-host-device"
)
target_compile_options
(
migraphx_device PRIVAT
E -fhip-lambda-host-device
)
target_compile_options
(
compile_for_gpu INTERFAC
E -fhip-lambda-host-device
)
endif
()
set_target_properties
(
migraphx_device PROPERTIES EXPORT_NAME device
)
rocm_set_soversion
(
migraphx_device
${
MIGRAPHX_SO_VERSION
}
)
rocm_clang_tidy_check
(
migraphx_device
)
target_link_libraries
(
migraphx_device PUBLIC migraphx
)
target_link_libraries
(
migraphx_device PRIVATE compile_for_gpu
)
target_include_directories
(
migraphx_device PUBLIC $<BUILD_INTERFACE:
${
CMAKE_CURRENT_SOURCE_DIR
}
/include>
)
target_include_directories
(
migraphx_device PRIVATE $<BUILD_INTERFACE:
${
CMAKE_CURRENT_SOURCE_DIR
}
/device/include>
)
add_library
(
kernel_file_check EXCLUDE_FROM_ALL
)
foreach
(
KERNEL_FILE
${
KERNEL_FILES
}
)
get_filename_component
(
KERNEL_BASE_FILE
${
KERNEL_FILE
}
NAME_WE
)
file
(
WRITE
${
CMAKE_CURRENT_BINARY_DIR
}
/kernels/include/migraphx/kernels/
${
KERNEL_BASE_FILE
}
.cpp
"#include <migraphx/kernels/
${
KERNEL_BASE_FILE
}
.hpp>
\n
"
)
target_sources
(
kernel_file_check PRIVATE
${
CMAKE_CURRENT_BINARY_DIR
}
/kernels/include/migraphx/kernels/
${
KERNEL_BASE_FILE
}
.cpp
)
endforeach
()
target_include_directories
(
kernel_file_check PRIVATE $<BUILD_INTERFACE:
${
CMAKE_CURRENT_SOURCE_DIR
}
/kernels/include/>
)
target_link_libraries
(
kernel_file_check compile_for_gpu
)
rocm_clang_tidy_check
(
kernel_file_check
)
add_library
(
migraphx_gpu
abs.cpp
analyze_streams.cpp
...
...
@@ -341,7 +347,7 @@ target_link_libraries(migraphx_gpu PRIVATE migraphx_device migraphx_kernels)
add_subdirectory
(
driver
)
rocm_install_targets
(
TARGETS migraphx_gpu migraphx_device
TARGETS migraphx_gpu migraphx_device
compile_for_gpu
INCLUDE
${
CMAKE_CURRENT_SOURCE_DIR
}
/include
)
...
...
src/targets/gpu/compile_roialign.cpp
View file @
a33d6fa2
...
...
@@ -14,17 +14,29 @@ namespace gpu {
static
const
char
*
const
roialign_kernel
=
R"__migraphx__(
#include <migraphx/kernels/roialign.hpp>
#include <migraphx/kernels/basic_ops.hpp>
#include <migraphx/kernels/integral_constant.hpp>
#include <migraphx/kernels/generic_constant.hpp>
#include <args.hpp>
using
namespace migraphx
;
namespace migraphx
{
extern "C" {
__global__ void roialign_kernel(void* in_x, void* in_rois, void* in_ind, void* y)
{
make_tensors()(in_x, in_rois, in_ind, y)([](auto&&... xs) { roialign(xs...); });
make_tensors()(in_x, in_rois, in_ind, y)([](auto&&... xs) {
auto settings = make_roalign_settings(MIGRAPHX_MAKE_CONSTANT(float{ROIS_OFFSET}),
_c<bool{IS_AVG_POOLING}>,
_c<int64_t{SAMPLING_RATIO}>,
MIGRAPHX_MAKE_CONSTANT(float{SPATIAL_SCALE}));
roialign(xs..., settings);
});
}
}
} // namespace migraphx
int main() {}
)__migraphx__"
;
...
...
src/targets/gpu/kernels/include/migraphx/kernels/array.hpp
View file @
a33d6fa2
...
...
@@ -176,23 +176,23 @@ struct array
}
};
template
<
class
T
,
T
...
x
s
>
struct
integral_const_array
:
array
<
T
,
sizeof
...(
x
s
)
>
template
<
class
T
,
T
...
X
s
>
struct
integral_const_array
:
array
<
T
,
sizeof
...(
X
s
)
>
{
using
base_array
=
array
<
T
,
sizeof
...(
x
s
)
>
;
MIGRAPHX_DEVICE_CONSTEXPR
integral_const_array
()
:
base_array
({
x
s
...})
{}
using
base_array
=
array
<
T
,
sizeof
...(
X
s
)
>
;
MIGRAPHX_DEVICE_CONSTEXPR
integral_const_array
()
:
base_array
({
X
s
...})
{}
};
template
<
class
T
,
T
...
x
s
,
class
F
>
constexpr
auto
transform
(
integral_const_array
<
T
,
x
s
...
>
,
F
f
)
template
<
class
T
,
T
...
X
s
,
class
F
>
constexpr
auto
transform
(
integral_const_array
<
T
,
X
s
...
>
,
F
f
)
{
return
integral_const_array
<
T
,
f
(
x
s
)...
>
{};
return
integral_const_array
<
T
,
f
(
X
s
)...
>
{};
}
template
<
class
T
,
T
...
x
s
,
class
U
,
U
...
y
s
,
class
F
>
constexpr
auto
transform
(
integral_const_array
<
T
,
x
s
...
>
,
integral_const_array
<
U
,
y
s
...
>
,
F
f
)
template
<
class
T
,
T
...
X
s
,
class
U
,
U
...
Y
s
,
class
F
>
constexpr
auto
transform
(
integral_const_array
<
T
,
X
s
...
>
,
integral_const_array
<
U
,
Y
s
...
>
,
F
f
)
{
return
integral_const_array
<
T
,
f
(
x
s
,
y
s
)...
>
{};
return
integral_const_array
<
T
,
f
(
X
s
,
Y
s
)...
>
{};
}
template
<
index_int
...
Ns
>
...
...
src/targets/gpu/kernels/include/migraphx/kernels/debug.hpp
View file @
a33d6fa2
#ifndef MIGRAPHX_GUARD_KERNELS_DEBUG_HPP
#define MIGRAPHX_GUARD_KERNELS_DEBUG_HPP
#include <
hip/hip_runtime.h
>
#include <
migraphx/kernels/hip.hpp
>
namespace
migraphx
{
inline
__host__
__device__
void
// Workaround hip's broken abort on device code
#ifdef __HIP_DEVICE_COMPILE__
// NOLINTNEXTLINE
#define MIGRAPHX_HIP_NORETURN
#else
// NOLINTNEXTLINE
#define MIGRAPHX_HIP_NORETURN [[noreturn]]
#endif
// noreturn cannot be used on this function because abort in hip is broken
MIGRAPHX_HIP_NORETURN
inline
__host__
__device__
void
assert_fail
(
const
char
*
assertion
,
const
char
*
file
,
unsigned
int
line
,
const
char
*
function
)
{
printf
(
"%s:%u: %s: assertion '%s' failed.
\n
"
,
file
,
line
,
function
,
assertion
);
...
...
src/targets/gpu/kernels/include/migraphx/kernels/functional.hpp
View file @
a33d6fa2
...
...
@@ -168,6 +168,7 @@ constexpr auto transform_args(F f, Fs... fs)
return
[
=
](
auto
...
xs
)
{
return
transform_args
(
f
)(
xs
...)(
transform_args
(
fs
...));
};
}
// NOLINTNEXTLINE
#define MIGRAPHX_LIFT(...) \
([](auto&&... xs) { return (__VA_ARGS__)(static_cast<decltype(xs)>(xs)...); })
...
...
src/targets/gpu/kernels/include/migraphx/kernels/generic_constant.hpp
0 → 100644
View file @
a33d6fa2
#ifndef MIGRAPHX_GUARD_KERNELS_GENERIC_CONSTANT_HPP
#define MIGRAPHX_GUARD_KERNELS_GENERIC_CONSTANT_HPP
namespace
migraphx
{
template
<
class
F
>
struct
generic_constant
{
static
constexpr
auto
value
=
F
{}();
using
value_type
=
decltype
(
value
);
using
type
=
generic_constant
;
constexpr
operator
value_type
()
const
noexcept
{
return
value
;
}
constexpr
value_type
operator
()()
const
noexcept
{
return
value
;
}
};
template
<
class
F
>
constexpr
generic_constant
<
F
>
make_generic_constant
(
F
)
{
return
{};
}
// NOLINTNEXTLINE
#define MIGRAPHX_MAKE_CONSTANT(x) \
make_generic_constant([] { \
struct fun \
{ \
constexpr auto operator()() const { return x; } \
}; \
return fun{}; \
}())
}
// namespace migraphx
#endif // MIGRAPHX_GUARD_KERNELS_GENERIC_CONSTANT_HPP
src/targets/gpu/kernels/include/migraphx/kernels/hip.hpp
0 → 100644
View file @
a33d6fa2
#ifndef MIGRAPHX_GUARD_KERNELS_HIP_HPP
#define MIGRAPHX_GUARD_KERNELS_HIP_HPP
// Workaround macro redefinition issue with clang tidy
#if defined(__HIP_PLATFORM_HCC__) && defined(MIGRAPHX_USE_CLANG_TIDY)
#undef __HIP_PLATFORM_HCC__ // NOLINT
#endif
#include <hip/hip_runtime.h>
#endif // MIGRAPHX_GUARD_KERNELS_HIP_HPP
src/targets/gpu/kernels/include/migraphx/kernels/index.hpp
100755 → 100644
View file @
a33d6fa2
#ifndef MIGRAPHX_GUARD_KERNELS_INDEX_HPP
#define MIGRAPHX_GUARD_KERNELS_INDEX_HPP
#include <
hip/hip_runtime.h
>
#include <
migraphx/kernels/hip.hpp
>
#include <migraphx/kernels/types.hpp>
namespace
migraphx
{
...
...
@@ -17,7 +17,7 @@ struct index
#ifdef MIGRAPHX_NGLOBAL
return
MIGRAPHX_NGLOBAL
;
#else
return
blockDim
.
x
*
gridDim
.
x
;
return
blockDim
.
x
*
gridDim
.
x
;
// NOLINT
#endif
}
...
...
@@ -26,7 +26,7 @@ struct index
#ifdef MIGRAPHX_NLOCAL
return
MIGRAPHX_NLOCAL
;
#else
return
blockDim
.
x
;
return
blockDim
.
x
;
// NOLINT
#endif
}
...
...
@@ -53,7 +53,7 @@ struct index
inline
__device__
index
make_index
()
{
return
index
{
blockIdx
.
x
*
blockDim
.
x
+
threadIdx
.
x
,
threadIdx
.
x
,
blockIdx
.
x
};
return
index
{
blockIdx
.
x
*
blockDim
.
x
+
threadIdx
.
x
,
threadIdx
.
x
,
blockIdx
.
x
};
// NOLINT
}
}
// namespace migraphx
...
...
src/targets/gpu/kernels/include/migraphx/kernels/integral_constant.hpp
View file @
a33d6fa2
...
...
@@ -5,28 +5,30 @@
namespace
migraphx
{
template
<
class
T
,
T
v
>
template
<
class
T
,
T
V
>
struct
integral_constant
{
static
constexpr
T
value
=
v
;
static
constexpr
T
value
=
V
;
using
value_type
=
T
;
using
type
=
integral_constant
;
constexpr
operator
value_type
()
const
noexcept
{
return
value
;
}
constexpr
value_type
operator
()()
const
noexcept
{
return
value
;
}
};
// NOLINTNEXTLINE
#define MIGRAPHX_INTEGRAL_CONSTANT_BINARY_OP(op) \
template <class T, T
v
, class U, U w> \
constexpr inline integral_constant<decltype(
v
op w), (
v
op w)> operator op( \
integral_constant<T,
v
>, integral_constant<U, w>) noexcept \
template <class T, T
V
, class U, U w> \
constexpr inline integral_constant<decltype(
V
op w), (
V
op w)> operator op( \
integral_constant<T,
V
>, integral_constant<U, w>) noexcept \
{ \
return {}; \
}
// NOLINTNEXTLINE
#define MIGRAPHX_INTEGRAL_CONSTANT_UNARY_OP(op) \
template <class T, T
v
> \
constexpr inline integral_constant<decltype(op
v
), (op
v
)> operator op( \
integral_constant<T,
v
>) noexcept \
template <class T, T
V
> \
constexpr inline integral_constant<decltype(op
V
), (op
V
)> operator op( \
integral_constant<T,
V
>) noexcept \
{ \
return {}; \
}
...
...
@@ -64,8 +66,8 @@ using false_type = bool_constant<false>;
template
<
index_int
N
>
using
index_constant
=
integral_constant
<
index_int
,
N
>
;
template
<
auto
v
>
static
constexpr
auto
_c
=
integral_constant
<
decltype
(
v
),
v
>
{};
template
<
auto
V
>
static
constexpr
auto
_c
=
integral_constant
<
decltype
(
V
),
V
>
{};
// NOLINT
}
// namespace migraphx
#endif // MIGRAPHX_GUARD_KERNELS_INTEGRAL_CONSTANT_HPP
src/targets/gpu/kernels/include/migraphx/kernels/preload.hpp
View file @
a33d6fa2
...
...
@@ -14,9 +14,7 @@ constexpr auto traverse_preload(Shapes... ss)
auto
each
=
[
&
](
auto
x
)
{
constexpr
auto
s
=
decltype
(
x
.
get_shape
()){};
constexpr
auto
size
=
_c
<
s
.
element_space
()
>
;
if
constexpr
(
not
s
.
broadcasted
())
return
f
(
x
,
offset
,
false_type
{});
else
if
constexpr
((
s
.
elements
()
-
size
)
<
64
)
if
constexpr
(
not
s
.
broadcasted
()
or
(
s
.
elements
()
-
size
)
<
64
)
return
f
(
x
,
offset
,
false_type
{});
else
{
...
...
src/targets/gpu/kernels/include/migraphx/kernels/print.hpp
View file @
a33d6fa2
#ifndef MIGRAPHX_GUARD_KERNELS_PRINT_HPP
#define MIGRAPHX_GUARD_KERNELS_PRINT_HPP
#include <
hip/hip_runtime.h
>
#include <
migraphx/kernels/hip.hpp
>
#include <migraphx/kernels/index.hpp>
#include <migraphx/kernels/functional.hpp>
#include <migraphx/kernels/algorithm.hpp>
...
...
src/targets/gpu/kernels/include/migraphx/kernels/roialign.hpp
View file @
a33d6fa2
...
...
@@ -4,7 +4,7 @@
#include <migraphx/kernels/index.hpp>
#include <migraphx/kernels/dfor.hpp>
#include <migraphx/kernels/basic_ops.hpp>
#include <
args
.hpp>
#include <
migraphx/kernels/array
.hpp>
namespace
migraphx
{
...
...
@@ -104,14 +104,24 @@ MIGRAPHX_DEVICE_CONSTEXPR T calc_pooling(const T*& data,
return
op
.
final
(
output_val
,
count
);
}
template
<
class
T
,
class
U
,
class
V
,
class
W
>
__device__
void
ro
i
align
(
const
T
&
x_t
,
const
U
&
rois_t
,
const
V
&
ind_t
,
const
W
&
y_t
)
template
<
class
T
1
,
class
T2
,
class
T3
,
class
T4
>
struct
roalign
_settings
{
const
float
roi_offset
=
ROIS_OFFSET
;
const
bool
is_avg_pooling
=
IS_AVG_POOLING
;
const
int64_t
sampling_ratio
=
SAMPLING_RATIO
;
const
float
spatial_scale
=
SPATIAL_SCALE
;
T1
roi_offset
{};
T2
is_avg_pooling
{};
T3
sampling_ratio
{};
T4
spatial_scale
{};
};
template
<
class
...
Ts
>
constexpr
roalign_settings
<
Ts
...
>
make_roalign_settings
(
Ts
...
xs
)
{
return
{
xs
...};
}
template
<
class
T
,
class
U
,
class
V
,
class
W
,
class
Settings
>
__device__
void
roialign
(
const
T
&
x_t
,
const
U
&
rois_t
,
const
V
&
ind_t
,
const
W
&
y_t
,
Settings
s
)
{
auto
index
=
make_index
();
const
auto
*
x
=
x_t
.
data
();
const
auto
*
rois
=
rois_t
.
data
();
...
...
@@ -146,9 +156,10 @@ __device__ void roialign(const T& x_t, const U& rois_t, const V& ind_t, const W&
const
auto
*
offset_rois
=
rois
+
(
n
*
roi_column_num
);
const
int
batch_ind
=
ind
[
n
];
array
<
float
,
2
>
roi_starts
=
{
offset_rois
[
1
]
*
spatial_scale
,
offset_rois
[
0
]
*
spatial_scale
};
array
<
float
,
2
>
roi_ends
=
{
offset_rois
[
3
]
*
spatial_scale
,
offset_rois
[
2
]
*
spatial_scale
};
array
<
float
,
2
>
roi_starts
=
{
offset_rois
[
1
]
*
s
.
spatial_scale
,
offset_rois
[
0
]
*
s
.
spatial_scale
};
array
<
float
,
2
>
roi_ends
=
{
offset_rois
[
3
]
*
s
.
spatial_scale
,
offset_rois
[
2
]
*
s
.
spatial_scale
};
array
<
float
,
2
>
roi_size
{};
array
<
float
,
2
>
bin_size
{};
...
...
@@ -161,11 +172,11 @@ __device__ void roialign(const T& x_t, const U& rois_t, const V& ind_t, const W&
bin_size
[
ii
]
=
roi_size
[
ii
]
/
out_dims
[
ii
];
bin_grid_size
[
ii
]
=
(
sampling_ratio
>
0
)
?
sampling_ratio
:
std
::
ceil
(
roi_size
[
ii
]
/
out_dims
[
ii
]);
(
s
.
sampling_ratio
>
0
)
?
s
.
sampling_ratio
:
std
::
ceil
(
roi_size
[
ii
]
/
out_dims
[
ii
]);
}
const
auto
*
offset_x
=
x
+
((
batch_ind
*
channel_num
+
c
)
*
in_dims
[
0
]
*
in_dims
[
1
]);
if
constexpr
(
is_avg_pooling
)
if
constexpr
(
s
.
is_avg_pooling
)
{
out_ptr
[
i
]
=
calc_pooling
(
offset_x
,
roi_starts
,
...
...
@@ -173,7 +184,7 @@ __device__ void roialign(const T& x_t, const U& rois_t, const V& ind_t, const W&
{
ph
,
pw
},
bin_grid_size
,
in_dims
,
roi_offset
,
s
.
roi_offset
,
avg_pool
{});
}
else
...
...
@@ -184,7 +195,7 @@ __device__ void roialign(const T& x_t, const U& rois_t, const V& ind_t, const W&
{
ph
,
pw
},
bin_grid_size
,
in_dims
,
roi_offset
,
s
.
roi_offset
,
max_pool
{});
}
}
...
...
src/targets/gpu/kernels/include/migraphx/kernels/types.hpp
View file @
a33d6fa2
#ifndef MIGRAPHX_GUARD_AMDMIGRAPHX_KERNELS_TYPES_HPP
#define MIGRAPHX_GUARD_AMDMIGRAPHX_KERNELS_TYPES_HPP
#include <
hip/hip_runtime.h
>
#include <
migraphx/kernels/hip.hpp
>
namespace
migraphx
{
...
...
src/targets/gpu/kernels/include/migraphx/kernels/vec.hpp
View file @
a33d6fa2
...
...
@@ -13,7 +13,7 @@ constexpr auto vec_size(vec<T, N>)
}
template
<
class
T
>
constexpr
auto
vec_size
(
T
,
...)
constexpr
auto
vec_size
(
T
,
...)
// NOLINT
{
return
index_constant
<
0
>
{};
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment