我编写了一个shell脚本来自动生成内核代码:
#!/bin/bash
# -----------------------------------------------------------
# Description: Register Blocking CSR kernel auto generation.
# -----------------------------------------------------------
#set -x
KERNEL_SRC=kernel.cpp
file_gen() {
if [ -f ${KERNEL_SRC} ]
then
rm -f ${KERNEL_SRC}
touch ${KERNEL_SRC}
fi
echo "/*">>${KERNEL_SRC}
echo " * Register Blocking CSR implement.">>${KERNEL_SRC}
echo " *">>${KERNEL_SRC}
echo " */">>${KERNEL_SRC}
echo >>${KERNEL_SRC}
echo >>${KERNEL_SRC}
}
emit_func_header() {
R=$1
C=$2
echo "void bcsr_${R}x${C}(const int &bm, const int *b_row_start, const int *b_col_idx," >> ${KERNEL_SRC}
echo "const double *b_values, const double *x, double *y) {" >> ${KERNEL_SRC}
}
emit_func_body() {
local R=${1}
local C=${2}
#echo ${R} ${C}
echo "int i, j;" >>${KERNEL_SRC}
echo "double" >>${KERNEL_SRC}
local m=$(( ${R} - 1 ))
# emit d0, d1, ..., d(r-1), x0, x1, ..., x(c-1)
for i in `seq 0 $m`
do
echo "d${i}, ">>${KERNEL_SRC}
done
local t=$(( ${C} - 1 ))
for i in `seq 0 $t`
do
if [ ${i} -eq ${t} ]
then
echo "x${i};">>${KERNEL_SRC}
else
echo "x${i}, ">>${KERNEL_SRC}
fi
done
# emit outer loop
echo "for (i = 0; i < bm; ++i) {">>${KERNEL_SRC}
# init d0, d1, ..., d(r-1)
for i in `seq 0 $m`
do
echo "d${i} = y[${R} * i + ${i}];">>${KERNEL_SRC}
done
# emit inner loop
echo "for (j = b_row_start[i]; j < b_row_start[i + 1]; ++j, b_values += ${R} * ${C}) {">>${KERNEL_SRC}
# init x0, x1, ..., x(c-1)
for i in `seq 0 $t`
do
echo "x${i} = x[${C} * b_col_idx[j] + ${i}];">>${KERNEL_SRC}
done
# reduce d0, d1, ..., d(r-1)
for i in `seq 0 $t`
do
for j in `seq 0 $m`
do
index=$(( $(( ${j} * ${C} )) + ${i} ))
echo "d${j} += b_values[${index}] * x${i};">>${KERNEL_SRC}
done
done
# write back d0, d1, ..., d(r-1)
for i in `seq 0 $m`
do
echo "y[${R} * i + ${i}] = d${i};">>${KERNEL_SRC}
done
# end inner loop
echo "}">>${KERNEL_SRC}
# end outer loop
echo "}">>${KERNEL_SRC}
}
emit_func_tail() {
echo "}" >> ${KERNEL_SRC}
}
echo "Begin to generate kernel..."
file_gen
for i in `seq 1 12`
do
for j in `seq 1 12`
do
echo ${i} ${j}
emit_func_header ${i} ${j}
emit_func_body ${i} ${j}
emit_func_tail
echo >>${KERNEL_SRC}
done
done
#clang-format -i $KERNEL_SRC
echo "End kernel generating..."
期望: 带有代码的kernel.cpp:
void bcsr_1x1(...) {...}
void bcsr_1x2(...) {...}
...
void bcsr_1x12(...) {...}
void bcsr_2x1(...) {...}
...
void bcsr_2x12(...) {...}
...
void bcsr_12x12(...) {...}
总共144个bcsr子例程,但实际输出包含负数,例如:
bcsr_ - 1x3(...)
由于核心代码是:
for i in `seq 1 12`
do
for j in `seq 1 12`
do
echo ${i} ${j}
emit_func_header ${i} ${j}
emit_func_body ${i} ${j}
emit_func_tail
echo >>${KERNEL_SRC}
done
done
外循环的范围是1到12,内循环的范围是1到12,其预期输出不应包含任何负数。
bash版本: GNU bash版本3.2.57(1)-发行版(x86_64-apple-darwin17) 版权所有(C)2007自由软件基金会,公司。
答案 0 :(得分:0)
这可能是一个范围问题,当我使用其他名称更改循环索引时,称为函数emit_func_body的内部循环包含局部变量i
,
一切正常:
for _i in `seq 1 12`
do
for _j in `seq 1 12`
do
echo ${_i} ${_j}
emit_func_header ${_i} ${_j}
emit_func_body ${_i} ${_j}
emit_func_tail
echo >>${KERNEL_SRC}
done
done
答案 1 :(得分:0)
其中一个函数使用全局变量i
并覆盖主循环中的值。
快速解决方案是将local i
添加到要使用此变量作为局部变量的任何函数,并通常检查所有函数以确保将其使用的所有变量都声明为local
。
如果您不打算将其全部重写为具有更好的范围规则的语言,我还建议您为所有变量添加适当的引号,并检查Shell脚本的重定向规则。特别是,将所有诊断消息打印为标准错误,并在主循环中使用单个重定向。
# Correspondingly refactor file_gen; no need to rm or touch
file_gen >"$KERNEL_SRC"
for i in `seq 1 12`
do
for j in `seq 1 12`
do
echo "$i $j" >&2
emit_func_header "$i" "$j"
emit_func_body "$i" "$j"
emit_func_tail
echo
done
done >>"$KERNEL_SRC"
只要您仍在使用Bash,您可能还想用传统的三参数seq
循环替换for
。