除getelementptr外,LLVM常量表达式的生成场景与技术问询
LLVM常量表达式的非getelementptr生成场景
LLVM具备常量表达式的概念,这类表达式可对常量操作数执行算术、逻辑等各类运算,语法与指令中同类运算类似但不完全相同,例如会将操作数用()包裹。
你可能会认为它们用于处理C源码中的普通常量表达式(如1 + 2),但实际并非如此——这类简单常量会被编译器直接求值,不会生成LLVM常量表达式。LLVM常量表达式的核心用途,是处理仅在链接或加载时才确定为常量的值,比如常见的数组指针偏移示例:
int a[100]; int *b = a + 30;
编译后生成的LLVM IR会使用getelementptr常量表达式:
@a = dso_local global [100 x i32] zeroinitializer, align 16 @b = dso_local global ptr getelementptr (i8, ptr @a, i64 120), align 8
回到核心问题:存在特定的源码构造,能让Clang生成除getelementptr之外的LLVM常量表达式,以下是几个典型场景:
对全局变量地址执行位运算
int global_var; int *ptr = (int*)((char*)&global_var | 0x8);对应的LLVM IR会生成包含
or常量表达式的全局初始化代码:@global_var = dso_local global i32 0, align 4 @ptr = dso_local global ptr or (ptr @global_var, ptr inttoptr (i64 8 to ptr)), align 8基于全局变量地址的算术运算
int arr[10]; int *offset_ptr = &arr[0] + (0x10 >> 2);生成的LLVM IR会使用
add常量表达式:@arr = dso_local global [10 x i32] zeroinitializer, align 16 @offset_ptr = dso_local global ptr add (ptr @arr, ptr inttoptr (i64 4 to ptr)), align 8对全局变量地址做对齐操作(逻辑运算)
int buf; int *aligned_ptr = (int*)((char*)&buf & ~0xF);对应的LLVM IR会包含
and常量表达式:@buf = dso_local global i32 0, align 4 @aligned_ptr = dso_local global ptr and (ptr @buf, ptr inttoptr (i64 -16 to ptr)), align 8
这些场景的共性是:当源码中对全局变量的地址进行编译期无法直接求值(但链接/加载时会成为常量)的运算时,Clang会生成这类非getelementptr的LLVM常量表达式——因为运算结果要到链接阶段才能确定具体内存地址,无法在编译期直接算出数值常量,所以需要用常量表达式保留运算逻辑。
内容的提问来源于stack exchange,提问作者rwallace
相关产品推荐
相关产品推荐

