2017-07-17 113 views
0

我得到了一个要求,我有一个c文件,并且我正在生成LLVM IR。从生成的每个指令LLVM IR我计算需要执行多少个周期,现在我的问题是如何追溯到相同的C代码,并显示特定的C代码块(说功能)花了计算数量的周期(我实际上是从生成的LLVM IR代码计算的)。如何将C函数映射到LLVM IR?

我有如下交流代码:

int arithmeticOperations(int x, int y) 
{ 
    int aa, ab, ac, ad; 
    if(x>10) 
    { 
     aa = x+y; 
     ab = x-y; 
     for(x = 1; x <= aa; ++x) 
     { 
      y += x; 
     } 
    } 
    else 
    { 
     ac = x*y; 
     ad = x/y;  
    } 
    return aa * ab * ac * ad; 
} 

void arithmeticOperationsPart2(int x, int y) 
{ 
    int aa, ab, ac, ad; 
    if(x>10) 
    { 
     aa = x+y; 
     ab = x-y; 
    } 
    else 
    { 
     ac = x*y; 
     ad = x/y;  
    } 
} 

int main() 
{ 
    arithmeticOperations(35, 7); 
    arithmeticOperationsPart2(35, 7); 
} 

我使用命令创建LLVM IR:

clang -Os -S -emit-llvm addition.c 

这个输出addition.ll文件,如下:

; ModuleID = 'addition.c' 
source_filename = "addition.c" 
target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128" 
target triple = "x86_64-pc-windows-msvc18.0.0" 

; Function Attrs: norecurse nounwind optsize readnone uwtable 
define i32 @arithmeticOperations(i32, i32) local_unnamed_addr #0 { 
    %3 = icmp sgt i32 %0, 10 
    br i1 %3, label %4, label %7 

; <label>:4:          ; preds = %2 
    %5 = add nsw i32 %1, %0 
    %6 = sub nsw i32 %0, %1 
    br label %10 

; <label>:7:          ; preds = %2 
    %8 = mul nsw i32 %1, %0 
    %9 = sdiv i32 %0, %1 
    br label %10 

; <label>:10:          ; preds = %4, %7 
    %11 = phi i32 [ undef, %7 ], [ %5, %4 ] 
    %12 = phi i32 [ undef, %7 ], [ %6, %4 ] 
    %13 = phi i32 [ %8, %7 ], [ undef, %4 ] 
    %14 = phi i32 [ %9, %7 ], [ undef, %4 ] 
    %15 = mul nsw i32 %12, %11 
    %16 = mul nsw i32 %15, %13 
    %17 = mul nsw i32 %16, %14 
    ret i32 %17 
} 

; Function Attrs: norecurse nounwind optsize readnone uwtable 
define void @arithmeticOperationsPart2(i32, i32) local_unnamed_addr #0 { 
    ret void 
} 

; Function Attrs: norecurse nounwind optsize readnone uwtable 
define i32 @main() local_unnamed_addr #0 { 
    ret i32 0 
} 

attributes #0 = { norecurse nounwind optsize readnone uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } 

!llvm.module.flags = !{!0} 
!llvm.ident = !{!1} 

!0 = !{i32 1, !"PIC Level", i32 2} 
!1 = !{!"clang version 5.0.0 (trunk 302984) (llvm/trunk 302983)"} 

现在我想过滤LLVM代码与它生成的c源代码的对应关系(特定于某个函数)

例如(目前我要筛选的c函数arithmeticOperations):

%3 = icmp sgt i32 %0, 10 
    br i1 %3, label %4, label %7 

; <label>:4:          ; preds = %2 
    %5 = add nsw i32 %1, %0 
    %6 = sub nsw i32 %0, %1 
    br label %10 

; <label>:7:          ; preds = %2 
    %8 = mul nsw i32 %1, %0 
    %9 = sdiv i32 %0, %1 
    br label %10 

; <label>:10:          ; preds = %4, %7 
    %11 = phi i32 [ undef, %7 ], [ %5, %4 ] 
    %12 = phi i32 [ undef, %7 ], [ %6, %4 ] 
    %13 = phi i32 [ %8, %7 ], [ undef, %4 ] 
    %14 = phi i32 [ %9, %7 ], [ undef, %4 ] 
    %15 = mul nsw i32 %12, %11 
    %16 = mul nsw i32 %15, %13 
    %17 = mul nsw i32 %16, %14 
    ret i32 %17 

对应于C代码的以下部分:

int aa, ab, ac, ad; 
    if(x>10) 
    { 
     aa = x+y; 
     ab = x-y; 
     for(x = 1; x <= aa; ++x) 
     { 
      y += x; 
     } 
    } 
    else 
    { 
     ac = x*y; 
     ad = x/y;  
    } 
    return aa * ab * ac * ad; 
+0

为什么不从C或LLVM IR生成汇编列表文件,并自动获得平台架构的指令计数? –

+0

@FrankC:感谢您的回复,我没有完全理解,LLVM IR生成的指令计数对于所有目标都是通用的吗? –

+0

当您从LLVM-IR生成汇编程序列表时,指令集将是平台体系结构特定的。 –

回答

1

你可以告诉铛发出调试信息通过添加-g标志:

clang -Os -S -emit-llvm -g addition.c 

然后你会发现很多关于哪个指令对应于你的ll文件中的哪一行。

例如,arithmeticOperations函数的开始被翻译如下,与线!dgb !<number>结束参照调试信息条目:

; Function Attrs: nounwind optsize readnone uwtable 
define i32 @arithmeticOperations(i32 %x, i32 %y) local_unnamed_addr #0 !dbg !7 { 
entry: 
    tail call void @llvm.dbg.value(metadata i32 %y, i64 0, metadata !12, metadata !18), !dbg !19 
    tail call void @llvm.dbg.value(metadata i32 %x, i64 0, metadata !13, metadata !18), !dbg !20 
    %cmp = icmp sgt i32 %x, 10, !dbg !21 
    br i1 %cmp, label %if.then, label %if.else, !dbg !23 

在接近文件的末尾会有许多“DILocation”条目告诉你其中相应的源代码是:

... 
!19 = !DILocation(line: 1, column: 37, scope: !7) 
!20 = !DILocation(line: 1, column: 30, scope: !7) 
!21 = !DILocation(line: 4, column: 9, scope: !22) 
!22 = distinct !DILexicalBlock(scope: !7, file: !1, line: 4, column: 8) 
!23 = !DILocation(line: 4, column: 8, scope: !7) 

所以,如果你有兴趣这条线的来源:

%cmp = icmp sgt i32 %x, 10, !dbg !21 

你必须寻找调试项21:

!21 = !DILocation(line: 4, column: 9, scope: !22) 

事实上,9号线在这里的,如果是:

9: if(x>10) 

红clangs调试信息是如此精确甚至点到'>'运算符。

+0

需要注意的一点是,优化通过不需要保存调试信息。所以-g应该只与-O0或等价物一起使用。 –

+0

@PaulR:非常感谢您的回答,这对我来说是一个很好的信息,但我正在寻找的是自动化过程。通过这种方法,我必须再次编写一个解析器来将调试信息行匹配到源代码。 –

+0

@PaulR:我做了一些研究,发现了一些解析器,但没有一个解析器是最新的,所以感谢您使用我的方法来操作文件和提取信息。 –