IR -> source pretty printing?

Hi,

I often find myself staring at IR and wanting to look at the C source code it corresponds to. To do so, I look up the debug identifier for the given IR line, scroll to the bottom of the IR file to find the debug identifier, look at the debug location (source and column), and then look at the source file. Too many steps. What would be great is a tool that took two files, i.e., a .c file and a .bc file, and printed out the IR with the corresponding C source right beneath each IR line.

It wouldn’t be too hard for me to write such a tool, but I thought I’d check to see if something already exists before I reinvent the wheel. Is there anything out there?

Thanks,
Steve

To the best of my knowledge, there is no tool that does this. Regards, John Criswell

llvm-dis has a -show-annotations option; not precisely what you're looking
for, but it does print the line numbers inline.

-Eli

Hi Stephen,

A tool within LLVM has been developed to address your issue. Here is a brief description for this tool. Please let me know if you have any questions.

Thanks,

Jin

The existing LLVM compiler only provides incomplete hierarchical information such as loopInfo and regionInfo. It does not provide any information to model the if branches. It does not provide accurate information to understand whether the loop is do-while loop, while loop or do-loop either. This information is essential for compiler analysis, transformations and program understanding. In order to overcome these issues, the SNodeInfo is designed to provide the complete hierarchical information.

An SNode represents a single structured control flow element, e.g. if-then, if-then-else, do-while-loop, while-loop, do-loop, switch. In the extreme case, it represents one basic block. At the top level, SNodes are linked to each other

via the Pred/Succ lists to form a complete CFG for the routine. Each SNode consists of one or more structural sub-elements, or Children. For example, an if-then-else has Children representing the conditional SNode, the then SNode, and the else SNode. Each child is itself at the top of an arbitrarily complex tree of

SNodes.

Given an example in C code and the corresponding LLVM IR, it is hard to figure out the control flow inside the loop from the LLVM IR. After the SNodeInfo is built on top of the LLVM IR, it is easy to understand there is a if-then statement inside a loop.

void foo(int n, int *b)

{

for (int j=0;j<n;j++) {

b[j] = j;

}

}

LLVM IR for the example compiled with -g

; Function Attrs: nounwind uwtable

define void @foo(i32 %n, i32* nocapture %b) #0 !dbg !7 {

entry:

tail call void @llvm.dbg.value(metadata i32 %n, i64 0, metadata !13, metadata !17), !dbg !18

tail call void @llvm.dbg.value(metadata i32* %b, i64 0, metadata !14, metadata !17), !dbg !18

tail call void @llvm.dbg.value(metadata i32 0, i64 0, metadata !15, metadata !17), !dbg !19

%cmp5 = icmp sgt i32 %n, 0, !dbg !20

br i1 %cmp5, label %for.body, label %for.cond.cleanup, !dbg !20

for.cond.cleanup: ; preds = %for.body, %entry

ret void, !dbg !23

for.body: ; preds = %entry, %for.body

%indvars.iv = phi i64 [ %indvars.iv.next, %for.body ], [ 0, %entry ]

%arrayidx = getelementptr inbounds i32, i32* %b, i64 %indvars.iv, !dbg !24

%0 = trunc i64 %indvars.iv to i32, !dbg !24

store i32 %0, i32* %arrayidx, align 4, !dbg !24, !tbaa !26

%indvars.iv.next = add nuw nsw i64 %indvars.iv, 1, !dbg !20

%lftr.wideiv = trunc i64 %indvars.iv.next to i32, !dbg !20

%exitcond = icmp eq i32 %lftr.wideiv, %n, !dbg !20

br i1 %exitcond, label %for.cond.cleanup, label %for.body, !dbg !20

}

Pretty print of SNode Graph

/* B[%entry] */

/* Line 1 */

tail call void @llvm.dbg.value(metadata i32 %n, i64 0, metadata !13, metadata !17), !dbg !18

tail call void @llvm.dbg.value(metadata i32* %b, i64 0, metadata !14, metadata !17), !dbg !18

/* Line 3 */

tail call void @llvm.dbg.value(metadata i32 0, i64 0, metadata !15, metadata !17), !dbg !19

%cmp5 = icmp sgt i32 %n, 0, !dbg !20

br i1 %cmp5, label %for.body, label %for.cond.cleanup, !dbg !20

if (%cmp5) {

do {

/* B[%for.body] */

%indvars.iv = phi i64 [ %indvars.iv.next, %for.body ], [ 0, %entry ]

/* Line 4 */

%arrayidx = getelementptr inbounds i32, i32* %b, i64 %indvars.iv, !dbg !24

%0 = trunc i64 %indvars.iv to i32, !dbg !24

store i32 %0, i32* %arrayidx, align 4, !dbg !24, !tbaa !26

/* Line 3 */

%indvars.iv.next = add nuw nsw i64 %indvars.iv, 1, !dbg !20

%lftr.wideiv = trunc i64 %indvars.iv.next to i32, !dbg !20

%exitcond = icmp eq i32 %lftr.wideiv, %n, !dbg !20

br i1 %exitcond, label %for.cond.cleanup, label %for.body, !dbg !20

} while (%exitcond == false)

}

/* B[%for.cond.cleanup] */

/* Line 6 */

ret void, !dbg !23