#include "CGModule.h"
#include "llvm/IR/Attributes.h"
#include "llvm/IR/Dominators.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/Verifier.h"
#include "llvm/Support/Host.h"
#include "Base/CGTypes/CGFunctionType.h"
#include "Base/CGTypes/CGType.h"
#ifdef CANGJIE_CODEGEN_CJNATIVE_BACKEND
#include "CJNative/CGTypes/CGExtensionDef.h"
#include "CJNative/CJNativeCGCFFI.h"
#endif
#include "DIBuilder.h"
#include "IRAttribute.h"
#include "IRBuilder.h"
#include "IncrementalGen/IncrementalGen.h"
#include "Utils/CGCommonDef.h"
#include "cangjie/CHIR/IR/AttributeInfo.h"
#include "cangjie/CHIR/IR/Package.h"
#include "cangjie/CHIR/IR/Value/Value.h"
#include "cangjie/Utils/ProfileRecorder.h"
namespace Cangjie::CodeGen {
inline std::string CGModule::GetDataLayoutString(const GlobalOptions& options)
{
if (options.IsLTOEnabled() && options.target.arch == Triple::ArchType::X86_64 && options.target.IsMacOS()) {
return "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128";
}
if (options.target.IsMacOS() && options.target.arch == Triple::ArchType::AARCH64) {
return "e-m:o-i64:64-i128:128-n32:64-S128";
}
if (options.target.arch == Triple::ArchType::ARM32) {
return "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64";
}
return options.target.IsMinGW() ? "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
: "e-m:e-i64:64-f80:128-n8:16:32:64-S128";
}
std::string CGModule::GetTargetTripleString(const Triple::Info& target)
{
if (target.IsMacOS()) {
if (target.arch == Triple::ArchType::AARCH64) {
return "arm64-apple-macosx12.0.0";
}
return target.ArchToString() + "-apple-macosx12.0.0";
} else if (target.arch == Triple::ArchType::AARCH64 && target.env == Triple::Environment::OHOS) {
return target.ArchToString() + "-unknown-linux-ohos";
} else if (target.arch == Triple::ArchType::ARM32 && target.os == Triple::OSType::LINUX) {
return "armv7a-linux-gnu";
} else {
return llvm::sys::getDefaultTargetTriple();
}
}
#ifdef CANGJIE_CODEGEN_CJNATIVE_BACKEND
CGModule::CGModule(SubCHIRPackage& subCHIRPackage, CGPkgContext& cgPkgCtx)
: cgCtx(std::make_unique<CGContext>(subCHIRPackage, cgPkgCtx)),
module(std::make_unique<llvm::Module>(
std::to_string(subCHIRPackage.subCHIRPackageIdx) + '-' + cgPkgCtx.GetCurrentPkgName(),
cgCtx->GetLLVMContext())),
commonBitMap(std::make_unique<llvm::CommonBitmap>(*module))
#endif
{
module->addModuleFlag(llvm::Module::Warning, "CJBC", static_cast<uint32_t>(1));
module->addModuleFlag(llvm::Module::Warning, "Cangjie_OPT", static_cast<uint32_t>(0));
if (cgCtx->GetCompileOptions().target.IsMacOS()) {
auto identifier = cgCtx->GetCurrentPkgName();
std::replace(identifier.begin(), identifier.end(), '/', '.');
module->addModuleFlag(
llvm::Module::Warning, "Cangjie_PACKAGE_ID", llvm::MDString::get(module->getContext(), identifier));
}
const auto& options = cgCtx->GetCompileOptions();
module->setDataLayout(CGModule::GetDataLayoutString(options));
module->setTargetTriple(CGModule::GetTargetTripleString(options.target));
InitDebugInfo();
#ifdef CANGJIE_CODEGEN_CJNATIVE_BACKEND
if (options.target.os == Triple::OSType::WINDOWS && options.target.arch == Triple::ArchType::X86_64) {
cffi = std::make_unique<WindowsAmd64CJNativeCGCFFI>(*this);
} else if (Utils::In(options.target.os, {Triple::OSType::LINUX, Triple::OSType::DARWIN}) &&
options.target.arch == Triple::ArchType::X86_64) {
cffi = std::make_unique<LinuxAmd64CJNativeCGCFFI>(*this);
} else if (options.target.arch == Triple::ArchType::AARCH64 &&
Utils::In(options.target.os, {Triple::OSType::LINUX})) {
cffi = std::make_unique<LinuxAarch64CJNativeCGCFFI>(*this);
#ifdef __APPLE__
} else if (options.target.arch == Triple::ArchType::AARCH64 && options.target.os == Triple::OSType::DARWIN) {
cffi = std::make_unique<MacAArch64CJNativeCGCFFI>(*this);
} else if (options.target.arch == Triple::ArchType::AARCH64 && options.target.os == Triple::OSType::IOS) {
cffi = std::make_unique<MacAArch64CJNativeCGCFFI>(*this);
#endif
} else if (options.target.arch == Triple::ArchType::ARM32) {
cffi = std::make_unique<LinuxOhosArm32CJNativeCGCFFI>(*this);
} else {
cffi = std::make_unique<LinuxAmd64CJNativeCGCFFI>(*this);
}
#endif
}
CGModule::~CGModule()
{
diBuilder = nullptr;
incrementalGen = nullptr;
if (module) {
auto context = &module->getContext();
module = nullptr;
delete context;
context = nullptr;
}
}
#ifdef CANGJIE_CODEGEN_CJNATIVE_BACKEND
void CGModule::GenTypeInfo()
{
while (!delayGenTypeInfo.empty()) {
auto cgType = delayGenTypeInfo.top();
delayGenTypeInfo.pop();
cgType->GenTypeInfo();
}
}
void CGModule::GenTypeTemplate()
{
while (!delayGenTypeTemplate.empty()) {
auto cgType = delayGenTypeTemplate.top();
delayGenTypeTemplate.pop();
cgType->GenTypeTemplate();
}
}
bool CGModule::InitIncrementalGen()
{
CJC_ASSERT(cgCtx->GetCGPkgContext().IsIncrementEnabled());
incrementalGen = std::make_unique<IncrementalGen>(cgCtx->IsCGParallelEnabled());
auto cachePath =
cgCtx->GetCompileOptions().GenerateCachedPathNameForCodeGen(module->getSourceFileName(), "_cache.bc");
return incrementalGen->Init(cachePath, cgCtx->GetLLVMContext());
}
void CGModule::GenIncremental()
{
auto& option = cgCtx->GetCompileOptions();
GenCodeGenAddedMetadata();
if (cgCtx->GetCGPkgContext().IsIncrementEnabled()) {
CJC_NULLPTR_CHECK(incrementalGen);
auto& llvmStdout = llvm::outs();
if (llvm::verifyModule(*module, &llvmStdout)) {
InternalError("Incremental part failed to be compiled");
}
if (option.NeedDumpIRToFile()) {
const auto& dp = GenDumpPath(
option.output, cgCtx->GetCurrentPkgName(), "Incre", module->getSourceFileName(), "incre.ll");
DumpIR(*module, dp);
}
auto newModule = incrementalGen->LinkModules(ReleaseLLVMModule(), cgCtx->GetCachedMangleMap());
for (auto name: incrementalGen->GetIncrLLVMUsedNames()) {
GetCGContext().AddLLVMUsedVars(name);
}
for (auto name : incrementalGen->GetIncrCachedStaticGINames()) {
GetCGContext().RegisterStaticGIName(name);
}
ResetLLVMModule(newModule);
}
if (option.enIncrementalCompilation) {
auto cachePath = option.GenerateCachedPathNameForCodeGen(module->getSourceFileName(), "_cache.bc");
CodeGen::SaveToBitcodeFile(*module, cachePath);
}
if (auto namedMD = module->getNamedMetadata("CodeGenAddedForIncr"); namedMD) {
namedMD->eraseFromParent();
}
if (auto namedMD = module->getNamedMetadata("StaticGenericTIsForIncr"); namedMD) {
namedMD->eraseFromParent();
}
}
void CGModule::GenCodeGenAddedMetadata() const
{
auto codegenAddedNamedMD = GetLLVMModule()->getOrInsertNamedMetadata("CodeGenAddedForIncr");
const auto& codegenAddedFuncsOrVars = GetCGContext().GetCodeGenAddedFuncsOrVars();
for (auto& kv : codegenAddedFuncsOrVars) {
std::vector<llvm::Metadata*> ops;
ops.push_back(llvm::MDString::get(GetLLVMContext(), kv.first));
for (auto& name : kv.second) {
ops.push_back(llvm::MDString::get(GetLLVMContext(), name));
}
auto md = llvm::MDTuple::get(GetLLVMContext(), ops);
codegenAddedNamedMD->addOperand(md);
}
auto staticGINames = GetCGContext().GetStaticGINames();
auto staticGINamedMD = GetLLVMModule()->getOrInsertNamedMetadata("StaticGenericTIsForIncr");
for (auto name : staticGINames) {
staticGINamedMD->addOperand(llvm::MDTuple::get(GetLLVMContext(), llvm::MDString::get(GetLLVMContext(), name)));
}
}
#endif
namespace {
#ifdef CANGJIE_CODEGEN_CJNATIVE_BACKEND
inline void SetCFFIStub(const CHIR::Value& func, llvm::Function* function)
{
CJC_NULLPTR_CHECK(function);
if (func.IsFuncWithBody()) {
const CHIR::Function& funcNode = StaticCast<const CHIR::Function&>(func);
if (funcNode.IsCFunc()) {
if (!funcNode.IsCFFIWrapper()) {
function->addFnAttr(C2CJ_ATTR);
} else if (funcNode.GetIdentifier().find(':') != std::string::npos) {
function->addFnAttr("pkg_c_wrapper");
} else {
function->addFnAttr(CJSTUB_ATTR);
}
}
}
}
#endif
void AddToGenericParamMapUnderExtendScope(const llvm::Function* function, std::unique_ptr<CGFunction>& cgFunc,
const CHIR::Function& f, std::optional<size_t> outerTIIdx)
{
CJC_NULLPTR_CHECK(function);
auto extendDef = StaticCast<CHIR::ExtendDef*>(f.GetParentCustomTypeDef());
auto extendedType = extendDef->GetExtendedType();
for (auto gt : extendDef->GetGenericTypeParams()) {
std::vector<size_t> path;
CGExtensionDef::FoundGenericTypeAndCollectPath(*extendedType, *gt, path);
auto outerTi = function->getArg(static_cast<unsigned>(outerTIIdx.value()));
(void)cgFunc->genericParamsMap.emplace(gt, [outerTi, path, extendedType](IRBuilder2& irBuilder) {
auto entryTypeArgs = irBuilder.GetTypeArgsFromTypeInfo(outerTi);
std::unordered_map<const CHIR::Type*, CGExtensionDef::InnerTiInfo> map;
std::queue<size_t> remainPath;
for (auto idx : path) {
remainPath.push(idx);
}
return CGExtensionDef::GetTypeInfoWithPath(
irBuilder, *extendedType, entryTypeArgs, std::move(remainPath), map);
});
}
}
void AddToGenericParamMapWithOuterTI(const llvm::Function* function, std::unique_ptr<CGFunction>& cgFunc,
const CHIR::Value& func, std::optional<size_t> outerTIIdx)
{
CJC_NULLPTR_CHECK(function);
uint32_t idx = 0;
auto outerTiArg = function->getArg(static_cast<unsigned>(outerTIIdx.value()));
outerTiArg->setName("outerTI");
auto outerDef = StaticCast<const CHIR::Function&>(func).GetParentCustomTypeDef();
CJC_ASSERT(outerDef);
if (!outerDef->GetGenericTypeParams().empty()) {
auto outerType = outerDef->IsExtend() ? dynamic_cast<const CHIR::ExtendDef*>(outerDef)->GetExtendedType()
: outerDef->GetType();
(void)cgFunc->genericParamsMap.emplace(
outerType, [outerTiArg]([[maybe_unused]] IRBuilder2& irBuilder) { return outerTiArg; });
}
for (auto gt : outerDef->GetGenericTypeParams()) {
(void)cgFunc->genericParamsMap.emplace(gt, [function, outerTIIdx, idx](IRBuilder2& irBuilder) {
auto outerTI = function->getArg(static_cast<unsigned>(outerTIIdx.value()));
auto tiPtrType = CGType::GetOrCreateTypeInfoPtrType(irBuilder.GetLLVMContext());
auto typeArgs = irBuilder.GetTypeArgsFromTypeInfo(outerTI);
auto tiAddr = irBuilder.CreateConstInBoundsGEP1_32(tiPtrType, typeArgs, idx);
return irBuilder.LLVMIRBuilder2::CreateLoad(tiPtrType, tiAddr);
});
++idx;
}
}
}
CGFunction* CGModule::GetOrInsertCGFunction(const CHIR::Value* func, bool forWrapper)
{
CJC_NULLPTR_CHECK(func);
if (auto it = valueMapping.find(func); it != valueMapping.end()) {
auto cgFunction = dynamic_cast<CGFunction*>(it->second);
CJC_NULLPTR_CHECK(cgFunction);
return cgFunction;
}
auto cgFuncType = StaticCast<CGFunctionType*>(CGType::GetOrCreateWithNode(*this, func, true, forWrapper));
#ifdef CANGJIE_CODEGEN_CJNATIVE_BACKEND
auto chirFuncTy = StaticCast<CHIR::FuncType*>(func->GetType());
CJC_NULLPTR_CHECK(chirFuncTy);
llvm::FunctionType* functionType =
chirFuncTy->IsCFunc() ? cffi->GetCFuncType(*chirFuncTy) : cgFuncType->GetLLVMFunctionType();
#endif
auto function = llvm::cast<llvm::Function>(
module->getOrInsertFunction(func->GetIdentifierWithoutPrefix(), functionType).getCallee());
if (forWrapper) {
function->addFnAttr("wrapper");
}
if (func->TestAttr(CHIR::Attribute::NO_INLINE)) {
function->addFnAttr(llvm::Attribute::NoInline);
}
if (cgFuncType->HasBasePtr()) {
AddFnAttr(function, llvm::Attribute::get(module->getContext(), STRUCT_MUT_FUNC_ATTR));
AddFnAttr(function, llvm::Attribute::get(module->getContext(), THIS_PARAM_HAS_BP));
}
auto chirFunc = StaticCast<const CHIR::Function*>(func);
auto chirLinkage = chirFunc->Get<CHIR::LinkTypeInfo>();
if (func->IsFuncWithBody()) {
bool markByMD = cgCtx->IsCGParallelEnabled() && !IsCHIRWrapper(func->GetIdentifierWithoutPrefix());
AddLinkageTypeMetadata(*function, CHIRLinkage2LLVMLinkage(chirLinkage), markByMD);
} else if (chirLinkage == Linkage::EXTERNAL_WEAK) {
function->setLinkage(llvm::GlobalValue::ExternalWeakLinkage);
}
auto cgFunc = std::make_unique<CGFunction>(function, cgFuncType, func, *this);
for (auto& [gt, idx] : cgFuncType->GetGenericParamIndicesMap()) {
function->getArg(static_cast<unsigned>(idx))->setName("ti." + gt->GetSrcCodeIdentifier());
auto index = idx;
(void)cgFunc->genericParamsMap.emplace(
gt, [function, index](IRBuilder2&) { return function->getArg(static_cast<unsigned>(index)); });
}
auto outerTIIdx = cgFuncType->GetOuterTypeInfoIndex();
if (auto f = DynamicCast<const CHIR::Function*>(func); f && f->IsInExtend()) {
CJC_ASSERT(outerTIIdx.has_value());
AddToGenericParamMapUnderExtendScope(function, cgFunc, *f, outerTIIdx);
}
if (outerTIIdx.has_value()) {
AddToGenericParamMapWithOuterTI(function, cgFunc, *func, outerTIIdx);
}
if (auto thisTIIdx = cgFuncType->GetThisTypeInfoIndex()) {
auto thisTiArg = function->getArg(static_cast<unsigned>(thisTIIdx.value()));
thisTiArg->setName("thisTI");
}
#ifdef CANGJIE_CODEGEN_CJNATIVE_BACKEND
SetCFFIStub(*func, function);
if (chirFuncTy->IsCFunc()) {
cffi->AddFunctionAttr(*chirFuncTy, *function);
} else {
SetGCCangjie(function);
auto chirParamTypes = dynamic_cast<CHIR::FuncType*>(func->GetType())->GetParamTypes();
for (size_t idx = 0; idx < chirParamTypes.size(); ++idx) {
if (chirParamTypes[idx]->IsStruct()) {
cgFunc->GetArgByIndexFromCHIR(idx)->addAttr(llvm::Attribute::ReadOnly);
cgFunc->GetArgByIndexFromCHIR(idx)->addAttr(llvm::Attribute::NoCapture);
}
}
}
if (func->IsFuncWithBody()) {
if (!StaticCast<const CHIR::Function*>(func)->IsCFFIWrapper()) {
SetGCCangjie(function);
}
}
if (func->TestAttr(CHIR::Attribute::NO_SIDE_EFFECT)) {
function->addFnAttr(llvm::Attribute::NoUnwind);
function->addFnAttr(llvm::Attribute::ReadOnly);
function->addFnAttr(llvm::Attribute::WillReturn);
}
#endif
auto ret = cgFunc.get();
(void)functions.emplace(function, ret);
SetOrUpdateMappedCGValue(func, std::move(cgFunc));
return ret;
}
CGValue* CGModule::GetOrInsertGlobalVariable(const CHIR::GlobalVar* chirGV)
{
CJC_ASSERT_WITH_MSG(chirGV, "chirGV is null");
if (auto it = valueMapping.find(chirGV); it != valueMapping.end()) {
CJC_NULLPTR_CHECK(it->second);
return it->second;
}
auto cgVarType = CGType::GetOrCreate(*this, chirGV->GetType());
llvm::GlobalVariable* gv = llvm::cast<llvm::GlobalVariable>(module->getOrInsertGlobal(
chirGV->GetIdentifierWithoutPrefix(), cgVarType->GetPointerElementType()->GetLLVMType()));
if (!chirGV->TestAttr(CHIR::Attribute::IMPORTED) || chirGV->IsLocalConst()) {
auto chirLinkage = chirGV->Get<CHIR::LinkTypeInfo>();
AddLinkageTypeMetadata(*gv, CHIRLinkage2LLVMLinkage(chirLinkage), cgCtx->IsCGParallelEnabled());
}
#ifdef CANGJIE_CODEGEN_CJNATIVE_BACKEND
gv->addAttribute(CJGLOBAL_VALUE_ATTR);
if (cgCtx->GetCompileOptions().EnableAsan() || cgCtx->GetCompileOptions().EnableHwAsan()) {
gv->addAttribute("address_sanitize_global");
}
if (chirGV->TestAttr(CHIR::Attribute::NON_RECOMPILE)) {
gv->addAttribute("nonRecompile");
}
#endif
auto cgVar = std::make_unique<CGValue>(gv, cgVarType);
auto ret = cgVar.get();
SetOrUpdateMappedCGValue(chirGV, std::move(cgVar));
return ret;
}
CGValue* CGModule::GetMappedCGValue(const CHIR::Value* chirValue)
{
CJC_NULLPTR_CHECK(chirValue);
if (auto cgValue = GetMappedValue(chirValue); cgValue) {
return cgValue;
}
if (auto func = DynamicCast<const CHIR::Function*>(chirValue)) {
return GetOrInsertCGFunction(func);
} else if (auto gv = DynamicCast<const CHIR::GlobalVar*>(chirValue)) {
return GetOrInsertGlobalVariable(gv);
} else {
CJC_ASSERT_WITH_MSG(false, "Should not reach here: value not dominate all uses in CHIR.");
return nullptr;
}
}
llvm::Value* CGModule::GenerateUnitTypeValue()
{
auto unitVal = module->getGlobalVariable(UNIT_VAL_STR);
if (unitVal == nullptr) {
llvm::Type* unitType = CGType::GetUnitCGType(*this)->GetLLVMType();
auto gv = module->getOrInsertGlobal(UNIT_VAL_STR, unitType);
unitVal = llvm::cast<llvm::GlobalVariable>(gv);
CJC_NULLPTR_CHECK(unitVal);
unitVal->addAttribute(CJGLOBAL_VALUE_ATTR);
unitVal->setInitializer(llvm::UndefValue::get(unitType));
AddLinkageTypeMetadata(*unitVal,
cgCtx->GetCompileOptions().target.IsMinGW() ? llvm::GlobalValue::PrivateLinkage
: llvm::GlobalValue::WeakODRLinkage,
false);
}
return unitVal;
}
#ifdef CANGJIE_CODEGEN_CJNATIVE_BACKEND
llvm::Constant* CGModule::GetExceptionIntrinsicPersonality()
{
auto funcName = "__cj_personality_v0$";
if (cgCtx->GetCompileOptions().target.IsMacOS()) {
auto retTy = llvm::Type::getInt32Ty(module->getContext());
return GetOrInsertFunction(funcName, llvm::FunctionType::get(retTy, true));
}
llvm::Function* func = module->getFunction(funcName);
if (!func) {
auto& llvmCtx = module->getContext();
auto retTy = llvm::Type::getInt32Ty(llvmCtx);
auto functionCallee = module->getOrInsertFunction(funcName, llvm::FunctionType::get(retTy, true));
func = llvm::cast<llvm::Function>(functionCallee.getCallee());
AddLinkageTypeMetadata(*func, llvm::GlobalValue::PrivateLinkage, false);
auto entryBB = llvm::BasicBlock::Create(llvmCtx, "entry", func);
IRBuilder2 irBuilder(*this, entryBB);
(void)irBuilder.CreateRet(llvm::ConstantInt::get(retTy, 0));
}
return func;
}
#endif
void CGModule::Opt()
{
for (auto& [function, cgFunction] : std::as_const(functions)) {
if (function == nullptr || cgFunction->GetRawValue() == nullptr) {
continue;
}
cgFunction->Opt();
}
}
bool CGModule::Verify() const
{
bool wellFormed = true;
if (llvm::verifyModule(*module, &llvm::outs())) {
wellFormed = false;
}
return wellFormed;
}
void CGModule::InitDebugInfo()
{
module->addModuleFlag(
llvm::Module::Warning, "Debug Info Version", static_cast<uint32_t>(llvm::DEBUG_METADATA_VERSION));
module->addModuleFlag(llvm::Module::Warning, "Dwarf Version", 4);
diBuilder = std::make_unique<DIBuilder>(*this);
diBuilder->CreateCompileUnit(module->getSourceFileName());
diBuilder->CreateNameSpace(GetCGContext().GetCurrentPkgName());
}
llvm::Constant* CGModule::GenerateTypeNameConstantString(const std::string& typeMangledName, bool isWeakODR, const std::string& qualifiedName) const
{
auto linkageType =
isWeakODR ? llvm::GlobalValue::LinkageTypes::WeakODRLinkage : llvm::GlobalValue::LinkageTypes::PrivateLinkage;
auto strConstant =
llvm::ConstantDataArray::getString(module->getContext(), qualifiedName != "" ? qualifiedName : typeMangledName);
auto globalValue = module->getOrInsertGlobal(typeMangledName + ".name", strConstant->getType());
auto klassName = llvm::cast<llvm::GlobalVariable>(globalValue);
klassName->setInitializer(strConstant);
klassName->setAlignment(llvm::Align(1));
klassName->addAttribute(CJTYPE_NAME_ATTR);
klassName->setConstant(true);
klassName->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global);
AddLinkageTypeMetadata(*klassName, linkageType, false);
return llvm::ConstantExpr::getBitCast(klassName, llvm::Type::getInt8PtrTy(module->getContext()));
}
llvm::GlobalVariable* CGModule::GeneratePrivateUnnamedAddrConstant(
const std::string& name, llvm::Constant* constVal) const
{
auto type = constVal->getType();
auto res = llvm::cast<llvm::GlobalVariable>(module->getOrInsertGlobal(name, type));
res->setConstant(true);
res->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global);
AddLinkageTypeMetadata(*res, llvm::GlobalValue::PrivateLinkage, false);
auto& layOut = module->getDataLayout();
auto align = llvm::MaybeAlign(layOut.getPrefTypeAlignment(type));
res->setAlignment(align);
res->setInitializer(constVal);
return res;
}
llvm::GlobalVariable* CGModule::GetOrCreateGlobalVariable(
llvm::Constant* constVal, const std::string& gvContent, bool isTuple)
{
std::string name = isTuple ? GetConstantTupleName(gvContent) : GetConstantArrayName(gvContent);
if (auto gv = module->getGlobalVariable(name, true); gv) {
return gv;
} else {
return GeneratePrivateUnnamedAddrConstant(name, constVal);
}
}
llvm::Function* CGModule::GetOrInsertFunction(const std::string& funcMangledName, llvm::FunctionType* funcType) const
{
auto functionCallee = module->getOrInsertFunction(funcMangledName, funcType);
auto callee = functionCallee.getCallee();
CJC_ASSERT(llvm::isa<llvm::Function>(callee));
return llvm::cast<llvm::Function>(callee);
}
#ifdef CANGJIE_CODEGEN_CJNATIVE_BACKEND
std::string CGModule::GetEnumCaseClassName(const CHIR::EnumType& chirEnumType, std::size_t ctorIndex)
{
auto enumDef = chirEnumType.GetEnumDef();
auto name =
enumDef->GetPackageName() + ':' + GetCustomTypeDefIdentifier(*enumDef) + ':' + std::to_string(ctorIndex);
if (!CGType::GetOrCreate(*this, &chirEnumType)->IsDynamicGI() && !chirEnumType.GetTypeArgs().empty()) {
name = name + '<' + GetTypeArgsQualifiedName(chirEnumType.GetTypeArgs()) + '>';
}
return name;
}
llvm::GlobalVariable* CGModule::GetOrCreateEnumCtorTIOrTT(const CHIR::EnumType& chirEnumType, std::size_t ctorIndex)
{
auto isTT = CGType::GetOrCreate(*this, &chirEnumType)->IsDynamicGI();
auto className = GetEnumCaseClassName(chirEnumType, ctorIndex) + (isTT ? ".tt" : ".ti");
auto gvType = isTT ? CGType::GetOrCreateTypeTemplateType(cgCtx->GetLLVMContext())
: CGType::GetOrCreateTypeInfoType(cgCtx->GetLLVMContext());
auto gvOfEnumCtorTIOrTT = GetLLVMModule()->getGlobalVariable(className, true);
if (!gvOfEnumCtorTIOrTT) {
gvOfEnumCtorTIOrTT = llvm::cast<llvm::GlobalVariable>(GetLLVMModule()->getOrInsertGlobal(className, gvType));
EnumCtorTIOrTTGenerator(*this, chirEnumType, ctorIndex).Emit();
}
return gvOfEnumCtorTIOrTT;
}
#endif
std::vector<llvm::Constant*> CGModule::InitRawArrayUInt8Constants() const
{
auto& ctx = GetLLVMContext();
auto int32Ty = llvm::Type::getInt32Ty(ctx);
auto int32PtrTy = llvm::Type::getInt32PtrTy(ctx);
auto int8Ty = llvm::Type::getInt8Ty(ctx);
auto int8PtrTy = llvm::Type::getInt8PtrTy(ctx);
auto int16Ty = llvm::Type::getInt16Ty(ctx);
auto typeTemplateType = CGType::GetOrCreateTypeTemplateType(ctx);
auto typeInfoType = CGType::GetOrCreateTypeInfoType(ctx);
auto ttName = "RawArray.tt";
auto memberTiName = "UInt8.ti";
if (module->getGlobalVariable(memberTiName, true) == nullptr) {
auto gvUInt8Ti = llvm::cast<llvm::GlobalVariable>(module->getOrInsertGlobal(memberTiName, typeInfoType));
auto metaUInt8Ti = llvm::MDTuple::get(ctx, {llvm::MDString::get(ctx, "UInt8.Type")});
gvUInt8Ti->setMetadata(GC_TYPE_META_NAME, metaUInt8Ti);
gvUInt8Ti->addAttribute(GC_KLASS_ATTR);
gvUInt8Ti->addAttribute(NOT_MODIFIABLE_CLASS_ATTR);
}
auto constantInt8Zero = llvm::ConstantInt::get(int8Ty, 0);
auto constantInt16Zero = llvm::ConstantInt::get(int16Ty, 0);
auto constantNullPtrInt8Ptr = llvm::ConstantPointerNull::get(int8PtrTy);
std::vector<llvm::Constant*> typeInfoVec(TYPE_INFO_FIELDS_NUM);
typeInfoVec[static_cast<size_t>(TYPEINFO_NAME)] = GenerateTypeNameConstantString("RawArray<UInt8>", false);
typeInfoVec[static_cast<size_t>(TYPEINFO_TYPE_KIND)] =
llvm::ConstantInt::get(int8Ty, static_cast<size_t>(UGTypeKind::UG_RAWARRAY));
typeInfoVec[static_cast<size_t>(TYPEINFO_FIELDS_NUM)] = constantInt16Zero;
typeInfoVec[static_cast<size_t>(TYPEINFO_FIELDS)] = constantNullPtrInt8Ptr;
typeInfoVec[static_cast<size_t>(TYPEINFO_SIZE)] = llvm::ConstantInt::get(int32Ty, 0);
typeInfoVec[static_cast<size_t>(TYPEINFO_UUID)] = llvm::Constant::getNullValue(int32Ty);
typeInfoVec[static_cast<size_t>(TYPEINFO_ALIGN)] = constantInt8Zero;
typeInfoVec[static_cast<size_t>(TYPEINFO_SOURCE_GENERIC)] =
llvm::ConstantExpr::getBitCast(GetLLVMModule()->getOrInsertGlobal(ttName, typeTemplateType), int8PtrTy);
typeInfoVec[static_cast<size_t>(TYPEINFO_TYPE_ARGS_NUM)] = constantInt8Zero;
typeInfoVec[static_cast<size_t>(TYPEINFO_INHERITED_CLASS_NUM)] =
llvm::ConstantInt::get(int16Ty, INHERITED_CLASS_NUM_FE_FLAG);
typeInfoVec[static_cast<size_t>(TYPEINFO_OFFSETS)] = llvm::ConstantPointerNull::get(int32PtrTy);
typeInfoVec[static_cast<size_t>(TYPEINFO_TYPE_ARGS)] = constantNullPtrInt8Ptr;
typeInfoVec[static_cast<size_t>(TYPEINFO_SUPER)] =
llvm::cast<llvm::GlobalVariable>(GetLLVMModule()->getOrInsertGlobal(memberTiName, typeInfoType));
typeInfoVec[static_cast<size_t>(TYPEINFO_EXTENSIONDEF_PTR)] =
llvm::ConstantPointerNull::get(CGType::GetOrCreateExtensionDefPtrType(ctx)->getPointerTo());
typeInfoVec[static_cast<size_t>(TYPEINFO_MTABLE)] = constantNullPtrInt8Ptr;
typeInfoVec[static_cast<size_t>(TYPEINFO_REFLECTION)] = constantNullPtrInt8Ptr;
typeInfoVec[static_cast<size_t>(TYPEINFO_GC_TIB)] =
llvm::ConstantPointerNull::get(CGType::GetBitMapType(ctx)->getPointerTo());
typeInfoVec[static_cast<size_t>(TYPEINFO_FLAG)] = constantInt8Zero;
return typeInfoVec;
}
bool CGModule::IsLinkNameUsedInMeta(const std::string& linkageName)
{
if (linkNameUsedInMeta.empty()) {
std::vector<std::string> metaTypes = {METADATA_PKG, METADATA_TYPES, METADATA_TYPETEMPLATES,
METADATA_PRIMITIVE_TYPES, METADATA_PRIMITIVE_TYPETEMPLATES, METADATA_GLOBAL_VAR, METADATA_FUNCTIONS};
std::for_each(metaTypes.begin(), metaTypes.end(), [this](auto& type) {
CollectLinkNameUsedInMeta(this->module->getNamedMetadata(type), this->linkNameUsedInMeta);
});
}
return linkNameUsedInMeta.find(linkageName) != linkNameUsedInMeta.end();
}
const std::vector<std::unique_ptr<CGExtensionDef>>& CGModule::GetAllCGExtensionDefs()
{
auto& subCHIRPkg = GetCGContext().GetSubCHIRPackage();
std::unordered_set<CHIR::CustomTypeDef*> traversedCustomTypeDefs;
for (auto customDef : subCHIRPkg.chirCustomDefs) {
if (!traversedCustomTypeDefs.emplace(customDef).second) {
CJC_ASSERT(false && "Duplicated customDef provided by CHIR.");
continue;
}
switch (customDef->GetCustomKind()) {
case CHIR::CustomDefKind::TYPE_CLASS: {
auto classDef = dynamic_cast<CHIR::ClassDef*>(customDef);
if (!IsCoreObject(*classDef) && !IsClosureConversionEnvClass(*classDef)) {
(void)cgExtensionDefs.emplace_back(std::make_unique<CGExtensionDef>(*this, *customDef));
}
break;
}
case CHIR::CustomDefKind::TYPE_ENUM:
case CHIR::CustomDefKind::TYPE_STRUCT: {
(void)cgExtensionDefs.emplace_back(std::make_unique<CGExtensionDef>(*this, *customDef));
break;
}
case CHIR::CustomDefKind::TYPE_EXTEND: {
auto extendedType = dynamic_cast<CHIR::ExtendDef*>(customDef)->GetExtendedType();
if (!extendedType->IsNominal() ||
dynamic_cast<CHIR::CustomType*>(extendedType)->GetCustomTypeDef()
->TestAttr(CHIR::Attribute::IMPORTED)) {
(void)cgExtensionDefs.emplace_back(std::make_unique<CGExtensionDef>(*this, *customDef));
}
break;
}
default:
CJC_ASSERT(false && "Should not reach here.");
return cgExtensionDefs;
}
}
return cgExtensionDefs;
}
}