Reputation: 622
I am new to llvm framework and was able to run a basic pass to iterate over instructions in a simple IR function with only entry basic block, but to expand upon that I got an .ll file from clang for a simple c function ( don't mind the correctness of the function I don't care about it for the sake of learning llvm at least for now ).
// fact.c
int fact(int n){
int t =1;
for(int i = 2;i<=n;i++){
t = t*i;
}
return t;
}
I was able to get a fact.ll file for this function, given below, and there are 3 functions in the fact.ll which I hand coded into the IR. foo
, add
and bar
. And I attempt to run a simple pass which will iterate over each BasicBlock and gather it's inst opcodes and simply print them at the end, My issue is the opt tool is able to do it for foo
, add
and bar
functions but not for the fact
function.
Pass file :
#include "llvm/Transforms/Utils/MyHello.h"
#include <string>
using namespace llvm;
PreservedAnalyses MyHelloPass::run(Function &F,FunctionAnalysisManager &AM) {
std::string output;
errs()<<F.getName()<<"\n";
for(Function::iterator BB = F.begin();BB!=F.end();BB++){
for(BasicBlock::iterator I = BB->begin();I!=BB->end();I++){
output+=(I->getOpcodeName());
output+='\n';
}
}
errs()<<output<<'\n';
return PreservedAnalyses::all();
}
fact.ll
; ModuleID = 'fact.c'
source_filename = "fact.c"
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"
; Function Attrs: noinline nounwind optnone uwtable
define dso_local i32 @fact(i32 noundef %n) #0 {
entry:
%n.addr = alloca i32, align 4
%t = alloca i32, align 4
%i = alloca i32, align 4
store i32 %n, i32* %n.addr, align 4
store i32 1, i32* %t, align 4
store i32 2, i32* %i, align 4
br label %for.cond
for.cond: ; preds = %for.inc, %entry
%0 = load i32, i32* %i, align 4
%1 = load i32, i32* %n.addr, align 4
%cmp = icmp sle i32 %0, %1
br i1 %cmp, label %for.body, label %for.end
for.body: ; preds = %for.cond
%2 = load i32, i32* %t, align 4
%3 = load i32, i32* %i, align 4
%mul = mul nsw i32 %2, %3
store i32 %mul, i32* %t, align 4
br label %for.inc
for.inc: ; preds = %for.body
%4 = load i32, i32* %i, align 4
%inc = add nsw i32 %4, 1
store i32 %inc, i32* %i, align 4
br label %for.cond, !llvm.loop !6
for.end: ; preds = %for.cond
%5 = load i32, i32* %t, align 4
ret i32 %5
}
define i32 @foo(){
%a = add i32 2,3
ret i32 %a
}
define i32 @add(i32 %a,i32 %b){
%c = add i32 %a,%b
%d = add i32 %c,%c
%e = sub i32 %c, %d
%f = mul i32 %d, %e
ret i32 %f
}
define void @bar(){
ret void
}
attributes #0 = { noinline nounwind optnone uwtable "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
!llvm.module.flags = !{!0, !1, !2, !3, !4}
!llvm.ident = !{!5}
!0 = !{i32 1, !"wchar_size", i32 4}
!1 = !{i32 7, !"PIC Level", i32 2}
!2 = !{i32 7, !"PIE Level", i32 2}
!3 = !{i32 7, !"uwtable", i32 2}
!4 = !{i32 7, !"frame-pointer", i32 2}
!5 = !{!"AMD\C2\A0\C2\A0-DCLANG_REPOSITORY_STRING=CLANG: clang version 15.0.0 (CLANG: Jenkins CPUPC_Mirror_To_Staging_Merge-Build#892) (based on LLVM Mirror.Version.14.0.0)"}
!6 = distinct !{!6, !7}
!7 = !{!"llvm.loop.mustprogress"}
run command : opt -disable-output fact.ll -passes="myhello"
Ouput :
foo
add
ret
add
add
add
sub
mul
ret
bar
ret
Upvotes: 1
Views: 740
Reputation: 1342
See the optnone
in:
; Function Attrs: noinline nounwind optnone uwtable define dso_local i32 @fact(i32 noundef %n) #0 {
That means that this function is opting out of optimizations, hence your pass will not be run on that function.
You can manually remove the optnone
from the definition of #0
at the bottom (note: the ; Function Attrs: ...
line is merely a comment, changing it has no effect) or you can build your LLVM IR with "clang -O2". You may want to also add -mllvm -disable-llvm-optzns
if you want clang to produce IR that could be optimized but hasn't been run through LLVM passes.
Upvotes: 2