#include <iostream>

#include "llvm/Module.h"
#include "llvm/Function.h"
#include "llvm/PassManager.h"
#include "llvm/CallingConv.h"
#include "llvm/Analysis/Verifier.h"
#include "llvm/Assembly/PrintModulePass.h"
#include "llvm/Support/IRBuilder.h"
#include "llvm/Support/raw_ostream.h"

using namespace llvm;

int main()
{
    LLVMContext& ctx = makeLLVMModule();

    Module* m = new Module("test");

    Constant* c = m->getOrInsertFunction("mul_add",
     /*ret type*/                           IntegerType::get(ctx,32),
     /*args*/                               IntegerType::get(ctx,32),
                                            IntegerType::get(ctx, 32),
                                            IntegerType::get(ctx,32),
     /*varargs terminated with null*/       NULL);

     Function* mul_add = cast<Function>(c);
     mul_add->setCallingConv(CallingConv::C);


     Function::arg_iterator args = mul_add->arg_begin();
      Value* x = args++;
      x->setName("x");
      Value* y = args++;
      y->setName("y");
      Value* z = args++;
      z->setName("z");

  BasicBlock* block = BasicBlock::Create(getGlobalContext(), "entry", mul_add);
   IRBuilder<> builder(block);

   Value* tmp = builder.CreateBinOp(Instruction::Mul,
                                      x, y, "tmp");
     Value* tmp2 = builder.CreateBinOp(Instruction::Add,
                                       tmp, z, "tmp2");

     builder.CreateRet(tmp2);

    verifyModule(*m, PrintMessageAction);

    PassManager man;
    man.add(createPrintModulePass(&outs()));
    man.run(*m);

    delete m;

    return 0;
}

