#include "stdio.h"
int main()
{
int i = 0;
for(; i < 21; i++)
{
printf("%d \n", i);
}
return 0;
}
输出
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
many loop count 21
自动判断是否超出了预期的循环次数。
LLVM是新一代的编译工具,强大的模块化支持,让程序员很方便的介入到编译过程中的各个方面,本篇文章主要利用函数处理阶段来插桩部分代码。
FunctionPass是LLVM在处理函数代码生成时,会调用的Pass模块。本篇文章中直接在LLVM自带的HelloWorldPass里加入我们的代码。
PreservedAnalyses HelloWorldPass::run(Function &F,
FunctionAnalysisManager &AM) {
LoopInfo *LI = &AM.getResult<LoopAnalysis>(F);
errs() << F.getName() << " loopcount:" << LI->getTopLevelLoopsVector().size() << "\n";
Type *intType = Type::getInt32Ty(F.getContext());
std::vector<Type *> printfArgsTypes({Type::getInt8PtrTy(F.getContext())});
FunctionType *printfType = FunctionType::get(intType, printfArgsTypes, true);
auto printfFunc = F.getEntryBlock().getModule()->getOrInsertFunction("printf", printfType);
for(auto &l : LI->getTopLevelLoopsVector())
{
auto pp = l->getLoopPredecessor();
if(pp)
{
IRBuilder<> builderInit(pp->getFirstNonPHI());
auto pLoopCount = builderInit.CreateAlloca(builderInit.getInt32Ty(), nullptr, "loopcount");
builderInit.CreateStore(ConstantInt::get(builderInit.getInt32Ty(), 0), pLoopCount);
auto pB = l->getHeader();
builderInit.SetInsertPoint(pB->getFirstNonPHI());
auto *addL = builderInit.CreateLoad(builderInit.getInt32Ty(), pLoopCount, "loadLoopCount");
auto *one = ConstantInt::get(builderInit.getInt32Ty(), 1);
auto *pRest = builderInit.CreateAdd(addL, one, "inc loopCount");
builderInit.CreateStore(pRest, pLoopCount);
auto pBExit = l->getExitBlock();
if(pBExit != nullptr)
{
builderInit.SetInsertPoint(pBExit->getFirstNonPHI());
auto *addL = builderInit.CreateLoad(builderInit.getInt32Ty(), pLoopCount, "loadLoopCount");
auto *n100W = ConstantInt::get(builderInit.getInt32Ty(), 20);
auto *pCmp = cast<ICmpInst>(builderInit.CreateCmp(CmpInst::Predicate::ICMP_UGE, addL, n100W, "Cmp"));// builderInit.CreateCmp();
//auto pAssert = BasicBlock::Create(pBExit->getContext(), "assert");
Instruction *Brnch =
SplitBlockAndInsertIfThen(pCmp, pCmp->getNextNode(), false);
builderInit.SetInsertPoint(Brnch);
Value *puts_params[] = {
builderInit.CreateGlobalStringPtr("many loop count %d \n", "loopttip"),
addL
};
builderInit.CreateCall(printfFunc, puts_params, "printlog");
// auto pIfThen = SplitBlockAndInsertIfThen(pCmp, pBExit->getFirstNonPHI(), false, nullptr, (DominatorTree*)nullptr, nullptr, pAssert);
// builderInit.Insert(pIfThen, "ifthen");
//pBExit->getModule()->getOrInsertFunction()
//builderInit.CreateSelect(pCmp, )
}
}
}
return PreservedAnalyses::none();
}
生成的IR对比
; ModuleID = 'test.c'
source_filename = "test.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"
@.str = private unnamed_addr constant [5 x i8] c"%d \0A\00", align 1
@loopttip = private unnamed_addr constant [21 x i8] c"many loop count %d \0A\00", align 1
; Function Attrs: nofree nounwind uwtable
define dso_local i32 @main() local_unnamed_addr #0 {
%1 = alloca i32, align 4
store i32 0, i32* %1, align 4
%2 = load i32, i32* %1, align 4
br label %3
3: ; preds = %0, %3
%4 = phi i32 [ %2, %0 ], [ %6, %3 ]
%5 = phi i32 [ 0, %0 ], [ %8, %3 ]
%6 = add i32 %4, 1
%7 = call i32 (i8*, ...) @printf(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([5 x i8], [5 x i8]* @.str, i64 0, i64 0), i32 noundef %5)
%8 = add nuw nsw i32 %5, 1
%9 = icmp eq i32 %8, 21
br i1 %9, label %10, label %3, !llvm.loop !3
10: ; preds = %3
store i32 %6, i32* %1, align 4
%11 = load i32, i32* %1, align 4
%12 = icmp ugt i32 %11, 19
br i1 %12, label %13, label %15
13: ; preds = %10
%14 = call i32 (i8*, ...) @printf(i8* nonnull dereferenceable(1) getelementptr inbounds ([21 x i8], [21 x i8]* @loopttip, i64 0, i64 0), i32 %11)
br label %15
15: ; preds = %10, %13
ret i32 0
}
; Function Attrs: nofree nounwind
declare dso_local noundef i32 @printf(i8* nocapture noundef readonly, ...) local_unnamed_addr #1
attributes #0 = { nofree nounwind uwtable "frame-pointer"="none" "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" }
attributes #1 = { nofree nounwind "frame-pointer"="none" "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}
!llvm.ident = !{!2}
!0 = !{i32 1, !"wchar_size", i32 4}
!1 = !{i32 7, !"uwtable", i32 2}
!2 = !{!"clang version 15.0.0 (https://github.com/llvm/llvm-project.git a4d2943bf6b350ea62745ab25c7dcc2f1d17a470)"}
!3 = distinct !{!3, !4, !5}
!4 = !{!"llvm.loop.mustprogress"}
!5 = !{!"llvm.loop.unroll.disable"}
; ModuleID = '../llvm-test/test.ll.out'
source_filename = "test.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"
@.str = private unnamed_addr constant [5 x i8] c"%d \0A\00", align 1
@loopttip = private unnamed_addr constant [21 x i8] c"many loop count %d \0A\00", align 1
@loopttip.1 = private unnamed_addr constant [21 x i8] c"many loop count %d \0A\00", align 1
; Function Attrs: nofree nounwind uwtable
define dso_local i32 @main() local_unnamed_addr #0 {
%loopcount = alloca i32, align 4
store i32 0, i32* %loopcount, align 4
%1 = alloca i32, align 4
store i32 0, i32* %1, align 4
%2 = load i32, i32* %1, align 4
br label %3
3: ; preds = %3, %0
%4 = phi i32 [ %2, %0 ], [ %6, %3 ]
%5 = phi i32 [ 0, %0 ], [ %8, %3 ]
%loadLoopCount = load i32, i32* %loopcount, align 4;这里自增循环次数
%"inc loopCount" = add i32 %loadLoopCount, 1
store i32 %"inc loopCount", i32* %loopcount, align 4
%6 = add i32 %4, 1
%7 = call i32 (i8*, ...) @printf(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([5 x i8], [5 x i8]* @.str, i64 0, i64 0), i32 noundef %5)
%8 = add nuw nsw i32 %5, 1
%9 = icmp eq i32 %8, 21
br i1 %9, label %10, label %3, !llvm.loop !3
10: ; preds = %3
%loadLoopCount1 = load i32, i32* %loopcount, align 4
%Cmp = icmp uge i32 %loadLoopCount1, 20 ;这里判断循环次数
br i1 %Cmp, label %11, label %12
11: ; preds = %10
%printlog = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([21 x i8], [21 x i8]* @loopttip.1, i32 0, i32 0), i32 %loadLoopCount1)
br label %12
12: ; preds = %10, %11
store i32 %6, i32* %1, align 4
%13 = load i32, i32* %1, align 4
%14 = icmp ugt i32 %13, 19
br i1 %14, label %15, label %17
15: ; preds = %12
%16 = call i32 (i8*, ...) @printf(i8* nonnull dereferenceable(1) getelementptr inbounds ([21 x i8], [21 x i8]* @loopttip, i64 0, i64 0), i32 %13)
br label %17
17: ; preds = %15, %12
ret i32 0
}
; Function Attrs: nofree nounwind
declare dso_local noundef i32 @printf(i8* nocapture noundef readonly, ...) local_unnamed_addr #1
attributes #0 = { nofree nounwind uwtable "frame-pointer"="none" "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" }
attributes #1 = { nofree nounwind "frame-pointer"="none" "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}
!llvm.ident = !{!2}
!0 = !{i32 1, !"wchar_size", i32 4}
!1 = !{i32 7, !"uwtable", i32 2}
!2 = !{!"clang version 15.0.0 (https://github.com/llvm/llvm-project.git a4d2943bf6b350ea62745ab25c7dcc2f1d17a470)"}
!3 = distinct !{!3, !4, !5}
!4 = !{!"llvm.loop.mustprogress"}
!5 = !{!"llvm.loop.unroll.disable"}
//clang/lib/CodeGen/BackendUtil.cpp
void EmitAssemblyHelper::RunOptimizationPipeline(
BackendAction Action, std::unique_ptr<raw_pwrite_stream> &OS,
std::unique_ptr<llvm::ToolOutputFile> &ThinLinkOS) {
....
PB.registerScalarOptimizerLateEPCallback(
[](FunctionPassManager &FPM, OptimizationLevel Level) {
FPM.addPass(HelloWorldPass());
});
....
}
本篇文章只是初试LLVM做的一个练习课题,仅供参考。