ldc/ldc-1.23.0-llvm-11.patch

6729 lines
257 KiB
Diff

From 69269f3bd968dbb90de52b245827bd61b4f6afe0 Mon Sep 17 00:00:00 2001
From: Martin Kinkelin <noone@nowhere.com>
Date: Sun, 23 Aug 2020 17:25:10 +0200
Subject: [PATCH 01/16] Refactor IRScope handling
Replace the stack of IRScopes, each with its own IRBuilder, by directly
tampering with the state of a single IRBuilder.
This seems like the most feasible way to account for a breaking change
in LLVM 11, disallowing IRBuilder from being copied.
---
gen/aa.cpp | 4 +-
gen/arrays.cpp | 14 +++---
gen/asmstmt.cpp | 4 +-
gen/classes.cpp | 4 +-
gen/funcgenstate.cpp | 2 +-
gen/functions.cpp | 25 +++++-----
gen/irstate.cpp | 69 ++++++++++++++++++---------
gen/irstate.h | 37 +++++++++++----
gen/statements.cpp | 100 ++++++++++++++++++++--------------------
gen/toir.cpp | 34 +++++++-------
gen/trycatchfinally.cpp | 32 ++++++-------
ir/irclass.cpp | 8 ++--
12 files changed, 186 insertions(+), 147 deletions(-)
diff --git a/gen/aa.cpp b/gen/aa.cpp
index 64766066..5344dc33 100644
--- a/gen/aa.cpp
+++ b/gen/aa.cpp
@@ -91,12 +91,12 @@ DLValue *DtoAAIndex(Loc &loc, Type *type, DValue *aa, DValue *key,
// set up failbb to call the array bounds error runtime function
- gIR->scope() = IRScope(failbb);
+ gIR->ir->SetInsertPoint(failbb);
DtoBoundsCheckFailCall(gIR, loc);
// if ok, proceed in okbb
- gIR->scope() = IRScope(okbb);
+ gIR->ir->SetInsertPoint(okbb);
}
return new DLValue(type, ret);
}
diff --git a/gen/arrays.cpp b/gen/arrays.cpp
index b9d22f01..0d867b07 100644
--- a/gen/arrays.cpp
+++ b/gen/arrays.cpp
@@ -144,7 +144,7 @@ static void DtoArrayInit(Loc &loc, LLValue *ptr, LLValue *length,
llvm::BranchInst::Create(condbb, gIR->scopebb());
// replace current scope
- gIR->scope() = IRScope(condbb);
+ gIR->ir->SetInsertPoint(condbb);
// create the condition
LLValue *cond_val =
@@ -155,7 +155,7 @@ static void DtoArrayInit(Loc &loc, LLValue *ptr, LLValue *length,
llvm::BranchInst::Create(bodybb, endbb, cond_val, gIR->scopebb());
// rewrite scope
- gIR->scope() = IRScope(bodybb);
+ gIR->ir->SetInsertPoint(bodybb);
LLValue *itr_val = DtoLoad(itr);
// assign array element value
@@ -171,7 +171,7 @@ static void DtoArrayInit(Loc &loc, LLValue *ptr, LLValue *length,
llvm::BranchInst::Create(condbb, gIR->scopebb());
// rewrite the scope
- gIR->scope() = IRScope(endbb);
+ gIR->ir->SetInsertPoint(endbb);
}
////////////////////////////////////////////////////////////////////////////////
@@ -1118,12 +1118,12 @@ LLValue *DtoArrayEqCmp_memcmp(Loc &loc, DValue *l, DValue *r, IRState &irs) {
// Note: no extra null checks are needed before passing the pointers to memcmp.
// The array comparison is UB for non-zero length, and memcmp will correctly
// return 0 (equality) when the length is zero.
- irs.scope() = IRScope(memcmpBB);
+ irs.ir->SetInsertPoint(memcmpBB);
auto memcmpAnswer = callMemcmp(loc, irs, l_ptr, r_ptr, l_length);
irs.ir->CreateBr(memcmpEndBB);
// Merge the result of length check and memcmp call into a phi node.
- irs.scope() = IRScope(memcmpEndBB);
+ irs.ir->SetInsertPoint(memcmpEndBB);
llvm::PHINode *phi =
irs.ir->CreatePHI(LLType::getInt32Ty(gIR->context()), 2, "cmp_result");
phi->addIncoming(DtoConstInt(1), incomingBB);
@@ -1348,11 +1348,11 @@ void DtoIndexBoundsCheck(Loc &loc, DValue *arr, DValue *index) {
gIR->ir->CreateCondBr(cond, okbb, failbb);
// set up failbb to call the array bounds error runtime function
- gIR->scope() = IRScope(failbb);
+ gIR->ir->SetInsertPoint(failbb);
DtoBoundsCheckFailCall(gIR, loc);
// if ok, proceed in okbb
- gIR->scope() = IRScope(okbb);
+ gIR->ir->SetInsertPoint(okbb);
}
void DtoBoundsCheckFailCall(IRState *irs, Loc &loc) {
diff --git a/gen/asmstmt.cpp b/gen/asmstmt.cpp
index be2f090b..d4c76b87 100644
--- a/gen/asmstmt.cpp
+++ b/gen/asmstmt.cpp
@@ -752,11 +752,11 @@ void CompoundAsmStatement_toIR(CompoundAsmStatement *stmt, IRState *p) {
pair.second),
casebb);
- p->scope() = IRScope(casebb);
+ p->ir->SetInsertPoint(casebb);
DtoGoto(stmt->loc, pair.first);
}
- p->scope() = IRScope(bb);
+ p->ir->SetInsertPoint(bb);
}
}
diff --git a/gen/classes.cpp b/gen/classes.cpp
index 037ef923..0777ce02 100644
--- a/gen/classes.cpp
+++ b/gen/classes.cpp
@@ -221,11 +221,11 @@ void DtoFinalizeScopeClass(Loc &loc, LLValue *inst, bool hasDtor) {
getNullValue(monitor->getType()), ".hasMonitor");
llvm::BranchInst::Create(ifbb, endbb, hasMonitor, gIR->scopebb());
- gIR->scope() = IRScope(ifbb);
+ gIR->ir->SetInsertPoint(ifbb);
DtoFinalizeClass(loc, inst);
gIR->ir->CreateBr(endbb);
- gIR->scope() = IRScope(endbb);
+ gIR->ir->SetInsertPoint(endbb);
}
////////////////////////////////////////////////////////////////////////////////
diff --git a/gen/funcgenstate.cpp b/gen/funcgenstate.cpp
index ca61adb7..e2c16958 100644
--- a/gen/funcgenstate.cpp
+++ b/gen/funcgenstate.cpp
@@ -140,6 +140,6 @@ llvm::CallSite FuncGenState::callOrInvoke(llvm::Value *callee,
invoke->setAttributes(calleeFn->getAttributes());
}
- irs.scope() = IRScope(postinvoke);
+ irs.ir->SetInsertPoint(postinvoke);
return invoke;
}
diff --git a/gen/functions.cpp b/gen/functions.cpp
index c8c0ec3d..554102ca 100644
--- a/gen/functions.cpp
+++ b/gen/functions.cpp
@@ -883,12 +883,12 @@ void emitDMDStyleFunctionTrace(IRState &irs, FuncDeclaration *fd,
// Push cleanup block that calls _c_trace_epi at function exit.
{
auto traceEpilogBB = irs.insertBB("trace_epi");
- auto saveScope = irs.scope();
- irs.scope() = IRScope(traceEpilogBB);
+ const auto savedInsertPoint = irs.getInsertPoint();
+ irs.ir->SetInsertPoint(traceEpilogBB);
irs.ir->CreateCall(
getRuntimeFunction(fd->endloc, irs.module, "_c_trace_epi"));
funcGen.scopes.pushCleanup(traceEpilogBB, irs.scopebb());
- irs.scope() = saveScope;
+ irs.setInsertPoint(savedInsertPoint);
}
}
@@ -1165,13 +1165,10 @@ void DtoDefineFunction(FuncDeclaration *fd, bool linkageAvailableExternally) {
llvm::BasicBlock *beginbb =
llvm::BasicBlock::Create(gIR->context(), "", func);
- gIR->scopes.push_back(IRScope(beginbb));
- SCOPE_EXIT {
- gIR->scopes.pop_back();
- };
-
- // Set the FastMath options for this function scope.
- gIR->scopes.back().builder.setFastMathFlags(irFunc->FMF);
+ // set up the IRBuilder scope for the function
+ FunctionIRBuilderScope irBuilderScope(*gIR);
+ gIR->setInsertPoint(beginbb);
+ gIR->ir->setFastMathFlags(irFunc->FMF);
// @naked: emit body and return, no prologue/epilogue
if (func->hasFnAttribute(llvm::Attribute::Naked)) {
@@ -1277,11 +1274,11 @@ void DtoDefineFunction(FuncDeclaration *fd, bool linkageAvailableExternally) {
{
auto *vaendBB =
llvm::BasicBlock::Create(gIR->context(), "vaend", gIR->topfunc());
- IRScope saveScope = gIR->scope();
- gIR->scope() = IRScope(vaendBB);
+ const auto savedInsertPoint = gIR->getInsertPoint();
+ gIR->ir->SetInsertPoint(vaendBB);
gIR->ir->CreateCall(GET_INTRINSIC_DECL(vaend), llAp);
funcGen.scopes.pushCleanup(vaendBB, gIR->scopebb());
- gIR->scope() = saveScope;
+ gIR->setInsertPoint(savedInsertPoint);
}
}
@@ -1297,7 +1294,7 @@ void DtoDefineFunction(FuncDeclaration *fd, bool linkageAvailableExternally) {
if (!funcGen.retBlock)
funcGen.retBlock = gIR->insertBB("return");
funcGen.scopes.runCleanups(0, funcGen.retBlock);
- gIR->scope() = IRScope(funcGen.retBlock);
+ gIR->ir->SetInsertPoint(funcGen.retBlock);
}
funcGen.scopes.popCleanups(0);
}
diff --git a/gen/irstate.cpp b/gen/irstate.cpp
index f5e3c299..0ac6ddc3 100644
--- a/gen/irstate.cpp
+++ b/gen/irstate.cpp
@@ -26,20 +26,9 @@ llvm::TargetMachine *gTargetMachine = nullptr;
const llvm::DataLayout *gDataLayout = nullptr;
TargetABI *gABI = nullptr;
-////////////////////////////////////////////////////////////////////////////////
-IRScope::IRScope() : builder(gIR->context()) { begin = nullptr; }
-
-IRScope::IRScope(llvm::BasicBlock *b) : begin(b), builder(b) {}
-
-IRScope &IRScope::operator=(const IRScope &rhs) {
- begin = rhs.begin;
- builder.SetInsertPoint(begin);
- return *this;
-}
-
////////////////////////////////////////////////////////////////////////////////
IRState::IRState(const char *name, llvm::LLVMContext &context)
- : module(name, context), objc(module), DBuilder(this) {
+ : builder(context), module(name, context), objc(module), DBuilder(this) {
ir.state = this;
mem.addRange(&inlineAsmLocs, sizeof(inlineAsmLocs));
}
@@ -57,20 +46,41 @@ llvm::Function *IRState::topfunc() { return func()->getLLVMFunc(); }
llvm::Instruction *IRState::topallocapoint() { return funcGen().allocapoint; }
-IRScope &IRState::scope() {
- assert(!scopes.empty());
- return scopes.back();
+InsertionPoint IRState::getInsertPoint() {
+ auto bb = builder.GetInsertBlock();
+ if (!bb)
+ return {nullptr, llvm::None};
+
+ llvm::Optional<llvm::BasicBlock::iterator> point = builder.GetInsertPoint();
+ if (point == bb->end())
+ point = llvm::None;
+
+ return {bb, point};
+}
+
+void IRState::setInsertPoint(llvm::BasicBlock *insertAtEnd) {
+ builder.SetInsertPoint(insertAtEnd);
+}
+
+void IRState::setInsertPoint(InsertionPoint point) {
+ if (!point.bb) {
+ builder.ClearInsertionPoint();
+ } else if (!point.point.hasValue()) {
+ builder.SetInsertPoint(point.bb);
+ } else {
+ builder.SetInsertPoint(point.bb, point.point.getValue());
+ }
}
llvm::BasicBlock *IRState::scopebb() {
- IRScope &s = scope();
- assert(s.begin);
- return s.begin;
+ auto bb = ir->GetInsertBlock();
+ assert(bb);
+ return bb;
}
bool IRState::scopereturned() {
- // return scope().returned;
- return !scopebb()->empty() && scopebb()->back().isTerminator();
+ auto bb = scopebb();
+ return !bb->empty() && bb->back().isTerminator();
}
llvm::BasicBlock *IRState::insertBBBefore(llvm::BasicBlock *successor,
@@ -283,8 +293,25 @@ const Loc &IRState::getInlineAsmSrcLoc(unsigned srcLocCookie) const {
////////////////////////////////////////////////////////////////////////////////
+FunctionIRBuilderScope::FunctionIRBuilderScope(IRState &state)
+ : state(state), previousInsertionPoint(state.getInsertPoint()),
+ previousFMF(state.builder.getFastMathFlags()),
+ previousDebugLoc(state.builder.getCurrentDebugLocation()) {
+ state.builder.ClearInsertionPoint();
+ state.builder.clearFastMathFlags();
+ state.builder.SetCurrentDebugLocation({});
+}
+
+FunctionIRBuilderScope::~FunctionIRBuilderScope() {
+ state.setInsertPoint(previousInsertionPoint);
+ state.builder.setFastMathFlags(previousFMF);
+ state.builder.SetCurrentDebugLocation(previousDebugLoc);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
IRBuilder<> *IRBuilderHelper::operator->() {
- IRBuilder<> &b = state->scope().builder;
+ IRBuilder<> &b = state->builder;
assert(b.GetInsertBlock() != NULL);
return &b;
}
diff --git a/gen/irstate.h b/gen/irstate.h
index a47c276c..340bfb57 100644
--- a/gen/irstate.h
+++ b/gen/irstate.h
@@ -59,16 +59,28 @@ class StructLiteralExp;
struct IrFunction;
struct IrModule;
-// represents a scope
-struct IRScope {
- llvm::BasicBlock *begin;
- IRBuilder<> builder;
+// insertion point for IRBuilder
+struct InsertionPoint {
+ llvm::BasicBlock *bb; // can be null
+ llvm::Optional<llvm::BasicBlock::iterator> point; // bb end if not set
+
+ InsertionPoint(llvm::BasicBlock *bb,
+ llvm::Optional<llvm::BasicBlock::iterator> point)
+ : bb(bb), point(std::move(point)) {}
+};
- IRScope();
- IRScope(const IRScope &) = default;
- explicit IRScope(llvm::BasicBlock *b);
+// Resets the IRBuilder for a new function and restores its previous state on
+// destruction.
+struct FunctionIRBuilderScope {
+private:
+ IRState &state;
+ InsertionPoint previousInsertionPoint;
+ llvm::FastMathFlags previousFMF;
+ llvm::DebugLoc previousDebugLoc;
- IRScope &operator=(const IRScope &rhs);
+public:
+ FunctionIRBuilderScope(IRState &state);
+ ~FunctionIRBuilderScope();
};
struct IRBuilderHelper {
@@ -111,6 +123,10 @@ struct IRAsmBlock {
// represents the LLVM module (object file)
struct IRState {
private:
+ IRBuilder<> builder;
+ friend struct FunctionIRBuilderScope;
+ friend struct IRBuilderHelper;
+
std::vector<std::pair<llvm::GlobalVariable *, llvm::Constant *>>
globalsToReplace;
Array<Loc> inlineAsmLocs; // tracked by GC
@@ -155,8 +171,9 @@ public:
llvm::Instruction *topallocapoint();
// basic block scopes
- std::vector<IRScope> scopes;
- IRScope &scope();
+ InsertionPoint getInsertPoint();
+ void setInsertPoint(llvm::BasicBlock *insertAtEnd);
+ void setInsertPoint(InsertionPoint point);
llvm::BasicBlock *scopebb();
bool scopereturned();
diff --git a/gen/statements.cpp b/gen/statements.cpp
index f7e4bbce..34266b4c 100644
--- a/gen/statements.cpp
+++ b/gen/statements.cpp
@@ -276,7 +276,7 @@ public:
// Pop the cleanups pushed during evaluation of the return expression.
funcGen.scopes.popCleanups(cleanupScopeBeforeExpression);
- irs->scope() = IRScope(funcGen.retBlock);
+ irs->ir->SetInsertPoint(funcGen.retBlock);
}
// If we need to emit the actual return instruction, do so.
@@ -299,7 +299,7 @@ public:
// Finally, create a new predecessor-less dummy bb as the current IRScope
// to make sure we do not emit any extra instructions after the terminating
// instruction (ret or branch to return bb), which would be illegal IR.
- irs->scope() = IRScope(irs->insertBB("dummy.afterreturn"));
+ irs->ir->SetInsertPoint(irs->insertBB("dummy.afterreturn"));
}
//////////////////////////////////////////////////////////////////////////
@@ -426,7 +426,7 @@ public:
PGO.addBranchWeights(brinstr, brweights);
// replace current scope
- irs->scope() = IRScope(ifbb);
+ irs->ir->SetInsertPoint(ifbb);
// do scoped statements
@@ -441,7 +441,7 @@ public:
}
if (stmt->elsebody) {
- irs->scope() = IRScope(elsebb);
+ irs->ir->SetInsertPoint(elsebb);
irs->DBuilder.EmitBlockStart(stmt->elsebody->loc);
stmt->elsebody->accept(this);
if (!irs->scopereturned()) {
@@ -454,7 +454,7 @@ public:
irs->DBuilder.EmitBlockEnd();
// rewrite the scope
- irs->scope() = IRScope(endbb);
+ irs->ir->SetInsertPoint(endbb);
}
//////////////////////////////////////////////////////////////////////////
@@ -495,7 +495,7 @@ public:
irs->ir->CreateBr(whilebb);
// replace current scope
- irs->scope() = IRScope(whilebb);
+ irs->ir->SetInsertPoint(whilebb);
// create the condition
emitCoverageLinecountInc(stmt->condition->loc);
@@ -514,7 +514,7 @@ public:
}
// rewrite scope
- irs->scope() = IRScope(whilebodybb);
+ irs->ir->SetInsertPoint(whilebodybb);
// while body code
irs->funcGen().jumpTargets.pushLoopTarget(stmt, whilebb, endbb);
@@ -530,7 +530,7 @@ public:
}
// rewrite the scope
- irs->scope() = IRScope(endbb);
+ irs->ir->SetInsertPoint(endbb);
// end the dwarf lexical block
irs->DBuilder.EmitBlockEnd();
@@ -558,7 +558,7 @@ public:
llvm::BranchInst::Create(dowhilebb, irs->scopebb());
// replace current scope
- irs->scope() = IRScope(dowhilebb);
+ irs->ir->SetInsertPoint(dowhilebb);
// do-while body code
irs->funcGen().jumpTargets.pushLoopTarget(stmt, condbb, endbb);
@@ -570,7 +570,7 @@ public:
// branch to condition block
llvm::BranchInst::Create(condbb, irs->scopebb());
- irs->scope() = IRScope(condbb);
+ irs->ir->SetInsertPoint(condbb);
// create the condition
emitCoverageLinecountInc(stmt->condition->loc);
@@ -592,7 +592,7 @@ public:
}
// rewrite the scope
- irs->scope() = IRScope(endbb);
+ irs->ir->SetInsertPoint(endbb);
// end the dwarf lexical block
irs->DBuilder.EmitBlockEnd();
@@ -635,7 +635,7 @@ public:
irs->funcGen().jumpTargets.pushLoopTarget(scopeStart, forincbb, endbb);
// replace current scope
- irs->scope() = IRScope(forbb);
+ irs->ir->SetInsertPoint(forbb);
// create the condition
llvm::Value *cond_val;
@@ -658,7 +658,7 @@ public:
}
// rewrite scope
- irs->scope() = IRScope(forbodybb);
+ irs->ir->SetInsertPoint(forbodybb);
// do for body code
PGO.emitCounterIncrement(stmt);
@@ -670,7 +670,7 @@ public:
if (!irs->scopereturned()) {
llvm::BranchInst::Create(forincbb, irs->scopebb());
}
- irs->scope() = IRScope(forincbb);
+ irs->ir->SetInsertPoint(forincbb);
// increment
if (stmt->increment) {
@@ -687,7 +687,7 @@ public:
irs->funcGen().jumpTargets.popLoopTarget();
// rewrite the scope
- irs->scope() = IRScope(endbb);
+ irs->ir->SetInsertPoint(endbb);
// end the dwarf lexical block
irs->DBuilder.EmitBlockEnd();
@@ -731,7 +731,7 @@ public:
// the break terminated this basicblock, start a new one
llvm::BasicBlock *bb = irs->insertBB("afterbreak");
- irs->scope() = IRScope(bb);
+ irs->ir->SetInsertPoint(bb);
}
//////////////////////////////////////////////////////////////////////////
@@ -766,7 +766,7 @@ public:
// the continue terminated this basicblock, start a new one
llvm::BasicBlock *bb = irs->insertBB("aftercontinue");
- irs->scope() = IRScope(bb);
+ irs->ir->SetInsertPoint(bb);
}
//////////////////////////////////////////////////////////////////////////
@@ -818,7 +818,7 @@ public:
: irs->insertBBAfter(finallybb, "try.success");
// Emit the finally block and set up the cleanup scope for it.
- irs->scope() = IRScope(finallybb);
+ irs->ir->SetInsertPoint(finallybb);
irs->DBuilder.EmitBlockStart(stmt->finalbody->loc);
stmt->finalbody->accept(this);
irs->DBuilder.EmitBlockEnd();
@@ -832,7 +832,7 @@ public:
irs->funcGen().scopes.pushCleanup(finallybb, irs->scopebb());
}
// Emit the try block.
- irs->scope() = IRScope(trybb);
+ irs->ir->SetInsertPoint(trybb);
assert(stmt->_body);
irs->DBuilder.EmitBlockStart(stmt->_body->loc);
@@ -842,7 +842,7 @@ public:
if (successbb) {
if (!computeCode)
irs->funcGen().scopes.runCleanups(cleanupBefore, successbb);
- irs->scope() = IRScope(successbb);
+ irs->ir->SetInsertPoint(successbb);
// PGO counter tracks the continuation of the try-finally statement
PGO.emitCounterIncrement(stmt);
}
@@ -874,7 +874,7 @@ public:
irs->funcGen().scopes.pushTryCatch(stmt, endbb);
// Emit the try block.
- irs->scope() = IRScope(trybb);
+ irs->ir->SetInsertPoint(trybb);
assert(stmt->_body);
irs->DBuilder.EmitBlockStart(stmt->_body->loc);
@@ -886,7 +886,7 @@ public:
irs->funcGen().scopes.popTryCatch();
- irs->scope() = IRScope(endbb);
+ irs->ir->SetInsertPoint(endbb);
// PGO counter tracks the continuation of the try statement
PGO.emitCounterIncrement(stmt);
@@ -920,7 +920,7 @@ public:
// TODO: Should not be needed.
llvm::BasicBlock *bb = irs->insertBB("afterthrow");
- irs->scope() = IRScope(bb);
+ irs->ir->SetInsertPoint(bb);
}
//////////////////////////////////////////////////////////////////////////
@@ -986,7 +986,7 @@ public:
// do switch body
assert(stmt->_body);
- irs->scope() = IRScope(bodybb);
+ irs->ir->SetInsertPoint(bodybb);
funcGen.jumpTargets.pushBreakTarget(stmt, endbb);
stmt->_body->accept(this);
funcGen.jumpTargets.popBreakTarget();
@@ -994,7 +994,7 @@ public:
llvm::BranchInst::Create(endbb, irs->scopebb());
}
- irs->scope() = IRScope(oldbb);
+ irs->ir->SetInsertPoint(oldbb);
if (useSwitchInst) {
// The case index value.
LLValue *condVal = DtoRVal(toElemDtor(stmt->condition));
@@ -1018,7 +1018,7 @@ public:
{
llvm::BasicBlock *defaultcntr =
irs->insertBBBefore(defaultTargetBB, "defaultcntr");
- irs->scope() = IRScope(defaultcntr);
+ irs->ir->SetInsertPoint(defaultcntr);
if (stmt->sdefault)
PGO.emitCounterIncrement(stmt->sdefault);
llvm::BranchInst::Create(defaultTargetBB, defaultcntr);
@@ -1033,7 +1033,7 @@ public:
const auto body = funcGen.switchTargets.get(cs);
auto casecntr = irs->insertBBBefore(body, "casecntr");
- irs->scope() = IRScope(casecntr);
+ irs->ir->SetInsertPoint(casecntr);
PGO.emitCounterIncrement(cs);
llvm::BranchInst::Create(body, casecntr);
si->addCase(isaConstantInt(indices[i]), casecntr);
@@ -1068,13 +1068,13 @@ public:
// Prepend extra BB to "default:" to increment profiling counter.
llvm::BasicBlock *defaultcntr =
irs->insertBBBefore(defaultTargetBB, "defaultcntr");
- irs->scope() = IRScope(defaultcntr);
+ irs->ir->SetInsertPoint(defaultcntr);
PGO.emitCounterIncrement(stmt->sdefault);
llvm::BranchInst::Create(defaultTargetBB, defaultcntr);
defaultTargetBB = defaultcntr;
}
- irs->scope() = IRScope(nextbb);
+ irs->ir->SetInsertPoint(nextbb);
auto failedCompareCount = incomingPGORegionCount;
for (size_t i = 0; i < caseCount; ++i) {
LLValue *cmp = irs->ir->CreateICmp(llvm::ICmpInst::ICMP_EQ, indices[i],
@@ -1087,11 +1087,11 @@ public:
if (PGO.emitsInstrumentation()) {
llvm::BasicBlock *casecntr =
irs->insertBBBefore(casejumptargetbb, "casecntr");
- auto savedbb = irs->scope();
- irs->scope() = IRScope(casecntr);
+ const auto savedInsertPoint = irs->getInsertPoint();
+ irs->ir->SetInsertPoint(casecntr);
PGO.emitCounterIncrement(cs);
llvm::BranchInst::Create(casejumptargetbb, casecntr);
- irs->scope() = savedbb;
+ irs->setInsertPoint(savedInsertPoint);
casejumptargetbb = casecntr;
}
@@ -1111,13 +1111,13 @@ public:
PGO.addBranchWeights(branchinst, brweights);
}
- irs->scope() = IRScope(nextbb);
+ irs->ir->SetInsertPoint(nextbb);
}
llvm::BranchInst::Create(defaultTargetBB, irs->scopebb());
}
- irs->scope() = IRScope(endbb);
+ irs->ir->SetInsertPoint(endbb);
// PGO counter tracks exit point of switch statement:
PGO.emitCounterIncrement(stmt);
}
@@ -1141,7 +1141,7 @@ public:
llvm::BranchInst::Create(body, irs->scopebb());
}
- irs->scope() = IRScope(body);
+ irs->ir->SetInsertPoint(body);
assert(stmt->statement);
irs->DBuilder.EmitBlockStart(stmt->statement->loc);
@@ -1172,7 +1172,7 @@ public:
llvm::BranchInst::Create(body, irs->scopebb());
}
- irs->scope() = IRScope(body);
+ irs->ir->SetInsertPoint(body);
assert(stmt->statement);
irs->DBuilder.EmitBlockStart(stmt->statement->loc);
@@ -1231,7 +1231,7 @@ public:
llvm::BasicBlock *nextbb = (i + 1 == nstmt) ? endbb : blocks[i + 1];
// update scope
- irs->scope() = IRScope(thisbb);
+ irs->ir->SetInsertPoint(thisbb);
// push loop scope
// continue goes to next statement, break goes to end
@@ -1251,7 +1251,7 @@ public:
}
}
- irs->scope() = IRScope(endbb);
+ irs->ir->SetInsertPoint(endbb);
// PGO counter tracks the continuation after the loop
PGO.emitCounterIncrement(stmt);
@@ -1334,7 +1334,7 @@ public:
llvm::BranchInst::Create(condbb, irs->scopebb());
// condition
- irs->scope() = IRScope(condbb);
+ irs->ir->SetInsertPoint(condbb);
LLValue *done = nullptr;
LLValue *load = DtoLoad(keyvar);
@@ -1353,7 +1353,7 @@ public:
}
// init body
- irs->scope() = IRScope(bodybb);
+ irs->ir->SetInsertPoint(bodybb);
PGO.emitCounterIncrement(stmt);
// get value for this iteration
@@ -1383,7 +1383,7 @@ public:
}
// next
- irs->scope() = IRScope(nextbb);
+ irs->ir->SetInsertPoint(nextbb);
if (stmt->op == TOKforeach) {
LLValue *load = DtoLoad(keyvar);
load = irs->ir->CreateAdd(load, LLConstantInt::get(keytype, 1, false));
@@ -1395,7 +1395,7 @@ public:
irs->DBuilder.EmitBlockEnd();
// end
- irs->scope() = IRScope(endbb);
+ irs->ir->SetInsertPoint(endbb);
}
//////////////////////////////////////////////////////////////////////////
@@ -1438,7 +1438,7 @@ public:
llvm::BranchInst::Create(condbb, irs->scopebb());
// CONDITION
- irs->scope() = IRScope(condbb);
+ irs->ir->SetInsertPoint(condbb);
// first we test that lwr < upr
lower = DtoLoad(keyval);
@@ -1462,7 +1462,7 @@ public:
}
// BODY
- irs->scope() = IRScope(bodybb);
+ irs->ir->SetInsertPoint(bodybb);
PGO.emitCounterIncrement(stmt);
// reverse foreach decrements here
@@ -1486,7 +1486,7 @@ public:
}
// NEXT
- irs->scope() = IRScope(nextbb);
+ irs->ir->SetInsertPoint(nextbb);
// forward foreach increments here
if (stmt->op == TOKforeach) {
@@ -1503,7 +1503,7 @@ public:
irs->DBuilder.EmitBlockEnd();
// END
- irs->scope() = IRScope(endbb);
+ irs->ir->SetInsertPoint(endbb);
}
//////////////////////////////////////////////////////////////////////////
@@ -1538,7 +1538,7 @@ public:
llvm::BranchInst::Create(labelBB, irs->scopebb());
}
- irs->scope() = IRScope(labelBB);
+ irs->ir->SetInsertPoint(labelBB);
}
PGO.emitCounterIncrement(stmt);
@@ -1565,7 +1565,7 @@ public:
// TODO: Should not be needed.
llvm::BasicBlock *bb = irs->insertBB("aftergoto");
- irs->scope() = IRScope(bb);
+ irs->ir->SetInsertPoint(bb);
}
//////////////////////////////////////////////////////////////////////////
@@ -1590,7 +1590,7 @@ public:
// TODO: Should not be needed.
llvm::BasicBlock *bb = irs->insertBB("aftergotodefault");
- irs->scope() = IRScope(bb);
+ irs->ir->SetInsertPoint(bb);
}
//////////////////////////////////////////////////////////////////////////
@@ -1616,7 +1616,7 @@ public:
// TODO: Should not be needed.
llvm::BasicBlock *bb = irs->insertBB("aftergotocase");
- irs->scope() = IRScope(bb);
+ irs->ir->SetInsertPoint(bb);
}
//////////////////////////////////////////////////////////////////////////
diff --git a/gen/toir.cpp b/gen/toir.cpp
index d9353933..bbbd3783 100644
--- a/gen/toir.cpp
+++ b/gen/toir.cpp
@@ -188,11 +188,11 @@ void pushVarDtorCleanup(IRState *p, VarDeclaration *vd) {
llvm::BasicBlock *beginBB = p->insertBB(llvm::Twine("dtor.") + vd->toChars());
// TODO: Clean this up with push/pop insertion point methods.
- IRScope oldScope = p->scope();
- p->scope() = IRScope(beginBB);
+ const auto savedInsertPoint = p->getInsertPoint();
+ p->ir->SetInsertPoint(beginBB);
toElemDtor(vd->edtor);
p->funcGen().scopes.pushCleanup(beginBB, p->scopebb());
- p->scope() = oldScope;
+ p->setInsertPoint(savedInsertPoint);
}
}
@@ -253,7 +253,7 @@ public:
llvm::BasicBlock *endbb = p->insertBB("toElem.success");
p->funcGen().scopes.runCleanups(initialCleanupScope, endbb);
p->funcGen().scopes.popCleanups(initialCleanupScope);
- p->scope() = IRScope(endbb);
+ p->ir->SetInsertPoint(endbb);
destructTemporaries = false;
}
@@ -1145,10 +1145,10 @@ public:
p->ir->CreateCondBr(okCond, okbb, failbb);
- p->scope() = IRScope(failbb);
+ p->ir->SetInsertPoint(failbb);
DtoBoundsCheckFailCall(p, e->loc);
- p->scope() = IRScope(okbb);
+ p->ir->SetInsertPoint(okbb);
}
// offset by lower
@@ -1267,19 +1267,19 @@ public:
lfptr, rfptr, ".fptreqcmp");
llvm::BranchInst::Create(fptreq, fptrneq, fptreqcmp, p->scopebb());
- p->scope() = IRScope(fptreq);
+ p->ir->SetInsertPoint(fptreq);
llvm::Value *lctx = p->ir->CreateExtractValue(lhs, 0, ".lctx");
llvm::Value *rctx = p->ir->CreateExtractValue(rhs, 0, ".rctx");
llvm::Value *ctxcmp =
p->ir->CreateICmp(icmpPred, lctx, rctx, ".ctxcmp");
llvm::BranchInst::Create(dgcmpend, p->scopebb());
- p->scope() = IRScope(fptrneq);
+ p->ir->SetInsertPoint(fptrneq);
llvm::Value *fptrcmp =
p->ir->CreateICmp(icmpPred, lfptr, rfptr, ".fptrcmp");
llvm::BranchInst::Create(dgcmpend, p->scopebb());
- p->scope() = IRScope(dgcmpend);
+ p->ir->SetInsertPoint(dgcmpend);
llvm::PHINode *phi = p->ir->CreatePHI(ctxcmp->getType(), 2, ".dgcmp");
phi->addIncoming(ctxcmp, fptreq);
phi->addIncoming(fptrcmp, fptrneq);
@@ -1655,7 +1655,7 @@ public:
// assign branch weights to this branch instruction.
// failed: call assert runtime function
- p->scope() = IRScope(failedbb);
+ p->ir->SetInsertPoint(failedbb);
if (global.params.checkAction == CHECKACTION_halt) {
p->ir->CreateCall(GET_INTRINSIC_DECL(trap), {});
@@ -1679,7 +1679,7 @@ public:
}
// passed:
- p->scope() = IRScope(passedbb);
+ p->ir->SetInsertPoint(passedbb);
// class/struct invariants
if (global.params.useInvariants != CHECKENABLEon)
@@ -1764,7 +1764,7 @@ public:
p->ir->CreateCondBr(ubool, isAndAnd ? rhsBB : endBB,
isAndAnd ? endBB : rhsBB, branchweights);
- p->scope() = IRScope(rhsBB);
+ p->ir->SetInsertPoint(rhsBB);
PGO.emitCounterIncrement(e);
emitCoverageLinecountInc(e->e2->loc);
DValue *v = toElemDtor(e->e2);
@@ -1776,7 +1776,7 @@ public:
llvm::BasicBlock *newblock = p->scopebb();
llvm::BranchInst::Create(endBB, p->scopebb());
- p->scope() = IRScope(endBB);
+ p->ir->SetInsertPoint(endBB);
// DMD allows stuff like `x == 0 && assert(false)`
if (e->type->toBasetype()->ty == Tvoid) {
@@ -1821,7 +1821,7 @@ public:
// this is sensible, since someone might goto behind the assert
// and prevents compiler errors if a terminator follows the assert
llvm::BasicBlock *bb = p->insertBB("afterhalt");
- p->scope() = IRScope(bb);
+ p->ir->SetInsertPoint(bb);
}
//////////////////////////////////////////////////////////////////////////////
@@ -2003,7 +2003,7 @@ public:
auto branchweights = PGO.createProfileWeights(truecount, falsecount);
p->ir->CreateCondBr(cond_val, condtrue, condfalse, branchweights);
- p->scope() = IRScope(condtrue);
+ p->ir->SetInsertPoint(condtrue);
PGO.emitCounterIncrement(e);
DValue *u = toElem(e->e1);
if (retPtr) {
@@ -2012,7 +2012,7 @@ public:
}
llvm::BranchInst::Create(condend, p->scopebb());
- p->scope() = IRScope(condfalse);
+ p->ir->SetInsertPoint(condfalse);
DValue *v = toElem(e->e2);
if (retPtr) {
LLValue *lval = makeLValue(e->loc, v);
@@ -2020,7 +2020,7 @@ public:
}
llvm::BranchInst::Create(condend, p->scopebb());
- p->scope() = IRScope(condend);
+ p->ir->SetInsertPoint(condend);
if (retPtr)
result = new DSpecialRefValue(e->type, retPtr);
}
diff --git a/gen/trycatchfinally.cpp b/gen/trycatchfinally.cpp
index b06c4ae3..9a42de2e 100644
--- a/gen/trycatchfinally.cpp
+++ b/gen/trycatchfinally.cpp
@@ -74,7 +74,7 @@ void TryCatchScope::emitCatchBodies(IRState &irs, llvm::Value *ehPtrSlot) {
for (auto c : *stmt->catches) {
auto catchBB =
irs.insertBBBefore(endbb, llvm::Twine("catch.") + c->type->toChars());
- irs.scope() = IRScope(catchBB);
+ irs.ir->SetInsertPoint(catchBB);
irs.DBuilder.EmitBlockStart(c->loc);
PGO.emitCounterIncrement(c);
@@ -218,9 +218,8 @@ void emitBeginCatchMSVC(IRState &irs, Catch *ctch,
// redirect scope to avoid the generation of debug info before the
// catchpad
- IRScope save = irs.scope();
- irs.scope() = IRScope(gIR->topallocapoint()->getParent());
- irs.scope().builder.SetInsertPoint(gIR->topallocapoint());
+ const auto savedInsertPoint = irs.getInsertPoint();
+ irs.ir->SetInsertPoint(gIR->topallocapoint());
DtoDeclarationExp(var);
// catch handler will be outlined, so always treat as a nested reference
@@ -232,7 +231,7 @@ void emitBeginCatchMSVC(IRState &irs, Catch *ctch,
cpyObj = exnObj;
exnObj = DtoAlloca(var->type, "exnObj");
}
- irs.scope() = save;
+ irs.setInsertPoint(savedInsertPoint);
irs.DBuilder.EmitStopPoint(ctch->loc); // re-set debug loc after the
// SetInsertPoint(allocaInst) call
} else if (ctch->type) {
@@ -275,7 +274,7 @@ void emitBeginCatchMSVC(IRState &irs, Catch *ctch,
// outside the catch funclet
llvm::BasicBlock *catchhandler = irs.insertBB("catchhandler");
llvm::CatchReturnInst::Create(catchpad, catchhandler, irs.scopebb());
- irs.scope() = IRScope(catchhandler);
+ irs.ir->SetInsertPoint(catchhandler);
irs.funcGen().pgo.emitCounterIncrement(ctch);
if (!isCPPclass) {
auto enterCatchFn =
@@ -302,7 +301,7 @@ void TryCatchScope::emitCatchBodiesMSVC(IRState &irs, llvm::Value *) {
auto catchBB =
irs.insertBBBefore(endbb, llvm::Twine("catch.") + c->type->toChars());
- irs.scope() = IRScope(catchBB);
+ irs.ir->SetInsertPoint(catchBB);
irs.DBuilder.EmitBlockStart(c->loc);
emitBeginCatchMSVC(irs, c, catchSwitchInst);
@@ -689,12 +688,12 @@ llvm::BasicBlock *TryCatchFinallyScopes::emitLandingPad() {
}
// save and rewrite scope
- IRScope savedIRScope = irs.scope();
+ const auto savedInsertPoint = irs.getInsertPoint();
// insert landing pads at the end of the function, in emission order,
// to improve human-readability of the IR
llvm::BasicBlock *beginBB = irs.insertBBBefore(nullptr, "landingPad");
- irs.scope() = IRScope(beginBB);
+ irs.ir->SetInsertPoint(beginBB);
llvm::LandingPadInst *landingPad = createLandingPadInst(irs);
@@ -724,7 +723,7 @@ llvm::BasicBlock *TryCatchFinallyScopes::emitLandingPad() {
llvm::BasicBlock *afterCleanupBB =
irs.insertBB(beginBB->getName() + llvm::Twine(".after.cleanup"));
runCleanups(lastCleanup, newCleanup, afterCleanupBB);
- irs.scope() = IRScope(afterCleanupBB);
+ irs.ir->SetInsertPoint(afterCleanupBB);
lastCleanup = newCleanup;
}
@@ -747,7 +746,7 @@ llvm::BasicBlock *TryCatchFinallyScopes::emitLandingPad() {
irs.ir->CreateCondBr(
irs.ir->CreateICmpEQ(irs.ir->CreateLoad(ehSelectorSlot), ehTypeId),
cb.bodyBB, mismatchBB, cb.branchWeights);
- irs.scope() = IRScope(mismatchBB);
+ irs.ir->SetInsertPoint(mismatchBB);
}
}
@@ -765,7 +764,7 @@ llvm::BasicBlock *TryCatchFinallyScopes::emitLandingPad() {
irs.ir->CreateBr(resumeUnwindBlock);
}
- irs.scope() = savedIRScope;
+ irs.setInsertPoint(savedInsertPoint);
return beginBB;
}
@@ -780,13 +779,13 @@ llvm::BasicBlock *TryCatchFinallyScopes::getOrCreateResumeUnwindBlock() {
resumeUnwindBlock = irs.insertBB("eh.resume");
llvm::BasicBlock *oldBB = irs.scopebb();
- irs.scope() = IRScope(resumeUnwindBlock);
+ irs.ir->SetInsertPoint(resumeUnwindBlock);
llvm::Function *resumeFn = getUnwindResumeFunction(Loc(), irs.module);
irs.ir->CreateCall(resumeFn, DtoLoad(getOrCreateEhPtrSlot()));
irs.ir->CreateUnreachable();
- irs.scope() = IRScope(oldBB);
+ irs.ir->SetInsertPoint(oldBB);
}
return resumeUnwindBlock;
}
@@ -844,8 +843,7 @@ TryCatchFinallyScopes::runCleanupPad(CleanupCursor scope,
// can place an exception frame (but not done here)
auto frame = getNullPtr(getVoidPtrType());
- auto savedInsertBlock = irs.ir->GetInsertBlock();
- auto savedInsertPoint = irs.ir->GetInsertPoint();
+ auto savedInsertPoint = irs.getInsertPoint();
auto savedDbgLoc = irs.DBuilder.GetCurrentLoc();
auto endFn = getRuntimeFunction(Loc(), irs.module, "_d_leave_cleanup");
@@ -865,7 +863,7 @@ TryCatchFinallyScopes::runCleanupPad(CleanupCursor scope,
beginFn, frame, {llvm::OperandBundleDef("funclet", cleanuppad)}, "");
llvm::BranchInst::Create(copybb, cleanupret, exec, cleanupbb);
- irs.ir->SetInsertPoint(savedInsertBlock, savedInsertPoint);
+ irs.setInsertPoint(savedInsertPoint);
irs.DBuilder.EmitStopPoint(savedDbgLoc);
return cleanupbb;
diff --git a/ir/irclass.cpp b/ir/irclass.cpp
index 9b315f2e..8eecc2cd 100644
--- a/ir/irclass.cpp
+++ b/ir/irclass.cpp
@@ -560,7 +560,10 @@ void IrClass::defineInterfaceVtbl(BaseClass *b, bool new_instance,
// create entry and end blocks
llvm::BasicBlock *beginbb =
llvm::BasicBlock::Create(gIR->context(), "", thunk);
- gIR->scopes.push_back(IRScope(beginbb));
+
+ // set up the IRBuilder scope for the thunk
+ FunctionIRBuilderScope irBuilderScope(*gIR);
+ gIR->setInsertPoint(beginbb);
gIR->DBuilder.EmitFuncStart(thunkFd);
@@ -606,9 +609,6 @@ void IrClass::defineInterfaceVtbl(BaseClass *b, bool new_instance,
gIR->DBuilder.EmitFuncEnd(thunkFd);
- // clean up
- gIR->scopes.pop_back();
-
gIR->funcGenStates.pop_back();
}
--
2.29.0
From 9c42dfd9d0c7ee2a8ef8896204fe7da7b39fc750 Mon Sep 17 00:00:00 2001
From: Martin Kinkelin <noone@nowhere.com>
Date: Sun, 23 Aug 2020 17:29:12 +0200
Subject: [PATCH 02/16] LLVM 11: Adapt debuginfos wrt. static array and vector
lengths
To overcome a new assertion, complaining that subranges with lower
bounds (always 0) aren't supported for CodeView.
---
gen/dibuilder.cpp | 27 +++++++++++++++++++--------
1 file changed, 19 insertions(+), 8 deletions(-)
diff --git a/gen/dibuilder.cpp b/gen/dibuilder.cpp
index 4675cc32..a5fdfceb 100644
--- a/gen/dibuilder.cpp
+++ b/gen/dibuilder.cpp
@@ -385,14 +385,19 @@ DIType DIBuilder::CreateVectorType(Type *type) {
// translate void vectors to byte vectors
if (te->toBasetype()->ty == Tvoid)
te = Type::tuns8;
- int64_t Dim = tv->size(Loc()) / te->size(Loc());
- LLMetadata *subscripts[] = {DBuilder.getOrCreateSubrange(0, Dim)};
+ const auto dim = tv->size(Loc()) / te->size(Loc());
+#if LDC_LLVM_VER >= 1100
+ const auto Dim = llvm::ConstantAsMetadata::get(DtoConstSize_t(dim));
+ auto subscript = DBuilder.getOrCreateSubrange(Dim, nullptr, nullptr, nullptr);
+#else
+ auto subscript = DBuilder.getOrCreateSubrange(0, dim);
+#endif
return DBuilder.createVectorType(
- getTypeAllocSize(T) * 8, // size (bits)
- getABITypeAlign(T) * 8, // align (bits)
- CreateTypeDescription(te), // element type
- DBuilder.getOrCreateArray(subscripts) // subscripts
+ getTypeAllocSize(T) * 8, // size (bits)
+ getABITypeAlign(T) * 8, // align (bits)
+ CreateTypeDescription(te), // element type
+ DBuilder.getOrCreateArray({subscript}) // subscripts
);
}
@@ -681,8 +686,14 @@ DIType DIBuilder::CreateSArrayType(Type *type) {
llvm::SmallVector<LLMetadata *, 8> subscripts;
while (t->ty == Tsarray) {
TypeSArray *tsa = static_cast<TypeSArray *>(t);
- int64_t Count = tsa->dim->toInteger();
- auto subscript = DBuilder.getOrCreateSubrange(0, Count);
+ const auto count = tsa->dim->toInteger();
+#if LDC_LLVM_VER >= 1100
+ const auto Count = llvm::ConstantAsMetadata::get(DtoConstSize_t(count));
+ const auto subscript =
+ DBuilder.getOrCreateSubrange(Count, nullptr, nullptr, nullptr);
+#else
+ const auto subscript = DBuilder.getOrCreateSubrange(0, count);
+#endif
subscripts.push_back(subscript);
t = t->nextOf();
}
--
2.29.0
From 96b9cde4289bb82cc9100d9b52e70f7e4febfb1d Mon Sep 17 00:00:00 2001
From: Martin Kinkelin <noone@nowhere.com>
Date: Sun, 23 Aug 2020 14:13:13 +0200
Subject: [PATCH 03/16] Add support for LLVM 11
One major change is the removal of llvm::CallSite, which I've replaced
by llvm::CallBase*.
---
CMakeLists.txt | 7 +-
cmake/Modules/FindLLVM.cmake | 3 +-
dmd/root/longdouble.h | 2 +
driver/archiver.cpp | 3 +
driver/cache.cpp | 23 +-
driver/cl_options-llvm.cpp | 81 +-
driver/codegenerator.cpp | 13 +-
driver/ldmd.cpp | 4 +
driver/linker-gcc.cpp | 2 +-
driver/linker.cpp | 2 +-
gen/aa.cpp | 16 +-
gen/abi-generic.h | 7 +-
gen/arrays.cpp | 60 +-
gen/classes.cpp | 10 +-
gen/funcgenstate.cpp | 19 +-
gen/funcgenstate.h | 8 +-
gen/functions.cpp | 2 +-
gen/irstate.cpp | 41 +-
gen/irstate.h | 32 +-
gen/llvm.h | 9 +-
gen/llvmhelpers.cpp | 28 +-
gen/passes/GarbageCollect2Stack.cpp | 107 +-
gen/tocall.cpp | 26 +-
gen/toconstelem.cpp | 7 +-
gen/toir.cpp | 11 +-
gen/tollvm.cpp | 8 +-
gen/trycatchfinally.cpp | 10 +-
gen/uda.cpp | 6 +
ir/irtype.cpp | 7 +-
tests/lit.site.cfg.in | 2 +-
tools/ldc-profdata/llvm-profdata-11.0.cpp | 1344 +++++++++++++++++++++
utils/FileCheck-11.0.cpp | 859 +++++++++++++
utils/gen_gccbuiltins.cpp | 34 +-
33 files changed, 2563 insertions(+), 230 deletions(-)
create mode 100644 tools/ldc-profdata/llvm-profdata-11.0.cpp
create mode 100644 utils/FileCheck-11.0.cpp
diff --git a/CMakeLists.txt b/CMakeLists.txt
index d6f7c596..46c2d3ae 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -450,7 +450,12 @@ include(HandleLTOPGOBuildOptions)
set(LDC_DYNAMIC_COMPILE "AUTO" CACHE STRING "Support dynamic compilation (ON|OFF). Enabled by default.")
option(LDC_DYNAMIC_COMPILE_USE_CUSTOM_PASSES "Use custom LDC passes in jit" ON)
if(LDC_DYNAMIC_COMPILE STREQUAL "AUTO")
- set(LDC_DYNAMIC_COMPILE ON)
+ if(LDC_LLVM_VER LESS 1100)
+ set(LDC_DYNAMIC_COMPILE ON)
+ else()
+ # FIXME: support LLVM 11+ too
+ set(LDC_DYNAMIC_COMPILE OFF)
+ endif()
endif()
message(STATUS "Building LDC with dynamic compilation support: ${LDC_DYNAMIC_COMPILE} (LDC_DYNAMIC_COMPILE=${LDC_DYNAMIC_COMPILE})")
if(LDC_DYNAMIC_COMPILE)
diff --git a/cmake/Modules/FindLLVM.cmake b/cmake/Modules/FindLLVM.cmake
index f02aa2c4..a192ccd3 100644
--- a/cmake/Modules/FindLLVM.cmake
+++ b/cmake/Modules/FindLLVM.cmake
@@ -30,7 +30,8 @@
# We also want an user-specified LLVM_ROOT_DIR to take precedence over the
# system default locations such as /usr/local/bin. Executing find_program()
# multiples times is the approach recommended in the docs.
-set(llvm_config_names llvm-config-10.0 llvm-config100 llvm-config-10
+set(llvm_config_names llvm-config-11.0 llvm-config110 llvm-config-11
+ llvm-config-10.0 llvm-config100 llvm-config-10
llvm-config-9.0 llvm-config90 llvm-config-9
llvm-config-8.0 llvm-config80 llvm-config-8
llvm-config-7.0 llvm-config70 llvm-config-7
diff --git a/dmd/root/longdouble.h b/dmd/root/longdouble.h
index 7916d569..31282b63 100644
--- a/dmd/root/longdouble.h
+++ b/dmd/root/longdouble.h
@@ -216,6 +216,7 @@ longdouble_soft ldexpl(longdouble_soft ldval, int exp); // see strtold
inline longdouble_soft fabs (longdouble_soft ld) { return fabsl(ld); }
inline longdouble_soft sqrt (longdouble_soft ld) { return sqrtl(ld); }
+#if !IN_LLVM
#undef LDBL_DIG
#undef LDBL_MAX
#undef LDBL_MIN
@@ -235,6 +236,7 @@ inline longdouble_soft sqrt (longdouble_soft ld) { return sqrtl(ld); }
#define LDBL_MIN_EXP (-16381)
#define LDBL_MAX_10_EXP 4932
#define LDBL_MIN_10_EXP (-4932)
+#endif // !IN_LLVM
extern const longdouble_soft ld_qnan;
extern const longdouble_soft ld_inf;
diff --git a/driver/archiver.cpp b/driver/archiver.cpp
index c2c907b9..743afb42 100644
--- a/driver/archiver.cpp
+++ b/driver/archiver.cpp
@@ -18,6 +18,9 @@
#include "llvm/Object/MachO.h"
#include "llvm/Object/ObjectFile.h"
#include "llvm/Support/Errc.h"
+#if LDC_LLVM_VER >= 1100
+#include "llvm/Support/Host.h"
+#endif
#include "llvm/Support/Path.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/ToolDrivers/llvm-lib/LibDriver.h"
diff --git a/driver/cache.cpp b/driver/cache.cpp
index 77ddd3ff..bb0f26cb 100644
--- a/driver/cache.cpp
+++ b/driver/cache.cpp
@@ -65,13 +65,22 @@ static bool createSymLink(const char *to, const char *from) {
#include <windows.h>
namespace llvm {
namespace sys {
+#if LDC_LLVM_VER >= 1100
+namespace windows {
+// Fwd declaration to an internal LLVM function.
+std::error_code widenPath(const llvm::Twine &Path8,
+ llvm::SmallVectorImpl<wchar_t> &Path16,
+ size_t MaxPathLen = MAX_PATH);
+}
+#else
namespace path {
// Fwd declaration to an internal LLVM function.
std::error_code widenPath(const llvm::Twine &Path8,
llvm::SmallVectorImpl<wchar_t> &Path16);
}
-}
-}
+#endif // LDC_LLVM_VER < 1100
+} // namespace sys
+} // namespace llvm
// Returns true upon error.
namespace {
template <typename FType>
@@ -83,11 +92,17 @@ bool createLink(FType f, const char *to, const char *from) {
//
//===----------------------------------------------------------------------===//
+#if LDC_LLVM_VER >= 1100
+ using llvm::sys::windows::widenPath;
+#else
+ using llvm::sys::path::widenPath;
+#endif
+
llvm::SmallVector<wchar_t, 128> wide_from;
llvm::SmallVector<wchar_t, 128> wide_to;
- if (llvm::sys::path::widenPath(from, wide_from))
+ if (widenPath(from, wide_from))
return true;
- if (llvm::sys::path::widenPath(to, wide_to))
+ if (widenPath(to, wide_to))
return true;
if (!(*f)(wide_from.begin(), wide_to.begin(), NULL))
diff --git a/driver/cl_options-llvm.cpp b/driver/cl_options-llvm.cpp
index 4071074e..5071fd11 100644
--- a/driver/cl_options-llvm.cpp
+++ b/driver/cl_options-llvm.cpp
@@ -11,7 +11,11 @@
// Pull in command-line options and helper functions from special LLVM header
// shared by multiple LLVM tools.
-#if LDC_LLVM_VER >= 700
+#if LDC_LLVM_VER >= 1100
+#include "llvm/CodeGen/CommandFlags.h"
+static llvm::codegen::RegisterCodeGenFlags CGF;
+using namespace llvm;
+#elif LDC_LLVM_VER >= 700
#include "llvm/CodeGen/CommandFlags.inc"
#else
#include "llvm/CodeGen/CommandFlags.def"
@@ -21,7 +25,7 @@ static cl::opt<bool>
DisableRedZone("disable-red-zone", cl::ZeroOrMore,
cl::desc("Do not emit code that uses the red zone."));
-#if LDC_LLVM_VER >= 800
+#if LDC_LLVM_VER >= 800 && LDC_LLVM_VER < 1100
// legacy option
static cl::opt<bool>
disableFPElim("disable-fp-elim", cl::ZeroOrMore, cl::ReallyHidden,
@@ -32,19 +36,41 @@ static cl::opt<bool>
// in the opts namespace, including some additional helper functions.
namespace opts {
-std::string getArchStr() { return ::MArch; }
+std::string getArchStr() {
+#if LDC_LLVM_VER >= 1100
+ return codegen::getMArch();
+#else
+ return ::MArch;
+#endif
+}
-Optional<Reloc::Model> getRelocModel() { return ::getRelocModel(); }
+Optional<Reloc::Model> getRelocModel() {
+#if LDC_LLVM_VER >= 1100
+ return codegen::getExplicitRelocModel();
+#else
+ return ::getRelocModel();
+#endif
+}
-Optional<CodeModel::Model> getCodeModel() { return ::getCodeModel(); }
+Optional<CodeModel::Model> getCodeModel() {
+#if LDC_LLVM_VER >= 1100
+ return codegen::getExplicitCodeModel();
+#else
+ return ::getCodeModel();
+#endif
+}
#if LDC_LLVM_VER >= 800
llvm::Optional<llvm::FramePointer::FP> framePointerUsage() {
+#if LDC_LLVM_VER >= 1100
+ return codegen::getFramePointerUsage();
+#else
if (::FramePointerUsage.getNumOccurrences() > 0)
return ::FramePointerUsage.getValue();
if (disableFPElim.getNumOccurrences() > 0)
return disableFPElim ? llvm::FramePointer::All : llvm::FramePointer::None;
return llvm::None;
+#endif
}
#else
cl::boolOrDefault disableFPElim() {
@@ -57,6 +83,10 @@ cl::boolOrDefault disableFPElim() {
bool disableRedZone() { return ::DisableRedZone; }
bool printTargetFeaturesHelp() {
+#if LDC_LLVM_VER >= 1100
+ const auto MCPU = codegen::getMCPU();
+ const auto MAttrs = codegen::getMAttrs();
+#endif
if (MCPU == "help")
return true;
return std::any_of(MAttrs.begin(), MAttrs.end(),
@@ -64,11 +94,28 @@ bool printTargetFeaturesHelp() {
}
TargetOptions InitTargetOptionsFromCodeGenFlags() {
+#if LDC_LLVM_VER >= 1100
+ return codegen::InitTargetOptionsFromCodeGenFlags();
+#else
return ::InitTargetOptionsFromCodeGenFlags();
+#endif
+}
+
+std::string getCPUStr() {
+#if LDC_LLVM_VER >= 1100
+ return codegen::getCPUStr();
+#else
+ return ::getCPUStr();
+#endif
}
-std::string getCPUStr() { return ::getCPUStr(); }
-std::string getFeaturesStr() { return ::getFeaturesStr(); }
+std::string getFeaturesStr() {
+#if LDC_LLVM_VER >= 1100
+ return codegen::getFeaturesStr();
+#else
+ return ::getFeaturesStr();
+#endif
+}
} // namespace opts
#if LDC_WITH_LLD
@@ -81,30 +128,32 @@ TargetOptions initTargetOptionsFromCodeGenFlags() {
#else
TargetOptions InitTargetOptionsFromCodeGenFlags() {
#endif
- return ::InitTargetOptionsFromCodeGenFlags();
+ return ::opts::InitTargetOptionsFromCodeGenFlags();
}
#if LDC_LLVM_VER >= 1000
-Optional<Reloc::Model> getRelocModelFromCMModel() { return ::getRelocModel(); }
+Optional<Reloc::Model> getRelocModelFromCMModel() {
+ return ::opts::getRelocModel();
+}
#endif
#if LDC_LLVM_VER >= 900
Optional<CodeModel::Model> getCodeModelFromCMModel() {
- return ::getCodeModel();
-}
#else
Optional<CodeModel::Model> GetCodeModelFromCMModel() {
- return ::getCodeModel();
-}
#endif
+ return ::opts::getCodeModel();
+}
#if LDC_LLVM_VER >= 900
-std::string getCPUStr() { return ::getCPUStr(); }
+std::string getCPUStr() { return ::opts::getCPUStr(); }
#elif LDC_LLVM_VER >= 700
-std::string GetCPUStr() { return ::getCPUStr(); }
+std::string GetCPUStr() { return ::opts::getCPUStr(); }
#endif
-#if LDC_LLVM_VER >= 900
+#if LDC_LLVM_VER >= 1100
+std::vector<std::string> getMAttrs() { return codegen::getMAttrs(); }
+#elif LDC_LLVM_VER >= 900
std::vector<std::string> getMAttrs() { return ::MAttrs; }
#elif LDC_LLVM_VER >= 800
std::vector<std::string> GetMAttrs() { return ::MAttrs; }
diff --git a/driver/codegenerator.cpp b/driver/codegenerator.cpp
index 0833df46..9edbbcf9 100644
--- a/driver/codegenerator.cpp
+++ b/driver/codegenerator.cpp
@@ -23,7 +23,9 @@
#include "gen/logger.h"
#include "gen/modules.h"
#include "gen/runtime.h"
-#if LDC_LLVM_VER >= 900
+#if LDC_LLVM_VER >= 1100
+#include "llvm/IR/LLVMRemarkStreamer.h"
+#elif LDC_LLVM_VER >= 900
#include "llvm/IR/RemarkStreamer.h"
#endif
#include "llvm/Support/FileSystem.h"
@@ -52,8 +54,13 @@ createAndSetDiagnosticsOutputFile(IRState &irs, llvm::LLVMContext &ctx,
const bool withHotness = opts::isUsingPGOProfile();
#if LDC_LLVM_VER >= 900
- auto remarksFileOrError = llvm::setupOptimizationRemarks(
- ctx, diagnosticsFilename, "", "", withHotness);
+ auto remarksFileOrError =
+#if LDC_LLVM_VER >= 1100
+ llvm::setupLLVMOptimizationRemarks(
+#else
+ llvm::setupOptimizationRemarks(
+#endif
+ ctx, diagnosticsFilename, "", "", withHotness);
if (llvm::Error e = remarksFileOrError.takeError()) {
irs.dmodule->error("Could not create file %s: %s",
diagnosticsFilename.c_str(),
diff --git a/driver/ldmd.cpp b/driver/ldmd.cpp
index e4dc80d6..ef50e47f 100644
--- a/driver/ldmd.cpp
+++ b/driver/ldmd.cpp
@@ -476,7 +476,11 @@ void translateArgs(const llvm::SmallVectorImpl<const char *> &ldmdArgs,
else if (strcmp(p + 1, "gf") == 0) {
ldcArgs.push_back("-g");
} else if (strcmp(p + 1, "gs") == 0) {
+#if LDC_LLVM_VER >= 1100
+ ldcArgs.push_back("-frame-pointer=all");
+#else
ldcArgs.push_back("-disable-fp-elim");
+#endif
} else if (strcmp(p + 1, "gx") == 0) {
goto Lnot_in_ldc;
} else if (strcmp(p + 1, "gt") == 0) {
diff --git a/driver/linker-gcc.cpp b/driver/linker-gcc.cpp
index 1b364fb7..e2a25231 100644
--- a/driver/linker-gcc.cpp
+++ b/driver/linker-gcc.cpp
@@ -321,7 +321,7 @@ void ArgsBuilder::addSanitizerLinkFlags(const llvm::Triple &triple,
// When we reach here, we did not find the sanitizer library.
// Fallback, requires Clang.
- args.push_back(fallbackFlag);
+ args.emplace_back(fallbackFlag);
}
// Adds all required link flags for -fsanitize=fuzzer when libFuzzer library is
diff --git a/driver/linker.cpp b/driver/linker.cpp
index 3fc08ca9..ab3ab205 100644
--- a/driver/linker.cpp
+++ b/driver/linker.cpp
@@ -145,7 +145,7 @@ static std::vector<std::string>
parseLibNames(llvm::StringRef commaSeparatedList, llvm::StringRef suffix = {}) {
std::vector<std::string> result;
- std::stringstream list(commaSeparatedList);
+ std::stringstream list(commaSeparatedList.str());
while (list.good()) {
std::string lib;
std::getline(list, lib, ',');
diff --git a/gen/aa.cpp b/gen/aa.cpp
index 5344dc33..0c011f87 100644
--- a/gen/aa.cpp
+++ b/gen/aa.cpp
@@ -65,12 +65,10 @@ DLValue *DtoAAIndex(Loc &loc, Type *type, DValue *aa, DValue *key,
LLValue *castedAATI = DtoBitCast(rawAATI, funcTy->getParamType(1));
LLValue *valsize = DtoConstSize_t(getTypeAllocSize(DtoType(type)));
ret = gIR->CreateCallOrInvoke(func, aaval, castedAATI, valsize, pkey,
- "aa.index")
- .getInstruction();
+ "aa.index");
} else {
LLValue *keyti = to_keyti(aa, funcTy->getParamType(1));
- ret = gIR->CreateCallOrInvoke(func, aaval, keyti, pkey, "aa.index")
- .getInstruction();
+ ret = gIR->CreateCallOrInvoke(func, aaval, keyti, pkey, "aa.index");
}
// cast return value
@@ -134,8 +132,7 @@ DValue *DtoAAIn(Loc &loc, Type *type, DValue *aa, DValue *key) {
pkey = DtoBitCast(pkey, getVoidPtrType());
// call runtime
- LLValue *ret = gIR->CreateCallOrInvoke(func, aaval, keyti, pkey, "aa.in")
- .getInstruction();
+ LLValue *ret = gIR->CreateCallOrInvoke(func, aaval, keyti, pkey, "aa.in");
// cast return value
LLType *targettype = DtoType(type);
@@ -179,9 +176,9 @@ DValue *DtoAARemove(Loc &loc, DValue *aa, DValue *key) {
pkey = DtoBitCast(pkey, funcTy->getParamType(2));
// call runtime
- LLCallSite call = gIR->CreateCallOrInvoke(func, aaval, keyti, pkey);
+ LLValue *res = gIR->CreateCallOrInvoke(func, aaval, keyti, pkey);
- return new DImValue(Type::tbool, call.getInstruction());
+ return new DImValue(Type::tbool, res);
}
////////////////////////////////////////////////////////////////////////////////
@@ -197,8 +194,7 @@ LLValue *DtoAAEquals(Loc &loc, TOK op, DValue *l, DValue *r) {
LLValue *abval = DtoBitCast(DtoRVal(r), funcTy->getParamType(2));
LLValue *aaTypeInfo = DtoTypeInfoOf(t);
LLValue *res =
- gIR->CreateCallOrInvoke(func, aaTypeInfo, aaval, abval, "aaEqRes")
- .getInstruction();
+ gIR->CreateCallOrInvoke(func, aaTypeInfo, aaval, abval, "aaEqRes");
const auto predicate = eqTokToICmpPred(op, /* invert = */ true);
res = gIR->ir->CreateICmp(predicate, res, DtoConstInt(0));
diff --git a/gen/abi-generic.h b/gen/abi-generic.h
index b4d4999e..f7c41f42 100644
--- a/gen/abi-generic.h
+++ b/gen/abi-generic.h
@@ -36,7 +36,12 @@ struct LLTypeMemoryLayout {
const size_t sizeInBits = getTypeBitSize(type);
assert(sizeInBits % 8 == 0);
return llvm::VectorType::get(LLIntegerType::get(gIR->context(), 8),
- sizeInBits / 8);
+ sizeInBits / 8
+#if LDC_LLVM_VER >= 1100
+ ,
+ /*Scalable=*/false
+#endif
+ );
}
if (LLStructType *structType = isaStruct(type)) {
diff --git a/gen/arrays.cpp b/gen/arrays.cpp
index 0d867b07..3d2a3f56 100644
--- a/gen/arrays.cpp
+++ b/gen/arrays.cpp
@@ -198,7 +198,7 @@ static void copySlice(Loc &loc, LLValue *dstarr, LLValue *dstlen, LLValue *srcar
const bool checksEnabled =
global.params.useAssert == CHECKENABLEon || gIR->emitArrayBoundsChecks();
if (checksEnabled && !knownInBounds) {
- LLValue *fn = getRuntimeFunction(loc, gIR->module, "_d_array_slice_copy");
+ LLFunction *fn = getRuntimeFunction(loc, gIR->module, "_d_array_slice_copy");
gIR->CreateCallOrInvoke(
fn, {dstarr, dstlen, srcarr, srclen, DtoConstSize_t(elementSize)}, "",
/*isNothrow=*/true);
@@ -293,20 +293,18 @@ void DtoArrayAssign(Loc &loc, DValue *lhs, DValue *rhs, int op,
}
} else if (isConstructing) {
LLFunction *fn = getRuntimeFunction(loc, gIR->module, "_d_arrayctor");
- LLCallSite call = gIR->CreateCallOrInvoke(fn, DtoTypeInfoOf(elemType),
- DtoSlice(rhsPtr, rhsLength),
- DtoSlice(lhsPtr, lhsLength));
- call.setCallingConv(llvm::CallingConv::C);
+ gIR->CreateCallOrInvoke(fn, DtoTypeInfoOf(elemType),
+ DtoSlice(rhsPtr, rhsLength),
+ DtoSlice(lhsPtr, lhsLength));
} else // assigning
{
LLValue *tmpSwap = DtoAlloca(elemType, "arrayAssign.tmpSwap");
LLFunction *fn = getRuntimeFunction(
loc, gIR->module,
!canSkipPostblit ? "_d_arrayassign_l" : "_d_arrayassign_r");
- LLCallSite call = gIR->CreateCallOrInvoke(
+ gIR->CreateCallOrInvoke(
fn, DtoTypeInfoOf(elemType), DtoSlice(rhsPtr, rhsLength),
DtoSlice(lhsPtr, lhsLength), DtoBitCast(tmpSwap, getVoidPtrType()));
- call.setCallingConv(llvm::CallingConv::C);
}
} else {
// scalar rhs:
@@ -335,12 +333,11 @@ void DtoArrayAssign(Loc &loc, DValue *lhs, DValue *rhs, int op,
LLFunction *fn = getRuntimeFunction(loc, gIR->module,
isConstructing ? "_d_arraysetctor"
: "_d_arraysetassign");
- LLCallSite call = gIR->CreateCallOrInvoke(
+ gIR->CreateCallOrInvoke(
fn, lhsPtr, DtoBitCast(makeLValue(loc, rhs), getVoidPtrType()),
gIR->ir->CreateTruncOrBitCast(lhsLength,
LLType::getInt32Ty(gIR->context())),
DtoTypeInfoOf(stripModifiers(t2)));
- call.setCallingConv(llvm::CallingConv::C);
}
}
}
@@ -704,8 +701,7 @@ DSliceValue *DtoNewDynArray(Loc &loc, Type *arrayType, DValue *dim,
// call allocator
LLValue *newArray =
- gIR->CreateCallOrInvoke(fn, arrayTypeInfo, arrayLen, ".gc_mem")
- .getInstruction();
+ gIR->CreateCallOrInvoke(fn, arrayTypeInfo, arrayLen, ".gc_mem");
// return a DSliceValue with the well-known length for better optimizability
auto ptr =
@@ -774,8 +770,7 @@ DSliceValue *DtoNewMulDimDynArray(Loc &loc, Type *arrayType, DValue **dims,
// call allocator
LLValue *newptr =
- gIR->CreateCallOrInvoke(fn, arrayTypeInfo, DtoLoad(darray), ".gc_mem")
- .getInstruction();
+ gIR->CreateCallOrInvoke(fn, arrayTypeInfo, DtoLoad(darray), ".gc_mem");
IF_LOG Logger::cout() << "final ptr = " << *newptr << '\n';
@@ -802,12 +797,10 @@ DSliceValue *DtoResizeDynArray(Loc &loc, Type *arrayType, DValue *array,
getRuntimeFunction(loc, gIR->module, zeroInit ? "_d_arraysetlengthT"
: "_d_arraysetlengthiT");
- LLValue *newArray =
- gIR->CreateCallOrInvoke(
- fn, DtoTypeInfoOf(arrayType), newdim,
- DtoBitCast(DtoLVal(array), fn->getFunctionType()->getParamType(2)),
- ".gc_mem")
- .getInstruction();
+ LLValue *newArray = gIR->CreateCallOrInvoke(
+ fn, DtoTypeInfoOf(arrayType), newdim,
+ DtoBitCast(DtoLVal(array), fn->getFunctionType()->getParamType(2)),
+ ".gc_mem");
return getSlice(arrayType, newArray);
}
@@ -853,14 +846,11 @@ DSliceValue *DtoCatAssignArray(Loc &loc, DValue *arr, Expression *exp) {
LLFunction *fn = getRuntimeFunction(loc, gIR->module, "_d_arrayappendT");
// Call _d_arrayappendT(TypeInfo ti, byte[] *px, byte[] y)
- LLValue *newArray =
- gIR->CreateCallOrInvoke(
- fn, DtoTypeInfoOf(arrayType),
- DtoBitCast(DtoLVal(arr), fn->getFunctionType()->getParamType(1)),
- DtoAggrPaint(DtoSlice(exp),
- fn->getFunctionType()->getParamType(2)),
- ".appendedArray")
- .getInstruction();
+ LLValue *newArray = gIR->CreateCallOrInvoke(
+ fn, DtoTypeInfoOf(arrayType),
+ DtoBitCast(DtoLVal(arr), fn->getFunctionType()->getParamType(1)),
+ DtoAggrPaint(DtoSlice(exp), fn->getFunctionType()->getParamType(2)),
+ ".appendedArray");
return getSlice(arrayType, newArray);
}
@@ -929,8 +919,7 @@ DSliceValue *DtoCatArrays(Loc &loc, Type *arrayType, Expression *exp1,
args.push_back(val);
}
- auto newArray =
- gIR->CreateCallOrInvoke(fn, args, ".appendedArray").getInstruction();
+ auto newArray = gIR->CreateCallOrInvoke(fn, args, ".appendedArray");
return getSlice(arrayType, newArray);
}
@@ -944,13 +933,10 @@ DSliceValue *DtoAppendDChar(Loc &loc, DValue *arr, Expression *exp,
LLFunction *fn = getRuntimeFunction(loc, gIR->module, func);
// Call function (ref string x, dchar c)
- LLValue *newArray =
- gIR->CreateCallOrInvoke(
- fn,
- DtoBitCast(DtoLVal(arr), fn->getFunctionType()->getParamType(0)),
- DtoBitCast(valueToAppend, fn->getFunctionType()->getParamType(1)),
- ".appendedArray")
- .getInstruction();
+ LLValue *newArray = gIR->CreateCallOrInvoke(
+ fn, DtoBitCast(DtoLVal(arr), fn->getFunctionType()->getParamType(0)),
+ DtoBitCast(valueToAppend, fn->getFunctionType()->getParamType(1)),
+ ".appendedArray");
return getSlice(arr->type, newArray);
}
@@ -1003,7 +989,7 @@ LLValue *DtoArrayEqCmp_impl(Loc &loc, const char *func, DValue *l,
args.push_back(DtoBitCast(tival, fn->getFunctionType()->getParamType(2)));
}
- return gIR->CreateCallOrInvoke(fn, args).getInstruction();
+ return gIR->CreateCallOrInvoke(fn, args);
}
/// When `true` is returned, the type can be compared using `memcmp`.
diff --git a/gen/classes.cpp b/gen/classes.cpp
index 0777ce02..b78f9295 100644
--- a/gen/classes.cpp
+++ b/gen/classes.cpp
@@ -103,10 +103,8 @@ DValue *DtoNewClass(Loc &loc, TypeClass *tc, NewExp *newexp) {
loc, gIR->module, useEHAlloc ? "_d_newThrowable" : "_d_allocclass");
LLConstant *ci = DtoBitCast(getIrAggr(tc->sym)->getClassInfoSymbol(),
DtoType(getClassInfoType()));
- mem = gIR->CreateCallOrInvoke(fn, ci,
- useEHAlloc ? ".newthrowable_alloc"
- : ".newclass_gc_alloc")
- .getInstruction();
+ mem = gIR->CreateCallOrInvoke(
+ fn, ci, useEHAlloc ? ".newthrowable_alloc" : ".newclass_gc_alloc");
mem = DtoBitCast(mem, DtoType(tc),
useEHAlloc ? ".newthrowable" : ".newclass_gc");
doInit = !useEHAlloc;
@@ -375,7 +373,7 @@ DValue *DtoDynamicCastObject(Loc &loc, DValue *val, Type *_to) {
assert(funcTy->getParamType(1) == cinfo->getType());
// call it
- LLValue *ret = gIR->CreateCallOrInvoke(func, obj, cinfo).getInstruction();
+ LLValue *ret = gIR->CreateCallOrInvoke(func, obj, cinfo);
// cast return value
ret = DtoBitCast(ret, DtoType(_to));
@@ -409,7 +407,7 @@ DValue *DtoDynamicCastInterface(Loc &loc, DValue *val, Type *_to) {
cinfo = DtoBitCast(cinfo, funcTy->getParamType(1));
// call it
- LLValue *ret = gIR->CreateCallOrInvoke(func, ptr, cinfo).getInstruction();
+ LLValue *ret = gIR->CreateCallOrInvoke(func, ptr, cinfo);
// cast return value
ret = DtoBitCast(ret, DtoType(_to));
diff --git a/gen/funcgenstate.cpp b/gen/funcgenstate.cpp
index e2c16958..ae0504e7 100644
--- a/gen/funcgenstate.cpp
+++ b/gen/funcgenstate.cpp
@@ -103,9 +103,10 @@ FuncGenState::FuncGenState(IrFunction &irFunc, IRState &irs)
: irFunc(irFunc), scopes(irs), jumpTargets(scopes), switchTargets(),
irs(irs) {}
-llvm::CallSite FuncGenState::callOrInvoke(llvm::Value *callee,
- llvm::ArrayRef<llvm::Value *> args,
- const char *name, bool isNothrow) {
+llvm::CallBase *FuncGenState::callOrInvoke(llvm::Value *callee,
+ llvm::FunctionType *calleeType,
+ llvm::ArrayRef<llvm::Value *> args,
+ const char *name, bool isNothrow) {
// If this is a direct call, we might be able to use the callee attributes
// to our advantage.
llvm::Function *calleeFn = llvm::dyn_cast<llvm::Function>(callee);
@@ -123,8 +124,14 @@ llvm::CallSite FuncGenState::callOrInvoke(llvm::Value *callee,
// calls inside a funclet must be annotated with its value
llvm::SmallVector<llvm::OperandBundleDef, 2> BundleList;
+#if LDC_LLVM_VER >= 1100
+ llvm::FunctionCallee calleeArg(calleeType, callee);
+#else
+ auto calleeArg = callee;
+#endif
+
if (doesNotThrow || scopes.empty()) {
- llvm::CallInst *call = irs.ir->CreateCall(callee, args, BundleList, name);
+ auto call = irs.ir->CreateCall(calleeArg, args, BundleList, name);
if (calleeFn) {
call->setAttributes(calleeFn->getAttributes());
}
@@ -134,8 +141,8 @@ llvm::CallSite FuncGenState::callOrInvoke(llvm::Value *callee,
llvm::BasicBlock *landingPad = scopes.getLandingPad();
llvm::BasicBlock *postinvoke = irs.insertBB("postinvoke");
- llvm::InvokeInst *invoke = irs.ir->CreateInvoke(
- callee, postinvoke, landingPad, args, BundleList, name);
+ auto invoke = irs.ir->CreateInvoke(calleeArg, postinvoke, landingPad, args,
+ BundleList, name);
if (calleeFn) {
invoke->setAttributes(calleeFn->getAttributes());
}
diff --git a/gen/funcgenstate.h b/gen/funcgenstate.h
index 365b38bf..bd1edc0d 100644
--- a/gen/funcgenstate.h
+++ b/gen/funcgenstate.h
@@ -18,7 +18,6 @@
#include "gen/pgo_ASTbased.h"
#include "gen/trycatchfinally.h"
#include "llvm/ADT/DenseMap.h"
-#include "llvm/IR/CallSite.h"
#include <vector>
class Identifier;
@@ -200,9 +199,10 @@ public:
/// Emits a call or invoke to the given callee, depending on whether there
/// are catches/cleanups active or not.
- llvm::CallSite callOrInvoke(llvm::Value *callee,
- llvm::ArrayRef<llvm::Value *> args,
- const char *name = "", bool isNothrow = false);
+ llvm::CallBase *callOrInvoke(llvm::Value *callee,
+ llvm::FunctionType *calleeType,
+ llvm::ArrayRef<llvm::Value *> args,
+ const char *name = "", bool isNothrow = false);
private:
IRState &irs;
diff --git a/gen/functions.cpp b/gen/functions.cpp
index 554102ca..46c10c46 100644
--- a/gen/functions.cpp
+++ b/gen/functions.cpp
@@ -926,7 +926,7 @@ void emulateWeakAnyLinkageForMSVC(LLFunction *func, LINK linkage) {
finalMangle = mangleBuffer;
}
- std::string finalWeakMangle = finalMangle;
+ std::string finalWeakMangle = finalMangle.str();
if (linkage == LINKcpp) {
assert(finalMangle.startswith("?"));
// prepend `__weak_` to first identifier
diff --git a/gen/irstate.cpp b/gen/irstate.cpp
index 0ac6ddc3..eb73ab41 100644
--- a/gen/irstate.cpp
+++ b/gen/irstate.cpp
@@ -99,35 +99,42 @@ llvm::BasicBlock *IRState::insertBB(const llvm::Twine &name) {
return insertBBAfter(scopebb(), name);
}
-LLCallSite IRState::CreateCallOrInvoke(LLValue *Callee, const char *Name) {
- return funcGen().callOrInvoke(Callee, {}, Name);
+llvm::Instruction *IRState::CreateCallOrInvoke(LLFunction *Callee,
+ const char *Name) {
+ return CreateCallOrInvoke(Callee, {}, Name);
}
-LLCallSite IRState::CreateCallOrInvoke(LLValue *Callee,
- llvm::ArrayRef<LLValue *> Args,
- const char *Name, bool isNothrow) {
- return funcGen().callOrInvoke(Callee, Args, Name, isNothrow);
+llvm::Instruction *IRState::CreateCallOrInvoke(LLFunction *Callee,
+ llvm::ArrayRef<LLValue *> Args,
+ const char *Name,
+ bool isNothrow) {
+ return funcGen().callOrInvoke(Callee, Callee->getFunctionType(), Args, Name,
+ isNothrow);
}
-LLCallSite IRState::CreateCallOrInvoke(LLValue *Callee, LLValue *Arg1,
- const char *Name) {
- return funcGen().callOrInvoke(Callee, {Arg1}, Name);
+llvm::Instruction *IRState::CreateCallOrInvoke(LLFunction *Callee,
+ LLValue *Arg1,
+ const char *Name) {
+ return CreateCallOrInvoke(Callee, llvm::ArrayRef<LLValue *>(Arg1), Name);
}
-LLCallSite IRState::CreateCallOrInvoke(LLValue *Callee, LLValue *Arg1,
- LLValue *Arg2, const char *Name) {
+llvm::Instruction *IRState::CreateCallOrInvoke(LLFunction *Callee,
+ LLValue *Arg1, LLValue *Arg2,
+ const char *Name) {
return CreateCallOrInvoke(Callee, {Arg1, Arg2}, Name);
}
-LLCallSite IRState::CreateCallOrInvoke(LLValue *Callee, LLValue *Arg1,
- LLValue *Arg2, LLValue *Arg3,
- const char *Name) {
+llvm::Instruction *IRState::CreateCallOrInvoke(LLFunction *Callee,
+ LLValue *Arg1, LLValue *Arg2,
+ LLValue *Arg3,
+ const char *Name) {
return CreateCallOrInvoke(Callee, {Arg1, Arg2, Arg3}, Name);
}
-LLCallSite IRState::CreateCallOrInvoke(LLValue *Callee, LLValue *Arg1,
- LLValue *Arg2, LLValue *Arg3,
- LLValue *Arg4, const char *Name) {
+llvm::Instruction *IRState::CreateCallOrInvoke(LLFunction *Callee,
+ LLValue *Arg1, LLValue *Arg2,
+ LLValue *Arg3, LLValue *Arg4,
+ const char *Name) {
return CreateCallOrInvoke(Callee, {Arg1, Arg2, Arg3, Arg4}, Name);
}
diff --git a/gen/irstate.h b/gen/irstate.h
index 340bfb57..83a33310 100644
--- a/gen/irstate.h
+++ b/gen/irstate.h
@@ -22,7 +22,6 @@
#include "ir/irvar.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/StringMap.h"
-#include "llvm/IR/CallSite.h"
#include "llvm/ProfileData/InstrProfReader.h"
#include <deque>
#include <memory>
@@ -188,21 +187,22 @@ public:
llvm::BasicBlock *insertBB(const llvm::Twine &name);
// create a call or invoke, depending on the landing pad info
- llvm::CallSite CreateCallOrInvoke(LLValue *Callee, const char *Name = "");
- llvm::CallSite CreateCallOrInvoke(LLValue *Callee,
- llvm::ArrayRef<LLValue *> Args,
- const char *Name = "",
- bool isNothrow = false);
- llvm::CallSite CreateCallOrInvoke(LLValue *Callee, LLValue *Arg1,
- const char *Name = "");
- llvm::CallSite CreateCallOrInvoke(LLValue *Callee, LLValue *Arg1,
- LLValue *Arg2, const char *Name = "");
- llvm::CallSite CreateCallOrInvoke(LLValue *Callee, LLValue *Arg1,
- LLValue *Arg2, LLValue *Arg3,
- const char *Name = "");
- llvm::CallSite CreateCallOrInvoke(LLValue *Callee, LLValue *Arg1,
- LLValue *Arg2, LLValue *Arg3, LLValue *Arg4,
- const char *Name = "");
+ llvm::Instruction *CreateCallOrInvoke(LLFunction *Callee,
+ const char *Name = "");
+ llvm::Instruction *CreateCallOrInvoke(LLFunction *Callee,
+ llvm::ArrayRef<LLValue *> Args,
+ const char *Name = "",
+ bool isNothrow = false);
+ llvm::Instruction *CreateCallOrInvoke(LLFunction *Callee, LLValue *Arg1,
+ const char *Name = "");
+ llvm::Instruction *CreateCallOrInvoke(LLFunction *Callee, LLValue *Arg1,
+ LLValue *Arg2, const char *Name = "");
+ llvm::Instruction *CreateCallOrInvoke(LLFunction *Callee, LLValue *Arg1,
+ LLValue *Arg2, LLValue *Arg3,
+ const char *Name = "");
+ llvm::Instruction *CreateCallOrInvoke(LLFunction *Callee, LLValue *Arg1,
+ LLValue *Arg2, LLValue *Arg3,
+ LLValue *Arg4, const char *Name = "");
// this holds the array being indexed or sliced so $ will work
// might be a better way but it works. problem is I only get a
diff --git a/gen/llvm.h b/gen/llvm.h
index ade01294..a4870c80 100644
--- a/gen/llvm.h
+++ b/gen/llvm.h
@@ -30,7 +30,6 @@
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/DebugInfo.h"
-#include "llvm/IR/CallSite.h"
#if LDC_LLVM_VER >= 1000
// LLVM >= 10 requires C++14 and no longer has llvm::make_unique. Add it back
@@ -46,8 +45,14 @@ using llvm::APInt;
using llvm::IRBuilder;
#if LDC_LLVM_VER >= 1000
+#if LDC_LLVM_VER >= 1100
+#define LLAlign llvm::Align
+#else
+#define LLAlign llvm::MaybeAlign
+#endif
#define LLMaybeAlign llvm::MaybeAlign
#else
+#define LLAlign
#define LLMaybeAlign
#endif
@@ -75,6 +80,4 @@ using llvm::IRBuilder;
#define LLConstantInt llvm::ConstantInt
#define LLConstantFP llvm::ConstantFP
-#define LLCallSite llvm::CallSite
-
#define LLSmallVector llvm::SmallVector
diff --git a/gen/llvmhelpers.cpp b/gen/llvmhelpers.cpp
index 8096e93f..6024d827 100644
--- a/gen/llvmhelpers.cpp
+++ b/gen/llvmhelpers.cpp
@@ -85,7 +85,7 @@ LLValue *DtoNew(Loc &loc, Type *newtype) {
LLConstant *ti = DtoTypeInfoOf(newtype);
assert(isaPointer(ti));
// call runtime allocator
- LLValue *mem = gIR->CreateCallOrInvoke(fn, ti, ".gc_mem").getInstruction();
+ LLValue *mem = gIR->CreateCallOrInvoke(fn, ti, ".gc_mem");
// cast
return DtoBitCast(mem, DtoPtrToType(newtype), ".gc_mem");
}
@@ -95,7 +95,7 @@ LLValue *DtoNewStruct(Loc &loc, TypeStruct *newtype) {
loc, gIR->module,
newtype->isZeroInit(newtype->sym->loc) ? "_d_newitemT" : "_d_newitemiT");
LLConstant *ti = DtoTypeInfoOf(newtype);
- LLValue *mem = gIR->CreateCallOrInvoke(fn, ti, ".gc_struct").getInstruction();
+ LLValue *mem = gIR->CreateCallOrInvoke(fn, ti, ".gc_struct");
return DtoBitCast(mem, DtoPtrToType(newtype), ".gc_struct");
}
@@ -180,7 +180,9 @@ llvm::AllocaInst *DtoArrayAlloca(Type *type, unsigned arraysize,
auto ai = new llvm::AllocaInst(
lltype, gIR->module.getDataLayout().getAllocaAddrSpace(),
DtoConstUint(arraysize), name, gIR->topallocapoint());
- ai->setAlignment(LLMaybeAlign(DtoAlignment(type)));
+ if (auto alignment = DtoAlignment(type)) {
+ ai->setAlignment(LLAlign(alignment));
+ }
return ai;
}
@@ -190,7 +192,7 @@ llvm::AllocaInst *DtoRawAlloca(LLType *lltype, size_t alignment,
lltype, gIR->module.getDataLayout().getAllocaAddrSpace(), name,
gIR->topallocapoint());
if (alignment) {
- ai->setAlignment(LLMaybeAlign(alignment));
+ ai->setAlignment(LLAlign(alignment));
}
return ai;
}
@@ -201,7 +203,7 @@ LLValue *DtoGcMalloc(Loc &loc, LLType *lltype, const char *name) {
// parameters
LLValue *size = DtoConstSize_t(getTypeAllocSize(lltype));
// call runtime allocator
- LLValue *mem = gIR->CreateCallOrInvoke(fn, size, name).getInstruction();
+ LLValue *mem = gIR->CreateCallOrInvoke(fn, size, name);
// cast
return DtoBitCast(mem, getPtrToType(lltype), name);
}
@@ -1231,7 +1233,12 @@ LLConstant *DtoConstExpInit(Loc &loc, Type *targetType, Expression *exp) {
assert(tv->basetype->ty == Tsarray);
dinteger_t elemCount =
static_cast<TypeSArray *>(tv->basetype)->dim->toInteger();
- return llvm::ConstantVector::getSplat(elemCount, val);
+#if LDC_LLVM_VER >= 1100
+ const auto elementCount = llvm::ElementCount(elemCount, false);
+#else
+ const auto elementCount = elemCount;
+#endif
+ return llvm::ConstantVector::getSplat(elementCount, val);
}
if (llType->isIntegerTy() && targetLLType->isIntegerTy()) {
@@ -1310,9 +1317,14 @@ static char *DtoOverloadedIntrinsicName(TemplateInstance *ti,
if (dtype->isPPC_FP128Ty()) { // special case
replacement = "ppcf128";
} else if (dtype->isVectorTy()) {
+#if LDC_LLVM_VER >= 1100
+ auto vectorType = llvm::cast<llvm::FixedVectorType>(dtype);
+#else
+ auto vectorType = llvm::cast<llvm::VectorType>(dtype);
+#endif
llvm::raw_string_ostream stream(replacement);
- stream << 'v' << dtype->getVectorNumElements() << prefix
- << gDataLayout->getTypeSizeInBits(dtype->getVectorElementType());
+ stream << 'v' << vectorType->getNumElements() << prefix
+ << gDataLayout->getTypeSizeInBits(vectorType->getElementType());
stream.flush();
} else {
replacement = prefix + std::to_string(gDataLayout->getTypeSizeInBits(dtype));
diff --git a/gen/passes/GarbageCollect2Stack.cpp b/gen/passes/GarbageCollect2Stack.cpp
index a726f844..9463b190 100644
--- a/gen/passes/GarbageCollect2Stack.cpp
+++ b/gen/passes/GarbageCollect2Stack.cpp
@@ -28,7 +28,6 @@
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/ADT/StringMap.h"
-#include "llvm/IR/CallSite.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/Dominators.h"
@@ -115,14 +114,14 @@ public:
// Analyze the current call, filling in some fields. Returns true if
// this is an allocation we can stack-allocate.
- virtual bool analyze(CallSite CS, const Analysis &A) = 0;
+ virtual bool analyze(CallBase *CB, const Analysis &A) = 0;
// Returns the alloca to replace this call.
// It will always be inserted before the call.
- virtual Value *promote(CallSite CS, IRBuilder<> &B, const Analysis &A) {
+ virtual Value *promote(CallBase *CB, IRBuilder<> &B, const Analysis &A) {
NumGcToStack++;
- auto &BB = CS.getCaller()->getEntryBlock();
+ auto &BB = CB->getCaller()->getEntryBlock();
Instruction *Begin = &(*BB.begin());
// FIXME: set alignment on alloca?
@@ -167,8 +166,8 @@ public:
TypeInfoFI(ReturnType::Type returnType, unsigned tiArgNr)
: FunctionInfo(returnType), TypeInfoArgNr(tiArgNr) {}
- bool analyze(CallSite CS, const Analysis &A) override {
- Value *TypeInfo = CS.getArgument(TypeInfoArgNr);
+ bool analyze(CallBase *CB, const Analysis &A) override {
+ Value *TypeInfo = CB->getArgOperand(TypeInfoArgNr);
Ty = A.getTypeFor(TypeInfo);
if (!Ty) {
return false;
@@ -188,12 +187,12 @@ public:
: TypeInfoFI(returnType, tiArgNr), ArrSizeArgNr(arrSizeArgNr),
Initialized(initialized) {}
- bool analyze(CallSite CS, const Analysis &A) override {
- if (!TypeInfoFI::analyze(CS, A)) {
+ bool analyze(CallBase *CB, const Analysis &A) override {
+ if (!TypeInfoFI::analyze(CB, A)) {
return false;
}
- arrSize = CS.getArgument(ArrSizeArgNr);
+ arrSize = CB->getArgOperand(ArrSizeArgNr);
// Extract the element type from the array type.
const StructType *ArrTy = dyn_cast<StructType>(Ty);
@@ -217,15 +216,16 @@ public:
return true;
}
- Value *promote(CallSite CS, IRBuilder<> &B, const Analysis &A) override {
- IRBuilder<> Builder = B;
+ Value *promote(CallBase *CB, IRBuilder<> &B, const Analysis &A) override {
+ IRBuilder<> Builder(B.GetInsertBlock(), B.GetInsertPoint());
+
// If the allocation is of constant size it's best to put it in the
// entry block, so do so if we're not already there.
// For dynamically-sized allocations it's best to avoid the overhead
// of allocating them if possible, so leave those where they are.
// While we're at it, update statistics too.
if (isa<Constant>(arrSize)) {
- BasicBlock &Entry = CS.getCaller()->getEntryBlock();
+ BasicBlock &Entry = CB->getCaller()->getEntryBlock();
if (Builder.GetInsertBlock() != &Entry) {
Builder.SetInsertPoint(&Entry, Entry.begin());
}
@@ -250,7 +250,7 @@ public:
}
if (ReturnType == ReturnType::Array) {
- Value *arrStruct = llvm::UndefValue::get(CS.getType());
+ Value *arrStruct = llvm::UndefValue::get(CB->getType());
arrStruct = Builder.CreateInsertValue(arrStruct, arrSize, 0);
Value *memPtr =
Builder.CreateBitCast(alloca, PointerType::getUnqual(B.getInt8Ty()));
@@ -265,11 +265,11 @@ public:
// FunctionInfo for _d_allocclass
class AllocClassFI : public FunctionInfo {
public:
- bool analyze(CallSite CS, const Analysis &A) override {
- if (CS.arg_size() != 1) {
+ bool analyze(CallBase *CB, const Analysis &A) override {
+ if (CB->arg_size() != 1) {
return false;
}
- Value *arg = CS.getArgument(0)->stripPointerCasts();
+ Value *arg = CB->getArgOperand(0)->stripPointerCasts();
GlobalVariable *ClassInfo = dyn_cast<GlobalVariable>(arg);
if (!ClassInfo) {
return false;
@@ -322,12 +322,12 @@ class UntypedMemoryFI : public FunctionInfo {
Value *SizeArg;
public:
- bool analyze(CallSite CS, const Analysis &A) override {
- if (CS.arg_size() < SizeArgNr + 1) {
+ bool analyze(CallBase *CB, const Analysis &A) override {
+ if (CB->arg_size() < SizeArgNr + 1) {
return false;
}
- SizeArg = CS.getArgument(SizeArgNr);
+ SizeArg = CB->getArgOperand(SizeArgNr);
// If the user explicitly disabled the limits, don't even check
// whether the allocated size fits in 32 bits. This could cause
@@ -341,19 +341,20 @@ public:
}
// Should be i8.
- Ty = CS.getType()->getContainedType(0);
+ Ty = CB->getType()->getContainedType(0);
return true;
}
- Value *promote(CallSite CS, IRBuilder<> &B, const Analysis &A) override {
- IRBuilder<> Builder = B;
+ Value *promote(CallBase *CB, IRBuilder<> &B, const Analysis &A) override {
+ IRBuilder<> Builder(B.GetInsertBlock(), B.GetInsertPoint());
+
// If the allocation is of constant size it's best to put it in the
// entry block, so do so if we're not already there.
// For dynamically-sized allocations it's best to avoid the overhead
// of allocating them if possible, so leave those where they are.
// While we're at it, update statistics too.
if (isa<Constant>(SizeArg)) {
- BasicBlock &Entry = CS.getCaller()->getEntryBlock();
+ BasicBlock &Entry = CB->getCaller()->getEntryBlock();
if (Builder.GetInsertBlock() != &Entry) {
Builder.SetInsertPoint(&Entry, Entry.begin());
}
@@ -367,7 +368,7 @@ public:
AllocaInst *alloca =
Builder.CreateAlloca(Ty, count, ".nongc_mem"); // FIXME: align?
- return Builder.CreateBitCast(alloca, CS.getType());
+ return Builder.CreateBitCast(alloca, CB->getType());
}
explicit UntypedMemoryFI(unsigned sizeArgNr)
@@ -430,26 +431,24 @@ GarbageCollect2Stack::GarbageCollect2Stack()
KnownFunctions["_d_allocmemory"] = &AllocMemory;
}
-static void RemoveCall(CallSite CS, const Analysis &A) {
+static void RemoveCall(CallBase *CB, const Analysis &A) {
// For an invoke instruction, we insert a branch to the normal target BB
// immediately before it. Ideally, we would find a way to not invalidate
// the dominator tree here.
- if (CS.isInvoke()) {
- InvokeInst *Invoke = cast<InvokeInst>(CS.getInstruction());
-
+ if (auto Invoke = dyn_cast<InvokeInst>(CB)) {
BranchInst::Create(Invoke->getNormalDest(), Invoke);
- Invoke->getUnwindDest()->removePredecessor(CS->getParent());
+ Invoke->getUnwindDest()->removePredecessor(CB->getParent());
}
// Remove the runtime call.
if (A.CGNode) {
#if LDC_LLVM_VER >= 900
- A.CGNode->removeCallEdgeFor(*cast<CallBase>(CS.getInstruction()));
+ A.CGNode->removeCallEdgeFor(*CB);
#else
- A.CGNode->removeCallEdgeFor(CS);
+ A.CGNode->removeCallEdgeFor(CB);
#endif
}
- CS->eraseFromParent();
+ CB->eraseFromParent();
}
static bool
@@ -482,14 +481,13 @@ bool GarbageCollect2Stack::runOnFunction(Function &F) {
auto originalI = I;
// Ignore non-calls.
- Instruction *Inst = &(*(I++));
- CallSite CS(Inst);
- if (!CS.getInstruction()) {
+ auto CB = dyn_cast<CallBase>(&(*(I++)));
+ if (!CB) {
continue;
}
// Ignore indirect calls and calls to non-external functions.
- Function *Callee = CS.getCalledFunction();
+ Function *Callee = CB->getCalledFunction();
if (Callee == nullptr || !Callee->isDeclaration() ||
!Callee->hasExternalLinkage()) {
continue;
@@ -503,16 +501,16 @@ bool GarbageCollect2Stack::runOnFunction(Function &F) {
FunctionInfo *info = OMI->getValue();
- if (Inst->use_empty()) {
+ if (CB->use_empty()) {
Changed = true;
NumDeleted++;
- RemoveCall(CS, A);
+ RemoveCall(CB, A);
continue;
}
- LLVM_DEBUG(errs() << "GarbageCollect2Stack inspecting: " << *Inst);
+ LLVM_DEBUG(errs() << "GarbageCollect2Stack inspecting: " << *CB);
- if (!info->analyze(CS, A)) {
+ if (!info->analyze(CB, A)) {
continue;
}
@@ -522,7 +520,7 @@ bool GarbageCollect2Stack::runOnFunction(Function &F) {
continue;
}
} else {
- if (!isSafeToStackAllocate(originalI, Inst, DT, RemoveTailCallInsts)) {
+ if (!isSafeToStackAllocate(originalI, CB, DT, RemoveTailCallInsts)) {
continue;
}
}
@@ -537,18 +535,18 @@ bool GarbageCollect2Stack::runOnFunction(Function &F) {
}
IRBuilder<> Builder(&BB, originalI);
- Value *newVal = info->promote(CS, Builder, A);
+ Value *newVal = info->promote(CB, Builder, A);
LLVM_DEBUG(errs() << "Promoted to: " << *newVal);
// Make sure the type is the same as it was before, and replace all
// uses of the runtime call with the alloca.
- if (newVal->getType() != Inst->getType()) {
- newVal = Builder.CreateBitCast(newVal, Inst->getType());
+ if (newVal->getType() != CB->getType()) {
+ newVal = Builder.CreateBitCast(newVal, CB->getType());
}
- Inst->replaceAllUsesWith(newVal);
+ CB->replaceAllUsesWith(newVal);
- RemoveCall(CS, A);
+ RemoveCall(CB, A);
}
}
@@ -818,11 +816,11 @@ bool isSafeToStackAllocate(BasicBlock::iterator Alloc, Value *V,
switch (I->getOpcode()) {
case Instruction::Call:
case Instruction::Invoke: {
- CallSite CS(I);
+ auto CB = llvm::cast<CallBase>(I);
// Not captured if the callee is readonly, doesn't return a copy through
// its return value and doesn't unwind (a readonly function can leak bits
// by throwing an exception or not depending on the input value).
- if (CS.onlyReadsMemory() && CS.doesNotThrow() &&
+ if (CB->onlyReadsMemory() && CB->doesNotThrow() &&
I->getType() == llvm::Type::getVoidTy(I->getContext())) {
break;
}
@@ -834,18 +832,17 @@ bool isSafeToStackAllocate(BasicBlock::iterator Alloc, Value *V,
// that loading a value from a pointer does not cause the pointer to be
// captured, even though the loaded value might be the pointer itself
// (think of self-referential objects).
- CallSite::arg_iterator B = CS.arg_begin(), E = CS.arg_end();
- for (CallSite::arg_iterator A = B; A != E; ++A) {
+ auto B = CB->arg_begin(), E = CB->arg_end();
+ for (auto A = B; A != E; ++A) {
if (A->get() == V) {
- if (!CS.paramHasAttr(A - B, llvm::Attribute::AttrKind::NoCapture)) {
+ if (!CB->paramHasAttr(A - B, llvm::Attribute::AttrKind::NoCapture)) {
// The parameter is not marked 'nocapture' - captured.
return false;
}
- if (CS.isCall()) {
- CallInst *CI = cast<CallInst>(I);
- if (CI->isTailCall()) {
- RemoveTailCallInsts.push_back(CI);
+ if (auto call = dyn_cast<CallInst>(CB)) {
+ if (call->isTailCall()) {
+ RemoveTailCallInsts.push_back(call);
}
}
}
diff --git a/gen/tocall.cpp b/gen/tocall.cpp
index fb497446..b217ffd3 100644
--- a/gen/tocall.cpp
+++ b/gen/tocall.cpp
@@ -405,7 +405,9 @@ bool DtoLowerMagicIntrinsic(IRState *p, FuncDeclaration *fndecl, CallExp *e,
llvm::StoreInst *ret = p->ir->CreateStore(val, ptr);
ret->setAtomic(llvm::AtomicOrdering(atomicOrdering));
- ret->setAlignment(LLMaybeAlign(getTypeAllocSize(val->getType())));
+ if (auto alignment = getTypeAllocSize(val->getType())) {
+ ret->setAlignment(LLAlign(alignment));
+ }
return true;
}
@@ -435,7 +437,9 @@ bool DtoLowerMagicIntrinsic(IRState *p, FuncDeclaration *fndecl, CallExp *e,
}
llvm::LoadInst *load = p->ir->CreateLoad(ptr);
- load->setAlignment(LLMaybeAlign(getTypeAllocSize(load->getType())));
+ if (auto alignment = getTypeAllocSize(load->getType())) {
+ load->setAlignment(LLAlign(alignment));
+ }
load->setAtomic(llvm::AtomicOrdering(atomicOrdering));
llvm::Value *val = load;
if (val->getType() != pointeeType) {
@@ -868,21 +872,21 @@ DValue *DtoCallFunction(Loc &loc, Type *resulttype, DValue *fnval,
}
// call the function
- LLCallSite call = gIR->CreateCallOrInvoke(callable, args, "", tf->isnothrow);
+ llvm::CallBase *call = gIR->funcGen().callOrInvoke(callable, callableTy, args,
+ "", tf->isnothrow);
// PGO: Insert instrumentation or attach profile metadata at indirect call
// sites.
- if (!call.getCalledFunction()) {
+ if (!call->getCalledFunction()) {
auto &PGO = gIR->funcGen().pgo;
- PGO.emitIndirectCallPGO(call.getInstruction(), callable);
+ PGO.emitIndirectCallPGO(call, callable);
}
// get return value
const int sretArgIndex =
(irFty.arg_sret && irFty.arg_this && gABI->passThisBeforeSret(tf) ? 1
: 0);
- LLValue *retllval =
- (irFty.arg_sret ? args[sretArgIndex] : call.getInstruction());
+ LLValue *retllval = (irFty.arg_sret ? args[sretArgIndex] : call);
bool retValIsLVal =
(tf->isref && returnTy != Tvoid) || (irFty.arg_sret != nullptr);
@@ -1002,16 +1006,16 @@ DValue *DtoCallFunction(Loc &loc, Type *resulttype, DValue *fnval,
gIR->context(),
static_cast<llvm::Intrinsic::ID>(llfunc->getIntrinsicID()));
} else {
- call.setCallingConv(callconv);
+ call->setCallingConv(callconv);
}
} else {
- call.setCallingConv(callconv);
+ call->setCallingConv(callconv);
}
// merge in function attributes set in callOrInvoke
attrlist = attrlist.addAttributes(
gIR->context(), LLAttributeList::FunctionIndex,
- llvm::AttrBuilder(call.getAttributes(), LLAttributeList::FunctionIndex));
- call.setAttributes(attrlist);
+ llvm::AttrBuilder(call->getAttributes(), LLAttributeList::FunctionIndex));
+ call->setAttributes(attrlist);
// Special case for struct constructor calls: For temporaries, using the
// this pointer value returned from the constructor instead of the alloca
diff --git a/gen/toconstelem.cpp b/gen/toconstelem.cpp
index 9a9ee994..282a6276 100644
--- a/gen/toconstelem.cpp
+++ b/gen/toconstelem.cpp
@@ -664,8 +664,13 @@ public:
// cast.
// FIXME: Check DMD source to understand why two different ASTs are
// constructed.
+#if LDC_LLVM_VER >= 1100
+ const auto elementCount = llvm::ElementCount(elemCount, false);
+#else
+ const auto elementCount = elemCount;
+#endif
result = llvm::ConstantVector::getSplat(
- elemCount, toConstElem(e->e1->optimize(WANTvalue)));
+ elementCount, toConstElem(e->e1->optimize(WANTvalue)));
}
}
diff --git a/gen/toir.cpp b/gen/toir.cpp
index bbbd3783..63aa1154 100644
--- a/gen/toir.cpp
+++ b/gen/toir.cpp
@@ -2428,8 +2428,7 @@ public:
LLValue *valuesArray = DtoAggrPaint(slice, funcTy->getParamType(2));
LLValue *aa = gIR->CreateCallOrInvoke(func, aaTypeInfo, keysArray,
- valuesArray, "aa")
- .getInstruction();
+ valuesArray, "aa");
if (basetype->ty != Taarray) {
LLValue *tmp = DtoAlloca(e->type, "aaliteral");
DtoStore(aa, DtoGEP(tmp, 0u, 0));
@@ -2623,7 +2622,13 @@ public:
DValue *val = toElem(e->e1);
LLValue *llElement = getCastElement(val);
if (auto llConstant = isaConstant(llElement)) {
- auto vectorConstant = llvm::ConstantVector::getSplat(N, llConstant);
+#if LDC_LLVM_VER >= 1100
+ const auto elementCount = llvm::ElementCount(N, false);
+#else
+ const auto elementCount = N;
+#endif
+ auto vectorConstant =
+ llvm::ConstantVector::getSplat(elementCount, llConstant);
DtoStore(vectorConstant, dstMem);
} else {
for (unsigned int i = 0; i < N; ++i) {
diff --git a/gen/tollvm.cpp b/gen/tollvm.cpp
index 0d14027f..73f1bce8 100644
--- a/gen/tollvm.cpp
+++ b/gen/tollvm.cpp
@@ -452,7 +452,9 @@ LLValue *DtoLoad(LLValue *src, const char *name) {
// the type.
LLValue *DtoAlignedLoad(LLValue *src, const char *name) {
llvm::LoadInst *ld = gIR->ir->CreateLoad(src, name);
- ld->setAlignment(LLMaybeAlign(getABITypeAlign(ld->getType())));
+ if (auto alignment = getABITypeAlign(ld->getType())) {
+ ld->setAlignment(LLAlign(alignment));
+ }
return ld;
}
@@ -489,7 +491,9 @@ void DtoAlignedStore(LLValue *src, LLValue *dst) {
assert(src->getType() != llvm::Type::getInt1Ty(gIR->context()) &&
"Should store bools as i8 instead of i1.");
llvm::StoreInst *st = gIR->ir->CreateStore(src, dst);
- st->setAlignment(LLMaybeAlign(getABITypeAlign(src->getType())));
+ if (auto alignment = getABITypeAlign(src->getType())) {
+ st->setAlignment(LLAlign(alignment));
+ }
}
////////////////////////////////////////////////////////////////////////////////
diff --git a/gen/trycatchfinally.cpp b/gen/trycatchfinally.cpp
index 9a42de2e..b18da5b7 100644
--- a/gen/trycatchfinally.cpp
+++ b/gen/trycatchfinally.cpp
@@ -365,9 +365,9 @@ llvm::BasicBlock *CleanupScope::run(IRState &irs, llvm::BasicBlock *sourceBlock,
// We need a branch selector if we are here...
if (!branchSelector) {
// ... and have not created one yet, so do so now.
+ llvm::Type *branchSelectorType = llvm::Type::getInt32Ty(irs.context());
branchSelector = new llvm::AllocaInst(
- llvm::Type::getInt32Ty(irs.context()),
- irs.module.getDataLayout().getAllocaAddrSpace(),
+ branchSelectorType, irs.module.getDataLayout().getAllocaAddrSpace(),
llvm::Twine("branchsel.") + beginBlock()->getName(),
irs.topallocapoint());
@@ -380,7 +380,11 @@ llvm::BasicBlock *CleanupScope::run(IRState &irs, llvm::BasicBlock *sourceBlock,
// And convert the BranchInst to the existing branch target to a
// SelectInst so we can append the other cases to it.
endBlock()->getTerminator()->eraseFromParent();
- llvm::Value *sel = new llvm::LoadInst(branchSelector, "", endBlock());
+ llvm::Value *sel = new llvm::LoadInst(
+#if LDC_LLVM_VER >= 1100
+ branchSelectorType,
+#endif
+ branchSelector, "", endBlock());
llvm::SwitchInst::Create(
sel, exitTargets[0].branchTarget,
1, // Expected number of branches, only for pre-allocating.
diff --git a/gen/uda.cpp b/gen/uda.cpp
index 80fa194e..a8395463 100644
--- a/gen/uda.cpp
+++ b/gen/uda.cpp
@@ -16,6 +16,7 @@
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringSwitch.h"
+#if LDC_LLVM_VER < 1100
namespace llvm {
// Auto-generate:
// Attribute::AttrKind getAttrKindFromName(StringRef AttrName) { ... }
@@ -26,6 +27,7 @@ namespace llvm {
#include "llvm/IR/Attributes.inc"
#endif
}
+#endif
namespace {
@@ -205,7 +207,11 @@ void applyAttrLLVMAttr(StructLiteralExp *sle, llvm::AttrBuilder &attrs) {
llvm::StringRef key = getStringElem(sle, 0);
llvm::StringRef value = getStringElem(sle, 1);
if (value.empty()) {
+#if LDC_LLVM_VER >= 1100
+ const auto kind = llvm::Attribute::getAttrKindFromName(key);
+#else
const auto kind = llvm::getAttrKindFromName(key);
+#endif
if (kind != llvm::Attribute::None) {
attrs.addAttribute(kind);
} else {
diff --git a/ir/irtype.cpp b/ir/irtype.cpp
index f2aaf72f..46c94fb2 100644
--- a/ir/irtype.cpp
+++ b/ir/irtype.cpp
@@ -220,5 +220,10 @@ llvm::Type *IrTypeVector::vector2llvm(Type *dt) {
TypeSArray *tsa = static_cast<TypeSArray *>(tv->basetype);
uint64_t dim = static_cast<uint64_t>(tsa->dim->toUInteger());
LLType *elemType = DtoMemType(tsa->next);
- return llvm::VectorType::get(elemType, dim);
+ return llvm::VectorType::get(elemType, dim
+#if LDC_LLVM_VER >= 1100
+ ,
+ /*Scalable=*/false
+#endif
+ );
}
diff --git a/tests/lit.site.cfg.in b/tests/lit.site.cfg.in
index 9f051e1a..cb51035a 100644
--- a/tests/lit.site.cfg.in
+++ b/tests/lit.site.cfg.in
@@ -84,7 +84,7 @@ config.available_features.add("llvm%d" % config.llvm_version)
plusoneable_llvmversion = config.llvm_version // 10 + config.llvm_version%10
for version in range(60, plusoneable_llvmversion+1):
config.available_features.add("atleast_llvm%d0%d" % (version//10, version%10))
-for version in range(plusoneable_llvmversion, 101):
+for version in range(plusoneable_llvmversion, 111):
config.available_features.add("atmost_llvm%d0%d" % (version//10, version%10))
# Define OS as available feature (Windows, Darwin, Linux)
diff --git a/tools/ldc-profdata/llvm-profdata-11.0.cpp b/tools/ldc-profdata/llvm-profdata-11.0.cpp
new file mode 100644
index 00000000..843f072a
--- /dev/null
+++ b/tools/ldc-profdata/llvm-profdata-11.0.cpp
@@ -0,0 +1,1344 @@
+//===- llvm-profdata.cpp - LLVM profile data tool -------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// llvm-profdata merges .profdata files.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/SmallSet.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/IR/LLVMContext.h"
+#include "llvm/ProfileData/InstrProfReader.h"
+#include "llvm/ProfileData/InstrProfWriter.h"
+#include "llvm/ProfileData/ProfileCommon.h"
+#include "llvm/ProfileData/SampleProfReader.h"
+#include "llvm/ProfileData/SampleProfWriter.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/FormattedStream.h"
+#include "llvm/Support/InitLLVM.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/ThreadPool.h"
+#include "llvm/Support/Threading.h"
+#include "llvm/Support/WithColor.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+
+using namespace llvm;
+
+enum ProfileFormat {
+ PF_None = 0,
+ PF_Text,
+ PF_Compact_Binary,
+ PF_Ext_Binary,
+ PF_GCC,
+ PF_Binary
+};
+
+static void warn(Twine Message, std::string Whence = "",
+ std::string Hint = "") {
+ WithColor::warning();
+ if (!Whence.empty())
+ errs() << Whence << ": ";
+ errs() << Message << "\n";
+ if (!Hint.empty())
+ WithColor::note() << Hint << "\n";
+}
+
+static void exitWithError(Twine Message, std::string Whence = "",
+ std::string Hint = "") {
+ WithColor::error();
+ if (!Whence.empty())
+ errs() << Whence << ": ";
+ errs() << Message << "\n";
+ if (!Hint.empty())
+ WithColor::note() << Hint << "\n";
+ ::exit(1);
+}
+
+static void exitWithError(Error E, StringRef Whence = "") {
+ if (E.isA<InstrProfError>()) {
+ handleAllErrors(std::move(E), [&](const InstrProfError &IPE) {
+ instrprof_error instrError = IPE.get();
+ StringRef Hint = "";
+ if (instrError == instrprof_error::unrecognized_format) {
+ // Hint for common error of forgetting --sample for sample profiles.
+ Hint = "Perhaps you forgot to use the --sample option?";
+ }
+ exitWithError(IPE.message(), std::string(Whence), std::string(Hint));
+ });
+ }
+
+ exitWithError(toString(std::move(E)), std::string(Whence));
+}
+
+static void exitWithErrorCode(std::error_code EC, StringRef Whence = "") {
+ exitWithError(EC.message(), std::string(Whence));
+}
+
+namespace {
+enum ProfileKinds { instr, sample };
+enum FailureMode { failIfAnyAreInvalid, failIfAllAreInvalid };
+}
+
+static void warnOrExitGivenError(FailureMode FailMode, std::error_code EC,
+ StringRef Whence = "") {
+ if (FailMode == failIfAnyAreInvalid)
+ exitWithErrorCode(EC, Whence);
+ else
+ warn(EC.message(), std::string(Whence));
+}
+
+static void handleMergeWriterError(Error E, StringRef WhenceFile = "",
+ StringRef WhenceFunction = "",
+ bool ShowHint = true) {
+ if (!WhenceFile.empty())
+ errs() << WhenceFile << ": ";
+ if (!WhenceFunction.empty())
+ errs() << WhenceFunction << ": ";
+
+ auto IPE = instrprof_error::success;
+ E = handleErrors(std::move(E),
+ [&IPE](std::unique_ptr<InstrProfError> E) -> Error {
+ IPE = E->get();
+ return Error(std::move(E));
+ });
+ errs() << toString(std::move(E)) << "\n";
+
+ if (ShowHint) {
+ StringRef Hint = "";
+ if (IPE != instrprof_error::success) {
+ switch (IPE) {
+ case instrprof_error::hash_mismatch:
+ case instrprof_error::count_mismatch:
+ case instrprof_error::value_site_count_mismatch:
+ Hint = "Make sure that all profile data to be merged is generated "
+ "from the same binary.";
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (!Hint.empty())
+ errs() << Hint << "\n";
+ }
+}
+
+namespace {
+/// A remapper from original symbol names to new symbol names based on a file
+/// containing a list of mappings from old name to new name.
+class SymbolRemapper {
+ std::unique_ptr<MemoryBuffer> File;
+ DenseMap<StringRef, StringRef> RemappingTable;
+
+public:
+ /// Build a SymbolRemapper from a file containing a list of old/new symbols.
+ static std::unique_ptr<SymbolRemapper> create(StringRef InputFile) {
+ auto BufOrError = MemoryBuffer::getFileOrSTDIN(InputFile);
+ if (!BufOrError)
+ exitWithErrorCode(BufOrError.getError(), InputFile);
+
+ auto Remapper = std::make_unique<SymbolRemapper>();
+ Remapper->File = std::move(BufOrError.get());
+
+ for (line_iterator LineIt(*Remapper->File, /*SkipBlanks=*/true, '#');
+ !LineIt.is_at_eof(); ++LineIt) {
+ std::pair<StringRef, StringRef> Parts = LineIt->split(' ');
+ if (Parts.first.empty() || Parts.second.empty() ||
+ Parts.second.count(' ')) {
+ exitWithError("unexpected line in remapping file",
+ (InputFile + ":" + Twine(LineIt.line_number())).str(),
+ "expected 'old_symbol new_symbol'");
+ }
+ Remapper->RemappingTable.insert(Parts);
+ }
+ return Remapper;
+ }
+
+ /// Attempt to map the given old symbol into a new symbol.
+ ///
+ /// \return The new symbol, or \p Name if no such symbol was found.
+ StringRef operator()(StringRef Name) {
+ StringRef New = RemappingTable.lookup(Name);
+ return New.empty() ? Name : New;
+ }
+};
+}
+
+struct WeightedFile {
+ std::string Filename;
+ uint64_t Weight;
+};
+typedef SmallVector<WeightedFile, 5> WeightedFileVector;
+
+/// Keep track of merged data and reported errors.
+struct WriterContext {
+ std::mutex Lock;
+ InstrProfWriter Writer;
+ std::vector<std::pair<Error, std::string>> Errors;
+ std::mutex &ErrLock;
+ SmallSet<instrprof_error, 4> &WriterErrorCodes;
+
+ WriterContext(bool IsSparse, std::mutex &ErrLock,
+ SmallSet<instrprof_error, 4> &WriterErrorCodes)
+ : Lock(), Writer(IsSparse), Errors(), ErrLock(ErrLock),
+ WriterErrorCodes(WriterErrorCodes) {}
+};
+
+/// Computer the overlap b/w profile BaseFilename and TestFileName,
+/// and store the program level result to Overlap.
+static void overlapInput(const std::string &BaseFilename,
+ const std::string &TestFilename, WriterContext *WC,
+ OverlapStats &Overlap,
+ const OverlapFuncFilters &FuncFilter,
+ raw_fd_ostream &OS, bool IsCS) {
+ auto ReaderOrErr = InstrProfReader::create(TestFilename);
+ if (Error E = ReaderOrErr.takeError()) {
+ // Skip the empty profiles by returning sliently.
+ instrprof_error IPE = InstrProfError::take(std::move(E));
+ if (IPE != instrprof_error::empty_raw_profile)
+ WC->Errors.emplace_back(make_error<InstrProfError>(IPE), TestFilename);
+ return;
+ }
+
+ auto Reader = std::move(ReaderOrErr.get());
+ for (auto &I : *Reader) {
+ OverlapStats FuncOverlap(OverlapStats::FunctionLevel);
+ FuncOverlap.setFuncInfo(I.Name, I.Hash);
+
+ WC->Writer.overlapRecord(std::move(I), Overlap, FuncOverlap, FuncFilter);
+ FuncOverlap.dump(OS);
+ }
+}
+
+/// Load an input into a writer context.
+static void loadInput(const WeightedFile &Input, SymbolRemapper *Remapper,
+ WriterContext *WC) {
+ std::unique_lock<std::mutex> CtxGuard{WC->Lock};
+
+ // Copy the filename, because llvm::ThreadPool copied the input "const
+ // WeightedFile &" by value, making a reference to the filename within it
+ // invalid outside of this packaged task.
+ std::string Filename = Input.Filename;
+
+ auto ReaderOrErr = InstrProfReader::create(Input.Filename);
+ if (Error E = ReaderOrErr.takeError()) {
+ // Skip the empty profiles by returning sliently.
+ instrprof_error IPE = InstrProfError::take(std::move(E));
+ if (IPE != instrprof_error::empty_raw_profile)
+ WC->Errors.emplace_back(make_error<InstrProfError>(IPE), Filename);
+ return;
+ }
+
+ auto Reader = std::move(ReaderOrErr.get());
+ bool IsIRProfile = Reader->isIRLevelProfile();
+ bool HasCSIRProfile = Reader->hasCSIRLevelProfile();
+ if (WC->Writer.setIsIRLevelProfile(IsIRProfile, HasCSIRProfile)) {
+ WC->Errors.emplace_back(
+ make_error<StringError>(
+ "Merge IR generated profile with Clang generated profile.",
+ std::error_code()),
+ Filename);
+ return;
+ }
+
+ for (auto &I : *Reader) {
+ if (Remapper)
+ I.Name = (*Remapper)(I.Name);
+ const StringRef FuncName = I.Name;
+ bool Reported = false;
+ WC->Writer.addRecord(std::move(I), Input.Weight, [&](Error E) {
+ if (Reported) {
+ consumeError(std::move(E));
+ return;
+ }
+ Reported = true;
+ // Only show hint the first time an error occurs.
+ instrprof_error IPE = InstrProfError::take(std::move(E));
+ std::unique_lock<std::mutex> ErrGuard{WC->ErrLock};
+ bool firstTime = WC->WriterErrorCodes.insert(IPE).second;
+ handleMergeWriterError(make_error<InstrProfError>(IPE), Input.Filename,
+ FuncName, firstTime);
+ });
+ }
+ if (Reader->hasError())
+ if (Error E = Reader->getError())
+ WC->Errors.emplace_back(std::move(E), Filename);
+}
+
+/// Merge the \p Src writer context into \p Dst.
+static void mergeWriterContexts(WriterContext *Dst, WriterContext *Src) {
+ for (auto &ErrorPair : Src->Errors)
+ Dst->Errors.push_back(std::move(ErrorPair));
+ Src->Errors.clear();
+
+ Dst->Writer.mergeRecordsFromWriter(std::move(Src->Writer), [&](Error E) {
+ instrprof_error IPE = InstrProfError::take(std::move(E));
+ std::unique_lock<std::mutex> ErrGuard{Dst->ErrLock};
+ bool firstTime = Dst->WriterErrorCodes.insert(IPE).second;
+ if (firstTime)
+ warn(toString(make_error<InstrProfError>(IPE)));
+ });
+}
+
+static void writeInstrProfile(StringRef OutputFilename,
+ ProfileFormat OutputFormat,
+ InstrProfWriter &Writer) {
+ std::error_code EC;
+ raw_fd_ostream Output(OutputFilename.data(), EC, sys::fs::OF_None);
+ if (EC)
+ exitWithErrorCode(EC, OutputFilename);
+
+ if (OutputFormat == PF_Text) {
+ if (Error E = Writer.writeText(Output))
+ exitWithError(std::move(E));
+ } else {
+ Writer.write(Output);
+ }
+}
+
+static void mergeInstrProfile(const WeightedFileVector &Inputs,
+ SymbolRemapper *Remapper,
+ StringRef OutputFilename,
+ ProfileFormat OutputFormat, bool OutputSparse,
+ unsigned NumThreads, FailureMode FailMode) {
+ if (OutputFilename.compare("-") == 0)
+ exitWithError("Cannot write indexed profdata format to stdout.");
+
+ if (OutputFormat != PF_Binary && OutputFormat != PF_Compact_Binary &&
+ OutputFormat != PF_Ext_Binary && OutputFormat != PF_Text)
+ exitWithError("Unknown format is specified.");
+
+ std::mutex ErrorLock;
+ SmallSet<instrprof_error, 4> WriterErrorCodes;
+
+ // If NumThreads is not specified, auto-detect a good default.
+ if (NumThreads == 0)
+ NumThreads = std::min(hardware_concurrency().compute_thread_count(),
+ unsigned((Inputs.size() + 1) / 2));
+ // FIXME: There's a bug here, where setting NumThreads = Inputs.size() fails
+ // the merge_empty_profile.test because the InstrProfWriter.ProfileKind isn't
+ // merged, thus the emitted file ends up with a PF_Unknown kind.
+
+ // Initialize the writer contexts.
+ SmallVector<std::unique_ptr<WriterContext>, 4> Contexts;
+ for (unsigned I = 0; I < NumThreads; ++I)
+ Contexts.emplace_back(std::make_unique<WriterContext>(
+ OutputSparse, ErrorLock, WriterErrorCodes));
+
+ if (NumThreads == 1) {
+ for (const auto &Input : Inputs)
+ loadInput(Input, Remapper, Contexts[0].get());
+ } else {
+ ThreadPool Pool(hardware_concurrency(NumThreads));
+
+ // Load the inputs in parallel (N/NumThreads serial steps).
+ unsigned Ctx = 0;
+ for (const auto &Input : Inputs) {
+ Pool.async(loadInput, Input, Remapper, Contexts[Ctx].get());
+ Ctx = (Ctx + 1) % NumThreads;
+ }
+ Pool.wait();
+
+ // Merge the writer contexts together (~ lg(NumThreads) serial steps).
+ unsigned Mid = Contexts.size() / 2;
+ unsigned End = Contexts.size();
+ assert(Mid > 0 && "Expected more than one context");
+ do {
+ for (unsigned I = 0; I < Mid; ++I)
+ Pool.async(mergeWriterContexts, Contexts[I].get(),
+ Contexts[I + Mid].get());
+ Pool.wait();
+ if (End & 1) {
+ Pool.async(mergeWriterContexts, Contexts[0].get(),
+ Contexts[End - 1].get());
+ Pool.wait();
+ }
+ End = Mid;
+ Mid /= 2;
+ } while (Mid > 0);
+ }
+
+ // Handle deferred errors encountered during merging. If the number of errors
+ // is equal to the number of inputs the merge failed.
+ unsigned NumErrors = 0;
+ for (std::unique_ptr<WriterContext> &WC : Contexts) {
+ for (auto &ErrorPair : WC->Errors) {
+ ++NumErrors;
+ warn(toString(std::move(ErrorPair.first)), ErrorPair.second);
+ }
+ }
+ if (NumErrors == Inputs.size() ||
+ (NumErrors > 0 && FailMode == failIfAnyAreInvalid))
+ exitWithError("No profiles could be merged.");
+
+ writeInstrProfile(OutputFilename, OutputFormat, Contexts[0]->Writer);
+}
+
+/// Make a copy of the given function samples with all symbol names remapped
+/// by the provided symbol remapper.
+static sampleprof::FunctionSamples
+remapSamples(const sampleprof::FunctionSamples &Samples,
+ SymbolRemapper &Remapper, sampleprof_error &Error) {
+ sampleprof::FunctionSamples Result;
+ Result.setName(Remapper(Samples.getName()));
+ Result.addTotalSamples(Samples.getTotalSamples());
+ Result.addHeadSamples(Samples.getHeadSamples());
+ for (const auto &BodySample : Samples.getBodySamples()) {
+ Result.addBodySamples(BodySample.first.LineOffset,
+ BodySample.first.Discriminator,
+ BodySample.second.getSamples());
+ for (const auto &Target : BodySample.second.getCallTargets()) {
+ Result.addCalledTargetSamples(BodySample.first.LineOffset,
+ BodySample.first.Discriminator,
+ Remapper(Target.first()), Target.second);
+ }
+ }
+ for (const auto &CallsiteSamples : Samples.getCallsiteSamples()) {
+ sampleprof::FunctionSamplesMap &Target =
+ Result.functionSamplesAt(CallsiteSamples.first);
+ for (const auto &Callsite : CallsiteSamples.second) {
+ sampleprof::FunctionSamples Remapped =
+ remapSamples(Callsite.second, Remapper, Error);
+ MergeResult(Error,
+ Target[std::string(Remapped.getName())].merge(Remapped));
+ }
+ }
+ return Result;
+}
+
+static sampleprof::SampleProfileFormat FormatMap[] = {
+ sampleprof::SPF_None,
+ sampleprof::SPF_Text,
+ sampleprof::SPF_Compact_Binary,
+ sampleprof::SPF_Ext_Binary,
+ sampleprof::SPF_GCC,
+ sampleprof::SPF_Binary};
+
+static std::unique_ptr<MemoryBuffer>
+getInputFileBuf(const StringRef &InputFile) {
+ if (InputFile == "")
+ return {};
+
+ auto BufOrError = MemoryBuffer::getFileOrSTDIN(InputFile);
+ if (!BufOrError)
+ exitWithErrorCode(BufOrError.getError(), InputFile);
+
+ return std::move(*BufOrError);
+}
+
+static void populateProfileSymbolList(MemoryBuffer *Buffer,
+ sampleprof::ProfileSymbolList &PSL) {
+ if (!Buffer)
+ return;
+
+ SmallVector<StringRef, 32> SymbolVec;
+ StringRef Data = Buffer->getBuffer();
+ Data.split(SymbolVec, '\n', /*MaxSplit=*/-1, /*KeepEmpty=*/false);
+
+ for (StringRef symbol : SymbolVec)
+ PSL.add(symbol);
+}
+
+static void handleExtBinaryWriter(sampleprof::SampleProfileWriter &Writer,
+ ProfileFormat OutputFormat,
+ MemoryBuffer *Buffer,
+ sampleprof::ProfileSymbolList &WriterList,
+ bool CompressAllSections, bool UseMD5,
+ bool GenPartialProfile) {
+ populateProfileSymbolList(Buffer, WriterList);
+ if (WriterList.size() > 0 && OutputFormat != PF_Ext_Binary)
+ warn("Profile Symbol list is not empty but the output format is not "
+ "ExtBinary format. The list will be lost in the output. ");
+
+ Writer.setProfileSymbolList(&WriterList);
+
+ if (CompressAllSections) {
+ if (OutputFormat != PF_Ext_Binary)
+ warn("-compress-all-section is ignored. Specify -extbinary to enable it");
+ else
+ Writer.setToCompressAllSections();
+ }
+ if (UseMD5) {
+ if (OutputFormat != PF_Ext_Binary)
+ warn("-use-md5 is ignored. Specify -extbinary to enable it");
+ else
+ Writer.setUseMD5();
+ }
+ if (GenPartialProfile) {
+ if (OutputFormat != PF_Ext_Binary)
+ warn("-gen-partial-profile is ignored. Specify -extbinary to enable it");
+ else
+ Writer.setPartialProfile();
+ }
+}
+
+static void
+mergeSampleProfile(const WeightedFileVector &Inputs, SymbolRemapper *Remapper,
+ StringRef OutputFilename, ProfileFormat OutputFormat,
+ StringRef ProfileSymbolListFile, bool CompressAllSections,
+ bool UseMD5, bool GenPartialProfile, FailureMode FailMode) {
+ using namespace sampleprof;
+ StringMap<FunctionSamples> ProfileMap;
+ SmallVector<std::unique_ptr<sampleprof::SampleProfileReader>, 5> Readers;
+ LLVMContext Context;
+ sampleprof::ProfileSymbolList WriterList;
+ for (const auto &Input : Inputs) {
+ auto ReaderOrErr = SampleProfileReader::create(Input.Filename, Context);
+ if (std::error_code EC = ReaderOrErr.getError()) {
+ warnOrExitGivenError(FailMode, EC, Input.Filename);
+ continue;
+ }
+
+ // We need to keep the readers around until after all the files are
+ // read so that we do not lose the function names stored in each
+ // reader's memory. The function names are needed to write out the
+ // merged profile map.
+ Readers.push_back(std::move(ReaderOrErr.get()));
+ const auto Reader = Readers.back().get();
+ if (std::error_code EC = Reader->read()) {
+ warnOrExitGivenError(FailMode, EC, Input.Filename);
+ Readers.pop_back();
+ continue;
+ }
+
+ StringMap<FunctionSamples> &Profiles = Reader->getProfiles();
+ for (StringMap<FunctionSamples>::iterator I = Profiles.begin(),
+ E = Profiles.end();
+ I != E; ++I) {
+ sampleprof_error Result = sampleprof_error::success;
+ FunctionSamples Remapped =
+ Remapper ? remapSamples(I->second, *Remapper, Result)
+ : FunctionSamples();
+ FunctionSamples &Samples = Remapper ? Remapped : I->second;
+ StringRef FName = Samples.getName();
+ MergeResult(Result, ProfileMap[FName].merge(Samples, Input.Weight));
+ if (Result != sampleprof_error::success) {
+ std::error_code EC = make_error_code(Result);
+ handleMergeWriterError(errorCodeToError(EC), Input.Filename, FName);
+ }
+ }
+
+ std::unique_ptr<sampleprof::ProfileSymbolList> ReaderList =
+ Reader->getProfileSymbolList();
+ if (ReaderList)
+ WriterList.merge(*ReaderList);
+ }
+ auto WriterOrErr =
+ SampleProfileWriter::create(OutputFilename, FormatMap[OutputFormat]);
+ if (std::error_code EC = WriterOrErr.getError())
+ exitWithErrorCode(EC, OutputFilename);
+
+ auto Writer = std::move(WriterOrErr.get());
+ // WriterList will have StringRef refering to string in Buffer.
+ // Make sure Buffer lives as long as WriterList.
+ auto Buffer = getInputFileBuf(ProfileSymbolListFile);
+ handleExtBinaryWriter(*Writer, OutputFormat, Buffer.get(), WriterList,
+ CompressAllSections, UseMD5, GenPartialProfile);
+ Writer->write(ProfileMap);
+}
+
+static WeightedFile parseWeightedFile(const StringRef &WeightedFilename) {
+ StringRef WeightStr, FileName;
+ std::tie(WeightStr, FileName) = WeightedFilename.split(',');
+
+ uint64_t Weight;
+ if (WeightStr.getAsInteger(10, Weight) || Weight < 1)
+ exitWithError("Input weight must be a positive integer.");
+
+ return {std::string(FileName), Weight};
+}
+
+static void addWeightedInput(WeightedFileVector &WNI, const WeightedFile &WF) {
+ StringRef Filename = WF.Filename;
+ uint64_t Weight = WF.Weight;
+
+ // If it's STDIN just pass it on.
+ if (Filename == "-") {
+ WNI.push_back({std::string(Filename), Weight});
+ return;
+ }
+
+ llvm::sys::fs::file_status Status;
+ llvm::sys::fs::status(Filename, Status);
+ if (!llvm::sys::fs::exists(Status))
+ exitWithErrorCode(make_error_code(errc::no_such_file_or_directory),
+ Filename);
+ // If it's a source file, collect it.
+ if (llvm::sys::fs::is_regular_file(Status)) {
+ WNI.push_back({std::string(Filename), Weight});
+ return;
+ }
+
+ if (llvm::sys::fs::is_directory(Status)) {
+ std::error_code EC;
+ for (llvm::sys::fs::recursive_directory_iterator F(Filename, EC), E;
+ F != E && !EC; F.increment(EC)) {
+ if (llvm::sys::fs::is_regular_file(F->path())) {
+ addWeightedInput(WNI, {F->path(), Weight});
+ }
+ }
+ if (EC)
+ exitWithErrorCode(EC, Filename);
+ }
+}
+
+static void parseInputFilenamesFile(MemoryBuffer *Buffer,
+ WeightedFileVector &WFV) {
+ if (!Buffer)
+ return;
+
+ SmallVector<StringRef, 8> Entries;
+ StringRef Data = Buffer->getBuffer();
+ Data.split(Entries, '\n', /*MaxSplit=*/-1, /*KeepEmpty=*/false);
+ for (const StringRef &FileWeightEntry : Entries) {
+ StringRef SanitizedEntry = FileWeightEntry.trim(" \t\v\f\r");
+ // Skip comments.
+ if (SanitizedEntry.startswith("#"))
+ continue;
+ // If there's no comma, it's an unweighted profile.
+ else if (SanitizedEntry.find(',') == StringRef::npos)
+ addWeightedInput(WFV, {std::string(SanitizedEntry), 1});
+ else
+ addWeightedInput(WFV, parseWeightedFile(SanitizedEntry));
+ }
+}
+
+static int merge_main(int argc, const char *argv[]) {
+ cl::list<std::string> InputFilenames(cl::Positional,
+ cl::desc("<filename...>"));
+ cl::list<std::string> WeightedInputFilenames("weighted-input",
+ cl::desc("<weight>,<filename>"));
+ cl::opt<std::string> InputFilenamesFile(
+ "input-files", cl::init(""),
+ cl::desc("Path to file containing newline-separated "
+ "[<weight>,]<filename> entries"));
+ cl::alias InputFilenamesFileA("f", cl::desc("Alias for --input-files"),
+ cl::aliasopt(InputFilenamesFile));
+ cl::opt<bool> DumpInputFileList(
+ "dump-input-file-list", cl::init(false), cl::Hidden,
+ cl::desc("Dump the list of input files and their weights, then exit"));
+ cl::opt<std::string> RemappingFile("remapping-file", cl::value_desc("file"),
+ cl::desc("Symbol remapping file"));
+ cl::alias RemappingFileA("r", cl::desc("Alias for --remapping-file"),
+ cl::aliasopt(RemappingFile));
+ cl::opt<std::string> OutputFilename("output", cl::value_desc("output"),
+ cl::init("-"), cl::Required,
+ cl::desc("Output file"));
+ cl::alias OutputFilenameA("o", cl::desc("Alias for --output"),
+ cl::aliasopt(OutputFilename));
+ cl::opt<ProfileKinds> ProfileKind(
+ cl::desc("Profile kind:"), cl::init(instr),
+ cl::values(clEnumVal(instr, "Instrumentation profile (default)"),
+ clEnumVal(sample, "Sample profile")));
+ cl::opt<ProfileFormat> OutputFormat(
+ cl::desc("Format of output profile"), cl::init(PF_Binary),
+ cl::values(
+ clEnumValN(PF_Binary, "binary", "Binary encoding (default)"),
+ clEnumValN(PF_Compact_Binary, "compbinary",
+ "Compact binary encoding"),
+ clEnumValN(PF_Ext_Binary, "extbinary", "Extensible binary encoding"),
+ clEnumValN(PF_Text, "text", "Text encoding"),
+ clEnumValN(PF_GCC, "gcc",
+ "GCC encoding (only meaningful for -sample)")));
+ cl::opt<FailureMode> FailureMode(
+ "failure-mode", cl::init(failIfAnyAreInvalid), cl::desc("Failure mode:"),
+ cl::values(clEnumValN(failIfAnyAreInvalid, "any",
+ "Fail if any profile is invalid."),
+ clEnumValN(failIfAllAreInvalid, "all",
+ "Fail only if all profiles are invalid.")));
+ cl::opt<bool> OutputSparse("sparse", cl::init(false),
+ cl::desc("Generate a sparse profile (only meaningful for -instr)"));
+ cl::opt<unsigned> NumThreads(
+ "num-threads", cl::init(0),
+ cl::desc("Number of merge threads to use (default: autodetect)"));
+ cl::alias NumThreadsA("j", cl::desc("Alias for --num-threads"),
+ cl::aliasopt(NumThreads));
+ cl::opt<std::string> ProfileSymbolListFile(
+ "prof-sym-list", cl::init(""),
+ cl::desc("Path to file containing the list of function symbols "
+ "used to populate profile symbol list"));
+ cl::opt<bool> CompressAllSections(
+ "compress-all-sections", cl::init(false), cl::Hidden,
+ cl::desc("Compress all sections when writing the profile (only "
+ "meaningful for -extbinary)"));
+ cl::opt<bool> UseMD5(
+ "use-md5", cl::init(false), cl::Hidden,
+ cl::desc("Choose to use MD5 to represent string in name table (only "
+ "meaningful for -extbinary)"));
+ cl::opt<bool> GenPartialProfile(
+ "gen-partial-profile", cl::init(false), cl::Hidden,
+ cl::desc("Generate a partial profile (only meaningful for -extbinary)"));
+
+ cl::ParseCommandLineOptions(argc, argv, "LLVM profile data merger\n");
+
+ WeightedFileVector WeightedInputs;
+ for (StringRef Filename : InputFilenames)
+ addWeightedInput(WeightedInputs, {std::string(Filename), 1});
+ for (StringRef WeightedFilename : WeightedInputFilenames)
+ addWeightedInput(WeightedInputs, parseWeightedFile(WeightedFilename));
+
+ // Make sure that the file buffer stays alive for the duration of the
+ // weighted input vector's lifetime.
+ auto Buffer = getInputFileBuf(InputFilenamesFile);
+ parseInputFilenamesFile(Buffer.get(), WeightedInputs);
+
+ if (WeightedInputs.empty())
+ exitWithError("No input files specified. See " +
+ sys::path::filename(argv[0]) + " -help");
+
+ if (DumpInputFileList) {
+ for (auto &WF : WeightedInputs)
+ outs() << WF.Weight << "," << WF.Filename << "\n";
+ return 0;
+ }
+
+ std::unique_ptr<SymbolRemapper> Remapper;
+ if (!RemappingFile.empty())
+ Remapper = SymbolRemapper::create(RemappingFile);
+
+ if (ProfileKind == instr)
+ mergeInstrProfile(WeightedInputs, Remapper.get(), OutputFilename,
+ OutputFormat, OutputSparse, NumThreads, FailureMode);
+ else
+ mergeSampleProfile(WeightedInputs, Remapper.get(), OutputFilename,
+ OutputFormat, ProfileSymbolListFile, CompressAllSections,
+ UseMD5, GenPartialProfile, FailureMode);
+
+ return 0;
+}
+
+/// Computer the overlap b/w profile BaseFilename and profile TestFilename.
+static void overlapInstrProfile(const std::string &BaseFilename,
+ const std::string &TestFilename,
+ const OverlapFuncFilters &FuncFilter,
+ raw_fd_ostream &OS, bool IsCS) {
+ std::mutex ErrorLock;
+ SmallSet<instrprof_error, 4> WriterErrorCodes;
+ WriterContext Context(false, ErrorLock, WriterErrorCodes);
+ WeightedFile WeightedInput{BaseFilename, 1};
+ OverlapStats Overlap;
+ Error E = Overlap.accumulateCounts(BaseFilename, TestFilename, IsCS);
+ if (E)
+ exitWithError(std::move(E), "Error in getting profile count sums");
+ if (Overlap.Base.CountSum < 1.0f) {
+ OS << "Sum of edge counts for profile " << BaseFilename << " is 0.\n";
+ exit(0);
+ }
+ if (Overlap.Test.CountSum < 1.0f) {
+ OS << "Sum of edge counts for profile " << TestFilename << " is 0.\n";
+ exit(0);
+ }
+ loadInput(WeightedInput, nullptr, &Context);
+ overlapInput(BaseFilename, TestFilename, &Context, Overlap, FuncFilter, OS,
+ IsCS);
+ Overlap.dump(OS);
+}
+
+static int overlap_main(int argc, const char *argv[]) {
+ cl::opt<std::string> BaseFilename(cl::Positional, cl::Required,
+ cl::desc("<base profile file>"));
+ cl::opt<std::string> TestFilename(cl::Positional, cl::Required,
+ cl::desc("<test profile file>"));
+ cl::opt<std::string> Output("output", cl::value_desc("output"), cl::init("-"),
+ cl::desc("Output file"));
+ cl::alias OutputA("o", cl::desc("Alias for --output"), cl::aliasopt(Output));
+ cl::opt<bool> IsCS("cs", cl::init(false),
+ cl::desc("For context sensitive counts"));
+ cl::opt<unsigned long long> ValueCutoff(
+ "value-cutoff", cl::init(-1),
+ cl::desc(
+ "Function level overlap information for every function in test "
+ "profile with max count value greater then the parameter value"));
+ cl::opt<std::string> FuncNameFilter(
+ "function",
+ cl::desc("Function level overlap information for matching functions"));
+ cl::ParseCommandLineOptions(argc, argv, "LLVM profile data overlap tool\n");
+
+ std::error_code EC;
+ raw_fd_ostream OS(Output.data(), EC, sys::fs::OF_Text);
+ if (EC)
+ exitWithErrorCode(EC, Output);
+
+ overlapInstrProfile(BaseFilename, TestFilename,
+ OverlapFuncFilters{ValueCutoff, FuncNameFilter}, OS,
+ IsCS);
+
+ return 0;
+}
+
+typedef struct ValueSitesStats {
+ ValueSitesStats()
+ : TotalNumValueSites(0), TotalNumValueSitesWithValueProfile(0),
+ TotalNumValues(0) {}
+ uint64_t TotalNumValueSites;
+ uint64_t TotalNumValueSitesWithValueProfile;
+ uint64_t TotalNumValues;
+ std::vector<unsigned> ValueSitesHistogram;
+} ValueSitesStats;
+
+static void traverseAllValueSites(const InstrProfRecord &Func, uint32_t VK,
+ ValueSitesStats &Stats, raw_fd_ostream &OS,
+ InstrProfSymtab *Symtab) {
+ uint32_t NS = Func.getNumValueSites(VK);
+ Stats.TotalNumValueSites += NS;
+ for (size_t I = 0; I < NS; ++I) {
+ uint32_t NV = Func.getNumValueDataForSite(VK, I);
+ std::unique_ptr<InstrProfValueData[]> VD = Func.getValueForSite(VK, I);
+ Stats.TotalNumValues += NV;
+ if (NV) {
+ Stats.TotalNumValueSitesWithValueProfile++;
+ if (NV > Stats.ValueSitesHistogram.size())
+ Stats.ValueSitesHistogram.resize(NV, 0);
+ Stats.ValueSitesHistogram[NV - 1]++;
+ }
+
+ uint64_t SiteSum = 0;
+ for (uint32_t V = 0; V < NV; V++)
+ SiteSum += VD[V].Count;
+ if (SiteSum == 0)
+ SiteSum = 1;
+
+ for (uint32_t V = 0; V < NV; V++) {
+ OS << "\t[ " << format("%2u", I) << ", ";
+ if (Symtab == nullptr)
+ OS << format("%4" PRIu64, VD[V].Value);
+ else
+ OS << Symtab->getFuncName(VD[V].Value);
+ OS << ", " << format("%10" PRId64, VD[V].Count) << " ] ("
+ << format("%.2f%%", (VD[V].Count * 100.0 / SiteSum)) << ")\n";
+ }
+ }
+}
+
+static void showValueSitesStats(raw_fd_ostream &OS, uint32_t VK,
+ ValueSitesStats &Stats) {
+ OS << " Total number of sites: " << Stats.TotalNumValueSites << "\n";
+ OS << " Total number of sites with values: "
+ << Stats.TotalNumValueSitesWithValueProfile << "\n";
+ OS << " Total number of profiled values: " << Stats.TotalNumValues << "\n";
+
+ OS << " Value sites histogram:\n\tNumTargets, SiteCount\n";
+ for (unsigned I = 0; I < Stats.ValueSitesHistogram.size(); I++) {
+ if (Stats.ValueSitesHistogram[I] > 0)
+ OS << "\t" << I + 1 << ", " << Stats.ValueSitesHistogram[I] << "\n";
+ }
+}
+
+static int showInstrProfile(const std::string &Filename, bool ShowCounts,
+ uint32_t TopN, bool ShowIndirectCallTargets,
+ bool ShowMemOPSizes, bool ShowDetailedSummary,
+ std::vector<uint32_t> DetailedSummaryCutoffs,
+ bool ShowAllFunctions, bool ShowCS,
+ uint64_t ValueCutoff, bool OnlyListBelow,
+ const std::string &ShowFunction, bool TextFormat,
+ raw_fd_ostream &OS) {
+ auto ReaderOrErr = InstrProfReader::create(Filename);
+ std::vector<uint32_t> Cutoffs = std::move(DetailedSummaryCutoffs);
+ if (ShowDetailedSummary && Cutoffs.empty()) {
+ Cutoffs = {800000, 900000, 950000, 990000, 999000, 999900, 999990};
+ }
+ InstrProfSummaryBuilder Builder(std::move(Cutoffs));
+ if (Error E = ReaderOrErr.takeError())
+ exitWithError(std::move(E), Filename);
+
+ auto Reader = std::move(ReaderOrErr.get());
+ bool IsIRInstr = Reader->isIRLevelProfile();
+ size_t ShownFunctions = 0;
+ size_t BelowCutoffFunctions = 0;
+ int NumVPKind = IPVK_Last - IPVK_First + 1;
+ std::vector<ValueSitesStats> VPStats(NumVPKind);
+
+ auto MinCmp = [](const std::pair<std::string, uint64_t> &v1,
+ const std::pair<std::string, uint64_t> &v2) {
+ return v1.second > v2.second;
+ };
+
+ std::priority_queue<std::pair<std::string, uint64_t>,
+ std::vector<std::pair<std::string, uint64_t>>,
+ decltype(MinCmp)>
+ HottestFuncs(MinCmp);
+
+ if (!TextFormat && OnlyListBelow) {
+ OS << "The list of functions with the maximum counter less than "
+ << ValueCutoff << ":\n";
+ }
+
+ // Add marker so that IR-level instrumentation round-trips properly.
+ if (TextFormat && IsIRInstr)
+ OS << ":ir\n";
+
+ for (const auto &Func : *Reader) {
+ if (Reader->isIRLevelProfile()) {
+ bool FuncIsCS = NamedInstrProfRecord::hasCSFlagInHash(Func.Hash);
+ if (FuncIsCS != ShowCS)
+ continue;
+ }
+ bool Show =
+ ShowAllFunctions || (!ShowFunction.empty() &&
+ Func.Name.find(ShowFunction) != Func.Name.npos);
+
+ bool doTextFormatDump = (Show && TextFormat);
+
+ if (doTextFormatDump) {
+ InstrProfSymtab &Symtab = Reader->getSymtab();
+ InstrProfWriter::writeRecordInText(Func.Name, Func.Hash, Func, Symtab,
+ OS);
+ continue;
+ }
+
+ assert(Func.Counts.size() > 0 && "function missing entry counter");
+ Builder.addRecord(Func);
+
+ uint64_t FuncMax = 0;
+ uint64_t FuncSum = 0;
+ for (size_t I = 0, E = Func.Counts.size(); I < E; ++I) {
+ FuncMax = std::max(FuncMax, Func.Counts[I]);
+ FuncSum += Func.Counts[I];
+ }
+
+ if (FuncMax < ValueCutoff) {
+ ++BelowCutoffFunctions;
+ if (OnlyListBelow) {
+ OS << " " << Func.Name << ": (Max = " << FuncMax
+ << " Sum = " << FuncSum << ")\n";
+ }
+ continue;
+ } else if (OnlyListBelow)
+ continue;
+
+ if (TopN) {
+ if (HottestFuncs.size() == TopN) {
+ if (HottestFuncs.top().second < FuncMax) {
+ HottestFuncs.pop();
+ HottestFuncs.emplace(std::make_pair(std::string(Func.Name), FuncMax));
+ }
+ } else
+ HottestFuncs.emplace(std::make_pair(std::string(Func.Name), FuncMax));
+ }
+
+ if (Show) {
+ if (!ShownFunctions)
+ OS << "Counters:\n";
+
+ ++ShownFunctions;
+
+ OS << " " << Func.Name << ":\n"
+ << " Hash: " << format("0x%016" PRIx64, Func.Hash) << "\n"
+ << " Counters: " << Func.Counts.size() << "\n";
+ if (!IsIRInstr)
+ OS << " Function count: " << Func.Counts[0] << "\n";
+
+ if (ShowIndirectCallTargets)
+ OS << " Indirect Call Site Count: "
+ << Func.getNumValueSites(IPVK_IndirectCallTarget) << "\n";
+
+ uint32_t NumMemOPCalls = Func.getNumValueSites(IPVK_MemOPSize);
+ if (ShowMemOPSizes && NumMemOPCalls > 0)
+ OS << " Number of Memory Intrinsics Calls: " << NumMemOPCalls
+ << "\n";
+
+ if (ShowCounts) {
+ OS << " Block counts: [";
+ size_t Start = (IsIRInstr ? 0 : 1);
+ for (size_t I = Start, E = Func.Counts.size(); I < E; ++I) {
+ OS << (I == Start ? "" : ", ") << Func.Counts[I];
+ }
+ OS << "]\n";
+ }
+
+ if (ShowIndirectCallTargets) {
+ OS << " Indirect Target Results:\n";
+ traverseAllValueSites(Func, IPVK_IndirectCallTarget,
+ VPStats[IPVK_IndirectCallTarget], OS,
+ &(Reader->getSymtab()));
+ }
+
+ if (ShowMemOPSizes && NumMemOPCalls > 0) {
+ OS << " Memory Intrinsic Size Results:\n";
+ traverseAllValueSites(Func, IPVK_MemOPSize, VPStats[IPVK_MemOPSize], OS,
+ nullptr);
+ }
+ }
+ }
+ if (Reader->hasError())
+ exitWithError(Reader->getError(), Filename);
+
+ if (TextFormat)
+ return 0;
+ std::unique_ptr<ProfileSummary> PS(Builder.getSummary());
+ OS << "Instrumentation level: "
+ << (Reader->isIRLevelProfile() ? "IR" : "Front-end") << "\n";
+ if (ShowAllFunctions || !ShowFunction.empty())
+ OS << "Functions shown: " << ShownFunctions << "\n";
+ OS << "Total functions: " << PS->getNumFunctions() << "\n";
+ if (ValueCutoff > 0) {
+ OS << "Number of functions with maximum count (< " << ValueCutoff
+ << "): " << BelowCutoffFunctions << "\n";
+ OS << "Number of functions with maximum count (>= " << ValueCutoff
+ << "): " << PS->getNumFunctions() - BelowCutoffFunctions << "\n";
+ }
+ OS << "Maximum function count: " << PS->getMaxFunctionCount() << "\n";
+ OS << "Maximum internal block count: " << PS->getMaxInternalCount() << "\n";
+
+ if (TopN) {
+ std::vector<std::pair<std::string, uint64_t>> SortedHottestFuncs;
+ while (!HottestFuncs.empty()) {
+ SortedHottestFuncs.emplace_back(HottestFuncs.top());
+ HottestFuncs.pop();
+ }
+ OS << "Top " << TopN
+ << " functions with the largest internal block counts: \n";
+ for (auto &hotfunc : llvm::reverse(SortedHottestFuncs))
+ OS << " " << hotfunc.first << ", max count = " << hotfunc.second << "\n";
+ }
+
+ if (ShownFunctions && ShowIndirectCallTargets) {
+ OS << "Statistics for indirect call sites profile:\n";
+ showValueSitesStats(OS, IPVK_IndirectCallTarget,
+ VPStats[IPVK_IndirectCallTarget]);
+ }
+
+ if (ShownFunctions && ShowMemOPSizes) {
+ OS << "Statistics for memory intrinsic calls sizes profile:\n";
+ showValueSitesStats(OS, IPVK_MemOPSize, VPStats[IPVK_MemOPSize]);
+ }
+
+ if (ShowDetailedSummary) {
+ OS << "Total number of blocks: " << PS->getNumCounts() << "\n";
+ OS << "Total count: " << PS->getTotalCount() << "\n";
+ PS->printDetailedSummary(OS);
+ }
+ return 0;
+}
+
+static void showSectionInfo(sampleprof::SampleProfileReader *Reader,
+ raw_fd_ostream &OS) {
+ if (!Reader->dumpSectionInfo(OS)) {
+ WithColor::warning() << "-show-sec-info-only is only supported for "
+ << "sample profile in extbinary format and is "
+ << "ignored for other formats.\n";
+ return;
+ }
+}
+
+namespace {
+struct HotFuncInfo {
+ StringRef FuncName;
+ uint64_t TotalCount;
+ double TotalCountPercent;
+ uint64_t MaxCount;
+ uint64_t EntryCount;
+
+ HotFuncInfo()
+ : FuncName(), TotalCount(0), TotalCountPercent(0.0f), MaxCount(0),
+ EntryCount(0) {}
+
+ HotFuncInfo(StringRef FN, uint64_t TS, double TSP, uint64_t MS, uint64_t ES)
+ : FuncName(FN), TotalCount(TS), TotalCountPercent(TSP), MaxCount(MS),
+ EntryCount(ES) {}
+};
+} // namespace
+
+// Print out detailed information about hot functions in PrintValues vector.
+// Users specify titles and offset of every columns through ColumnTitle and
+// ColumnOffset. The size of ColumnTitle and ColumnOffset need to be the same
+// and at least 4. Besides, users can optionally give a HotFuncMetric string to
+// print out or let it be an empty string.
+static void dumpHotFunctionList(const std::vector<std::string> &ColumnTitle,
+ const std::vector<int> &ColumnOffset,
+ const std::vector<HotFuncInfo> &PrintValues,
+ uint64_t HotFuncCount, uint64_t TotalFuncCount,
+ uint64_t HotProfCount, uint64_t TotalProfCount,
+ const std::string &HotFuncMetric,
+ raw_fd_ostream &OS) {
+ assert(ColumnOffset.size() == ColumnTitle.size());
+ assert(ColumnTitle.size() >= 4);
+ assert(TotalFuncCount > 0);
+ double TotalProfPercent = 0;
+ if (TotalProfCount > 0)
+ TotalProfPercent = ((double)HotProfCount) / TotalProfCount * 100;
+
+ formatted_raw_ostream FOS(OS);
+ FOS << HotFuncCount << " out of " << TotalFuncCount
+ << " functions with profile ("
+ << format("%.2f%%", (((double)HotFuncCount) / TotalFuncCount * 100))
+ << ") are considered hot functions";
+ if (!HotFuncMetric.empty())
+ FOS << " (" << HotFuncMetric << ")";
+ FOS << ".\n";
+ FOS << HotProfCount << " out of " << TotalProfCount << " profile counts ("
+ << format("%.2f%%", TotalProfPercent) << ") are from hot functions.\n";
+
+ for (size_t I = 0; I < ColumnTitle.size(); ++I) {
+ FOS.PadToColumn(ColumnOffset[I]);
+ FOS << ColumnTitle[I];
+ }
+ FOS << "\n";
+
+ for (const HotFuncInfo &R : PrintValues) {
+ FOS.PadToColumn(ColumnOffset[0]);
+ FOS << R.TotalCount << " (" << format("%.2f%%", R.TotalCountPercent) << ")";
+ FOS.PadToColumn(ColumnOffset[1]);
+ FOS << R.MaxCount;
+ FOS.PadToColumn(ColumnOffset[2]);
+ FOS << R.EntryCount;
+ FOS.PadToColumn(ColumnOffset[3]);
+ FOS << R.FuncName << "\n";
+ }
+ return;
+}
+
+static int
+showHotFunctionList(const StringMap<sampleprof::FunctionSamples> &Profiles,
+ ProfileSummary &PS, raw_fd_ostream &OS) {
+ using namespace sampleprof;
+
+ const uint32_t HotFuncCutoff = 990000;
+ auto &SummaryVector = PS.getDetailedSummary();
+ uint64_t MinCountThreshold = 0;
+ for (const ProfileSummaryEntry &SummaryEntry : SummaryVector) {
+ if (SummaryEntry.Cutoff == HotFuncCutoff) {
+ MinCountThreshold = SummaryEntry.MinCount;
+ break;
+ }
+ }
+ assert(MinCountThreshold != 0);
+
+ // Traverse all functions in the profile and keep only hot functions.
+ // The following loop also calculates the sum of total samples of all
+ // functions.
+ std::multimap<uint64_t, std::pair<const FunctionSamples *, const uint64_t>,
+ std::greater<uint64_t>>
+ HotFunc;
+ uint64_t ProfileTotalSample = 0;
+ uint64_t HotFuncSample = 0;
+ uint64_t HotFuncCount = 0;
+ uint64_t MaxCount = 0;
+ for (const auto &I : Profiles) {
+ const FunctionSamples &FuncProf = I.second;
+ ProfileTotalSample += FuncProf.getTotalSamples();
+ MaxCount = FuncProf.getMaxCountInside();
+
+ // MinCountThreshold is a block/line threshold computed for a given cutoff.
+ // We intentionally compare the maximum sample count in a function with this
+ // threshold to get an approximate threshold for hot functions.
+ if (MaxCount >= MinCountThreshold) {
+ HotFunc.emplace(FuncProf.getTotalSamples(),
+ std::make_pair(&(I.second), MaxCount));
+ HotFuncSample += FuncProf.getTotalSamples();
+ ++HotFuncCount;
+ }
+ }
+
+ std::vector<std::string> ColumnTitle{"Total sample (%)", "Max sample",
+ "Entry sample", "Function name"};
+ std::vector<int> ColumnOffset{0, 24, 42, 58};
+ std::string Metric =
+ std::string("max sample >= ") + std::to_string(MinCountThreshold);
+ std::vector<HotFuncInfo> PrintValues;
+ for (const auto &FuncPair : HotFunc) {
+ const FunctionSamples &Func = *FuncPair.second.first;
+ double TotalSamplePercent =
+ (ProfileTotalSample > 0)
+ ? (Func.getTotalSamples() * 100.0) / ProfileTotalSample
+ : 0;
+ PrintValues.emplace_back(HotFuncInfo(
+ Func.getFuncName(), Func.getTotalSamples(), TotalSamplePercent,
+ FuncPair.second.second, Func.getEntrySamples()));
+ }
+ dumpHotFunctionList(ColumnTitle, ColumnOffset, PrintValues, HotFuncCount,
+ Profiles.size(), HotFuncSample, ProfileTotalSample,
+ Metric, OS);
+
+ return 0;
+}
+
+static int showSampleProfile(const std::string &Filename, bool ShowCounts,
+ bool ShowAllFunctions, bool ShowDetailedSummary,
+ const std::string &ShowFunction,
+ bool ShowProfileSymbolList,
+ bool ShowSectionInfoOnly, bool ShowHotFuncList,
+ raw_fd_ostream &OS) {
+ using namespace sampleprof;
+ LLVMContext Context;
+ auto ReaderOrErr = SampleProfileReader::create(Filename, Context);
+ if (std::error_code EC = ReaderOrErr.getError())
+ exitWithErrorCode(EC, Filename);
+
+ auto Reader = std::move(ReaderOrErr.get());
+
+ if (ShowSectionInfoOnly) {
+ showSectionInfo(Reader.get(), OS);
+ return 0;
+ }
+
+ if (std::error_code EC = Reader->read())
+ exitWithErrorCode(EC, Filename);
+
+ if (ShowAllFunctions || ShowFunction.empty())
+ Reader->dump(OS);
+ else
+ Reader->dumpFunctionProfile(ShowFunction, OS);
+
+ if (ShowProfileSymbolList) {
+ std::unique_ptr<sampleprof::ProfileSymbolList> ReaderList =
+ Reader->getProfileSymbolList();
+ ReaderList->dump(OS);
+ }
+
+ if (ShowDetailedSummary) {
+ auto &PS = Reader->getSummary();
+ PS.printSummary(OS);
+ PS.printDetailedSummary(OS);
+ }
+
+ if (ShowHotFuncList)
+ showHotFunctionList(Reader->getProfiles(), Reader->getSummary(), OS);
+
+ return 0;
+}
+
+static int show_main(int argc, const char *argv[]) {
+ cl::opt<std::string> Filename(cl::Positional, cl::Required,
+ cl::desc("<profdata-file>"));
+
+ cl::opt<bool> ShowCounts("counts", cl::init(false),
+ cl::desc("Show counter values for shown functions"));
+ cl::opt<bool> TextFormat(
+ "text", cl::init(false),
+ cl::desc("Show instr profile data in text dump format"));
+ cl::opt<bool> ShowIndirectCallTargets(
+ "ic-targets", cl::init(false),
+ cl::desc("Show indirect call site target values for shown functions"));
+ cl::opt<bool> ShowMemOPSizes(
+ "memop-sizes", cl::init(false),
+ cl::desc("Show the profiled sizes of the memory intrinsic calls "
+ "for shown functions"));
+ cl::opt<bool> ShowDetailedSummary("detailed-summary", cl::init(false),
+ cl::desc("Show detailed profile summary"));
+ cl::list<uint32_t> DetailedSummaryCutoffs(
+ cl::CommaSeparated, "detailed-summary-cutoffs",
+ cl::desc(
+ "Cutoff percentages (times 10000) for generating detailed summary"),
+ cl::value_desc("800000,901000,999999"));
+ cl::opt<bool> ShowHotFuncList(
+ "hot-func-list", cl::init(false),
+ cl::desc("Show profile summary of a list of hot functions"));
+ cl::opt<bool> ShowAllFunctions("all-functions", cl::init(false),
+ cl::desc("Details for every function"));
+ cl::opt<bool> ShowCS("showcs", cl::init(false),
+ cl::desc("Show context sensitive counts"));
+ cl::opt<std::string> ShowFunction("function",
+ cl::desc("Details for matching functions"));
+
+ cl::opt<std::string> OutputFilename("output", cl::value_desc("output"),
+ cl::init("-"), cl::desc("Output file"));
+ cl::alias OutputFilenameA("o", cl::desc("Alias for --output"),
+ cl::aliasopt(OutputFilename));
+ cl::opt<ProfileKinds> ProfileKind(
+ cl::desc("Profile kind:"), cl::init(instr),
+ cl::values(clEnumVal(instr, "Instrumentation profile (default)"),
+ clEnumVal(sample, "Sample profile")));
+ cl::opt<uint32_t> TopNFunctions(
+ "topn", cl::init(0),
+ cl::desc("Show the list of functions with the largest internal counts"));
+ cl::opt<uint32_t> ValueCutoff(
+ "value-cutoff", cl::init(0),
+ cl::desc("Set the count value cutoff. Functions with the maximum count "
+ "less than this value will not be printed out. (Default is 0)"));
+ cl::opt<bool> OnlyListBelow(
+ "list-below-cutoff", cl::init(false),
+ cl::desc("Only output names of functions whose max count values are "
+ "below the cutoff value"));
+ cl::opt<bool> ShowProfileSymbolList(
+ "show-prof-sym-list", cl::init(false),
+ cl::desc("Show profile symbol list if it exists in the profile. "));
+ cl::opt<bool> ShowSectionInfoOnly(
+ "show-sec-info-only", cl::init(false),
+ cl::desc("Show the information of each section in the sample profile. "
+ "The flag is only usable when the sample profile is in "
+ "extbinary format"));
+
+ cl::ParseCommandLineOptions(argc, argv, "LLVM profile data summary\n");
+
+ if (OutputFilename.empty())
+ OutputFilename = "-";
+
+ if (!Filename.compare(OutputFilename)) {
+ errs() << sys::path::filename(argv[0])
+ << ": Input file name cannot be the same as the output file name!\n";
+ return 1;
+ }
+
+ std::error_code EC;
+ raw_fd_ostream OS(OutputFilename.data(), EC, sys::fs::OF_Text);
+ if (EC)
+ exitWithErrorCode(EC, OutputFilename);
+
+ if (ShowAllFunctions && !ShowFunction.empty())
+ WithColor::warning() << "-function argument ignored: showing all functions\n";
+
+ if (ProfileKind == instr)
+ return showInstrProfile(Filename, ShowCounts, TopNFunctions,
+ ShowIndirectCallTargets, ShowMemOPSizes,
+ ShowDetailedSummary, DetailedSummaryCutoffs,
+ ShowAllFunctions, ShowCS, ValueCutoff,
+ OnlyListBelow, ShowFunction, TextFormat, OS);
+ else
+ return showSampleProfile(Filename, ShowCounts, ShowAllFunctions,
+ ShowDetailedSummary, ShowFunction,
+ ShowProfileSymbolList, ShowSectionInfoOnly,
+ ShowHotFuncList, OS);
+}
+
+int main(int argc, const char *argv[]) {
+ InitLLVM X(argc, argv);
+
+ StringRef ProgName(sys::path::filename(argv[0]));
+ if (argc > 1) {
+ int (*func)(int, const char *[]) = nullptr;
+
+ if (strcmp(argv[1], "merge") == 0)
+ func = merge_main;
+ else if (strcmp(argv[1], "show") == 0)
+ func = show_main;
+ else if (strcmp(argv[1], "overlap") == 0)
+ func = overlap_main;
+
+ if (func) {
+ std::string Invocation(ProgName.str() + " " + argv[1]);
+ argv[1] = Invocation.c_str();
+ return func(argc - 1, argv + 1);
+ }
+
+ if (strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "-help") == 0 ||
+ strcmp(argv[1], "--help") == 0) {
+
+ errs() << "OVERVIEW: LLVM profile data tools\n\n"
+ << "USAGE: " << ProgName << " <command> [args...]\n"
+ << "USAGE: " << ProgName << " <command> -help\n\n"
+ << "See each individual command --help for more details.\n"
+ << "Available commands: merge, show, overlap\n";
+ return 0;
+ }
+ }
+
+ if (argc < 2)
+ errs() << ProgName << ": No command specified!\n";
+ else
+ errs() << ProgName << ": Unknown command!\n";
+
+ errs() << "USAGE: " << ProgName << " <merge|show|overlap> [args...]\n";
+ return 1;
+}
diff --git a/utils/FileCheck-11.0.cpp b/utils/FileCheck-11.0.cpp
new file mode 100644
index 00000000..fa79c5e8
--- /dev/null
+++ b/utils/FileCheck-11.0.cpp
@@ -0,0 +1,859 @@
+//===- FileCheck.cpp - Check that File's Contents match what is expected --===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// FileCheck does a line-by line check of a file that validates whether it
+// contains the expected content. This is useful for regression tests etc.
+//
+// This program exits with an exit status of 2 on error, exit status of 0 if
+// the file matched the expected contents, and exit status of 1 if it did not
+// contain the expected contents.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/InitLLVM.h"
+#include "llvm/Support/Process.h"
+#include "llvm/Support/WithColor.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/FileCheck.h"
+#include <cmath>
+using namespace llvm;
+
+static cl::extrahelp FileCheckOptsEnv(
+ "\nOptions are parsed from the environment variable FILECHECK_OPTS and\n"
+ "from the command line.\n");
+
+static cl::opt<std::string>
+ CheckFilename(cl::Positional, cl::desc("<check-file>"), cl::Optional);
+
+static cl::opt<std::string>
+ InputFilename("input-file", cl::desc("File to check (defaults to stdin)"),
+ cl::init("-"), cl::value_desc("filename"));
+
+static cl::list<std::string> CheckPrefixes(
+ "check-prefix",
+ cl::desc("Prefix to use from check file (defaults to 'CHECK')"));
+static cl::alias CheckPrefixesAlias(
+ "check-prefixes", cl::aliasopt(CheckPrefixes), cl::CommaSeparated,
+ cl::NotHidden,
+ cl::desc(
+ "Alias for -check-prefix permitting multiple comma separated values"));
+
+static cl::list<std::string> CommentPrefixes(
+ "comment-prefixes", cl::CommaSeparated, cl::Hidden,
+ cl::desc("Comma-separated list of comment prefixes to use from check file\n"
+ "(defaults to 'COM,RUN'). Please avoid using this feature in\n"
+ "LLVM's LIT-based test suites, which should be easier to\n"
+ "maintain if they all follow a consistent comment style. This\n"
+ "feature is meant for non-LIT test suites using FileCheck."));
+
+static cl::opt<bool> NoCanonicalizeWhiteSpace(
+ "strict-whitespace",
+ cl::desc("Do not treat all horizontal whitespace as equivalent"));
+
+static cl::opt<bool> IgnoreCase(
+ "ignore-case",
+ cl::desc("Use case-insensitive matching"));
+
+static cl::list<std::string> ImplicitCheckNot(
+ "implicit-check-not",
+ cl::desc("Add an implicit negative check with this pattern to every\n"
+ "positive check. This can be used to ensure that no instances of\n"
+ "this pattern occur which are not matched by a positive pattern"),
+ cl::value_desc("pattern"));
+
+static cl::list<std::string>
+ GlobalDefines("D", cl::AlwaysPrefix,
+ cl::desc("Define a variable to be used in capture patterns."),
+ cl::value_desc("VAR=VALUE"));
+
+static cl::opt<bool> AllowEmptyInput(
+ "allow-empty", cl::init(false),
+ cl::desc("Allow the input file to be empty. This is useful when making\n"
+ "checks that some error message does not occur, for example."));
+
+static cl::opt<bool> MatchFullLines(
+ "match-full-lines", cl::init(false),
+ cl::desc("Require all positive matches to cover an entire input line.\n"
+ "Allows leading and trailing whitespace if --strict-whitespace\n"
+ "is not also passed."));
+
+static cl::opt<bool> EnableVarScope(
+ "enable-var-scope", cl::init(false),
+ cl::desc("Enables scope for regex variables. Variables with names that\n"
+ "do not start with '$' will be reset at the beginning of\n"
+ "each CHECK-LABEL block."));
+
+static cl::opt<bool> AllowDeprecatedDagOverlap(
+ "allow-deprecated-dag-overlap", cl::init(false),
+ cl::desc("Enable overlapping among matches in a group of consecutive\n"
+ "CHECK-DAG directives. This option is deprecated and is only\n"
+ "provided for convenience as old tests are migrated to the new\n"
+ "non-overlapping CHECK-DAG implementation.\n"));
+
+static cl::opt<bool> Verbose(
+ "v", cl::init(false), cl::ZeroOrMore,
+ cl::desc("Print directive pattern matches, or add them to the input dump\n"
+ "if enabled.\n"));
+
+static cl::opt<bool> VerboseVerbose(
+ "vv", cl::init(false), cl::ZeroOrMore,
+ cl::desc("Print information helpful in diagnosing internal FileCheck\n"
+ "issues, or add it to the input dump if enabled. Implies\n"
+ "-v.\n"));
+
+// The order of DumpInputValue members affects their precedence, as documented
+// for -dump-input below.
+enum DumpInputValue {
+ DumpInputNever,
+ DumpInputFail,
+ DumpInputAlways,
+ DumpInputHelp
+};
+
+static cl::list<DumpInputValue> DumpInputs(
+ "dump-input",
+ cl::desc("Dump input to stderr, adding annotations representing\n"
+ "currently enabled diagnostics. When there are multiple\n"
+ "occurrences of this option, the <value> that appears earliest\n"
+ "in the list below has precedence. The default is 'fail'.\n"),
+ cl::value_desc("mode"),
+ cl::values(clEnumValN(DumpInputHelp, "help", "Explain input dump and quit"),
+ clEnumValN(DumpInputAlways, "always", "Always dump input"),
+ clEnumValN(DumpInputFail, "fail", "Dump input on failure"),
+ clEnumValN(DumpInputNever, "never", "Never dump input")));
+
+// The order of DumpInputFilterValue members affects their precedence, as
+// documented for -dump-input-filter below.
+enum DumpInputFilterValue {
+ DumpInputFilterError,
+ DumpInputFilterAnnotation,
+ DumpInputFilterAnnotationFull,
+ DumpInputFilterAll
+};
+
+static cl::list<DumpInputFilterValue> DumpInputFilters(
+ "dump-input-filter",
+ cl::desc("In the dump requested by -dump-input, print only input lines of\n"
+ "kind <value> plus any context specified by -dump-input-context.\n"
+ "When there are multiple occurrences of this option, the <value>\n"
+ "that appears earliest in the list below has precedence. The\n"
+ "default is 'error' when -dump-input=fail, and it's 'all' when\n"
+ "-dump-input=always.\n"),
+ cl::values(clEnumValN(DumpInputFilterAll, "all", "All input lines"),
+ clEnumValN(DumpInputFilterAnnotationFull, "annotation-full",
+ "Input lines with annotations"),
+ clEnumValN(DumpInputFilterAnnotation, "annotation",
+ "Input lines with starting points of annotations"),
+ clEnumValN(DumpInputFilterError, "error",
+ "Input lines with starting points of error "
+ "annotations")));
+
+static cl::list<unsigned> DumpInputContexts(
+ "dump-input-context", cl::value_desc("N"),
+ cl::desc("In the dump requested by -dump-input, print <N> input lines\n"
+ "before and <N> input lines after any lines specified by\n"
+ "-dump-input-filter. When there are multiple occurrences of\n"
+ "this option, the largest specified <N> has precedence. The\n"
+ "default is 5.\n"));
+
+typedef cl::list<std::string>::const_iterator prefix_iterator;
+
+
+
+
+
+
+
+static void DumpCommandLine(int argc, char **argv) {
+ errs() << "FileCheck command line: ";
+ for (int I = 0; I < argc; I++)
+ errs() << " " << argv[I];
+ errs() << "\n";
+}
+
+struct MarkerStyle {
+ /// The starting char (before tildes) for marking the line.
+ char Lead;
+ /// What color to use for this annotation.
+ raw_ostream::Colors Color;
+ /// A note to follow the marker, or empty string if none.
+ std::string Note;
+ /// Does this marker indicate inclusion by -dump-input-filter=error?
+ bool FiltersAsError;
+ MarkerStyle() {}
+ MarkerStyle(char Lead, raw_ostream::Colors Color,
+ const std::string &Note = "", bool FiltersAsError = false)
+ : Lead(Lead), Color(Color), Note(Note), FiltersAsError(FiltersAsError) {
+ assert((!FiltersAsError || !Note.empty()) &&
+ "expected error diagnostic to have note");
+ }
+};
+
+static MarkerStyle GetMarker(FileCheckDiag::MatchType MatchTy) {
+ switch (MatchTy) {
+ case FileCheckDiag::MatchFoundAndExpected:
+ return MarkerStyle('^', raw_ostream::GREEN);
+ case FileCheckDiag::MatchFoundButExcluded:
+ return MarkerStyle('!', raw_ostream::RED, "error: no match expected",
+ /*FiltersAsError=*/true);
+ case FileCheckDiag::MatchFoundButWrongLine:
+ return MarkerStyle('!', raw_ostream::RED, "error: match on wrong line",
+ /*FiltersAsError=*/true);
+ case FileCheckDiag::MatchFoundButDiscarded:
+ return MarkerStyle('!', raw_ostream::CYAN,
+ "discard: overlaps earlier match");
+ case FileCheckDiag::MatchNoneAndExcluded:
+ return MarkerStyle('X', raw_ostream::GREEN);
+ case FileCheckDiag::MatchNoneButExpected:
+ return MarkerStyle('X', raw_ostream::RED, "error: no match found",
+ /*FiltersAsError=*/true);
+ case FileCheckDiag::MatchFuzzy:
+ return MarkerStyle('?', raw_ostream::MAGENTA, "possible intended match",
+ /*FiltersAsError=*/true);
+ }
+ llvm_unreachable_internal("unexpected match type");
+}
+
+static void DumpInputAnnotationHelp(raw_ostream &OS) {
+ OS << "The following description was requested by -dump-input=help to\n"
+ << "explain the input dump printed by FileCheck.\n"
+ << "\n"
+ << "Related command-line options:\n"
+ << "\n"
+ << " - -dump-input=<value> enables or disables the input dump\n"
+ << " - -dump-input-filter=<value> filters the input lines\n"
+ << " - -dump-input-context=<N> adjusts the context of filtered lines\n"
+ << " - -v and -vv add more annotations\n"
+ << " - -color forces colors to be enabled both in the dump and below\n"
+ << " - -help documents the above options in more detail\n"
+ << "\n"
+ << "These options can also be set via FILECHECK_OPTS. For example, for\n"
+ << "maximum debugging output on failures:\n"
+ << "\n"
+ << " $ FILECHECK_OPTS='-dump-input-filter=all -vv -color' ninja check\n"
+ << "\n"
+ << "Input dump annotation format:\n"
+ << "\n";
+
+ // Labels for input lines.
+ OS << " - ";
+ WithColor(OS, raw_ostream::SAVEDCOLOR, true) << "L:";
+ OS << " labels line number L of the input file\n";
+
+ // Labels for annotation lines.
+ OS << " - ";
+ WithColor(OS, raw_ostream::SAVEDCOLOR, true) << "T:L";
+ OS << " labels the only match result for either (1) a pattern of type T"
+ << " from\n"
+ << " line L of the check file if L is an integer or (2) the"
+ << " I-th implicit\n"
+ << " pattern if L is \"imp\" followed by an integer "
+ << "I (index origin one)\n";
+ OS << " - ";
+ WithColor(OS, raw_ostream::SAVEDCOLOR, true) << "T:L'N";
+ OS << " labels the Nth match result for such a pattern\n";
+
+ // Markers on annotation lines.
+ OS << " - ";
+ WithColor(OS, raw_ostream::SAVEDCOLOR, true) << "^~~";
+ OS << " marks good match (reported if -v)\n"
+ << " - ";
+ WithColor(OS, raw_ostream::SAVEDCOLOR, true) << "!~~";
+ OS << " marks bad match, such as:\n"
+ << " - CHECK-NEXT on same line as previous match (error)\n"
+ << " - CHECK-NOT found (error)\n"
+ << " - CHECK-DAG overlapping match (discarded, reported if "
+ << "-vv)\n"
+ << " - ";
+ WithColor(OS, raw_ostream::SAVEDCOLOR, true) << "X~~";
+ OS << " marks search range when no match is found, such as:\n"
+ << " - CHECK-NEXT not found (error)\n"
+ << " - CHECK-NOT not found (success, reported if -vv)\n"
+ << " - CHECK-DAG not found after discarded matches (error)\n"
+ << " - ";
+ WithColor(OS, raw_ostream::SAVEDCOLOR, true) << "?";
+ OS << " marks fuzzy match when no match is found\n";
+
+ // Elided lines.
+ OS << " - ";
+ WithColor(OS, raw_ostream::SAVEDCOLOR, true) << "...";
+ OS << " indicates elided input lines and annotations, as specified by\n"
+ << " -dump-input-filter and -dump-input-context\n";
+
+ // Colors.
+ OS << " - colors ";
+ WithColor(OS, raw_ostream::GREEN, true) << "success";
+ OS << ", ";
+ WithColor(OS, raw_ostream::RED, true) << "error";
+ OS << ", ";
+ WithColor(OS, raw_ostream::MAGENTA, true) << "fuzzy match";
+ OS << ", ";
+ WithColor(OS, raw_ostream::CYAN, true, false) << "discarded match";
+ OS << ", ";
+ WithColor(OS, raw_ostream::CYAN, true, true) << "unmatched input";
+ OS << "\n";
+}
+
+/// An annotation for a single input line.
+struct InputAnnotation {
+ /// The index of the match result across all checks
+ unsigned DiagIndex;
+ /// The label for this annotation.
+ std::string Label;
+ /// Is this the initial fragment of a diagnostic that has been broken across
+ /// multiple lines?
+ bool IsFirstLine;
+ /// What input line (one-origin indexing) this annotation marks. This might
+ /// be different from the starting line of the original diagnostic if
+ /// !IsFirstLine.
+ unsigned InputLine;
+ /// The column range (one-origin indexing, open end) in which to mark the
+ /// input line. If InputEndCol is UINT_MAX, treat it as the last column
+ /// before the newline.
+ unsigned InputStartCol, InputEndCol;
+ /// The marker to use.
+ MarkerStyle Marker;
+ /// Whether this annotation represents a good match for an expected pattern.
+ bool FoundAndExpectedMatch;
+};
+
+/// Get an abbreviation for the check type.
+std::string GetCheckTypeAbbreviation(Check::FileCheckType Ty) {
+ switch (Ty) {
+ case Check::CheckPlain:
+ if (Ty.getCount() > 1)
+ return "count";
+ return "check";
+ case Check::CheckNext:
+ return "next";
+ case Check::CheckSame:
+ return "same";
+ case Check::CheckNot:
+ return "not";
+ case Check::CheckDAG:
+ return "dag";
+ case Check::CheckLabel:
+ return "label";
+ case Check::CheckEmpty:
+ return "empty";
+ case Check::CheckComment:
+ return "com";
+ case Check::CheckEOF:
+ return "eof";
+ case Check::CheckBadNot:
+ return "bad-not";
+ case Check::CheckBadCount:
+ return "bad-count";
+ case Check::CheckNone:
+ llvm_unreachable("invalid FileCheckType");
+ }
+ llvm_unreachable("unknown FileCheckType");
+}
+
+static void
+BuildInputAnnotations(const SourceMgr &SM, unsigned CheckFileBufferID,
+ const std::pair<unsigned, unsigned> &ImpPatBufferIDRange,
+ const std::vector<FileCheckDiag> &Diags,
+ std::vector<InputAnnotation> &Annotations,
+ unsigned &LabelWidth) {
+ // How many diagnostics have we seen so far?
+ unsigned DiagCount = 0;
+ // How many diagnostics has the current check seen so far?
+ unsigned CheckDiagCount = 0;
+ // What's the widest label?
+ LabelWidth = 0;
+ for (auto DiagItr = Diags.begin(), DiagEnd = Diags.end(); DiagItr != DiagEnd;
+ ++DiagItr) {
+ InputAnnotation A;
+ A.DiagIndex = DiagCount++;
+
+ // Build label, which uniquely identifies this check result.
+ unsigned CheckBufferID = SM.FindBufferContainingLoc(DiagItr->CheckLoc);
+ auto CheckLineAndCol =
+ SM.getLineAndColumn(DiagItr->CheckLoc, CheckBufferID);
+ llvm::raw_string_ostream Label(A.Label);
+ Label << GetCheckTypeAbbreviation(DiagItr->CheckTy) << ":";
+ if (CheckBufferID == CheckFileBufferID)
+ Label << CheckLineAndCol.first;
+ else if (ImpPatBufferIDRange.first <= CheckBufferID &&
+ CheckBufferID < ImpPatBufferIDRange.second)
+ Label << "imp" << (CheckBufferID - ImpPatBufferIDRange.first + 1);
+ else
+ llvm_unreachable("expected diagnostic's check location to be either in "
+ "the check file or for an implicit pattern");
+ unsigned CheckDiagIndex = UINT_MAX;
+ auto DiagNext = std::next(DiagItr);
+ if (DiagNext != DiagEnd && DiagItr->CheckTy == DiagNext->CheckTy &&
+ DiagItr->CheckLoc == DiagNext->CheckLoc)
+ CheckDiagIndex = CheckDiagCount++;
+ else if (CheckDiagCount) {
+ CheckDiagIndex = CheckDiagCount;
+ CheckDiagCount = 0;
+ }
+ if (CheckDiagIndex != UINT_MAX)
+ Label << "'" << CheckDiagIndex;
+ Label.flush();
+ LabelWidth = std::max((std::string::size_type)LabelWidth, A.Label.size());
+
+ A.Marker = GetMarker(DiagItr->MatchTy);
+ A.FoundAndExpectedMatch =
+ DiagItr->MatchTy == FileCheckDiag::MatchFoundAndExpected;
+
+ // Compute the mark location, and break annotation into multiple
+ // annotations if it spans multiple lines.
+ A.IsFirstLine = true;
+ A.InputLine = DiagItr->InputStartLine;
+ A.InputStartCol = DiagItr->InputStartCol;
+ if (DiagItr->InputStartLine == DiagItr->InputEndLine) {
+ // Sometimes ranges are empty in order to indicate a specific point, but
+ // that would mean nothing would be marked, so adjust the range to
+ // include the following character.
+ A.InputEndCol =
+ std::max(DiagItr->InputStartCol + 1, DiagItr->InputEndCol);
+ Annotations.push_back(A);
+ } else {
+ assert(DiagItr->InputStartLine < DiagItr->InputEndLine &&
+ "expected input range not to be inverted");
+ A.InputEndCol = UINT_MAX;
+ Annotations.push_back(A);
+ for (unsigned L = DiagItr->InputStartLine + 1, E = DiagItr->InputEndLine;
+ L <= E; ++L) {
+ // If a range ends before the first column on a line, then it has no
+ // characters on that line, so there's nothing to render.
+ if (DiagItr->InputEndCol == 1 && L == E)
+ break;
+ InputAnnotation B;
+ B.DiagIndex = A.DiagIndex;
+ B.Label = A.Label;
+ B.IsFirstLine = false;
+ B.InputLine = L;
+ B.Marker = A.Marker;
+ B.Marker.Lead = '~';
+ B.Marker.Note = "";
+ B.InputStartCol = 1;
+ if (L != E)
+ B.InputEndCol = UINT_MAX;
+ else
+ B.InputEndCol = DiagItr->InputEndCol;
+ B.FoundAndExpectedMatch = A.FoundAndExpectedMatch;
+ Annotations.push_back(B);
+ }
+ }
+ }
+}
+
+static unsigned FindInputLineInFilter(
+ DumpInputFilterValue DumpInputFilter, unsigned CurInputLine,
+ const std::vector<InputAnnotation>::iterator &AnnotationBeg,
+ const std::vector<InputAnnotation>::iterator &AnnotationEnd) {
+ if (DumpInputFilter == DumpInputFilterAll)
+ return CurInputLine;
+ for (auto AnnotationItr = AnnotationBeg; AnnotationItr != AnnotationEnd;
+ ++AnnotationItr) {
+ switch (DumpInputFilter) {
+ case DumpInputFilterAll:
+ llvm_unreachable("unexpected DumpInputFilterAll");
+ break;
+ case DumpInputFilterAnnotationFull:
+ return AnnotationItr->InputLine;
+ case DumpInputFilterAnnotation:
+ if (AnnotationItr->IsFirstLine)
+ return AnnotationItr->InputLine;
+ break;
+ case DumpInputFilterError:
+ if (AnnotationItr->IsFirstLine && AnnotationItr->Marker.FiltersAsError)
+ return AnnotationItr->InputLine;
+ break;
+ }
+ }
+ return UINT_MAX;
+}
+
+/// To OS, print a vertical ellipsis (right-justified at LabelWidth) if it would
+/// occupy less lines than ElidedLines, but print ElidedLines otherwise. Either
+/// way, clear ElidedLines. Thus, if ElidedLines is empty, do nothing.
+static void DumpEllipsisOrElidedLines(raw_ostream &OS, std::string &ElidedLines,
+ unsigned LabelWidth) {
+ if (ElidedLines.empty())
+ return;
+ unsigned EllipsisLines = 3;
+ if (EllipsisLines < StringRef(ElidedLines).count('\n')) {
+ for (unsigned i = 0; i < EllipsisLines; ++i) {
+ WithColor(OS, raw_ostream::BLACK, /*Bold=*/true)
+ << right_justify(".", LabelWidth);
+ OS << '\n';
+ }
+ } else
+ OS << ElidedLines;
+ ElidedLines.clear();
+}
+
+static void DumpAnnotatedInput(raw_ostream &OS, const FileCheckRequest &Req,
+ DumpInputFilterValue DumpInputFilter,
+ unsigned DumpInputContext,
+ StringRef InputFileText,
+ std::vector<InputAnnotation> &Annotations,
+ unsigned LabelWidth) {
+ OS << "Input was:\n<<<<<<\n";
+
+ // Sort annotations.
+ std::sort(Annotations.begin(), Annotations.end(),
+ [](const InputAnnotation &A, const InputAnnotation &B) {
+ // 1. Sort annotations in the order of the input lines.
+ //
+ // This makes it easier to find relevant annotations while
+ // iterating input lines in the implementation below. FileCheck
+ // does not always produce diagnostics in the order of input
+ // lines due to, for example, CHECK-DAG and CHECK-NOT.
+ if (A.InputLine != B.InputLine)
+ return A.InputLine < B.InputLine;
+ // 2. Sort annotations in the temporal order FileCheck produced
+ // their associated diagnostics.
+ //
+ // This sort offers several benefits:
+ //
+ // A. On a single input line, the order of annotations reflects
+ // the FileCheck logic for processing directives/patterns.
+ // This can be helpful in understanding cases in which the
+ // order of the associated directives/patterns in the check
+ // file or on the command line either (i) does not match the
+ // temporal order in which FileCheck looks for matches for the
+ // directives/patterns (due to, for example, CHECK-LABEL,
+ // CHECK-NOT, or `--implicit-check-not`) or (ii) does match
+ // that order but does not match the order of those
+ // diagnostics along an input line (due to, for example,
+ // CHECK-DAG).
+ //
+ // On the other hand, because our presentation format presents
+ // input lines in order, there's no clear way to offer the
+ // same benefit across input lines. For consistency, it might
+ // then seem worthwhile to have annotations on a single line
+ // also sorted in input order (that is, by input column).
+ // However, in practice, this appears to be more confusing
+ // than helpful. Perhaps it's intuitive to expect annotations
+ // to be listed in the temporal order in which they were
+ // produced except in cases the presentation format obviously
+ // and inherently cannot support it (that is, across input
+ // lines).
+ //
+ // B. When diagnostics' annotations are split among multiple
+ // input lines, the user must track them from one input line
+ // to the next. One property of the sort chosen here is that
+ // it facilitates the user in this regard by ensuring the
+ // following: when comparing any two input lines, a
+ // diagnostic's annotations are sorted in the same position
+ // relative to all other diagnostics' annotations.
+ return A.DiagIndex < B.DiagIndex;
+ });
+
+ // Compute the width of the label column.
+ const unsigned char *InputFilePtr = InputFileText.bytes_begin(),
+ *InputFileEnd = InputFileText.bytes_end();
+ unsigned LineCount = InputFileText.count('\n');
+ if (InputFileEnd[-1] != '\n')
+ ++LineCount;
+ unsigned LineNoWidth = std::log10(LineCount) + 1;
+ // +3 below adds spaces (1) to the left of the (right-aligned) line numbers
+ // on input lines and (2) to the right of the (left-aligned) labels on
+ // annotation lines so that input lines and annotation lines are more
+ // visually distinct. For example, the spaces on the annotation lines ensure
+ // that input line numbers and check directive line numbers never align
+ // horizontally. Those line numbers might not even be for the same file.
+ // One space would be enough to achieve that, but more makes it even easier
+ // to see.
+ LabelWidth = std::max(LabelWidth, LineNoWidth) + 3;
+
+ // Print annotated input lines.
+ unsigned PrevLineInFilter = 0; // 0 means none so far
+ unsigned NextLineInFilter = 0; // 0 means uncomputed, UINT_MAX means none
+ std::string ElidedLines;
+ raw_string_ostream ElidedLinesOS(ElidedLines);
+ ColorMode TheColorMode =
+ WithColor(OS).colorsEnabled() ? ColorMode::Enable : ColorMode::Disable;
+ if (TheColorMode == ColorMode::Enable)
+ ElidedLinesOS.enable_colors(true);
+ auto AnnotationItr = Annotations.begin(), AnnotationEnd = Annotations.end();
+ for (unsigned Line = 1;
+ InputFilePtr != InputFileEnd || AnnotationItr != AnnotationEnd;
+ ++Line) {
+ const unsigned char *InputFileLine = InputFilePtr;
+
+ // Compute the previous and next line included by the filter.
+ if (NextLineInFilter < Line)
+ NextLineInFilter = FindInputLineInFilter(DumpInputFilter, Line,
+ AnnotationItr, AnnotationEnd);
+ assert(NextLineInFilter && "expected NextLineInFilter to be computed");
+ if (NextLineInFilter == Line)
+ PrevLineInFilter = Line;
+
+ // Elide this input line and its annotations if it's not within the
+ // context specified by -dump-input-context of an input line included by
+ // -dump-input-filter. However, in case the resulting ellipsis would occupy
+ // more lines than the input lines and annotations it elides, buffer the
+ // elided lines and annotations so we can print them instead.
+ raw_ostream *LineOS = &OS;
+ if ((!PrevLineInFilter || PrevLineInFilter + DumpInputContext < Line) &&
+ (NextLineInFilter == UINT_MAX ||
+ Line + DumpInputContext < NextLineInFilter))
+ LineOS = &ElidedLinesOS;
+ else {
+ LineOS = &OS;
+ DumpEllipsisOrElidedLines(OS, ElidedLinesOS.str(), LabelWidth);
+ }
+
+ // Print right-aligned line number.
+ WithColor(*LineOS, raw_ostream::BLACK, /*Bold=*/true, /*BF=*/false,
+ TheColorMode)
+ << format_decimal(Line, LabelWidth) << ": ";
+
+ // For the case where -v and colors are enabled, find the annotations for
+ // good matches for expected patterns in order to highlight everything
+ // else in the line. There are no such annotations if -v is disabled.
+ std::vector<InputAnnotation> FoundAndExpectedMatches;
+ if (Req.Verbose && TheColorMode == ColorMode::Enable) {
+ for (auto I = AnnotationItr; I != AnnotationEnd && I->InputLine == Line;
+ ++I) {
+ if (I->FoundAndExpectedMatch)
+ FoundAndExpectedMatches.push_back(*I);
+ }
+ }
+
+ // Print numbered line with highlighting where there are no matches for
+ // expected patterns.
+ bool Newline = false;
+ {
+ WithColor COS(*LineOS, raw_ostream::SAVEDCOLOR, /*Bold=*/false,
+ /*BG=*/false, TheColorMode);
+ bool InMatch = false;
+ if (Req.Verbose)
+ COS.changeColor(raw_ostream::CYAN, true, true);
+ for (unsigned Col = 1; InputFilePtr != InputFileEnd && !Newline; ++Col) {
+ bool WasInMatch = InMatch;
+ InMatch = false;
+ for (auto M : FoundAndExpectedMatches) {
+ if (M.InputStartCol <= Col && Col < M.InputEndCol) {
+ InMatch = true;
+ break;
+ }
+ }
+ if (!WasInMatch && InMatch)
+ COS.resetColor();
+ else if (WasInMatch && !InMatch)
+ COS.changeColor(raw_ostream::CYAN, true, true);
+ if (*InputFilePtr == '\n')
+ Newline = true;
+ else
+ COS << *InputFilePtr;
+ ++InputFilePtr;
+ }
+ }
+ *LineOS << '\n';
+ unsigned InputLineWidth = InputFilePtr - InputFileLine - Newline;
+
+ // Print any annotations.
+ while (AnnotationItr != AnnotationEnd &&
+ AnnotationItr->InputLine == Line) {
+ WithColor COS(*LineOS, AnnotationItr->Marker.Color, /*Bold=*/true,
+ /*BG=*/false, TheColorMode);
+ // The two spaces below are where the ": " appears on input lines.
+ COS << left_justify(AnnotationItr->Label, LabelWidth) << " ";
+ unsigned Col;
+ for (Col = 1; Col < AnnotationItr->InputStartCol; ++Col)
+ COS << ' ';
+ COS << AnnotationItr->Marker.Lead;
+ // If InputEndCol=UINT_MAX, stop at InputLineWidth.
+ for (++Col; Col < AnnotationItr->InputEndCol && Col <= InputLineWidth;
+ ++Col)
+ COS << '~';
+ const std::string &Note = AnnotationItr->Marker.Note;
+ if (!Note.empty()) {
+ // Put the note at the end of the input line. If we were to instead
+ // put the note right after the marker, subsequent annotations for the
+ // same input line might appear to mark this note instead of the input
+ // line.
+ for (; Col <= InputLineWidth; ++Col)
+ COS << ' ';
+ COS << ' ' << Note;
+ }
+ COS << '\n';
+ ++AnnotationItr;
+ }
+ }
+ DumpEllipsisOrElidedLines(OS, ElidedLinesOS.str(), LabelWidth);
+
+ OS << ">>>>>>\n";
+}
+
+int main(int argc, char **argv) {
+ // Enable use of ANSI color codes because FileCheck is using them to
+ // highlight text.
+ llvm::sys::Process::UseANSIEscapeCodes(true);
+
+ InitLLVM X(argc, argv);
+ cl::ParseCommandLineOptions(argc, argv, /*Overview*/ "", /*Errs*/ nullptr,
+ "FILECHECK_OPTS");
+
+ // Select -dump-input* values. The -help documentation specifies the default
+ // value and which value to choose if an option is specified multiple times.
+ // In the latter case, the general rule of thumb is to choose the value that
+ // provides the most information.
+ DumpInputValue DumpInput =
+ DumpInputs.empty()
+ ? DumpInputFail
+ : *std::max_element(DumpInputs.begin(), DumpInputs.end());
+ DumpInputFilterValue DumpInputFilter;
+ if (DumpInputFilters.empty())
+ DumpInputFilter = DumpInput == DumpInputAlways ? DumpInputFilterAll
+ : DumpInputFilterError;
+ else
+ DumpInputFilter =
+ *std::max_element(DumpInputFilters.begin(), DumpInputFilters.end());
+ unsigned DumpInputContext = DumpInputContexts.empty()
+ ? 5
+ : *std::max_element(DumpInputContexts.begin(),
+ DumpInputContexts.end());
+
+ if (DumpInput == DumpInputHelp) {
+ DumpInputAnnotationHelp(outs());
+ return 0;
+ }
+ if (CheckFilename.empty()) {
+ errs() << "<check-file> not specified\n";
+ return 2;
+ }
+
+ FileCheckRequest Req;
+ for (StringRef Prefix : CheckPrefixes)
+ Req.CheckPrefixes.push_back(Prefix);
+
+ for (StringRef Prefix : CommentPrefixes)
+ Req.CommentPrefixes.push_back(Prefix);
+
+ for (StringRef CheckNot : ImplicitCheckNot)
+ Req.ImplicitCheckNot.push_back(CheckNot);
+
+ bool GlobalDefineError = false;
+ for (StringRef G : GlobalDefines) {
+ size_t EqIdx = G.find('=');
+ if (EqIdx == std::string::npos) {
+ errs() << "Missing equal sign in command-line definition '-D" << G
+ << "'\n";
+ GlobalDefineError = true;
+ continue;
+ }
+ if (EqIdx == 0) {
+ errs() << "Missing variable name in command-line definition '-D" << G
+ << "'\n";
+ GlobalDefineError = true;
+ continue;
+ }
+ Req.GlobalDefines.push_back(G);
+ }
+ if (GlobalDefineError)
+ return 2;
+
+ Req.AllowEmptyInput = AllowEmptyInput;
+ Req.EnableVarScope = EnableVarScope;
+ Req.AllowDeprecatedDagOverlap = AllowDeprecatedDagOverlap;
+ Req.Verbose = Verbose;
+ Req.VerboseVerbose = VerboseVerbose;
+ Req.NoCanonicalizeWhiteSpace = NoCanonicalizeWhiteSpace;
+ Req.MatchFullLines = MatchFullLines;
+ Req.IgnoreCase = IgnoreCase;
+
+ if (VerboseVerbose)
+ Req.Verbose = true;
+
+ FileCheck FC(Req);
+ if (!FC.ValidateCheckPrefixes())
+ return 2;
+
+ Regex PrefixRE = FC.buildCheckPrefixRegex();
+ std::string REError;
+ if (!PrefixRE.isValid(REError)) {
+ errs() << "Unable to combine check-prefix strings into a prefix regular "
+ "expression! This is likely a bug in FileCheck's verification of "
+ "the check-prefix strings. Regular expression parsing failed "
+ "with the following error: "
+ << REError << "\n";
+ return 2;
+ }
+
+ SourceMgr SM;
+
+ // Read the expected strings from the check file.
+ ErrorOr<std::unique_ptr<MemoryBuffer>> CheckFileOrErr =
+ MemoryBuffer::getFileOrSTDIN(CheckFilename);
+ if (std::error_code EC = CheckFileOrErr.getError()) {
+ errs() << "Could not open check file '" << CheckFilename
+ << "': " << EC.message() << '\n';
+ return 2;
+ }
+ MemoryBuffer &CheckFile = *CheckFileOrErr.get();
+
+ SmallString<4096> CheckFileBuffer;
+ StringRef CheckFileText = FC.CanonicalizeFile(CheckFile, CheckFileBuffer);
+
+ unsigned CheckFileBufferID =
+ SM.AddNewSourceBuffer(MemoryBuffer::getMemBuffer(
+ CheckFileText, CheckFile.getBufferIdentifier()),
+ SMLoc());
+
+ std::pair<unsigned, unsigned> ImpPatBufferIDRange;
+ if (FC.readCheckFile(SM, CheckFileText, PrefixRE, &ImpPatBufferIDRange))
+ return 2;
+
+ // Open the file to check and add it to SourceMgr.
+ ErrorOr<std::unique_ptr<MemoryBuffer>> InputFileOrErr =
+ MemoryBuffer::getFileOrSTDIN(InputFilename);
+ if (InputFilename == "-")
+ InputFilename = "<stdin>"; // Overwrite for improved diagnostic messages
+ if (std::error_code EC = InputFileOrErr.getError()) {
+ errs() << "Could not open input file '" << InputFilename
+ << "': " << EC.message() << '\n';
+ return 2;
+ }
+ MemoryBuffer &InputFile = *InputFileOrErr.get();
+
+ if (InputFile.getBufferSize() == 0 && !AllowEmptyInput) {
+ errs() << "FileCheck error: '" << InputFilename << "' is empty.\n";
+ DumpCommandLine(argc, argv);
+ return 2;
+ }
+
+ SmallString<4096> InputFileBuffer;
+ StringRef InputFileText = FC.CanonicalizeFile(InputFile, InputFileBuffer);
+
+ SM.AddNewSourceBuffer(MemoryBuffer::getMemBuffer(
+ InputFileText, InputFile.getBufferIdentifier()),
+ SMLoc());
+
+ std::vector<FileCheckDiag> Diags;
+ int ExitCode = FC.checkInput(SM, InputFileText,
+ DumpInput == DumpInputNever ? nullptr : &Diags)
+ ? EXIT_SUCCESS
+ : 1;
+ if (DumpInput == DumpInputAlways ||
+ (ExitCode == 1 && DumpInput == DumpInputFail)) {
+ errs() << "\n"
+ << "Input file: " << InputFilename << "\n"
+ << "Check file: " << CheckFilename << "\n"
+ << "\n"
+ << "-dump-input=help explains the following input dump.\n"
+ << "\n";
+ std::vector<InputAnnotation> Annotations;
+ unsigned LabelWidth;
+ BuildInputAnnotations(SM, CheckFileBufferID, ImpPatBufferIDRange, Diags,
+ Annotations, LabelWidth);
+ DumpAnnotatedInput(errs(), Req, DumpInputFilter, DumpInputContext,
+ InputFileText, Annotations, LabelWidth);
+ }
+
+ return ExitCode;
+}
diff --git a/utils/gen_gccbuiltins.cpp b/utils/gen_gccbuiltins.cpp
index 3afdfd12..cc7bd1a5 100644
--- a/utils/gen_gccbuiltins.cpp
+++ b/utils/gen_gccbuiltins.cpp
@@ -68,16 +68,17 @@ string dtype(Record* rec, bool readOnlyMem)
return "";
}
-string attributes(ListInit* propertyList)
+StringRef attributes(ListInit* propertyList)
{
- string prop =
- propertyList->size()
- ? propertyList->getElementAsRecord(0)->getName() : "";
-
- return
- prop == "IntrNoMem" ? " pure @safe" :
- prop == "IntrReadArgMem" ? " pure" :
- prop == "IntrReadWriteArgMem" ? " pure" : "";
+ const auto prop = propertyList->size()
+ ? propertyList->getElementAsRecord(0)->getName()
+ : "";
+
+ if (prop == "IntrNoMem")
+ return " pure @safe";
+ if (prop == "IntrReadArgMem" || prop == "IntrReadWriteArgMem")
+ return " pure";
+ return "";
}
void processRecord(raw_ostream& os, Record& rec, string arch)
@@ -85,8 +86,8 @@ void processRecord(raw_ostream& os, Record& rec, string arch)
if(!rec.getValue("GCCBuiltinName"))
return;
- string builtinName = rec.getValueAsString("GCCBuiltinName");
- string name = rec.getName();
+ const StringRef builtinName = rec.getValueAsString("GCCBuiltinName");
+ string name = rec.getName().str();
if(name.substr(0, 4) != "int_" || name.find(arch) == string::npos)
return;
@@ -96,9 +97,8 @@ void processRecord(raw_ostream& os, Record& rec, string arch)
name = string("llvm.") + name;
ListInit* propsList = rec.getValueAsListInit("IntrProperties");
- string prop =
- propsList->size()
- ? propsList->getElementAsRecord(0)->getName() : "";
+ const StringRef prop =
+ propsList->size() ? propsList->getElementAsRecord(0)->getName() : "";
bool readOnlyMem = prop == "IntrReadArgMem" || prop == "IntrReadMem";
@@ -127,8 +127,8 @@ void processRecord(raw_ostream& os, Record& rec, string arch)
else
return;
- os << "pragma(LDC_intrinsic, \"" + name + "\")\n ";
- os << ret + " " + builtinName + "(";
+ os << "pragma(LDC_intrinsic, \"" << name << "\")\n ";
+ os << ret << " " << builtinName << "(";
if(params.size())
os << params[0];
@@ -136,7 +136,7 @@ void processRecord(raw_ostream& os, Record& rec, string arch)
for(size_t i = 1; i < params.size(); i++)
os << ", " << params[i];
- os << ")" + attributes(propsList) + ";\n\n";
+ os << ")" << attributes(propsList) << ";\n\n";
}
std::string arch;
--
2.29.0
From 93dc2a59cfa2c662a2cf39e4a8d0427fb3d9099c Mon Sep 17 00:00:00 2001
From: Martin Kinkelin <noone@nowhere.com>
Date: Sun, 23 Aug 2020 17:56:52 +0200
Subject: [PATCH 04/16] Azure CI: Upgrade to LDC-LLVM v11.0.0-rc2
The AArch64 build for Shippable hasn't succeeded (failed to compile
MLIR).
---
.azure-pipelines/android-llvm-config.in | 28 ++++++++++++-------------
.azure-pipelines/posix.yml | 9 ++++----
.azure-pipelines/windows.yml | 3 ++-
azure-pipelines.yml | 2 +-
4 files changed, 22 insertions(+), 20 deletions(-)
diff --git a/.azure-pipelines/android-llvm-config.in b/.azure-pipelines/android-llvm-config.in
index 9d49ca08..d00ac475 100644
--- a/.azure-pipelines/android-llvm-config.in
+++ b/.azure-pipelines/android-llvm-config.in
@@ -54,26 +54,26 @@ components="aarch64 aarch64asmparser aarch64codegen aarch64desc aarch64disassemb
aggressiveinstcombine all all-targets analysis arm armasmparser armcodegen armdesc armdisassembler arminfo \
armutils asmparser asmprinter binaryformat bitreader bitstreamreader bitwriter cfguard codegen core coroutines \
coverage debuginfocodeview debuginfodwarf debuginfogsym debuginfomsf debuginfopdb demangle dlltooldriver \
-dwarflinker engine executionengine frontendopenmp fuzzmutate globalisel instcombine instrumentation interpreter \
+dwarflinker engine executionengine extensions frontendopenmp fuzzmutate globalisel instcombine instrumentation interpreter \
ipo irreader jitlink libdriver lineeditor linker lto mc mca mcdisassembler mcjit mcparser mirparser native \
nativecodegen objcarcopts object objectyaml option orcerror orcjit passes profiledata remarks runtimedyld \
scalaropts selectiondag support symbolize tablegen target textapi transformutils vectorize webassembly \
webassemblyasmparser webassemblycodegen webassemblydesc webassemblydisassembler webassemblyinfo windowsmanifest \
-x86 x86asmparser x86codegen x86desc x86disassembler x86info x86utils xray"
+x86 x86asmparser x86codegen x86desc x86disassembler x86info xray"
static_libs="-lLLVMXRay -lLLVMWindowsManifest -lLLVMTableGen -lLLVMSymbolize -lLLVMDebugInfoPDB -lLLVMOrcJIT \
--lLLVMOrcError -lLLVMJITLink -lLLVMObjectYAML -lLLVMMIRParser -lLLVMMCA -lLLVMLTO -lLLVMPasses -lLLVMObjCARCOpts \
--lLLVMLineEditor -lLLVMLibDriver -lLLVMInterpreter -lLLVMFuzzMutate -lLLVMFrontendOpenMP -lLLVMMCJIT \
+-lLLVMOrcError -lLLVMJITLink -lLLVMObjectYAML -lLLVMMIRParser -lLLVMMCA -lLLVMLTO -lLLVMPasses -lLLVMCoroutines \
+-lLLVMObjCARCOpts -lLLVMipo -lLLVMInstrumentation -lLLVMVectorize -lLLVMLinker -lLLVMIRReader -lLLVMAsmParser \
+-lLLVMFrontendOpenMP -lLLVMExtensions -lLLVMLineEditor -lLLVMLibDriver -lLLVMInterpreter -lLLVMFuzzMutate -lLLVMMCJIT \
-lLLVMExecutionEngine -lLLVMRuntimeDyld -lLLVMDWARFLinker -lLLVMDlltoolDriver -lLLVMOption -lLLVMDebugInfoGSYM \
--lLLVMCoverage -lLLVMCoroutines -lLLVMipo -lLLVMInstrumentation -lLLVMVectorize -lLLVMLinker -lLLVMIRReader \
--lLLVMAsmParser -lLLVMX86Disassembler -lLLVMX86AsmParser -lLLVMX86CodeGen -lLLVMX86Desc -lLLVMX86Utils \
--lLLVMX86Info -lLLVMWebAssemblyDisassembler -lLLVMWebAssemblyCodeGen -lLLVMWebAssemblyDesc \
--lLLVMWebAssemblyAsmParser -lLLVMWebAssemblyInfo -lLLVMARMDisassembler -lLLVMARMCodeGen -lLLVMARMAsmParser \
--lLLVMARMDesc -lLLVMARMUtils -lLLVMARMInfo -lLLVMAArch64Disassembler -lLLVMMCDisassembler -lLLVMAArch64CodeGen \
--lLLVMCFGuard -lLLVMGlobalISel -lLLVMSelectionDAG -lLLVMAsmPrinter -lLLVMDebugInfoDWARF -lLLVMCodeGen \
--lLLVMTarget -lLLVMScalarOpts -lLLVMInstCombine -lLLVMAggressiveInstCombine -lLLVMTransformUtils -lLLVMBitWriter \
--lLLVMAnalysis -lLLVMProfileData -lLLVMObject -lLLVMTextAPI -lLLVMBitReader -lLLVMCore -lLLVMRemarks \
--lLLVMBitstreamReader -lLLVMAArch64AsmParser -lLLVMMCParser -lLLVMAArch64Desc -lLLVMMC -lLLVMDebugInfoCodeView \
--lLLVMDebugInfoMSF -lLLVMBinaryFormat -lLLVMAArch64Utils -lLLVMAArch64Info -lLLVMSupport -lLLVMDemangle"
+-lLLVMCoverage -lLLVMX86Disassembler -lLLVMX86AsmParser -lLLVMX86CodeGen -lLLVMX86Desc -lLLVMX86Info \
+-lLLVMWebAssemblyDisassembler -lLLVMWebAssemblyCodeGen -lLLVMWebAssemblyDesc -lLLVMWebAssemblyAsmParser \
+-lLLVMWebAssemblyInfo -lLLVMARMDisassembler -lLLVMARMCodeGen -lLLVMARMAsmParser -lLLVMARMDesc -lLLVMARMUtils \
+-lLLVMARMInfo -lLLVMAArch64Disassembler -lLLVMMCDisassembler -lLLVMAArch64CodeGen -lLLVMCFGuard -lLLVMGlobalISel \
+-lLLVMSelectionDAG -lLLVMAsmPrinter -lLLVMDebugInfoDWARF -lLLVMCodeGen -lLLVMTarget -lLLVMScalarOpts \
+-lLLVMInstCombine -lLLVMAggressiveInstCombine -lLLVMTransformUtils -lLLVMBitWriter -lLLVMAnalysis -lLLVMProfileData \
+-lLLVMObject -lLLVMTextAPI -lLLVMBitReader -lLLVMCore -lLLVMRemarks -lLLVMBitstreamReader -lLLVMAArch64AsmParser \
+-lLLVMMCParser -lLLVMAArch64Desc -lLLVMMC -lLLVMDebugInfoCodeView -lLLVMDebugInfoMSF -lLLVMBinaryFormat \
+-lLLVMAArch64Utils -lLLVMAArch64Info -lLLVMSupport -lLLVMDemangle"
shared_libs="-lLLVM-$version"
libs=$shared_libs
handle_args () {
diff --git a/.azure-pipelines/posix.yml b/.azure-pipelines/posix.yml
index e12191a6..15c2a559 100644
--- a/.azure-pipelines/posix.yml
+++ b/.azure-pipelines/posix.yml
@@ -47,7 +47,7 @@ steps:
if [ "${BUILD_SOURCEBRANCH:0:10}" != "refs/tags/" ]; then
assertsSuffix="-withAsserts"
fi
- curl -L -o llvm.tar.xz https://github.com/ldc-developers/llvm-project/releases/download/ldc-v$LLVM_VERSION/llvm-$LLVM_VERSION-$HOST_OS-x86_64$assertsSuffix.tar.xz
+ curl -L -o llvm.tar.xz https://github.com/ldc-developers/llvm-project/releases/download/CI/llvm-$LLVM_VERSION-$HOST_OS-x86_64$assertsSuffix.tar.xz
mkdir llvm
tar -xf llvm.tar.xz --strip 1 -C llvm
# Set PARALLEL_JOBS env variable and persist it for future steps
@@ -110,7 +110,7 @@ steps:
set -ex
cd ..
# Download & extract LDC-flavoured LLVM for Android target
- curl -L -o llvm-$ARCH.tar.xz https://github.com/ldc-developers/llvm-project/releases/download/ldc-v$LLVM_VERSION/llvm-$LLVM_VERSION-$CI_OS-$ARCH.tar.xz
+ curl -L -o llvm-$ARCH.tar.xz https://github.com/ldc-developers/llvm-project/releases/download/CI/llvm-$LLVM_VERSION-$CI_OS-$ARCH.tar.xz
mkdir llvm-$ARCH
tar -xf llvm-$ARCH.tar.xz --strip 1 -C llvm-$ARCH
# Download & extract Android NDK
@@ -130,7 +130,7 @@ steps:
if [ "$ARCH" = "armv7a" ]; then androidEnv="androideabi"; fi
LLVM_TRIPLE=$ARCH--linux-$androidEnv
sed $BUILD_SOURCESDIRECTORY/.azure-pipelines/android-llvm-config.in \
- -e "s|@LLVM_VERSION@|$LLVM_VERSION|g" \
+ -e "s|@LLVM_VERSION@|11.0.0|g" \
-e "s|@LLVM_INSTALL_DIR@|$PWD/llvm-$ARCH|g" \
-e "s|@LLVM_DEFAULT_TARGET_TRIPLE@|$LLVM_TRIPLE|g" \
-e "s|@LLVM_TARGETS@|AArch64 ARM X86 WebAssembly|g" > llvm-$ARCH/bin/llvm-config
@@ -378,7 +378,8 @@ steps:
cd ..
installed/bin/ldc2 -enable-dynamic-compile -run $BUILD_SOURCESDIRECTORY/tests/dynamiccompile/array.d
displayName: Run dynamic-compile integration test
- condition: and(succeeded(), ne(variables['CI_OS'], 'android'))
+ #condition: and(succeeded(), ne(variables['CI_OS'], 'android'))
+ condition: not(always())
# Add dub & dlang tools
- script: |
diff --git a/.azure-pipelines/windows.yml b/.azure-pipelines/windows.yml
index 47ecf985..c2fc43da 100644
--- a/.azure-pipelines/windows.yml
+++ b/.azure-pipelines/windows.yml
@@ -56,7 +56,7 @@ steps:
:: Download & extract LDC-flavoured LLVM
set ASSERTS_SUFFIX=
if not "%BUILD_SOURCEBRANCH:~0,10%" == "refs/tags/" ( set ASSERTS_SUFFIX=-withAsserts)
- curl -L -o llvm.7z https://github.com/ldc-developers/llvm-project/releases/download/ldc-v%LLVM_VERSION%/llvm-%LLVM_VERSION%-windows-%ARCH%%ASSERTS_SUFFIX%.7z 2>&1
+ curl -L -o llvm.7z https://github.com/ldc-developers/llvm-project/releases/download/CI/llvm-%LLVM_VERSION%-windows-%ARCH%%ASSERTS_SUFFIX%.7z 2>&1
mkdir llvm
cd llvm
7z x ../llvm.7z > nul
@@ -172,6 +172,7 @@ steps:
call "%VSINSTALLDIR%Common7\Tools\VsDevCmd.bat" -arch=%ARCH%
installed\bin\ldc2 -enable-dynamic-compile -run %BUILD_SOURCESDIRECTORY%/tests/dynamiccompile/array.d
displayName: Run dynamic-compile integration test
+ condition: not(always())
- script: |
cd ..
call "%VSINSTALLDIR%Common7\Tools\VsDevCmd.bat" -arch=%ARCH%
diff --git a/azure-pipelines.yml b/azure-pipelines.yml
index d4807498..ac415714 100644
--- a/azure-pipelines.yml
+++ b/azure-pipelines.yml
@@ -1,5 +1,5 @@
variables:
- LLVM_VERSION: 10.0.1
+ LLVM_VERSION: b3db88a4
CLANG_VERSION: 10.0.1
HOST_LDC_VERSION: 1.22.0
--
2.29.0
From 7544a974754efcbe2b4ed1a5ee8aaa4d6d88a201 Mon Sep 17 00:00:00 2001
From: Martin Kinkelin <noone@nowhere.com>
Date: Mon, 24 Aug 2020 20:47:54 +0200
Subject: [PATCH 05/16] Fix LLVM < 8 compatibility (no llvm::CallBase)
---
gen/funcgenstate.cpp | 8 +++---
gen/funcgenstate.h | 8 +++---
gen/llvm.h | 21 +++++++++++++++
gen/passes/GarbageCollect2Stack.cpp | 42 ++++++++++++++++++-----------
gen/tocall.cpp | 7 ++---
5 files changed, 60 insertions(+), 26 deletions(-)
diff --git a/gen/funcgenstate.cpp b/gen/funcgenstate.cpp
index ae0504e7..fbdb9a34 100644
--- a/gen/funcgenstate.cpp
+++ b/gen/funcgenstate.cpp
@@ -103,10 +103,10 @@ FuncGenState::FuncGenState(IrFunction &irFunc, IRState &irs)
: irFunc(irFunc), scopes(irs), jumpTargets(scopes), switchTargets(),
irs(irs) {}
-llvm::CallBase *FuncGenState::callOrInvoke(llvm::Value *callee,
- llvm::FunctionType *calleeType,
- llvm::ArrayRef<llvm::Value *> args,
- const char *name, bool isNothrow) {
+LLCallBasePtr FuncGenState::callOrInvoke(llvm::Value *callee,
+ llvm::FunctionType *calleeType,
+ llvm::ArrayRef<llvm::Value *> args,
+ const char *name, bool isNothrow) {
// If this is a direct call, we might be able to use the callee attributes
// to our advantage.
llvm::Function *calleeFn = llvm::dyn_cast<llvm::Function>(callee);
diff --git a/gen/funcgenstate.h b/gen/funcgenstate.h
index bd1edc0d..af719c74 100644
--- a/gen/funcgenstate.h
+++ b/gen/funcgenstate.h
@@ -199,10 +199,10 @@ public:
/// Emits a call or invoke to the given callee, depending on whether there
/// are catches/cleanups active or not.
- llvm::CallBase *callOrInvoke(llvm::Value *callee,
- llvm::FunctionType *calleeType,
- llvm::ArrayRef<llvm::Value *> args,
- const char *name = "", bool isNothrow = false);
+ LLCallBasePtr callOrInvoke(llvm::Value *callee,
+ llvm::FunctionType *calleeType,
+ llvm::ArrayRef<llvm::Value *> args,
+ const char *name = "", bool isNothrow = false);
private:
IRState &irs;
diff --git a/gen/llvm.h b/gen/llvm.h
index a4870c80..bed932f8 100644
--- a/gen/llvm.h
+++ b/gen/llvm.h
@@ -30,6 +30,9 @@
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/DebugInfo.h"
+#if LDC_LLVM_VER < 800
+#include "llvm/IR/CallSite.h"
+#endif
#if LDC_LLVM_VER >= 1000
// LLVM >= 10 requires C++14 and no longer has llvm::make_unique. Add it back
@@ -81,3 +84,21 @@ using llvm::IRBuilder;
#define LLConstantFP llvm::ConstantFP
#define LLSmallVector llvm::SmallVector
+
+#if LDC_LLVM_VER >= 800
+using LLCallBasePtr = llvm::CallBase *;
+#else
+class LLCallBasePtr {
+ llvm::CallSite CS;
+
+public:
+ LLCallBasePtr(llvm::CallInst *CI) : CS(CI) {}
+ LLCallBasePtr(llvm::InvokeInst *II) : CS(II) {}
+ explicit LLCallBasePtr(llvm::Instruction *I) : CS(I) {}
+
+ llvm::CallSite *operator->() { return &CS; }
+
+ operator llvm::CallSite &() { return CS; }
+ operator llvm::Instruction *() { return CS.getInstruction(); }
+};
+#endif
diff --git a/gen/passes/GarbageCollect2Stack.cpp b/gen/passes/GarbageCollect2Stack.cpp
index 9463b190..fc914762 100644
--- a/gen/passes/GarbageCollect2Stack.cpp
+++ b/gen/passes/GarbageCollect2Stack.cpp
@@ -114,11 +114,11 @@ public:
// Analyze the current call, filling in some fields. Returns true if
// this is an allocation we can stack-allocate.
- virtual bool analyze(CallBase *CB, const Analysis &A) = 0;
+ virtual bool analyze(LLCallBasePtr CB, const Analysis &A) = 0;
// Returns the alloca to replace this call.
// It will always be inserted before the call.
- virtual Value *promote(CallBase *CB, IRBuilder<> &B, const Analysis &A) {
+ virtual Value *promote(LLCallBasePtr CB, IRBuilder<> &B, const Analysis &A) {
NumGcToStack++;
auto &BB = CB->getCaller()->getEntryBlock();
@@ -166,7 +166,7 @@ public:
TypeInfoFI(ReturnType::Type returnType, unsigned tiArgNr)
: FunctionInfo(returnType), TypeInfoArgNr(tiArgNr) {}
- bool analyze(CallBase *CB, const Analysis &A) override {
+ bool analyze(LLCallBasePtr CB, const Analysis &A) override {
Value *TypeInfo = CB->getArgOperand(TypeInfoArgNr);
Ty = A.getTypeFor(TypeInfo);
if (!Ty) {
@@ -187,7 +187,7 @@ public:
: TypeInfoFI(returnType, tiArgNr), ArrSizeArgNr(arrSizeArgNr),
Initialized(initialized) {}
- bool analyze(CallBase *CB, const Analysis &A) override {
+ bool analyze(LLCallBasePtr CB, const Analysis &A) override {
if (!TypeInfoFI::analyze(CB, A)) {
return false;
}
@@ -216,7 +216,7 @@ public:
return true;
}
- Value *promote(CallBase *CB, IRBuilder<> &B, const Analysis &A) override {
+ Value *promote(LLCallBasePtr CB, IRBuilder<> &B, const Analysis &A) override {
IRBuilder<> Builder(B.GetInsertBlock(), B.GetInsertPoint());
// If the allocation is of constant size it's best to put it in the
@@ -265,7 +265,7 @@ public:
// FunctionInfo for _d_allocclass
class AllocClassFI : public FunctionInfo {
public:
- bool analyze(CallBase *CB, const Analysis &A) override {
+ bool analyze(LLCallBasePtr CB, const Analysis &A) override {
if (CB->arg_size() != 1) {
return false;
}
@@ -322,7 +322,7 @@ class UntypedMemoryFI : public FunctionInfo {
Value *SizeArg;
public:
- bool analyze(CallBase *CB, const Analysis &A) override {
+ bool analyze(LLCallBasePtr CB, const Analysis &A) override {
if (CB->arg_size() < SizeArgNr + 1) {
return false;
}
@@ -345,7 +345,7 @@ public:
return true;
}
- Value *promote(CallBase *CB, IRBuilder<> &B, const Analysis &A) override {
+ Value *promote(LLCallBasePtr CB, IRBuilder<> &B, const Analysis &A) override {
IRBuilder<> Builder(B.GetInsertBlock(), B.GetInsertPoint());
// If the allocation is of constant size it's best to put it in the
@@ -431,11 +431,11 @@ GarbageCollect2Stack::GarbageCollect2Stack()
KnownFunctions["_d_allocmemory"] = &AllocMemory;
}
-static void RemoveCall(CallBase *CB, const Analysis &A) {
+static void RemoveCall(LLCallBasePtr CB, const Analysis &A) {
// For an invoke instruction, we insert a branch to the normal target BB
// immediately before it. Ideally, we would find a way to not invalidate
// the dominator tree here.
- if (auto Invoke = dyn_cast<InvokeInst>(CB)) {
+ if (auto Invoke = dyn_cast<InvokeInst>(static_cast<Instruction *>(CB))) {
BranchInst::Create(Invoke->getNormalDest(), Invoke);
Invoke->getUnwindDest()->removePredecessor(CB->getParent());
}
@@ -448,7 +448,7 @@ static void RemoveCall(CallBase *CB, const Analysis &A) {
A.CGNode->removeCallEdgeFor(CB);
#endif
}
- CB->eraseFromParent();
+ static_cast<Instruction *>(CB)->eraseFromParent();
}
static bool
@@ -481,10 +481,18 @@ bool GarbageCollect2Stack::runOnFunction(Function &F) {
auto originalI = I;
// Ignore non-calls.
- auto CB = dyn_cast<CallBase>(&(*(I++)));
+ Instruction *Inst = &(*(I++));
+#if LDC_LLVM_VER >= 800
+ auto CB = dyn_cast<CallBase>(Inst);
if (!CB) {
continue;
}
+#else
+ LLCallBasePtr CB(Inst);
+ if (!CB->getInstruction()) {
+ continue;
+ }
+#endif
// Ignore indirect calls and calls to non-external functions.
Function *Callee = CB->getCalledFunction();
@@ -501,7 +509,7 @@ bool GarbageCollect2Stack::runOnFunction(Function &F) {
FunctionInfo *info = OMI->getValue();
- if (CB->use_empty()) {
+ if (static_cast<Instruction *>(CB)->use_empty()) {
Changed = true;
NumDeleted++;
RemoveCall(CB, A);
@@ -544,7 +552,7 @@ bool GarbageCollect2Stack::runOnFunction(Function &F) {
if (newVal->getType() != CB->getType()) {
newVal = Builder.CreateBitCast(newVal, CB->getType());
}
- CB->replaceAllUsesWith(newVal);
+ static_cast<Instruction *>(CB)->replaceAllUsesWith(newVal);
RemoveCall(CB, A);
}
@@ -816,7 +824,11 @@ bool isSafeToStackAllocate(BasicBlock::iterator Alloc, Value *V,
switch (I->getOpcode()) {
case Instruction::Call:
case Instruction::Invoke: {
+#if LDC_LLVM_VER >= 800
auto CB = llvm::cast<CallBase>(I);
+#else
+ LLCallBasePtr CB(I);
+#endif
// Not captured if the callee is readonly, doesn't return a copy through
// its return value and doesn't unwind (a readonly function can leak bits
// by throwing an exception or not depending on the input value).
@@ -840,7 +852,7 @@ bool isSafeToStackAllocate(BasicBlock::iterator Alloc, Value *V,
return false;
}
- if (auto call = dyn_cast<CallInst>(CB)) {
+ if (auto call = dyn_cast<CallInst>(static_cast<Instruction *>(CB))) {
if (call->isTailCall()) {
RemoveTailCallInsts.push_back(call);
}
diff --git a/gen/tocall.cpp b/gen/tocall.cpp
index b217ffd3..ff4e7359 100644
--- a/gen/tocall.cpp
+++ b/gen/tocall.cpp
@@ -872,8 +872,8 @@ DValue *DtoCallFunction(Loc &loc, Type *resulttype, DValue *fnval,
}
// call the function
- llvm::CallBase *call = gIR->funcGen().callOrInvoke(callable, callableTy, args,
- "", tf->isnothrow);
+ LLCallBasePtr call = gIR->funcGen().callOrInvoke(callable, callableTy, args,
+ "", tf->isnothrow);
// PGO: Insert instrumentation or attach profile metadata at indirect call
// sites.
@@ -886,7 +886,8 @@ DValue *DtoCallFunction(Loc &loc, Type *resulttype, DValue *fnval,
const int sretArgIndex =
(irFty.arg_sret && irFty.arg_this && gABI->passThisBeforeSret(tf) ? 1
: 0);
- LLValue *retllval = (irFty.arg_sret ? args[sretArgIndex] : call);
+ LLValue *retllval = irFty.arg_sret ? args[sretArgIndex]
+ : static_cast<llvm::Instruction *>(call);
bool retValIsLVal =
(tf->isref && returnTy != Tvoid) || (irFty.arg_sret != nullptr);
--
2.29.0
From cacdc461543ab2cbebc4dad0dee5292704364f38 Mon Sep 17 00:00:00 2001
From: Martin Kinkelin <noone@nowhere.com>
Date: Tue, 25 Aug 2020 01:41:24 +0200
Subject: [PATCH 06/16] Use LLVM 10+ setFunctionAttributes()
Which supports more cmdline options in the meantime than what we have
been supporting manually, and should be future-proof, similar to
InitTargetOptionsFromCodeGenFlags().
Attributes are only set if explicitly specified in the cmdline (and not
already present in the function's existing attributes).
This started out as a workaround for not being able to determine whether
the user has explicitly set -frame-pointer in the cmdline with LLVM 11,
and ended with having to touch more than I wanted. An *enabled*
-ffast-math flag (from us, not LLVM) overriding LLVM's
-enable-unsafe-fp-math, but e.g. -ffast-math=false NOT overriding was/is
one of the quirks.
---
driver/cl_options-llvm.cpp | 13 +++++++++++++
driver/cl_options-llvm.h | 8 ++++++++
gen/functions.cpp | 31 +++++++++++++++++++-----------
gen/optimizer.cpp | 4 ++--
gen/optimizer.h | 4 ++--
tests/codegen/attr_targetoptions.d | 4 ----
tests/codegen/inlineIR_math.d | 10 ++++++----
7 files changed, 51 insertions(+), 23 deletions(-)
diff --git a/driver/cl_options-llvm.cpp b/driver/cl_options-llvm.cpp
index 5071fd11..0910ed1b 100644
--- a/driver/cl_options-llvm.cpp
+++ b/driver/cl_options-llvm.cpp
@@ -63,6 +63,8 @@ Optional<CodeModel::Model> getCodeModel() {
#if LDC_LLVM_VER >= 800
llvm::Optional<llvm::FramePointer::FP> framePointerUsage() {
#if LDC_LLVM_VER >= 1100
+ // Defaults to `FP::None`; no way to check if set explicitly by user except
+ // indirectly via setFunctionAttributes()...
return codegen::getFramePointerUsage();
#else
if (::FramePointerUsage.getNumOccurrences() > 0)
@@ -116,6 +118,17 @@ std::string getFeaturesStr() {
return ::getFeaturesStr();
#endif
}
+
+#if LDC_LLVM_VER >= 1000
+void setFunctionAttributes(StringRef cpu, StringRef features,
+ Function &function) {
+#if LDC_LLVM_VER >= 1100
+ return codegen::setFunctionAttributes(cpu, features, function);
+#else
+ return ::setFunctionAttributes(cpu, features, function);
+#endif
+}
+#endif
} // namespace opts
#if LDC_WITH_LLD
diff --git a/driver/cl_options-llvm.h b/driver/cl_options-llvm.h
index dda90542..d43bc584 100644
--- a/driver/cl_options-llvm.h
+++ b/driver/cl_options-llvm.h
@@ -14,6 +14,10 @@
#include "llvm/Support/CodeGen.h"
#include "llvm/Target/TargetOptions.h"
+namespace llvm {
+class Function;
+}
+
namespace opts {
std::string getArchStr();
@@ -31,4 +35,8 @@ bool printTargetFeaturesHelp();
llvm::TargetOptions InitTargetOptionsFromCodeGenFlags();
std::string getCPUStr();
std::string getFeaturesStr();
+#if LDC_LLVM_VER >= 1000
+void setFunctionAttributes(llvm::StringRef cpu, llvm::StringRef features,
+ llvm::Function &function);
+#endif
}
diff --git a/gen/functions.cpp b/gen/functions.cpp
index 46c10c46..84f05e6b 100644
--- a/gen/functions.cpp
+++ b/gen/functions.cpp
@@ -454,20 +454,28 @@ void applyParamAttrsToLLFunc(TypeFunction *f, IrFuncTy &irFty,
/// does the same). See https://llvm.org/bugs/show_bug.cgi?id=23172
void applyTargetMachineAttributes(llvm::Function &func,
const llvm::TargetMachine &target) {
- const llvm::TargetOptions &TO = target.Options;
+ const auto dcompute = gIR->dcomputetarget;
- // TODO: implement commandline switches to change the default values.
// TODO: (correctly) apply these for NVPTX (but not for SPIRV).
- if (gIR->dcomputetarget && gIR->dcomputetarget->target == DComputeTarget::OpenCL)
+ if (dcompute && dcompute->target == DComputeTarget::OpenCL)
return;
- if (!gIR->dcomputetarget) {
- // Target CPU capabilities
- func.addFnAttr("target-cpu", target.getTargetCPU());
- auto featStr = target.getTargetFeatureString();
- if (!featStr.empty())
- func.addFnAttr("target-features", featStr);
- }
+ const auto cpu = dcompute ? "" : target.getTargetCPU();
+ const auto features = dcompute ? "" : target.getTargetFeatureString();
+
+#if LDC_LLVM_VER >= 1000
+ opts::setFunctionAttributes(cpu, features, func);
+ if (opts::fFastMath) // -ffast-math[=true] overrides -enable-unsafe-fp-math
+ func.addFnAttr("unsafe-fp-math", "true");
+ if (!func.hasFnAttribute("frame-pointer")) // not explicitly set by user
+ func.addFnAttr("frame-pointer", isOptimizationEnabled() ? "none" : "all");
+#else
+ if (!cpu.empty())
+ func.addFnAttr("target-cpu", cpu);
+ if (!features.empty())
+ func.addFnAttr("target-features", features);
+
// Floating point settings
+ const auto &TO = target.Options;
func.addFnAttr("unsafe-fp-math", TO.UnsafeFPMath ? "true" : "false");
// This option was removed from llvm::TargetOptions in LLVM 5.0.
// Clang sets this to true when `-cl-mad-enable` is passed (OpenCL only).
@@ -490,10 +498,11 @@ void applyTargetMachineAttributes(llvm::Function &func,
func.addFnAttr("frame-pointer", "all");
break;
}
-#else
+#else // LDC_LLVM_VER < 800
func.addFnAttr("no-frame-pointer-elim",
willEliminateFramePointer() ? "false" : "true");
#endif
+#endif // LDC_LLVM_VER < 1000
}
void applyXRayAttributes(FuncDeclaration &fdecl, llvm::Function &func) {
diff --git a/gen/optimizer.cpp b/gen/optimizer.cpp
index 5832251b..c4faeb16 100644
--- a/gen/optimizer.cpp
+++ b/gen/optimizer.cpp
@@ -131,14 +131,14 @@ bool willCrossModuleInline() {
return enableCrossModuleInlining == llvm::cl::BOU_TRUE;
}
-#if LDC_LLVM_VER >= 800
+#if LDC_LLVM_VER >= 800 && LDC_LLVM_VER < 1000
llvm::FramePointer::FP whichFramePointersToEmit() {
if (auto option = opts::framePointerUsage())
return *option;
return isOptimizationEnabled() ? llvm::FramePointer::None
: llvm::FramePointer::All;
}
-#else
+#elif LDC_LLVM_VER < 800
bool willEliminateFramePointer() {
const llvm::cl::boolOrDefault disableFPElimEnum = opts::disableFPElim();
return disableFPElimEnum == llvm::cl::BOU_FALSE ||
diff --git a/gen/optimizer.h b/gen/optimizer.h
index 0a5583bb..eb08f268 100644
--- a/gen/optimizer.h
+++ b/gen/optimizer.h
@@ -34,9 +34,9 @@ bool willInline();
bool willCrossModuleInline();
-#if LDC_LLVM_VER >= 800
+#if LDC_LLVM_VER >= 800 && LDC_LLVM_VER < 1000
llvm::FramePointer::FP whichFramePointersToEmit();
-#else
+#elif LDC_LLVM_VER < 800
bool willEliminateFramePointer();
#endif
diff --git a/tests/codegen/attr_targetoptions.d b/tests/codegen/attr_targetoptions.d
index eb8ec92d..f70fd24b 100644
--- a/tests/codegen/attr_targetoptions.d
+++ b/tests/codegen/attr_targetoptions.d
@@ -17,10 +17,6 @@ void foo()
// COMMON: attributes #[[KEYVALUE]]
// COMMON-DAG: "target-cpu"=
-// COMMON-DAG: "unsafe-fp-math"="false"
-// COMMON-DAG: "less-precise-fpmad"="false"
-// COMMON-DAG: "no-infs-fp-math"="false"
-// COMMON-DAG: "no-nans-fp-math"="false"
// WITH_FP-DAG: "frame-pointer"="all"
// NO_FP-DAG: "frame-pointer"="none"
diff --git a/tests/codegen/inlineIR_math.d b/tests/codegen/inlineIR_math.d
index 000ce927..03c534e1 100644
--- a/tests/codegen/inlineIR_math.d
+++ b/tests/codegen/inlineIR_math.d
@@ -91,7 +91,7 @@ extern (C) double aliasInlineUnsafe(double[] a, double[] b)
}
// LLVM-LABEL: define{{.*}} @aliasInlineSafe
-// LLVM-SAME: #[[UNSAFEFPMATH2:[0-9]+]]
+// LLVM-SAME: #[[NO_UNSAFEFPMATH:[0-9]+]]
// ASM-LABEL: aliasInlineSafe:
extern (C) double aliasInlineSafe(double[] a, double[] b)
{
@@ -113,6 +113,8 @@ double neverInlinedEnclosingFunction()
return muladd(1.0, 2.0, 3.0);
}
-// LLVM-DAG: attributes #[[UNSAFEFPMATH]] ={{.*}} "unsafe-fp-math"="true"
-// LLVM-DAG: attributes #[[UNSAFEFPMATH2]] ={{.*}} "unsafe-fp-math"="false"
-// LLVM-DAG: attributes #[[FEAT]] ={{.*}} "target-features"="{{.*}}+fma{{.*}}"
+// LLVM: attributes #[[UNSAFEFPMATH]] ={{.*}} "unsafe-fp-math"="true"
+// LLVM: attributes #[[FEAT]] ={{.*}} "target-features"="{{.*}}+fma{{.*}}"
+
+// LLVM: attributes #[[NO_UNSAFEFPMATH]] =
+// LLVM-NOT: "unsafe-fp-math"="true"
--
2.29.0
From 2fb31f84a98f3fabbcfb5dae651b08d2f5538b5f Mon Sep 17 00:00:00 2001
From: Martin Kinkelin <noone@nowhere.com>
Date: Tue, 25 Aug 2020 19:24:42 +0200
Subject: [PATCH 07/16] Adapt lit-test plugins/addFuncEntryCall for LLVM 11
---
tests/plugins/addFuncEntryCall/addFuncEntryCallPass.cpp | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/tests/plugins/addFuncEntryCall/addFuncEntryCallPass.cpp b/tests/plugins/addFuncEntryCall/addFuncEntryCallPass.cpp
index f24a3c3e..69befefd 100644
--- a/tests/plugins/addFuncEntryCall/addFuncEntryCallPass.cpp
+++ b/tests/plugins/addFuncEntryCall/addFuncEntryCallPass.cpp
@@ -50,7 +50,11 @@ bool FuncEntryCallPass::runOnFunction(Function &F) {
// (this includes e.g. `ldc.register_dso`!)
llvm::BasicBlock &block = F.getEntryBlock();
IRBuilder<> builder(&block, block.begin());
+#if LLVM_VERSION >= 1100
+ builder.CreateCall(FunctionCallee(cast<Function>(funcToCallUponEntry)));
+#else
builder.CreateCall(funcToCallUponEntry);
+#endif
return true;
}
--
2.29.0
From 1d969cfccaf7181b5760a0ae7cd6088a36e3de44 Mon Sep 17 00:00:00 2001
From: Martin Kinkelin <noone@nowhere.com>
Date: Tue, 25 Aug 2020 19:25:19 +0200
Subject: [PATCH 08/16] Revise IRScope refactoring
LLVM already provides suited RAII helper types to restore the IRBuilder
state. [They sadly aren't movable, so I've had to wrap them in a
unique_ptr.]
While at it, also minimally revise debuginfo generation for functions.
---
gen/dibuilder.cpp | 29 +++++-----------
gen/dibuilder.h | 13 ++-----
gen/functions.cpp | 14 +++-----
gen/irstate.cpp | 54 +++++------------------------
gen/irstate.h | 41 +++++++++-------------
gen/passes/GarbageCollect2Stack.cpp | 30 ++++++++--------
gen/statements.cpp | 4 +--
gen/toir.cpp | 4 +--
gen/trycatchfinally.cpp | 14 ++------
ir/irclass.cpp | 6 +---
10 files changed, 59 insertions(+), 150 deletions(-)
diff --git a/gen/dibuilder.cpp b/gen/dibuilder.cpp
index a5fdfceb..137c79a5 100644
--- a/gen/dibuilder.cpp
+++ b/gen/dibuilder.cpp
@@ -207,7 +207,7 @@ void DIBuilder::SetValue(const Loc &loc, llvm::Value *value,
IR->scopebb());
}
-DIFile DIBuilder::CreateFile(Loc &loc) {
+DIFile DIBuilder::CreateFile(const Loc &loc) {
const char *filename = loc.filename;
if (!filename)
filename = IR->dmodule->srcfile.toChars();
@@ -1149,26 +1149,15 @@ void DIBuilder::EmitFuncStart(FuncDeclaration *fd) {
Logger::println("D to dwarf funcstart");
LOG_SCOPE;
- assert(static_cast<llvm::MDNode *>(getIrFunc(fd)->diSubprogram) != 0);
- EmitStopPoint(fd->loc);
-}
-
-void DIBuilder::EmitFuncEnd(FuncDeclaration *fd) {
- if (!mustEmitLocationsDebugInfo())
- return;
-
- Logger::println("D to dwarf funcend");
- LOG_SCOPE;
-
auto irFunc = getIrFunc(fd);
-
- assert(static_cast<llvm::MDNode *>(irFunc->diSubprogram) != 0);
- EmitStopPoint(fd->endloc);
-
+ assert(irFunc->diSubprogram);
irFunc->getLLVMFunc()->setSubprogram(irFunc->diSubprogram);
+
+ IR->ir->SetCurrentDebugLocation({}); // clear first
+ EmitStopPoint(fd->loc);
}
-void DIBuilder::EmitBlockStart(Loc &loc) {
+void DIBuilder::EmitBlockStart(const Loc &loc) {
if (!mustEmitLocationsDebugInfo())
return;
@@ -1193,7 +1182,7 @@ void DIBuilder::EmitBlockEnd() {
fn->diLexicalBlocks.pop();
}
-void DIBuilder::EmitStopPoint(Loc &loc) {
+void DIBuilder::EmitStopPoint(const Loc &loc) {
if (!mustEmitLocationsDebugInfo())
return;
@@ -1202,6 +1191,7 @@ void DIBuilder::EmitStopPoint(Loc &loc) {
// cannot do this in all cases).
if (!loc.linnum && IR->ir->getCurrentDebugLocation())
return;
+
unsigned linnum = loc.linnum;
// without proper loc use the line of the enclosing symbol that has line
// number debug info
@@ -1215,11 +1205,8 @@ void DIBuilder::EmitStopPoint(Loc &loc) {
LOG_SCOPE;
IR->ir->SetCurrentDebugLocation(
llvm::DebugLoc::get(linnum, col, GetCurrentScope()));
- currentLoc = loc;
}
-Loc DIBuilder::GetCurrentLoc() const { return currentLoc; }
-
void DIBuilder::EmitValue(llvm::Value *val, VarDeclaration *vd) {
auto sub = IR->func()->variableMap.find(vd);
if (sub == IR->func()->variableMap.end())
diff --git a/gen/dibuilder.h b/gen/dibuilder.h
index fb535235..2ea095b5 100644
--- a/gen/dibuilder.h
+++ b/gen/dibuilder.h
@@ -72,8 +72,6 @@ class DIBuilder {
return CUNode;
}
- Loc currentLoc;
-
public:
explicit DIBuilder(IRState *const IR);
@@ -114,18 +112,13 @@ public:
/// \brief Emits debug info for function start
void EmitFuncStart(FuncDeclaration *fd);
- /// \brief Emits debug info for function end
- void EmitFuncEnd(FuncDeclaration *fd);
-
/// \brief Emits debug info for block start
- void EmitBlockStart(Loc &loc);
+ void EmitBlockStart(const Loc &loc);
/// \brief Emits debug info for block end
void EmitBlockEnd();
- Loc GetCurrentLoc() const;
-
- void EmitStopPoint(Loc &loc);
+ void EmitStopPoint(const Loc &loc);
void EmitValue(llvm::Value *val, VarDeclaration *vd);
@@ -171,7 +164,7 @@ private:
llvm::SmallVector<llvm::Metadata *, 16> &elems);
void AddStaticMembers(AggregateDeclaration *sd, ldc::DIFile file,
llvm::SmallVector<llvm::Metadata *, 16> &elems);
- DIFile CreateFile(Loc &loc);
+ DIFile CreateFile(const Loc &loc);
DIFile CreateFile();
DIFile CreateFile(Dsymbol* decl);
DIType CreateBasicType(Type *type);
diff --git a/gen/functions.cpp b/gen/functions.cpp
index 84f05e6b..1af45d08 100644
--- a/gen/functions.cpp
+++ b/gen/functions.cpp
@@ -892,12 +892,11 @@ void emitDMDStyleFunctionTrace(IRState &irs, FuncDeclaration *fd,
// Push cleanup block that calls _c_trace_epi at function exit.
{
auto traceEpilogBB = irs.insertBB("trace_epi");
- const auto savedInsertPoint = irs.getInsertPoint();
+ const auto savedInsertPoint = irs.saveInsertPoint();
irs.ir->SetInsertPoint(traceEpilogBB);
irs.ir->CreateCall(
getRuntimeFunction(fd->endloc, irs.module, "_c_trace_epi"));
funcGen.scopes.pushCleanup(traceEpilogBB, irs.scopebb());
- irs.setInsertPoint(savedInsertPoint);
}
}
@@ -1175,9 +1174,9 @@ void DtoDefineFunction(FuncDeclaration *fd, bool linkageAvailableExternally) {
llvm::BasicBlock::Create(gIR->context(), "", func);
// set up the IRBuilder scope for the function
- FunctionIRBuilderScope irBuilderScope(*gIR);
- gIR->setInsertPoint(beginbb);
+ const auto savedIRBuilderScope = gIR->setInsertPoint(beginbb);
gIR->ir->setFastMathFlags(irFunc->FMF);
+ gIR->DBuilder.EmitFuncStart(fd);
// @naked: emit body and return, no prologue/epilogue
if (func->hasFnAttribute(llvm::Attribute::Naked)) {
@@ -1200,9 +1199,6 @@ void DtoDefineFunction(FuncDeclaration *fd, bool linkageAvailableExternally) {
"alloca_point", beginbb);
funcGen.allocapoint = allocaPoint;
- // debug info - after all allocas, but before any llvm.dbg.declare etc
- gIR->DBuilder.EmitFuncStart(fd);
-
emitInstrumentationFnEnter(fd);
if (global.params.trace && fd->emitInstrumentation && !fd->isCMain() &&
@@ -1283,11 +1279,10 @@ void DtoDefineFunction(FuncDeclaration *fd, bool linkageAvailableExternally) {
{
auto *vaendBB =
llvm::BasicBlock::Create(gIR->context(), "vaend", gIR->topfunc());
- const auto savedInsertPoint = gIR->getInsertPoint();
+ const auto savedInsertPoint = gIR->saveInsertPoint();
gIR->ir->SetInsertPoint(vaendBB);
gIR->ir->CreateCall(GET_INTRINSIC_DECL(vaend), llAp);
funcGen.scopes.pushCleanup(vaendBB, gIR->scopebb());
- gIR->setInsertPoint(savedInsertPoint);
}
}
@@ -1328,7 +1323,6 @@ void DtoDefineFunction(FuncDeclaration *fd, bool linkageAvailableExternally) {
gIR->ir->CreateRet(llvm::UndefValue::get(func->getReturnType()));
}
}
- gIR->DBuilder.EmitFuncEnd(fd);
// erase alloca point
if (allocaPoint->getParent()) {
diff --git a/gen/irstate.cpp b/gen/irstate.cpp
index eb73ab41..54990b15 100644
--- a/gen/irstate.cpp
+++ b/gen/irstate.cpp
@@ -46,36 +46,15 @@ llvm::Function *IRState::topfunc() { return func()->getLLVMFunc(); }
llvm::Instruction *IRState::topallocapoint() { return funcGen().allocapoint; }
-InsertionPoint IRState::getInsertPoint() {
- auto bb = builder.GetInsertBlock();
- if (!bb)
- return {nullptr, llvm::None};
-
- llvm::Optional<llvm::BasicBlock::iterator> point = builder.GetInsertPoint();
- if (point == bb->end())
- point = llvm::None;
-
- return {bb, point};
-}
-
-void IRState::setInsertPoint(llvm::BasicBlock *insertAtEnd) {
- builder.SetInsertPoint(insertAtEnd);
-}
-
-void IRState::setInsertPoint(InsertionPoint point) {
- if (!point.bb) {
- builder.ClearInsertionPoint();
- } else if (!point.point.hasValue()) {
- builder.SetInsertPoint(point.bb);
- } else {
- builder.SetInsertPoint(point.bb, point.point.getValue());
- }
+std::unique_ptr<IRBuilderScope> IRState::setInsertPoint(llvm::BasicBlock *bb) {
+ auto savedScope = llvm::make_unique<IRBuilderScope>(builder);
+ builder.SetInsertPoint(bb);
+ return savedScope;
}
-llvm::BasicBlock *IRState::scopebb() {
- auto bb = ir->GetInsertBlock();
- assert(bb);
- return bb;
+std::unique_ptr<llvm::IRBuilderBase::InsertPointGuard>
+IRState::saveInsertPoint() {
+ return llvm::make_unique<llvm::IRBuilderBase::InsertPointGuard>(builder);
}
bool IRState::scopereturned() {
@@ -300,26 +279,9 @@ const Loc &IRState::getInlineAsmSrcLoc(unsigned srcLocCookie) const {
////////////////////////////////////////////////////////////////////////////////
-FunctionIRBuilderScope::FunctionIRBuilderScope(IRState &state)
- : state(state), previousInsertionPoint(state.getInsertPoint()),
- previousFMF(state.builder.getFastMathFlags()),
- previousDebugLoc(state.builder.getCurrentDebugLocation()) {
- state.builder.ClearInsertionPoint();
- state.builder.clearFastMathFlags();
- state.builder.SetCurrentDebugLocation({});
-}
-
-FunctionIRBuilderScope::~FunctionIRBuilderScope() {
- state.setInsertPoint(previousInsertionPoint);
- state.builder.setFastMathFlags(previousFMF);
- state.builder.SetCurrentDebugLocation(previousDebugLoc);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-
IRBuilder<> *IRBuilderHelper::operator->() {
IRBuilder<> &b = state->builder;
- assert(b.GetInsertBlock() != NULL);
+ assert(b.GetInsertBlock());
return &b;
}
diff --git a/gen/irstate.h b/gen/irstate.h
index 83a33310..37b9a119 100644
--- a/gen/irstate.h
+++ b/gen/irstate.h
@@ -58,28 +58,15 @@ class StructLiteralExp;
struct IrFunction;
struct IrModule;
-// insertion point for IRBuilder
-struct InsertionPoint {
- llvm::BasicBlock *bb; // can be null
- llvm::Optional<llvm::BasicBlock::iterator> point; // bb end if not set
-
- InsertionPoint(llvm::BasicBlock *bb,
- llvm::Optional<llvm::BasicBlock::iterator> point)
- : bb(bb), point(std::move(point)) {}
-};
-
-// Resets the IRBuilder for a new function and restores its previous state on
-// destruction.
-struct FunctionIRBuilderScope {
+// Saves the IRBuilder state and restores it on destruction.
+struct IRBuilderScope {
private:
- IRState &state;
- InsertionPoint previousInsertionPoint;
- llvm::FastMathFlags previousFMF;
- llvm::DebugLoc previousDebugLoc;
+ llvm::IRBuilderBase::InsertPointGuard ipGuard;
+ llvm::IRBuilderBase::FastMathFlagGuard fmfGuard;
public:
- FunctionIRBuilderScope(IRState &state);
- ~FunctionIRBuilderScope();
+ explicit IRBuilderScope(llvm::IRBuilderBase &builder)
+ : ipGuard(builder), fmfGuard(builder) {}
};
struct IRBuilderHelper {
@@ -123,7 +110,6 @@ struct IRAsmBlock {
struct IRState {
private:
IRBuilder<> builder;
- friend struct FunctionIRBuilderScope;
friend struct IRBuilderHelper;
std::vector<std::pair<llvm::GlobalVariable *, llvm::Constant *>>
@@ -169,11 +155,16 @@ public:
llvm::Function *topfunc();
llvm::Instruction *topallocapoint();
- // basic block scopes
- InsertionPoint getInsertPoint();
- void setInsertPoint(llvm::BasicBlock *insertAtEnd);
- void setInsertPoint(InsertionPoint point);
- llvm::BasicBlock *scopebb();
+ // Use this to set the IRBuilder's insertion point for a new function.
+ // The previous IRBuilder state is restored when the returned value is
+ // destructed. Use `ir->SetInsertPoint()` instead to change the insertion
+ // point inside the same function.
+ std::unique_ptr<IRBuilderScope> setInsertPoint(llvm::BasicBlock *bb);
+ // Use this to have the IRBuilder's current insertion point (incl. debug
+ // location) restored when the returned value is destructed.
+ std::unique_ptr<llvm::IRBuilderBase::InsertPointGuard> saveInsertPoint();
+ // Returns the basic block the IRBuilder currently inserts into.
+ llvm::BasicBlock *scopebb() { return ir->GetInsertBlock(); }
bool scopereturned();
// Creates a new basic block and inserts it before the specified one.
diff --git a/gen/passes/GarbageCollect2Stack.cpp b/gen/passes/GarbageCollect2Stack.cpp
index fc914762..cbac1620 100644
--- a/gen/passes/GarbageCollect2Stack.cpp
+++ b/gen/passes/GarbageCollect2Stack.cpp
@@ -217,17 +217,16 @@ public:
}
Value *promote(LLCallBasePtr CB, IRBuilder<> &B, const Analysis &A) override {
- IRBuilder<> Builder(B.GetInsertBlock(), B.GetInsertPoint());
-
// If the allocation is of constant size it's best to put it in the
// entry block, so do so if we're not already there.
// For dynamically-sized allocations it's best to avoid the overhead
// of allocating them if possible, so leave those where they are.
// While we're at it, update statistics too.
+ const IRBuilderBase::InsertPointGuard savedInsertPoint(B);
if (isa<Constant>(arrSize)) {
BasicBlock &Entry = CB->getCaller()->getEntryBlock();
- if (Builder.GetInsertBlock() != &Entry) {
- Builder.SetInsertPoint(&Entry, Entry.begin());
+ if (B.GetInsertBlock() != &Entry) {
+ B.SetInsertPoint(&Entry, Entry.begin());
}
NumGcToStack++;
} else {
@@ -235,9 +234,9 @@ public:
}
// Convert array size to 32 bits if necessary
- Value *count = Builder.CreateIntCast(arrSize, Builder.getInt32Ty(), false);
+ Value *count = B.CreateIntCast(arrSize, B.getInt32Ty(), false);
AllocaInst *alloca =
- Builder.CreateAlloca(Ty, count, ".nongc_mem"); // FIXME: align?
+ B.CreateAlloca(Ty, count, ".nongc_mem"); // FIXME: align?
if (Initialized) {
// For now, only zero-init is supported.
@@ -251,10 +250,10 @@ public:
if (ReturnType == ReturnType::Array) {
Value *arrStruct = llvm::UndefValue::get(CB->getType());
- arrStruct = Builder.CreateInsertValue(arrStruct, arrSize, 0);
+ arrStruct = B.CreateInsertValue(arrStruct, arrSize, 0);
Value *memPtr =
- Builder.CreateBitCast(alloca, PointerType::getUnqual(B.getInt8Ty()));
- arrStruct = Builder.CreateInsertValue(arrStruct, memPtr, 1);
+ B.CreateBitCast(alloca, PointerType::getUnqual(B.getInt8Ty()));
+ arrStruct = B.CreateInsertValue(arrStruct, memPtr, 1);
return arrStruct;
}
@@ -346,17 +345,16 @@ public:
}
Value *promote(LLCallBasePtr CB, IRBuilder<> &B, const Analysis &A) override {
- IRBuilder<> Builder(B.GetInsertBlock(), B.GetInsertPoint());
-
// If the allocation is of constant size it's best to put it in the
// entry block, so do so if we're not already there.
// For dynamically-sized allocations it's best to avoid the overhead
// of allocating them if possible, so leave those where they are.
// While we're at it, update statistics too.
+ const IRBuilderBase::InsertPointGuard savedInsertPoint(B);
if (isa<Constant>(SizeArg)) {
BasicBlock &Entry = CB->getCaller()->getEntryBlock();
- if (Builder.GetInsertBlock() != &Entry) {
- Builder.SetInsertPoint(&Entry, Entry.begin());
+ if (B.GetInsertBlock() != &Entry) {
+ B.SetInsertPoint(&Entry, Entry.begin());
}
NumGcToStack++;
} else {
@@ -364,11 +362,11 @@ public:
}
// Convert array size to 32 bits if necessary
- Value *count = Builder.CreateIntCast(SizeArg, Builder.getInt32Ty(), false);
+ Value *count = B.CreateIntCast(SizeArg, B.getInt32Ty(), false);
AllocaInst *alloca =
- Builder.CreateAlloca(Ty, count, ".nongc_mem"); // FIXME: align?
+ B.CreateAlloca(Ty, count, ".nongc_mem"); // FIXME: align?
- return Builder.CreateBitCast(alloca, CB->getType());
+ return B.CreateBitCast(alloca, CB->getType());
}
explicit UntypedMemoryFI(unsigned sizeArgNr)
diff --git a/gen/statements.cpp b/gen/statements.cpp
index 34266b4c..e5fc5932 100644
--- a/gen/statements.cpp
+++ b/gen/statements.cpp
@@ -1087,12 +1087,10 @@ public:
if (PGO.emitsInstrumentation()) {
llvm::BasicBlock *casecntr =
irs->insertBBBefore(casejumptargetbb, "casecntr");
- const auto savedInsertPoint = irs->getInsertPoint();
+ const auto savedInsertPoint = irs->saveInsertPoint();
irs->ir->SetInsertPoint(casecntr);
PGO.emitCounterIncrement(cs);
llvm::BranchInst::Create(casejumptargetbb, casecntr);
- irs->setInsertPoint(savedInsertPoint);
-
casejumptargetbb = casecntr;
}
diff --git a/gen/toir.cpp b/gen/toir.cpp
index 63aa1154..fcccfaec 100644
--- a/gen/toir.cpp
+++ b/gen/toir.cpp
@@ -187,12 +187,10 @@ namespace {
void pushVarDtorCleanup(IRState *p, VarDeclaration *vd) {
llvm::BasicBlock *beginBB = p->insertBB(llvm::Twine("dtor.") + vd->toChars());
- // TODO: Clean this up with push/pop insertion point methods.
- const auto savedInsertPoint = p->getInsertPoint();
+ const auto savedInsertPoint = p->saveInsertPoint();
p->ir->SetInsertPoint(beginBB);
toElemDtor(vd->edtor);
p->funcGen().scopes.pushCleanup(beginBB, p->scopebb());
- p->setInsertPoint(savedInsertPoint);
}
}
diff --git a/gen/trycatchfinally.cpp b/gen/trycatchfinally.cpp
index b18da5b7..835ed77b 100644
--- a/gen/trycatchfinally.cpp
+++ b/gen/trycatchfinally.cpp
@@ -218,7 +218,7 @@ void emitBeginCatchMSVC(IRState &irs, Catch *ctch,
// redirect scope to avoid the generation of debug info before the
// catchpad
- const auto savedInsertPoint = irs.getInsertPoint();
+ const auto savedInsertPoint = irs.saveInsertPoint();
irs.ir->SetInsertPoint(gIR->topallocapoint());
DtoDeclarationExp(var);
@@ -231,9 +231,6 @@ void emitBeginCatchMSVC(IRState &irs, Catch *ctch,
cpyObj = exnObj;
exnObj = DtoAlloca(var->type, "exnObj");
}
- irs.setInsertPoint(savedInsertPoint);
- irs.DBuilder.EmitStopPoint(ctch->loc); // re-set debug loc after the
- // SetInsertPoint(allocaInst) call
} else if (ctch->type) {
// catch without var
exnObj = DtoAlloca(ctch->type, "exnObj");
@@ -692,7 +689,7 @@ llvm::BasicBlock *TryCatchFinallyScopes::emitLandingPad() {
}
// save and rewrite scope
- const auto savedInsertPoint = irs.getInsertPoint();
+ const auto savedInsertPoint = irs.saveInsertPoint();
// insert landing pads at the end of the function, in emission order,
// to improve human-readability of the IR
@@ -768,7 +765,6 @@ llvm::BasicBlock *TryCatchFinallyScopes::emitLandingPad() {
irs.ir->CreateBr(resumeUnwindBlock);
}
- irs.setInsertPoint(savedInsertPoint);
return beginBB;
}
@@ -847,8 +843,7 @@ TryCatchFinallyScopes::runCleanupPad(CleanupCursor scope,
// can place an exception frame (but not done here)
auto frame = getNullPtr(getVoidPtrType());
- auto savedInsertPoint = irs.getInsertPoint();
- auto savedDbgLoc = irs.DBuilder.GetCurrentLoc();
+ const auto savedInsertPoint = irs.saveInsertPoint();
auto endFn = getRuntimeFunction(Loc(), irs.module, "_d_leave_cleanup");
irs.ir->SetInsertPoint(cleanupret);
@@ -867,8 +862,5 @@ TryCatchFinallyScopes::runCleanupPad(CleanupCursor scope,
beginFn, frame, {llvm::OperandBundleDef("funclet", cleanuppad)}, "");
llvm::BranchInst::Create(copybb, cleanupret, exec, cleanupbb);
- irs.setInsertPoint(savedInsertPoint);
- irs.DBuilder.EmitStopPoint(savedDbgLoc);
-
return cleanupbb;
}
diff --git a/ir/irclass.cpp b/ir/irclass.cpp
index 8eecc2cd..0d74614e 100644
--- a/ir/irclass.cpp
+++ b/ir/irclass.cpp
@@ -562,9 +562,7 @@ void IrClass::defineInterfaceVtbl(BaseClass *b, bool new_instance,
llvm::BasicBlock::Create(gIR->context(), "", thunk);
// set up the IRBuilder scope for the thunk
- FunctionIRBuilderScope irBuilderScope(*gIR);
- gIR->setInsertPoint(beginbb);
-
+ const auto savedIRBuilderScope = gIR->setInsertPoint(beginbb);
gIR->DBuilder.EmitFuncStart(thunkFd);
// Copy the function parameters, so later we can pass them to the
@@ -607,8 +605,6 @@ void IrClass::defineInterfaceVtbl(BaseClass *b, bool new_instance,
llvm::ReturnInst::Create(gIR->context(), call, beginbb);
}
- gIR->DBuilder.EmitFuncEnd(thunkFd);
-
gIR->funcGenStates.pop_back();
}
--
2.29.0
From 4b7f14f58d8a6bae056b8b5254c2c8f96a0636a0 Mon Sep 17 00:00:00 2001
From: Martin Kinkelin <noone@nowhere.com>
Date: Wed, 26 Aug 2020 00:31:31 +0200
Subject: [PATCH 09/16] Hide new LLVM 11 CLI options
---
driver/cl_options.cpp | 44 +++++++++++++++++++++++++++----------------
1 file changed, 28 insertions(+), 16 deletions(-)
diff --git a/driver/cl_options.cpp b/driver/cl_options.cpp
index 40afb6dd..25c13bf0 100644
--- a/driver/cl_options.cpp
+++ b/driver/cl_options.cpp
@@ -620,17 +620,24 @@ void hideLLVMOptions() {
static const char *const hiddenOptions[] = {
"aarch64-neon-syntax", "addrsig", "arm-add-build-attributes",
"arm-implicit-it", "asm-instrumentation", "asm-show-inst",
- "atomic-counter-update-promoted", "bounds-checking-single-trap",
+ "atomic-counter-update-promoted", "atomic-first-counter",
+ "basicblock-sections", "bounds-checking-single-trap",
+ "cfg-hide-deoptimize-paths", "cfg-hide-unreachable-paths",
"code-model", "cost-kind", "cppfname", "cppfor", "cppgen",
"cvp-dont-add-nowrap-flags",
"cvp-dont-process-adds", "debug-counter", "debug-entry-values",
- "debugger-tune", "denormal-fp-math", "disable-debug-info-verifier",
+ "debugger-tune", "debugify-level", "debugify-quiet",
+ "denormal-fp-math", "denormal-fp-math-f32", "disable-debug-info-verifier",
"disable-objc-arc-checkforcfghazards", "disable-spill-fusing",
- "do-counter-promotion", "emscripten-cxx-exceptions-whitelist",
+ "do-counter-promotion", "dwarf64", "emit-call-site-info",
+ "emscripten-cxx-exceptions-allowed",
+ "emscripten-cxx-exceptions-whitelist",
"emulated-tls", "enable-correct-eh-support",
"enable-cse-in-irtranslator", "enable-cse-in-legalizer",
"enable-emscripten-cxx-exceptions", "enable-emscripten-sjlj",
- "enable-fp-mad", "enable-gvn-memdep", "enable-implicit-null-checks",
+ "enable-fp-mad", "enable-gvn-hoist", "enable-gvn-memdep",
+ "enable-gvn-sink", "enable-implicit-null-checks",
+ "enable-load-in-loop-pre",
"enable-load-pre", "enable-loop-simplifycfg-term-folding",
"enable-misched", "enable-name-compression", "enable-no-infs-fp-math",
"enable-no-nans-fp-math", "enable-no-signed-zeros-fp-math",
@@ -640,23 +647,27 @@ void hideLLVMOptions() {
"exhaustive-register-search", "expensive-combines",
"fatal-assembler-warnings", "filter-print-funcs",
"force-dwarf-frame-section", "gpsize", "hash-based-counter-split",
+ "hot-cold-split",
"imp-null-check-page-size", "imp-null-max-insts-to-consider",
"import-all-index", "incremental-linker-compatible",
"instcombine-code-sinking", "instcombine-guard-widening-window",
"instcombine-max-iterations", "instcombine-max-num-phis",
- "instcombine-maxarray-size", "instrprof-atomic-counter-update-all",
- "internalize-public-api-file",
+ "instcombine-maxarray-size", "instcombine-negator-enabled",
+ "instcombine-negator-max-depth",
+ "instrprof-atomic-counter-update-all", "internalize-public-api-file",
"internalize-public-api-list", "iterative-counter-promotion",
"join-liveintervals", "jump-table-type", "limit-float-precision",
- "lto-embed-bitcode", "matrix-propagate-shape",
+ "lto-embed-bitcode", "matrix-default-layout", "matrix-propagate-shape",
"max-counter-promotions", "max-counter-promotions-per-loop",
"mc-relax-all", "mc-x86-disable-arith-relaxation", "meabi",
"memop-size-large", "memop-size-range", "merror-missing-parenthesis",
"merror-noncontigious-register", "mfuture-regs", "mips-compact-branches",
- "mips16-constant-islands", "mips16-hard-float", "mlsm", "mno-compound",
+ "mips16-constant-islands", "mips16-hard-float", "mir-strip-debugify-only",
+ "mlsm", "mno-compound",
"mno-fixup", "mno-ldc1-sdc1", "mno-pairing", "mwarn-missing-parenthesis",
"mwarn-noncontigious-register", "mwarn-sign-mismatch",
- "no-discriminators", "nozero-initialized-in-bss", "nvptx-sched4reg",
+ "no-discriminators", "no-xray-index",
+ "nozero-initialized-in-bss", "nvptx-sched4reg",
"objc-arc-annotation-target-identifier", "pie-copy-relocations",
"poison-checking-function-local",
"polly-dump-after", "polly-dump-after-file", "polly-dump-before",
@@ -666,7 +677,7 @@ void hideLLVMOptions() {
"profile-file", "profile-info-file", "profile-verifier-noassert",
"r600-ir-structurize", "rdf-dump", "rdf-limit", "recip", "regalloc",
"relax-elf-relocations", "remarks-section", "rewrite-map-file", "rng-seed",
- "safepoint-ir-verifier-print-only",
+ "runtime-counter-relocation", "safepoint-ir-verifier-print-only",
"sample-profile-check-record-coverage",
"sample-profile-check-sample-coverage",
"sample-profile-inline-hot-threshold",
@@ -674,14 +685,15 @@ void hideLLVMOptions() {
"speculative-counter-promotion-max-exiting",
"speculative-counter-promotion-to-loop", "spiller", "spirv-debug",
"spirv-erase-cl-md", "spirv-lower-const-expr", "spirv-mem2reg",
- "spirv-no-deref-attr", "spirv-text", "spvbool-validate",
+ "spirv-no-deref-attr", "spirv-text",
+ "spv-lower-saddwithoverflow-validate", "spvbool-validate",
"spvmemmove-validate",
"stack-alignment", "stack-size-section", "stack-symbol-ordering",
"stackmap-version", "static-func-full-module-prefix",
"static-func-strip-dirname-prefix", "stats", "stats-json", "strip-debug",
- "struct-path-tbaa", "summary-file", "tailcallopt", "thread-model",
- "time-passes", "time-trace-granularity", "tls-size",
- "unfold-element-atomic-memcpy-max-elements",
+ "struct-path-tbaa", "summary-file", "tail-predication", "tailcallopt",
+ "thread-model", "time-passes", "time-trace-granularity", "tls-size",
+ "unfold-element-atomic-memcpy-max-elements", "unique-bb-section-names",
"unique-section-names", "unit-at-a-time", "use-ctors",
"verify-debug-info", "verify-dom-info", "verify-loop-info",
"verify-loop-lcssa", "verify-machine-dom-info", "verify-regalloc",
@@ -689,6 +701,7 @@ void hideLLVMOptions() {
"vp-counters-per-site", "vp-static-alloc",
"x86-align-branch", "x86-align-branch-boundary",
"x86-branches-within-32B-boundaries", "x86-early-ifcvt",
+ "x86-pad-max-prefix-size",
"x86-recip-refinement-steps", "x86-use-vzeroupper",
// We enable -fdata-sections/-ffunction-sections by default where it makes
@@ -697,8 +710,7 @@ void hideLLVMOptions() {
// We need our own switch as these two are defined by LLVM and linked to
// static TargetMachine members, but the default we want to use depends
// on the target triple (and thus we do not know it until after the
- // command
- // line has been parsed).
+ // command line has been parsed).
"fdata-sections", "ffunction-sections", "data-sections",
"function-sections"};
--
2.29.0
From 7aea2e73e9b1af5985ddf44eaf18af5483ffab97 Mon Sep 17 00:00:00 2001
From: Martin Kinkelin <noone@nowhere.com>
Date: Wed, 26 Aug 2020 01:08:01 +0200
Subject: [PATCH 10/16] Adapt dynamic-compile/JIT stuff for LLVM 11
---
.azure-pipelines/posix.yml | 3 +-
.azure-pipelines/windows.yml | 1 -
CMakeLists.txt | 7 +----
gen/dynamiccompile.cpp | 9 ++++--
runtime/jit-rt/cpp-so/bind.cpp | 12 ++++++--
runtime/jit-rt/cpp-so/disassembler.cpp | 38 ++++++++++++++++++++++----
runtime/jit-rt/cpp-so/jit_context.cpp | 5 ++++
7 files changed, 57 insertions(+), 18 deletions(-)
diff --git a/.azure-pipelines/posix.yml b/.azure-pipelines/posix.yml
index 15c2a559..2c2598b7 100644
--- a/.azure-pipelines/posix.yml
+++ b/.azure-pipelines/posix.yml
@@ -378,8 +378,7 @@ steps:
cd ..
installed/bin/ldc2 -enable-dynamic-compile -run $BUILD_SOURCESDIRECTORY/tests/dynamiccompile/array.d
displayName: Run dynamic-compile integration test
- #condition: and(succeeded(), ne(variables['CI_OS'], 'android'))
- condition: not(always())
+ condition: and(succeeded(), ne(variables['CI_OS'], 'android'))
# Add dub & dlang tools
- script: |
diff --git a/.azure-pipelines/windows.yml b/.azure-pipelines/windows.yml
index c2fc43da..09f9e370 100644
--- a/.azure-pipelines/windows.yml
+++ b/.azure-pipelines/windows.yml
@@ -172,7 +172,6 @@ steps:
call "%VSINSTALLDIR%Common7\Tools\VsDevCmd.bat" -arch=%ARCH%
installed\bin\ldc2 -enable-dynamic-compile -run %BUILD_SOURCESDIRECTORY%/tests/dynamiccompile/array.d
displayName: Run dynamic-compile integration test
- condition: not(always())
- script: |
cd ..
call "%VSINSTALLDIR%Common7\Tools\VsDevCmd.bat" -arch=%ARCH%
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 46c2d3ae..d6f7c596 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -450,12 +450,7 @@ include(HandleLTOPGOBuildOptions)
set(LDC_DYNAMIC_COMPILE "AUTO" CACHE STRING "Support dynamic compilation (ON|OFF). Enabled by default.")
option(LDC_DYNAMIC_COMPILE_USE_CUSTOM_PASSES "Use custom LDC passes in jit" ON)
if(LDC_DYNAMIC_COMPILE STREQUAL "AUTO")
- if(LDC_LLVM_VER LESS 1100)
- set(LDC_DYNAMIC_COMPILE ON)
- else()
- # FIXME: support LLVM 11+ too
- set(LDC_DYNAMIC_COMPILE OFF)
- endif()
+ set(LDC_DYNAMIC_COMPILE ON)
endif()
message(STATUS "Building LDC with dynamic compilation support: ${LDC_DYNAMIC_COMPILE} (LDC_DYNAMIC_COMPILE=${LDC_DYNAMIC_COMPILE})")
if(LDC_DYNAMIC_COMPILE)
diff --git a/gen/dynamiccompile.cpp b/gen/dynamiccompile.cpp
index d59cd00f..05d613d6 100644
--- a/gen/dynamiccompile.cpp
+++ b/gen/dynamiccompile.cpp
@@ -193,8 +193,8 @@ void stripModule(llvm::Module &module) {
void fixRtModule(llvm::Module &newModule,
const decltype(IRState::dynamicCompiledFunctions) &funcs) {
- std::unordered_map<std::string, std::string> thunkVar2func;
- std::unordered_map<std::string, std::string> thunkFun2func;
+ std::unordered_map<std::string, llvm::StringRef> thunkVar2func;
+ std::unordered_map<std::string, llvm::StringRef> thunkFun2func;
std::unordered_set<std::string> externalFuncs;
for (auto &&it : funcs) {
assert(nullptr != it.first);
@@ -769,7 +769,12 @@ void createThunkFunc(llvm::Module &module, const llvm::Function *src,
for (auto &arg : dst->args()) {
args.push_back(&arg);
}
+#if LDC_LLVM_VER >= 1100
+ auto ret = builder.CreateCall(
+ llvm::FunctionCallee(dst->getFunctionType(), thunkPtr), args);
+#else
auto ret = builder.CreateCall(thunkPtr, args);
+#endif
ret->setCallingConv(src->getCallingConv());
ret->setAttributes(src->getAttributes());
if (dst->getReturnType()->isVoidTy()) {
diff --git a/runtime/jit-rt/cpp-so/bind.cpp b/runtime/jit-rt/cpp-so/bind.cpp
index 37cb7e79..e1a0bea3 100644
--- a/runtime/jit-rt/cpp-so/bind.cpp
+++ b/runtime/jit-rt/cpp-so/bind.cpp
@@ -19,8 +19,14 @@
#include "valueparser.h"
#if LDC_LLVM_VER >= 1000
+#if LDC_LLVM_VER >= 1100
+#define LLAlign llvm::Align
+#else
+#define LLAlign llvm::MaybeAlign
+#endif
#define LLMaybeAlign llvm::MaybeAlign
#else
+#define LLAlign
#define LLMaybeAlign
#endif
@@ -77,14 +83,16 @@ allocParam(llvm::IRBuilder<> &builder, llvm::Type &srcType,
if (param.type == ParamType::Aggregate && srcType.isPointerTy()) {
auto elemType = llvm::cast<llvm::PointerType>(&srcType)->getElementType();
auto stackArg = builder.CreateAlloca(elemType);
- stackArg->setAlignment(LLMaybeAlign(layout.getABITypeAlignment(elemType)));
+ if (auto alignment = layout.getABITypeAlignment(elemType))
+ stackArg->setAlignment(LLAlign(alignment));
auto init =
parseInitializer(layout, *elemType, param.data, errHandler, override);
builder.CreateStore(init, stackArg);
return stackArg;
}
auto stackArg = builder.CreateAlloca(&srcType);
- stackArg->setAlignment(LLMaybeAlign(layout.getABITypeAlignment(&srcType)));
+ if (auto alignment = layout.getABITypeAlignment(&srcType))
+ stackArg->setAlignment(LLAlign(alignment));
auto init =
parseInitializer(layout, srcType, param.data, errHandler, override);
builder.CreateStore(init, stackArg);
diff --git a/runtime/jit-rt/cpp-so/disassembler.cpp b/runtime/jit-rt/cpp-so/disassembler.cpp
index 79e47761..eda0be22 100644
--- a/runtime/jit-rt/cpp-so/disassembler.cpp
+++ b/runtime/jit-rt/cpp-so/disassembler.cpp
@@ -135,11 +135,21 @@ void printFunction(const llvm::MCDisassembler &disasm,
switch (status) {
case llvm::MCDisassembler::Fail:
- streamer.EmitRawText("failed to disassemble");
+#if LDC_LLVM_VER >= 1100
+ streamer.emitRawText(
+#else
+ streamer.EmitRawText(
+#endif
+ "failed to disassemble");
return;
case llvm::MCDisassembler::SoftFail:
- streamer.EmitRawText("potentially undefined instruction encoding:");
+#if LDC_LLVM_VER >= 1100
+ streamer.emitRawText(
+#else
+ streamer.EmitRawText(
+#endif
+ "potentially undefined instruction encoding:");
LLVM_FALLTHROUGH;
case llvm::MCDisassembler::Success:
@@ -152,14 +162,22 @@ void printFunction(const llvm::MCDisassembler &disasm,
}
} else if (Stage::Emit == stage) {
if (auto label = symTable.getTargetLabel(pos)) {
+#if LDC_LLVM_VER >= 1100
+ streamer.emitLabel(label);
+#else
streamer.EmitLabel(label);
+#endif
}
commentStream.flush();
if (!comment.empty()) {
streamer.AddComment(comment);
comment.clear();
}
+#if LDC_LLVM_VER >= 1100
+ streamer.emitInstruction(inst, sti);
+#else
streamer.EmitInstruction(inst, sti);
+#endif
}
break;
}
@@ -304,7 +322,11 @@ void disassemble(const llvm::TargetMachine &tm,
for (const auto &symbol : object.symbols()) {
const auto secIt = llvm::cantFail(symbol.getSection());
if (object.section_end() != secIt) {
+#if LDC_LLVM_VER >= 1100
+ auto offset = llvm::cantFail(symbol.getValue());
+#else
auto offset = symbol.getValue();
+#endif
sectionsToProcess[secIt->getIndex()].push_back(offset);
}
}
@@ -322,9 +344,7 @@ void disassemble(const llvm::TargetMachine &tm,
const auto sec = *secIt;
llvm::StringRef data;
#if LDC_LLVM_VER >= 900
- auto dataOrError = sec.getContents();
- assert(dataOrError);
- data = *dataOrError;
+ data = llvm::cantFail(sec.getContents());
#else
sec.getContents(data);
#endif
@@ -333,7 +353,11 @@ void disassemble(const llvm::TargetMachine &tm,
llvm::cantFail(symbol.getType())) {
symTable.reset();
symTable.addLabel(0, 0, name); // Function start
+#if LDC_LLVM_VER >= 1100
+ auto offset = llvm::cantFail(symbol.getValue());
+#else
auto offset = symbol.getValue();
+#endif
processRelocations(symTable, offset, object, sec);
// TODO: something more optimal
@@ -360,7 +384,11 @@ void disassemble(const llvm::TargetMachine &tm,
reinterpret_cast<const uint8_t *>(data.data() + offset), size);
printFunction(*disasm, *mcia, buff, symTable, *sti, *asmStreamer);
+#if LDC_LLVM_VER >= 1100
+ asmStreamer->emitRawText("");
+#else
asmStreamer->EmitRawText("");
+#endif
}
}
}
diff --git a/runtime/jit-rt/cpp-so/jit_context.cpp b/runtime/jit-rt/cpp-so/jit_context.cpp
index 2a783e18..ad4378eb 100644
--- a/runtime/jit-rt/cpp-so/jit_context.cpp
+++ b/runtime/jit-rt/cpp-so/jit_context.cpp
@@ -202,7 +202,12 @@ std::shared_ptr<llvm::orc::SymbolResolver>
DynamicCompilerContext::createResolver() {
return llvm::orc::createLegacyLookupResolver(
execSession,
+#if LDC_LLVM_VER >= 1100
+ [this](llvm::StringRef name_) -> llvm::JITSymbol {
+ const std::string name = name_.str();
+#else
[this](const std::string &name) -> llvm::JITSymbol {
+#endif
if (auto Sym = compileLayer.findSymbol(name, false)) {
return Sym;
} else if (auto Err = Sym.takeError()) {
--
2.29.0
From c8889a9219a7d6ae96f81d020ae6d8f760e84297 Mon Sep 17 00:00:00 2001
From: Martin Kinkelin <noone@nowhere.com>
Date: Wed, 26 Aug 2020 12:30:21 +0200
Subject: [PATCH 11/16] Fix alignment issue when casting vector rvalue to
static array
Previously, the static-array alloca wasn't suitably aligned for the
store instruction, which uses the greater vector alignment.
This has surfaced now with LLVM 11 on Win32 - this fixes dmd-testsuite's
runnable/ldc_llvm_inline_ir.d.
---
gen/llvmhelpers.cpp | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/gen/llvmhelpers.cpp b/gen/llvmhelpers.cpp
index 6024d827..8b5ff3c4 100644
--- a/gen/llvmhelpers.cpp
+++ b/gen/llvmhelpers.cpp
@@ -637,8 +637,7 @@ DValue *DtoCastVector(Loc &loc, DValue *val, Type *to) {
LLValue *vector = DtoRVal(val);
IF_LOG Logger::cout() << "src: " << *vector << "to type: " << *tolltype
<< " (creating temporary)\n";
- LLValue *array = DtoAlloca(to);
- DtoStore(vector, DtoBitCast(array, getPtrToType(vector->getType())));
+ LLValue *array = DtoAllocaDump(vector, tolltype, DtoAlignment(val->type));
return new DLValue(to, array);
}
if (totype->ty == Tvector && to->size() == val->type->size()) {
--
2.29.0
From 76de43f6c2f3ba211095ce0b36d8cff44ae50a39 Mon Sep 17 00:00:00 2001
From: Martin Kinkelin <noone@nowhere.com>
Date: Wed, 26 Aug 2020 17:26:16 +0200
Subject: [PATCH 12/16] Disable lit-test instrument/xray_link.d for Mac and
LLVM 11+
---
tests/instrument/xray_link.d | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/tests/instrument/xray_link.d b/tests/instrument/xray_link.d
index 3f2079c5..6ef69dd6 100644
--- a/tests/instrument/xray_link.d
+++ b/tests/instrument/xray_link.d
@@ -1,5 +1,9 @@
// REQUIRES: XRay_RT
+// fails on macOS with LLVM 11 due to a linker error, see
+// https://github.com/llvm/llvm-test-suite/commit/2c3c4a6286d453f763c0245c6536ddd368f0db99
+// XFAIL: Darwin && atleast_llvm1100
+
// RUN: %ldc -fxray-instrument -fxray-instruction-threshold=1 -of=%t%exe %s -vv | FileCheck %s
void foo()
--
2.29.0
From ca05705af6bc8a9d58821e3a3646cc6bfa5020de Mon Sep 17 00:00:00 2001
From: Martin Kinkelin <noone@nowhere.com>
Date: Tue, 1 Sep 2020 00:17:44 +0200
Subject: [PATCH 13/16] Azure CI: Bump LDC-LLVM to v11.0.0-rc2+
---
azure-pipelines.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/azure-pipelines.yml b/azure-pipelines.yml
index ac415714..8b0f9fee 100644
--- a/azure-pipelines.yml
+++ b/azure-pipelines.yml
@@ -1,5 +1,5 @@
variables:
- LLVM_VERSION: b3db88a4
+ LLVM_VERSION: 887792a5
CLANG_VERSION: 10.0.1
HOST_LDC_VERSION: 1.22.0
--
2.29.0
From aa7d38ff7ee6f771539e40a3c5ad532c4e755304 Mon Sep 17 00:00:00 2001
From: Martin Kinkelin <noone@nowhere.com>
Date: Tue, 22 Sep 2020 21:04:07 +0200
Subject: [PATCH 14/16] Azure CI: Bump LDC-LLVM to ~v11.0.0-rc3
---
azure-pipelines.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/azure-pipelines.yml b/azure-pipelines.yml
index 8b0f9fee..459948e1 100644
--- a/azure-pipelines.yml
+++ b/azure-pipelines.yml
@@ -1,5 +1,5 @@
variables:
- LLVM_VERSION: 887792a5
+ LLVM_VERSION: cc7582ff
CLANG_VERSION: 10.0.1
HOST_LDC_VERSION: 1.22.0
--
2.29.0
From 5b0a046fd63a4aef559815afac9461a76d8cb5d2 Mon Sep 17 00:00:00 2001
From: Martin Kinkelin <noone@nowhere.com>
Date: Tue, 29 Sep 2020 03:38:09 +0200
Subject: [PATCH 15/16] CI: Bump LDC-LLVM to v11.0.0-rc4
---
azure-pipelines.yml | 2 +-
shippable.yml | 4 ++--
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/azure-pipelines.yml b/azure-pipelines.yml
index 459948e1..cf37e6ea 100644
--- a/azure-pipelines.yml
+++ b/azure-pipelines.yml
@@ -1,5 +1,5 @@
variables:
- LLVM_VERSION: cc7582ff
+ LLVM_VERSION: f13ab423
CLANG_VERSION: 10.0.1
HOST_LDC_VERSION: 1.22.0
diff --git a/shippable.yml b/shippable.yml
index e98d00a8..3e47fb57 100644
--- a/shippable.yml
+++ b/shippable.yml
@@ -13,7 +13,7 @@ env:
global:
- secure: RQ6gpJFPBDGVlnz+ZzSgeMpkcnvcA/7Lzyj/r06fMFR5iOz2cYaImCekNRw2PlhYQ+0FCQ119TLMKNOa7OUu6XxUp5LZtq7pSB6QLe3RB3YysFsosNPlY/wyyRsrW9ICEbDP/X8kPcfrDtOPGS/dGIwgeo0+R4Yl0OLDK9GrExEY45bWgvuLqoWDO89pi31kBk5LG5MAYhHZ0UTdboi5A2GRT0T8M0kr53jBRka8FGkbncXfHp9+/6IjTVJoUduRkdsk0A9RN1KRoao6rtrBNNvwIStc6zxJSOHszoaTp/K/ucGC4InZl/9GHPS/Y78SGKn7YJv3tGmcGzqAxrVaXQ==
matrix:
- - LLVM_VERSION=10.0.1
+ - LLVM_VERSION=f13ab423
HOST_LDC_VERSION=1.22.0
EXTRA_CMAKE_FLAGS="-DBUILD_LTO_LIBS=ON -DCMAKE_EXE_LINKER_FLAGS=-static-libstdc++ -DJITRT_EXTRA_LDFLAGS=-static-libstdc++ -DLDC_INSTALL_LTOPLUGIN=ON -DLDC_INSTALL_LLVM_RUNTIME_LIBS=ON -DLDC_INSTALL_LLVM_RUNTIME_LIBS_ARCH=aarch64"
@@ -39,7 +39,7 @@ build:
echo 'Using LLVM with enabled assertions'
assertsSuffix="-withAsserts"
fi
- curl -L -o llvm.tar.xz https://github.com/ldc-developers/llvm-project/releases/download/ldc-v$LLVM_VERSION/llvm-$LLVM_VERSION-linux-aarch64$assertsSuffix.tar.xz
+ curl -L -o llvm.tar.xz https://github.com/ldc-developers/llvm-project/releases/download/CI/llvm-$LLVM_VERSION-linux-aarch64$assertsSuffix.tar.xz
- mkdir llvm
- tar -xf llvm.tar.xz --strip 1 -C llvm
- rm llvm.tar.xz
--
2.29.0
From 92ec0435e61f49ea20b70c3e10e9749eb8bd231b Mon Sep 17 00:00:00 2001
From: Martin Kinkelin <noone@nowhere.com>
Date: Wed, 30 Sep 2020 17:29:40 +0200
Subject: [PATCH 16/16] CI: Bump LDC-LLVM to v11.0.0-rc4+ with AArch64
regression fix
---
azure-pipelines.yml | 2 +-
shippable.yml | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/azure-pipelines.yml b/azure-pipelines.yml
index cf37e6ea..f404b3a9 100644
--- a/azure-pipelines.yml
+++ b/azure-pipelines.yml
@@ -1,5 +1,5 @@
variables:
- LLVM_VERSION: f13ab423
+ LLVM_VERSION: 84863923
CLANG_VERSION: 10.0.1
HOST_LDC_VERSION: 1.22.0
diff --git a/shippable.yml b/shippable.yml
index 3e47fb57..d4ce5c8e 100644
--- a/shippable.yml
+++ b/shippable.yml
@@ -13,7 +13,7 @@ env:
global:
- secure: RQ6gpJFPBDGVlnz+ZzSgeMpkcnvcA/7Lzyj/r06fMFR5iOz2cYaImCekNRw2PlhYQ+0FCQ119TLMKNOa7OUu6XxUp5LZtq7pSB6QLe3RB3YysFsosNPlY/wyyRsrW9ICEbDP/X8kPcfrDtOPGS/dGIwgeo0+R4Yl0OLDK9GrExEY45bWgvuLqoWDO89pi31kBk5LG5MAYhHZ0UTdboi5A2GRT0T8M0kr53jBRka8FGkbncXfHp9+/6IjTVJoUduRkdsk0A9RN1KRoao6rtrBNNvwIStc6zxJSOHszoaTp/K/ucGC4InZl/9GHPS/Y78SGKn7YJv3tGmcGzqAxrVaXQ==
matrix:
- - LLVM_VERSION=f13ab423
+ - LLVM_VERSION=84863923
HOST_LDC_VERSION=1.22.0
EXTRA_CMAKE_FLAGS="-DBUILD_LTO_LIBS=ON -DCMAKE_EXE_LINKER_FLAGS=-static-libstdc++ -DJITRT_EXTRA_LDFLAGS=-static-libstdc++ -DLDC_INSTALL_LTOPLUGIN=ON -DLDC_INSTALL_LLVM_RUNTIME_LIBS=ON -DLDC_INSTALL_LLVM_RUNTIME_LIBS_ARCH=aarch64"
--
2.29.0