Hexagon LLVM编译架构介绍(18)
5 编码实践
5.1 概述
本章介绍了为 LLVM 编译器用户推荐的编码实践。
这些做法通常会导致编译器生成更优化的代码。
本章涵盖以下主题:
- 使用 int 类型作为循环计数器
- 将函数参数标记为限制(如果可能)
- 不要按值传递或返回结构
- 避免使用内联汇编
5.2 使用 int 类型作为循环计数器
强烈建议对循环计数器使用 int 类型,这会导致编译器生成更高效的代码。 如果代码使用非 int 类型,则编译器必须插入零和符号扩展以遵守 C 规则。 例如,不推荐使用以下代码:
extern int A[30], B[30];
for (short int ctr = 0; ctr < 30; ++ctr) {
A[ctr] = B[ctr] + 55;
}
请改用此代码:
extern int A[30], B[30];
for (int ctr = 0; ctr < 30; ++ctr) {
A[ctr] = B[ctr] + 55;
}
5.3 将函数参数标记为限制(如果可能)
LLVM 支持函数参数的限制关键字。 在作为函数参数传入的指针上使用限制指示编译器该指针将专门用于取消引用它指向的地址。 这允许编译器对内存访问启用更积极的优化。
笔记
使用restrict 关键字时,必须确保对该函数进行的所有调用都满足restrict 条件。 如果参数被错误地标记为限制,编译器可能会生成不正确的代码。
5.4 不要按值传递或返回结构体
强烈建议通过引用而不是通过值将结构传递给(和返回)函数。
如果将结构按值传递给函数,则编译器必须生成代码,以便在应用程序运行时复制该结构。 这可能非常低效,并且会降低编译代码的性能。 因此,建议通过指针传递结构。
例如,以下代码效率低下:
struct S {
int z;
int y[50];
char *x;
long int w[40];
};
int bar(struct S arg1) {
...
}
int baz() {
struct S;
... populate elements of S ...
bar(S);
}
虽然此代码效率更高:
struct S {
int z;
int y[50];
char *x;
long int w[40];
};
int bar(struct *S arg1) {
/* Access z here using ‘arg1->z’ (instead of ‘arg1.z’) */
...
}
int baz() {
struct S;
... populate elements of S ...
bar(&S);
}
或者,在 C++ 中,可以通过使用引用参数来简化高效代码:
struct S {
int z;
int y[50];
char *x;
long int w[40];
};
int bar(struct &S arg1) {
...
}
int baz() {
struct S;
... populate elements of S ...
bar(S);
}
5.5 避免使用内联汇编
强烈建议不要在 C 文件中使用内联汇编片段,原因有两个:
- 内联汇编片段极难正确编写。 例如,省略输入、输出或 clobber 参数经常会导致代码不正确。 由此产生的故障极难调试。
- 内联汇编不能跨处理器版本移植。 如果您需要发出特定的汇编指令,建议使用内部编译器而不是内联汇编。
内部函数很容易插入到 C 文件中,并且可以跨处理器版本移植。 如果内在函数不足,那么您应该添加一个用汇编编写的包含所需功能的新函数。 应从 C 代码调用汇编函数。