[clang] [llvm] [SPIR-V] Add SPIR-V structurizer (PR #107408)
Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= Message-ID: In-Reply-To: michalpaszkowski wrote: @Keenuts Apologies for the delay! The patch looks good to me. I added a couple of minor comments (above), but if the pass would be extended in subsequent commits, please feel free to address these in the next pull request or reply later. Thank you for working on this, this is really exciting work! https://github.com/llvm/llvm-project/pull/107408 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [llvm] [SPIR-V] Add SPIR-V structurizer (PR #107408)
Nathan =?utf-8?q?Gau=C3=ABr?= , Nathan =?utf-8?q?Gau=C3=ABr?= , Nathan =?utf-8?q?Gau=C3=ABr?= , Nathan =?utf-8?q?Gau=C3=ABr?= , Nathan =?utf-8?q?Gau=C3=ABr?= , Nathan =?utf-8?q?Gau=C3=ABr?= , Nathan =?utf-8?q?Gau=C3=ABr?= , Nathan =?utf-8?q?Gau=C3=ABr?= , Nathan =?utf-8?q?Gau=C3=ABr?= , Nathan =?utf-8?q?Gau=C3=ABr?= , Nathan =?utf-8?q?Gau=C3=ABr?= , Nathan =?utf-8?q?Gau=C3=ABr?= , Nathan =?utf-8?q?Gau=C3=ABr?= , Nathan =?utf-8?q?Gau=C3=ABr?= , Nathan =?utf-8?q?Gau=C3=ABr?= , Nathan =?utf-8?q?Gau=C3=ABr?= Message-ID: In-Reply-To: https://github.com/michalpaszkowski approved this pull request. https://github.com/llvm/llvm-project/pull/107408 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [llvm] [SPIR-V] Add SPIR-V structurizer (PR #107408)
Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= Message-ID: In-Reply-To: @@ -0,0 +1,1242 @@ +//===-- SPIRVStructurizer.cpp --*- C++ -*-===// +// +// 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 +// +//===--===// +// +//===--===// + +#include "Analysis/SPIRVConvergenceRegionAnalysis.h" +#include "SPIRV.h" +#include "SPIRVSubtarget.h" +#include "SPIRVTargetMachine.h" +#include "SPIRVUtils.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/Analysis/LoopInfo.h" +#include "llvm/CodeGen/IntrinsicLowering.h" +#include "llvm/IR/CFG.h" +#include "llvm/IR/Dominators.h" +#include "llvm/IR/IRBuilder.h" +#include "llvm/IR/IntrinsicInst.h" +#include "llvm/IR/Intrinsics.h" +#include "llvm/IR/IntrinsicsSPIRV.h" +#include "llvm/InitializePasses.h" +#include "llvm/Transforms/Utils/Cloning.h" +#include "llvm/Transforms/Utils/LoopSimplify.h" +#include "llvm/Transforms/Utils/LowerMemIntrinsics.h" +#include +#include +#include + +using namespace llvm; +using namespace SPIRV; + +namespace llvm { + +void initializeSPIRVStructurizerPass(PassRegistry &); + +namespace { + +using BlockSet = std::unordered_set; +using Edge = std::pair; + +// Helper function to do a partial order visit from the block |Start|, calling +// |Op| on each visited node. +void partialOrderVisit(BasicBlock &Start, + std::function Op) { + PartialOrderingVisitor V(*Start.getParent()); + V.partialOrderVisit(Start, Op); +} + +// Returns the exact convergence region in the tree defined by `Node` for which +// `BB` is the header, nullptr otherwise. +const ConvergenceRegion *getRegionForHeader(const ConvergenceRegion *Node, +BasicBlock *BB) { + if (Node->Entry == BB) +return Node; + + for (auto *Child : Node->Children) { +const auto *CR = getRegionForHeader(Child, BB); +if (CR != nullptr) + return CR; + } + return nullptr; +} + +// Returns the single BasicBlock exiting the convergence region `CR`, +// nullptr if no such exit exists. +BasicBlock *getExitFor(const ConvergenceRegion *CR) { + std::unordered_set ExitTargets; + for (BasicBlock *Exit : CR->Exits) { +for (BasicBlock *Successor : successors(Exit)) { + if (CR->Blocks.count(Successor) == 0) +ExitTargets.insert(Successor); +} + } + + assert(ExitTargets.size() <= 1); + if (ExitTargets.size() == 0) +return nullptr; + + return *ExitTargets.begin(); +} + +// Returns the merge block designated by I if I is a merge instruction, nullptr +// otherwise. +BasicBlock *getDesignatedMergeBlock(Instruction *I) { + IntrinsicInst *II = dyn_cast(I); + if (II == nullptr) +return nullptr; + + if (II->getIntrinsicID() != Intrinsic::spv_loop_merge && + II->getIntrinsicID() != Intrinsic::spv_selection_merge) +return nullptr; + + BlockAddress *BA = cast(II->getOperand(0)); + return BA->getBasicBlock(); +} + +// Returns the continue block designated by I if I is an OpLoopMerge, nullptr +// otherwise. +BasicBlock *getDesignatedContinueBlock(Instruction *I) { + IntrinsicInst *II = dyn_cast(I); + if (II == nullptr) +return nullptr; + + if (II->getIntrinsicID() != Intrinsic::spv_loop_merge) +return nullptr; + + BlockAddress *BA = cast(II->getOperand(1)); + return BA->getBasicBlock(); +} + +// Returns true if Header has one merge instruction which designated Merge as +// merge block. +bool isDefinedAsSelectionMergeBy(BasicBlock &Header, BasicBlock &Merge) { + for (auto &I : Header) { +BasicBlock *MB = getDesignatedMergeBlock(&I); +if (MB == &Merge) + return true; + } + return false; +} + +// Returns true if the BB has one OpLoopMerge instruction. +bool hasLoopMergeInstruction(BasicBlock &BB) { + for (auto &I : BB) +if (getDesignatedContinueBlock(&I)) + return true; + return false; +} + +// Returns true is I is an OpSelectionMerge or OpLoopMerge instruction, false +// otherwise. +bool isMergeInstruction(Instruction *I) { + return getDesignatedMergeBlock(I) != nullptr; +} + +// Returns all blocks in F having at least one OpLoopMerge or OpSelectionMerge +// instruction. +SmallPtrSet getHeaderBlocks(Function &F) { + SmallPtrSet Output; + for (BasicBlock &BB : F) { +for (Instruction &I : BB) { + if (getDesignatedMergeBlock(&I) != nullptr) +
[clang] [llvm] [SPIR-V] Add SPIR-V structurizer (PR #107408)
Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= Message-ID: In-Reply-To: @@ -0,0 +1,1242 @@ +//===-- SPIRVStructurizer.cpp --*- C++ -*-===// +// +// 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 +// +//===--===// +// +//===--===// + +#include "Analysis/SPIRVConvergenceRegionAnalysis.h" +#include "SPIRV.h" +#include "SPIRVSubtarget.h" +#include "SPIRVTargetMachine.h" +#include "SPIRVUtils.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/Analysis/LoopInfo.h" +#include "llvm/CodeGen/IntrinsicLowering.h" +#include "llvm/IR/CFG.h" +#include "llvm/IR/Dominators.h" +#include "llvm/IR/IRBuilder.h" +#include "llvm/IR/IntrinsicInst.h" +#include "llvm/IR/Intrinsics.h" +#include "llvm/IR/IntrinsicsSPIRV.h" +#include "llvm/InitializePasses.h" +#include "llvm/Transforms/Utils/Cloning.h" +#include "llvm/Transforms/Utils/LoopSimplify.h" +#include "llvm/Transforms/Utils/LowerMemIntrinsics.h" +#include +#include +#include + +using namespace llvm; +using namespace SPIRV; + +namespace llvm { + +void initializeSPIRVStructurizerPass(PassRegistry &); + +namespace { + +using BlockSet = std::unordered_set; +using Edge = std::pair; + +// Helper function to do a partial order visit from the block |Start|, calling +// |Op| on each visited node. +void partialOrderVisit(BasicBlock &Start, + std::function Op) { + PartialOrderingVisitor V(*Start.getParent()); + V.partialOrderVisit(Start, Op); +} + +// Returns the exact convergence region in the tree defined by `Node` for which +// `BB` is the header, nullptr otherwise. +const ConvergenceRegion *getRegionForHeader(const ConvergenceRegion *Node, +BasicBlock *BB) { + if (Node->Entry == BB) +return Node; + + for (auto *Child : Node->Children) { +const auto *CR = getRegionForHeader(Child, BB); +if (CR != nullptr) + return CR; + } + return nullptr; +} + +// Returns the single BasicBlock exiting the convergence region `CR`, +// nullptr if no such exit exists. +BasicBlock *getExitFor(const ConvergenceRegion *CR) { + std::unordered_set ExitTargets; + for (BasicBlock *Exit : CR->Exits) { +for (BasicBlock *Successor : successors(Exit)) { + if (CR->Blocks.count(Successor) == 0) +ExitTargets.insert(Successor); +} + } + + assert(ExitTargets.size() <= 1); + if (ExitTargets.size() == 0) +return nullptr; + + return *ExitTargets.begin(); +} + +// Returns the merge block designated by I if I is a merge instruction, nullptr +// otherwise. +BasicBlock *getDesignatedMergeBlock(Instruction *I) { + IntrinsicInst *II = dyn_cast(I); + if (II == nullptr) +return nullptr; + + if (II->getIntrinsicID() != Intrinsic::spv_loop_merge && + II->getIntrinsicID() != Intrinsic::spv_selection_merge) +return nullptr; + + BlockAddress *BA = cast(II->getOperand(0)); + return BA->getBasicBlock(); +} + +// Returns the continue block designated by I if I is an OpLoopMerge, nullptr +// otherwise. +BasicBlock *getDesignatedContinueBlock(Instruction *I) { + IntrinsicInst *II = dyn_cast(I); + if (II == nullptr) +return nullptr; + + if (II->getIntrinsicID() != Intrinsic::spv_loop_merge) +return nullptr; + + BlockAddress *BA = cast(II->getOperand(1)); + return BA->getBasicBlock(); +} + +// Returns true if Header has one merge instruction which designated Merge as +// merge block. +bool isDefinedAsSelectionMergeBy(BasicBlock &Header, BasicBlock &Merge) { + for (auto &I : Header) { +BasicBlock *MB = getDesignatedMergeBlock(&I); +if (MB == &Merge) + return true; + } + return false; +} + +// Returns true if the BB has one OpLoopMerge instruction. +bool hasLoopMergeInstruction(BasicBlock &BB) { + for (auto &I : BB) +if (getDesignatedContinueBlock(&I)) + return true; + return false; +} + +// Returns true is I is an OpSelectionMerge or OpLoopMerge instruction, false +// otherwise. +bool isMergeInstruction(Instruction *I) { + return getDesignatedMergeBlock(I) != nullptr; +} + +// Returns all blocks in F having at least one OpLoopMerge or OpSelectionMerge +// instruction. +SmallPtrSet getHeaderBlocks(Function &F) { + SmallPtrSet Output; + for (BasicBlock &BB : F) { +for (Instruction &I : BB) { + if (getDesignatedMergeBlock(&I) != nullptr) +
[clang] [llvm] [SPIR-V] Add SPIR-V structurizer (PR #107408)
Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= Message-ID: In-Reply-To: https://github.com/michalpaszkowski edited https://github.com/llvm/llvm-project/pull/107408 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [llvm] [SPIR-V] Add SPIR-V structurizer (PR #107408)
Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= Message-ID: In-Reply-To: @@ -0,0 +1,1242 @@ +//===-- SPIRVStructurizer.cpp --*- C++ -*-===// +// +// 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 +// +//===--===// +// +//===--===// + +#include "Analysis/SPIRVConvergenceRegionAnalysis.h" +#include "SPIRV.h" +#include "SPIRVSubtarget.h" +#include "SPIRVTargetMachine.h" +#include "SPIRVUtils.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/Analysis/LoopInfo.h" +#include "llvm/CodeGen/IntrinsicLowering.h" +#include "llvm/IR/CFG.h" +#include "llvm/IR/Dominators.h" +#include "llvm/IR/IRBuilder.h" +#include "llvm/IR/IntrinsicInst.h" +#include "llvm/IR/Intrinsics.h" +#include "llvm/IR/IntrinsicsSPIRV.h" +#include "llvm/InitializePasses.h" +#include "llvm/Transforms/Utils/Cloning.h" +#include "llvm/Transforms/Utils/LoopSimplify.h" +#include "llvm/Transforms/Utils/LowerMemIntrinsics.h" +#include +#include +#include + +using namespace llvm; +using namespace SPIRV; + +namespace llvm { + +void initializeSPIRVStructurizerPass(PassRegistry &); + +namespace { + +using BlockSet = std::unordered_set; +using Edge = std::pair; + +// Helper function to do a partial order visit from the block |Start|, calling +// |Op| on each visited node. +void partialOrderVisit(BasicBlock &Start, + std::function Op) { + PartialOrderingVisitor V(*Start.getParent()); + V.partialOrderVisit(Start, Op); +} + +// Returns the exact convergence region in the tree defined by `Node` for which +// `BB` is the header, nullptr otherwise. +const ConvergenceRegion *getRegionForHeader(const ConvergenceRegion *Node, +BasicBlock *BB) { + if (Node->Entry == BB) +return Node; + + for (auto *Child : Node->Children) { +const auto *CR = getRegionForHeader(Child, BB); +if (CR != nullptr) + return CR; + } + return nullptr; +} + +// Returns the single BasicBlock exiting the convergence region `CR`, +// nullptr if no such exit exists. +BasicBlock *getExitFor(const ConvergenceRegion *CR) { + std::unordered_set ExitTargets; + for (BasicBlock *Exit : CR->Exits) { +for (BasicBlock *Successor : successors(Exit)) { + if (CR->Blocks.count(Successor) == 0) +ExitTargets.insert(Successor); +} + } + + assert(ExitTargets.size() <= 1); + if (ExitTargets.size() == 0) +return nullptr; + + return *ExitTargets.begin(); +} + +// Returns the merge block designated by I if I is a merge instruction, nullptr +// otherwise. +BasicBlock *getDesignatedMergeBlock(Instruction *I) { + IntrinsicInst *II = dyn_cast(I); + if (II == nullptr) +return nullptr; + + if (II->getIntrinsicID() != Intrinsic::spv_loop_merge && + II->getIntrinsicID() != Intrinsic::spv_selection_merge) +return nullptr; + + BlockAddress *BA = cast(II->getOperand(0)); + return BA->getBasicBlock(); +} + +// Returns the continue block designated by I if I is an OpLoopMerge, nullptr +// otherwise. +BasicBlock *getDesignatedContinueBlock(Instruction *I) { + IntrinsicInst *II = dyn_cast(I); + if (II == nullptr) +return nullptr; + + if (II->getIntrinsicID() != Intrinsic::spv_loop_merge) +return nullptr; + + BlockAddress *BA = cast(II->getOperand(1)); + return BA->getBasicBlock(); +} + +// Returns true if Header has one merge instruction which designated Merge as +// merge block. +bool isDefinedAsSelectionMergeBy(BasicBlock &Header, BasicBlock &Merge) { + for (auto &I : Header) { +BasicBlock *MB = getDesignatedMergeBlock(&I); +if (MB == &Merge) + return true; + } + return false; +} + +// Returns true if the BB has one OpLoopMerge instruction. +bool hasLoopMergeInstruction(BasicBlock &BB) { + for (auto &I : BB) +if (getDesignatedContinueBlock(&I)) + return true; + return false; +} + +// Returns true is I is an OpSelectionMerge or OpLoopMerge instruction, false +// otherwise. +bool isMergeInstruction(Instruction *I) { + return getDesignatedMergeBlock(I) != nullptr; +} + +// Returns all blocks in F having at least one OpLoopMerge or OpSelectionMerge +// instruction. +SmallPtrSet getHeaderBlocks(Function &F) { + SmallPtrSet Output; + for (BasicBlock &BB : F) { +for (Instruction &I : BB) { + if (getDesignatedMergeBlock(&I) != nullptr) +
[clang] [llvm] [SPIR-V] Add SPIR-V structurizer (PR #107408)
Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= Message-ID: In-Reply-To: @@ -0,0 +1,1242 @@ +//===-- SPIRVStructurizer.cpp --*- C++ -*-===// +// +// 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 +// +//===--===// +// +//===--===// + +#include "Analysis/SPIRVConvergenceRegionAnalysis.h" +#include "SPIRV.h" +#include "SPIRVSubtarget.h" +#include "SPIRVTargetMachine.h" +#include "SPIRVUtils.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/Analysis/LoopInfo.h" +#include "llvm/CodeGen/IntrinsicLowering.h" +#include "llvm/IR/CFG.h" +#include "llvm/IR/Dominators.h" +#include "llvm/IR/IRBuilder.h" +#include "llvm/IR/IntrinsicInst.h" +#include "llvm/IR/Intrinsics.h" +#include "llvm/IR/IntrinsicsSPIRV.h" +#include "llvm/InitializePasses.h" +#include "llvm/Transforms/Utils/Cloning.h" +#include "llvm/Transforms/Utils/LoopSimplify.h" +#include "llvm/Transforms/Utils/LowerMemIntrinsics.h" +#include +#include +#include + +using namespace llvm; +using namespace SPIRV; + +namespace llvm { + +void initializeSPIRVStructurizerPass(PassRegistry &); + +namespace { + +using BlockSet = std::unordered_set; +using Edge = std::pair; + +// Helper function to do a partial order visit from the block |Start|, calling +// |Op| on each visited node. +void partialOrderVisit(BasicBlock &Start, + std::function Op) { + PartialOrderingVisitor V(*Start.getParent()); + V.partialOrderVisit(Start, Op); +} + +// Returns the exact convergence region in the tree defined by `Node` for which +// `BB` is the header, nullptr otherwise. +const ConvergenceRegion *getRegionForHeader(const ConvergenceRegion *Node, +BasicBlock *BB) { + if (Node->Entry == BB) +return Node; + + for (auto *Child : Node->Children) { +const auto *CR = getRegionForHeader(Child, BB); +if (CR != nullptr) + return CR; + } + return nullptr; +} + +// Returns the single BasicBlock exiting the convergence region `CR`, +// nullptr if no such exit exists. +BasicBlock *getExitFor(const ConvergenceRegion *CR) { + std::unordered_set ExitTargets; + for (BasicBlock *Exit : CR->Exits) { +for (BasicBlock *Successor : successors(Exit)) { + if (CR->Blocks.count(Successor) == 0) +ExitTargets.insert(Successor); +} + } + + assert(ExitTargets.size() <= 1); + if (ExitTargets.size() == 0) +return nullptr; + + return *ExitTargets.begin(); +} + +// Returns the merge block designated by I if I is a merge instruction, nullptr +// otherwise. +BasicBlock *getDesignatedMergeBlock(Instruction *I) { + IntrinsicInst *II = dyn_cast(I); + if (II == nullptr) +return nullptr; + + if (II->getIntrinsicID() != Intrinsic::spv_loop_merge && + II->getIntrinsicID() != Intrinsic::spv_selection_merge) +return nullptr; + + BlockAddress *BA = cast(II->getOperand(0)); + return BA->getBasicBlock(); +} + +// Returns the continue block designated by I if I is an OpLoopMerge, nullptr +// otherwise. +BasicBlock *getDesignatedContinueBlock(Instruction *I) { + IntrinsicInst *II = dyn_cast(I); + if (II == nullptr) +return nullptr; + + if (II->getIntrinsicID() != Intrinsic::spv_loop_merge) +return nullptr; + + BlockAddress *BA = cast(II->getOperand(1)); + return BA->getBasicBlock(); +} + +// Returns true if Header has one merge instruction which designated Merge as +// merge block. +bool isDefinedAsSelectionMergeBy(BasicBlock &Header, BasicBlock &Merge) { + for (auto &I : Header) { +BasicBlock *MB = getDesignatedMergeBlock(&I); +if (MB == &Merge) + return true; + } + return false; +} + +// Returns true if the BB has one OpLoopMerge instruction. +bool hasLoopMergeInstruction(BasicBlock &BB) { + for (auto &I : BB) +if (getDesignatedContinueBlock(&I)) + return true; + return false; +} + +// Returns true is I is an OpSelectionMerge or OpLoopMerge instruction, false +// otherwise. +bool isMergeInstruction(Instruction *I) { + return getDesignatedMergeBlock(I) != nullptr; +} + +// Returns all blocks in F having at least one OpLoopMerge or OpSelectionMerge +// instruction. +SmallPtrSet getHeaderBlocks(Function &F) { + SmallPtrSet Output; + for (BasicBlock &BB : F) { +for (Instruction &I : BB) { + if (getDesignatedMergeBlock(&I) != nullptr) +
[clang] [llvm] [SPIR-V] Add SPIR-V structurizer (PR #107408)
Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= Message-ID: In-Reply-To: @@ -0,0 +1,1242 @@ +//===-- SPIRVStructurizer.cpp --*- C++ -*-===// +// +// 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 +// +//===--===// +// +//===--===// + +#include "Analysis/SPIRVConvergenceRegionAnalysis.h" +#include "SPIRV.h" +#include "SPIRVSubtarget.h" +#include "SPIRVTargetMachine.h" +#include "SPIRVUtils.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/Analysis/LoopInfo.h" +#include "llvm/CodeGen/IntrinsicLowering.h" +#include "llvm/IR/CFG.h" +#include "llvm/IR/Dominators.h" +#include "llvm/IR/IRBuilder.h" +#include "llvm/IR/IntrinsicInst.h" +#include "llvm/IR/Intrinsics.h" +#include "llvm/IR/IntrinsicsSPIRV.h" +#include "llvm/InitializePasses.h" +#include "llvm/Transforms/Utils/Cloning.h" +#include "llvm/Transforms/Utils/LoopSimplify.h" +#include "llvm/Transforms/Utils/LowerMemIntrinsics.h" +#include +#include +#include + +using namespace llvm; +using namespace SPIRV; + +namespace llvm { + +void initializeSPIRVStructurizerPass(PassRegistry &); + +namespace { + +using BlockSet = std::unordered_set; +using Edge = std::pair; + +// Helper function to do a partial order visit from the block |Start|, calling +// |Op| on each visited node. +void partialOrderVisit(BasicBlock &Start, + std::function Op) { + PartialOrderingVisitor V(*Start.getParent()); + V.partialOrderVisit(Start, Op); +} + +// Returns the exact convergence region in the tree defined by `Node` for which +// `BB` is the header, nullptr otherwise. +const ConvergenceRegion *getRegionForHeader(const ConvergenceRegion *Node, +BasicBlock *BB) { + if (Node->Entry == BB) +return Node; + + for (auto *Child : Node->Children) { +const auto *CR = getRegionForHeader(Child, BB); +if (CR != nullptr) + return CR; + } + return nullptr; +} + +// Returns the single BasicBlock exiting the convergence region `CR`, +// nullptr if no such exit exists. +BasicBlock *getExitFor(const ConvergenceRegion *CR) { + std::unordered_set ExitTargets; + for (BasicBlock *Exit : CR->Exits) { +for (BasicBlock *Successor : successors(Exit)) { + if (CR->Blocks.count(Successor) == 0) +ExitTargets.insert(Successor); +} + } + + assert(ExitTargets.size() <= 1); + if (ExitTargets.size() == 0) +return nullptr; + + return *ExitTargets.begin(); +} + +// Returns the merge block designated by I if I is a merge instruction, nullptr +// otherwise. +BasicBlock *getDesignatedMergeBlock(Instruction *I) { + IntrinsicInst *II = dyn_cast(I); + if (II == nullptr) +return nullptr; + + if (II->getIntrinsicID() != Intrinsic::spv_loop_merge && + II->getIntrinsicID() != Intrinsic::spv_selection_merge) +return nullptr; + + BlockAddress *BA = cast(II->getOperand(0)); + return BA->getBasicBlock(); +} + +// Returns the continue block designated by I if I is an OpLoopMerge, nullptr +// otherwise. +BasicBlock *getDesignatedContinueBlock(Instruction *I) { + IntrinsicInst *II = dyn_cast(I); + if (II == nullptr) +return nullptr; + + if (II->getIntrinsicID() != Intrinsic::spv_loop_merge) +return nullptr; + + BlockAddress *BA = cast(II->getOperand(1)); + return BA->getBasicBlock(); +} + +// Returns true if Header has one merge instruction which designated Merge as +// merge block. +bool isDefinedAsSelectionMergeBy(BasicBlock &Header, BasicBlock &Merge) { + for (auto &I : Header) { +BasicBlock *MB = getDesignatedMergeBlock(&I); +if (MB == &Merge) + return true; + } + return false; +} + +// Returns true if the BB has one OpLoopMerge instruction. +bool hasLoopMergeInstruction(BasicBlock &BB) { + for (auto &I : BB) +if (getDesignatedContinueBlock(&I)) + return true; + return false; +} + +// Returns true is I is an OpSelectionMerge or OpLoopMerge instruction, false +// otherwise. +bool isMergeInstruction(Instruction *I) { + return getDesignatedMergeBlock(I) != nullptr; +} + +// Returns all blocks in F having at least one OpLoopMerge or OpSelectionMerge +// instruction. +SmallPtrSet getHeaderBlocks(Function &F) { + SmallPtrSet Output; + for (BasicBlock &BB : F) { +for (Instruction &I : BB) { + if (getDesignatedMergeBlock(&I) != nullptr) +
[clang] [llvm] [SPIR-V] Add SPIR-V structurizer (PR #107408)
Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= Message-ID: In-Reply-To: https://github.com/michalpaszkowski edited https://github.com/llvm/llvm-project/pull/107408 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [llvm] [SPIR-V] Add SPIR-V structurizer (PR #107408)
Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= Message-ID: In-Reply-To: @@ -0,0 +1,1242 @@ +//===-- SPIRVStructurizer.cpp --*- C++ -*-===// +// +// 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 +// +//===--===// +// +//===--===// + +#include "Analysis/SPIRVConvergenceRegionAnalysis.h" +#include "SPIRV.h" +#include "SPIRVSubtarget.h" +#include "SPIRVTargetMachine.h" +#include "SPIRVUtils.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/Analysis/LoopInfo.h" +#include "llvm/CodeGen/IntrinsicLowering.h" +#include "llvm/IR/CFG.h" +#include "llvm/IR/Dominators.h" +#include "llvm/IR/IRBuilder.h" +#include "llvm/IR/IntrinsicInst.h" +#include "llvm/IR/Intrinsics.h" +#include "llvm/IR/IntrinsicsSPIRV.h" +#include "llvm/InitializePasses.h" +#include "llvm/Transforms/Utils/Cloning.h" +#include "llvm/Transforms/Utils/LoopSimplify.h" +#include "llvm/Transforms/Utils/LowerMemIntrinsics.h" +#include +#include +#include + +using namespace llvm; +using namespace SPIRV; + +namespace llvm { + +void initializeSPIRVStructurizerPass(PassRegistry &); + +namespace { + +using BlockSet = std::unordered_set; +using Edge = std::pair; + +// Helper function to do a partial order visit from the block |Start|, calling +// |Op| on each visited node. +void partialOrderVisit(BasicBlock &Start, + std::function Op) { + PartialOrderingVisitor V(*Start.getParent()); + V.partialOrderVisit(Start, Op); +} + +// Returns the exact convergence region in the tree defined by `Node` for which +// `BB` is the header, nullptr otherwise. +const ConvergenceRegion *getRegionForHeader(const ConvergenceRegion *Node, +BasicBlock *BB) { + if (Node->Entry == BB) +return Node; + + for (auto *Child : Node->Children) { +const auto *CR = getRegionForHeader(Child, BB); +if (CR != nullptr) + return CR; + } + return nullptr; +} + +// Returns the single BasicBlock exiting the convergence region `CR`, +// nullptr if no such exit exists. +BasicBlock *getExitFor(const ConvergenceRegion *CR) { + std::unordered_set ExitTargets; + for (BasicBlock *Exit : CR->Exits) { +for (BasicBlock *Successor : successors(Exit)) { + if (CR->Blocks.count(Successor) == 0) +ExitTargets.insert(Successor); +} + } + + assert(ExitTargets.size() <= 1); + if (ExitTargets.size() == 0) +return nullptr; + + return *ExitTargets.begin(); +} + +// Returns the merge block designated by I if I is a merge instruction, nullptr +// otherwise. +BasicBlock *getDesignatedMergeBlock(Instruction *I) { + IntrinsicInst *II = dyn_cast(I); + if (II == nullptr) +return nullptr; + + if (II->getIntrinsicID() != Intrinsic::spv_loop_merge && + II->getIntrinsicID() != Intrinsic::spv_selection_merge) +return nullptr; + + BlockAddress *BA = cast(II->getOperand(0)); + return BA->getBasicBlock(); +} + +// Returns the continue block designated by I if I is an OpLoopMerge, nullptr +// otherwise. +BasicBlock *getDesignatedContinueBlock(Instruction *I) { + IntrinsicInst *II = dyn_cast(I); + if (II == nullptr) +return nullptr; + + if (II->getIntrinsicID() != Intrinsic::spv_loop_merge) +return nullptr; + + BlockAddress *BA = cast(II->getOperand(1)); + return BA->getBasicBlock(); +} + +// Returns true if Header has one merge instruction which designated Merge as +// merge block. +bool isDefinedAsSelectionMergeBy(BasicBlock &Header, BasicBlock &Merge) { + for (auto &I : Header) { +BasicBlock *MB = getDesignatedMergeBlock(&I); +if (MB == &Merge) + return true; + } + return false; +} + +// Returns true if the BB has one OpLoopMerge instruction. +bool hasLoopMergeInstruction(BasicBlock &BB) { + for (auto &I : BB) +if (getDesignatedContinueBlock(&I)) + return true; + return false; +} + +// Returns true is I is an OpSelectionMerge or OpLoopMerge instruction, false +// otherwise. +bool isMergeInstruction(Instruction *I) { + return getDesignatedMergeBlock(I) != nullptr; +} + +// Returns all blocks in F having at least one OpLoopMerge or OpSelectionMerge +// instruction. +SmallPtrSet getHeaderBlocks(Function &F) { + SmallPtrSet Output; + for (BasicBlock &BB : F) { +for (Instruction &I : BB) { + if (getDesignatedMergeBlock(&I) != nullptr) +
[clang] [llvm] [SPIR-V] Add SPIR-V structurizer (PR #107408)
Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= , Nathan =?utf-8?q?Gauër?= Message-ID: In-Reply-To: @@ -0,0 +1,1242 @@ +//===-- SPIRVStructurizer.cpp --*- C++ -*-===// +// +// 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 +// +//===--===// +// +//===--===// + +#include "Analysis/SPIRVConvergenceRegionAnalysis.h" +#include "SPIRV.h" +#include "SPIRVSubtarget.h" +#include "SPIRVTargetMachine.h" +#include "SPIRVUtils.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/Analysis/LoopInfo.h" +#include "llvm/CodeGen/IntrinsicLowering.h" +#include "llvm/IR/CFG.h" +#include "llvm/IR/Dominators.h" +#include "llvm/IR/IRBuilder.h" +#include "llvm/IR/IntrinsicInst.h" +#include "llvm/IR/Intrinsics.h" +#include "llvm/IR/IntrinsicsSPIRV.h" +#include "llvm/InitializePasses.h" +#include "llvm/Transforms/Utils/Cloning.h" +#include "llvm/Transforms/Utils/LoopSimplify.h" +#include "llvm/Transforms/Utils/LowerMemIntrinsics.h" +#include +#include +#include + +using namespace llvm; +using namespace SPIRV; + +namespace llvm { + +void initializeSPIRVStructurizerPass(PassRegistry &); + +namespace { + +using BlockSet = std::unordered_set; +using Edge = std::pair; + +// Helper function to do a partial order visit from the block |Start|, calling +// |Op| on each visited node. +void partialOrderVisit(BasicBlock &Start, + std::function Op) { + PartialOrderingVisitor V(*Start.getParent()); + V.partialOrderVisit(Start, Op); +} + +// Returns the exact convergence region in the tree defined by `Node` for which +// `BB` is the header, nullptr otherwise. +const ConvergenceRegion *getRegionForHeader(const ConvergenceRegion *Node, +BasicBlock *BB) { + if (Node->Entry == BB) +return Node; + + for (auto *Child : Node->Children) { +const auto *CR = getRegionForHeader(Child, BB); +if (CR != nullptr) + return CR; + } + return nullptr; +} + +// Returns the single BasicBlock exiting the convergence region `CR`, +// nullptr if no such exit exists. +BasicBlock *getExitFor(const ConvergenceRegion *CR) { + std::unordered_set ExitTargets; + for (BasicBlock *Exit : CR->Exits) { +for (BasicBlock *Successor : successors(Exit)) { + if (CR->Blocks.count(Successor) == 0) +ExitTargets.insert(Successor); +} + } + + assert(ExitTargets.size() <= 1); + if (ExitTargets.size() == 0) +return nullptr; + + return *ExitTargets.begin(); +} + +// Returns the merge block designated by I if I is a merge instruction, nullptr +// otherwise. +BasicBlock *getDesignatedMergeBlock(Instruction *I) { + IntrinsicInst *II = dyn_cast(I); + if (II == nullptr) +return nullptr; + + if (II->getIntrinsicID() != Intrinsic::spv_loop_merge && + II->getIntrinsicID() != Intrinsic::spv_selection_merge) +return nullptr; + + BlockAddress *BA = cast(II->getOperand(0)); + return BA->getBasicBlock(); +} + +// Returns the continue block designated by I if I is an OpLoopMerge, nullptr +// otherwise. +BasicBlock *getDesignatedContinueBlock(Instruction *I) { + IntrinsicInst *II = dyn_cast(I); + if (II == nullptr) +return nullptr; + + if (II->getIntrinsicID() != Intrinsic::spv_loop_merge) +return nullptr; + + BlockAddress *BA = cast(II->getOperand(1)); + return BA->getBasicBlock(); +} + +// Returns true if Header has one merge instruction which designated Merge as +// merge block. +bool isDefinedAsSelectionMergeBy(BasicBlock &Header, BasicBlock &Merge) { + for (auto &I : Header) { +BasicBlock *MB = getDesignatedMergeBlock(&I); +if (MB == &Merge) + return true; + } + return false; +} + +// Returns true if the BB has one OpLoopMerge instruction. +bool hasLoopMergeInstruction(BasicBlock &BB) { + for (auto &I : BB) +if (getDesignatedContinueBlock(&I)) + return true; + return false; +} + +// Returns true is I is an OpSelectionMerge or OpLoopMerge instruction, false +// otherwise. +bool isMergeInstruction(Instruction *I) { + return getDesignatedMergeBlock(I) != nullptr; +} + +// Returns all blocks in F having at least one OpLoopMerge or OpSelectionMerge +// instruction. +SmallPtrSet getHeaderBlocks(Function &F) { + SmallPtrSet Output; + for (BasicBlock &BB : F) { +for (Instruction &I : BB) { + if (getDesignatedMergeBlock(&I) != nullptr) +
[clang] [llvm] [clang][HLSL] Add WaveIsFirstLane() intrinsic (PR #103299)
https://github.com/michalpaszkowski approved this pull request. https://github.com/llvm/llvm-project/pull/103299 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [llvm] [clang][SPIR-V] Add support for AMDGCN flavoured SPIRV (PR #89796)
https://github.com/michalpaszkowski approved this pull request. @AlexVlx LGTM! Thank you! https://github.com/llvm/llvm-project/pull/89796 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [llvm] [clang][SPIR-V] Add support for AMDGCN flavoured SPIRV (PR #89796)
@@ -56,6 +56,10 @@ static std::string computeDataLayout(const Triple &TT) { if (Arch == Triple::spirv32) return "e-p:32:32-i64:64-v16:16-v24:32-v32:32-v48:64-" "v96:128-v192:256-v256:256-v512:512-v1024:1024-G1"; + if (TT.getVendor() == Triple::VendorType::AMD && michalpaszkowski wrote: @AlexVlx Thanks for the pull request. Could you also please update the [SPIRVUsage](https://llvm.org/docs/SPIRVUsage.html) document? Any relevant information in the target triple section would be really appreciated. https://github.com/llvm/llvm-project/pull/89796 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [llvm] [clang][SPIR-V] Add support for AMDGCN flavoured SPIRV (PR #89796)
https://github.com/michalpaszkowski requested changes to this pull request. https://github.com/llvm/llvm-project/pull/89796 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [llvm] [clang][SPIR-V] Add support for AMDGCN flavoured SPIRV (PR #89796)
https://github.com/michalpaszkowski edited https://github.com/llvm/llvm-project/pull/89796 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [llvm] [clang][SPIR-V] Add support for AMDGCN flavoured SPIRV (PR #89796)
@@ -1,4 +1,5 @@ ; RUN: llc -O0 -mtriple=spirv64-unknown-unknown %s -o - | FileCheck %s +; RUN: llc -O0 -mtriple=spirv64-amd-amdhsa %s -o - | FileCheck %s michalpaszkowski wrote: I am okay with either approach. I think we can assume that the core functionality will stay the same for all "flavors". In case of any changes in the future to this assumption, we could create larger tests covering multiple features, which will not provide any isolation value but just ensure the features are still there. https://github.com/llvm/llvm-project/pull/89796 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][CodeGen] Add AS for Globals to SPIR & SPIRV datalayouts (PR #88455)
https://github.com/michalpaszkowski approved this pull request. LGTM (from the SPIR-V backend side)! https://github.com/llvm/llvm-project/pull/88455 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [llvm] [HLSL][SPIRV] Add any intrinsic lowering (PR #88325)
https://github.com/michalpaszkowski approved this pull request. https://github.com/llvm/llvm-project/pull/88325 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Offload] Move HIP and CUDA to new driver by default (PR #84420)
michalpaszkowski wrote: Hi @jhuber6! Thank you for the pull request! > This is not intended to be landed immediately, but to allow for greater > testing. One potential issue I've discovered is the lack of SPIR-V > support or handling for `--offload`. Do you mean the SPIR-V target (backend)? I have not followed this area of work closely. What is missing or what exactly needs to be supported by the SPIR-V target? Any help or pointers would be greatly appreciated! https://github.com/llvm/llvm-project/pull/84420 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [llvm] [HLSL][SPIR-V] Add SV_DispatchThreadID semantic support (PR #82536)
https://github.com/michalpaszkowski approved this pull request. https://github.com/llvm/llvm-project/pull/82536 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [llvm] [HLSL][SPIR-V] Add create.handle intrinsic (PR #81038)
https://github.com/michalpaszkowski approved this pull request. https://github.com/llvm/llvm-project/pull/81038 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [llvm] [HLSL][SPIR-V] Add Vulkan to target triple (PR #76749)
https://github.com/michalpaszkowski approved this pull request. https://github.com/llvm/llvm-project/pull/76749 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [llvm] [clang] [LLVM] Add IRNormalizer Pass (PR #68176)
michalpaszkowski wrote: [Here are the slides](https://llvm.org/devmtg/2019-10/slides/Paszkowski-LLVMCanon.pdf) that were presented at the LLVM Dev Meeting in 2019. It might be useful to include the link in the commit message for reference. @nikic Thanks for catching more things in the review! Especially the commutative ordering of operands/arguments. When it comes to including hashes in the naming algorithm (renaming is controlled using an option for already named values), the ideas is that by just looking at an instruction further down (a use) you can tell whether any inputs are different. And the other way around, by looking at initial instructions you can see how their "output footprint" has changed after transformations. The example below is a bit outdated, but reflects the general idea we had when considering naming algorithms: https://github.com/llvm/llvm-project/assets/13875746/fdb85b98-bce9-48df-91c0-35ffd115bae0";> https://github.com/llvm/llvm-project/assets/13875746/24d74cf1-ad21-47c0-9057-6065c7a4f472";> https://github.com/llvm/llvm-project/pull/68176 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[llvm] [clang] [clang-tools-extra] [LLVM] Add IRNormalizer Pass (PR #68176)
https://github.com/michalpaszkowski approved this pull request. Thank you for working on this! LGTM! https://github.com/llvm/llvm-project/pull/68176 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [LLVM] Add IRNormalizer Pass (PR #68176)
michalpaszkowski wrote: I added a couple more comments regarding the name change and formatting of the docs, but apart from these the patch looks good to me. https://github.com/llvm/llvm-project/pull/68176 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [LLVM] Add IRNormalizer Pass (PR #68176)
@@ -0,0 +1,637 @@ +//===--- IRNormalizer.cpp - IR Canonicalizer ---===// +// +// 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 +// +//===--===// +/// \file +/// This file implements the IRNormalizer class which aims to transform LLVM +/// Modules into a canonical form by reordering and renaming instructions while +/// preserving the same semantics. The normalizer makes it easier to spot +/// semantic differences while diffing two modules which have undergone +/// different passes. +/// +//===--===// + +#include "llvm/Transforms/Utils/IRNormalizer.h" +#include "llvm/ADT/SetVector.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/IR/BasicBlock.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/IRBuilder.h" +#include "llvm/IR/InstIterator.h" +#include "llvm/IR/Module.h" +#include "llvm/InitializePasses.h" +#include "llvm/Pass.h" +#include "llvm/PassRegistry.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Transforms/Utils.h" +#include +#include + +#define DEBUG_TYPE "normalize" + +using namespace llvm; + +namespace { +/// IRNormalizer aims to transform LLVM IR into canonical form. +class IRNormalizer { +public: + /// \name Canonicalizer flags. + /// @{ + /// Preserves original order of instructions. + static cl::opt PreserveOrder; + /// Renames all instructions (including user-named). + static cl::opt RenameAll; + /// Folds all regular instructions (including pre-outputs). + static cl::opt FoldPreoutputs; + /// Sorts and reorders operands in commutative instructions. + static cl::opt ReorderOperands; + /// @} + + bool runOnFunction(Function &F); + +private: + // Random constant for hashing, so the state isn't zero. + const uint64_t MagicHashConstant = 0x6acaa36bef8325c5ULL; + DenseSet NamedInstructions; + + /// \name Naming. + /// @{ + void nameFunctionArguments(Function &F); + void nameBasicBlocks(Function &F); + void nameInstruction(Instruction *I); + void nameAsInitialInstruction(Instruction *I); + void nameAsRegularInstruction(Instruction *I); + void foldInstructionName(Instruction *I); + /// @} + + /// \name Reordering. + /// @{ + void reorderInstructions(SmallVector &Outputs); + void reorderInstruction(Instruction *Used, Instruction *User, + SmallPtrSet &Visited); + void reorderInstructionOperandsByNames(Instruction *I); + void reorderPHIIncomingValues(PHINode *PN); + /// @} + + /// \name Utility methods. + /// @{ + SmallVector collectOutputInstructions(Function &F); + bool isOutput(const Instruction *I); + bool isInitialInstruction(const Instruction *I); + bool hasOnlyImmediateOperands(const Instruction *I); + SetVector + getOutputFootprint(Instruction *I, + SmallPtrSet &Visited); + /// @} +}; +} // namespace + +cl::opt IRNormalizer::PreserveOrder( +"preserve-order", cl::Hidden, +cl::desc("Preserves original instruction order")); +cl::opt IRNormalizer::RenameAll( +"rename-all", cl::Hidden, +cl::desc("Renames all instructions (including user-named)")); +cl::opt IRNormalizer::FoldPreoutputs( +"fold-all", cl::Hidden, +cl::desc("Folds all regular instructions (including pre-outputs)")); +cl::opt IRNormalizer::ReorderOperands( +"reorder-operands", cl::Hidden, +cl::desc("Sorts and reorders operands in commutative instructions")); + +/// Entry method to the IRNormalizer. +/// +/// \param M Module to canonicalize. michalpaszkowski wrote: canonicalize -> normalize https://github.com/llvm/llvm-project/pull/68176 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [LLVM] Add IRNormalizer Pass (PR #68176)
@@ -42,7 +42,10 @@ Non-comprehensive list of changes in this release functionality, or simply have a lot to talk about), see the `NOTE` below for adding a new subsection. -* ... +* Added a new IRNormalizer pass which aims to transform LLVM modules into + a canonical form by reordering and renaming instructions while preserving the + same semantics. The canonicalizer makes it easier to spot semantic differences michalpaszkowski wrote: canonicalizer -> normalizer https://github.com/llvm/llvm-project/pull/68176 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [LLVM] Add IRNormalizer Pass (PR #68176)
@@ -543,6 +543,15 @@ variables with initializers are marked as internal. An interprocedural variant of :ref:`Sparse Conditional Constant Propagation `. +``ir-normalizer``: Transforms IR into a canonical form that's easier to diff + + +This pass aims to transform LLVM Modules into a canonical form by reordering and +renaming instructions while preserving the same semantics. The canonicalizer makes michalpaszkowski wrote: canonicalizer -> normalizer https://github.com/llvm/llvm-project/pull/68176 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [LLVM] Add IRNormalizer Pass (PR #68176)
@@ -0,0 +1,637 @@ +//===--- IRNormalizer.cpp - IR Canonicalizer ---===// +// +// 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 +// +//===--===// +/// \file +/// This file implements the IRNormalizer class which aims to transform LLVM +/// Modules into a canonical form by reordering and renaming instructions while +/// preserving the same semantics. The normalizer makes it easier to spot +/// semantic differences while diffing two modules which have undergone +/// different passes. +/// +//===--===// + +#include "llvm/Transforms/Utils/IRNormalizer.h" +#include "llvm/ADT/SetVector.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/IR/BasicBlock.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/IRBuilder.h" +#include "llvm/IR/InstIterator.h" +#include "llvm/IR/Module.h" +#include "llvm/InitializePasses.h" +#include "llvm/Pass.h" +#include "llvm/PassRegistry.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Transforms/Utils.h" +#include +#include + +#define DEBUG_TYPE "normalize" + +using namespace llvm; + +namespace { +/// IRNormalizer aims to transform LLVM IR into canonical form. +class IRNormalizer { +public: + /// \name Canonicalizer flags. michalpaszkowski wrote: Canonicalizer -> Normalizer https://github.com/llvm/llvm-project/pull/68176 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [LLVM] Add IRNormalizer Pass (PR #68176)
@@ -0,0 +1,637 @@ +//===--- IRNormalizer.cpp - IR Canonicalizer ---===// michalpaszkowski wrote: Canonicalizer -> Normalizer https://github.com/llvm/llvm-project/pull/68176 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [LLVM] Add IRNormalizer Pass (PR #68176)
@@ -543,6 +543,15 @@ variables with initializers are marked as internal. An interprocedural variant of :ref:`Sparse Conditional Constant Propagation `. +``ir-normalizer``: Transforms IR into a canonical form that's easier to diff + + +This pass aims to transform LLVM Modules into a canonical form by reordering and +renaming instructions while preserving the same semantics. The canonicalizer makes +it easier to spot semantic differences while diffing two modules which have undergone +two different passes. + +--- michalpaszkowski wrote: Shouldn't this line be removed? and the line underscoring the "``ir-normalizer``: Transforms IR into a canonical form that's easier to diff" be made a bit longer? https://github.com/llvm/llvm-project/pull/68176 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] llvm-canon (PR #68176)
michalpaszkowski wrote: > Please don't use the term canon/canonicalize for this pass or tool. LLVM has > an existing notion of "canonicalization" which does not coincide with what is > being done here. @nikic I don't think the name "canon" or "canonicalizer" will lead to any confusion here. This is in fact what the pass is doing and mimics the name of MIR canonicalizer with similar assumptions as @plotfi noted . Using the term "canonicalization" for the current/existing set of passes is not really common or well defined. As for the RFC, there was a discussion thread in the LLVM Dev Mailing: https://lists.llvm.org/pipermail/llvm-dev/2019-August/134475.html https://github.com/llvm/llvm-project/pull/68176 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] llvm-canon (PR #68176)
michalpaszkowski wrote: > Please don't use the term canon/canonicalize for this pass or tool. LLVM has > an existing notion of "canonicalization" which does not coincide with what is > being done here. @nikic I don't think the name "canon" or "canonicalizer" will lead to any confusion here. This is in fact what the pass is doing and mimics the name of MIR canonicalizer with similar assumptions as @plotfi noted . Using the term "canonicalization" for the current/existing set of passes is not really common or well defined. As for the RFC, there was a discussion thread in the LLVM Dev Mailing: https://lists.llvm.org/pipermail/llvm-dev/2019-August/134475.html https://github.com/llvm/llvm-project/pull/68176 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] llvm-canon (PR #68176)
@@ -0,0 +1,638 @@ +//===--- IRCanonicalizer.cpp - IR Canonicalizer ---===// +// +// 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 +// +//===--===// +/// \file +/// This file implements the IRCanonicalizer class which aims to transform LLVM +/// Modules into a canonical form by reordering and renaming instructions while +/// preserving the same semantics. The canonicalizer makes it easier to spot +/// semantic differences while diffing two modules which have undergone +/// different passes. +/// +//===--===// + +#include "llvm/ADT/SetVector.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/IR/BasicBlock.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/IRBuilder.h" +#include "llvm/IR/InstIterator.h" +#include "llvm/IR/Module.h" +#include "llvm/InitializePasses.h" +#include "llvm/Pass.h" +#include "llvm/PassRegistry.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Transforms/Utils.h" +#include "llvm/Transforms/Utils/IRCanonicalizer.h" +#include +#include + +#define DEBUG_TYPE "canon" + +using namespace llvm; + +namespace { +/// IRCanonicalizer aims to transform LLVM IR into canonical form. +class IRCanonicalizer { +public: + /// \name Canonicalizer flags. + /// @{ + /// Preserves original order of instructions. + static cl::opt PreserveOrder; + /// Renames all instructions (including user-named). + static cl::opt RenameAll; + /// Folds all regular instructions (including pre-outputs). + static cl::opt FoldPreoutputs; + /// Sorts and reorders operands in commutative instructions. + static cl::opt ReorderOperands; + /// @} + + bool runOnFunction(Function &F); + +private: + // Random constant for hashing, so the state isn't zero. + const uint64_t MagicHashConstant = 0x6acaa36bef8325c5ULL; + DenseSet NamedInstructions; + + /// \name Naming. + /// @{ + void nameFunctionArguments(Function &F); + void nameBasicBlocks(Function &F); + void nameInstruction(Instruction *I); + void nameAsInitialInstruction(Instruction *I); + void nameAsRegularInstruction(Instruction *I); + void foldInstructionName(Instruction *I); + /// @} + + /// \name Reordering. + /// @{ + void reorderInstructions(SmallVector &Outputs); + void reorderInstruction(Instruction *Used, Instruction *User, + SmallPtrSet &Visited); + void reorderInstructionOperandsByNames(Instruction *I); + void reorderPHIIncomingValues(PHINode *PN); + /// @} + + /// \name Utility methods. + /// @{ + SmallVector collectOutputInstructions(Function &F); + bool isOutput(const Instruction *I); + bool isInitialInstruction(const Instruction *I); + bool hasOnlyImmediateOperands(const Instruction *I); + SetVector + getOutputFootprint(Instruction *I, + SmallPtrSet &Visited); + /// @} +}; +} // namespace + +cl::opt IRCanonicalizer::PreserveOrder( +"preserve-order", cl::Hidden, +cl::desc("Preserves original instruction order")); +cl::opt IRCanonicalizer::RenameAll( +"rename-all", cl::Hidden, +cl::desc("Renames all instructions (including user-named)")); +cl::opt IRCanonicalizer::FoldPreoutputs( +"fold-all", cl::Hidden, +cl::desc("Folds all regular instructions (including pre-outputs)")); +cl::opt IRCanonicalizer::ReorderOperands( +"reorder-operands", cl::Hidden, +cl::desc("Sorts and reorders operands in commutative instructions")); + +/// Entry method to the IRCanonicalizer. +/// +/// \param M Module to canonicalize. +bool IRCanonicalizer::runOnFunction(Function &F) { + nameFunctionArguments(F); + nameBasicBlocks(F); + + SmallVector Outputs = collectOutputInstructions(F); + + if (!PreserveOrder) +reorderInstructions(Outputs); + + for (auto &I : Outputs) +nameInstruction(I); + + for (auto &I : instructions(F)) { +if (!PreserveOrder) { + if (ReorderOperands && I.isCommutative()) +reorderInstructionOperandsByNames(&I); + + if (auto *PN = dyn_cast(&I)) +reorderPHIIncomingValues(PN); +} + +foldInstructionName(&I); + } + + return true; +} + +/// Numbers arguments. +/// +/// \param F Function whose arguments will be renamed. +void IRCanonicalizer::nameFunctionArguments(Function &F) { + int ArgumentCounter = 0; + for (auto &A : F.args()) { +if (RenameAll || A.getName().empty()) { + A.setName("a" + Twine(ArgumentCounter)); + ++ArgumentCounter; +} + } +} + +/// Names basic blocks using a generated hash for each basic block in +/// a function considering the opcode and the order of output instructions. +/// +/// \param F Function containing basic blocks to rename. +void IRCanonicalizer::nameBas
[clang] llvm-canon (PR #68176)
@@ -0,0 +1,638 @@ +//===--- IRCanonicalizer.cpp - IR Canonicalizer ---===// +// +// 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 +// +//===--===// +/// \file +/// This file implements the IRCanonicalizer class which aims to transform LLVM +/// Modules into a canonical form by reordering and renaming instructions while +/// preserving the same semantics. The canonicalizer makes it easier to spot +/// semantic differences while diffing two modules which have undergone +/// different passes. +/// +//===--===// + +#include "llvm/ADT/SetVector.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/IR/BasicBlock.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/IRBuilder.h" +#include "llvm/IR/InstIterator.h" +#include "llvm/IR/Module.h" +#include "llvm/InitializePasses.h" +#include "llvm/Pass.h" +#include "llvm/PassRegistry.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Transforms/Utils.h" +#include "llvm/Transforms/Utils/IRCanonicalizer.h" +#include +#include + +#define DEBUG_TYPE "canon" + +using namespace llvm; + +namespace { +/// IRCanonicalizer aims to transform LLVM IR into canonical form. +class IRCanonicalizer { +public: + /// \name Canonicalizer flags. + /// @{ + /// Preserves original order of instructions. + static cl::opt PreserveOrder; + /// Renames all instructions (including user-named). + static cl::opt RenameAll; + /// Folds all regular instructions (including pre-outputs). + static cl::opt FoldPreoutputs; + /// Sorts and reorders operands in commutative instructions. + static cl::opt ReorderOperands; + /// @} + + bool runOnFunction(Function &F); + +private: + // Random constant for hashing, so the state isn't zero. + const uint64_t MagicHashConstant = 0x6acaa36bef8325c5ULL; + DenseSet NamedInstructions; + + /// \name Naming. + /// @{ + void nameFunctionArguments(Function &F); + void nameBasicBlocks(Function &F); + void nameInstruction(Instruction *I); + void nameAsInitialInstruction(Instruction *I); + void nameAsRegularInstruction(Instruction *I); + void foldInstructionName(Instruction *I); + /// @} + + /// \name Reordering. + /// @{ + void reorderInstructions(SmallVector &Outputs); + void reorderInstruction(Instruction *Used, Instruction *User, + SmallPtrSet &Visited); + void reorderInstructionOperandsByNames(Instruction *I); + void reorderPHIIncomingValues(PHINode *PN); + /// @} + + /// \name Utility methods. + /// @{ + SmallVector collectOutputInstructions(Function &F); + bool isOutput(const Instruction *I); + bool isInitialInstruction(const Instruction *I); + bool hasOnlyImmediateOperands(const Instruction *I); + SetVector + getOutputFootprint(Instruction *I, + SmallPtrSet &Visited); + /// @} +}; +} // namespace + +cl::opt IRCanonicalizer::PreserveOrder( +"preserve-order", cl::Hidden, +cl::desc("Preserves original instruction order")); +cl::opt IRCanonicalizer::RenameAll( +"rename-all", cl::Hidden, +cl::desc("Renames all instructions (including user-named)")); +cl::opt IRCanonicalizer::FoldPreoutputs( +"fold-all", cl::Hidden, +cl::desc("Folds all regular instructions (including pre-outputs)")); +cl::opt IRCanonicalizer::ReorderOperands( +"reorder-operands", cl::Hidden, +cl::desc("Sorts and reorders operands in commutative instructions")); + +/// Entry method to the IRCanonicalizer. +/// +/// \param M Module to canonicalize. +bool IRCanonicalizer::runOnFunction(Function &F) { + nameFunctionArguments(F); + nameBasicBlocks(F); + + SmallVector Outputs = collectOutputInstructions(F); + + if (!PreserveOrder) +reorderInstructions(Outputs); + + for (auto &I : Outputs) +nameInstruction(I); + + for (auto &I : instructions(F)) { +if (!PreserveOrder) { + if (ReorderOperands && I.isCommutative()) +reorderInstructionOperandsByNames(&I); + + if (auto *PN = dyn_cast(&I)) +reorderPHIIncomingValues(PN); +} + +foldInstructionName(&I); + } + + return true; +} + +/// Numbers arguments. +/// +/// \param F Function whose arguments will be renamed. +void IRCanonicalizer::nameFunctionArguments(Function &F) { + int ArgumentCounter = 0; + for (auto &A : F.args()) { +if (RenameAll || A.getName().empty()) { + A.setName("a" + Twine(ArgumentCounter)); + ++ArgumentCounter; +} + } +} + +/// Names basic blocks using a generated hash for each basic block in +/// a function considering the opcode and the order of output instructions. +/// +/// \param F Function containing basic blocks to rename. +void IRCanonicalizer::nameBas
[clang-tools-extra] llvm-canon (PR #68176)
michalpaszkowski wrote: Thank you @justinfargnoli and @AidanGoldfarb for taking over this work and reaching out! I will review your changes in the coming week. CC @ChrisCummins FYI https://github.com/llvm/llvm-project/pull/68176 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] llvm-canon (PR #68176)
michalpaszkowski wrote: Thank you @justinfargnoli and @AidanGoldfarb for taking over this work and reaching out! I will review your changes in the coming week. CC @ChrisCummins FYI https://github.com/llvm/llvm-project/pull/68176 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits