6729 lines
257 KiB
Diff
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
|
|
|