Skip to content

Instantly share code, notes, and snippets.

@DeadMG
Created August 8, 2014 12:57
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save DeadMG/b7b7b9988067e8b32954 to your computer and use it in GitHub Desktop.
Save DeadMG/b7b7b9988067e8b32954 to your computer and use it in GitHub Desktop.
std::shared_ptr<Expression> ClangFunctionType::BuildCall(std::shared_ptr<Expression> val, std::vector<std::shared_ptr<Expression>> args, Context c) {
struct Call : Expression {
Call(Analyzer& an, std::shared_ptr<Expression> self, std::vector<std::shared_ptr<Expression>> args, Context c)
: a(an), args(std::move(args)), val(std::move(self))
{
if (GetType()->AlwaysKeepInMemory()) {
Ret = Wide::Memory::MakeUnique<ImplicitTemporaryExpr>(GetType(), c);
if (!GetType()->IsTriviallyDestructible())
Destructor = GetType()->BuildDestructorCall(Ret, c, true);
else
Destructor = {};
}
}
Type* GetType() override final {
auto fty = dynamic_cast<ClangFunctionType*>(val->GetType());
return fty->GetReturnType();
}
Analyzer& a;
std::vector<std::shared_ptr<Expression>> args;
std::shared_ptr<Expression> val;
std::shared_ptr<Expression> Ret;
std::function<void(CodegenContext&)> Destructor;
llvm::Value* ComputeValue(CodegenContext& con) override final {
auto clangfuncty = dynamic_cast<ClangFunctionType*>(val->GetType());
llvm::Value* llvmfunc = val->GetValue(con);
clang::CodeGen::CodeGenFunction codegenfunc(clangfuncty->from->GetCodegenModule(con), true);
codegenfunc.AllocaInsertPt = con.GetAllocaInsertPoint();
codegenfunc.Builder.SetInsertPoint(con->GetInsertBlock(), con->GetInsertBlock()->end());
clang::CodeGen::CallArgList list;
for (auto&& arg : args) {
auto val = arg->GetValue(con);
if (arg->GetType() == a.GetBooleanType())
val = con->CreateTrunc(val, llvm::IntegerType::getInt1Ty(con));
auto clangty = *arg->GetType()->GetClangType(*clangfuncty->from);
if (arg->GetType()->AlwaysKeepInMemory())
list.add(clang::CodeGen::RValue::getAggregate(val), clangty);
else
list.add(clang::CodeGen::RValue::get(val), clangty);
}
llvm::Instruction* call_or_invoke;
clang::CodeGen::ReturnValueSlot slot;
if (clangfuncty->GetReturnType()->AlwaysKeepInMemory()) {
slot = clang::CodeGen::ReturnValueSlot(Ret->GetValue(con), false);
}
auto result = codegenfunc.EmitCall(clangfuncty->GetCGFunctionInfo(con), llvmfunc, slot, list, nullptr, &call_or_invoke);
// We need to invoke if we're not destructing, and we have something to destroy OR a catch block we may need to jump to.
if (!con.destructing && (con.HasDestructors() || con.EHHandler)) {
llvm::BasicBlock* continueblock = llvm::BasicBlock::Create(con, "continue", con->GetInsertBlock()->getParent());
// If we have a try/catch block, let the catch block figure out what to do.
// Else, kill everything in the scope and resume.
if (auto invokeinst = llvm::dyn_cast<llvm::InvokeInst>(call_or_invoke)) {
invokeinst->setUnwindDest(con.CreateLandingpadForEH());
} else {
auto callinst = llvm::cast<llvm::CallInst>(call_or_invoke);
std::vector<llvm::Value*> args;
for (unsigned i = 0; i < callinst->getNumArgOperands(); ++i)
args.push_back(callinst->getArgOperand(i));
invokeinst = con->CreateInvoke(llvmfunc, continueblock, con.CreateLandingpadForEH(), args);
invokeinst->setAttributes(callinst->getAttributes());
call_or_invoke = invokeinst;
callinst->replaceAllUsesWith(invokeinst);
callinst->eraseFromParent();
}
con->SetInsertPoint(continueblock);
}
if (!clangfuncty->GetReturnType()->IsTriviallyDestructible())
con.AddDestructor(Destructor);
if (call_or_invoke->getType() == clangfuncty->GetReturnType()->GetLLVMType(con))
return call_or_invoke;
if (result.isScalar()) {
auto val = result.getScalarVal();
if (val->getType() == llvm::IntegerType::getInt1Ty(con))
return con->CreateZExt(val, llvm::IntegerType::getInt8Ty(con));
return val;
}
auto val = result.getAggregateAddr();
if (clangfuncty->GetReturnType()->IsReference() || clangfuncty->GetReturnType()->AlwaysKeepInMemory())
return val;
return con->CreateLoad(val);
}
};
return Wide::Memory::MakeUnique<Call>(analyzer, std::move(val), std::move(args), c);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment