LLVM -Learn-Work3
@2022-05-03 18:54:36
@sizaif
Work3:插入一个函数并调用。函数用于检查加法结果,如果大于 100,则取
余 100。此函数会修改加法结果。(函数操作)
//main.c
#define _GNU_SOURCE
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
int main() {
puts("plz input two numbers");
size_t bufsize = 100;
char* buf = malloc(bufsize);
getline(&buf, &bufsize, stdin);
double f1 = atof(buf);
getline(&buf, &bufsize, stdin);
double f2 = atof(buf);
printf("%.2f + %.2f = %.2f \n", f1, f2, f1+f2);
free(buf);
return 0;
}
一) 思路
第一种一种思路:
-
创建一个全局变量
fdd_res
, -
添加
store
指令, 将fadd
指令的结果存储到全局变量中, -
构造函数,读取全局变量的值,如果大于100,则对100取余,否则什么都不做
-
修改
printf
函数第三个参数为全局变量fadd_res
第二种一种思路:
- 构造函数
work_fn
,其函数传参(fadd
)的结果值 - 函数拿到其值,做取余操作,并返回结果
- 主函数存储
work_fn
返回结果,并修改printf函数的参数。
二) 思路一执行
2.1) 读取IR
LLVMContext context;
IRBuilder<> builder(context);
std::unique_ptr<Module> M;
std::unique_ptr<MIRParser> MIR;
SMDiagnostic Err;
/**
* #include "llvm/IRReader/IRReader.h"
* 2022-04-26 03:04:32
* TODO:
* from IR file get Moudle class
* */
M = parseIRFile(StringRef(argv[1]),Err,context);
if(M){
std::cout<<"debug: M is not null"<<std::endl;
// M->print(llvm::outs(),nullptr);
}
else{
std::cout<<"M is null"<<std::endl;
Err.print(argv[0],errs());
}
2.2) 找到fadd
指令与fadd
后一个指令
/**
* 2022-04-26 03:25:52
* TODO:
* 获取main函数
* */
auto main_fn = M->getFunction(StringRef("main"));
/**
* 2022-04-28 02:14:46
* TODO:
* 找到fadd指令,与fadd的后一个指令
* */
Instruction *in_fadd,*in_prt;
for (inst_iterator I = inst_begin(*main_fn), E = inst_end(*main_fn); I != E; ++I){
if(I->isBinaryOp() && I->getOpcode()==Instruction::FAdd){
// outs() << *I << "\n";
in_fadd = &*I;
in_prt = &*(I.operator++());
}
}
2.3) 创建全局变量,添加必要的指令
/**
* 2022-04-28 02:42:32
* TODO:
* %20 = load double, double* %5, align 8
* %21 = fadd double %19, %20
* 1. 创建全局变量fadd_res
* 2. 存入常量100
* 3. 将ADD结果存入内存中
* */
auto f32 = builder.getDoubleTy();
// 创建初始值0与100
auto const_100 = ConstantFP::get(f32,double(100));
auto const_0 = ConstantFP::get(f32,double(0));
auto in_alloc02 = new GlobalVariable(*M,
f32,
false,
GlobalValue::PrivateLinkage,
const_0,
"fadd_res");
// 设置对齐方式
in_alloc02->setAlignment(MaybeAlign(8));
// 插入基本指令,将FADD结果,存到fadd_res中
builder.SetInsertPoint(in_prt);
auto in_alloc01 = builder.CreateAlloca(f32,0,"ina1");
auto in_store01 = builder.CreateStore(const_100,in_alloc01);
auto in_store02 = builder.CreateStore(in_fadd,in_alloc02);
2.4) 构造函数读取结果进行修改
/**
* 2022-05-03 16:33:58
* TODO:
* 新建一个函数:
* void work03_fn(){
* if(fdd_res > 100)
* fdd_res = fdd_res %100;
* }
* */
// 创建函数
auto fn_prototype = FunctionType::get(builder.getVoidTy(), true);
auto work03_fn = Function::Create(fn_prototype,
Function::ExternalLinkage,
"work03_fn",
M.get());
// 创建基本块
auto work03_fn_defaut= BasicBlock::Create(context, "work03_fn_defaut", work03_fn);
auto work03_fn_change = BasicBlock::Create(context, "work03_fn_change", work03_fn);
auto work03_fn_nothing = BasicBlock::Create(context, "work03_fn_nothing", work03_fn);
// 默认基本块 指令操作
builder.SetInsertPoint(work03_fn_defaut);
auto work03_de_load_01 = builder.CreateLoad(f32,in_alloc02);
auto work03_de_fcmp_01 = builder.CreateFCmpUGT(work03_de_load_01,const_100);
auto work03_de_br_01 = builder.CreateCondBr(work03_de_fcmp_01,
work03_fn_change,
work03_fn_nothing);
// 取余 指令操作
builder.SetInsertPoint(work03_fn_change);
auto work03_ch_load_01 = builder.CreateLoad(f32,in_alloc02);
auto work03_ch_frem_01 = builder.CreateFRem(work03_ch_load_01,const_100);
auto work03_ch_store_01 = builder.CreateStore(work03_ch_frem_01,in_alloc02);
builder.CreateRetVoid();
// 第三个基本块什么都不做
builder.SetInsertPoint(work03_fn_nothing);
builder.CreateRetVoid();
2.5) 修改printf参数
/**
* 2022-05-03 18:27:56
* TODO:
* 在调用prtinf 函数之前插入调用函数指令
* 以及读取fadd_res, 修改printf 第三个参数
* */
builder.SetInsertPoint(in_prt);
builder.CreateCall(work03_fn);
auto in_load03 = builder.CreateLoad(f32,in_alloc02);
in_prt->setOperand(3,in_load03);
2.6) Module验证与存到文件
/**
* #include "llvm/IR/Verifier.h"
* 2022-05-02 11:43:34
* TODO:
* 修改完Module后进行验证Module的完整性
* verifyModule(*M,&errs()): true if the module is broken.
* */
if(!llvm::verifyModule(*M,&errs())){
outs()<<"debug: Module verify is ok \n";
M->print(outs(),nullptr);
}
/**
* #include "llvm/Bitcode/BitcodeWriter.h"
* 2022-05-03 12:55:33
* TODO:
* 将修改后的IR 存储到文件中, 执行
* */
std::error_code EC;
llvm::raw_fd_ostream OS("aftermain.bc", EC,llvm::sys::fs::OpenFlags());
llvm::WriteBitcodeToFile(*M,OS,true);
OS.flush();
2.7) 全部源码
/**
* 2022-05-03 16:16:19
* sizaif
* Work3:插入一个函数并调用。函数用于检查加法结果,如果大于 100,则取余 100。此函数会修改加法结果。(函数操作)
* clang++ $(llvm-config --cxxflags --ldflags --system-libs --libs) -o main main.cpp
* ./main main.ll
* lli aftermain.bc
* */
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
#include <llvm/IR/IRBuilder.h>
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/InstIterator.h"
#include "llvm/IR/Instruction.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/InstrTypes.h"
#include "llvm/IR/Verifier.h"
#include "llvm/IRReader/IRReader.h"
#include "llvm/CodeGen/MIRParser/MIRParser.h"
#include "llvm/Support/InitLLVM.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/Support/SourceMgr.h"
#include <llvm/Support/raw_os_ostream.h>
#include "llvm/Bitcode/BitcodeWriter.h"
#include <iostream>
#include <string>
#include <fstream>
#include <cstdio>
using namespace llvm;
int main(int argc,char **argv){
LLVMContext context;
IRBuilder<> builder(context);
std::unique_ptr<Module> M;
std::unique_ptr<MIRParser> MIR;
SMDiagnostic Err;
/**
* #include "llvm/IRReader/IRReader.h"
* 2022-04-26 03:04:32
* TODO:
* from IR file get Moudle class
* */
M = parseIRFile(StringRef(argv[1]),Err,context);
if(M){
std::cout<<"debug: M is not null"<<std::endl;
// M->print(llvm::outs(),nullptr);
}
else{
std::cout<<"M is null"<<std::endl;
Err.print(argv[0],errs());
}
/**
* 2022-04-26 03:25:52
* TODO:
* 获取main函数
* */
auto main_fn = M->getFunction(StringRef("main"));
/**
* 2022-04-28 02:14:46
* TODO:
* 找到fadd指令,与fadd的后一个指令
* */
Instruction *in_fadd,*in_prt;
for (inst_iterator I = inst_begin(*main_fn), E = inst_end(*main_fn); I != E; ++I){
if(I->isBinaryOp() && I->getOpcode()==Instruction::FAdd){
// outs() << *I << "\n";
in_fadd = &*I;
in_prt = &*(I.operator++());
}
}
/**
* 2022-04-28 02:42:32
* TODO:
* %20 = load double, double* %5, align 8
* %21 = fadd double %19, %20
* 1. 创建全局变量fadd_res
* 2. 存入常量100
* 3. 将ADD结果存入内存中
* */
auto f32 = builder.getDoubleTy();
auto const_100 = ConstantFP::get(f32,double(100));
// 创建初始值0
auto const_0 = ConstantFP::get(f32,double(0));
auto in_alloc02 = new GlobalVariable(*M,f32,false,GlobalValue::PrivateLinkage,const_0,"fadd_res");
// 设置对齐方式
in_alloc02->setAlignment(MaybeAlign(8));
// 插入基本指令,将FADD结果,存到fadd_res中
builder.SetInsertPoint(in_prt);
auto in_alloc01 = builder.CreateAlloca(f32,0,"ina1");
auto in_store01 = builder.CreateStore(const_100,in_alloc01);
auto in_store02 = builder.CreateStore(in_fadd,in_alloc02);
/**
* 2022-05-03 16:33:58
* TODO:
* 新建一个函数:
* void work03_fn(){
* if(fdd_res > 100)
* fdd_res = fdd_res %100;
* }
* */
// 创建函数
auto fn_prototype = FunctionType::get(builder.getVoidTy(), true);
auto work03_fn = Function::Create(fn_prototype,Function::ExternalLinkage,"work03_fn",M.get());
// 创建基本块
auto work03_fn_defaut= BasicBlock::Create(context, "work03_fn_defaut", work03_fn);
auto work03_fn_change = BasicBlock::Create(context, "work03_fn_change", work03_fn);
auto work03_fn_nothing = BasicBlock::Create(context, "work03_fn_nothing", work03_fn);
// 默认基本块 指令操作
builder.SetInsertPoint(work03_fn_defaut);
auto work03_de_load_01 = builder.CreateLoad(f32,in_alloc02);
auto work03_de_fcmp_01 = builder.CreateFCmpUGT(work03_de_load_01,const_100);
auto work03_de_br_01 = builder.CreateCondBr(work03_de_fcmp_01,work03_fn_change,work03_fn_nothing);
// 取余 指令操作
builder.SetInsertPoint(work03_fn_change);
auto work03_ch_load_01 = builder.CreateLoad(f32,in_alloc02);
auto work03_ch_frem_01 = builder.CreateFRem(work03_ch_load_01,const_100);
auto work03_ch_store_01 = builder.CreateStore(work03_ch_frem_01,in_alloc02);
builder.CreateRetVoid();
// 第三个基本块什么都不做
builder.SetInsertPoint(work03_fn_nothing);
builder.CreateRetVoid();
/**
* 2022-05-03 18:27:56
* TODO:
* 在调用prtinf 函数之前插入调用函数指令
* 以及读取fadd_res, 修改printf 第三个参数
* */
builder.SetInsertPoint(in_prt);
builder.CreateCall(work03_fn);
auto in_load03 = builder.CreateLoad(f32,in_alloc02);
in_prt->setOperand(3,in_load03);
// M->print(outs(),nullptr);
/**
* #include "llvm/IR/Verifier.h"
* 2022-05-02 11:43:34
* TODO:
* 修改完Module后进行验证Module的完整性
* verifyModule(*M,&errs()): true if the module is broken.
* */
if(!llvm::verifyModule(*M,&errs())){
outs()<<"debug: Module verify is ok \n";
// M->print(outs(),nullptr);
}
/**
* #include "llvm/Bitcode/BitcodeWriter.h"
* 2022-05-03 12:55:33
* TODO:
* 将修改后的IR 存储到文件中, 执行
* */
std::error_code EC;
llvm::raw_fd_ostream OS("aftermain.bc", EC,llvm::sys::fs::OpenFlags());
llvm::WriteBitcodeToFile(*M,OS,true);
OS.flush();
return 0;
}
2.8) 效果
修改后IR如下:
./main main.ll
debug: M is not null
debug: Module verify is ok
; ModuleID = 'main.ll'
source_filename = "t.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"
%struct._IO_FILE = type { i32, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, %struct._IO_marker*, %struct._IO_FILE*, i32, i32, i64, i16, i8, [1 x i8], i8*, i64, %struct._IO_codecvt*, %struct._IO_wide_data*, %struct._IO_FILE*, i8*, i64, i32, [20 x i8] }
%struct._IO_marker = type opaque
%struct._IO_codecvt = type opaque
%struct._IO_wide_data = type opaque
@.str = private unnamed_addr constant [22 x i8] c"plz input two numbers\00", align 1
@stdin = external dso_local global %struct._IO_FILE*, align 8
@.str.1 = private unnamed_addr constant [21 x i8] c"%.2f + %.2f = %.2f \0A\00", align 1
@fadd_res = private global double 0.000000e+00, align 8
; Function Attrs: noinline nounwind optnone uwtable
define dso_local i32 @main() #0 {
%1 = alloca i32, align 4
%2 = alloca i64, align 8
%3 = alloca i8*, align 8
%4 = alloca double, align 8
%5 = alloca double, align 8
store i32 0, i32* %1, align 4
%6 = call i32 @puts(i8* noundef getelementptr inbounds ([22 x i8], [22 x i8]* @.str, i64 0, i64 0))
store i64 100, i64* %2, align 8
%7 = load i64, i64* %2, align 8
%8 = call noalias i8* @malloc(i64 noundef %7) #4
store i8* %8, i8** %3, align 8
%9 = load %struct._IO_FILE*, %struct._IO_FILE** @stdin, align 8
%10 = call i64 @getline(i8** noundef %3, i64* noundef %2, %struct._IO_FILE* noundef %9)
%11 = load i8*, i8** %3, align 8
%12 = call double @atof(i8* noundef %11) #5
store double %12, double* %4, align 8
%13 = load %struct._IO_FILE*, %struct._IO_FILE** @stdin, align 8
%14 = call i64 @getline(i8** noundef %3, i64* noundef %2, %struct._IO_FILE* noundef %13)
%15 = load i8*, i8** %3, align 8
%16 = call double @atof(i8* noundef %15) #5
store double %16, double* %5, align 8
%17 = load double, double* %4, align 8
%18 = load double, double* %5, align 8
%19 = load double, double* %4, align 8
%20 = load double, double* %5, align 8
%21 = fadd double %19, %20
%ina1 = alloca double, align 8
store double 1.000000e+02, double* %ina1, align 8
store double %21, double* @fadd_res, align 8
call void (...) @work03_fn()
%22 = load double, double* @fadd_res, align 8
%23 = call i32 (i8*, ...) @printf(i8* noundef getelementptr inbounds ([21 x i8], [21 x i8]* @.str.1, i64 0, i64 0), double noundef %17, double noundef %18, double noundef %22)
%24 = load i8*, i8** %3, align 8
call void @free(i8* noundef %24) #4
ret i32 0
}
declare dso_local i32 @puts(i8* noundef) #1
; Function Attrs: nounwind
declare dso_local noalias i8* @malloc(i64 noundef) #2
declare dso_local i64 @getline(i8** noundef, i64* noundef, %struct._IO_FILE* noundef) #1
; Function Attrs: nounwind readonly willreturn
declare dso_local double @atof(i8* noundef) #3
declare dso_local i32 @printf(i8* noundef, ...) #1
; Function Attrs: nounwind
declare dso_local void @free(i8* noundef) #2
define void @work03_fn(...) {
work03_fn_defaut:
%0 = load double, double* @fadd_res, align 8
%1 = fcmp ugt double %0, 1.000000e+02
br i1 %1, label %work03_fn_change, label %work03_fn_nothing
work03_fn_change: ; preds = %work03_fn_defaut
%2 = load double, double* @fadd_res, align 8
%3 = frem double %2, 1.000000e+02
store double %3, double* @fadd_res, align 8
ret void
work03_fn_nothing: ; preds = %work03_fn_defaut
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" }
attributes #1 = { "frame-pointer"="all" "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 #2 = { nounwind "frame-pointer"="all" "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 #3 = { nounwind readonly willreturn "frame-pointer"="all" "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 #4 = { nounwind }
attributes #5 = { nounwind readonly willreturn }
!llvm.module.flags = !{!0, !1, !2}
!llvm.ident = !{!3}
!0 = !{i32 1, !"wchar_size", i32 4}
!1 = !{i32 7, !"uwtable", i32 1}
!2 = !{i32 7, !"frame-pointer", i32 2}
!3 = !{!"clang version 14.0.0"}
三) 思路二执行
2.1) -2.2) 同上
添加相关必要指令
/**
* 2022-04-28 02:42:32
* TODO:
* 1. 创建常量100
* 2. 插入基本指令,存储最终的修改fadd结果
* */
auto f32 = builder.getDoubleTy();
auto const_100 = ConstantFP::get(f32,double(100));
// 插入基本指令,存储最终的修改fadd结果
builder.SetInsertPoint(in_prt);
auto in_alloc02 = builder.CreateAlloca(f32,0,"ia01");
2.3) 构造函数
/**
* 2022-05-03 22:05:01
* TODO:
* 新建一个函数:
* double work03_fn(double fdd_res){
* if(fdd_res > 100)
* return fdd_res = fdd_res %100;
* }else{
* return fdd_res;
* }
* */
// 创建函数的参数
std::vector<Type*>parms;
parms.push_back(f32);
ArrayRef<Type*>fn_parm(parms);
// 创建函数
auto fn_prototype = FunctionType::get(builder.getDoubleTy(),fn_parm,true);
auto work03_fn = Function::Create(fn_prototype,Function::ExternalLinkage,"work03_fn",M.get());
// 创建传的实参
std::vector<Value*>args;
args.push_back(in_fadd);
ArrayRef<Value*> argRef(args);
// 创建基本块
auto work03_fn_defaut= BasicBlock::Create(context, "work03_fn_defaut", work03_fn);
auto work03_fn_change = BasicBlock::Create(context, "work03_fn_change", work03_fn);
auto work03_fn_nothing = BasicBlock::Create(context, "work03_fn_nothing", work03_fn);
// 默认基本块 指令操作
builder.SetInsertPoint(work03_fn_defaut);
// 拿到函数参数
auto work03_de_alloc_01 = builder.CreateAlloca(f32,0,"ial02");
Function::arg_iterator argsit = work03_fn->arg_begin();
auto work03_de_p1 = argsit;
auto work03_de_store_01 = builder.CreateStore(work03_de_p1,work03_de_alloc_01);
// 比较大小
auto work03_de_load_01 = builder.CreateLoad(f32,work03_de_alloc_01);
auto work03_de_fcmp_01 = builder.CreateFCmpUGT(work03_de_load_01,const_100);
auto work03_de_br_01 = builder.CreateCondBr(work03_de_fcmp_01,work03_fn_change,work03_fn_nothing);
// 取余 指令操作
builder.SetInsertPoint(work03_fn_change);
auto work03_ch_load_01 = builder.CreateLoad(f32,work03_de_alloc_01);
auto work03_ch_frem_01 = builder.CreateFRem(work03_ch_load_01,const_100);
auto work03_ch_store_01 = builder.CreateStore(work03_ch_frem_01,work03_de_alloc_01);
auto work03_ch_load02 = builder.CreateLoad(f32,work03_de_alloc_01);
builder.CreateRet(work03_ch_load02);
// 第三个基本块 不做修改,返回从参数种拿到的值
builder.SetInsertPoint(work03_fn_nothing);
auto work03_no_load01 = builder.CreateLoad(f32,work03_de_alloc_01);
builder.CreateRet(work03_no_load01);
2.4) 修改printf函数
/**
* 2022-05-03 18:27:56
* TODO:
* 在调用prtinf 函数之前插入调用函数指令
* 以及读取fadd_res, 修改printf 第三个参数
* */
builder.SetInsertPoint(in_prt);
auto in_call_01 = builder.CreateCall(work03_fn,argRef);
auto in_store03 = builder.CreateStore(in_call_01,in_alloc02);
auto in_load03 = builder.CreateLoad(f32,in_alloc02);
in_prt->setOperand(3,in_load03);
2.5)-2.6) 验证与写入
/**
* #include "llvm/IR/Verifier.h"
* 2022-05-02 11:43:34
* TODO:
* 修改完Module后进行验证Module的完整性
* verifyModule(*M,&errs()): true if the module is broken.
* */
if(!llvm::verifyModule(*M,&errs())){
outs()<<"debug: Module verify is ok \n";
M->print(outs(),nullptr);
}
/**
* #include "llvm/Bitcode/BitcodeWriter.h"
* 2022-05-03 12:55:33
* TODO:
* 将修改后的IR 存储到文件中, 执行
* */
std::error_code EC;
llvm::raw_fd_ostream OS("aftermain2.bc", EC,llvm::sys::fs::OpenFlags());
llvm::WriteBitcodeToFile(*M,OS,true);
OS.flush();
2.7) 全部源码
/**
* 2022-05-03 16:16:19
* sizaif
* Work3:插入一个函数并调用。函数用于检查加法结果,如果大于 100,则取余 100。此函数会修改加法结果。(函数操作)
*
* clang++ $(llvm-config --cxxflags --ldflags --system-libs --libs) -o main2 main2.cpp
* ./main2 main.ll
* lli aftermain2.bc
* */
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
#include <llvm/IR/IRBuilder.h>
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/InstIterator.h"
#include "llvm/IR/Instruction.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/InstrTypes.h"
#include "llvm/IR/Verifier.h"
#include "llvm/IRReader/IRReader.h"
#include "llvm/CodeGen/MIRParser/MIRParser.h"
#include "llvm/Support/InitLLVM.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/Support/SourceMgr.h"
#include <llvm/Support/raw_os_ostream.h>
#include "llvm/Bitcode/BitcodeWriter.h"
#include <iostream>
#include <string>
#include <fstream>
#include <cstdio>
using namespace llvm;
int main(int argc,char **argv){
LLVMContext context;
IRBuilder<> builder(context);
std::unique_ptr<Module> M;
std::unique_ptr<MIRParser> MIR;
SMDiagnostic Err;
/**
* #include "llvm/IRReader/IRReader.h"
* 2022-04-26 03:04:32
* TODO:
* from IR file get Moudle class
* */
M = parseIRFile(StringRef(argv[1]),Err,context);
if(M){
std::cout<<"debug: M is not null"<<std::endl;
// M->print(llvm::outs(),nullptr);
}
else{
std::cout<<"M is null"<<std::endl;
Err.print(argv[0],errs());
}
/**
* 2022-04-26 03:25:52
* TODO:
* 获取main函数
* */
auto main_fn = M->getFunction(StringRef("main"));
/**
* 2022-04-28 02:14:46
* TODO:
* 找到fadd指令,与fadd的后一个指令
* */
Instruction *in_fadd,*in_prt;
for (inst_iterator I = inst_begin(*main_fn), E = inst_end(*main_fn); I != E; ++I){
if(I->isBinaryOp() && I->getOpcode()==Instruction::FAdd){
// outs() << *I << "\n";
in_fadd = &*I;
in_prt = &*(I.operator++());
}
}
/**
* 2022-04-28 02:42:32
* TODO:
* 1. 创建常量100
* 2. 插入基本指令,存储最终的修改fadd结果
* */
auto f32 = builder.getDoubleTy();
auto const_100 = ConstantFP::get(f32,double(100));
// 插入基本指令,存储最终的修改fadd结果
builder.SetInsertPoint(in_prt);
auto in_alloc02 = builder.CreateAlloca(f32,0,"ia01");
/**
* 2022-05-03 22:05:01
* TODO:
* 新建一个函数:
* double work03_fn(double fdd_res){
* if(fdd_res > 100)
* return fdd_res = fdd_res %100;
* }else{
* return fdd_res;
* }
* */
// 创建函数的参数
std::vector<Type*>parms;
parms.push_back(f32);
ArrayRef<Type*>fn_parm(parms);
// 创建函数
auto fn_prototype = FunctionType::get(builder.getDoubleTy(),fn_parm,true);
auto work03_fn = Function::Create(fn_prototype,Function::ExternalLinkage,"work03_fn",M.get());
// 创建传的实参
std::vector<Value*>args;
args.push_back(in_fadd);
ArrayRef<Value*> argRef(args);
// 创建基本块
auto work03_fn_defaut= BasicBlock::Create(context, "work03_fn_defaut", work03_fn);
auto work03_fn_change = BasicBlock::Create(context, "work03_fn_change", work03_fn);
auto work03_fn_nothing = BasicBlock::Create(context, "work03_fn_nothing", work03_fn);
// 默认基本块 指令操作
builder.SetInsertPoint(work03_fn_defaut);
// 拿到函数参数
auto work03_de_alloc_01 = builder.CreateAlloca(f32,0,"ial02");
Function::arg_iterator argsit = work03_fn->arg_begin();
auto work03_de_p1 = argsit;
auto work03_de_store_01 = builder.CreateStore(work03_de_p1,work03_de_alloc_01);
// 比较大小
auto work03_de_load_01 = builder.CreateLoad(f32,work03_de_alloc_01);
auto work03_de_fcmp_01 = builder.CreateFCmpUGT(work03_de_load_01,const_100);
auto work03_de_br_01 = builder.CreateCondBr(work03_de_fcmp_01,work03_fn_change,work03_fn_nothing);
// 取余 指令操作
builder.SetInsertPoint(work03_fn_change);
auto work03_ch_load_01 = builder.CreateLoad(f32,work03_de_alloc_01);
auto work03_ch_frem_01 = builder.CreateFRem(work03_ch_load_01,const_100);
auto work03_ch_store_01 = builder.CreateStore(work03_ch_frem_01,work03_de_alloc_01);
auto work03_ch_load02 = builder.CreateLoad(f32,work03_de_alloc_01);
builder.CreateRet(work03_ch_load02);
// 第三个基本块 不做修改,返回从参数种拿到的值
builder.SetInsertPoint(work03_fn_nothing);
auto work03_no_load01 = builder.CreateLoad(f32,work03_de_alloc_01);
builder.CreateRet(work03_no_load01);
/**
* 2022-05-03 18:27:56
* TODO:
* 在调用prtinf 函数之前插入调用函数指令
* 以及读取fadd_res, 修改printf 第三个参数
* */
builder.SetInsertPoint(in_prt);
auto in_call_01 = builder.CreateCall(work03_fn,argRef);
auto in_store03 = builder.CreateStore(in_call_01,in_alloc02);
auto in_load03 = builder.CreateLoad(f32,in_alloc02);
in_prt->setOperand(3,in_load03);
// M->print(outs(),nullptr);
/**
* #include "llvm/IR/Verifier.h"
* 2022-05-02 11:43:34
* TODO:
* 修改完Module后进行验证Module的完整性
* verifyModule(*M,&errs()): true if the module is broken.
* */
if(!llvm::verifyModule(*M,&errs())){
outs()<<"debug: Module verify is ok \n";
M->print(outs(),nullptr);
}
/**
* #include "llvm/Bitcode/BitcodeWriter.h"
* 2022-05-03 12:55:33
* TODO:
* 将修改后的IR 存储到文件中, 执行
* */
std::error_code EC;
llvm::raw_fd_ostream OS("aftermain2.bc", EC,llvm::sys::fs::OpenFlags());
llvm::WriteBitcodeToFile(*M,OS,true);
OS.flush();
return 0;
}
2.8) 效果
修改后IR代码如下:
; ModuleID = 'main.ll'
source_filename = "t.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"
%struct._IO_FILE = type { i32, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, %struct._IO_marker*, %struct._IO_FILE*, i32, i32, i64, i16, i8, [1 x i8], i8*, i64, %struct._IO_codecvt*, %struct._IO_wide_data*, %struct._IO_FILE*, i8*, i64, i32, [20 x i8] }
%struct._IO_marker = type opaque
%struct._IO_codecvt = type opaque
%struct._IO_wide_data = type opaque
@.str = private unnamed_addr constant [22 x i8] c"plz input two numbers\00", align 1
@stdin = external dso_local global %struct._IO_FILE*, align 8
@.str.1 = private unnamed_addr constant [21 x i8] c"%.2f + %.2f = %.2f \0A\00", align 1
; Function Attrs: noinline nounwind optnone uwtable
define dso_local i32 @main() #0 {
%1 = alloca i32, align 4
%2 = alloca i64, align 8
%3 = alloca i8*, align 8
%4 = alloca double, align 8
%5 = alloca double, align 8
store i32 0, i32* %1, align 4
%6 = call i32 @puts(i8* noundef getelementptr inbounds ([22 x i8], [22 x i8]* @.str, i64 0, i64 0))
store i64 100, i64* %2, align 8
%7 = load i64, i64* %2, align 8
%8 = call noalias i8* @malloc(i64 noundef %7) #4
store i8* %8, i8** %3, align 8
%9 = load %struct._IO_FILE*, %struct._IO_FILE** @stdin, align 8
%10 = call i64 @getline(i8** noundef %3, i64* noundef %2, %struct._IO_FILE* noundef %9)
%11 = load i8*, i8** %3, align 8
%12 = call double @atof(i8* noundef %11) #5
store double %12, double* %4, align 8
%13 = load %struct._IO_FILE*, %struct._IO_FILE** @stdin, align 8
%14 = call i64 @getline(i8** noundef %3, i64* noundef %2, %struct._IO_FILE* noundef %13)
%15 = load i8*, i8** %3, align 8
%16 = call double @atof(i8* noundef %15) #5
store double %16, double* %5, align 8
%17 = load double, double* %4, align 8
%18 = load double, double* %5, align 8
%19 = load double, double* %4, align 8
%20 = load double, double* %5, align 8
%21 = fadd double %19, %20
%ia01 = alloca double, align 8
%22 = call double (double, ...) @work03_fn(double %21)
store double %22, double* %ia01, align 8
%23 = load double, double* %ia01, align 8
%24 = call i32 (i8*, ...) @printf(i8* noundef getelementptr inbounds ([21 x i8], [21 x i8]* @.str.1, i64 0, i64 0), double noundef %17, double noundef %18, double noundef %23)
%25 = load i8*, i8** %3, align 8
call void @free(i8* noundef %25) #4
ret i32 0
}
declare dso_local i32 @puts(i8* noundef) #1
; Function Attrs: nounwind
declare dso_local noalias i8* @malloc(i64 noundef) #2
declare dso_local i64 @getline(i8** noundef, i64* noundef, %struct._IO_FILE* noundef) #1
; Function Attrs: nounwind readonly willreturn
declare dso_local double @atof(i8* noundef) #3
declare dso_local i32 @printf(i8* noundef, ...) #1
; Function Attrs: nounwind
declare dso_local void @free(i8* noundef) #2
define double @work03_fn(double %0, ...) {
work03_fn_defaut:
%ial02 = alloca double, align 8
store double %0, double* %ial02, align 8
%1 = load double, double* %ial02, align 8
%2 = fcmp ugt double %1, 1.000000e+02
br i1 %2, label %work03_fn_change, label %work03_fn_nothing
work03_fn_change: ; preds = %work03_fn_defaut
%3 = load double, double* %ial02, align 8
%4 = frem double %3, 1.000000e+02
store double %4, double* %ial02, align 8
%5 = load double, double* %ial02, align 8
ret double %5
work03_fn_nothing: ; preds = %work03_fn_defaut
%6 = load double, double* %ial02, align 8
ret double %6
}
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" }
attributes #1 = { "frame-pointer"="all" "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 #2 = { nounwind "frame-pointer"="all" "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 #3 = { nounwind readonly willreturn "frame-pointer"="all" "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 #4 = { nounwind }
attributes #5 = { nounwind readonly willreturn }
!llvm.module.flags = !{!0, !1, !2}
!llvm.ident = !{!3}
!0 = !{i32 1, !"wchar_size", i32 4}
!1 = !{i32 7, !"uwtable", i32 1}
!2 = !{i32 7, !"frame-pointer", i32 2}
!3 = !{!"clang version 14.0.0"}
四) 总结
- 涉及到创建全局变量操作, 创建时需要初始化其值。
一种时直接构造创建,或使用Module类中getOrInsertGlobal
方法。
auto in_alloc02 = new GlobalVariable(*M,f32,false,GlobalValue::PrivateLinkage,const_0,"fadd_res");
GlobalVariable::GlobalVariable(Module &M, Type *Ty, bool constant,
LinkageTypes Link, Constant *InitVal,
const Twine &Name, GlobalVariable *Before,
ThreadLocalMode TLMode,
Optional<unsigned> AddressSpace,
bool isExternallyInitialized)
// Overload to construct a global variable using its constructor's defaults.
Constant *Module::getOrInsertGlobal(StringRef Name, Type *Ty) {
return getOrInsertGlobal(Name, Ty, [&] {
return new GlobalVariable(*this, Ty, false, GlobalVariable::ExternalLinkage,
nullptr, Name);
});
}
-
创建函数操作,
- 先指定返回类型与函数的参数
- 构造函数
- 创建基本块
- 遍历函数的参数并读取
- 基本块插入指令
- 添加返回指令,即使函数为
void
,也应添加ret void
指令