#include "llvm/IR/DerivedTypes.h"
#include "Base/CGTypes/CGType.h"
#include "CGModule.h"
#include "DIBuilder.h"
#include "IRBuilder.h"
namespace Cangjie {
namespace CodeGen {
static constexpr uint64_t MIN_ANDROID_ARM32_ENUM_ALIGN = 4;
IRBuilder2::IRBuilder2(CGModule& cgMod) : LLVMIRBuilder2(cgMod.GetLLVMContext()), cgMod(cgMod)
{
if (cgMod.GetCGContext().GetCompileOptions().fastMathMode) {
llvm::FastMathFlags fmf;
fmf.setFast(true);
setFastMathFlags(fmf);
}
}
CGContext& IRBuilder2::GetCGContext() const
{
return cgMod.GetCGContext();
}
llvm::LLVMContext& IRBuilder2::GetLLVMContext() const
{
return cgMod.GetLLVMContext();
}
llvm::CallBase* IRBuilder2::CreateCallOrInvoke(
llvm::FunctionType* fTy, llvm::Value* callee, std::vector<llvm::Value*> args)
{
auto unwindBlock = cgMod.GetCGContext().TopUnwindBlockStack();
if (unwindBlock.has_value()) {
auto currentBB = GetInsertBlock();
auto normalDest = llvm::BasicBlock::Create(getContext(), "normalDest", currentBB->getParent());
normalDest->moveAfter(currentBB);
auto resultVal = CreateInvoke(fTy, callee, normalDest, unwindBlock.value(), args);
SetInsertPoint(normalDest);
return resultVal;
} else {
return CreateCall(fTy, callee, args);
}
}
llvm::CallBase* IRBuilder2::CreateCallOrInvoke(llvm::Function* callee, const llvm::ArrayRef<llvm::Value*> args)
{
auto unwindBlock = cgMod.GetCGContext().TopUnwindBlockStack();
llvm::CallBase* callBase = nullptr;
if (unwindBlock.has_value()) {
auto currentBB = GetInsertBlock();
auto normalDest = llvm::BasicBlock::Create(getContext(), "normalDest", currentBB->getParent());
normalDest->moveAfter(currentBB);
callBase = CreateInvoke(callee, normalDest, unwindBlock.value(), args);
SetInsertPoint(normalDest);
} else {
callBase = CreateCall(callee, args);
}
if (callee->hasStructRetAttr()) {
callBase->addAttributeAtIndex(
static_cast<unsigned>(llvm::AttributeList::FirstArgIndex), llvm::Attribute::NoAlias);
auto sRetAttr =
llvm::Attribute::getWithStructRetType(callBase->getContext(), callee->getArg(0)->getParamStructRetType());
callBase->addAttributeAtIndex(static_cast<unsigned>(llvm::AttributeList::FirstArgIndex), sRetAttr);
}
return callBase;
}
void IRBuilder2::SetInsertPointToAllocas(llvm::Function* curFunc)
{
auto entryBB = &curFunc->getEntryBlock();
if (entryBB->getName() != "allocas") {
auto allocasBB = llvm::BasicBlock::Create(getContext(), "allocas", GetInsertFunction(), entryBB);
SetInsertPoint(allocasBB);
auto inst = CreateBr(entryBB);
inst->setDebugLoc(llvm::DebugLoc());
entryBB = allocasBB;
}
SetInsertPoint(entryBB->getTerminator());
}
llvm::AllocaInst* IRBuilder2::CreateEntryAlloca(llvm::Type* type, llvm::Value* arraySize, const llvm::Twine& name)
{
CJC_ASSERT(type);
auto curPt = LLVMIRBuilder2::GetInsertPoint();
auto curBB = LLVMIRBuilder2::GetInsertBlock();
CJC_ASSERT(curBB && "Can't get the current basic block.");
auto curFunc = curBB->getParent();
CJC_ASSERT(curFunc && "Can't get the current function.");
auto currentLoc = getCurrentDebugLocation();
SetInsertPointToAllocas(curFunc);
auto allocaInst = LLVMIRBuilder2::CreateAlloca(type, arraySize, name);
LLVMIRBuilder2::SetInsertPoint(curBB, curPt);
SetCurrentDebugLocation(currentLoc);
return allocaInst;
}
llvm::Instruction* IRBuilder2::CreateEntryAlloca(const CGType& cgType, const llvm::Twine& name)
{
if (cgType.GetSize()) {
auto allocatedType = cgType.IsCGFunction()
? dynamic_cast<const CGFunctionType&>(cgType).GetLLVMFunctionType()->getPointerTo()
: cgType.GetLLVMType();
auto allocaInst = CreateEntryAlloca(allocatedType, nullptr, name);
auto& options = cgMod.GetCGContext().GetCompileOptions();
auto cgEnumType = cgType.IsCGEnum() ? StaticCast<const CGEnumType*>(&cgType) : nullptr;
auto isOptionLikeNonRef = cgEnumType && cgEnumType->IsOptionLikeNonRef();
auto isAllAssociatedValuesAreNonRef = cgEnumType && cgEnumType->IsAllAssociatedValuesAreNonRef();
if ((allocatedType->isStructTy() && options.enableCompileDebug &&
options.optimizationLevel == GlobalOptions::OptimizationLevel::O0) ||
(options.cjdbMode && isOptionLikeNonRef)) {
(void)CreateMemsetStructWith0(allocaInst);
}
auto& target = GetCGContext().GetCompileOptions().target;
if (CGEnumType::NeedAndroidArm32AlignedEnumLayout(target) && cgEnumType &&
isAllAssociatedValuesAreNonRef) {
allocaInst->setAlignment(llvm::Align(MIN_ANDROID_ARM32_ENUM_ALIGN));
}
return allocaInst;
}
if (cgType.GetOriginal().IsGeneric()) {
return CreateEntryAlloca(getInt8PtrTy(1), nullptr, name);
}
llvm::Value* size = GetLayoutSize_32(cgType.GetOriginal());
auto allocaInst = CallIntrinsicAllocaGeneric({CreateTypeInfo(cgType.GetOriginal()), size});
allocaInst->setDebugLoc(llvm::DebugLoc());
return allocaInst;
}
llvm::Value* IRBuilder2::CreateLoad(const CGValue& cgVal, const llvm::Twine& name)
{
auto elementCGType = cgVal.GetCGType()->GetPointerElementType();
auto elementType = elementCGType->GetLLVMType();
if (auto& ori = elementCGType->GetOriginal(); !elementCGType->GetSize() && !ori.IsGeneric()) {
auto ti = CreateTypeInfo(ori);
auto payloadSize = GetLayoutSize_32(ori);
auto tmp = CallIntrinsicAllocaGeneric({ti, payloadSize});
auto basePtr = GetCGContext().GetBasePtrOf(cgVal.GetRawValue());
auto addrSpace = cgVal.GetRawValue()->getType()->getPointerAddressSpace();
if (basePtr == nullptr) {
if (addrSpace == 1U) {
CallIntrinsicAssignGeneric({tmp, *cgVal, ti});
} else {
CallGCWriteGenericPayload({tmp, *cgVal, payloadSize});
}
} else {
CJC_ASSERT(addrSpace == 1U);
CallGCReadGeneric({tmp, basePtr, *cgVal, payloadSize});
}
return tmp;
}
auto* loadInst = CreateLoad(elementType, cgVal.GetRawValue(), name);
if (auto& ori = elementCGType->GetOriginal(); ori.IsEnum()) {
llvm::cast<llvm::Instruction>(loadInst)->setMetadata(
"untrusted_ref", llvm::MDNode::get(cgMod.GetLLVMContext(), {}));
}
return loadInst;
}
llvm::Value* IRBuilder2::CreateStructGEP(llvm::Type* ty, llvm::Value* ptr, unsigned idx, const llvm::Twine& name)
{
return LLVMIRBuilder2::CreateConstInBoundsGEP2_32(ty, ptr, 0, idx, name);
}
llvm::Value* IRBuilder2::CreateVArrayGEP(
const CGValue* varrayPtr, std::vector<llvm::Value*>& idxList, const llvm::Twine& name)
{
(void)idxList.insert(idxList.begin(), getInt64(0));
auto varray = llvm::dyn_cast<llvm::ArrayType>(varrayPtr->GetCGType()->GetPointerElementType()->GetLLVMType());
return LLVMIRBuilder2::CreateGEP(varray, varrayPtr->GetRawValue(), idxList, name);
}
llvm::BasicBlock* IRBuilder2::CreateEntryBasicBlock(llvm::Function* parent, const std::string& name) const
{
auto& functionBBs = parent->getBasicBlockList();
llvm::BasicBlock* oldEntryBB = nullptr;
if (!functionBBs.empty()) {
oldEntryBB = &functionBBs.front();
}
return llvm::BasicBlock::Create(getContext(), name, parent, oldEntryBB);
}
std::vector<llvm::BasicBlock*> IRBuilder2::CreateAndInsertBasicBlocks(
const std::initializer_list<std::string>& basicBlocksName) const
{
std::vector<llvm::BasicBlock*> ret;
auto bb = GetInsertBlock();
auto function = bb->getParent();
for (auto& bbName : basicBlocksName) {
auto it = ret.emplace_back(llvm::BasicBlock::Create(getContext(), bbName, function));
it->moveAfter(bb);
bb = it;
}
return ret;
}
void IRBuilder2::EmitDeclare(const CHIR::Debug& debugNode, bool pointerWrapper)
{
CJC_ASSERT(cgMod.GetCGContext().GetCompileOptions().enableCompileDebug);
cgMod.diBuilder->EmitDeclare(debugNode, *GetInsertBlock(), pointerWrapper);
EmitLocation(CHIRExprWrapper(debugNode));
}
void IRBuilder2::CreateLocalVarPointer(const CHIR::Debug& debugNode, const CGValue& cgValue)
{
CJC_ASSERT(cgMod.GetCGContext().GetCompileOptions().enableCompileDebug);
auto cgType = cgValue.GetCGType();
auto arg = cgValue.GetRawValue();
auto tmpArg = CreateEntryAlloca(
llvm::Type::getInt8PtrTy(cgMod.GetLLVMContext(), 1), nullptr, debugNode.GetSrcCodeIdentifier() + ".debug");
auto inst = CreateStore(arg, tmpArg);
llvm::cast<llvm::Instruction>(tmpArg)->setDebugLoc(llvm::DebugLoc());
CJC_NULLPTR_CHECK(inst);
inst->setDebugLoc(llvm::DebugLoc());
cgMod.SetOrUpdateMappedCGValue(debugNode.GetValue(), std::make_unique<CGValue>(tmpArg, cgType));
EmitDeclare(debugNode);
cgMod.SetValuesToLoad(debugNode.GetValue(), llvm::Type::getInt8PtrTy(cgMod.GetLLVMContext(), 1), tmpArg);
cgMod.SetOrUpdateMappedCGValue(debugNode.GetValue(), std::make_unique<CGValue>(arg, cgType));
}
void IRBuilder2::CreateUnBoxDeclare(const CHIR::Debug& debugNode, const CGValue& cgValue)
{
CJC_ASSERT(DeRef(*debugNode.GetOperand(0)->GetType())->IsClass());
auto capturedTy = StaticCast<CHIR::ClassType*>(DeRef(*debugNode.GetOperand(0)->GetType()))
->GetClassDef()
->GetDirectInstanceVar(0)
.type;
auto capturedCGType = CGType::GetOrCreate(cgMod, capturedTy);
auto load = CreateLoad(cgValue);
auto eleType = cgValue.GetCGType()->GetPointerElementType()->GetPointerElementType();
auto ret = GetPayloadFromObject(load);
auto layoutType = dynamic_cast<const CGClassType*>(eleType)->GetLayoutType();
ret = CreateBitCast(ret, layoutType->getPointerTo(1));
ret = LLVMIRBuilder2::CreateStructGEP(layoutType, ret, 0);
CJC_ASSERT(ret->getType()->isPointerTy());
llvm::Value* alloca;
if (capturedCGType->IsRefType() || capturedCGType->IsStructType()) {
alloca = CreateEntryAlloca(getInt8PtrTy(1), nullptr, debugNode.GetSrcCodeIdentifier() + ".debug");
auto bitCast = CreateBitCast(ret, getInt8PtrTy(1));
CreateStore(bitCast, alloca);
} else {
alloca = CreateEntryAlloca(ret->getType(), nullptr, debugNode.GetSrcCodeIdentifier() + ".debug");
CreateStore(ret, alloca);
}
cgMod.diBuilder->EmitUnBoxDeclare(
debugNode, *DeRef(*capturedTy), debugNode.GetSrcCodeIdentifier(), alloca, *GetInsertBlock());
EmitLocation(CHIRExprWrapper(debugNode));
}
void IRBuilder2::CreateEnvDeclare(const CHIR::GetElementRef& getEleRef, llvm::Value* gep)
{
auto envTy = DeRef(*getEleRef.GetOperand(0)->GetType());
CJC_ASSERT(envTy->IsClass());
for capturedVar with var of CHIR is like:
func (%1: env) {
%2: $Captured_XXE&& = GetElementRef(%1, memberIndex) // this gep what we are translating now
%3: $Captured_XXE& = Load(%2)
...
%n: XX& = GetElementRef(%3, 0)
}
and for capturedVar with let of CHIR is like:
func (%1: env) {
%2: XXE& = GetElementRef(%1, memberIndex) // this gep what we are translating now
}
*/
CJC_NULLPTR_CHECK(getEleRef.GetResultType());
auto retTy = DeRef(*getEleRef.GetResultType());
bool isCapturedWithVar = retTy->IsClass() && IsCapturedClass(*StaticCast<CHIR::ClassType*>(retTy)->GetClassDef());
auto name = StaticCast<CHIR::ClassType*>(envTy)->GetClassDef()->GetDirectInstanceVar(getEleRef.GetPath()[0]).name;
if (isCapturedWithVar) {
auto capturedClass = getEleRef.GetResultType();
auto load = CreateLoad(CGValue(gep, CGType::GetOrCreate(cgMod, capturedClass)));
CJC_ASSERT(capturedClass->IsRef());
auto capturedVarPointer = CreateGEP(
CGValue(load, CGType::GetOrCreate(cgMod, StaticCast<CHIR::RefType*>(capturedClass)->GetBaseType())), {0});
auto capturedTy =
StaticCast<CHIR::ClassType*>(DeRef(*capturedClass))->GetClassDef()->GetDirectInstanceVar(0).type;
auto capturedCGType = CGType::GetOrCreate(cgMod, capturedTy);
auto pointer = capturedCGType->IsRefType() || capturedCGType->IsStructType()
? getInt8PtrTy(1)
: capturedVarPointer.GetRawValue()->getType();
auto ret = capturedCGType->IsRefType() || capturedCGType->IsStructType()
? CreateBitCast(capturedVarPointer.GetRawValue(), getInt8PtrTy(1))
: capturedVarPointer.GetRawValue();
auto alloca = CreateEntryAlloca(pointer, nullptr, name + ".debug");
CreateStore(ret, alloca);
cgMod.diBuilder->EmitUnBoxDeclare(getEleRef, *DeRef(*capturedTy), name, alloca, *GetInsertBlock());
} else {
CJC_NULLPTR_CHECK(getEleRef.GetResultType());
CJC_ASSERT(getEleRef.GetResultType()->IsRef());
auto capturedCGType =
CGType::GetOrCreate(cgMod, StaticCast<CHIR::RefType*>(getEleRef.GetResultType())->GetBaseType());
auto pointer = capturedCGType->IsRefType() || capturedCGType->IsStructType() ? getInt8PtrTy(1) : gep->getType();
auto ret =
capturedCGType->IsRefType() || capturedCGType->IsStructType() ? CreateBitCast(gep, getInt8PtrTy(1)) : gep;
auto alloca = CreateEntryAlloca(pointer, nullptr, name + ".debug");
CreateStore(ret, alloca);
cgMod.diBuilder->EmitUnBoxDeclare(getEleRef, *retTy, name, alloca, *GetInsertBlock());
}
}
llvm::Type* IRBuilder2::HandleArgPointerType(const CGType& argType) const
{
if (argType.IsRefType()) {
return argType.GetPointerElementType()->GetLLVMType()->getPointerTo(1);
} else {
return GetPointerToWithSpecificAddrSpace(&argType, 0);
}
}
void IRBuilder2::CreateValuePointer(const CHIR::Debug& debugNode, const CGValue& cgValue)
{
auto cgType = cgValue.GetCGType();
CJC_NULLPTR_CHECK(cgType);
bool isRefType = cgType->IsRefType();
auto arg = cgValue.GetRawValue();
CJC_NULLPTR_CHECK(arg);
auto argType = arg->getType();
CJC_NULLPTR_CHECK(argType);
auto isDeriveType = argType->isPointerTy() && !isRefType;
argType = cgType->IsPointerType() ? HandleArgPointerType(*cgType) : argType;
llvm::Value* debugArg = isDeriveType ? CreateAddrSpaceCast(arg, argType) : arg;
auto tmpArg = CreateEntryAlloca(argType, nullptr, arg->getName() + ".debug");
auto inst = CreateStore(debugArg, tmpArg);
llvm::cast<llvm::Instruction>(tmpArg)->setDebugLoc(llvm::DebugLoc());
CJC_NULLPTR_CHECK(inst);
inst->setDebugLoc(llvm::DebugLoc());
cgMod.SetOrUpdateMappedCGValue(debugNode.GetValue(), std::make_unique<CGValue>(tmpArg, cgType));
EmitDeclare(debugNode);
if (!isDeriveType) {
cgMod.SetValuesToLoad(debugNode.GetValue(), argType, tmpArg);
}
cgMod.SetOrUpdateMappedCGValue(debugNode.GetValue(), std::make_unique<CGValue>(arg, cgType));
}
void IRBuilder2::CreateBoxedValueForValueType(const CHIR::Debug& debugNode, const CGValue& cgValue)
{
auto curLoc = getCurrentDebugLocation();
SetCurrentDebugLocation(llvm::DebugLoc());
auto arg = cgValue.GetRawValue();
auto cgType = cgValue.GetCGType();
auto payloadSize = GetLayoutSize_32(*debugNode.GetValue()->GetType());
CJC_NULLPTR_CHECK(arg);
auto argType = arg->getType();
auto tiValue = CreateTypeInfo(DeRef(*debugNode.GetValue()->GetType()));
auto thisDebug = CallIntrinsicAllocaGeneric({tiValue, payloadSize});
thisDebug->setName(arg->getName() + ".generic.alloca");
auto ty = DeRef(*debugNode.GetValue()->GetType());
CJC_NULLPTR_CHECK(ty);
if (debugNode.GetValue()->IsParameter()) {
auto payload = GetPayloadFromObject(thisDebug);
auto castedPtr = CreateBitCast(payload, argType->getPointerTo(1));
auto addrType = CGType::GetOrCreate(cgMod,
CGType::GetRefTypeOf(cgMod.GetCGContext().GetCHIRBuilder(), *debugNode.GetValue()->GetType()),
CGType::TypeExtraInfo(1U));
CreateStore(cgValue, CGValue(castedPtr, addrType));
if (ty->IsStruct()) {
const auto& curCHIRFunc = StaticCast<const CHIR::Function&>(GetInsertCGFunction()->GetOriginal());
bool shouldUpdateThis =
curCHIRFunc.GetSrcCodeIdentifier() == "init" || curCHIRFunc.TestAttr(CHIR::Attribute::MUT);
cgMod.GetCGContext().debugValue =
shouldUpdateThis && arg->getName() == "this" ? thisDebug : cgMod.GetCGContext().debugValue;
}
}
auto tempAlloca = thisDebug;
bool pointerWrapper = false;
bool isZeroSize = CGType::GetOrCreate(cgMod, ty)->GetSize() == 0;
if (arg->getName() != "this" || !argType->isPointerTy() || isZeroSize) {
tempAlloca = CreateEntryAlloca(getInt8PtrTy(1), nullptr, arg->getName() + ".debug");
CreateStore(thisDebug, tempAlloca);
pointerWrapper = true;
} else {
thisDebug->setName(arg->getName() + ".debug");
}
cgMod.SetOrUpdateMappedCGValue(debugNode.GetValue(), std::make_unique<CGValue>(tempAlloca, cgType));
EmitDeclare(debugNode, pointerWrapper);
bool isStructThis = ty->IsStruct() && debugNode.GetSrcCodeIdentifier() == "this";
if (!debugNode.GetValue()->IsParameter() || isStructThis) {
cgMod.SetBoxedValuesToLoad(debugNode.GetValue(), argType, thisDebug);
}
cgMod.SetOrUpdateMappedCGValue(debugNode.GetValue(), std::make_unique<CGValue>(arg, cgType));
SetCurrentDebugLocation(curLoc);
}
void IRBuilder2::CreateLoadInstForParameter(const CHIR::Expression& chirExpression)
{
for (auto operand : chirExpression.GetOperands()) {
if (auto it = cgMod.GetValuesToLoad(operand); it.has_value()) {
auto loadInst = LLVMIRBuilder2::CreateLoad(it->first, it->second);
if (auto basePtr = GetCGContext().GetBasePtrOf(**(cgMod | operand))) {
GetCGContext().SetBasePtr(loadInst, basePtr);
}
FixedCGTypeOfFuncArg(cgMod, *operand, *loadInst);
}
if (auto it = cgMod.GetBoxedValuesToLoad(operand); it.has_value()) {
if (chirExpression.GetExprKind() == CHIR::ExprKind::STORE_ELEMENT_REF &&
chirExpression.GetOperand(1) == operand) {
auto gep = CreateGEP(getInt8Ty(), it->second, getInt64(8));
auto castToCurrentValue = CreateBitCast(gep, it->first);
FixedCGTypeOfFuncArg(cgMod, *operand, *castToCurrentValue);
continue;
}
auto payload = GetPayloadFromObject(it->second);
auto castedPtr =
CreateBitCast(payload, llvm::cast<llvm::PointerType>(it->first)->getElementType()->getPointerTo(1));
if (chirExpression.GetExprKind() == CHIR::ExprKind::STORE && chirExpression.GetOperand(1) == operand) {
FixedCGTypeOfFuncArg(cgMod, *operand, *castedPtr);
continue;
}
CJC_ASSERT(castedPtr->getType()->isPointerTy() && it->first->isPointerTy());
llvm::Value* temp = castedPtr;
if (llvm::cast<llvm::PointerType>(it->first)->getElementType()->isStructTy() &&
llvm::cast<llvm::PointerType>(it->first)->getAddressSpace() == 0) {
auto elemType = llvm::cast<llvm::PointerType>(it->first)->getElementType();
temp = CreateEntryAlloca(llvm::cast<llvm::PointerType>(it->first)->getElementType(), nullptr,
it->second->getName() + ".copied");
if (IsTypeContainsRef(elemType)) {
auto structType = llvm::cast<llvm::StructType>(elemType);
auto layOut = GetLLVMModule()->getDataLayout().getStructLayout(structType);
auto size = getInt64(layOut->getSizeInBytes());
CallGCReadAgg(structType, {temp, it->second, castedPtr, size});
} else {
auto layOut = GetCGModule().GetLLVMModule()->getDataLayout().getStructLayout(
llvm::cast<llvm::StructType>(elemType));
CJC_NULLPTR_CHECK(layOut);
auto size = layOut->getSizeInBytes();
auto align = layOut->getAlignment();
CreateMemCpy(temp, align, castedPtr, align, size);
}
}
FixedCGTypeOfFuncArg(cgMod, *operand, *temp);
}
}
}
void IRBuilder2::CreateGenericParaDeclare(const CGFunction& cgFunc)
{
if (!cgMod.GetCGContext().GetCompileOptions().enableCompileDebug) {
return;
}
if (cgFunc.chirFunc.TestAttr(CHIR::Attribute::NO_DEBUG_INFO)) {
return;
}
auto chirFunc = dynamic_cast<const CHIR::Function*>(&cgFunc.GetOriginal());
size_t genericIndex = 0;
auto null = llvm::ConstantPointerNull::get(llvm::Type::getInt8PtrTy(cgMod.GetLLVMContext()));
if (cgFunc.GetCGFunctionType()->GetOuterTypeInfoIndex().has_value()) {
auto outerDef = chirFunc->GetParentCustomTypeDef();
for (auto genericTy : outerDef->GetGenericTypeParams()) {
cgMod.diBuilder->EmitGenericDeclare(*genericTy, null, *GetInsertBlock(), genericIndex);
++genericIndex;
}
}
for (auto genericTy : chirFunc->GetGenericTypeParams()) {
cgMod.diBuilder->EmitGenericDeclare(*genericTy, null, *GetInsertBlock(), genericIndex);
++genericIndex;
}
}
void IRBuilder2::EmitLocation(const CHIRExprWrapper& debugNode, const bool removable)
{
if (!cgMod.GetCGContext().IsLineInfoEnabled()) {
return;
}
llvm::DILocation* diLoc = cgMod.diBuilder->CreateDILoc(debugNode, removable);
SetCurrentDebugLocation(diLoc);
}
#ifdef CANGJIE_CODEGEN_CJNATIVE_BACKEND
llvm::Value* IRBuilder2::CallIntrinsicNull() const
{
return llvm::ConstantPointerNull::get(llvm::cast<llvm::PointerType>(CGType::GetRefType(GetLLVMContext())));
}
#endif
llvm::Value* IRBuilder2::CallIntrinsicIsNull(llvm::Value* value)
{
#ifdef CANGJIE_CODEGEN_CJNATIVE_BACKEND
auto rhs = CallIntrinsicNull();
CJC_NULLPTR_CHECK(rhs);
return CreateICmpEQ(value, rhs);
#endif
}
llvm::Value* IRBuilder2::CallIntrinsicIsNonNull(llvm::Value* value)
{
auto rhs = CallIntrinsicNull();
CJC_NULLPTR_CHECK(rhs);
return CreateICmpNE(value, rhs);
}
#ifdef CANGJIE_CODEGEN_CJNATIVE_BACKEND
llvm::Value* IRBuilder2::CallIntrinsicRef2Null(llvm::Value* value)
{
return value;
}
#endif
llvm::Value* IRBuilder2::CallClassIntrinsicInstanceOf(
llvm::Value* instance, [[maybe_unused]] const CHIR::Type* targetTy)
{
#ifdef CANGJIE_CODEGEN_CJNATIVE_BACKEND
auto instanceInt8Ptr = CreateBitCast(instance, getInt8PtrTy()->getPointerTo(1));
auto instanceTi = CreateLoad(getInt8PtrTy(), instanceInt8Ptr);
auto targetTiPtr = CreateTypeInfo(*targetTy);
auto targetTi = CreateBitCast(targetTiPtr, llvm::Type::getInt8PtrTy(cgMod.GetLLVMContext()));
return CallIntrinsicIsSubtype({instanceTi, targetTi});
#endif
}
void IRBuilder2::CallExceptionIntrinsicThrow(llvm::Value* exceptionValue)
{
auto throwFunc = GetExceptionIntrinsicThrow();
CJC_NULLPTR_CHECK(throwFunc);
std::vector<llvm::Value*> params{exceptionValue};
auto unwindBlock = cgMod.GetCGContext().TopUnwindBlockStack();
if (unwindBlock.has_value()) {
auto currentBB = GetInsertBlock();
auto normalDest = llvm::BasicBlock::Create(getContext(), "normalDest", currentBB->getParent());
normalDest->moveAfter(currentBB);
(void)CreateInvoke(throwFunc, normalDest, unwindBlock.value(), params);
SetInsertPoint(normalDest);
} else {
(void)CreateCall(throwFunc, params);
}
}
}
}