mirror of
https://github.com/AdaCore/gnat-llvm.git
synced 2026-02-12 13:05:32 -08:00
1852 lines
49 KiB
C++
1852 lines
49 KiB
C++
#include <string.h>
|
|
|
|
#include "llvm-c/Types.h"
|
|
#include "llvm/ADT/APFloat.h"
|
|
#include "llvm/ADT/APInt.h"
|
|
#include "llvm/ADT/StringExtras.h"
|
|
#include "llvm/Analysis/AliasAnalysis.h"
|
|
#include "llvm/Analysis/TargetLibraryInfo.h"
|
|
#include "llvm/Analysis/TargetTransformInfo.h"
|
|
#include "llvm/IR/Attributes.h"
|
|
#include "llvm/IR/BasicBlock.h"
|
|
#include "llvm/IR/DerivedTypes.h"
|
|
#include "llvm/IR/DIBuilder.h"
|
|
#include "llvm/IR/MDBuilder.h"
|
|
#include "llvm/IR/Function.h"
|
|
#include "llvm/IR/GlobalValue.h"
|
|
#include "llvm/IR/InlineAsm.h"
|
|
#include "llvm/IR/InstrTypes.h"
|
|
#include "llvm/IR/Instruction.h"
|
|
#include "llvm/IR/Instructions.h"
|
|
#include "llvm/IR/IRBuilder.h"
|
|
#include "llvm/IR/LegacyPassManager.h"
|
|
#include "llvm/IR/Metadata.h"
|
|
#include "llvm/IR/Module.h"
|
|
#include "llvm/MC/TargetRegistry.h"
|
|
#include "llvm/Passes/PassBuilder.h"
|
|
#include "llvm/Passes/PassPlugin.h"
|
|
#include "llvm/Support/Casting.h"
|
|
#include "llvm/Support/Error.h"
|
|
#include "llvm/Support/raw_ostream.h"
|
|
#include "llvm/Support/TargetSelect.h"
|
|
#include "llvm/Target/TargetMachine.h"
|
|
#include "llvm/Target/TargetOptions.h"
|
|
#include "llvm/TargetParser/AArch64TargetParser.h"
|
|
#include "llvm/Transforms/InstCombine/InstCombine.h"
|
|
#include "llvm/Transforms/Instrumentation/AddressSanitizer.h"
|
|
#include "llvm/Transforms/Instrumentation/SanitizerCoverage.h"
|
|
#include "llvm/Transforms/IPO.h"
|
|
#include "llvm/Transforms/IPO/AlwaysInliner.h"
|
|
#include "llvm/Transforms/Scalar/LoopPassManager.h"
|
|
#include "llvm/Transforms/Scalar/LoopRotation.h"
|
|
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
|
|
#include "llvm-c/Core.h"
|
|
#include "llvm-c/DebugInfo.h"
|
|
|
|
#include "clang/Basic/Diagnostic.h"
|
|
#include "clang/Basic/DiagnosticIDs.h"
|
|
#include "clang/Basic/DiagnosticOptions.h"
|
|
#include "clang/Basic/TargetInfo.h"
|
|
#include "clang/Basic/TargetOptions.h"
|
|
|
|
// Adapt to varying patches to LLVM.
|
|
#include "gnat-llvm-config.h"
|
|
|
|
using namespace llvm;
|
|
using namespace llvm::sys;
|
|
|
|
using namespace clang;
|
|
|
|
extern "C"
|
|
Instruction *
|
|
Get_Latest_Instruction (IRBuilder<> *bld)
|
|
{
|
|
return dyn_cast<Instruction>(&*--bld->GetInsertPoint ());
|
|
}
|
|
|
|
extern "C"
|
|
void
|
|
Add_Debug_Flags (Module *TheModule)
|
|
{
|
|
TheModule->addModuleFlag (Module::Warning, "Debug Info Version",
|
|
DEBUG_METADATA_VERSION);
|
|
TheModule->addModuleFlag (Module::Warning, "Dwarf Version", 4);
|
|
}
|
|
|
|
extern "C"
|
|
MDBuilder *
|
|
Create_MDBuilder_In_Context (LLVMContext &Ctx)
|
|
{
|
|
return new MDBuilder (Ctx);
|
|
}
|
|
|
|
extern "C"
|
|
MDNode *
|
|
Create_TBAA_Root (MDBuilder *MDHelper)
|
|
{
|
|
return MDHelper->createTBAARoot ("Ada Root");
|
|
}
|
|
|
|
extern "C"
|
|
void
|
|
Add_Cold_Attribute (Function *fn)
|
|
{
|
|
fn->addFnAttr (Attribute::Cold);
|
|
}
|
|
|
|
extern "C"
|
|
void
|
|
Add_Dereferenceable_Attribute (Function *fn, unsigned idx,
|
|
unsigned long long Bytes)
|
|
{
|
|
fn->addDereferenceableParamAttr (idx, Bytes);
|
|
}
|
|
|
|
extern "C"
|
|
void
|
|
Add_Ret_Dereferenceable_Attribute (Function *fn, unsigned long long Bytes)
|
|
{
|
|
/* There doesn't appear to be a way to do this in LLVM 14, so skip for now.
|
|
fn->addDereferenceableRetAttr (Bytes); */
|
|
}
|
|
|
|
extern "C"
|
|
void
|
|
Add_Dereferenceable_Or_Null_Attribute (Function *fn, unsigned idx,
|
|
unsigned long long Bytes)
|
|
{
|
|
fn->addDereferenceableOrNullParamAttr (idx, Bytes);
|
|
}
|
|
|
|
extern "C"
|
|
void
|
|
Add_Ret_Dereferenceable_Or_Null_Attribute (Function *fn,
|
|
unsigned long long Bytes)
|
|
{
|
|
/* There doesn't appear to be a way to do this in LLVM 14, so skip for now.
|
|
fn->addDereferenceableOrNullRetAttr (Bytes); */
|
|
}
|
|
|
|
extern "C"
|
|
void
|
|
Add_Inline_Always_Attribute (Function *fn)
|
|
{
|
|
fn->addFnAttr (Attribute::AlwaysInline);
|
|
}
|
|
|
|
extern "C"
|
|
void
|
|
Add_Inline_Hint_Attribute (Function *fn)
|
|
{
|
|
fn->addFnAttr (Attribute::InlineHint);
|
|
}
|
|
|
|
extern "C"
|
|
void
|
|
Add_Inline_No_Attribute (Function *fn)
|
|
{
|
|
fn->addFnAttr (Attribute::NoInline);
|
|
}
|
|
|
|
extern "C"
|
|
void
|
|
Add_Uwtable_Attribute (Function *fn)
|
|
{
|
|
fn->setUWTableKind(UWTableKind::Default);
|
|
}
|
|
|
|
extern "C"
|
|
void
|
|
Add_Fn_Readonly_Attribute (Function *fn)
|
|
{
|
|
fn->setOnlyReadsMemory ();
|
|
}
|
|
|
|
extern "C"
|
|
void
|
|
Add_Named_Attribute (Function *fn, const char *name, const char *val,
|
|
LLVMContext &Ctx)
|
|
{
|
|
fn->addFnAttr (Attribute::get (Ctx, StringRef (name, strlen (name)),
|
|
StringRef (val, strlen (val))));
|
|
}
|
|
|
|
extern "C"
|
|
void
|
|
Add_Nest_Attribute (Value *v, unsigned idx)
|
|
{
|
|
if (Function *fn = dyn_cast<Function>(v))
|
|
fn->addParamAttr (idx, Attribute::Nest);
|
|
else if (CallInst *ci = dyn_cast<CallInst>(v))
|
|
ci->addParamAttr (idx, Attribute::Nest);
|
|
else if (InvokeInst *ii = dyn_cast<InvokeInst>(v))
|
|
ii->addParamAttr (idx, Attribute::Nest);
|
|
}
|
|
|
|
extern "C"
|
|
void
|
|
Add_Noalias_Attribute (Function *fn, unsigned idx)
|
|
{
|
|
fn->addParamAttr (idx, Attribute::NoAlias);
|
|
}
|
|
|
|
extern "C"
|
|
void
|
|
Add_Ret_Noalias_Attribute (Function *fn)
|
|
{
|
|
fn->addRetAttr (Attribute::NoAlias);
|
|
}
|
|
|
|
extern "C"
|
|
void
|
|
Add_Nocapture_Attribute (LLVMContext *Context, Function *fn, unsigned idx)
|
|
{
|
|
#if LLVM_VERSION_MAJOR < 21
|
|
fn->addParamAttr(idx, Attribute::NoCapture);
|
|
#else
|
|
fn->addParamAttr(
|
|
idx, Attribute::getWithCaptureInfo(*Context, CaptureInfo::none()));
|
|
#endif
|
|
}
|
|
|
|
extern "C"
|
|
void
|
|
Add_Non_Null_Attribute (Function *fn, unsigned idx)
|
|
{
|
|
fn->addParamAttr (idx, Attribute::NonNull);
|
|
}
|
|
|
|
extern "C"
|
|
void
|
|
Add_Ret_Non_Null_Attribute (Function *fn, unsigned idx)
|
|
{
|
|
fn->addRetAttr (Attribute::NonNull);
|
|
}
|
|
|
|
extern "C"
|
|
void
|
|
Add_Readonly_Attribute (Function *fn, unsigned idx)
|
|
{
|
|
fn->addParamAttr (idx, Attribute::ReadOnly);
|
|
}
|
|
|
|
extern "C"
|
|
void
|
|
Add_Writeonly_Attribute (Function *fn, unsigned idx)
|
|
{
|
|
fn->addParamAttr (idx, Attribute::WriteOnly);
|
|
}
|
|
|
|
extern "C"
|
|
void
|
|
Add_Opt_For_Fuzzing_Attribute (Function *fn)
|
|
{
|
|
fn->addFnAttr(Attribute::OptForFuzzing);
|
|
}
|
|
|
|
extern "C"
|
|
void
|
|
Add_Sanitize_Address_Attribute (Function *fn)
|
|
{
|
|
fn->addFnAttr(Attribute::SanitizeAddress);
|
|
}
|
|
|
|
extern "C"
|
|
void
|
|
Add_No_Implicit_Float_Attribute (Function *fn)
|
|
{
|
|
fn->addFnAttr(Attribute::NoImplicitFloat);
|
|
}
|
|
|
|
extern "C"
|
|
bool
|
|
Has_Inline_Attribute (Function *fn)
|
|
{
|
|
return fn->hasFnAttribute (Attribute::InlineHint);
|
|
}
|
|
|
|
extern "C"
|
|
bool
|
|
Has_Inline_Always_Attribute (Function *fn)
|
|
{
|
|
return fn->hasFnAttribute (Attribute::AlwaysInline);
|
|
}
|
|
|
|
extern "C"
|
|
bool
|
|
Has_Nest_Attribute (Function *fn, unsigned idx)
|
|
{
|
|
return fn->hasParamAttribute (idx, Attribute::Nest);
|
|
}
|
|
|
|
extern "C"
|
|
bool
|
|
Call_Param_Has_Nest (CallBase *CI, unsigned idx)
|
|
{
|
|
return CI->getAttributes ().hasParamAttr (idx, Attribute::Nest);
|
|
}
|
|
|
|
extern "C"
|
|
MDNode *
|
|
Create_TBAA_Scalar_Type_Node (LLVMContext &ctx, MDBuilder *MDHelper,
|
|
const char *name, uint64_t size, MDNode *parent)
|
|
{
|
|
Type *Int64 = Type::getInt64Ty (ctx);
|
|
auto MDname = MDHelper->createString (name);
|
|
auto MDsize = MDHelper->createConstant (ConstantInt::get (Int64, size));
|
|
return MDNode::get (ctx, {parent, MDsize, MDname});
|
|
}
|
|
|
|
extern "C"
|
|
MDNode *
|
|
Create_TBAA_Struct_Type_Node (LLVMContext &ctx, MDBuilder *MDHelper,
|
|
const char *name, uint64_t size, int num_fields,
|
|
MDNode *parent, MDNode *fields[],
|
|
uint64_t offsets[], uint64_t sizes[])
|
|
{
|
|
Type *Int64 = Type::getInt64Ty (ctx);
|
|
SmallVector<Metadata *, 8> Ops (num_fields * 3 + 3);
|
|
Ops [0] = parent;
|
|
Ops [1] = MDHelper->createConstant (ConstantInt::get (Int64, size));
|
|
Ops [2] = MDHelper->createString (name);
|
|
for (unsigned i = 0; i < num_fields; i++)
|
|
{
|
|
Ops[3 + i * 3] = fields[i];
|
|
Ops[3 + i * 3 + 1]
|
|
= MDHelper->createConstant (ConstantInt::get (Int64, offsets[i]));
|
|
Ops[3 + i * 3 + 2]
|
|
= MDHelper->createConstant (ConstantInt::get (Int64, sizes[i]));
|
|
}
|
|
|
|
return MDNode:: get (ctx, Ops);
|
|
}
|
|
|
|
extern "C"
|
|
MDNode *
|
|
Create_TBAA_Struct_Node (LLVMContext &ctx, MDBuilder *MDHelper,
|
|
int num_fields, MDNode *types[], uint64_t offsets[],
|
|
uint64_t sizes[])
|
|
{
|
|
Type *Int64 = Type::getInt64Ty (ctx);
|
|
SmallVector<Metadata *, 8> Ops (num_fields * 3);
|
|
for (unsigned i = 0; i < num_fields; i++)
|
|
{
|
|
Ops[i * 3]
|
|
= MDHelper->createConstant (ConstantInt::get (Int64, offsets[i]));
|
|
Ops[i * 3 + 1]
|
|
= MDHelper->createConstant (ConstantInt::get (Int64, sizes[i]));
|
|
Ops[i * 3 + 2] = types[i];
|
|
}
|
|
|
|
return MDNode:: get (ctx, Ops);
|
|
}
|
|
|
|
extern "C"
|
|
MDNode *
|
|
Create_TBAA_Access_Tag (MDBuilder *MDHelper, MDNode *BaseType,
|
|
MDNode *AccessType, uint64_t offset, uint64_t size)
|
|
{
|
|
return MDHelper->createTBAAAccessTag (BaseType, AccessType, offset, size,
|
|
false);
|
|
}
|
|
|
|
extern "C"
|
|
void
|
|
Set_NUW (Instruction *inst)
|
|
{
|
|
inst->setHasNoUnsignedWrap ();
|
|
}
|
|
|
|
extern "C"
|
|
void
|
|
Set_NSW (Instruction *inst)
|
|
{
|
|
inst->setHasNoSignedWrap ();
|
|
}
|
|
|
|
extern "C"
|
|
bool
|
|
Has_NSW (Instruction *inst)
|
|
{
|
|
return inst->hasNoSignedWrap ();
|
|
}
|
|
|
|
extern "C"
|
|
void
|
|
Add_TBAA_Access (Instruction *inst, MDNode *md)
|
|
{
|
|
inst->setMetadata (LLVMContext::MD_tbaa, md);
|
|
}
|
|
|
|
extern "C"
|
|
void
|
|
Set_DSO_Local (GlobalObject *GV)
|
|
{
|
|
GV->setDSOLocal (true);
|
|
}
|
|
|
|
/* Return nonnull if this value is a constant data. */
|
|
|
|
extern "C"
|
|
Value *
|
|
Is_Constant_Data (Value *v)
|
|
{
|
|
return dyn_cast<ConstantData>(v);
|
|
}
|
|
|
|
/* Say whether this struct type has a name. */
|
|
|
|
extern "C"
|
|
bool
|
|
Struct_Has_Name (StructType *t)
|
|
{
|
|
return t->hasName ();
|
|
}
|
|
|
|
/* Say whether this value has a name */
|
|
|
|
extern "C"
|
|
bool
|
|
Value_Has_Name (Value *v)
|
|
{
|
|
return v->getName ().size () != 0;
|
|
}
|
|
|
|
/* The LLVM C interface only provide single-index forms of extractvalue
|
|
and insertvalue, so provide the multi-index forms here. */
|
|
|
|
extern "C"
|
|
Value *
|
|
Build_Extract_Value_C (IRBuilder<> *bld, Value *aggr,
|
|
unsigned *IdxList, unsigned NumIdx, char *name)
|
|
{
|
|
return bld->CreateExtractValue (aggr, {IdxList, NumIdx}, name);
|
|
}
|
|
|
|
extern "C"
|
|
Value *
|
|
Build_Insert_Value_C (IRBuilder<> *bld, Value *aggr, Value *elt,
|
|
unsigned *IdxList, unsigned NumIdx, char *name)
|
|
{
|
|
return bld->CreateInsertValue (aggr, elt, {IdxList, NumIdx}, name);
|
|
}
|
|
|
|
/* The LLVM C interface only provides a subset of the arguments for building
|
|
memory copy/move/set, so we provide the full interface here. */
|
|
|
|
extern "C"
|
|
Value *
|
|
Build_MemCpy (IRBuilder<> *bld, Value *Dst, unsigned DstAlign, Value *Src,
|
|
unsigned SrcAlign, Value *Size, bool isVolatile, MDNode *TBAATag,
|
|
MDNode *TBAAStructTag, MDNode *ScopeTag, MDNode *NoAliasTag)
|
|
{
|
|
#if LLVM_VERSION_MAJOR < 21
|
|
return bld->CreateMemCpy(Dst, MaybeAlign(DstAlign), Src, MaybeAlign(SrcAlign),
|
|
Size, isVolatile, TBAATag, TBAAStructTag, ScopeTag,
|
|
NoAliasTag);
|
|
#else
|
|
return bld->CreateMemCpy(
|
|
Dst, MaybeAlign(DstAlign), Src, MaybeAlign(SrcAlign), Size, isVolatile,
|
|
AAMDNodes(TBAATag, TBAAStructTag, ScopeTag, NoAliasTag));
|
|
#endif
|
|
}
|
|
|
|
extern "C"
|
|
Value *
|
|
Build_MemMove (IRBuilder<> *bld, Value *Dst, unsigned DstAlign, Value *Src,
|
|
unsigned SrcAlign, Value *Size, bool isVolatile,
|
|
MDNode *TBAATag, MDNode *ScopeTag, MDNode *NoAliasTag)
|
|
{
|
|
#if LLVM_VERSION_MAJOR < 21
|
|
return bld->CreateMemMove(Dst, MaybeAlign(DstAlign), Src,
|
|
MaybeAlign(SrcAlign), Size, isVolatile, TBAATag,
|
|
ScopeTag, NoAliasTag);
|
|
#else
|
|
return bld->CreateMemMove(Dst, MaybeAlign(DstAlign), Src,
|
|
MaybeAlign(SrcAlign), Size, isVolatile,
|
|
AAMDNodes(TBAATag, nullptr, ScopeTag, NoAliasTag));
|
|
#endif
|
|
}
|
|
|
|
extern "C"
|
|
Value *
|
|
Build_MemSet (IRBuilder<> *bld, Value *Ptr, Value *Val, Value *Size,
|
|
unsigned align, bool isVolatile, MDNode *TBAATag,
|
|
MDNode *ScopeTag, MDNode *NoAliasTag)
|
|
{
|
|
#if LLVM_VERSION_MAJOR < 21
|
|
return bld->CreateMemSet(Ptr, Val, Size, MaybeAlign(align), isVolatile,
|
|
TBAATag, ScopeTag, NoAliasTag);
|
|
#else
|
|
return bld->CreateMemSet(Ptr, Val, Size, MaybeAlign(align), isVolatile,
|
|
AAMDNodes(TBAATag, nullptr, ScopeTag, NoAliasTag));
|
|
#endif
|
|
}
|
|
|
|
extern "C"
|
|
CallInst *
|
|
Create_Lifetime_Start (IRBuilder<> *bld, Value *Ptr, ConstantInt *Size)
|
|
{
|
|
return bld->CreateLifetimeStart (Ptr, Size);
|
|
}
|
|
|
|
extern "C"
|
|
CallInst *
|
|
Create_Lifetime_End (IRBuilder<> *bld, Value *Ptr, ConstantInt *Size)
|
|
{
|
|
return bld->CreateLifetimeEnd (Ptr, Size);
|
|
}
|
|
|
|
extern "C"
|
|
CallInst *
|
|
Create_Invariant_Start (IRBuilder<> *bld, Value *Ptr, ConstantInt *Size)
|
|
{
|
|
return bld->CreateInvariantStart (Ptr, Size);
|
|
}
|
|
|
|
extern "C"
|
|
unsigned char
|
|
Does_Not_Throw (Function *fn)
|
|
{
|
|
return fn->doesNotThrow () ? 1 : 0;
|
|
}
|
|
|
|
extern "C"
|
|
void
|
|
Set_Does_Not_Throw (Function *fn)
|
|
{
|
|
return fn->setDoesNotThrow ();
|
|
}
|
|
|
|
extern "C"
|
|
unsigned char
|
|
Does_Not_Return (Function *fn)
|
|
{
|
|
return fn->doesNotReturn () ? 1 : 0;
|
|
}
|
|
|
|
extern "C"
|
|
void
|
|
Set_Does_Not_Return (Function *fn)
|
|
{
|
|
return fn->setDoesNotReturn ();
|
|
}
|
|
|
|
/* The LLVM C procedure Set_Volatile only works for loads and stores, not
|
|
Atomic instructions. */
|
|
|
|
extern "C"
|
|
void
|
|
Set_Volatile_For_Atomic (Instruction *inst)
|
|
{
|
|
if (AtomicRMWInst *ARW = dyn_cast<AtomicRMWInst>(inst))
|
|
ARW->setVolatile (true);
|
|
else
|
|
cast<AtomicCmpXchgInst>(inst)->setVolatile (true);
|
|
}
|
|
|
|
extern "C"
|
|
void
|
|
Set_Weak_For_Atomic_Xchg (AtomicCmpXchgInst *inst)
|
|
{
|
|
inst->setWeak (true);
|
|
}
|
|
|
|
extern "C"
|
|
void
|
|
Add_Function_To_Module (Function *f, Module *m, bool allowDeduplication)
|
|
{
|
|
// Check if the function already exists in the module. We only add imported
|
|
// functions to the module after we've processed the entire GNAT tree, and we
|
|
// deduplicate based on GNAT node IDs. However, builtin functions such as
|
|
// __gnat_last_chance_handler are processed separately (because there is no
|
|
// associated node in the GNAT tree) and added eagerly to the module.
|
|
//
|
|
// If a module uses a builtin function implicitly and also calls it
|
|
// explicitly, we don't want two LLVM values representing the same function.
|
|
// In this case, we replace all uses of one with the other (unless they're
|
|
// identical), which is safe because the LLVM value is just a declaration for
|
|
// a function to be imported.
|
|
|
|
auto existingFunction = m->getFunction(f->getName());
|
|
if (existingFunction == f)
|
|
return;
|
|
|
|
if (existingFunction && !allowDeduplication) {
|
|
assert(f->isDeclaration() && existingFunction->isDeclaration() &&
|
|
f->getFunctionType() == existingFunction->getFunctionType());
|
|
f->replaceAllUsesWith(existingFunction);
|
|
delete f;
|
|
} else {
|
|
m->getFunctionList().push_back(f);
|
|
}
|
|
}
|
|
|
|
extern "C"
|
|
void
|
|
Dump_Metadata (MDNode *MD)
|
|
{
|
|
MD->print (errs ());
|
|
}
|
|
|
|
extern "C"
|
|
unsigned
|
|
Get_Metadata_Num_Operands (MDNode *MD)
|
|
{
|
|
return MD->getNumOperands ();
|
|
}
|
|
|
|
extern "C"
|
|
uint64_t
|
|
Get_Metadata_Operand_Constant_Value (MDNode *MD, unsigned i)
|
|
{
|
|
return mdconst::extract<ConstantInt> (MD->getOperand (i))->getZExtValue ();
|
|
}
|
|
|
|
extern "C"
|
|
MDNode *
|
|
Get_Metadata_Operand (MDNode *MD, unsigned i)
|
|
{
|
|
return dyn_cast<MDNode>(MD->getOperand (i));
|
|
}
|
|
|
|
extern "C"
|
|
void
|
|
Initialize_LLVM (void)
|
|
{
|
|
// Initialize the target registry etc. These functions appear to be
|
|
// in LLVM.Target, but they reference static inline function, so they
|
|
// can only be used from C, not Ada.
|
|
|
|
InitializeAllTargetInfos ();
|
|
InitializeAllTargets ();
|
|
InitializeAllTargetMCs ();
|
|
InitializeAllAsmParsers ();
|
|
InitializeAllAsmPrinters ();
|
|
}
|
|
|
|
// Description of C type properties to pass to Ada. Unless otherwise noted,
|
|
// sizes are in bits.
|
|
struct Target_C_Type_Info {
|
|
unsigned PointerSize;
|
|
unsigned CharSize;
|
|
unsigned WCharTSize;
|
|
unsigned ShortSize;
|
|
unsigned IntSize;
|
|
unsigned LongSize;
|
|
unsigned LongLongSize;
|
|
unsigned LongLongAlignment;
|
|
unsigned LongLongLongSize;
|
|
unsigned LongLongLongAlignment;
|
|
unsigned DoubleSize;
|
|
unsigned DoubleAlignment;
|
|
unsigned LongDoubleSemanticSize; // 0 if the target doesn't have long double
|
|
unsigned LongDoubleStorageSize; // 0 if the target doesn't have long double
|
|
unsigned LongDoubleAlignment; // 0 if the target doesn't have long double
|
|
unsigned MaximumAlignmentBytes;
|
|
unsigned RegisterSize;
|
|
unsigned SystemAllocatorAlignment;
|
|
};
|
|
|
|
extern "C"
|
|
void
|
|
Get_Target_C_Types (const char *TargetTriple, const char *CPU, const char *ABI,
|
|
const char *Features, Target_C_Type_Info *Result,
|
|
int Emit_C, unsigned char *success)
|
|
{
|
|
*Result = {};
|
|
*success = 0;
|
|
|
|
auto Options = std::make_shared<clang::TargetOptions>();
|
|
Options->Triple = TargetTriple;
|
|
|
|
std::string CPUString = CPU;
|
|
if (CPUString != "generic") // GNAT-LLVM's default CPU, unknown to LLVM
|
|
Options->CPU = CPU;
|
|
|
|
std::string FeatureString = Features;
|
|
if (!FeatureString.empty()) {
|
|
SmallVector<StringRef, 16> FeatureVector;
|
|
SplitString(FeatureString, FeatureVector, ",");
|
|
for (const auto F : FeatureVector)
|
|
Options->Features.push_back(F.str());
|
|
}
|
|
|
|
// The Clang API requires us to provide a handler for diagnostic messages
|
|
// emitted during the operation.
|
|
//
|
|
// ??? Use a real diagnostics consumer if we ever get an error from Clang.
|
|
IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
|
|
#if LLVM_VERSION_MAJOR < 21
|
|
IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
|
|
DiagnosticsEngine Diags(DiagID, &*DiagOpts, new IgnoringDiagConsumer());
|
|
#else
|
|
DiagnosticOptions DiagOpts;
|
|
DiagnosticsEngine Diags(DiagID, DiagOpts, new IgnoringDiagConsumer());
|
|
#endif
|
|
|
|
// Finally, we can create the TargetInfo structure.
|
|
#if LLVM_VERSION_MAJOR < 21
|
|
std::unique_ptr<TargetInfo> Info(
|
|
TargetInfo::CreateTargetInfo(Diags, Options));
|
|
#else
|
|
std::unique_ptr<TargetInfo> Info(
|
|
TargetInfo::CreateTargetInfo(Diags, *Options));
|
|
#endif
|
|
|
|
std::string ABIString = ABI;
|
|
if (!ABIString.empty())
|
|
Info->setABI(ABIString);
|
|
|
|
if (Info == nullptr)
|
|
return;
|
|
|
|
Result->PointerSize = Info->getPointerWidth(LangAS::Default);
|
|
Result->CharSize = Info->getCharWidth();
|
|
Result->WCharTSize = Info->getWCharWidth();
|
|
Result->ShortSize = Info->getShortWidth();
|
|
Result->IntSize = Info->getIntWidth();
|
|
Result->LongSize = Info->getLongWidth();
|
|
Result->LongLongSize = Info->getLongLongWidth();
|
|
Result->LongLongAlignment = Info->getLongLongAlign();
|
|
if (Info->hasInt128Type() && !Emit_C) {
|
|
Result->LongLongLongSize = 128;
|
|
Result->LongLongLongAlignment = Info->getInt128Align();
|
|
} else {
|
|
Result->LongLongLongSize = Result->LongLongSize;
|
|
Result->LongLongLongAlignment = Result->LongLongAlignment;
|
|
}
|
|
Result->DoubleSize = Info->getDoubleWidth();
|
|
Result->DoubleAlignment = Info->getDoubleAlign();
|
|
if (Info->hasLongDoubleType()) {
|
|
Result->LongDoubleSemanticSize =
|
|
APFloat::semanticsSizeInBits(Info->getLongDoubleFormat());
|
|
Result->LongDoubleStorageSize = Info->getLongDoubleWidth();
|
|
Result->LongDoubleAlignment = Info->getLongDoubleAlign();
|
|
}
|
|
Result->MaximumAlignmentBytes = Info->getSuitableAlign() / 8;
|
|
Result->RegisterSize = Info->getRegisterWidth();
|
|
Result->SystemAllocatorAlignment = Info->getNewAlign() / 8;
|
|
|
|
// For Linux on x86, we know that the allocated memory is even more strictly
|
|
// aligned than what LLVM thinks.
|
|
Triple TT(TargetTriple);
|
|
if (TT.getArch() == Triple::x86 && TT.isOSLinux())
|
|
Result->SystemAllocatorAlignment = 16;
|
|
|
|
*success = 1;
|
|
}
|
|
|
|
/* This is a dummy optimization "pass" that serves just to obtain loop
|
|
information when generating C.
|
|
|
|
For now, we don't actually do anything except collect information to look
|
|
at in the debugger. */
|
|
|
|
namespace llvm
|
|
{
|
|
class Loop;
|
|
|
|
struct OurLoopPass : PassInfoMixin<OurLoopPass>
|
|
{
|
|
public:
|
|
PreservedAnalyses run (Loop &L, LoopAnalysisManager &AM,
|
|
LoopStandardAnalysisResults &AR, LPMUpdater &U);
|
|
static bool isRequired ()
|
|
{
|
|
return true;
|
|
}
|
|
};
|
|
}
|
|
|
|
PreservedAnalyses
|
|
OurLoopPass::run (Loop &L, LoopAnalysisManager &LAM,
|
|
LoopStandardAnalysisResults &AR, LPMUpdater &U)
|
|
{
|
|
|
|
auto pre = L.getLoopPreheader ();
|
|
auto header = L.getHeader ();
|
|
auto latch = L.getLoopLatch ();
|
|
auto cmp = L.getLatchCmpInst ();
|
|
auto issimple = L.isLoopSimplifyForm ();
|
|
return PreservedAnalyses::all ();
|
|
}
|
|
|
|
extern "C"
|
|
LLVMBool
|
|
LLVM_Optimize_Module (Module *M, TargetMachine *TM, int CodeOptLevel,
|
|
int SizeOptLevel, bool NeedLoopInfo, bool UnrollLoops,
|
|
bool LoopVectorization, bool SLPVectorization,
|
|
bool MergeFunctions, bool PrepareForThinLTO,
|
|
bool PrepareForLTO, bool RerollLoops, bool EnableFuzzer,
|
|
bool EnableAddressSanitizer, const char *SanCovAllowList,
|
|
const char *SanCovIgnoreList, const char *PassPluginName,
|
|
char **ErrorMessage) {
|
|
// This code is derived from EmitAssemblyWithNewPassManager in clang
|
|
|
|
std::optional<PGOOptions> PGOOpt;
|
|
PipelineTuningOptions PTO;
|
|
PassInstrumentationCallbacks PIC;
|
|
Triple TargetTriple (M->getTargetTriple ());
|
|
OptimizationLevel Level
|
|
= (CodeOptLevel == 1 ? OptimizationLevel::O1
|
|
: CodeOptLevel == 2 ? OptimizationLevel::O2
|
|
: CodeOptLevel == 3 ? OptimizationLevel::O3
|
|
: OptimizationLevel::O0);
|
|
PTO.LoopUnrolling = UnrollLoops;
|
|
PTO.LoopInterleaving = UnrollLoops;
|
|
PTO.LoopVectorization = LoopVectorization;
|
|
PTO.SLPVectorization = SLPVectorization;
|
|
PTO.MergeFunctions = MergeFunctions;
|
|
|
|
LoopAnalysisManager LAM;
|
|
FunctionAnalysisManager FAM;
|
|
CGSCCAnalysisManager CGAM;
|
|
ModuleAnalysisManager MAM;
|
|
|
|
PassBuilder PB (TM, PTO, PGOOpt, &PIC);
|
|
|
|
if (PassPluginName != nullptr)
|
|
{
|
|
auto Plugin = PassPlugin::Load (PassPluginName);
|
|
|
|
if (auto Err = Plugin.takeError())
|
|
{
|
|
handleAllErrors(std::move(Err), [&](const StringError &Err) {
|
|
if (ErrorMessage != nullptr)
|
|
*ErrorMessage = strdup (Err.getMessage().c_str());
|
|
});
|
|
|
|
return 1;
|
|
}
|
|
|
|
Plugin->registerPassBuilderCallbacks(PB);
|
|
}
|
|
|
|
FAM.registerPass ([&] { return PB.buildDefaultAAPipeline (); });
|
|
|
|
// Register the target library analysis directly and give it a customized
|
|
// preset TLI.
|
|
TargetLibraryInfoImpl *TLII = new TargetLibraryInfoImpl(TargetTriple);
|
|
FAM.registerPass ([&] { return TargetLibraryAnalysis (*TLII); });
|
|
|
|
// Register all the basic analyses with the managers.
|
|
|
|
PB.registerModuleAnalyses (MAM);
|
|
PB.registerCGSCCAnalyses (CGAM);
|
|
PB.registerFunctionAnalyses (FAM);
|
|
PB.registerLoopAnalyses (LAM);
|
|
PB.crossRegisterProxies (LAM, FAM, CGAM, MAM);
|
|
|
|
// Register additional passes for the sanitizers if applicable. This code is
|
|
// inspired by addSanitizers in LLVM's clang/lib/CodeGen/BackendUtil.cpp.
|
|
PB.registerOptimizerLastEPCallback(
|
|
#if LLVM_VERSION_MAJOR < 21
|
|
[&](ModulePassManager &MPM, OptimizationLevel Level) {
|
|
#else
|
|
[&](ModulePassManager &MPM, OptimizationLevel Level, ThinOrFullLTOPhase) {
|
|
#endif
|
|
if (EnableFuzzer) {
|
|
// Configure sanitizer coverage according to what Clang does in
|
|
// clang/lib/Driver/SanitizerArgs.cpp when the fuzzer is enabled.
|
|
SanitizerCoverageOptions CoverageOpts;
|
|
CoverageOpts.CoverageType = SanitizerCoverageOptions::SCK_Edge;
|
|
CoverageOpts.Inline8bitCounters = true;
|
|
CoverageOpts.IndirectCalls = true;
|
|
CoverageOpts.TraceCmp = true;
|
|
CoverageOpts.PCTable = true;
|
|
if (TargetTriple.isOSLinux())
|
|
CoverageOpts.StackDepth = true;
|
|
|
|
std::vector<std::string> AllowListFiles;
|
|
if (SanCovAllowList != nullptr)
|
|
AllowListFiles.push_back(SanCovAllowList);
|
|
|
|
std::vector<std::string> IgnoreListFiles;
|
|
if (SanCovIgnoreList != nullptr)
|
|
IgnoreListFiles.push_back(SanCovIgnoreList);
|
|
|
|
MPM.addPass(SanitizerCoveragePass(CoverageOpts, AllowListFiles,
|
|
IgnoreListFiles));
|
|
}
|
|
|
|
if (EnableAddressSanitizer)
|
|
MPM.addPass(AddressSanitizerPass(AddressSanitizerOptions()));
|
|
});
|
|
|
|
ModulePassManager MPM;
|
|
if (CodeOptLevel == 0)
|
|
{
|
|
#if LLVM_VERSION_MAJOR < 21
|
|
bool LTOPhase = PrepareForLTO || PrepareForThinLTO;
|
|
#else
|
|
ThinOrFullLTOPhase LTOPhase = ThinOrFullLTOPhase::None;
|
|
if (PrepareForLTO) {
|
|
LTOPhase = ThinOrFullLTOPhase::FullLTOPreLink;
|
|
} else if (PrepareForThinLTO) {
|
|
LTOPhase = ThinOrFullLTOPhase::ThinLTOPreLink;
|
|
}
|
|
#endif
|
|
MPM = PB.buildO0DefaultPipeline(Level, LTOPhase);
|
|
if (NeedLoopInfo)
|
|
MPM.addPass(createModuleToFunctionPassAdaptor(
|
|
createFunctionToLoopPassAdaptor(LoopRotatePass())));
|
|
} else if (PrepareForThinLTO)
|
|
MPM = PB.buildThinLTOPreLinkDefaultPipeline (Level);
|
|
else if (PrepareForLTO)
|
|
MPM = PB.buildLTOPreLinkDefaultPipeline (Level);
|
|
else
|
|
MPM = PB.buildPerModuleDefaultPipeline (Level);
|
|
|
|
if (NeedLoopInfo)
|
|
MPM.addPass (createModuleToFunctionPassAdaptor
|
|
(createFunctionToLoopPassAdaptor (OurLoopPass ())));
|
|
MPM.run (*M, MAM);
|
|
return 0;
|
|
}
|
|
|
|
extern "C"
|
|
Value *
|
|
Get_Float_From_Words_And_Exp (LLVMContext *Context, Type *T, int Exp,
|
|
unsigned NumWords, const uint64_t Words[])
|
|
{
|
|
auto LongInt = APInt (NumWords * 64, {Words, NumWords});
|
|
auto Initial = APFloat (T->getFltSemantics (),
|
|
APInt::getZero(T->getPrimitiveSizeInBits()));
|
|
Initial.convertFromAPInt (LongInt, false, APFloat::rmTowardZero);
|
|
auto Result = scalbn (Initial, Exp, APFloat::rmTowardZero);
|
|
return ConstantFP::get (*Context, Result);
|
|
}
|
|
|
|
extern "C"
|
|
Value *
|
|
Pred_FP (LLVMContext *Context, Type *T, Value *Val)
|
|
{
|
|
// We want to compute the predecessor of Val, but the "next" function
|
|
// can return unnormalized, so we have to multiply by one (adding zero
|
|
// doesn't do it).
|
|
auto apf = dyn_cast<ConstantFP>(Val)->getValueAPF ();
|
|
auto one = APFloat (T->getFltSemantics (), 1);
|
|
apf.next (true);
|
|
apf.multiply (one, APFloat::rmTowardZero);
|
|
return ConstantFP:: get (*Context, apf);
|
|
}
|
|
|
|
extern "C"
|
|
int
|
|
Convert_FP_To_String (Value *V, char *Buf)
|
|
{
|
|
const APFloat &APF = dyn_cast<ConstantFP>(V)->getValueAPF ();
|
|
|
|
if (&APF.getSemantics () == &APFloat::IEEEsingle ()
|
|
|| &APF.getSemantics () == &APFloat::IEEEdouble ())
|
|
{
|
|
if (!APF.isInfinity () && !APF.isNaN ())
|
|
{
|
|
SmallString<128> StrVal;
|
|
APF.toString (StrVal, 0, 0, false);
|
|
|
|
if (&APF.getSemantics () == &APFloat::IEEEsingle ())
|
|
StrVal += "f";
|
|
|
|
strcpy (Buf, StrVal.c_str ());
|
|
return strlen (Buf);
|
|
}
|
|
|
|
// Output special values in hexadecimal format
|
|
std::string S =
|
|
("0x" + utohexstr (APF.bitcastToAPInt ().getZExtValue (),
|
|
/*Lower=*/true)
|
|
+ "p0");
|
|
|
|
std::strcpy (Buf, S.c_str ());
|
|
return S.length ();
|
|
}
|
|
|
|
return strlen (strcpy (Buf, "<unsupported floating point type>"));
|
|
}
|
|
|
|
extern "C"
|
|
Value *
|
|
Get_Infinity (Type *T)
|
|
{
|
|
return ConstantFP::getInfinity (T, false);
|
|
}
|
|
|
|
extern "C"
|
|
bool
|
|
Equals_Int (ConstantInt *v, uint64_t val)
|
|
{
|
|
return v->equalsInt (val);
|
|
}
|
|
|
|
/* Return whether V1 and V2 have the same constant values, interpreted as
|
|
signed integers. If the sizes differ, we have to convert to the
|
|
widest size. */
|
|
|
|
extern "C"
|
|
bool
|
|
Equal_Constants (ConstantInt *v1, ConstantInt *v2)
|
|
{
|
|
APInt i1 = v1->getValue (), i2 = v2->getValue ();
|
|
|
|
if (i1.getBitWidth () > i2.getBitWidth ())
|
|
i2 = i2.sext (i1.getBitWidth ());
|
|
else if (i2.getBitWidth () > i1.getBitWidth ())
|
|
i1 = i1.sext (i2.getBitWidth ());
|
|
return i1 == i2;
|
|
}
|
|
|
|
extern "C"
|
|
bool
|
|
Get_GEP_Constant_Offset (Value *GEP, DataLayout &dl, uint64_t *result)
|
|
{
|
|
auto Offset =
|
|
APInt(dl.getIndexSizeInBits(GEP->getType()->getPointerAddressSpace()), 0);
|
|
auto GEPO = dyn_cast<GEPOperator>(GEP);
|
|
|
|
if (!GEPO || !GEPO->accumulateConstantOffset (dl, Offset)
|
|
|| !Offset.isIntN (64))
|
|
return false;
|
|
|
|
*result = Offset.getZExtValue ();
|
|
return true;
|
|
}
|
|
|
|
extern "C"
|
|
int64_t
|
|
Get_Element_Offset (DataLayout &DL, StructType *ST, unsigned idx)
|
|
{
|
|
const StructLayout *SL = DL.getStructLayout (ST);
|
|
return SL->getElementOffset (idx);
|
|
}
|
|
|
|
extern "C"
|
|
unsigned
|
|
Get_Num_CDA_Elements (ConstantDataArray *CA)
|
|
{
|
|
return CA->getNumElements ();
|
|
}
|
|
|
|
extern "C"
|
|
bool
|
|
Is_C_String (ConstantDataSequential *CDS)
|
|
{
|
|
return CDS->isCString ();
|
|
}
|
|
|
|
/* There are two LLVM "opcodes": the real LLVM opcode, which is used
|
|
throughout the LLVM C++ interface, and a "stable" version of the
|
|
opcodes, that's used in the C interface. We need to map between them,
|
|
but the only function to do so in LLVM is static (in Core.cpp), so we
|
|
duplicate that small function here. */
|
|
|
|
static int map_from_llvmopcode (LLVMOpcode code)
|
|
{
|
|
switch (code)
|
|
{
|
|
#define HANDLE_INST(num, opc, clas) case LLVM##opc: return num;
|
|
#include "llvm/IR/Instruction.def"
|
|
#undef HANDLE_INST
|
|
}
|
|
|
|
llvm_unreachable ("Unhandled Opcode.");
|
|
}
|
|
|
|
extern "C"
|
|
const char *
|
|
Get_Opcode_Name (LLVMOpcode opc)
|
|
{
|
|
return Instruction::getOpcodeName (map_from_llvmopcode (opc));
|
|
}
|
|
|
|
extern "C"
|
|
Type *
|
|
Get_Load_Store_Type (Value *I)
|
|
{
|
|
return getLoadStoreType (I);
|
|
}
|
|
|
|
extern "C"
|
|
Type *
|
|
Get_Source_Element_Type (Value *I)
|
|
{
|
|
auto *GEPO = cast<GEPOperator>(I);
|
|
return GEPO->getSourceElementType ();
|
|
}
|
|
|
|
extern "C"
|
|
Type *
|
|
Get_Function_Type (Function *F)
|
|
{
|
|
return F->getFunctionType ();
|
|
}
|
|
|
|
extern "C"
|
|
BasicBlock *Get_Unique_Predecessor (BasicBlock *bb)
|
|
{
|
|
return bb->getUniquePredecessor ();
|
|
}
|
|
|
|
extern "C"
|
|
void
|
|
Invert_Predicate (CmpInst *c)
|
|
{
|
|
c->setPredicate (c->getInversePredicate ());
|
|
}
|
|
|
|
extern "C"
|
|
void
|
|
Swap_Successors (BranchInst *c)
|
|
{
|
|
c->swapSuccessors ();
|
|
}
|
|
|
|
extern "C"
|
|
void
|
|
Replace_Inst_With_Inst (Instruction *from, Instruction *to)
|
|
{
|
|
ReplaceInstWithInst (from, to);
|
|
}
|
|
|
|
extern "C"
|
|
BinaryOperator *
|
|
Create_And (Value *Op1, Value *Op2)
|
|
{
|
|
return BinaryOperator::CreateAnd (Op1, Op2);
|
|
}
|
|
|
|
extern "C"
|
|
BinaryOperator *
|
|
Create_Or (Value *Op1, Value *Op2)
|
|
{
|
|
return BinaryOperator::CreateOr (Op1, Op2);
|
|
}
|
|
|
|
extern "C"
|
|
CallInst *
|
|
Create_Call_2 (Function *Fn, Value *op1, Value *op2)
|
|
{
|
|
return CallInst::Create (Fn, {op1, op2});
|
|
}
|
|
|
|
extern "C"
|
|
ReturnInst *
|
|
Create_Return (LLVMContext &C, Value *retVal)
|
|
{
|
|
return ReturnInst::Create (C, retVal);
|
|
}
|
|
|
|
extern "C"
|
|
BranchInst *
|
|
Create_Br (BasicBlock *dest)
|
|
{
|
|
return BranchInst::Create (dest);
|
|
}
|
|
|
|
extern "C"
|
|
void
|
|
Insert_At_Block_End (Instruction *I, BasicBlock *BB, Instruction *From)
|
|
{
|
|
I->insertInto (BB, BB->end());
|
|
I->setDebugLoc (From->getDebugLoc ());
|
|
}
|
|
|
|
extern "C"
|
|
AllocaInst *
|
|
Insert_Alloca_Before (Type *Ty, Instruction *Before)
|
|
{
|
|
auto Inst = new AllocaInst (Ty, 0, "", Before);
|
|
Inst->setDebugLoc (Before->getDebugLoc ());
|
|
return Inst;
|
|
}
|
|
|
|
extern "C"
|
|
LoadInst*
|
|
Insert_Load_Before (Type *Ty, Value *Ptr, Instruction *Before)
|
|
{
|
|
auto Inst = new LoadInst (Ty, Ptr, "", Before);
|
|
Inst->setDebugLoc (Before->getDebugLoc ());
|
|
return Inst;
|
|
}
|
|
|
|
extern "C"
|
|
void
|
|
Insert_Store_Before (Value *Val, Value *Ptr, Instruction *Before)
|
|
{
|
|
auto Inst = new StoreInst (Val, Ptr, Before);
|
|
Inst->setDebugLoc (Before->getDebugLoc ());
|
|
}
|
|
|
|
extern "C"
|
|
bool
|
|
All_Preds_Are_Unc_Branches (BasicBlock *BB)
|
|
{
|
|
for (auto *PBB : predecessors (BB))
|
|
if (PBB->getTerminator ()->getNumSuccessors () != 1)
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
extern "C"
|
|
bool
|
|
Is_Dead_Basic_Block (BasicBlock *BB)
|
|
{
|
|
return BB->hasNPredecessors (0);
|
|
}
|
|
|
|
extern "C"
|
|
Value *
|
|
Get_First_Non_Phi_Or_Dbg (BasicBlock *BB)
|
|
{
|
|
#if LLVM_VERSION_MAJOR < 21
|
|
return BB->getFirstNonPHIOrDbg();
|
|
#else
|
|
return &*BB->getFirstNonPHIOrDbg();
|
|
#endif
|
|
}
|
|
|
|
extern "C"
|
|
bool
|
|
Is_Lifetime_Intrinsic (Instruction *v)
|
|
{
|
|
return v->isLifetimeStartOrEnd ();
|
|
}
|
|
|
|
extern "C"
|
|
void
|
|
Delete_Trailing_Dbg_Records (BasicBlock *b)
|
|
{
|
|
b->deleteTrailingDbgRecords();
|
|
}
|
|
|
|
/* If we call into CCG from GNAT LLVM during the compilation process to
|
|
record some information about a Value (for example, its signedness),
|
|
there's a chance that that value will be deleted during the optimization
|
|
process and that same address used for some other value. So we need to
|
|
set a callback on that value to notify us that this happened so we can
|
|
delete the value from our table. The below class and function is used
|
|
for that purpose. */
|
|
|
|
class GNATCallbackVH final : public CallbackVH
|
|
{
|
|
void (*fn) (Value *);
|
|
void deleted () override;
|
|
|
|
public:
|
|
GNATCallbackVH (Value *V, void (*Fn) (Value *));
|
|
};
|
|
|
|
void
|
|
GNATCallbackVH::deleted()
|
|
{
|
|
(this->fn) (getValPtr());
|
|
|
|
// This callback object is no longer needed, and we don't keep references to
|
|
// it anywhere, so self-delete.
|
|
delete this;
|
|
}
|
|
|
|
GNATCallbackVH::GNATCallbackVH (Value *V, void (*Fn) (Value *))
|
|
: CallbackVH (V), fn (Fn)
|
|
{
|
|
}
|
|
|
|
extern "C"
|
|
void
|
|
Notify_On_Value_Delete (Value *V, void (*Fn) (Value *))
|
|
{
|
|
GNATCallbackVH *CB= new GNATCallbackVH (V, Fn);
|
|
}
|
|
|
|
extern "C"
|
|
void
|
|
Set_Module_PIC_PIE (Module *M, int PIC, int PIE)
|
|
{
|
|
M->setPICLevel(static_cast<PICLevel::Level>(PIC));
|
|
M->setPIELevel(static_cast<PIELevel::Level>(PIE));
|
|
}
|
|
|
|
extern "C"
|
|
void
|
|
Set_Unwind_Tables (Module *M)
|
|
{
|
|
M->setUwtable(UWTableKind::Default);
|
|
}
|
|
|
|
extern "C"
|
|
void
|
|
Enable_Frame_Pointers (Module *M)
|
|
{
|
|
M->setFramePointer(FramePointerKind::All);
|
|
}
|
|
|
|
extern "C"
|
|
bool
|
|
Has_Default_PIE (const char *Target)
|
|
{
|
|
Triple TargetTriple(Target);
|
|
|
|
// Like Clang, we default to PIE on Linux and x86_64 Windows (out of the
|
|
// supported targets). See the comment at the call site in GNATLLVM.Codegen
|
|
// for details.
|
|
return TargetTriple.isOSLinux() ||
|
|
(TargetTriple.isOSWindows() && TargetTriple.getArch() == Triple::x86_64);
|
|
}
|
|
|
|
extern "C"
|
|
bool
|
|
Has_SEH (const char *Target)
|
|
{
|
|
Triple TargetTriple(Target);
|
|
|
|
return TargetTriple.isOSWindows ()
|
|
&& (TargetTriple.getArch () == Triple::x86_64
|
|
|| TargetTriple.getArch () == Triple::aarch64);
|
|
}
|
|
|
|
extern "C"
|
|
bool
|
|
Needs_Frame_Pointers (const char *Target)
|
|
{
|
|
Triple TargetTriple(Target);
|
|
|
|
// Like GCC, we enable frame pointers for x86 because backtrace computations
|
|
// rely on them, except on Linux where they use DWARF.
|
|
return !TargetTriple.isOSLinux() && (TargetTriple.getArch() == Triple::x86);
|
|
}
|
|
|
|
extern "C"
|
|
bool
|
|
Is_x86 (const char *Target)
|
|
{
|
|
Triple TargetTriple(Target);
|
|
return TargetTriple.getArch () == Triple::x86;
|
|
}
|
|
|
|
extern "C"
|
|
const char *
|
|
Get_Personality_Function_Name (const char *Target)
|
|
{
|
|
// For now, we don't support SJLJ exceptions, so we just need to decide
|
|
// whether the target uses SEH.
|
|
if (Has_SEH (Target))
|
|
return "__gnat_personality_seh0";
|
|
else
|
|
return "__gnat_personality_v0";
|
|
}
|
|
|
|
extern "C"
|
|
char *
|
|
Get_Features (const char *TargetTriple, const char *Arch, const char *CPU)
|
|
{
|
|
// This is a simplified version of Clang's tools::getTargetFeatures (see
|
|
// clang/lib/Driver/ToolChains/CommonArgs.cpp), adapted to the arguments that
|
|
// we have available and the defaults that we set during option parsing.
|
|
|
|
Triple T(TargetTriple);
|
|
|
|
// ??? We may want to add code for more target architectures here; Clang
|
|
// often puts it in clang/lib/Driver/ToolChains/Arch/.
|
|
|
|
switch (T.getArch()) {
|
|
default:
|
|
return nullptr;
|
|
|
|
case Triple::aarch64: {
|
|
// Here we replicate relevant parts of Clang's aarch64::getAArch64Features
|
|
// (see clang/lib/Driver/ToolChains/Arch/AArch64.cpp).
|
|
|
|
std::vector<StringRef> Features;
|
|
|
|
// Clang enables NEON by default, so we do the same.
|
|
Features.push_back("+neon");
|
|
|
|
auto ArchLowerCase = StringRef(Arch).lower();
|
|
if (ArchLowerCase.empty()) {
|
|
// Clang defaults to ARMv8-A if the user hasn't specified a CPU either,
|
|
// so let's do the same.
|
|
if (StringRef(CPU) == "generic")
|
|
ArchLowerCase = "armv8-a";
|
|
else
|
|
// ??? Clang can also derive the list of features from -mcpu (which only
|
|
// happens if -march isn't specified); we may want to do the same here.
|
|
return nullptr;
|
|
}
|
|
|
|
// The -march option value has the format
|
|
// "architecture+feature1+feature2", so first split the architecture from
|
|
// the list of features.
|
|
auto const ArchSplit = StringRef(ArchLowerCase).split("+");
|
|
auto const ArchInfo = AArch64::parseArch(ArchSplit.first);
|
|
|
|
if (ArchInfo == nullptr) {
|
|
errs() << "warning: ignoring unsupported -march value " << Arch << "\n";
|
|
return nullptr;
|
|
}
|
|
|
|
Features.push_back(ArchInfo->ArchFeature);
|
|
|
|
// Now process the user-specified additional features, if any.
|
|
if (!ArchSplit.second.empty()) {
|
|
SmallVector<StringRef, 8> FeatureSplit;
|
|
ArchSplit.second.split(FeatureSplit, "+", /*MaxSplit=*/-1,
|
|
/*KeepEmpty=*/false);
|
|
|
|
for (auto const Feature : FeatureSplit) {
|
|
auto const FeatureName = AArch64::getArchExtFeature(Feature);
|
|
if (!FeatureName.empty())
|
|
Features.push_back(FeatureName);
|
|
else
|
|
errs() << "warning: ignoring unsupported feature " << Feature << "\n";
|
|
}
|
|
}
|
|
|
|
// ??? There is a lot more in Clang's AArch64 feature lookup code that we
|
|
// may want to copy.
|
|
|
|
return strdup(join(Features, ",").c_str());
|
|
}
|
|
}
|
|
}
|
|
|
|
extern "C"
|
|
const char *
|
|
Get_Target_Default_CPU (const char *TargetTriple)
|
|
{
|
|
// Select a default CPU for a given target triple.
|
|
//
|
|
// For now do that only for x86 triples, but this might get extended later.
|
|
//
|
|
// If not selected explicitly, set the same default CPU as Clang does.
|
|
// Consistency with Clang is generally useful, and on x86 in particular,
|
|
// the choice of CPU results in selection of features.
|
|
// In this case the use of SSE rather than x87 for floating point
|
|
// operations improves rounding behavior.
|
|
//
|
|
// Return "generic" for anything else than x86.
|
|
|
|
Triple T(TargetTriple);
|
|
|
|
switch (T.getArch()) {
|
|
default:
|
|
return "generic";
|
|
case llvm::Triple::x86_64:
|
|
return "x86-64";
|
|
case llvm::Triple::x86:
|
|
return "pentium4";
|
|
}
|
|
}
|
|
|
|
extern "C"
|
|
unsigned
|
|
Get_Default_Address_Space (const DataLayout &DL)
|
|
{
|
|
return DL.getDefaultGlobalsAddressSpace();
|
|
}
|
|
|
|
extern "C"
|
|
void
|
|
Set_Absolute_Address (LLVMContext &Ctx, Value *V, Value *Addr)
|
|
{
|
|
cast<GlobalObject>(V)->setMetadata(
|
|
LLVMContext::MD_absolute_symbol,
|
|
MDNode::get(Ctx, {ValueAsMetadata::get(Addr)}));
|
|
}
|
|
|
|
extern "C"
|
|
bool
|
|
Need_Enable_Execute_Stack (const char *Target)
|
|
{
|
|
// Decide whether we need to call __enable_execute_stack in order to make the
|
|
// stack executable. The GNU linker does this automatically in ELF binaries,
|
|
// but lld doesn't, and on Windows the helper function is also required.
|
|
|
|
Triple TargetTriple(Target);
|
|
return TargetTriple.isOSWindows() || TargetTriple.isOSLinux();
|
|
}
|
|
|
|
extern "C"
|
|
void
|
|
Print_Targets (void)
|
|
{
|
|
TargetRegistry::printRegisteredTargetsForVersion(outs());
|
|
}
|
|
|
|
extern "C"
|
|
void
|
|
Enable_Init_Array (TargetMachine *TM)
|
|
{
|
|
TM->Options.UseInitArray = 1;
|
|
}
|
|
|
|
extern "C"
|
|
void
|
|
Create_And_Insert_Label (LLVMDIBuilderRef Builder, LLVMMetadataRef Scope,
|
|
const char *Name, LLVMMetadataRef File,
|
|
unsigned LineNo, unsigned ColmunNo, LLVMMetadataRef DebugLoc,
|
|
LLVMBasicBlockRef Block)
|
|
{
|
|
#if LLVM_VERSION_MAJOR < 21
|
|
auto *L = unwrap(Builder)->createLabel(unwrap<DIScope>(Scope),
|
|
StringRef(Name, strlen(Name)),
|
|
unwrap<DIFile>(File), LineNo, false);
|
|
#else
|
|
auto *L = unwrap(Builder)->createLabel(
|
|
unwrap<DIScope>(Scope), StringRef(Name, strlen(Name)),
|
|
unwrap<DIFile>(File), LineNo, ColmunNo, false, std::nullopt, false);
|
|
#endif
|
|
unwrap(Builder)->insertLabel(L, unwrap<DILocation>(DebugLoc),
|
|
unwrap(Block));
|
|
}
|
|
|
|
extern "C"
|
|
MDNode *
|
|
Create_Subrange_Type (LLVMDIBuilderRef Builder, LLVMMetadataRef Scope,
|
|
const char *Name, LLVMMetadataRef File, unsigned LineNumber,
|
|
uint64_t SizeInBits, uint32_t AlignInBits,
|
|
LLVMDIFlags Flags, LLVMBool IsUnsigned,
|
|
LLVMMetadataRef BaseType, LLVMMetadataRef LowerBound,
|
|
LLVMMetadataRef UpperBound, LLVMMetadataRef Stride,
|
|
LLVMMetadataRef Bias)
|
|
{
|
|
DINode::DIFlags DIF = static_cast<DINode::DIFlags>(Flags);
|
|
#ifdef GNAT_LLVM_HAVE_SUBRANGE_TYPE
|
|
DIScope *DS = Scope ? unwrap<DIScope>(Scope) : nullptr;
|
|
DIFile *DF = File ? unwrap<DIFile>(File) : nullptr;
|
|
DIType *Ty = BaseType ? unwrap<DIType>(BaseType) : nullptr;
|
|
return unwrap(Builder)->createSubrangeType(
|
|
StringRef(Name, strlen(Name)), DF, LineNumber,
|
|
DS, SizeInBits, AlignInBits, DIF, Ty,
|
|
unwrap(LowerBound), unwrap(UpperBound), unwrap(Stride), unwrap(Bias));
|
|
#else
|
|
return unwrap(Builder)->createBasicType(StringRef(Name, strlen(Name)), SizeInBits,
|
|
IsUnsigned
|
|
? llvm::dwarf::DW_ATE_unsigned
|
|
: llvm::dwarf::DW_ATE_signed,
|
|
DIF);
|
|
#endif // GNAT_LLVM_HAVE_SUBRANGE_TYPE
|
|
}
|
|
|
|
extern "C"
|
|
MDNode *
|
|
Create_Array_Type_With_Name (LLVMDIBuilderRef Builder, LLVMMetadataRef Scope,
|
|
const char *Name, LLVMMetadataRef File,
|
|
unsigned LineNo, uint64_t Size,
|
|
uint32_t AlignInBits, LLVMMetadataRef Ty,
|
|
LLVMMetadataRef BitStride,
|
|
LLVMMetadataRef *Subscripts,
|
|
unsigned NumSubscripts)
|
|
{
|
|
auto Subs = unwrap(Builder)->getOrCreateArray({unwrap(Subscripts),
|
|
NumSubscripts});
|
|
#ifdef GNAT_LLVM_HAVE_ARRAY_NAME
|
|
DIScope *DS = Scope ? unwrap<DIScope>(Scope) : nullptr;
|
|
DIFile *DF = File ? unwrap<DIFile>(File) : nullptr;
|
|
return unwrap(Builder)->createArrayType(
|
|
DS, StringRef(Name, strlen(Name)), DF,
|
|
LineNo, Size, AlignInBits, unwrap<DIType>(Ty), Subs,
|
|
nullptr, nullptr, nullptr, nullptr, unwrap(BitStride));
|
|
#else
|
|
return unwrap(Builder)->createArrayType(Size, AlignInBits,
|
|
unwrap<DIType>(Ty), Subs);
|
|
#endif // GNAT_LLVM_HAVE_ARRAY_NAME
|
|
}
|
|
|
|
extern "C"
|
|
Metadata *
|
|
Constant_As_Metadata (LLVMContext *Context, MDBuilder *MDHelper,
|
|
unsigned NumWords, const uint64_t Words[])
|
|
{
|
|
auto Result = APInt (NumWords * 64, {Words, NumWords});
|
|
return MDHelper->createConstant (ConstantInt::get (*Context, Result));
|
|
}
|
|
|
|
extern "C"
|
|
MDNode *
|
|
Create_Binary_Fixed_Point_Type (LLVMDIBuilderRef Builder, const char *Name,
|
|
uint64_t Size, uint32_t AlignInBits,
|
|
bool IsUnsigned, int Factor)
|
|
{
|
|
#ifdef GNAT_LLVM_HAVE_FIXED_POINT
|
|
return unwrap(Builder)->createBinaryFixedPointType(
|
|
Name, Size, AlignInBits,
|
|
IsUnsigned ? dwarf::DW_ATE_unsigned_fixed : dwarf::DW_ATE_signed_fixed,
|
|
DINode::FlagZero, Factor);
|
|
#else
|
|
return unwrap(Builder)->createBasicType(Name, Size,
|
|
IsUnsigned ?
|
|
dwarf::DW_ATE_unsigned :
|
|
dwarf::DW_ATE_signed,
|
|
DINode::FlagZero);
|
|
#endif // GNAT_LLVM_HAVE_FIXED_POINT
|
|
}
|
|
|
|
extern "C"
|
|
MDNode *
|
|
Create_Decimal_Fixed_Point_Type (LLVMDIBuilderRef Builder, const char *Name,
|
|
uint64_t Size, uint32_t AlignInBits,
|
|
bool IsUnsigned, int Factor)
|
|
{
|
|
#ifdef GNAT_LLVM_HAVE_FIXED_POINT
|
|
return unwrap(Builder)->createDecimalFixedPointType(
|
|
Name, Size, AlignInBits,
|
|
IsUnsigned ? dwarf::DW_ATE_unsigned_fixed : dwarf::DW_ATE_signed_fixed,
|
|
DINode::FlagZero, Factor);
|
|
#else
|
|
return unwrap(Builder)->createBasicType(Name, Size,
|
|
IsUnsigned ?
|
|
dwarf::DW_ATE_unsigned :
|
|
dwarf::DW_ATE_signed,
|
|
DINode::FlagZero);
|
|
#endif // GNAT_LLVM_HAVE_FIXED_POINT
|
|
}
|
|
|
|
extern "C"
|
|
MDNode *
|
|
Create_Rational_Fixed_Point_Type (LLVMDIBuilderRef Builder, const char *Name,
|
|
uint64_t Size, uint32_t AlignInBits,
|
|
bool IsUnsigned, Metadata *Num,
|
|
Metadata *Denom)
|
|
{
|
|
#ifdef GNAT_LLVM_HAVE_FIXED_POINT
|
|
Constant *Num_C = dyn_cast<ConstantAsMetadata>(Num)->getValue();
|
|
ConstantInt *Num_Int = dyn_cast<ConstantInt>(Num_C);
|
|
|
|
Constant *Denom_C = dyn_cast<ConstantAsMetadata>(Denom)->getValue();
|
|
ConstantInt *Denom_Int = dyn_cast<ConstantInt>(Denom_C);
|
|
|
|
return unwrap(Builder)->createRationalFixedPointType(
|
|
Name, Size, AlignInBits,
|
|
IsUnsigned ? dwarf::DW_ATE_unsigned_fixed : dwarf::DW_ATE_signed_fixed,
|
|
DINode::FlagZero, Num_Int->getValue(), Denom_Int->getValue());
|
|
#else
|
|
return unwrap(Builder)->createBasicType(Name, Size,
|
|
IsUnsigned ?
|
|
dwarf::DW_ATE_unsigned :
|
|
dwarf::DW_ATE_signed,
|
|
DINode::FlagZero);
|
|
#endif // GNAT_LLVM_HAVE_FIXED_POINT
|
|
}
|
|
|
|
extern "C"
|
|
void
|
|
Add_Instruction_Combining_Pass(legacy::PassManager *PM) {
|
|
PM->add(createInstructionCombiningPass());
|
|
}
|
|
|
|
extern "C"
|
|
void
|
|
Create_Import_Declarations (LLVMDIBuilderRef Builder, const char *Name,
|
|
LLVMMetadataRef Comp_Unit, LLVMMetadataRef File,
|
|
unsigned LineNo)
|
|
{
|
|
DIScope *Scope = unwrap<DIScope>(Comp_Unit);
|
|
|
|
DIScope *Outer = Scope;
|
|
DIModule *Module;
|
|
StringRef NameRef (Name);
|
|
SmallVector<StringRef, 8> NameSplit;
|
|
NameRef.split(NameSplit, "__");
|
|
for (StringRef ModName : NameSplit) {
|
|
Module = unwrap(Builder)->createModule(Outer, ModName, {}, {});
|
|
Outer = Module;
|
|
}
|
|
|
|
unwrap(Builder)->createImportedModule(Scope, Module, unwrap<DIFile>(File),
|
|
LineNo);
|
|
}
|
|
|
|
extern "C"
|
|
bool
|
|
Types_Can_Have_Function_Scope ()
|
|
{
|
|
#ifdef GNAT_LLVM_HAVE_TYPE_FN_SCOPE
|
|
return true;
|
|
#else
|
|
return false;
|
|
#endif
|
|
}
|
|
|
|
extern "C"
|
|
bool
|
|
Types_Can_Have_Dynamic_Offsets ()
|
|
{
|
|
#ifdef GNAT_LLVM_HAVE_DYNAMIC_OFFSETS
|
|
return true;
|
|
#else
|
|
return false;
|
|
#endif
|
|
}
|
|
|
|
extern "C"
|
|
bool
|
|
Types_Can_Have_Multiple_Variant_Members ()
|
|
{
|
|
#ifdef GNAT_LLVM_HAVE_MULTI_MEMBER_VARIANT
|
|
return true;
|
|
#else
|
|
return false;
|
|
#endif
|
|
}
|
|
|
|
extern "C"
|
|
bool
|
|
DI_Expression_Extensions ()
|
|
{
|
|
#ifdef GNAT_LLVM_HAVE_DW_EXPRESSION_EXTENSIONS
|
|
return true;
|
|
#else
|
|
return false;
|
|
#endif
|
|
}
|
|
|
|
extern "C"
|
|
bool
|
|
DI_Subrange_Allows_Member ()
|
|
{
|
|
#ifdef GNAT_LLVM_HAVE_SUBRANGE_TYPE_EXTENSION
|
|
return true;
|
|
#else
|
|
return false;
|
|
#endif
|
|
}
|
|
|
|
extern "C"
|
|
LLVMMetadataRef Create_Global_Variable_Declaration(
|
|
LLVMDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name,
|
|
const char *Linkage, LLVMMetadataRef File,
|
|
unsigned LineNo, LLVMMetadataRef Ty, LLVMBool LocalToUnit,
|
|
LLVMMetadataRef Expr, LLVMMetadataRef Decl, uint32_t AlignInBits) {
|
|
DIScope *DS = Scope ? unwrap<DIScope>(Scope) : nullptr;
|
|
DIFile *DF = File ? unwrap<DIFile>(File) : nullptr;
|
|
MDNode *MD = Decl ? unwrap<MDNode>(Decl) : nullptr;
|
|
|
|
return wrap(unwrap(Builder)->createGlobalVariableExpression(
|
|
DS, {Name, strlen(Name)}, {Linkage, strlen(Linkage)},
|
|
DF, LineNo, unwrap<DIType>(Ty), LocalToUnit,
|
|
false, unwrap<DIExpression>(Expr), MD,
|
|
nullptr, AlignInBits));
|
|
}
|
|
|
|
extern "C"
|
|
LLVMMetadataRef Replace_Composite_Elements(
|
|
LLVMDIBuilderRef Builder, LLVMMetadataRef Composite,
|
|
LLVMMetadataRef *Elements, unsigned NumElements) {
|
|
auto Elems = unwrap(Builder)->getOrCreateArray({unwrap(Elements), NumElements});
|
|
DICompositeType *T = unwrap<DICompositeType>(Composite);
|
|
unwrap(Builder)->replaceArrays(T, Elems);
|
|
// T might have been modified by replaceArrays.
|
|
return wrap(T);
|
|
}
|
|
|
|
extern "C"
|
|
LLVMMetadataRef Create_Variant_Part(
|
|
LLVMDIBuilderRef Builder, LLVMMetadataRef Discriminator,
|
|
LLVMMetadataRef *Elements, unsigned NumElements) {
|
|
DIDerivedType *Disc = Discriminator ? unwrap<DIDerivedType>(Discriminator) : nullptr;
|
|
auto Elems = unwrap(Builder)->getOrCreateArray({unwrap(Elements), NumElements});
|
|
|
|
return wrap(unwrap(Builder)->createVariantPart(
|
|
nullptr, {}, nullptr, 0, 0, 0, DINode::FlagZero,
|
|
Disc, Elems));
|
|
}
|
|
|
|
extern "C"
|
|
LLVMMetadataRef Create_Variant_Member(
|
|
LLVMContext *Context, LLVMDIBuilderRef Builder,
|
|
LLVMMetadataRef *Elements, unsigned NumElements,
|
|
uint64_t *Discriminants, unsigned NumDiscriminants) {
|
|
#ifdef GNAT_LLVM_HAVE_MULTI_MEMBER_VARIANT
|
|
auto Elems = unwrap(Builder)->getOrCreateArray({unwrap(Elements), NumElements});
|
|
Constant *D = nullptr;
|
|
// Note that this small optimization is actually required: when
|
|
// adding support for discriminant lists to LLVM, I did not realize
|
|
// that ConstantDataArray::get will return a ConstantAggregateZero
|
|
// when possible; and so the DWARF generation code does not handle
|
|
// this case. If a variant uses "when 0", this will result in a
|
|
// discriminant array of {0, 0}, which would then be ignored by the
|
|
// DWARF writer. This optimization works around this oddity to
|
|
// provide correct DWARF output.
|
|
if (NumDiscriminants == 2 && Discriminants[0] == Discriminants[1]) {
|
|
D = ConstantInt::get (Type::getInt64Ty (*Context), Discriminants[0]);
|
|
} else if (NumDiscriminants > 0) {
|
|
ArrayRef<uint64_t> Vals(Discriminants, NumDiscriminants);
|
|
D = ConstantDataArray::get(*Context, Vals);
|
|
}
|
|
return wrap(unwrap(Builder)->createVariantMemberType(nullptr, Elems, D, nullptr));
|
|
#else
|
|
// This should never be called in this situation.
|
|
assert(0);
|
|
#endif
|
|
}
|
|
|
|
extern "C"
|
|
LLVMMetadataRef Create_Pointer_Type(LLVMDIBuilderRef Builder,
|
|
LLVMMetadataRef Pointee,
|
|
uint64_t SizeInBits,
|
|
uint32_t AlignInBits) {
|
|
return wrap(unwrap(Builder)->createPointerType(
|
|
unwrap<DIType>(Pointee), SizeInBits, AlignInBits));
|
|
}
|
|
|
|
extern "C"
|
|
LLVMMetadataRef Create_Member(
|
|
LLVMDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name,
|
|
LLVMMetadataRef File, unsigned LineNo,
|
|
LLVMMetadataRef SizeInBits, LLVMMetadataRef OffsetInBits,
|
|
LLVMMetadataRef Ty, LLVMDIFlags Flags, LLVMBool IsBitField) {
|
|
#ifdef GNAT_LLVM_HAVE_DYNAMIC_OFFSETS
|
|
DINode::DIFlags DIF = static_cast<DINode::DIFlags>(Flags);
|
|
DIScope *DS = Scope ? unwrap<DIScope>(Scope) : nullptr;
|
|
DIFile *DF = File ? unwrap<DIFile>(File) : nullptr;
|
|
Metadata *SB = SizeInBits ? unwrap(SizeInBits) : nullptr;
|
|
Metadata *OB = OffsetInBits ? unwrap(OffsetInBits) : nullptr;
|
|
DIDerivedType *Result;
|
|
if (IsBitField) {
|
|
Result = unwrap(Builder)->createBitFieldMemberType(DS, Name, DF, LineNo,
|
|
SB, OB, 0, DIF,
|
|
unwrap<DIType>(Ty));
|
|
} else {
|
|
Result = unwrap(Builder)->createMemberType(DS, Name, DF, LineNo,
|
|
SB, 0, OB, DIF,
|
|
unwrap<DIType>(Ty));
|
|
}
|
|
return wrap(Result);
|
|
#else
|
|
// This should never be called in this situation.
|
|
assert(0);
|
|
#endif
|
|
}
|
|
|
|
extern "C"
|
|
LLVMMetadataRef Create_Struct_Type_Non_Constant_Size(
|
|
LLVMDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name,
|
|
LLVMMetadataRef File, unsigned LineNo,
|
|
LLVMMetadataRef SizeInBits, uint32_t AlignInBits,
|
|
LLVMDIFlags Flags, LLVMMetadataRef DerivedFrom,
|
|
LLVMMetadataRef *Elements, unsigned NumElements,
|
|
unsigned RunTimeLang, LLVMMetadataRef VTableHolder,
|
|
const char *UniqueId) {
|
|
#ifdef GNAT_LLVM_HAVE_DYNAMIC_OFFSETS
|
|
DINode::DIFlags DIF = static_cast<DINode::DIFlags>(Flags);
|
|
DIScope *DS = Scope ? unwrap<DIScope>(Scope) : nullptr;
|
|
DIFile *DF = File ? unwrap<DIFile>(File) : nullptr;
|
|
Metadata *SB = SizeInBits ? unwrap(SizeInBits) : nullptr;
|
|
DIType *DerF = DerivedFrom ? unwrap<DIType>(DerivedFrom) : nullptr;
|
|
DIType *VTH = VTableHolder ? unwrap<DIType>(VTableHolder) : nullptr;
|
|
StringRef NameRef(Name);
|
|
StringRef UniqueRef(UniqueId);
|
|
auto Elems = unwrap(Builder)->getOrCreateArray({unwrap(Elements), NumElements});
|
|
DICompositeType *Result
|
|
= unwrap(Builder)->createStructType(DS, NameRef, DF, LineNo, SB,
|
|
AlignInBits, DIF, DerF, Elems,
|
|
RunTimeLang, VTH, UniqueRef);
|
|
return wrap(Result);
|
|
#else
|
|
// This should never be called in this situation.
|
|
assert(0);
|
|
#endif
|
|
}
|