llvm memset memcpy 处理流程
code 框架:
ProcessMemIntrinsic(Module *m) {
//遍历module的function,寻找name为memset、memcpy的function。
ProcessMemset(memset_func);
ProcessMemcpy(memcpy_func);
}
ProcessMemset(memset_func) {
//遍历memset_func的user,对每条memset instruction进行replace
ReplaceMemsetInst(inst);
}
//; Function Attrs: argmemonly nounwind
//declare void @llvm.memset.p0i8.i64(i8* nocapture writeonly, i8, i64, i32, i1)
//call void @llvm.memset.p0i8.i64(i8* nonnull %4, i8 0, i64 256, i32 16, i1 false)
ReplaceMemsetInst(Instruction *inst) {
}
memset分析
memset的定义
memset()函数原型是void *memset(void *buffer, int c, int count) :
buffer:为指针, c:是赋给buffer的值, count:是buffer的长度.
memset的pass中定义初始值必为integer 类型。
memset的pass处理流程
1、遍历module的Function,记录name 为memset、memcpy的Function。
2、遍历Function’s user : memset Instruction,进行替换处理。
如何替换:
1、解析memset的指令参数,memset(void *buffer, int c, int count) ,初始值必为integer 类型。
(2)当buffer指向单个变量:
%2 = alloca iN
%3 = bitcast iN* %2 to i8*
call void @memset(i8* nonnull %4, i8 0, i64 256, i32 16, i1 false)
%2 = alloca iN
Store iN value, iN* %2
(1)当buffer指向的是数组。
memset的一维数组处理
bc情况罗列:
1、全局变量,并且用getelementptr
@zculling.z_buffer = internal unnamed_addr global [256 x [256 x i8]] zeroinitializer
tail call void @llvm.memset.p0i8.i64(i8* getelementptr inbounds ([256 x [256 x i8]], [256 x [256 x i8]]* @zculling.z_buffer, i64 0, i64 0, i64 0), i8 -1, i64 65536, i32 16, i1 false)
2、函数参数 %5
%8 = getelementptr inbounds [256 x i8], [256 x i8]* %5, i64 0, i64 0
call void @llvm.memset.p0i8.i64(i8* %8, i8 0, i64 65536, i32 1, i1 false)
3、 局部变量
%2 = alloca [num x iN]
%4 = bitcast [num x iN]* %2 to i8*
call void @llvm.memset.p0i8.i64(i8* nonnull %4, i8 value, i64 N*num/8 , i32 alignment, i1 false)
Memset 处理:A为array : [num x iN]
数据A初始化:memset(A,value,length,alignment)
label 0: A
%2 = alloca [num x iN]
br label meminst
meminst:
%phi_inst = phi i32 [0, %0], [%add_inst, %meminst]
%add_inst = add i32 %phi_inst , 1
%sext_inst = sext i32 phi_inst to i64
%A.addr = getelementptr [num x iN], [num x iN]* A, i64 0, i64 %sext_inst
Store iN value, iN* A.addr
%icmp_inst = icmp eq i32 %phi_inst, num
br i1 %icmp_inst, label %2, label %meminst
memset的多维数组处理
C代码:
int bb[20][2];
memset(bb,1,sizeof(bb));
clang.bc:
%1 = alloca [20 x [2 x i32]], align 16
%2 = bitcast [20 x [2 x i32]]* %1 to i8*
call void @llvm.memset (i8* nonnull %2, i8 1, i64 160, i32 16, i1 false)
Vivado:针对多级array处理
a.g.1.bc:
利用memset对变量进行两次赋值:
生成的bc:
memcpy分析
自己写得小例子
int main()
{
int bb[20][2][10];
memset(bb,1,sizeof(bb));
int result = 0;
for (int i = 0; i< 7;i++) {
bb[i][0][2]=bb[i][1][1]*bb[i][0][0]+i;
bb[i][1][2]=bb[i][0][1]*2;
printf("bb: %d\n",bb[i][0][1]);
result += bb[i][1][0]+bb[i][0][0];
}
int aa[20][2][10];
memset(aa,2,sizeof(aa));
memcpy(aa,bb,200*sizeof(int));
for (int ii = 0; ii< 10;ii++) {
aa[ii][0][2]=aa[ii][1][1]*aa[ii][0][0]+ii;
aa[ii][1][2]=aa[ii][0][1]*2;
printf("aa: %d\n",aa[ii][0][2]);
result += aa[ii][1][2]+aa[ii][0][0];
}
return 0;
}
; Function Attrs: argmemonly nounwind
declare void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture writeonly, i8* nocapture readonly, i64, i32, i1) #1
clang O1生成的bc
vivado生成的bc:
memcpy one array
char aa[10];
memset(aa,'a',sizeof(aa));
for (int i = 0; i < 10; i++) {
aa[i]=aa[i]+4;
printf("aa = %c\n",aa[i]);
aa[9-i]=aa[i];
}
char bb[10];
memcpy(&bb[0], &aa[0], sizeof(bb));
for (int i = 0; i < 10; i++) {
bb[9-i]=bb[i];
printf("bb[%d]=%c\n",i,bb[i]);
}