I'm using LLVM C++ api to generate LLVM IR and using JIT to run the function.
The function I want to simulate is
double foofor(double a)
{
for (int i = 0; i < 10; i++) {
a += 2;
}
return a;
}
The corresponding llvm IR code I generate is (using TheFunction->print)
define double #foofor(double %a) {
entry:
br label %loop
loop: ; preds = %loop, %entry
%a1 = phi double [ 0.000000e+00, %entry ], [ %nextvar, %loop ]
%addtmp = fadd double %a, 2.000000e+00
%nextvar = fadd double 1.000000e+00, %a1
%cmptmp = fcmp ult double %a1, 1.000000e+01
br i1 %cmptmp, label %loop, label %afterloop
afterloop: ; preds = %loop
ret double %addtmp
}
When I call foofor(40), I get 42 not 60(40 + 20).
The code I have write(without AST)
#include "./llvm-8.0.1.src/examples/Kaleidoscope/include/KaleidoscopeJIT.h"
#include "llvm/ADT/APFloat.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Type.h"
#include "llvm/IR/Verifier.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Transforms/InstCombine/InstCombine.h"
#include "llvm/Transforms/Scalar.h"
#include "llvm/Transforms/Scalar/GVN.h"
#include <string>
#include <vector>
#include <iostream>
using namespace std;
using namespace llvm;
using namespace llvm::orc;
//LLVM items
static LLVMContext TheContext;
static IRBuilder<> Builder(TheContext);
static std::unique_ptr<Module> TheModule;
//JIT
static std::unique_ptr<KaleidoscopeJIT> TheJIT;
/*
*double foofor(double a)
*{
* for(i = 0; i < a; i++) {
* a = a + 1
* }
* return a
*}
*
*/
int main()
{
InitializeNativeTarget();
InitializeNativeTargetAsmPrinter();
//init module
TheModule = llvm::make_unique<Module>("myjit", TheContext);
//used to be runned by jit later
TheJIT = llvm::make_unique<KaleidoscopeJIT>();
TheModule->setDataLayout(TheJIT->getTargetMachine().createDataLayout());
//define the args
vector<std::string> ArgNames;
//foocfor has 1 args
ArgNames.push_back(string("a"));
//make the 1 args attach to LLVM Type::double
std::vector<Type *> Doubles(ArgNames.size(), Type::getDoubleTy(TheContext));
//generate llvm function type
FunctionType *FT = FunctionType::get(Type::getDoubleTy(TheContext), Doubles, false);
//Create function whose FunctionType is FT
Function *TheFunction = Function::Create(FT, Function::ExternalLinkage, "foofor", TheModule.get());
//give the name for Function args and save the args in innerargs
unsigned Idx = 0;
std::vector<Value *>innerargs;
for (auto &Arg : TheFunction->args()) {
Arg.setName(ArgNames[Idx++]);
innerargs.push_back(&Arg);
}
//this function's basic block
BasicBlock *BB = BasicBlock::Create(TheContext, "entry", TheFunction);
//create the loop BasicBlock
BasicBlock *LoopBB = BasicBlock::Create(TheContext, "loop", TheFunction);
//exit the block
BasicBlock *AfterBB = BasicBlock::Create(TheContext, "afterloop", TheFunction);
Builder.SetInsertPoint(BB);
//add goto LoopBB in BB
Builder.CreateBr(LoopBB);
//start with LoopBB
Builder.SetInsertPoint(LoopBB);
//start with 0
Value *StartVal = ConstantFP::get(TheContext, APFloat(0.0));
//step is 1
Value *StepVal = ConstantFP::get(TheContext, APFloat(1.0));
//local Variable which name is a
PHINode *Variable = Builder.CreatePHI(Type::getDoubleTy(TheContext), 1, "a");
//if it's from start block, set Variable 0
Variable->addIncoming(StartVal, BB);
//do the body then do cond
//emit loop body in LoopBB
//body: arg_a += 1
Value *ret = Builder.CreateFAdd(innerargs[0], ConstantFP::get(TheContext, APFloat(2.0)), "addtmp");
//do the cond,if Variable >= 10 then break(goto AfterBB)
Value *NextVar = Builder.CreateFAdd(StepVal, Variable, "nextvar");
//if Variable < 10 then goto LoopBB or gotot AfterBB
Value *cond = Builder.CreateFCmpULT(Variable, ConstantFP::get(TheContext, APFloat(10.0)), "cmptmp");
Builder.CreateCondBr(cond, LoopBB, AfterBB);
Builder.SetInsertPoint(AfterBB);
Variable->addIncoming(NextVar, LoopBB);
Builder.CreateRet(ret);
TheFunction->print(errs());
//using jit to run this code
auto H = TheJIT->addModule(std::move(TheModule));
auto ExprSymbol = TheJIT->findSymbol("foofor");
double (*foofor)(double) = (double (*)(double))(intptr_t)cantFail(ExprSymbol.getAddress());
cout <<foofor(40)<<endl;
}
Here's the LLVM IR form for a variable that increases:
define double #foofor(double %a) {
entry:
br label %loop
loop: ; preds = %loop, %entry
%a1 = phi double [ 0.000000e+00, %entry ], [ %nextvar, %loop ]
%a2 = phi double [ 0.000000e+00, %a ], [ %addtmp, %loop ]
%addtmp = fadd double %a2, 2.000000e+00
%nextvar = fadd double 1.000000e+00, %a1
%cmptmp = fcmp ult double %a1, 1.000000e+01
br i1 %cmptmp, label %loop, label %afterloop
afterloop: ; preds = %loop
ret double %addtmp
}
%a1/%nextvar ought to be ints as well, not doubles, but I left that since that's not the subject of your question.
Related
Final goal: Trying to generate CFG related information(such as topological sort) using LLVM.
Status: I'm pretty new to LLVM and kind of lost - any kind of information or blogs to help me get started towards my final goal is great!
My Question: After reading Eli's code and blog post, I get the .ll file first and run the code but I got no result.
Here is the .ll file example:
; ModuleID = 'CWE15_External_Control_of_System_or_Configuration_Setting__w32_83a.cpp'
source_filename = "CWE15_External_Control_of_System_or_Configuration_Setting__w32_83a.cpp"
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"
%"class.CWE15_External_Control_of_System_or_Configuration_Setting__w32_83::CWE15_External_Control_of_System_or_Configuration_Setting__w32_83_bad" = type { i8* }
%"class.CWE15_External_Control_of_System_or_Configuration_Setting__w32_83::CWE15_External_Control_of_System_or_Configuration_Setting__w32_83_goodG2B" = type { i8* }
; Function Attrs: noinline optnone uwtable
define void #_ZN65CWE15_External_Control_of_System_or_Configuration_Setting__w32_833badEv() #0 {
%1 = alloca i8*, align 8
%2 = alloca [100 x i8], align 16
%3 = alloca %"class.CWE15_External_Control_of_System_or_Configuration_Setting__w32_83::CWE15_External_Control_of_System_or_Configuration_Setting__w32_83_bad", align 8
%4 = bitcast [100 x i8]* %2 to i8*
call void #llvm.memset.p0i8.i64(i8* %4, i8 0, i64 100, i32 16, i1 false)
%5 = getelementptr inbounds [100 x i8], [100 x i8]* %2, i32 0, i32 0
store i8* %5, i8** %1, align 8
%6 = load i8*, i8** %1, align 8
call void #_ZN65CWE15_External_Control_of_System_or_Configuration_Setting__w32_8369CWE15_External_Control_of_System_or_Configuration_Setting__w32_83_badC1EPc(%"class.CWE15_External_Control_of_System_or_Configuration_Setting__w32_83::CWE15_External_Control_of_System_or_Configuration_Setting__w32_83_bad"* %3, i8* %6)
call void #_ZN65CWE15_External_Control_of_System_or_Configuration_Setting__w32_8369CWE15_External_Control_of_System_or_Configuration_Setting__w32_83_badD1Ev(%"class.CWE15_External_Control_of_System_or_Configuration_Setting__w32_83::CWE15_External_Control_of_System_or_Configuration_Setting__w32_83_bad"* %3) #4
ret void
}
; Function Attrs: argmemonly nounwind
declare void #llvm.memset.p0i8.i64(i8* nocapture writeonly, i8, i64, i32, i1) #1
declare void #_ZN65CWE15_External_Control_of_System_or_Configuration_Setting__w32_8369CWE15_External_Control_of_System_or_Configuration_Setting__w32_83_badC1EPc(%"class.CWE15_External_Control_of_System_or_Configuration_Setting__w32_83::CWE15_External_Control_of_System_or_Configuration_Setting__w32_83_bad"*, i8*) unnamed_addr #2
; Function Attrs: nounwind
declare void #_ZN65CWE15_External_Control_of_System_or_Configuration_Setting__w32_8369CWE15_External_Control_of_System_or_Configuration_Setting__w32_83_badD1Ev(%"class.CWE15_External_Control_of_System_or_Configuration_Setting__w32_83::CWE15_External_Control_of_System_or_Configuration_Setting__w32_83_bad"*) unnamed_addr #3
; Function Attrs: noinline optnone uwtable
define void #_ZN65CWE15_External_Control_of_System_or_Configuration_Setting__w32_834goodEv() #0 {
call void #_ZN65CWE15_External_Control_of_System_or_Configuration_Setting__w32_83L7goodG2BEv()
ret void
}
; Function Attrs: noinline optnone uwtable
define internal void #_ZN65CWE15_External_Control_of_System_or_Configuration_Setting__w32_83L7goodG2BEv() #0 {
%1 = alloca i8*, align 8
%2 = alloca [100 x i8], align 16
%3 = alloca %"class.CWE15_External_Control_of_System_or_Configuration_Setting__w32_83::CWE15_External_Control_of_System_or_Configuration_Setting__w32_83_goodG2B", align 8
%4 = bitcast [100 x i8]* %2 to i8*
call void #llvm.memset.p0i8.i64(i8* %4, i8 0, i64 100, i32 16, i1 false)
%5 = getelementptr inbounds [100 x i8], [100 x i8]* %2, i32 0, i32 0
store i8* %5, i8** %1, align 8
%6 = load i8*, i8** %1, align 8
call void #_ZN65CWE15_External_Control_of_System_or_Configuration_Setting__w32_8373CWE15_External_Control_of_System_or_Configuration_Setting__w32_83_goodG2BC1EPc(%"class.CWE15_External_Control_of_System_or_Configuration_Setting__w32_83::CWE15_External_Control_of_System_or_Configuration_Setting__w32_83_goodG2B"* %3, i8* %6)
call void #_ZN65CWE15_External_Control_of_System_or_Configuration_Setting__w32_8373CWE15_External_Control_of_System_or_Configuration_Setting__w32_83_goodG2BD1Ev(%"class.CWE15_External_Control_of_System_or_Configuration_Setting__w32_83::CWE15_External_Control_of_System_or_Configuration_Setting__w32_83_goodG2B"* %3) #4
ret void
}
declare void #_ZN65CWE15_External_Control_of_System_or_Configuration_Setting__w32_8373CWE15_External_Control_of_System_or_Configuration_Setting__w32_83_goodG2BC1EPc(%"class.CWE15_External_Control_of_System_or_Configuration_Setting__w32_83::CWE15_External_Control_of_System_or_Configuration_Setting__w32_83_goodG2B"*, i8*) unnamed_addr #2
; Function Attrs: nounwind
declare void #_ZN65CWE15_External_Control_of_System_or_Configuration_Setting__w32_8373CWE15_External_Control_of_System_or_Configuration_Setting__w32_83_goodG2BD1Ev(%"class.CWE15_External_Control_of_System_or_Configuration_Setting__w32_83::CWE15_External_Control_of_System_or_Configuration_Setting__w32_83_goodG2B"*) unnamed_addr #3
attributes #0 = { noinline optnone uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "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" }
attributes #1 = { argmemonly nounwind }
attributes #2 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="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" }
attributes #3 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="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" }
attributes #4 = { nounwind }
!llvm.module.flags = !{!0}
!llvm.ident = !{!1}
!0 = !{i32 1, !"wchar_size", i32 4}
!1 = !{!"clang version 5.0.0 (tags/RELEASE_500/final 375507)"}
and here is the .cpp file which generate sort information:
//------------------------------------------------------------------------------
// bb_toposort_sccs LLVM sample. Demonstrates:
//
// * How to implement DFS & topological sort over the control-flow graph (CFG)
// of a function.
// * How to use po_iterator for post-order iteration over basic blocks.
// * How to use scc_iterator for post-order iteration over strongly-connected
// components in the graph of basic blocks.
//
// Eli Bendersky (eliben#gmail.com)
// This code is in the public domain
//------------------------------------------------------------------------------
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/PostOrderIterator.h"
#include "llvm/ADT/SCCIterator.h"
#include "llvm/IR/CFG.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/Instruction.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/IR/Module.h"
#include "llvm/IRReader/IRReader.h"
#include "llvm/Pass.h"
#include "llvm/Support/SourceMgr.h"
#include "llvm/Support/raw_ostream.h"
#include <string>
#include <vector>
using namespace llvm;
// Runs a topological sort on the basic blocks of the given function. Uses
// the simple recursive DFS from "Introduction to algorithms", with 3-coloring
// of vertices. The coloring enables detecting cycles in the graph with a simple
// test.
class TopoSorter {
public:
void runToposort(const Function &F) {
outs() << "Topological sort of " << F.getName() << ":\n";
// Initialize the color map by marking all the vertices white.
for (Function::const_iterator I = F.begin(), IE = F.end(); I != IE; ++I) {
ColorMap[&*I] = TopoSorter::WHITE;
}
// The BB graph has a single entry vertex from which the other BBs should
// be discoverable - the function entry block.
bool success = recursiveDFSToposort(&F.getEntryBlock());
if (success) {
// Now we have all the BBs inside SortedBBs in reverse topological order.
for (BBVector::const_reverse_iterator RI = SortedBBs.rbegin(),
RE = SortedBBs.rend();
RI != RE; ++RI) {
outs() << " " << (*RI)->getName() << "\n";
}
} else {
outs() << " Sorting failed\n";
}
}
private:
enum Color { WHITE, GREY, BLACK };
// Color marks per vertex (BB).
typedef DenseMap<const BasicBlock *, Color> BBColorMap;
// Collects vertices (BBs) in "finish" order. The first finished vertex is
// first, and so on.
typedef SmallVector<const BasicBlock *, 32> BBVector;
BBColorMap ColorMap;
BBVector SortedBBs;
// Helper function to recursively run topological sort from a given BB.
// Returns true if the sort succeeded and false otherwise; topological sort
// may fail if, for example, the graph is not a DAG (detected a cycle).
bool recursiveDFSToposort(const BasicBlock *BB) {
ColorMap[BB] = TopoSorter::GREY;
// For demonstration, using the lowest-level APIs here. A BB's successors
// are determined by looking at its terminator instruction.
const TerminatorInst *TInst = BB->getTerminator();
for (unsigned I = 0, NSucc = TInst->getNumSuccessors(); I < NSucc; ++I) {
BasicBlock *Succ = TInst->getSuccessor(I);
Color SuccColor = ColorMap[Succ];
if (SuccColor == TopoSorter::WHITE) {
if (!recursiveDFSToposort(Succ))
return false;
} else if (SuccColor == TopoSorter::GREY) {
// This detects a cycle because grey vertices are all ancestors of the
// currently explored vertex (in other words, they're "on the stack").
outs() << " Detected cycle: edge from " << BB->getName() << " to "
<< Succ->getName() << "\n";
return false;
}
}
// This BB is finished (fully explored), so we can add it to the vector.
ColorMap[BB] = TopoSorter::BLACK;
SortedBBs.push_back(BB);
return true;
}
};
class AnalyzeBBGraph : public FunctionPass {
public:
AnalyzeBBGraph(const std::string &AnalysisKind)
: FunctionPass(ID), AnalysisKind(AnalysisKind) {}
virtual bool runOnFunction(Function &F) {
if (AnalysisKind == "-topo") {
TopoSorter TS;
TS.runToposort(F);
} else if (AnalysisKind == "-po") {
// Use LLVM's post-order iterator to produce a reverse topological sort.
// Note that this doesn't detect cycles so if the graph is not a DAG, the
// result is not a true topological sort.
outs() << "Basic blocks of " << F.getName() << " in post-order:\n";
for (po_iterator<BasicBlock *> I = po_begin(&F.getEntryBlock()),
IE = po_end(&F.getEntryBlock());
I != IE; ++I) {
outs() << " " << (*I)->getName() << "\n";
}
} else if (AnalysisKind == "-scc") {
// Use LLVM's Strongly Connected Components (SCCs) iterator to produce
// a reverse topological sort of SCCs.
outs() << "SCCs for " << F.getName() << " in post-order:\n";
for (scc_iterator<Function *> I = scc_begin(&F), IE = scc_end(&F);
I != IE; ++I) {
// Obtain the vector of BBs in this SCC and print it out.
const std::vector<BasicBlock *> &SCCBBs = *I;
outs() << " SCC: ";
for (std::vector<BasicBlock *>::const_iterator BBI = SCCBBs.begin(),
BBIE = SCCBBs.end();
BBI != BBIE; ++BBI) {
outs() << (*BBI)->getName() << " ";
}
outs() << "\n";
}
} else {
outs() << "Unknown analysis kind: " << AnalysisKind << "\n";
}
return false;
}
// The address of this member is used to uniquely identify the class. This is
// used by LLVM's own RTTI mechanism.
static char ID;
private:
std::string AnalysisKind;
};
char AnalyzeBBGraph::ID = 0;
int main(int argc, char **argv) {
if (argc < 3) {
// Using very basic command-line argument parsing here...
errs() << "Usage: " << argv[0] << " -[topo|po|scc] <IR file>\n";
return 1;
}
// Parse the input LLVM IR file into a module.
SMDiagnostic Err;
LLVMContext Context;
std::unique_ptr<Module> Mod(parseIRFile(argv[2], Err, Context));
if (!Mod) {
Err.print(argv[0], errs());
return 1;
}
// Create a pass manager and fill it with the passes we want to run.
legacy::PassManager PM;
PM.add(new AnalyzeBBGraph(std::string(argv[1])));
PM.run(*Mod);
return 0;
}
here is my result looks like when I try to get topo sort:
Topological sort of _ZN65CWE15_External_Control_of_System_or_Configuration_Setting__w32_833badEv:
Topological sort of _ZN65CWE15_External_Control_of_System_or_Configuration_Setting__w32_834goodEv:
Topological sort of _ZN65CWE15_External_Control_of_System_or_Configuration_Setting__w32_83L7goodG2BEv:
I tried something else and I found out all the "getName()" print is nothing,
Is there something wrong with my code or somrthing wrong with my llvm IR ?
for(BasicBlock &BB : F){
outs() << "BB:" <<BB.getName() <<" has" <<BB.size() <<"instructions.\n";
for(Instruction &I : BB){
outs() << "details: "<<I <<"name: "<<I.getName() <<"\n";
for(Use &U : I.operands()){
Value *v = U.get();
outs() <<"value:"<< v<<"name:" << v->getName() <<"\n";
}
}
}
Any thoughts are appreciated!
You might want to run the instruction namer pass after you obtain your IR (the .ll file) in order to assign names to the basic blocks and the registers, because currently, they do not have any names apart from their numeric assignment (e.g. %1, etc). You can run this with:
opt -instnamer foo.bc -o foo-named.bc
The 3 functions definitions have only one basic block in them, so you are not going to get anything interesting, but it is a good start.
Another point that you might want to address now before moving on, is the optimization level. All your functions are annotated with optnone that will disable any kind of optimization from other LLVM passes. A more flexible way to get unoptimized IR, but one that will allow further optimizations to take effect on it is to extracted using:
clang -emit-llvm -O1 -Xclang -disable-llvm-passes foo.c
I'm trying to get the float value from a global variable and set it as an instruction's operand.
Here is what I want to do:
#a = private constant float 0x3FB99999A0000000
...
%1 = load float, float* #a ---> removed
%3 = fmul fast %1, %2 ---> %3 = fmul fast float 0x3FB99999A0000000, %2
Below is what I haved tried so far:
for (auto gv_iter = llvm_module.global_begin();gv_iter != llvm_module.global_end(); gv_iter++){
llvm::GlobalVariable* gv = &*gv_iter;
for(auto user_of_gv : gv->users()){
llvm::Instruction *instr_ld_gv = llvm::dyn_cast<llvm::Instruction>(user_of_gv);
llvm::Value *val_gv = llvm::cast<llvm::Value>(instr_ld_gv);
llvm::Constant *const_gv = gv->getInitializer();
llvm::ConstantFP *constfp_gv = llvm::dyn_cast<llvm::ConstantFP>(const_gv);
float gv_fpval = (constfp_gv->getValueAPF()).convertToFloat();
llvm::Constant *const_gv_opd = llvm::ConstantFP::get(llvm::Type::getFloatTy(llvm_context),gv_fpval);
for(auto user_of_load : val_gv->users()){
llvm::Instruction *instr_exe_gv = llvm::dyn_cast<llvm::Instruction>(user_of_load);
//P
for(int operand_num = 0;operand_num < instr_exe_gv->getNumOperands();operand_num++){
llvm::Value *val_instr_op = instr_exe_gv->getOperand(operand_num);
if(val_instr_op == val_gv){
instr_exe_gv->setOperand(operand_num,const_gv_opd);
instr_ld_gv->removeFromParent();
}
}
}
}
}
However, it'll cause segmentation fault when I tried to run my code.
I'm sure that I have accessed the global variable and instruction I wanted
by printing the value of
gv_fpval which is 0.1 because 0x3FB99999A0000000 equals 0.10000000149011612 in double
precision. It seems that the program crashes at setOperand().
Consider the following example
hello.cpp
#include <stdio.h>
// Global Constant value
float a=1.4f;
float Multiply(){
float b=2.2f;
float c=4.32f;
float d= a*c;
return d;
}
int main(int argc, char const *argv[])
{
printf("%f\n",Multiply());
return 0;
}
The module pass will loop for Floating point global variable and any use in the program will be replaced by the constant FP value. The LLVM pass are as follow ConstantReplacementPass.cpp:-
#include "llvm/Pass.h"
#include "llvm/IR/Function.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/IR/InstrTypes.h"
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Module.h"
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
#include "llvm/DebugInfo/DWARF/DWARFDebugLine.h"
#include "llvm/IR/DebugLoc.h"
#include "llvm/IR/DebugInfo.h"
using namespace llvm;
/* StackOverflow : https://stackoverflow.com/questions/48212351/how-to-get-llvm-global-variable-constant-value* /
/**Bernard Nongpoh */
namespace {
class ConstantReplacementPass : public ModulePass {
public:
static char ID;
ConstantReplacementPass() : ModulePass(ID) {
srand (time(NULL));
}
virtual bool runOnModule(Module &M) {
// list to collect instruction
/*
* You cannot change an iterator while iterating over it
• To remove instructions or modify, first collect the instructions to remove/modify
•
*
* **/
// This are the list of load to delete
SmallVector<Instruction*,128> *WorkListLoad=new SmallVector<Instruction*,128>();
// This is the list of instruction to modify the source operand
SmallVector<Instruction*,128> *WorkListUserOfLoad=new SmallVector<Instruction*,128>();
for (auto gv_iter = M.global_begin();gv_iter != M.global_end(); gv_iter++) {
/* GLOBAL DATA INFO*/
GlobalVariable *gv = &*gv_iter;
Constant *const_gv = gv->getInitializer();
ConstantFP *Fvalue;
if(!const_gv->isNullValue()) {
if (ConstantFP *constfp_gv = llvm::dyn_cast<llvm::ConstantFP>(const_gv)) {
float gv_fpval = (constfp_gv->getValueAPF()).convertToFloat();
Fvalue = constfp_gv;
errs() << gv_fpval; // Value retrieved here
// Collect Instruction to modify
}
for (auto user_of_gv: gv->users()) {
// Collect in a worklist
if (llvm::Instruction *instr_ld_gv = llvm::dyn_cast<Instruction>(user_of_gv)) {
if (LoadInst *loadInst = dyn_cast<LoadInst>(instr_ld_gv)) {
WorkListLoad->push_back(loadInst);
for (auto user_of_load:loadInst->users()) {
user_of_load->dump();
Instruction *instruction1 = dyn_cast<Instruction>(user_of_load);
instruction1->dump();
//instruction1->setOperand(0, Fvalue);
//instruction1->dump();
// if(Instruction *instruction1 = dyn_cast<Instruction>(user_of_load))
WorkListUserOfLoad->push_back(instruction1);
//instruction1->setOperand(0, Fvalue);
//instruction1->dump();
}
}
}
}
// Modify Here
while (!WorkListUserOfLoad->empty()) {
Instruction *instruction = WorkListUserOfLoad->pop_back_val();
instruction->setOperand(0, Fvalue);
instruction->dump();
}
// Removing all loads that are used by the global variable
while (!WorkListLoad->empty()) {
Instruction *instruction = WorkListLoad->pop_back_val();
instruction->eraseFromParent();
}
}
}
return true;
}
};
}
char ConstantReplacementPass::ID = 0;
static RegisterPass<ConstantReplacementPass> F0("constantREP", "Constant Replacement Pass "
, false,true);
Key points:-
Before doing any modification on the instruction. Collect first in the worklist.
perform the modification on the worklist.
you cannot do the modification while using the iterator.
I successfully tested on the above source code hello.cpp the corresponding IR after the pass is as follow:-
entry:
%b = alloca float, align 4
%c = alloca float, align 4
%d = alloca float, align 4
call void #llvm.dbg.declare(metadata float* %b, metadata !14, metadata !15),
... !dbg !16
store float 0x40019999A0000000, float* %b, align 4, !dbg !16
call void #llvm.dbg.declare(metadata float* %c, metadata !17, metadata !15),
... !dbg !18
store float 0x401147AE20000000, float* %c, align 4, !dbg !18
call void #llvm.dbg.declare(metadata float* %d, metadata !19, metadata !15),
... !dbg !20
%0 = load float, float* %c, align 4, !dbg !21
%mul = fmul float 0x3FF6666660000000, %0, !dbg !22
store float %mul, float* %d, align 4, !dbg !20
%1 = load float, float* %d, align 4, !dbg !23
ret float %1, !dbg !24
Maybe using -O3 optimization flag will wipe out everything...
Hope this helps..
I am pretty new with llvm and having trouble digging deep into the following IR line:
%call2 = call float bitcast (float (float, i32*)* #function to float (float, i32 addrspace(1)*)*)(float %11, i32 addrspace(1)* %arrayidx)
What I need to extract from this is line the type of the arguments of the function (i.e., (float %11, i32 addrspace(1)* %arrayidx))
I have tried the following, and played arround with ConstExpr a little as well, but cannot get to extract that addrspace(1)
for (Function::iterator block = F.begin(), blockEnd = F.end(); block != blockEnd; ++block) {
for (BasicBlock::iterator inst = block->begin(), instEnd = block->end(); inst != instEnd; ++inst) {
if (CallInst *call = dyn_cast<CallInst>(inst)) {
Function *calledFunction = call->getCalledFunction();
if (calledFunction == NULL) { // Called function is wrapped in a bitcast
Value* v = call->getCalledValue();
calledFunction = dyn_cast<Function>(v->stripPointerCasts());
FunctionType *ft = calledFunction->getFunctionType(); // This gives me the type "from" (the args without addrspace(1)
for( Function::arg_iterator arg = calledFunction->arg_begin(), marg_end = calledFunction->arg_end(); arg != marg_end ; arg++){
Type *argTy = arg->getType();
if (PointerType *ptrTy = dyn_cast<PointerType>(argTy)) {
if( ptrTy->getAddressSpace() !=0)
...
}
}
}
}
}
}
The above code gives me the types (float, i32*) and not (float, i32 addrspace(1)*)
Any help please?
The llvm ir
%call2 = call float bitcast (float (float, i32*)* #function to float (float, i32 addrspace(1)*)*)(float %11, i32 addrspace(1)* %arrayidx)
is casting function type float (float, i32*) to float (float, i32 addrspace(1)*) and calling it with argument (%11, %arrayidx).
If you want the types of argument you can check it using callInst::getArgOperand to get arguments in call instruction itself.
for (Function::iterator block = F.begin(), blockEnd = F.end(); block != blockEnd; ++block) {
for (BasicBlock::iterator inst = block->begin(), instEnd = block->end(); inst != instEnd; ++inst) {
if (CallInst *call = dyn_cast<CallInst>(inst)) {
Value *val11 = call->getArgOperand(0);
Value *valarrayIdx = call->getArgOperand(1);
Type *val11ty = val11->getType(); // this should be of float
Type *valarrayIdx = valarrayIdx->getType(); // this should be of i32 address(1)*
}
}
}
CallInst::getCalledFunction will give you the function.
For more info you can go through http://llvm.org/docs/doxygen/html/classllvm_1_1CallInst.html
I am working on an example from the LLVM Essentials book. The section is called Emitting if-else condition IR, and I keep getting the following error.
Assertion failed: (getOperand(0)->getType() == getOperand(1)->getType()
&& "Both operands to ICmp instruction are not of the same type!"),
function AssertOK,
file /usr/local/Cellar/llvm/3.6.2/include/llvm/IR/Instructions.h, line
997. Abort trap: 6
I've spent hours trying to figure this out, but I'm at my wit's end. I'm sure it's something minor, but I have no idea. The code I am using is below.
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Verifier.h"
#include <vector>
#include <iostream>
#include <typeinfo>
using namespace llvm;
static LLVMContext &Context = getGlobalContext();
static Module *ModuleOb = new Module("my compiler", Context);
static std::vector<std::string> FunArgs;
typedef SmallVector<BasicBlock *, 16> BBList;
typedef SmallVector<Value *, 16> ValList;
Function *createFunc(IRBuilder<> &Builder, std::string Name) {
std::vector<Type *> Integers(FunArgs.size(), Type::getInt32Ty(Context));
FunctionType *funcType =
llvm::FunctionType::get(Builder.getInt32Ty(), Integers, false);
Function *fooFunc = llvm::Function::Create(
funcType, llvm::Function::ExternalLinkage, Name, ModuleOb);
return fooFunc;
}
void setFuncArgs(Function *fooFunc, std::vector<std::string> FunArgs) {
unsigned Idx = 0;
Function::arg_iterator AI, AE;
for (AI = fooFunc->arg_begin(), AE = fooFunc->arg_end(); AI != AE;
++AI, ++Idx)
AI->setName(FunArgs[Idx]);
}
BasicBlock *createBB(Function *fooFunc, std::string Name) {
return BasicBlock::Create(Context, Name, fooFunc);
}
GlobalVariable *createGlob(IRBuilder<> &Builder, std::string Name) {
ModuleOb->getOrInsertGlobal(Name, Builder.getInt32Ty());
GlobalVariable *gVar = ModuleOb->getNamedGlobal(Name);
gVar->setLinkage(GlobalValue::CommonLinkage);
gVar->setAlignment(4);
return gVar;
}
Value *createArith(IRBuilder<> &Builder, Value *L, Value *R) {
return Builder.CreateMul(L, R, "multmp");
}
Value *createIfElse(IRBuilder<> &Builder, BBList List, ValList VL) {
Value *Condtn = VL[0];
Value *Arg1 = VL[1];
BasicBlock *ThenBB = List[0];
BasicBlock *ElseBB = List[1];
BasicBlock *MergeBB = List[2];
Builder.CreateCondBr(Condtn, ThenBB, ElseBB);
Builder.SetInsertPoint(ThenBB);
Value *ThenVal = Builder.CreateAdd(Arg1, Builder.getInt32(1), "thenaddtmp");
Builder.CreateBr(MergeBB);
Builder.SetInsertPoint(ElseBB);
Value *ElseVal = Builder.CreateAdd(Arg1, Builder.getInt32(2), "elseaddtmp");
Builder.CreateBr(MergeBB);
unsigned PhiBBSize = List.size() - 1;
Builder.SetInsertPoint(MergeBB);
PHINode *Phi = Builder.CreatePHI(Type::getInt32Ty(getGlobalContext()), PhiBBSize, "iftmp");
Phi->addIncoming(ThenVal, ThenBB);
Phi->addIncoming(ElseVal, ElseBB);
return Phi;
}
int main(int argc, char *argv[]) {
FunArgs.push_back("a");
FunArgs.push_back("b");
static IRBuilder<> Builder(Context);
GlobalVariable *gVar = createGlob(Builder, "x");
Function *fooFunc = createFunc(Builder, "foo");
setFuncArgs(fooFunc, FunArgs);
BasicBlock *entry = createBB(fooFunc, "entry");
Builder.SetInsertPoint(entry);
Value *Arg1 = fooFunc->arg_begin();
Value *constant = Builder.getInt32(16);
Value *val = createArith(Builder, Arg1, constant);
Value *val2 = Builder.getInt32(100);
Value *Compare = Builder.CreateICmpULT(val, val2, "cmptmp");
Value *Condtn = Builder.CreateICmpNE(Compare, Builder.getInt32(0), "ifcond");
ValList VL;
VL.push_back(Condtn);
VL.push_back(Arg1);
BasicBlock *ThenBB = createBB(fooFunc, "then");
BasicBlock *ElseBB = createBB(fooFunc, "else");
BasicBlock *MergeBB = createBB(fooFunc, "ifcont");
BBList List;
List.push_back(ThenBB);
List.push_back(ElseBB);
List.push_back(MergeBB);
Value *v = createIfElse(Builder, List, VL);
Builder.CreateRet(v);
verifyFunction(*fooFunc);
ModuleOb->dump();
return 0;
}
I know the issue is occurring at this location. I've tried to dynamically cast both to the same type, but still not compiling.
Value *Condtn = Builder.CreateICmpNE(Compare, Builder.getInt32(0), "ifcond");
The problem is with these two lines:
Value *Compare = Builder.CreateICmpULT(val, val2, "cmptmp");
Value *Condtn = Builder.CreateICmpNE(Compare, Builder.getInt32(0), "ifcond");
The first icmp instruction evaluates to a value of type i1, and you're trying to compare that to a value of type i32.
Your best bet would be to avoid the second icmp altogether, as it's superfluous (it will evaluate to the same value as Compare). Just use Compare as your condition.
Otherwise, you'd have to make sure the types match -- in this case you can just use Builder.getInt1(false) instead of Builder.getInt32(0). More generally you might use Builder.CreateIntCast to insert trunc or zext or sext instructions as needed.
I i'm trying to create a exception handler inside JIT llvm code. the current documentation regarding exception handling in LLVM is very handwavy at the moment, so i've been trying to reuse most of the snippets i get from http://llvm.org/demo in order to get a working example, but i'm not sure if those are up to date with llvm 2.9 (the version i am using).
This is what the module looks after Module::dump();
; ModuleID = 'testModule'
declare i32 #myfunc()
define i32 #test_function_that_invokes_another() {
entryBlock:
%0 = alloca i8*
%1 = alloca i32
%someName = invoke i32 #myfunc()
to label %exitBlock unwind label %unwindBlock
exitBlock: ; preds = %entryBlock
ret i32 1
unwindBlock: ; preds = %entryBlock
%2 = call i8* #llvm.eh.exception()
store i8* %2, i8** %0
%3 = call i32 (i8*, i8*, ...)* #llvm.eh.selector(i8* %2, i8* bitcast (i32 (...)* #__gxx_personality_v0 to i8*), i8* null)
store i32 1, i32* %1
%4 = load i8** %0
%5 = call i32 (...)* #__cxa_begin_catch(i8* %4) nounwind
%cleanup_call = call i32 #myCleanup()
%6 = call i32 (...)* #__cxa_end_catch()
ret i32 1
}
declare i32 #__gxx_personality_v0(...)
declare i32 #__cxa_begin_catch(...)
declare i32 #__cxa_end_catch(...)
declare i8* #llvm.eh.exception() nounwind readonly
declare i32 #llvm.eh.selector(i8*, i8*, ...) nounwind
declare i32 #myCleanup()
and this is what happens when i try to execute the function:
inside JIT calling C/C++ call
terminate called after throwing an instance of 'int'
Aborted
this shows that the function that throws gets called, it throws, but i never land in the cleanup call. (my cleanup call should have said 'inside JIT calling C/C++ Cleanup')
The function that invokes and (attempts) to catch a thrown exception is:
const inline llvm::FunctionType* getTestFunctionSignature(llvm::LLVMContext& context) {
return llvm::TypeBuilder< unsigned int(), false > ::get(context);
}
llvm::Function* createFunctionThatInvokesAnother( llvm::LLVMContext& ctx, llvm::Module* mod , llvm::Function* another ) {
llvm::Function* result = llvm::Function::Create(getTestFunctionSignature(ctx),
llvm::GlobalValue::ExternalLinkage,
"test_function_that_invokes_another",
mod);
llvm::BasicBlock* entry_block = llvm::BasicBlock::Create(ctx, "entryBlock", result);
llvm::BasicBlock* exit_block = llvm::BasicBlock::Create(ctx, "exitBlock", result);
llvm::BasicBlock* unwind_block = llvm::BasicBlock::Create(ctx, "unwindBlock", result);
llvm::IRBuilder<> builder(entry_block);
llvm::ConstantInt* ci = llvm::ConstantInt::get( mod->getContext() , llvm::APInt( 32 , llvm::StringRef("1"), 10));
llvm::PointerType* pty3 = llvm::PointerType::get(llvm::IntegerType::get(mod->getContext(), 8), 0);
llvm::AllocaInst* ptr_24 = new llvm::AllocaInst(pty3, "", entry_block);
llvm::AllocaInst* ptr_25 = new llvm::AllocaInst(llvm::IntegerType::get(mod->getContext(), 32), "", entry_block);
llvm::Twine name("someName");
builder.CreateInvoke( another , exit_block , unwind_block , "someName" );
builder.SetInsertPoint( exit_block );
builder.CreateRet(ci);
builder.SetInsertPoint( unwind_block );
llvm::Function* func___gxx_personality_v0 = func__gxx_personality_v0(mod);
llvm::Function* func___cxa_begin_catch = func__cxa_begin_catch(mod);
llvm::Function* func___cxa_end_catch = func__cxa_end_catch(mod);
llvm::Function* func_eh_ex = func_llvm_eh_exception(mod);
llvm::Function* func_eh_sel = func__llvm_eh_selector(mod);
llvm::Constant* const_ptr_17 = llvm::ConstantExpr::getCast(llvm::Instruction::BitCast, func___gxx_personality_v0, pty3);
llvm::ConstantPointerNull* const_ptr_18 = llvm::ConstantPointerNull::get(pty3);
llvm::CallInst* get_ex = llvm::CallInst::Create(func_eh_ex, "", unwind_block);
get_ex->setCallingConv(llvm::CallingConv::C);
get_ex->setTailCall(false);
new llvm::StoreInst(get_ex, ptr_24, false, unwind_block);
std::vector<llvm::Value*> int32_37_params;
int32_37_params.push_back(get_ex);
int32_37_params.push_back(const_ptr_17);
int32_37_params.push_back(const_ptr_18);
llvm::CallInst* eh_sel = llvm::CallInst::Create(func_eh_sel, int32_37_params.begin(), int32_37_params.end(), "", unwind_block);
eh_sel->setCallingConv(llvm::CallingConv::C);
eh_sel->setTailCall(false);
new llvm::StoreInst(ci, ptr_25, false, unwind_block);
llvm::LoadInst* ptr_29 = new llvm::LoadInst(ptr_24, "", false, unwind_block);
llvm::CallInst* ptr_30 = llvm::CallInst::Create(func___cxa_begin_catch, ptr_29, "", unwind_block);
ptr_30->setCallingConv(llvm::CallingConv::C);
ptr_30->setTailCall(false);
llvm::AttrListPtr ptr_30_PAL;
{
llvm::SmallVector<llvm::AttributeWithIndex, 4 > Attrs;
llvm::AttributeWithIndex PAWI;
PAWI.Index = 4294967295U;
PAWI.Attrs = 0 | llvm::Attribute::NoUnwind;
Attrs.push_back(PAWI);
ptr_30_PAL = llvm::AttrListPtr::get(Attrs.begin(), Attrs.end());
}
ptr_30->setAttributes(ptr_30_PAL);
llvm::Function* cleanup = call_myCleanup( mod );
builder.CreateCall( cleanup , "cleanup_call");
llvm::CallInst* end_catch = llvm::CallInst::Create(func___cxa_end_catch, "", unwind_block);
builder.CreateRet(ci);
//createCatchHandler( mod , unwind_block );
return result;
}
This gets called like the usual business:
testMain() {
llvm::LLVMContext ctx;
llvm::InitializeNativeTarget();
llvm::StringRef idRef("testModule");
llvm::Module* module = new llvm::Module(idRef, ctx);
std::string jitErrorString;
llvm::ExecutionEngine* execEngine = executionEngine( module , jitErrorString );
llvm::FunctionPassManager* OurFPM = new llvm::FunctionPassManager(module);
llvm::Function *thr = call_my_func_that_throws( module );
llvm::Function* result = createFunctionThatInvokesAnother(ctx, module ,thr);
std::string errorInfo;
llvm::verifyModule(* module, llvm::PrintMessageAction, & errorInfo);
module->dump();
void *fptr = execEngine->getPointerToFunction(result);
unsigned int (*fp)() = (unsigned int (*)())fptr;
try {
unsigned int value = fp();
} catch (...) {
std::cout << " handled a throw from JIT function" << std::endl;
}
}
where my function that throws is:
int myfunc() {
std::cout << " inside JIT calling C/C++ call" << std::endl;
throw 0;
};
llvm::Function* call_my_func_that_throws (llvm::Module* mod) {
std::vector< const llvm::Type* > FuncTy_ex_args;
llvm::FunctionType* FuncTy_ex = llvm::FunctionType::get( llvm::IntegerType::get( mod->getContext() , 32) , FuncTy_ex_args , false);
llvm::Function* result = llvm::Function::Create(FuncTy_ex, llvm::GlobalValue::ExternalLinkage, "myfunc", mod);
result->setCallingConv( llvm::CallingConv::C );
llvm::AttrListPtr PAL;
result->setAttributes( PAL );
llvm::sys::DynamicLibrary::AddSymbol( "myfunc" , (void*) &myfunc );
return result;
}
and my cleanup function is defined in a similar way:
int myCleanup() {
std::cout << " inside JIT calling C/C++ Cleanup" << std::endl;
return 18;
};
llvm::Function* call_myCleanup (llvm::Module* mod) {
std::vector< const llvm::Type* > FuncTy_ex_args;
llvm::FunctionType* FuncTy_ex = llvm::FunctionType::get( llvm::IntegerType::get( mod->getContext() , 32) , FuncTy_ex_args , false);
llvm::Function* result = llvm::Function::Create(FuncTy_ex, llvm::GlobalValue::ExternalLinkage, "myCleanup", mod);
result->setCallingConv( llvm::CallingConv::C );
llvm::AttrListPtr PAL;
result->setAttributes( PAL );
llvm::sys::DynamicLibrary::AddSymbol( "myCleanup" , (void*) &myCleanup );
return result;
}
I've also read this document regarding recent exception handling changes in LLVM, but is not clear how those changes translate to actual, you know, code
Right now the EH code is undergoing a large amount of revision. The demo, if I recall correctly, is not version 2.9, but current development sources - meaning trying to do something with 2.9 is going to be a world of hurt if you try that way.
That said, the EH representation is much better now and numerous patches have gone in to improve the documentation just this week. If you are trying to write a language that uses exceptions via llvm I highly suggest you migrate your code to current development sources.
All of that said, I'm not sure how well exception handling works in the JIT at all right now. It's nominally supported, but you may need to debug the unwind tables that are put into memory to make sure they're correct.