From 69269f3bd968dbb90de52b245827bd61b4f6afe0 Mon Sep 17 00:00:00 2001 From: Martin Kinkelin 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 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 point; // bb end if not set + + InsertionPoint(llvm::BasicBlock *bb, + llvm::Optional 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> globalsToReplace; Array inlineAsmLocs; // tracked by GC @@ -155,8 +171,9 @@ public: llvm::Instruction *topallocapoint(); // basic block scopes - std::vector 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 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 subscripts; while (t->ty == Tsarray) { TypeSArray *tsa = static_cast(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 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 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 &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 &Path16); } -} -} +#endif // LDC_LLVM_VER < 1100 +} // namespace sys +} // namespace llvm // Returns true upon error. namespace { template @@ -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 wide_from; llvm::SmallVector 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 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 disableFPElim("disable-fp-elim", cl::ZeroOrMore, cl::ReallyHidden, @@ -32,19 +36,41 @@ static cl::opt // 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 getRelocModel() { return ::getRelocModel(); } +Optional getRelocModel() { +#if LDC_LLVM_VER >= 1100 + return codegen::getExplicitRelocModel(); +#else + return ::getRelocModel(); +#endif +} -Optional getCodeModel() { return ::getCodeModel(); } +Optional getCodeModel() { +#if LDC_LLVM_VER >= 1100 + return codegen::getExplicitCodeModel(); +#else + return ::getCodeModel(); +#endif +} #if LDC_LLVM_VER >= 800 llvm::Optional 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 getRelocModelFromCMModel() { return ::getRelocModel(); } +Optional getRelocModelFromCMModel() { + return ::opts::getRelocModel(); +} #endif #if LDC_LLVM_VER >= 900 Optional getCodeModelFromCMModel() { - return ::getCodeModel(); -} #else Optional 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 getMAttrs() { return codegen::getMAttrs(); } +#elif LDC_LLVM_VER >= 900 std::vector getMAttrs() { return ::MAttrs; } #elif LDC_LLVM_VER >= 800 std::vector 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 &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 parseLibNames(llvm::StringRef commaSeparatedList, llvm::StringRef suffix = {}) { std::vector 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 args, - const char *name, bool isNothrow) { +llvm::CallBase *FuncGenState::callOrInvoke(llvm::Value *callee, + llvm::FunctionType *calleeType, + llvm::ArrayRef 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(callee); @@ -123,8 +124,14 @@ llvm::CallSite FuncGenState::callOrInvoke(llvm::Value *callee, // calls inside a funclet must be annotated with its value llvm::SmallVector 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 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 args, - const char *name = "", bool isNothrow = false); + llvm::CallBase *callOrInvoke(llvm::Value *callee, + llvm::FunctionType *calleeType, + llvm::ArrayRef 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 Args, - const char *Name, bool isNothrow) { - return funcGen().callOrInvoke(Callee, Args, Name, isNothrow); +llvm::Instruction *IRState::CreateCallOrInvoke(LLFunction *Callee, + llvm::ArrayRef 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(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 #include @@ -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 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 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(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(dtype); +#else + auto vectorType = llvm::cast(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(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(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(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(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(CS.getInstruction()); - + if (auto Invoke = dyn_cast(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(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(&(*(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(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(I); - if (CI->isTailCall()) { - RemoveTailCallInsts.push_back(CI); + if (auto call = dyn_cast(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(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(tv->basetype); uint64_t dim = static_cast(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 + +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()) { + 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 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 File; + DenseMap RemappingTable; + +public: + /// Build a SymbolRemapper from a file containing a list of old/new symbols. + static std::unique_ptr create(StringRef InputFile) { + auto BufOrError = MemoryBuffer::getFileOrSTDIN(InputFile); + if (!BufOrError) + exitWithErrorCode(BufOrError.getError(), InputFile); + + auto Remapper = std::make_unique(); + Remapper->File = std::move(BufOrError.get()); + + for (line_iterator LineIt(*Remapper->File, /*SkipBlanks=*/true, '#'); + !LineIt.is_at_eof(); ++LineIt) { + std::pair 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 WeightedFileVector; + +/// Keep track of merged data and reported errors. +struct WriterContext { + std::mutex Lock; + InstrProfWriter Writer; + std::vector> Errors; + std::mutex &ErrLock; + SmallSet &WriterErrorCodes; + + WriterContext(bool IsSparse, std::mutex &ErrLock, + SmallSet &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(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 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(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( + "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 ErrGuard{WC->ErrLock}; + bool firstTime = WC->WriterErrorCodes.insert(IPE).second; + handleMergeWriterError(make_error(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 ErrGuard{Dst->ErrLock}; + bool firstTime = Dst->WriterErrorCodes.insert(IPE).second; + if (firstTime) + warn(toString(make_error(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 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, 4> Contexts; + for (unsigned I = 0; I < NumThreads; ++I) + Contexts.emplace_back(std::make_unique( + 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 &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 +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 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 ProfileMap; + SmallVector, 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 &Profiles = Reader->getProfiles(); + for (StringMap::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 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 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 InputFilenames(cl::Positional, + cl::desc("")); + cl::list WeightedInputFilenames("weighted-input", + cl::desc(",")); + cl::opt InputFilenamesFile( + "input-files", cl::init(""), + cl::desc("Path to file containing newline-separated " + "[,] entries")); + cl::alias InputFilenamesFileA("f", cl::desc("Alias for --input-files"), + cl::aliasopt(InputFilenamesFile)); + cl::opt 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 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 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 ProfileKind( + cl::desc("Profile kind:"), cl::init(instr), + cl::values(clEnumVal(instr, "Instrumentation profile (default)"), + clEnumVal(sample, "Sample profile"))); + cl::opt 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( + "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 OutputSparse("sparse", cl::init(false), + cl::desc("Generate a sparse profile (only meaningful for -instr)")); + cl::opt 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 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 CompressAllSections( + "compress-all-sections", cl::init(false), cl::Hidden, + cl::desc("Compress all sections when writing the profile (only " + "meaningful for -extbinary)")); + cl::opt 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 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 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 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 BaseFilename(cl::Positional, cl::Required, + cl::desc("")); + cl::opt TestFilename(cl::Positional, cl::Required, + cl::desc("")); + cl::opt 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 IsCS("cs", cl::init(false), + cl::desc("For context sensitive counts")); + cl::opt 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 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 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 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 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 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 VPStats(NumVPKind); + + auto MinCmp = [](const std::pair &v1, + const std::pair &v2) { + return v1.second > v2.second; + }; + + std::priority_queue, + std::vector>, + 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 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> 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 &ColumnTitle, + const std::vector &ColumnOffset, + const std::vector &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 &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, + std::greater> + 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 ColumnTitle{"Total sample (%)", "Max sample", + "Entry sample", "Function name"}; + std::vector ColumnOffset{0, 24, 42, 58}; + std::string Metric = + std::string("max sample >= ") + std::to_string(MinCountThreshold); + std::vector 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 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 Filename(cl::Positional, cl::Required, + cl::desc("")); + + cl::opt ShowCounts("counts", cl::init(false), + cl::desc("Show counter values for shown functions")); + cl::opt TextFormat( + "text", cl::init(false), + cl::desc("Show instr profile data in text dump format")); + cl::opt ShowIndirectCallTargets( + "ic-targets", cl::init(false), + cl::desc("Show indirect call site target values for shown functions")); + cl::opt ShowMemOPSizes( + "memop-sizes", cl::init(false), + cl::desc("Show the profiled sizes of the memory intrinsic calls " + "for shown functions")); + cl::opt ShowDetailedSummary("detailed-summary", cl::init(false), + cl::desc("Show detailed profile summary")); + cl::list DetailedSummaryCutoffs( + cl::CommaSeparated, "detailed-summary-cutoffs", + cl::desc( + "Cutoff percentages (times 10000) for generating detailed summary"), + cl::value_desc("800000,901000,999999")); + cl::opt ShowHotFuncList( + "hot-func-list", cl::init(false), + cl::desc("Show profile summary of a list of hot functions")); + cl::opt ShowAllFunctions("all-functions", cl::init(false), + cl::desc("Details for every function")); + cl::opt ShowCS("showcs", cl::init(false), + cl::desc("Show context sensitive counts")); + cl::opt ShowFunction("function", + cl::desc("Details for matching functions")); + + cl::opt 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 ProfileKind( + cl::desc("Profile kind:"), cl::init(instr), + cl::values(clEnumVal(instr, "Instrumentation profile (default)"), + clEnumVal(sample, "Sample profile"))); + cl::opt TopNFunctions( + "topn", cl::init(0), + cl::desc("Show the list of functions with the largest internal counts")); + cl::opt 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 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 ShowProfileSymbolList( + "show-prof-sym-list", cl::init(false), + cl::desc("Show profile symbol list if it exists in the profile. ")); + cl::opt 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 << " [args...]\n" + << "USAGE: " << ProgName << " -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 << " [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 +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 + CheckFilename(cl::Positional, cl::desc(""), cl::Optional); + +static cl::opt + InputFilename("input-file", cl::desc("File to check (defaults to stdin)"), + cl::init("-"), cl::value_desc("filename")); + +static cl::list 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 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 NoCanonicalizeWhiteSpace( + "strict-whitespace", + cl::desc("Do not treat all horizontal whitespace as equivalent")); + +static cl::opt IgnoreCase( + "ignore-case", + cl::desc("Use case-insensitive matching")); + +static cl::list 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 + GlobalDefines("D", cl::AlwaysPrefix, + cl::desc("Define a variable to be used in capture patterns."), + cl::value_desc("VAR=VALUE")); + +static cl::opt 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 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 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 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 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 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 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 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 DumpInputFilters( + "dump-input-filter", + cl::desc("In the dump requested by -dump-input, print only input lines of\n" + "kind plus any context specified by -dump-input-context.\n" + "When there are multiple occurrences of this option, the \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 DumpInputContexts( + "dump-input-context", cl::value_desc("N"), + cl::desc("In the dump requested by -dump-input, print input lines\n" + "before and input lines after any lines specified by\n" + "-dump-input-filter. When there are multiple occurrences of\n" + "this option, the largest specified has precedence. The\n" + "default is 5.\n")); + +typedef cl::list::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= enables or disables the input dump\n" + << " - -dump-input-filter= filters the input lines\n" + << " - -dump-input-context= 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 &ImpPatBufferIDRange, + const std::vector &Diags, + std::vector &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::iterator &AnnotationBeg, + const std::vector::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 &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 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() << " 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> 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 ImpPatBufferIDRange; + if (FC.readCheckFile(SM, CheckFileText, PrefixRE, &ImpPatBufferIDRange)) + return 2; + + // Open the file to check and add it to SourceMgr. + ErrorOr> InputFileOrErr = + MemoryBuffer::getFileOrSTDIN(InputFilename); + if (InputFilename == "-") + InputFilename = ""; // 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 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 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 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 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 args, - const char *name, bool isNothrow) { +LLCallBasePtr FuncGenState::callOrInvoke(llvm::Value *callee, + llvm::FunctionType *calleeType, + llvm::ArrayRef 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(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 args, - const char *name = "", bool isNothrow = false); + LLCallBasePtr callOrInvoke(llvm::Value *callee, + llvm::FunctionType *calleeType, + llvm::ArrayRef 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(CB)) { + if (auto Invoke = dyn_cast(static_cast(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(CB)->eraseFromParent(); } static bool @@ -481,10 +481,18 @@ bool GarbageCollect2Stack::runOnFunction(Function &F) { auto originalI = I; // Ignore non-calls. - auto CB = dyn_cast(&(*(I++))); + Instruction *Inst = &(*(I++)); +#if LDC_LLVM_VER >= 800 + auto CB = dyn_cast(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(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(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(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(CB)) { + if (auto call = dyn_cast(static_cast(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(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 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 getCodeModel() { #if LDC_LLVM_VER >= 800 llvm::Optional 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 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(funcToCallUponEntry))); +#else builder.CreateCall(funcToCallUponEntry); +#endif return true; } -- 2.29.0 From 1d969cfccaf7181b5760a0ae7cd6088a36e3de44 Mon Sep 17 00:00:00 2001 From: Martin Kinkelin 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(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(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 &elems); void AddStaticMembers(AggregateDeclaration *sd, ldc::DIFile file, llvm::SmallVector &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 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 IRState::setInsertPoint(llvm::BasicBlock *bb) { + auto savedScope = llvm::make_unique(builder); + builder.SetInsertPoint(bb); + return savedScope; } -llvm::BasicBlock *IRState::scopebb() { - auto bb = ir->GetInsertBlock(); - assert(bb); - return bb; +std::unique_ptr +IRState::saveInsertPoint() { + return llvm::make_unique(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 point; // bb end if not set - - InsertionPoint(llvm::BasicBlock *bb, - llvm::Optional 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> @@ -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 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 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(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(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 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 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 thunkVar2func; - std::unordered_map thunkFun2func; + std::unordered_map thunkVar2func; + std::unordered_map thunkFun2func; std::unordered_set 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(&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(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 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 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 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 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 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 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 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