Skip to content

Instantly share code, notes, and snippets.

@rainyx
Created April 18, 2022 06:07
Show Gist options
  • Save rainyx/ad778d2c6dda5112f0a5dd6fa832e667 to your computer and use it in GitHub Desktop.
Save rainyx/ad778d2c6dda5112f0a5dd6fa832e667 to your computer and use it in GitHub Desktop.
Create IR code easily

DO NOT USE IT IN YOU PRODUCTION.

This is a toy project, it has lot of unimplemented code and strict assertions.

//
// Created by rainyx on 2022/4/16.
//
#include "IRMaker.h"
using namespace llvm;
using namespace std;
static bool hasTerminator(BasicBlock *BB) {
return BB->getTerminator() != nullptr;
}
static vector<Value *>unwrap(const ArrayRef<Val> &Arr) {
vector<Value *> Unwrapped;
for (auto V : Arr)
Unwrapped.push_back(V.unwrap());
return Unwrapped;
}
void IRMaker::when(const Val &Cond, const std::function<void (IRMaker &)> &IfBlk) {
BasicBlock *IfBB = BasicBlock::Create(Ctx, "If.body", F);
BasicBlock *EndBB = BasicBlock::Create(Ctx, "If.end", F);
BranchInst::Create(IfBB, EndBB, Cond.unwrap(), BB);
auto IfMaker = IRMaker(IfBB);
SubMaker = &IfMaker;
IfBlk(IfMaker);
SubMaker = nullptr;
if (!hasTerminator(IfMaker.BB))
BranchInst::Create(EndBB, IfMaker.BB);
BB = EndBB;
}
void IRMaker::when(const Val &Cond, const std::function<void (IRMaker &)> &IfBlk,
const std::function<void (IRMaker &)> &ElseBlk) {
BasicBlock *IfBB = BasicBlock::Create(Ctx, "If.True", F);
BasicBlock *ElseBB = BasicBlock::Create(Ctx, "If.False", F);
BasicBlock *EndBB = BasicBlock::Create(Ctx, "If.End", F);
BranchInst::Create(IfBB, ElseBB, Cond.unwrap(), BB);
auto IfMaker = IRMaker(IfBB);
SubMaker = &IfMaker;
IfBlk(IfMaker);
SubMaker = nullptr;
if (!hasTerminator(IfMaker.BB))
BranchInst::Create(EndBB, IfMaker.BB);
auto ElseMaker = IRMaker(ElseBB);
SubMaker = &ElseMaker;
ElseBlk(ElseMaker);
SubMaker = nullptr;
if (!hasTerminator(ElseMaker.BB))
BranchInst::Create(EndBB, ElseMaker.BB);
BB = EndBB;
}
void IRMaker::loopWhen(const std::function<Val (IRMaker &)> &CondBlk,
const std::function<void (IRMaker &)> &BodyBlk) {
BasicBlock *CondBB = BasicBlock::Create(Ctx, "Loop.Cond", F);
BasicBlock *BodyBB = BasicBlock::Create(Ctx, "Loop.Body", F);
BasicBlock *EndBB = BasicBlock::Create(Ctx, "Loop.End", F);
IRMaker CondMaker(CondBB);
SubMaker = &CondMaker;
Val Cond = CondBlk(CondMaker);
SubMaker = nullptr;
BranchInst::Create(CondBB, BB);
BranchInst::Create(BodyBB, EndBB, Cond.unwrap(), CondBB);
auto BodyMaker = IRMaker(BodyBB);
SubMaker = &BodyMaker;
BodyBlk(BodyMaker);
SubMaker = nullptr;
BranchInst::Create(CondBB, BodyMaker.BB);
BB = EndBB;
}
void IRMaker::loopUntil(const std::function<void (IRMaker &)> &BodyBlk,
const std::function<Val (IRMaker &)> &UntilBlk) {
BasicBlock *CondBB = BasicBlock::Create(Ctx, "Loop.Cond", F);
BasicBlock *BodyBB = BasicBlock::Create(Ctx, "Loop.Body", F);
BasicBlock *EndBB = BasicBlock::Create(Ctx, "Loop.End", F);
IRMaker CondMaker(CondBB);
SubMaker = &CondMaker;
Val Cond = UntilBlk(CondMaker);
SubMaker = nullptr;
BranchInst::Create(BodyBB, BB);
BranchInst::Create(EndBB, BodyBB, Cond.unwrap(), CondBB);
auto BodyMaker = IRMaker(BodyBB);
SubMaker = &BodyMaker;
BodyBlk(BodyMaker);
SubMaker = nullptr;
BranchInst::Create(CondBB, BodyMaker.BB);
BB = EndBB;
}
Val IRMaker::isNull(const Val &V, const Twine &Name) {
Val Null = null(V.unwrap()->getType());
return icmp(ICmpInst::ICMP_EQ, V, Null, Name);
}
Val IRMaker::isNotNull(const Val &V, const Twine &Name) {
Val Null = null(V.unwrap()->getType());
return icmp(ICmpInst::ICMP_NE, V, Null, Name);
}
Val IRMaker::call(Function *F, const ArrayRef<Val> &Args, const Twine &Name) {
return wrap(CallInst::Create(F, unwrap(Args), Name, getInsertionPoint()));
}
void IRMaker::ret(const Val &V) {
ReturnInst::Create(Ctx, V.unwrap(), getInsertionPoint());
}
void IRMaker::retNull() {
ReturnInst::Create(Ctx, null(F->getReturnType()).unwrap(), getInsertionPoint());
}
void IRMaker::ret() {
ReturnInst::Create(Ctx, getInsertionPoint());
}
Val IRMaker::alloc(const Val &InitialValue, const Twine &Name) {
Type *Ty = InitialValue.getType();
Val Ptr = alloc(Ty, nullptr, Name);
store(InitialValue, Ptr);
return Ptr;
}
Val IRMaker::alloc(Type *Ty, const Val *ArraySize, const Twine &Name) {
Value *ArrSz = ArraySize ? ArraySize->unwrap() : nullptr;
return wrap(new AllocaInst(Ty, 0, ArrSz, Name, getInsertionPoint()));
}
Val IRMaker::malloc(Type *Ty, const Twine &Name) {
return malloc(Ty, nullptr, Name);
}
Val IRMaker::malloc(Type *Ty, const Val *ArraySize, const Twine &Name) {
Type *ITy = i32Ty();
Constant *AllocSize = ConstantExpr::getSizeOf(Ty);
AllocSize = ConstantExpr::getTruncOrBitCast(AllocSize, ITy);
Value *ArrSz = ArraySize ? ArraySize->unwrap() : nullptr;
Instruction *Malloc = CallInst::CreateMalloc(getInsertionPoint(), ITy, Ty, AllocSize,
ArrSz, nullptr, "");
insertAtEnd(Malloc);
return wrap(Malloc);
}
void IRMaker::free(const Val &Ptr) {
Instruction *Free = CallInst::CreateFree(Ptr.unwrap(), getInsertionPoint());
insertAtEnd(Free);
}
Val IRMaker::add(const Val &Lhs, const Val &Rhs, const Twine &Name) {
return wrap(BinaryOperator::Create(Instruction::Add, Lhs.unwrap(), Rhs.unwrap(), Name, getInsertionPoint()));
}
Val IRMaker::sub(const Val &Lhs, const Val &Rhs, const Twine &Name) {
return bo(Instruction::Sub, Lhs, Rhs, Name);
}
Val IRMaker::mul(const Val &Lhs, const Val &Rhs, const Twine &Name) {
return bo(Instruction::Mul, Lhs, Rhs, Name);
}
Val IRMaker::sdiv(const Val &Lhs, const Val &Rhs, const Twine &Name) {
return bo(Instruction::SDiv, Lhs, Rhs, Name);
}
Val IRMaker::udiv(const Val &Lhs, const Val &Rhs, const Twine &Name) {
return bo(Instruction::UDiv, Lhs, Rhs, Name);
}
Val IRMaker::bitXor(const Val &Lhs, const Val &Rhs, const Twine &Name) {
return bo(Instruction::Xor, Lhs, Rhs, Name);
}
Val IRMaker::aAnd(const Val &Lhs, const Val &Rhs, const Twine &Name) {
return bo(Instruction::And, Lhs, Rhs, Name);
}
Val IRMaker::lAnd(const Val &Lhs, const Val &Rhs, const Twine &Name) {
return wrap(SelectInst::Create(Lhs.unwrap(), Rhs.unwrap(), ConstantInt::getNullValue(Rhs.unwrap()->getType()), Name, getInsertionPoint()));
}
Val IRMaker::aOr(const Val &Lhs, const Val &Rhs, const Twine &Name) {
return bo(Instruction::Or, Lhs, Rhs, Name);
}
Val IRMaker::lOr(const Val &Lhs, const Val &Rhs, const Twine &Name) {
return wrap(SelectInst::Create(Lhs.unwrap(), ConstantInt::getAllOnesValue(Rhs.unwrap()->getType()), Rhs.unwrap(), Name, getInsertionPoint()));
}
Val IRMaker::shl(const Val &Lhs, const Val &Rhs, const Twine &Name) {
return bo(Instruction::Shl, Lhs, Rhs, Name);
}
Val IRMaker::aShr(const Val &Lhs, const Val &Rhs, const Twine &Name) {
return bo(Instruction::AShr, Lhs, Rhs, Name);
}
Val IRMaker::lShr(const Val &Lhs, const Val &Rhs, const Twine &Name) {
return bo(Instruction::LShr, Lhs, Rhs, Name);
}
Val IRMaker::bo(Instruction::BinaryOps op, const Val &Lhs, const Val &Rhs, const Twine &Name) {
return wrap(BinaryOperator::Create(op, Lhs.unwrap(), Rhs.unwrap(), Name, getInsertionPoint()));
}
Val IRMaker::isGE(const Val &Lhs, const Val &Rhs, bool IsSigned, const Twine &Name) {
return icmp(IsSigned ? ICmpInst::ICMP_SGE : ICmpInst::ICMP_UGE, Lhs, Rhs, Name);
}
Val IRMaker::isGT(const Val &Lhs, const Val &Rhs, bool IsSigned, const Twine &Name) {
return icmp(IsSigned ? ICmpInst::ICMP_SGT : ICmpInst::ICMP_UGT, Lhs, Rhs, Name);
}
Val IRMaker::isLE(const Val &Lhs, const Val &Rhs, bool IsSigned, const Twine &Name) {
return icmp(IsSigned ? ICmpInst::ICMP_SLE : ICmpInst::ICMP_ULE, Lhs, Rhs, Name);
}
Val IRMaker::isLT(const Val &Lhs, const Val &Rhs, bool IsSigned, const Twine &Name) {
return icmp(IsSigned ? ICmpInst::ICMP_SLT : ICmpInst::ICMP_ULT, Lhs, Rhs, Name);
}
Val IRMaker::isEQ(const Val &Lhs, const Val &Rhs, const Twine &Name) {
return icmp(llvm::CmpInst::ICMP_EQ, Lhs, Rhs, Name);
}
Val IRMaker::isNE(const Val &Lhs, const Val &Rhs, const Twine &Name) {
return icmp(llvm::CmpInst::ICMP_NE, Lhs, Rhs, Name);
}
Val IRMaker::icmp(ICmpInst::Predicate P, const Val &Lhs, const Val &Rhs, const Twine &Name) {
auto ICMP = new ICmpInst(P, Lhs.unwrap(), Rhs.unwrap(), Name);
insertAtEnd(ICMP);
return wrap(ICMP);
}
Val IRMaker::gep(const Val &Ptr, const ArrayRef<Val> &IdxList, const Twine &Name) {
Value *RawPtr = Ptr.unwrap();
Type *PointeeType = RawPtr->getType()->getPointerElementType();
Value *GEP = GetElementPtrInst::Create(PointeeType, RawPtr, unwrap(IdxList), Name + "_GEP", getInsertionPoint());
return wrap(GEP);
}
Val IRMaker::gep(const Val &Ptr, const Val &Idx, const Twine &Name) {
Value *RawPtr = Ptr.unwrap();
Type *PointeeType = RawPtr->getType()->getPointerElementType();
Value *GEP = GetElementPtrInst::Create(PointeeType, RawPtr, Idx.unwrap(), Name + "_GEP", getInsertionPoint());
return wrap(GEP);
}
Val IRMaker::load(const Val &Ptr, const Twine &Name) {
Value *RawPtr = Ptr.unwrap();
Value *Value = new LoadInst(RawPtr->getType()->getPointerElementType(), RawPtr, Name, getInsertionPoint());
return wrap(Value);
}
Val IRMaker::load(const Val &Ptr, const ArrayRef<Val> &IdxList, const Twine &Name) {
Val GEP = gep(Ptr, IdxList, Name);
return load(GEP, Name);
}
Val IRMaker::load(const Val &Ptr, const Val &Idx, const Twine &Name) {
Val GEP = gep(Ptr, Idx, Name);
return load(GEP, Name);
}
void IRMaker::store(const Val &Ptr, const ArrayRef<Val> &IdxList, const Val &Ele) {
Val GEP = gep(Ptr, IdxList);
store(Ele, GEP);
}
void IRMaker::store(const Val &Ptr, const Val &Idx, const Val &Ele) {
Val GEP = gep(Ptr, Idx);
store(Ele, GEP);
}
void IRMaker::store(const Val &V, const Val &Ptr) {
new StoreInst(V.unwrap(), Ptr.unwrap(), getInsertionPoint());
}
Val IRMaker::null(Type *Ty) {
return wrap(Constant::getNullValue(Ty));
}
Val IRMaker::bitCast(const Val &Ptr, Type *DestTy, const Twine &Name) {
return cast(Instruction::BitCast, Ptr, DestTy, Name);
}
Val IRMaker::ptrToInt(const Val &Ptr, Type *DestTy, const Twine &Name) {
return cast(Instruction::PtrToInt, Ptr, DestTy, Name);
}
Val IRMaker::intToPtr(const Val &V, Type *DestTy, const Twine &Name) {
return cast(Instruction::IntToPtr, V, DestTy, Name);
}
Val IRMaker::cast(CastInst::CastOps Op, const Val &Ptr, Type *DestTy, const Twine &Name) {
auto CI = CastInst::Create(Op, Ptr.unwrap(), DestTy, Name);
insertAtEnd(CI);
return wrap(CI);
}
BasicBlock *IRMaker::getInsertionPoint() const {
return SubMaker ? SubMaker->getInsertionPoint() : BB;
}
void IRMaker::insertAtEnd(Instruction *Inst) {
BasicBlock *InsertionPoint = getInsertionPoint();
InsertionPoint->getInstList().insert(InsertionPoint->end(), Inst);
}
void Val::store(const Val &Idx, const Val &Ele) {
M.store(*this, Idx, Ele);
}
void Val::store(const ArrayRef<Val> &IdxList, const Val &Ele) {
M.store(*this, IdxList, Ele);
}
void Val::store(const ArrayRef<Value *> &IdxList, const Val &Ele) {
store(M.wrap(IdxList), Ele);
}
Val Val::load(uint32_t Idx) const {
return load(M.i32(Idx));
}
Val Val::load(const Val &Idx) const {
return M.load(*this, Idx);
}
Val Val::load(const ArrayRef<Val> &IdxList) const {
return M.load(*this, IdxList);
}
Val Val::load(const ArrayRef<Value *> &IdxList) const {
return load(M.wrap(IdxList));
}
Val Val::gep(const ArrayRef<Val> &IdxList) const {
return M.gep(*this, IdxList);
}
Val Val::gep(const ArrayRef<Value *> &IdxList) const {
return gep(M.wrap(IdxList));
}
Val Val::gep(const Val &Idx) const {
return M.gep(*this, Idx);
}
Val Val::load() const {
return M.load(*this);
}
void Val::store(const Val &V) {
M.store(V, *this);
}
void Val::store(uint32_t Idx, const Val &Ele) {
return store(M.i32(Idx), Ele);
}
Val Val::bitCast(Type *DestTy) {
return M.bitCast(*this, DestTy);
}
Val Val::ptrToInt(Type *DestTy) {
return M.ptrToInt(*this, DestTy);
}
Val Val::intToPtr(Type *DestTy) {
return M.intToPtr(*this, DestTy);
}
Val Val::isNull() {
return M.isNull(*this);
}
Val Val::isNotNull() {
return M.isNotNull(*this);
}
Val Val::operator==(const Val &Rhs) {
return M.isEQ(*this, Rhs);
}
Val Val::operator==(uint64_t Rhs) {
return operator==(wrapInt(Rhs));
}
Val Val::operator!=(const Val &Rhs) {
return M.isNE(*this, Rhs);
}
Val Val::operator!=(uint64_t Rhs) {
return operator!=(wrapInt(Rhs));
}
Val Val::operator<(const Val &Rhs) {
return M.isLT(*this, Rhs, Signed);
}
Val Val::operator<=(const Val &Rhs) {
return M.isLE(*this, Rhs, Signed);
}
Val Val::operator>(const Val &Rhs) {
return M.isGT(*this, Rhs, Signed);
}
Val Val::operator>=(const Val &Rhs) {
return M.isGE(*this, Rhs, Signed);
}
Val Val::operator>=(uint64_t Rhs) {
return operator>=(wrapInt(Rhs));
}
Val Val::operator+(const Val &Rhs) {
return M.add(*this, Rhs);
}
Val Val::operator+(uint64_t Rhs) {
return operator+(wrapInt(Rhs));
}
Val Val::operator-(const Val &Rhs) {
return M.sub(*this, Rhs);
}
Val Val::operator-(uint64_t Rhs) {
return operator-(wrapInt(Rhs));
}
Val Val::operator*(const Val &Rhs) {
return M.mul(*this, Rhs);
}
Val Val::operator*(uint64_t Rhs) {
return operator*(wrapInt(Rhs));
}
Val Val::operator/(const Val &Rhs) {
if (Signed) {
return M.sdiv(*this, Rhs);
} else {
return M.udiv(*this, Rhs);
}
}
Val Val::operator/(uint64_t Rhs) {
return operator/(wrapInt(Rhs));
}
Val Val::operator&(const Val &Rhs) {
return M.aAnd(*this, Rhs);
}
Val Val::operator&&(const Val &Rhs) {
return M.lAnd(*this, Rhs);
}
Val Val::operator|(const Val &Rhs) {
return M.aOr(*this, Rhs);
}
Val Val::operator||(const Val &Rhs) {
return M.lOr(*this, Rhs);
}
Val Val::operator^(const Val &Rhs) {
return M.bitXor(*this, Rhs);
}
Val Val::operator<<(const Val &Rhs) {
return M.shl(*this, Rhs);
}
Val Val::operator>>(const Val &Rhs) {
if (getType()->getIntegerBitWidth() == 1) {
return M.lShr(*this, Rhs);
} else {
return M.aShr(*this, Rhs);
}
}
Val Val::operator*() {
return load();
}
Val Val::wrapInt(uint64_t V) {
return M.i(cast<IntegerType>(getType()), V);
}
//
// Created by rainyx on 2022/4/16.
//
#ifndef MYTRANS_IRMAKER_H
#define MYTRANS_IRMAKER_H
#include "llvm/IR/Instructions.h"
#include "llvm/IR/Constants.h"
using namespace llvm;
using namespace std;
/**
* IRMaker creates highly readable IR code in LLVM project.
* It includes widely used functions, such as variable allocation, memory access and flow control, etc.
* With IRMaker, you don't need to care about when you need to create BB(BasicBlock) and complicated relationships between BBs.
* Nested lambda statements help you to organize your IR logic, just like high level programming language.
* // Demo: Generate Fibonacci sequence.
* // C version:
* int fib(int n) {
* if (n==1||n==2)
* return 1;
* return fib(n-1) + fib(n-2);
* }
*
* // IR version:
* Function *F = createFn("fib");
* IRMaker M(F);
*
* Val N = M.arg(0);
* M.when(N == 1 || N == 2, [&](IRMaker &IfM) {
* IfM.ret(IfM.i32(1))
* });
* M.ret(M.call(F, {N-1}) + M.call(F, {N-2});
*
* // Demo: Binary tree search with stack.
* // C Version:
* Node *BTS(Node *node, int v) {
* Node *stack[100];
* int stackIdx = 0;
* stack[0] = node;
* while (stackIdx >=0 ) {
* Node *top = stack[stackIdx--];
* if (top->v == v)
* return top;
* if (top->right)
* stack[++stackIdx] = top->right;
* if (top->left)
* stack[++stackIdx] = top->left;
* }
*
* return NULL;
* }
*
* // IR version:
* Function *F = createFn("BTS");
* IRMaker M(F);
* Val Node = M.arg(0);
* Val V = M.arg(1);
*
* Val StackSize = M.i32(100);
* Val StackPtr = M.alloc(NodePtrTy, &StackSize); // Alloc array with 100 elements.
* Val StackIdxPtr = M.alloc(M.i32(0)); // Alloc i32 variable with initial value 0.
* StackPtr.store(0, Node); // stack[0] = node
*
* // while (stackIdx >=0 )
* M.loopWhen([&](IRMaker &CondM) {
* return *StackIdxPtr >= 0;
* }, [&](IRMaker &LoopM) {
* Val TopPtr = StackPtr.load(*StackIdxPtr); // top = stack[stackIdx]
* StackIdxPtr.store(*StackIdxPtr - 1); // stackIdx --
* M.when(TopPtr.load(Idx_Node_Value) == V, [&](IRMaker &IfM) {
* IfM.ret(TopPtr);
* });
*
* // Push right if needed.
* M.when(TopPtr.load(Idx_Node_Right).isNotNull(), [&](IRMaker &IfM) {
* StackIdxPtr.store(*StackIdxPtr + 1); // stackIdx ++
* StackPtr.store(*StackIdxPtr, TopPtr.load(Idx_Node_Right)); // stack[stackIdx] = top->right;
* });
*
* // Push left if needed.
* M.when(TopPtr.load(Idx_Node_Left).isNotNull(), [&](IRMaker &IfM) {
* StackIdxPtr.store(*StackIdxPtr + 1); // stackIdx ++
* StackPtr.store(*StackIdxPtr, TopPtr.load(Idx_Node_Left)); // stack[stackIdx] = top->left;
* });
* });
*
* M.retNull();
*/
class IRMaker;
class Val {
public:
Val(Value *Raw, IRMaker &M): Raw(Raw), M(M) {}
Val &s() { Signed = true; return *this; }
Val &u() { Signed = false; return *this; }
Value *unwrap() const { return Raw; }
Type *getType() const { return Raw->getType(); }
Val gep(const Val &Idx) const;
Val gep(const ArrayRef<Val> &IdxList) const;
Val gep(const ArrayRef<Value *> &IdxList) const;
Val load() const;
Val load(uint32_t Idx) const;
Val load(const Val &Idx) const;
Val load(const ArrayRef<Val> &IdxList) const;
Val load(const ArrayRef<Value *> &IdxList) const;
void store(const Val &V);
void store(uint32_t Idx, const Val &Ele);
void store(const Val &Idx, const Val &Ele);
void store(const ArrayRef<Val> &IdxList, const Val &Ele);
void store(const ArrayRef<Value *> &IdxList, const Val &Ele);
Val bitCast(Type *DestTy);
Val ptrToInt(Type *DestTy);
Val intToPtr(Type *DestTy);
Val isNull();
Val isNotNull();
Val operator==(const Val &Rhs);
Val operator==(uint64_t Rhs);
Val operator!=(const Val &Rhs);
Val operator!=(uint64_t Rhs);
Val operator<(const Val &Rhs);
Val operator<=(const Val &Rhs);
Val operator>(const Val &Rhs);
Val operator>=(const Val &Rhs);
Val operator>=(uint64_t Rhs);
Val operator+(const Val &Rhs);
Val operator+(uint64_t Rhs);
Val operator-(const Val &Rhs);
Val operator-(uint64_t Rhs);
Val operator*(const Val &Rhs);
Val operator*(uint64_t Rhs);
Val operator/(const Val &Rhs);
Val operator/(uint64_t Rhs);
Val operator&&(const Val &Rhs);
Val operator&(const Val &Rhs);
Val operator||(const Val &Rhs);
Val operator|(const Val &Rhs);
Val operator^(const Val &Rhs);
Val operator>>(const Val &Rhs);
Val operator<<(const Val &Rhs);
Val operator*();
private:
Val wrapInt(uint64_t V);
private:
Value *Raw;
IRMaker &M;
bool Signed {true}; // Default value is signed
};
class IRMaker {
public:
explicit IRMaker(BasicBlock *BB): BB(BB), F(BB->getParent()), Ctx(F->getContext()) {}
IRMaker(Function *F): F(F), Ctx(F->getContext()) {
if (!F->getBasicBlockList().empty())
report_fatal_error("Function BBs is not empty!");
BasicBlock *EntryBB = BasicBlock::Create(Ctx, "Entry", F);
BB = EntryBB;
}
Val wrap(Value *V) {
return Val(V, *this);
}
vector<Val> wrap(const ArrayRef<Value *> &Arr) {
vector<Val> Wrapped;
for (auto V : Arr)
Wrapped.push_back(wrap(V));
return Wrapped;
}
// if (Cond) { ... } else { ... }
void when(const Val &Cond, const std::function<void (IRMaker &)> &IfBlk,
const std::function<void (IRMaker &)> &ElseBlk);
// if (Cond) { ... }
void when(const Val &Cond, const std::function<void (IRMaker &)> &IfBlk);
// while (Cond) { ... }
void loopWhen(const std::function<Val (IRMaker &)> &CondBlk,
const std::function<void (IRMaker &)> &BodyBlk);
// do { ... } while (!Cond)
void loopUntil(const std::function<void (IRMaker &)> &BodyBlk,
const std::function<Val (IRMaker &)> &UntilBlk);
Val arg(unsigned Idx) { return wrap(F->getArg(Idx)); }
Val isNull(const Val &V, const Twine &Name = "");
Val isNotNull(const Val &V, const Twine &Name = "");
Val isGE(const Val &Lhs, const Val &Rhs, bool IsSigned, const Twine &Name = "");
Val isGT(const Val &Lhs, const Val &Rhs, bool IsSigned, const Twine &Name = "");
Val isLE(const Val &Lhs, const Val &Rhs, bool IsSigned, const Twine &Name = "");
Val isLT(const Val &Lhs, const Val &Rhs, bool IsSigned, const Twine &Name = "");
Val isEQ(const Val &Lhs, const Val &Rhs, const Twine &Name = "");
Val isNE(const Val &Lhs, const Val &Rhs, const Twine &Name = "");
Val call(Function *F, const ArrayRef<Val> &Args, const Twine &Name = "");
void ret(const Val &V);
void retNull();
void ret();
Val gep(const Val &Ptr, const Val &Idx, const Twine &Name = "");
Val gep(const Val &Ptr, const ArrayRef<Val> &IdxList, const Twine &Name = "");
Val load(const Val &Ptr, const Twine &Name = "");
Val load(const Val &Ptr, const Val &Idx, const Twine &Name = "");
Val load(const Val &Ptr, const ArrayRef<Val> &IdxList, const Twine &Name = "");
void store(const Val &V, const Val &Ptr);
void store(const Val &Ptr, const Val &Idx, const Val &Ele);
void store(const Val &Ptr, const ArrayRef<Val> &IdxList, const Val &Ele);
Val alloc(const Val &InitialValue, const Twine &Name = "");
Val alloc(Type *Ty, const Val *ArraySize, const Twine &Name = "");
Val malloc(Type *Ty, const Twine &Name = "");
Val malloc(Type *Ty, const Val *ArraySize, const Twine &Name = "");
void free(const Val &Ptr);
Val add(const Val &Lhs, const Val &Rhs, const Twine &Name = "");
Val sub(const Val &Lhs, const Val &Rhs, const Twine &Name = "");
Val mul(const Val &Lhs, const Val &Rhs, const Twine &Name = "");
Val sdiv(const Val &Lhs, const Val &Rhs, const Twine &Name = "");
Val udiv(const Val &Lhs, const Val &Rhs, const Twine &Name = "");
Val bitXor(const Val &Lhs, const Val &Rhs, const Twine &Name = "");
Val aAnd(const Val &Lhs, const Val &Rhs, const Twine &Name = "");
Val lAnd(const Val &Lhs, const Val &Rhs, const Twine &Name = "");
Val aOr(const Val &Lhs, const Val &Rhs, const Twine &Name = "");
Val lOr(const Val &Lhs, const Val &Rhs, const Twine &Name = "");
Val shl(const Val &Lhs, const Val &Rhs, const Twine &Name = "");
Val aShr(const Val &Lhs, const Val &Rhs, const Twine &Name = "");
Val lShr(const Val &Lhs, const Val &Rhs, const Twine &Name = "");
Val bo(Instruction::BinaryOps op, const Val &Lhs, const Val &Rhs, const Twine &Name = "");
Val icmp(ICmpInst::Predicate P, const Val &Lhs, const Val &Rhs, const Twine &Name = "");
Val bitCast(const Val &Ptr, Type *DestTy, const Twine &Name = "");
Val ptrToInt(const Val &Ptr, Type *DestTy, const Twine &Name = "");
Val intToPtr(const Val &V, Type *DestTy, const Twine &Name = "");
Val cast(CastInst::CastOps Op, const Val &V, Type *DestTy, const Twine &Name = "");
Val null(Type *Ty);
Val i8(uint8_t V) { return i(i8Ty(), V); }
Val i16(uint16_t V) { return i(i16Ty(), V); }
Val i32(uint32_t V) { return i(i32Ty(), V); }
Val i64(uint64_t V) { return i(i64Ty(), V); }
Val i(IntegerType *Ty, uint64_t V) { return wrap(ConstantInt::get(Ty, V)); }
IntegerType *i8Ty() { return IntegerType::getInt8Ty(Ctx); }
IntegerType *i16Ty() { return IntegerType::getInt16Ty(Ctx); }
IntegerType *i32Ty() { return IntegerType::getInt32Ty(Ctx); }
IntegerType *i64Ty() { return IntegerType::getInt64Ty(Ctx); }
PointerType *i8PtrTy() { return IntegerType::getInt8PtrTy(Ctx); }
PointerType *i16PtrTy() { return IntegerType::getInt16PtrTy(Ctx); }
PointerType *i32PtrTy() { return IntegerType::getInt32PtrTy(Ctx); }
PointerType *i64PtrTy() { return IntegerType::getInt64PtrTy(Ctx); }
private:
BasicBlock *getInsertionPoint() const;
void insertAtEnd(Instruction *I);
private:
BasicBlock *BB;
Function *F;
LLVMContext &Ctx;
IRMaker *SubMaker {nullptr};
};
#endif //MYTRANS_IRMAKER_H
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment