|
51 | 51 | #include "SPIRVValue.h"
|
52 | 52 |
|
53 | 53 | #include "llvm/ADT/DenseMap.h"
|
54 |
| -#include "llvm/Analysis/CFG.h" |
| 54 | +#include "llvm/Analysis/LoopInfo.h" |
55 | 55 | #include "llvm/BinaryFormat/Dwarf.h"
|
56 | 56 | #include "llvm/IR/Constants.h"
|
57 | 57 | #include "llvm/IR/DerivedTypes.h"
|
| 58 | +#include "llvm/IR/Dominators.h" |
58 | 59 | #include "llvm/IR/IRBuilder.h"
|
59 | 60 | #include "llvm/IR/Instructions.h"
|
60 | 61 | #include "llvm/IR/IntrinsicInst.h"
|
@@ -590,18 +591,17 @@ SPIRVToLLVM::getMetadataFromNameAndParameter(std::string Name,
|
590 | 591 | }
|
591 | 592 |
|
592 | 593 | template <typename LoopInstType>
|
593 |
| -void SPIRVToLLVM::setLLVMLoopMetadata(const LoopInstType *LM, Instruction *BI) { |
| 594 | +void SPIRVToLLVM::setLLVMLoopMetadata(const LoopInstType *LM, |
| 595 | + const Loop *LoopObj) { |
594 | 596 | if (!LM)
|
595 | 597 | return;
|
596 | 598 |
|
597 |
| - assert(BI && isa<BranchInst>(BI)); |
598 |
| - |
599 | 599 | auto Temp = MDNode::getTemporary(*Context, None);
|
600 | 600 | auto Self = MDNode::get(*Context, Temp.get());
|
601 | 601 | Self->replaceOperandWith(0, Self);
|
602 | 602 | SPIRVWord LC = LM->getLoopControl();
|
603 | 603 | if (LC == LoopControlMaskNone) {
|
604 |
| - BI->setMetadata("llvm.loop", Self); |
| 604 | + LoopObj->setLoopID(Self); |
605 | 605 | return;
|
606 | 606 | }
|
607 | 607 |
|
@@ -685,49 +685,137 @@ void SPIRVToLLVM::setLLVMLoopMetadata(const LoopInstType *LM, Instruction *BI) {
|
685 | 685 | LoopControlParameters[++NumParam])));
|
686 | 686 | break;
|
687 | 687 | }
|
688 |
| - default: |
| 688 | + case DependencyArrayINTEL: { |
| 689 | + // Collect array variable <-> safelen information |
| 690 | + std::map<Value *, unsigned> ArraySflnMap; |
| 691 | + unsigned NumOperandPairs = LoopControlParameters[++NumParam]; |
| 692 | + unsigned OperandsEndIndex = NumParam + NumOperandPairs * 2; |
| 693 | + assert(OperandsEndIndex <= LoopControlParameters.size() && |
| 694 | + "Missing loop control parameter!"); |
| 695 | + SPIRVModule *M = LM->getModule(); |
| 696 | + while (NumParam < OperandsEndIndex) { |
| 697 | + SPIRVId ArraySPIRVId = LoopControlParameters[++NumParam]; |
| 698 | + Value *ArrayVar = ValueMap[M->getValue(ArraySPIRVId)]; |
| 699 | + unsigned Safelen = LoopControlParameters[++NumParam]; |
| 700 | + ArraySflnMap.emplace(ArrayVar, Safelen); |
| 701 | + } |
| 702 | + |
| 703 | + // A single run over the loop to retrieve all GetElementPtr instructions |
| 704 | + // that access relevant array variables |
| 705 | + std::map<Value *, std::vector<GetElementPtrInst *>> ArrayGEPMap; |
| 706 | + for (auto &BB : LoopObj->blocks()) { |
| 707 | + for (Instruction &I : *BB) { |
| 708 | + auto *GEP = dyn_cast<GetElementPtrInst>(&I); |
| 709 | + if (!GEP) |
| 710 | + continue; |
| 711 | + |
| 712 | + Value *AccessedArray = GEP->getPointerOperand(); |
| 713 | + auto ArraySflnIt = ArraySflnMap.find(AccessedArray); |
| 714 | + if (ArraySflnIt != ArraySflnMap.end()) |
| 715 | + ArrayGEPMap[AccessedArray].push_back(GEP); |
| 716 | + } |
| 717 | + } |
| 718 | + |
| 719 | + // Create index group metadata nodes specific - one per each array |
| 720 | + // variables. Mark each GEP accessing a particular array variable |
| 721 | + // into a corresponding index group |
| 722 | + std::map<unsigned, std::vector<MDNode *>> SafelenIdxGroupMap; |
| 723 | + for (auto &ArrayGEPIt : ArrayGEPMap) { |
| 724 | + // Emit a distinct index group that will be referenced from |
| 725 | + // llvm.loop.parallel_access_indices metadata |
| 726 | + auto *CurrentDepthIdxGroup = |
| 727 | + llvm::MDNode::getDistinct(*Context, None); |
| 728 | + unsigned Safelen = ArraySflnMap.find(ArrayGEPIt.first)->second; |
| 729 | + SafelenIdxGroupMap[Safelen].push_back(CurrentDepthIdxGroup); |
| 730 | + |
| 731 | + for (auto *GEP : ArrayGEPIt.second) { |
| 732 | + StringRef IdxGroupMDName("llvm.index.group"); |
| 733 | + llvm::MDNode *PreviousIdxGroup = GEP->getMetadata(IdxGroupMDName); |
| 734 | + if (!PreviousIdxGroup) { |
| 735 | + GEP->setMetadata(IdxGroupMDName, CurrentDepthIdxGroup); |
| 736 | + continue; |
| 737 | + } |
| 738 | + |
| 739 | + // If we're dealing with an embedded loop, it may be the case |
| 740 | + // that GEP instructions for some of the arrays were already |
| 741 | + // marked by the algorithm when it went over the outer level loops. |
| 742 | + // In order to retain the IVDep information for each "loop |
| 743 | + // dimension", we will mark such GEP's into a separate joined node |
| 744 | + // that will refer to the previous levels' index groups AND to the |
| 745 | + // index group specific to the current loop. |
| 746 | + std::vector<llvm::Metadata *> CurrentDepthOperands; |
| 747 | + for (auto &Op : PreviousIdxGroup->operands()) |
| 748 | + CurrentDepthOperands.push_back(Op); |
| 749 | + if (CurrentDepthOperands.size() == 0) |
| 750 | + CurrentDepthOperands.push_back(PreviousIdxGroup); |
| 751 | + CurrentDepthOperands.push_back(CurrentDepthIdxGroup); |
| 752 | + auto *JointIdxGroup = |
| 753 | + llvm::MDNode::get(*Context, CurrentDepthOperands); |
| 754 | + GEP->setMetadata(IdxGroupMDName, JointIdxGroup); |
| 755 | + } |
| 756 | + } |
| 757 | + |
| 758 | + for (auto &SflnIdxGroupIt : SafelenIdxGroupMap) { |
| 759 | + auto *Name = |
| 760 | + MDString::get(*Context, "llvm.loop.parallel_access_indices"); |
| 761 | + unsigned SflnValue = SflnIdxGroupIt.first; |
| 762 | + llvm::Metadata *SafelenMDOp = |
| 763 | + SflnValue ? ConstantAsMetadata::get(ConstantInt::get( |
| 764 | + Type::getInt32Ty(*Context), SflnValue)) |
| 765 | + : nullptr; |
| 766 | + std::vector<llvm::Metadata *> Parameters{Name}; |
| 767 | + for (auto *Node : SflnIdxGroupIt.second) |
| 768 | + Parameters.push_back(Node); |
| 769 | + if (SafelenMDOp) |
| 770 | + Parameters.push_back(SafelenMDOp); |
| 771 | + Metadata.push_back(llvm::MDNode::get(*Context, Parameters)); |
| 772 | + } |
689 | 773 | break;
|
690 | 774 | }
|
| 775 | + default: |
| 776 | + llvm_unreachable( |
| 777 | + "Unexpected token in LoopControlExtendedConstrolsMask"); |
| 778 | + } |
691 | 779 | ++NumParam;
|
692 | 780 | }
|
693 | 781 | }
|
694 | 782 | llvm::MDNode *Node = llvm::MDNode::get(*Context, Metadata);
|
695 | 783 |
|
696 | 784 | // Set the first operand to refer itself
|
697 | 785 | Node->replaceOperandWith(0, Node);
|
698 |
| - BI->setMetadata("llvm.loop", Node); |
| 786 | + LoopObj->setLoopID(Node); |
699 | 787 | }
|
700 | 788 |
|
701 | 789 | void SPIRVToLLVM::transLLVMLoopMetadata(const Function *F) {
|
702 | 790 | assert(F);
|
703 | 791 |
|
704 |
| - if (!FuncLoopMetadataMap.empty()) { |
705 |
| - // In SPIRV loop metadata is linked to a header basic block of a loop |
706 |
| - // whilst in LLVM IR it is linked to a latch basic block (the one |
707 |
| - // whose back edge goes to a header basic block) of the loop. |
708 |
| - |
709 |
| - using Edge = std::pair<const BasicBlock *, const BasicBlock *>; |
710 |
| - SmallVector<Edge, 32> Edges; |
711 |
| - FindFunctionBackedges(*F, Edges); |
712 |
| - |
713 |
| - for (const auto &BkEdge : Edges) { |
714 |
| - // Check that loop header BB contains loop metadata. |
715 |
| - const auto LMDItr = FuncLoopMetadataMap.find(BkEdge.second); |
716 |
| - if (LMDItr == FuncLoopMetadataMap.end()) |
717 |
| - continue; |
718 |
| - |
719 |
| - auto *BI = const_cast<Instruction *>(BkEdge.first->getTerminator()); |
720 |
| - const auto *LMD = LMDItr->second; |
721 |
| - if (LMD->getOpCode() == OpLoopMerge) { |
722 |
| - const auto *LM = static_cast<const SPIRVLoopMerge *>(LMD); |
723 |
| - setLLVMLoopMetadata<SPIRVLoopMerge>(LM, BI); |
724 |
| - } else if (LMD->getOpCode() == OpLoopControlINTEL) { |
725 |
| - const auto *LCI = static_cast<const SPIRVLoopControlINTEL *>(LMD); |
726 |
| - setLLVMLoopMetadata<SPIRVLoopControlINTEL>(LCI, BI); |
727 |
| - } |
| 792 | + if (FuncLoopMetadataMap.empty()) |
| 793 | + return; |
728 | 794 |
|
729 |
| - FuncLoopMetadataMap.erase(LMDItr); |
| 795 | + DominatorTree DomTree(*(const_cast<Function *>(F))); |
| 796 | + LoopInfo LI(DomTree); |
| 797 | + |
| 798 | + // In SPIRV loop metadata is linked to a header basic block of a loop |
| 799 | + // whilst in LLVM IR it is linked to a latch basic block (the one |
| 800 | + // whose back edge goes to a header basic block) of the loop. |
| 801 | + // To ensure consistent behaviour, we can rely on the `llvm::Loop` |
| 802 | + // class to handle the metadata placement |
| 803 | + for (const auto *LoopObj : LI.getLoopsInPreorder()) { |
| 804 | + // Check that loop header BB contains loop metadata. |
| 805 | + const auto LMDItr = FuncLoopMetadataMap.find(LoopObj->getHeader()); |
| 806 | + if (LMDItr == FuncLoopMetadataMap.end()) |
| 807 | + continue; |
| 808 | + |
| 809 | + const auto *LMD = LMDItr->second; |
| 810 | + if (LMD->getOpCode() == OpLoopMerge) { |
| 811 | + const auto *LM = static_cast<const SPIRVLoopMerge *>(LMD); |
| 812 | + setLLVMLoopMetadata<SPIRVLoopMerge>(LM, LoopObj); |
| 813 | + } else if (LMD->getOpCode() == OpLoopControlINTEL) { |
| 814 | + const auto *LCI = static_cast<const SPIRVLoopControlINTEL *>(LMD); |
| 815 | + setLLVMLoopMetadata<SPIRVLoopControlINTEL>(LCI, LoopObj); |
730 | 816 | }
|
| 817 | + |
| 818 | + FuncLoopMetadataMap.erase(LMDItr); |
731 | 819 | }
|
732 | 820 | }
|
733 | 821 |
|
|
0 commit comments