diff --git a/src/Passes/.clang-tidy b/src/Passes/.clang-tidy index 4af1584f6c..9265e6feab 100644 --- a/src/Passes/.clang-tidy +++ b/src/Passes/.clang-tidy @@ -36,6 +36,7 @@ modernize-use-override,\ modernize-use-transparent-functors,\ misc-*,\ -misc-misplaced-widening-cast,\ +-misc-no-recursion,\ performance-*" WarningsAsErrors: '*' diff --git a/src/Passes/CMakeLists.txt b/src/Passes/CMakeLists.txt index 5cc1965c47..ef96ef3f7b 100644 --- a/src/Passes/CMakeLists.txt +++ b/src/Passes/CMakeLists.txt @@ -109,5 +109,4 @@ message(STATUS "${llvm_libs}") # Adding the libraries add_subdirectory(Source) -add_subdirectory(tests) diff --git a/src/Passes/Makefile b/src/Passes/Makefile index 3b556306aa..edde9868e1 100644 --- a/src/Passes/Makefile +++ b/src/Passes/Makefile @@ -13,7 +13,13 @@ serve-docs: documentation doxygen: doxygen doxygen.cfg + +test-examples: + # Run all examples and verify that the output is a valid IR + cd examples && make all + clean: rm -rf Release/ rm -rf Debug/ + cd examples && make clean diff --git a/src/Passes/README.md b/src/Passes/README.md new file mode 100644 index 0000000000..93081a950a --- /dev/null +++ b/src/Passes/README.md @@ -0,0 +1,50 @@ +# QIR Passes + +This document contains a brief introduction on how to use the QIR passes. A more comprehensive [walk-through is found here](./docs/src/index.md). + +## Building + +To build the tool, create a new build directory and switch to that directory: + +```sh +mkdir Debug +cd Debug/ +``` + +To build the library, first configure CMake from the build directory + +```sh +cmake .. +``` + +and then make your target + +```sh +make qat +``` + +For full instructions on dependencies and how to build, follow [these instructions](./docs/src/DeveloperGuide/Building.md). + +## Getting started + +Once the project is built (see next sections), you can transform a QIR according to a profile as follows: + +```sh +./Source/Apps/qat --generate --profile baseProfile -S ../examples/QirAllocationAnalysis/analysis-example.ll +``` + +Likewise, you can validate that a QIR follows a specification by running (Note, not implemented yet): + +```sh +./Source/Apps/qat --validate --profile baseProfile -S ../examples/QirAllocationAnalysis/analysis-example.ll +``` + +## Documentation + +Most of the documentation is available [directly on Github](./docs/src/index.md). If you need API documentation, you can build and run it by typing + +```sh +make serve-docs +``` + +in the root folder of the passes directory. diff --git a/src/Passes/Source/AllocationManager/AllocationManager.cpp b/src/Passes/Source/AllocationManager/AllocationManager.cpp index 8396396d86..5889beb12d 100644 --- a/src/Passes/Source/AllocationManager/AllocationManager.cpp +++ b/src/Passes/Source/AllocationManager/AllocationManager.cpp @@ -30,23 +30,13 @@ namespace quantum map.index = allocation_index_; map.size = size; - if (!name.empty()) - { - if (name_to_index_.find(map.name) != name_to_index_.end()) - { - throw std::runtime_error("Memory segment with name " + map.name + " already exists."); - } - - name_to_index_[map.name] = map.index; - } - map.start = next_qubit_index_; // Advancing start next_qubit_index_ += size; map.end = map.start + size; - mappings_.emplace(allocation_index_, std::move(map)); + mappings_.emplace_back(std::move(map)); // Advancing the allocation index ++allocation_index_; @@ -54,51 +44,38 @@ namespace quantum return ret; } - AllocationManager::Index AllocationManager::getOffset(String const& name) const - { - auto it = name_to_index_.find(name); - if (it == name_to_index_.end()) - { - throw std::runtime_error("Memory segment with name " + name + " not found."); - } - auto index = it->second; - - auto it2 = mappings_.find(index); - if (it2 == mappings_.end()) - { - throw std::runtime_error( - "Memory segment with name " + name + " not found - index exist, but not present in mapping."); - } - - return it2->second.start; - } - - AllocationManager::Address AllocationManager::getAddress(String const& name, Index const& n) const - { - return getAddress(getOffset(name), n); - } - AllocationManager::Address AllocationManager::getAddress(Address const& address, Index const& n) const { return address + n; } - void AllocationManager::release(String const& name) + void AllocationManager::release(Address const& address) { - auto it = name_to_index_.find(name); - if (it == name_to_index_.end()) + --allocation_index_; + auto it = mappings_.begin(); + + // Finding the element. Note that we could implement binary + // search but assume that we are dealing with few allocations + while (it != mappings_.end() && it->start != address) { - throw std::runtime_error("Memory segment with name " + name + " not found."); + ++it; } - name_to_index_.erase(it); - // TODO(tfr): Address to index - } + if (it == mappings_.end()) + { + throw std::runtime_error("Qubit segment not found."); + } - void AllocationManager::release(Address const&) - { - // TODO(tfr): Address to index - // TODO(tfr): Name to index + mappings_.erase(it); + if (mappings_.empty()) + { + next_qubit_index_ = 0; + } + else + { + auto& b = mappings_.back(); + next_qubit_index_ = b.start + b.size; + } } } // namespace quantum diff --git a/src/Passes/Source/AllocationManager/AllocationManager.hpp b/src/Passes/Source/AllocationManager/AllocationManager.hpp index 19aa1dd907..66379c0f2b 100644 --- a/src/Passes/Source/AllocationManager/AllocationManager.hpp +++ b/src/Passes/Source/AllocationManager/AllocationManager.hpp @@ -46,7 +46,7 @@ namespace quantum using Resources = std::unordered_map; using NameToIndex = std::unordered_map; using AddressToIndex = std::unordered_map; - using Mappings = std::unordered_map; + using Mappings = std::vector; /// Construction only allowed using smart pointer allocation through static functions. /// Constructors are private to prevent @@ -68,19 +68,9 @@ namespace quantum /// future and to be future proof, please use AllocationManager::getAddress(). Address allocate(String const& name = "", Index const& size = 1); - /// Gets the Address of a named segment or address. Given a named resource segment, this - /// function returns the address of the first element in the - Address getOffset(String const& name) const; - - /// Gets the Address of a named segments n'th element. - Address getAddress(String const& name, Index const& n) const; - /// Gets the Address of n'th element in a segment given the segments address. Address getAddress(Address const& address, Index const& n) const; - /// Releases the named segment. - void release(String const& name); - /// Releases the segment by address. void release(Address const& address); diff --git a/src/Passes/Source/AllocationManager/Tests/Unit/main.cpp b/src/Passes/Source/AllocationManager/Tests/Unit/main.cpp index a872ba5bde..5914e1e4c0 100644 --- a/src/Passes/Source/AllocationManager/Tests/Unit/main.cpp +++ b/src/Passes/Source/AllocationManager/Tests/Unit/main.cpp @@ -18,9 +18,6 @@ TEST(AllocationManagerTestSuite, LinearAllocationTest) // We expect that allocating manager->allocate("test", 10); - EXPECT_TRUE(manager->getOffset("test") == 5); EXPECT_TRUE(manager->allocate() == 15); manager->allocate("test2", 10); - EXPECT_TRUE(manager->getOffset("test") == 5); - EXPECT_TRUE(manager->getOffset("test2") == 16); } diff --git a/src/Passes/Source/Apps/CMakeLists.txt b/src/Passes/Source/Apps/CMakeLists.txt index 8a3be9264a..052a87114b 100644 --- a/src/Passes/Source/Apps/CMakeLists.txt +++ b/src/Passes/Source/Apps/CMakeLists.txt @@ -1,4 +1,4 @@ add_executable(qat Qat/Qat.cpp Qat/LlvmAnalysis.cpp) target_link_libraries(qat ${llvm_libs}) -target_link_libraries(qat ExpandStaticAllocation QirAllocationAnalysis TransformationRule Rules AllocationManager Commandline Profiles) \ No newline at end of file +target_link_libraries(qat ProfilePass Rules AllocationManager Commandline Profiles) \ No newline at end of file diff --git a/src/Passes/Source/Apps/Qat/Qat.cpp b/src/Passes/Source/Apps/Qat/Qat.cpp index f6f1ef1a96..b175245028 100644 --- a/src/Passes/Source/Apps/Qat/Qat.cpp +++ b/src/Passes/Source/Apps/Qat/Qat.cpp @@ -16,6 +16,7 @@ #include "Commandline/Settings.hpp" #include "Profiles/BaseProfile.hpp" #include "Profiles/IProfile.hpp" +#include "Profiles/RuleSetProfile.hpp" #include "Llvm/Llvm.hpp" @@ -35,14 +36,24 @@ int main(int argc, char** argv) {{"debug", "false"}, {"generate", "false"}, {"validate", "false"}, - {"profile", "base-profile"}, - {"S", "false"}}}; + {"profile", "baseProfile"}, + {"S", "false"}, + {"O0", "false"}, + {"O1", "false"}, + {"O2", "false"}, + {"O3", "false"}, + {"verify-module", "false"}}}; ParameterParser parser(settings); parser.addFlag("debug"); parser.addFlag("generate"); parser.addFlag("validate"); + parser.addFlag("verify-module"); parser.addFlag("S"); + parser.addFlag("O0"); + parser.addFlag("O1"); + parser.addFlag("O2"); + parser.addFlag("O3"); parser.parseArgs(argc, argv); @@ -64,11 +75,27 @@ int main(int argc, char** argv) } // Extracting commandline parameters - bool debug = settings.get("debug") == "true"; - bool generate = settings.get("generate") == "true"; - bool validate = settings.get("validate") == "true"; - auto optimisation_level = llvm::PassBuilder::OptimizationLevel::O1; - std::shared_ptr profile = std::make_shared(); + bool debug = settings.get("debug") == "true"; + bool generate = settings.get("generate") == "true"; + bool validate = settings.get("validate") == "true"; + auto optimisation_level = llvm::PassBuilder::OptimizationLevel::O0; + std::shared_ptr profile = std::make_shared(); + + // Setting the optimisation level + if (settings.get("O1") == "true") + { + optimisation_level = llvm::PassBuilder::OptimizationLevel::O1; + } + + if (settings.get("O2") == "true") + { + optimisation_level = llvm::PassBuilder::OptimizationLevel::O2; + } + + if (settings.get("O3") == "true") + { + optimisation_level = llvm::PassBuilder::OptimizationLevel::O3; + } // In case we debug, we also print the settings to allow provide a full // picture of what is going. @@ -103,6 +130,19 @@ int main(int argc, char** argv) llvm::errs() << "Byte code ouput is not supported yet. Please add -S to get human readible " "LL code.\n"; } + + // Verifying the module. + if (settings.get("verify-module") == "true") + { + llvm::VerifierAnalysis verifier; + auto result = verifier.run(*module, analyser.moduleAnalysisManager()); + if (result.IRBroken) + { + llvm::errs() << "IR is broken." + << "\n"; + exit(-1); + } + } } if (validate) diff --git a/src/Passes/Source/CMakeLists.txt b/src/Passes/Source/CMakeLists.txt index 0b9124106c..0ebd5668fa 100644 --- a/src/Passes/Source/CMakeLists.txt +++ b/src/Passes/Source/CMakeLists.txt @@ -8,15 +8,18 @@ microsoft_add_library(Commandline) microsoft_add_library(AllocationManager) microsoft_add_library_tests(AllocationManager) +microsoft_add_library(ProfilePass) +target_link_libraries(ProfilePass PRIVATE Rules) +# microsoft_add_library_tests(ProfilePass) + + microsoft_add_library(Rules) -microsoft_add_library_tests(Rules ExpandStaticAllocation QirAllocationAnalysis TransformationRule Rules AllocationManager Commandline Profiles) +microsoft_add_library_tests(Rules Rules ProfilePass AllocationManager Commandline Profiles) target_link_libraries(Rules PRIVATE AllocationManager) -add_subdirectory(Passes) - microsoft_add_library(Profiles) -target_link_libraries(Profiles PRIVATE Rules ExpandStaticAllocation TransformationRule QirAllocationAnalysis) -microsoft_add_library_tests(Profiles ExpandStaticAllocation QirAllocationAnalysis TransformationRule Rules AllocationManager Commandline Profiles) +target_link_libraries(Profiles PRIVATE Rules) +microsoft_add_library_tests(Profiles Rules AllocationManager Commandline Profiles) add_subdirectory(Apps) diff --git a/src/Passes/Source/Llvm/Llvm.hpp b/src/Passes/Source/Llvm/Llvm.hpp index 4979a02f1d..edfe85991a 100644 --- a/src/Passes/Source/Llvm/Llvm.hpp +++ b/src/Passes/Source/Llvm/Llvm.hpp @@ -56,6 +56,9 @@ #include "llvm/Transforms/Scalar/ADCE.h" #include "llvm/Transforms/Scalar/DCE.h" +// Const folding +#include "llvm/Analysis/ConstantFolding.h" + #if defined(__clang__) #pragma clang diagnostic pop #endif diff --git a/src/Passes/Source/Passes/CMakeLists.txt b/src/Passes/Source/Passes/CMakeLists.txt deleted file mode 100644 index 2aa6666f2d..0000000000 --- a/src/Passes/Source/Passes/CMakeLists.txt +++ /dev/null @@ -1,47 +0,0 @@ - -macro(list_qs_passes result) - file(GLOB children RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/*) - set(dirlist "") - foreach(child ${children}) - if(IS_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/${child}) - list(APPEND dirlist ${child}) - endif() - endforeach() - set(${result} ${dirlist}) -endmacro() - -list_qs_passes(ALL_PASSES) - -foreach(pass_plugin ${ALL_PASSES}) - - # Getting sources - file(GLOB sources RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/${pass_plugin}/*.cpp) - - # Adding library - add_library(${pass_plugin} - SHARED - ${sources}) - - # Adding include directories - target_include_directories( - ${pass_plugin} - PRIVATE - "${CMAKE_CURRENT_SOURCE_DIR}" - ) - - target_include_directories( - ${pass_plugin} - PRIVATE - "${CMAKE_CURRENT_SOURCE_DIR}/../include" - ) - - - # Linking - target_link_libraries(${pass_plugin} Rules) - - if(MICROSOFT_ENABLE_DYNAMIC_LOADING) - target_link_libraries(${pass_plugin} - "$<$:-undefined dynamic_lookup>") - endif(MICROSOFT_ENABLE_DYNAMIC_LOADING) - -endforeach() diff --git a/src/Passes/Source/Passes/ExpandStaticAllocation/ExpandStaticAllocation.cpp b/src/Passes/Source/Passes/ExpandStaticAllocation/ExpandStaticAllocation.cpp deleted file mode 100644 index 5f045ce4ed..0000000000 --- a/src/Passes/Source/Passes/ExpandStaticAllocation/ExpandStaticAllocation.cpp +++ /dev/null @@ -1,186 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -#include "Passes/ExpandStaticAllocation/ExpandStaticAllocation.hpp" - -#include "Llvm/Llvm.hpp" - -#include -#include - -namespace microsoft -{ -namespace quantum -{ - /// This pass traverse the IR and uses the QirAllocationAnalysis to determine - /// if a function call results in qubit and/or result allocation. If that is the case, - /// it makes a copy of the function and replaces the function call with a call to the - /// new function. - llvm::PreservedAnalyses ExpandStaticAllocationPass::run( - llvm::Function& function, - llvm::FunctionAnalysisManager& fam) - { - - // Pass body - for (auto& basic_block : function) - { - // Keeping track of instructions to remove in each block - std::vector to_remove; - - for (auto& instruction : basic_block) - { - // Finding calls - auto* call_instr = llvm::dyn_cast(&instruction); - if (call_instr == nullptr) - { - continue; - } - - ConstantArguments argument_constants{}; - std::vector remaining_arguments{}; - - auto callee_function = call_instr->getCalledFunction(); - auto& use_quantum = fam.getResult(*callee_function); - - if (use_quantum.value) - { - uint32_t idx = 0; - auto n = static_cast(callee_function->arg_size()); - - // Finding argument constants - while (idx < n) - { - auto arg = callee_function->getArg(idx); - auto value = call_instr->getArgOperand(idx); - - auto cst = llvm::dyn_cast(value); - if (cst != nullptr) - { - argument_constants[arg->getName().str()] = cst; - } - else - { - remaining_arguments.push_back(idx); - } - - ++idx; - } - - // Checking which arrays are constant for this - auto new_callee = expandFunctionCall(*callee_function, argument_constants); - - // Replacing call if a new function was created - if (new_callee != nullptr) - { - llvm::IRBuilder<> builder(call_instr); - - // List with new call arguments - std::vector new_arguments; - for (auto const& i : remaining_arguments) - { - // Getting the i'th argument - llvm::Value* arg = call_instr->getArgOperand(i); - - // Adding arguments that were not constant - if (argument_constants.find(arg->getName().str()) == argument_constants.end()) - { - new_arguments.push_back(arg); - } - } - - // Creating a new call - llvm::Value* new_call = builder.CreateCall(new_callee, new_arguments); - new_call->takeName(call_instr); - - // Replace all calls to old function with calls to new function - instruction.replaceAllUsesWith(new_call); - - // Schedule original instruction for deletion - to_remove.push_back(&instruction); - } - } - } - - // Removing instructions - for (auto& instruction : to_remove) - { - if (!instruction->use_empty()) - { - instruction->replaceAllUsesWith(llvm::UndefValue::get(instruction->getType())); - } - instruction->eraseFromParent(); - } - } - - return llvm::PreservedAnalyses::none(); - } - - llvm::Function* ExpandStaticAllocationPass::expandFunctionCall( - llvm::Function& callee, - ConstantArguments const& const_args) - { - auto module = callee.getParent(); - auto& context = module->getContext(); - llvm::IRBuilder<> builder(context); - - // Copying the original function - llvm::ValueToValueMapTy remapper; - std::vector arg_types; - - // The user might be deleting arguments to the function by specifying them in - // the VMap. If so, we need to not add the arguments to the arg ty vector - // - for (auto const& arg : callee.args()) - { - // Skipping constant arguments - - if (const_args.find(arg.getName().str()) != const_args.end()) - { - continue; - } - - arg_types.push_back(arg.getType()); - } - - // Creating a new function - llvm::FunctionType* function_type = llvm::FunctionType::get( - callee.getFunctionType()->getReturnType(), arg_types, callee.getFunctionType()->isVarArg()); - auto function = llvm::Function::Create( - function_type, callee.getLinkage(), callee.getAddressSpace(), callee.getName(), module); - - // Copying the non-const arguments - auto dest_args_it = function->arg_begin(); - - for (auto const& arg : callee.args()) - { - auto const_it = const_args.find(arg.getName().str()); - if (const_it == const_args.end()) - { - // Mapping remaining function arguments - dest_args_it->setName(arg.getName()); - remapper[&arg] = &*dest_args_it++; - } - else - { - remapper[&arg] = llvm::ConstantInt::get(context, const_it->second->getValue()); - } - } - - llvm::SmallVector returns; // Ignore returns cloned. - - // TODO(QAT-private-issue-28): In LLVM 13 upgrade 'true' to - // 'llvm::CloneFunctionChangeType::LocalChangesOnly' - llvm::CloneFunctionInto(function, &callee, remapper, true, returns, "", nullptr); - - verifyFunction(*function); - - return function; - } - - bool ExpandStaticAllocationPass::isRequired() - { - return true; - } - -} // namespace quantum -} // namespace microsoft diff --git a/src/Passes/Source/Passes/ExpandStaticAllocation/ExpandStaticAllocation.hpp b/src/Passes/Source/Passes/ExpandStaticAllocation/ExpandStaticAllocation.hpp deleted file mode 100644 index 7f3a7bb8a8..0000000000 --- a/src/Passes/Source/Passes/ExpandStaticAllocation/ExpandStaticAllocation.hpp +++ /dev/null @@ -1,50 +0,0 @@ -#pragma once -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -#include "Passes/QirAllocationAnalysis/QirAllocationAnalysis.hpp" - -#include "Llvm/Llvm.hpp" - -#include - -namespace microsoft -{ -namespace quantum -{ - - /// This class copies functions which does static qubit and/or result allocation. This is done - /// to ensure that qubits/result registers are not reused but instead assigned unique ids. - class ExpandStaticAllocationPass : public llvm::PassInfoMixin - { - public: - using QubitAllocationResult = QirAllocationAnalysis::Result; - using ConstantArguments = std::unordered_map; - - /// Constructors and destructors - /// @{ - ExpandStaticAllocationPass() = default; - ExpandStaticAllocationPass(ExpandStaticAllocationPass const&) = default; - ExpandStaticAllocationPass(ExpandStaticAllocationPass&&) = default; - ~ExpandStaticAllocationPass() = default; - /// @} - - /// Operators - /// @{ - ExpandStaticAllocationPass& operator=(ExpandStaticAllocationPass const&) = default; - ExpandStaticAllocationPass& operator=(ExpandStaticAllocationPass&&) = default; - /// @} - - /// Functions required by LLVM - /// @{ - llvm::PreservedAnalyses run(llvm::Function& function, llvm::FunctionAnalysisManager& fam); - static bool isRequired(); - /// @} - - /// @{ - llvm::Function* expandFunctionCall(llvm::Function& callee, ConstantArguments const& const_args); - /// @} - }; - -} // namespace quantum -} // namespace microsoft diff --git a/src/Passes/Source/Passes/ExpandStaticAllocation/LibExpandStaticAllocation.cpp b/src/Passes/Source/Passes/ExpandStaticAllocation/LibExpandStaticAllocation.cpp deleted file mode 100644 index 56c72d6b03..0000000000 --- a/src/Passes/Source/Passes/ExpandStaticAllocation/LibExpandStaticAllocation.cpp +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -#include "Passes/ExpandStaticAllocation/ExpandStaticAllocation.hpp" - -#include "Llvm/Llvm.hpp" - -#include -#include - -namespace -{ -llvm::PassPluginLibraryInfo getExpandStaticAllocationPluginInfo() -{ - using namespace microsoft::quantum; - using namespace llvm; - - return {LLVM_PLUGIN_API_VERSION, "ExpandStaticAllocation", LLVM_VERSION_STRING, [](PassBuilder& pb) { - // Registering the pass - pb.registerPipelineParsingCallback( - [](StringRef name, FunctionPassManager& fpm, ArrayRef /*unused*/) { - if (name == "expand-static-allocation") - { - fpm.addPass(ExpandStaticAllocationPass()); - return true; - } - - return false; - }); - }}; -} -} // namespace - -// Interface for loading the plugin -extern "C" LLVM_ATTRIBUTE_WEAK ::llvm::PassPluginLibraryInfo llvmGetPassPluginInfo() -{ - return getExpandStaticAllocationPluginInfo(); -} diff --git a/src/Passes/Source/Passes/QirAllocationAnalysis/LibQirAllocationAnalysis.cpp b/src/Passes/Source/Passes/QirAllocationAnalysis/LibQirAllocationAnalysis.cpp deleted file mode 100644 index 47ad891e73..0000000000 --- a/src/Passes/Source/Passes/QirAllocationAnalysis/LibQirAllocationAnalysis.cpp +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -#include "Passes/QirAllocationAnalysis/QirAllocationAnalysis.hpp" - -#include "Llvm/Llvm.hpp" - -#include -#include - -namespace -{ -// Interface to plugin -llvm::PassPluginLibraryInfo getQirAllocationAnalysisPluginInfo() -{ - using namespace microsoft::quantum; - using namespace llvm; - - return {LLVM_PLUGIN_API_VERSION, "QirAllocationAnalysis", LLVM_VERSION_STRING, [](PassBuilder& pb) { - // Registering a printer for the anaylsis - pb.registerPipelineParsingCallback( - [](StringRef name, FunctionPassManager& fpm, ArrayRef /*unused*/) { - if (name == "print") - { - fpm.addPass(QirAllocationAnalysisPrinter(llvm::errs())); - return true; - } - return false; - }); - - pb.registerVectorizerStartEPCallback( - [](llvm::FunctionPassManager& fpm, llvm::PassBuilder::OptimizationLevel /*level*/) { - fpm.addPass(QirAllocationAnalysisPrinter(llvm::errs())); - }); - - // Registering the analysis module - pb.registerAnalysisRegistrationCallback( - [](FunctionAnalysisManager& fam) { fam.registerPass([] { return QirAllocationAnalysis(); }); }); - }}; -} - -} // namespace - -extern "C" LLVM_ATTRIBUTE_WEAK ::llvm::PassPluginLibraryInfo llvmGetPassPluginInfo() -{ - return getQirAllocationAnalysisPluginInfo(); -} diff --git a/src/Passes/Source/Passes/QirAllocationAnalysis/QirAllocationAnalysis.cpp b/src/Passes/Source/Passes/QirAllocationAnalysis/QirAllocationAnalysis.cpp deleted file mode 100644 index fea4377fee..0000000000 --- a/src/Passes/Source/Passes/QirAllocationAnalysis/QirAllocationAnalysis.cpp +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -#include "Passes/QirAllocationAnalysis/QirAllocationAnalysis.hpp" - -#include "Llvm/Llvm.hpp" - -#include -#include -#include - -namespace microsoft -{ -namespace quantum -{ - - QirAllocationAnalysis::Result QirAllocationAnalysis::run( - llvm::Function& function, - llvm::FunctionAnalysisManager& /*unused*/) - { - for (auto& basic_block : function) - { - for (auto& instr : basic_block) - { - auto call_instr = llvm::dyn_cast(&instr); - if (call_instr == nullptr) - { - continue; - } - auto target_function = call_instr->getCalledFunction(); - auto name = target_function->getName(); - - // Checking for qubit allocation - if (name == "__quantum__rt__qubit_allocate") - { - return {true}; - } - - if (name == "__quantum__rt__qubit_allocate_array") - { - return {true}; - } - - // Checking for result allocation - if (name == "__quantum__qis__m__body") - { - return {true}; - } - } - } - - return {false}; - } - - QirAllocationAnalysisPrinter::QirAllocationAnalysisPrinter(llvm::raw_ostream& out_stream) - : out_stream_(out_stream) - { - } - - llvm::PreservedAnalyses QirAllocationAnalysisPrinter::run( - llvm::Function& function, - llvm::FunctionAnalysisManager& fam) - { - auto& result = fam.getResult(function); - - if (result.value) - { - out_stream_ << function.getName() << " contains quantum allocations.\n"; - } - else - { - out_stream_ << function.getName() << " is logic only.\n"; - } - return llvm::PreservedAnalyses::all(); - } - - bool QirAllocationAnalysisPrinter::isRequired() - { - return true; - } - - llvm::AnalysisKey QirAllocationAnalysis::Key; - -} // namespace quantum -} // namespace microsoft diff --git a/src/Passes/Source/Passes/QirAllocationAnalysis/QirAllocationAnalysis.hpp b/src/Passes/Source/Passes/QirAllocationAnalysis/QirAllocationAnalysis.hpp deleted file mode 100644 index 3d6c6f3c21..0000000000 --- a/src/Passes/Source/Passes/QirAllocationAnalysis/QirAllocationAnalysis.hpp +++ /dev/null @@ -1,83 +0,0 @@ -#pragma once -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -#include "Llvm/Llvm.hpp" - -#include -#include - -namespace microsoft -{ -namespace quantum -{ - - /// QirAllocationAnalysis is a LLVM pass that statistics on the usage of operations which allocates - /// resources such as qubits and results. - class QirAllocationAnalysis : public llvm::AnalysisInfoMixin - { - public: - using String = std::string; - - /// Result annotation. Contains a single value which - /// is true if the function uses allocations of qubits or results. - struct Result - { - bool value{false}; - }; - - /// Constructors and destructors - /// @{ - QirAllocationAnalysis() = default; - QirAllocationAnalysis(QirAllocationAnalysis const&) = delete; - QirAllocationAnalysis(QirAllocationAnalysis&&) = default; - ~QirAllocationAnalysis() = default; - /// @} - - /// Operators - /// @{ - QirAllocationAnalysis& operator=(QirAllocationAnalysis const&) = delete; - QirAllocationAnalysis& operator=(QirAllocationAnalysis&&) = delete; - /// @} - - /// Functions required by LLVM - /// @{ - Result run(llvm::Function& function, llvm::FunctionAnalysisManager& /*unused*/); - /// @} - - private: - static llvm::AnalysisKey Key; // NOLINT - friend struct llvm::AnalysisInfoMixin; - }; - - /// QirAllocationAnalysisPrinter is a LLVM pass class that prints statistics generated by - /// QirAllocationAnalysis. - class QirAllocationAnalysisPrinter : public llvm::PassInfoMixin - { - public: - /// Constructors and destructors - /// @{ - explicit QirAllocationAnalysisPrinter(llvm::raw_ostream& out_stream); - QirAllocationAnalysisPrinter() = delete; - QirAllocationAnalysisPrinter(QirAllocationAnalysisPrinter const&) = delete; - QirAllocationAnalysisPrinter(QirAllocationAnalysisPrinter&&) = default; - ~QirAllocationAnalysisPrinter() = default; - /// @} - - /// Operators - /// @{ - QirAllocationAnalysisPrinter& operator=(QirAllocationAnalysisPrinter const&) = delete; - QirAllocationAnalysisPrinter& operator=(QirAllocationAnalysisPrinter&&) = delete; - /// @} - - /// Functions required by LLVM - /// @{ - llvm::PreservedAnalyses run(llvm::Function& function, llvm::FunctionAnalysisManager& fam); - static bool isRequired(); - /// @} - private: - llvm::raw_ostream& out_stream_; - }; - -} // namespace quantum -} // namespace microsoft diff --git a/src/Passes/Source/Passes/TransformationRule/LibTransformationRule.cpp b/src/Passes/Source/Passes/TransformationRule/LibTransformationRule.cpp deleted file mode 100644 index 41a9e19eef..0000000000 --- a/src/Passes/Source/Passes/TransformationRule/LibTransformationRule.cpp +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -#include "Passes/TransformationRule/TransformationRule.hpp" -#include "Rules/Factory.hpp" - -#include "Llvm/Llvm.hpp" - -#include -#include - -namespace -{ -llvm::PassPluginLibraryInfo getTransformationRulePluginInfo() -{ - using namespace microsoft::quantum; - using namespace llvm; - - return {LLVM_PLUGIN_API_VERSION, "TransformationRule", LLVM_VERSION_STRING, [](PassBuilder& pb) { - // Registering the pass - pb.registerPipelineParsingCallback( - [](StringRef name, FunctionPassManager& fpm, ArrayRef /*unused*/) { - // Base profile - if (name == "restrict-qir") - { - // Defining a harded coded set of rules as LLVM does not provide means - // to configure passes through opt. - RuleSet rule_set; - - // Defining the mapping - auto factory = RuleFactory(rule_set); - - factory.useStaticQubitArrayAllocation(); - factory.useStaticQubitAllocation(); - factory.useStaticResultAllocation(); - - factory.optimiseBranchQuatumOne(); - // factory.optimiseBranchQuatumZero(); - - factory.disableReferenceCounting(); - factory.disableAliasCounting(); - factory.disableStringSupport(); - - fpm.addPass(TransformationRulePass(std::move(rule_set))); - return true; - } - - return false; - }); - }}; -} -} // namespace - -// Interface for loading the plugin -extern "C" LLVM_ATTRIBUTE_WEAK ::llvm::PassPluginLibraryInfo llvmGetPassPluginInfo() -{ - return getTransformationRulePluginInfo(); -} diff --git a/src/Passes/Source/Passes/TransformationRule/TransformationRule.cpp b/src/Passes/Source/Passes/TransformationRule/TransformationRule.cpp deleted file mode 100644 index 297fbd8d4e..0000000000 --- a/src/Passes/Source/Passes/TransformationRule/TransformationRule.cpp +++ /dev/null @@ -1,88 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -#include "Passes/TransformationRule/TransformationRule.hpp" - -#include "Llvm/Llvm.hpp" - -#include -#include - -namespace microsoft -{ -namespace quantum -{ - TransformationRulePass::TransformationRulePass(RuleSet&& rule_set) - : rule_set_{std::move(rule_set)} - { - } - - llvm::PreservedAnalyses TransformationRulePass::run( - llvm::Function& function, - llvm::FunctionAnalysisManager& /*fam*/) - { - replacements_.clear(); - - // For every instruction in every block, we attempt a match - // and replace. - for (auto& basic_block : function) - { - for (auto& instr : basic_block) - { - rule_set_.matchAndReplace(&instr, replacements_); - } - } - - // Applying all replacements - for (auto it = replacements_.rbegin(); it != replacements_.rend(); ++it) - { - auto instr1 = llvm::dyn_cast(it->first); - if (instr1 == nullptr) - { - llvm::errs() << "; WARNING: cannot deal with non-instruction replacements\n"; - continue; - } - - // Cheking if have a replacement for the instruction - if (it->second != nullptr) - { - // ... if so, we just replace it, - auto instr2 = llvm::dyn_cast(it->second); - if (instr2 == nullptr) - { - llvm::errs() << "; WARNING: cannot replace instruction with non-instruction\n"; - continue; - } - llvm::ReplaceInstWithInst(instr1, instr2); - } - else - { - // ... otherwise we delete the the instruction - // Removing all uses - if (!instr1->use_empty()) - { - instr1->replaceAllUsesWith(llvm::UndefValue::get(instr1->getType())); - } - - // And finally we delete the instruction - instr1->eraseFromParent(); - } - } - - // If we did not change the IR, we report that we preserved all - if (replacements_.empty()) - { - return llvm::PreservedAnalyses::all(); - } - - // ... and otherwise, we report that we preserved none. - return llvm::PreservedAnalyses::none(); - } - - bool TransformationRulePass::isRequired() - { - return true; - } - -} // namespace quantum -} // namespace microsoft diff --git a/src/Passes/Source/Passes/TransformationRule/TransformationRule.hpp b/src/Passes/Source/Passes/TransformationRule/TransformationRule.hpp deleted file mode 100644 index 5f2bee4702..0000000000 --- a/src/Passes/Source/Passes/TransformationRule/TransformationRule.hpp +++ /dev/null @@ -1,75 +0,0 @@ -#pragma once -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -#include "Rules/RuleSet.hpp" - -#include "Llvm/Llvm.hpp" - -#include - -namespace microsoft -{ -namespace quantum -{ - - /// This class applies a set of transformation rules to the IR to transform it into a new IR. The - /// rules are added using the RuleSet class which allows the developer to create one or more rules - /// on how to transform the IR. - class TransformationRulePass : public llvm::PassInfoMixin - { - public: - using Replacements = ReplacementRule::Replacements; - using Instruction = llvm::Instruction; - using Rules = std::vector; - using Value = llvm::Value; - using Builder = ReplacementRule::Builder; - using AllocationManagerPtr = AllocationManager::AllocationManagerPtr; - - /// Construction and destruction configuration. - /// @{ - - /// Constructor which creates a pass with a given set of rules. - explicit TransformationRulePass(RuleSet&& rule_set); - - /// Default construction is not permitted. - TransformationRulePass() = delete; - - /// Copy construction is banned. - TransformationRulePass(TransformationRulePass const&) = delete; - - /// We allow move semantics. - TransformationRulePass(TransformationRulePass&&) = default; - - /// Default destruction. - ~TransformationRulePass() = default; - /// @} - - /// Operators - /// @{ - - /// Copy assignment is banned. - TransformationRulePass& operator=(TransformationRulePass const&) = delete; - - /// Move assignement is permitted. - TransformationRulePass& operator=(TransformationRulePass&&) = default; - /// @} - - /// Functions required by LLVM - /// @{ - - /// Implements the transformation analysis which uses the supplied ruleset to make substitutions - /// in each function. - llvm::PreservedAnalyses run(llvm::Function& function, llvm::FunctionAnalysisManager& fam); - - /// Whether or not this pass is required to run. - static bool isRequired(); - /// @} - - private: - RuleSet rule_set_{}; - Replacements replacements_; ///< Registered replacements to be executed. - }; - -} // namespace quantum -} // namespace microsoft diff --git a/src/Passes/Source/ProfilePass/Profile.cpp b/src/Passes/Source/ProfilePass/Profile.cpp new file mode 100644 index 0000000000..0afb32a85e --- /dev/null +++ b/src/Passes/Source/ProfilePass/Profile.cpp @@ -0,0 +1,680 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "ProfilePass/Profile.hpp" +#include "Rules/Factory.hpp" +#include "Rules/Notation/Notation.hpp" +#include "Rules/ReplacementRule.hpp" + +#include "Llvm/Llvm.hpp" + +#include +#include + +namespace microsoft +{ +namespace quantum +{ + + void ProfilePass::setupCopyAndExpand() + { + using namespace microsoft::quantum::notation; + addConstExprRule( + {branch("cond"_cap = constInt(), "if_false"_cap = _, "if_true"_cap = _), + [](Builder& builder, Value* val, Captures& captures, Replacements& replacements) { + auto cst = llvm::dyn_cast(captures["cond"]); + auto instr = llvm::dyn_cast(val); + + if (cst == nullptr || instr == nullptr) + { + return false; + } + + auto branch_cond = cst->getValue().getZExtValue(); + auto if_true = llvm::dyn_cast(captures["if_true"]); + auto if_false = llvm::dyn_cast(captures["if_false"]); + + auto type = instr->getType(); + if (type == nullptr) + { + return false; + } + + if (branch_cond) + { + builder.CreateBr(if_true); + instr->replaceAllUsesWith(llvm::UndefValue::get(type)); + } + else + { + builder.CreateBr(if_false); + instr->replaceAllUsesWith(llvm::UndefValue::get(type)); + } + + replacements.push_back({val, nullptr}); + + return true; + }}); + } + + void ProfilePass::addConstExprRule(ReplacementRule&& rule) + { + auto ret = std::make_shared(std::move(rule)); + + const_expr_replacements_.addRule(ret); + } + + void ProfilePass::constantFoldFunction(llvm::Function& function) + { + std::vector to_delete; + + // Folding all constants + for (auto& basic_block : function) + { + + for (auto& instr : basic_block) + { + auto module = instr.getModule(); + auto const& dl = module->getDataLayout(); + auto cst = llvm::ConstantFoldInstruction(&instr, dl, nullptr); + if (cst != nullptr) + { + instr.replaceAllUsesWith(cst); + to_delete.push_back(&instr); + } + } + } + + // Deleting constants + for (auto& x : to_delete) + { + x->eraseFromParent(); + } + + // Folding constant expressions + Replacements replacements; + for (auto& basic_block : function) + { + for (auto& instr : basic_block) + { + + const_expr_replacements_.matchAndReplace(&instr, replacements); + } + } + + for (auto& r : replacements) + { + if (r.second != nullptr) + { + throw std::runtime_error("Real replacements not implemented."); + } + auto instr = llvm::dyn_cast(r.first); + if (instr != nullptr) + { + instr->eraseFromParent(); + continue; + } + + auto block = llvm::dyn_cast(r.first); + if (block != nullptr) + { + llvm::DeleteDeadBlock(block); + } + } + } + + llvm::Value* ProfilePass::copyAndExpand(llvm::Value* input, DeletableInstructions& schedule_instruction_deletion) + { + llvm::Value* ret = input; + auto* call_instr = llvm::dyn_cast(input); + auto instr_ptr = llvm::dyn_cast(input); + if (call_instr != nullptr && instr_ptr != nullptr) + { + auto& instr = *instr_ptr; + + auto callee_function = call_instr->getCalledFunction(); + if (!callee_function->isDeclaration()) + { + ConstantArguments argument_constants{}; + std::vector remaining_arguments{}; + + uint32_t idx = 0; + auto n = static_cast(callee_function->arg_size()); + + // Finding argument constants + while (idx < n) + { + auto arg = callee_function->getArg(idx); + auto value = call_instr->getArgOperand(idx); + + auto cst = llvm::dyn_cast(value); + if (cst != nullptr) + { + argument_constants[arg->getName().str()] = cst; + } + else + { + remaining_arguments.push_back(idx); + } + + ++idx; + } + + // Making a function copy + auto new_callee = expandFunctionCall(*callee_function, argument_constants); + + // Replacing call if a new function was created + if (new_callee != nullptr) + { + + llvm::IRBuilder<> builder(call_instr); + + // List with new call arguments + std::vector new_arguments; + for (auto const& i : remaining_arguments) + { + // Getting the i'th argument + llvm::Value* arg = call_instr->getArgOperand(i); + + // Adding arguments that were not constant + if (argument_constants.find(arg->getName().str()) == argument_constants.end()) + { + new_arguments.push_back(arg); + } + } + + // Creating a new call + auto* new_call = builder.CreateCall(new_callee, new_arguments); + new_call->takeName(call_instr); + + // Replace all calls to old function with calls to new function + instr.replaceAllUsesWith(new_call); + + // Deleting instruction + schedule_instruction_deletion.push_back(&instr); + // TODO(tfr): Delete instruction, instr.deleteInstru??; + + constantFoldFunction(*new_callee); + + // Recursion: Returning the new call as the instruction to be analysed + ret = new_call; + } + + // Deleting the function the original function if it is no longer in use + if (callee_function->use_empty()) + { + callee_function->eraseFromParent(); + } + } + } + + return ret; + } + + llvm::Value* ProfilePass::detectActiveCode(llvm::Value* input, DeletableInstructions&) + { + active_pieces_.insert(input); + return input; + } + + bool ProfilePass::runOnFunction(llvm::Function& function, InstructionModifier const& modifier) + { + if (depth_ >= max_recursion_) + { + llvm::errs() << "Exceed max recursion of " << max_recursion_ << "\n"; + return false; + } + ++depth_; + + // Keep track of instructions scheduled for deletion + DeletableInstructions schedule_instruction_deletion; + + // Block queue + std::deque queue; + std::unordered_set blocks_queued; + queue.push_back(&function.getEntryBlock()); + blocks_queued.insert(&function.getEntryBlock()); + + // Executing the modifier on the function itsel + modifier(&function, schedule_instruction_deletion); + + while (!queue.empty()) + { + auto& basic_block = *(queue.front()); + queue.pop_front(); + + // Executing the modifier on the block + modifier(&basic_block, schedule_instruction_deletion); + + for (auto& instr : basic_block) + { + // Modifying instruction as needed + auto instr_ptr = modifier(&instr, schedule_instruction_deletion); + + // In case the instruction was scheduled for deletion + if (instr_ptr == nullptr) + { + continue; + } + + // Checking if we are calling a function + auto call_instr = llvm::dyn_cast(instr_ptr); + if (call_instr != nullptr) + { + auto callee_function = call_instr->getCalledFunction(); + if (!callee_function->isDeclaration()) + { + runOnFunction(*callee_function, modifier); + } + } + + // Following the branches to their basic blocks + auto* br_instr = llvm::dyn_cast(&instr); + if (br_instr != nullptr) + { + for (uint32_t i = 0; i < br_instr->getNumOperands(); ++i) + { + // TODO(tfr): This may not work on multi path branches (conditional) + // as we may accidently add the final path (contains qubit release) + // and we cannot make assumptions since optimisation may have rearranged + // everything. In this case, we should revert to the order they appear in the + // function + auto bb = llvm::dyn_cast(br_instr->getOperand(i)); + if (bb != nullptr) + { + + // Ensuring that we are not scheduling the same block twice + if (blocks_queued.find(bb) == blocks_queued.end()) + { + queue.push_back(bb); + blocks_queued.insert(bb); + } + } + } + } + } + } + + // Deleting constants + for (auto& x : schedule_instruction_deletion) + { + x->eraseFromParent(); + } + + --depth_; + + return true; + } + + bool ProfilePass::isActive(llvm::Value* value) const + { + return active_pieces_.find(value) != active_pieces_.end(); + } + + void ProfilePass::runCopyAndExpand(llvm::Module& module, llvm::ModuleAnalysisManager&) + { + replacements_.clear(); + // For every instruction in every block, we attempt a match + // and replace. + for (auto& function : module) + { + if (function.hasFnAttribute("EntryPoint")) + { + runOnFunction(function, [this](llvm::Value* value, DeletableInstructions& modifier) { + return copyAndExpand(value, modifier); + }); + } + } + + // Dead code detection + for (auto& function : module) + { + if (function.hasFnAttribute("EntryPoint")) + { + // Marking function as active + active_pieces_.insert(&function); + + // Detectecting active code + runOnFunction(function, [this](llvm::Value* value, DeletableInstructions& modifier) { + return detectActiveCode(value, modifier); + }); + } + } + + applyReplacements(); + } + + void ProfilePass::applyReplacements() + { + // Applying all replacements + + std::unordered_set already_removed; + for (auto it = replacements_.rbegin(); it != replacements_.rend(); ++it) + { + auto instr1 = llvm::dyn_cast(it->first); + + // Checking if by accident the same instruction was added + if (already_removed.find(instr1) != already_removed.end()) + { + throw std::runtime_error("Instruction was already removed."); + } + already_removed.insert(instr1); + + if (instr1 == nullptr) + { + llvm::errs() << "; WARNING: cannot deal with non-instruction replacements\n"; + continue; + } + + // Cheking if have a replacement for the instruction + if (it->second != nullptr) + { + // ... if so, we just replace it, + auto instr2 = llvm::dyn_cast(it->second); + if (instr2 == nullptr) + { + llvm::errs() << "; WARNING: cannot replace instruction with non-instruction\n"; + continue; + } + llvm::ReplaceInstWithInst(instr1, instr2); + } + else + { + // ... otherwise we delete the the instruction + // Removing all uses + if (!instr1->use_empty()) + { + auto type = instr1->getType(); + if (type != nullptr) + { + instr1->replaceAllUsesWith(llvm::UndefValue::get(type)); + } + } + + // And finally we delete the instruction + if (instr1->use_empty()) + { + instr1->eraseFromParent(); + } + } + } + + replacements_.clear(); + } + + void ProfilePass::runDetectActiveCode(llvm::Module& module, llvm::ModuleAnalysisManager&) + { + blocks_to_delete_.clear(); + functions_to_delete_.clear(); + + for (auto& function : module) + { + if (isActive(&function)) + { + for (auto& block : function) + { + if (!isActive(&block)) + { + blocks_to_delete_.push_back(&block); + } + } + } + else if (!function.isDeclaration()) + { + functions_to_delete_.push_back(&function); + } + } + } + + void ProfilePass::runDeleteDeadCode(llvm::Module&, llvm::ModuleAnalysisManager&) + { + std::vector to_delete; + + // Removing all function references and scheduling blocks for deletion + for (auto& function : functions_to_delete_) + { + // Schedule for deletion + function->replaceAllUsesWith(llvm::UndefValue::get(function->getType())); + + function->clearGC(); + function->clearMetadata(); + + for (auto& block : *function) + { + // Removing all instructions + for (auto& instr : block) + { + instr.replaceAllUsesWith(llvm::UndefValue::get(instr.getType())); + to_delete.push_back(&instr); + } + + // Removing all block references + block.replaceAllUsesWith(llvm::UndefValue::get(block.getType())); + + // Scheduling block deletion + blocks_to_delete_.push_back(&block); + } + } + + // Removing all instructions + for (auto& instr : to_delete) + { + instr->eraseFromParent(); + } + + // Deleting all blocks + for (auto block : blocks_to_delete_) + { + block->replaceAllUsesWith(llvm::UndefValue::get(block->getType())); + if (block->use_empty()) + { + block->eraseFromParent(); + } + } + + // Removing functions + for (auto& function : functions_to_delete_) + { + if (function->isDeclaration() && function->use_empty()) + { + function->eraseFromParent(); + } + } + } + + void ProfilePass::runReplacePhi(llvm::Module& module, llvm::ModuleAnalysisManager&) + { + using namespace microsoft::quantum::notation; + auto rule = phi("b1"_cap = _, "b2"_cap = _); + IOperandPrototype::Captures captures; + std::vector to_delete; + + for (auto& function : module) + { + for (auto& block : function) + { + for (auto& instr : block) + { + if (rule->match(&instr, captures)) + { + auto phi = llvm::dyn_cast(&instr); + if (phi == nullptr) + { + continue; + } + + auto val1 = captures["b1"]; + auto val2 = captures["b2"]; + + auto block1 = phi->getIncomingBlock(0); // TODO(tfr): Make sure that block1 matches val1 + auto block2 = phi->getIncomingBlock(1); + + if (!isActive(block1)) + { + val2->takeName(&instr); + instr.replaceAllUsesWith(val2); + to_delete.push_back(&instr); + } + else if (!isActive(block2)) + { + val1->takeName(&instr); + instr.replaceAllUsesWith(val1); + to_delete.push_back(&instr); + } + + captures.clear(); + } + } + } + } + + for (auto& x : to_delete) + { + x->eraseFromParent(); + } + } + + void ProfilePass::runApplyRules(llvm::Module& module, llvm::ModuleAnalysisManager&) + { + replacements_.clear(); + + std::unordered_set already_visited; + for (auto& function : module) + { + if (function.hasFnAttribute("EntryPoint")) + { + runOnFunction(function, [this, &already_visited](llvm::Value* value, DeletableInstructions&) { + auto instr = llvm::dyn_cast(value); + + // Sanity check + if (already_visited.find(value) != already_visited.end()) + { + throw std::runtime_error("Already visited"); + } + already_visited.insert(value); + + // Checking if we should analyse + if (instr != nullptr) + { + rule_set_.matchAndReplace(instr, replacements_); + } + return value; + }); + } + } + + applyReplacements(); + } + + llvm::PreservedAnalyses ProfilePass::run(llvm::Module& module, llvm::ModuleAnalysisManager& mam) + { + // In case the module is istructed to clone functions, + if (clone_functions_) + { + setupCopyAndExpand(); + runCopyAndExpand(module, mam); + } + + // Deleting dead code if configured to do so. This process consists + // of three steps: detecting dead code, removing phi nodes (and references) + // and finally deleting the code. This implementation is aggressive in the sense + // that any code that we cannot prove to be active is considered dead. + if (delete_dead_code_) + { + runDetectActiveCode(module, mam); + runReplacePhi(module, mam); + runDeleteDeadCode(module, mam); + } + + // Applying rule set + if (!apply_to_inactive_code_) + { + runApplyRules(module, mam); + } + else + { + replacements_.clear(); + for (auto& function : module) + { + for (auto& block : function) + { + for (auto& instr : block) + { + rule_set_.matchAndReplace(&instr, replacements_); + } + } + } + + applyReplacements(); + } + + return llvm::PreservedAnalyses::none(); + } + + llvm::Function* ProfilePass::expandFunctionCall(llvm::Function& callee, ConstantArguments const& const_args) + { + auto module = callee.getParent(); + auto& context = module->getContext(); + llvm::IRBuilder<> builder(context); + + // Copying the original function + llvm::ValueToValueMapTy remapper; + std::vector arg_types; + + // The user might be deleting arguments to the function by specifying them in + // the VMap. If so, we need to not add the arguments to the arg ty vector + // + for (auto const& arg : callee.args()) + { + // Skipping constant arguments + + if (const_args.find(arg.getName().str()) != const_args.end()) + { + continue; + } + + arg_types.push_back(arg.getType()); + } + + // Creating a new function + llvm::FunctionType* function_type = llvm::FunctionType::get( + callee.getFunctionType()->getReturnType(), arg_types, callee.getFunctionType()->isVarArg()); + auto function = llvm::Function::Create( + function_type, callee.getLinkage(), callee.getAddressSpace(), callee.getName(), module); + + // Copying the non-const arguments + auto dest_args_it = function->arg_begin(); + + for (auto const& arg : callee.args()) + { + auto const_it = const_args.find(arg.getName().str()); + if (const_it == const_args.end()) + { + // Mapping remaining function arguments + dest_args_it->setName(arg.getName()); + remapper[&arg] = &*dest_args_it++; + } + else + { + remapper[&arg] = llvm::ConstantInt::get(context, const_it->second->getValue()); + } + } + + llvm::SmallVector returns; // Ignore returns cloned. + + // TODO(QAT-private-issue-28): In LLVM 13 upgrade 'true' to + // 'llvm::CloneFunctionChangeType::LocalChangesOnly' + llvm::CloneFunctionInto(function, &callee, remapper, true, returns, "", nullptr); + + verifyFunction(*function); + + return function; + } + + bool ProfilePass::isRequired() + { + return true; + } + +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/ProfilePass/Profile.hpp b/src/Passes/Source/ProfilePass/Profile.hpp new file mode 100644 index 0000000000..3464d090b3 --- /dev/null +++ b/src/Passes/Source/ProfilePass/Profile.hpp @@ -0,0 +1,206 @@ +#pragma once +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "Rules/RuleSet.hpp" + +#include "Llvm/Llvm.hpp" + +#include +#include +#include + +namespace microsoft +{ +namespace quantum +{ + + /// This class applies a set of transformation rules to the IR to transform it into a new IR. The + /// rules are added using the RuleSet class which allows the developer to create one or more rules + /// on how to transform the IR. + /// + /// + /// The module executes the following steps: + /// + /// + /// + /// ┌─────────────────┐ + /// │ Apply profile │ + /// └─────────────────┘ + /// │ + /// │ + /// │ + /// │ + /// │ ┌───────────────────────────────┐ + /// │ │ │ + /// ├───────────────▶│ Copy and expand functions │──┐ + /// │ clone │ │ │ + /// │ functions? └───────────────────────────────┘ │ + /// │ │ delete dead │ + /// │ │ code? │ + /// │ ▼ │ + /// │ ┌───────────────────────────────┐ │ + /// │ │ │ │ + /// ├───────────────▶│ Determine active code │ │ + /// │ delete dead │ │ │ + /// │ code? └───────────────────────────────┘ │ + /// │ │ │ + /// │ │ │ + /// │ ▼ │ + /// │ ┌───────────────────────────────┐ │ leave dead + /// │ │ │ │ code? + /// │ │ Simplify phi nodes │ │ + /// │ │ │ │ + /// │ └───────────────────────────────┘ │ + /// │ │ │ + /// │ │ │ + /// │ ▼ │ + /// │ ┌───────────────────────────────┐ │ + /// │ │ │ │ + /// │ │ Delete dead code │ │ + /// │ │ │ │ + /// │ └───────────────────────────────┘ │ + /// │ │ │ + /// │ │ │ + /// │ ▼ │ + /// │ ┌───────────────────────────────┐ │ + /// │ fallback │ │ │ + /// └───────────────▶│ Apply rules │◀─┘ + /// │ │ + /// └───────────────────────────────┘ + /// + class ProfilePass : public llvm::PassInfoMixin + { + public: + using Replacements = ReplacementRule::Replacements; + using Instruction = llvm::Instruction; + using Rules = std::vector; + using Value = llvm::Value; + using Builder = ReplacementRule::Builder; + using AllocationManagerPtr = AllocationManager::AllocationManagerPtr; + using Captures = RuleSet::Captures; + using String = std::string; + using ConstantArguments = std::unordered_map; + + /// Construction and destruction configuration. + /// @{ + + /// Custom default constructor + explicit ProfilePass( + RuleSet&& rule_set, + bool clone_functions = true, + bool delete_dead_code = true, + bool apply_to_inactive_code = false, + uint64_t max_recursion = 512) + : rule_set_{std::move(rule_set)} + , clone_functions_{clone_functions} + , delete_dead_code_{delete_dead_code} + , apply_to_inactive_code_{apply_to_inactive_code} + , max_recursion_{max_recursion} + { + } + + /// Copy construction is banned. + ProfilePass(ProfilePass const&) = delete; + + /// We allow move semantics. + ProfilePass(ProfilePass&&) = default; + + /// Default destruction. + ~ProfilePass() = default; + /// @} + + /// Operators + /// @{ + + /// Copy assignment is banned. + ProfilePass& operator=(ProfilePass const&) = delete; + + /// Move assignement is permitted. + ProfilePass& operator=(ProfilePass&&) = default; + /// @} + + /// Implements the transformation analysis which uses the supplied ruleset to make substitutions + /// in each function. + llvm::PreservedAnalyses run(llvm::Module& module, llvm::ModuleAnalysisManager& mam); + + using DeletableInstructions = std::vector; + using InstructionModifier = std::function; + + /// Generic helper funcntions + /// @{ + bool runOnFunction(llvm::Function& function, InstructionModifier const& modifier); + void applyReplacements(); + /// @} + + /// Copy and expand + /// @{ + void runCopyAndExpand(llvm::Module& module, llvm::ModuleAnalysisManager& mam); + void setupCopyAndExpand(); + void addConstExprRule(ReplacementRule&& rule); + llvm::Value* copyAndExpand(llvm::Value* input, DeletableInstructions&); + llvm::Function* expandFunctionCall(llvm::Function& callee, ConstantArguments const& const_args = {}); + void constantFoldFunction(llvm::Function& callee); + /// @} + + /// Dead code detection + /// @{ + void runDetectActiveCode(llvm::Module& module, llvm::ModuleAnalysisManager& mam); + void runDeleteDeadCode(llvm::Module& module, llvm::ModuleAnalysisManager& mam); + llvm::Value* detectActiveCode(llvm::Value* input, DeletableInstructions&); + llvm::Value* deleteDeadCode(llvm::Value* input, DeletableInstructions&); + bool isActive(llvm::Value* value) const; + /// @} + + /// @{ + void runReplacePhi(llvm::Module& module, llvm::ModuleAnalysisManager& mam); + /// @} + + /// Rules + /// @{ + void runApplyRules(llvm::Module& module, llvm::ModuleAnalysisManager& mam); + bool onQubitRelease(llvm::Instruction* instruction, Captures& captures); + bool onQubitAllocate(llvm::Instruction* instruction, Captures& captures); + /// @} + + /// Whether or not this pass is required to run. + static bool isRequired(); + /// @} + + private: + /// Pass configuration + /// @{ + RuleSet rule_set_{}; + bool clone_functions_{true}; + bool delete_dead_code_{true}; + bool apply_to_inactive_code_{false}; + uint64_t max_recursion_{512}; + /// @} + + /// Generic + /// @{ + uint64_t depth_{0}; + /// @} + + /// Copy and expand + /// @{ + RuleSet const_expr_replacements_{}; + /// @} + + /// Dead code + /// @{ + std::unordered_set active_pieces_{}; + std::vector blocks_to_delete_; + std::vector functions_to_delete_; + /// @} + + // Phi detection + + /// Applying rules + /// @{ + Replacements replacements_; ///< Registered replacements to be executed. + /// @} + }; + +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Profiles/BaseProfile.cpp b/src/Passes/Source/Profiles/BaseProfile.cpp index 386150f774..209b00958d 100644 --- a/src/Passes/Source/Profiles/BaseProfile.cpp +++ b/src/Passes/Source/Profiles/BaseProfile.cpp @@ -1,11 +1,10 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -#include "Passes/ExpandStaticAllocation/ExpandStaticAllocation.hpp" -#include "Passes/QirAllocationAnalysis/QirAllocationAnalysis.hpp" -#include "Passes/TransformationRule/TransformationRule.hpp" +#include "ProfilePass/Profile.hpp" #include "Profiles/BaseProfile.hpp" #include "Rules/Factory.hpp" +#include "Rules/RuleSet.hpp" #include "Llvm/Llvm.hpp" @@ -17,26 +16,20 @@ namespace quantum { llvm::ModulePassManager BaseProfile::createGenerationModulePass( - llvm::PassBuilder& pass_builder, - llvm::PassBuilder::OptimizationLevel const& optimisation_level, - bool debug) + PassBuilder& pass_builder, + OptimizationLevel const& optimisation_level, + bool debug) { - auto ret = pass_builder.buildPerModuleDefaultPipeline(optimisation_level); - // buildPerModuleDefaultPipeline buildModuleOptimizationPipeline - auto function_pass_manager = pass_builder.buildFunctionSimplificationPipeline( + llvm::ModulePassManager ret = pass_builder.buildPerModuleDefaultPipeline(optimisation_level); + auto function_pass_manager = pass_builder.buildFunctionSimplificationPipeline( optimisation_level, llvm::PassBuilder::ThinLTOPhase::None, debug); auto inliner_pass = pass_builder.buildInlinerPipeline(optimisation_level, llvm::PassBuilder::ThinLTOPhase::None, debug); - // TODO(QAT-private-issue-29): Determine if static expansion should happen as a module pass - // instead of a function pass - function_pass_manager.addPass(ExpandStaticAllocationPass()); - - RuleSet rule_set; - // Defining the mapping - auto factory = RuleFactory(rule_set); + RuleSet rule_set; + auto factory = RuleFactory(rule_set); factory.useStaticQubitArrayAllocation(); factory.useStaticQubitAllocation(); @@ -49,16 +42,7 @@ namespace quantum factory.disableAliasCounting(); factory.disableStringSupport(); - function_pass_manager.addPass(TransformationRulePass(std::move(rule_set))); - - // Eliminate dead code - function_pass_manager.addPass(llvm::DCEPass()); - function_pass_manager.addPass(llvm::ADCEPass()); - - ret.addPass(createModuleToFunctionPassAdaptor(std::move(function_pass_manager))); - - // TODO(QAT-private-issue-30): Mordernise: Upon upgrading to LLVM 12 or 13, change CGPM to - // ret.addPass(llvm::createModuleToCGSCCPassAdaptor(std::move(CGPM))); + ret.addPass(ProfilePass(std::move(rule_set))); ret.addPass(llvm::AlwaysInlinerPass()); ret.addPass(std::move(inliner_pass)); @@ -67,17 +51,14 @@ namespace quantum } llvm::ModulePassManager BaseProfile::createValidationModulePass( - llvm::PassBuilder&, - llvm::PassBuilder::OptimizationLevel const&, + PassBuilder& pass_builder, + OptimizationLevel const& optimisation_level, bool) { - throw std::runtime_error("Validator not implmented yet"); + return pass_builder.buildPerModuleDefaultPipeline(optimisation_level); } - void BaseProfile::addFunctionAnalyses(FunctionAnalysisManager& fam) - { - fam.registerPass([] { return QirAllocationAnalysis(); }); - } + void BaseProfile::addFunctionAnalyses(FunctionAnalysisManager&) {} } // namespace quantum } // namespace microsoft diff --git a/src/Passes/Source/Profiles/BaseProfile.hpp b/src/Passes/Source/Profiles/BaseProfile.hpp index 88800136bd..85fac3638b 100644 --- a/src/Passes/Source/Profiles/BaseProfile.hpp +++ b/src/Passes/Source/Profiles/BaseProfile.hpp @@ -3,6 +3,7 @@ // Licensed under the MIT License. #include "Profiles/IProfile.hpp" +#include "Rules/RuleSet.hpp" #include "Llvm/Llvm.hpp" @@ -11,18 +12,41 @@ namespace microsoft namespace quantum { + /// BaseProfile defines a profile that configures the ruleset used by the Profile + /// pass. This profile is useful for generating dynamic profiles and is well suited for testing + /// purposes or YAML configured transformation of the IR. class BaseProfile : public IProfile { public: + using ConfigureFunction = std::function; + + /// @{ + /// The constructor takes a lambda function which configures the ruleset. This + /// function is invoked during the creation of the generation module. + BaseProfile() = default; + /// @} + + /// Interface functions + /// @{ + + /// Creates a new module pass using the ConfigureFunction passed to the constructor of this + /// profile. llvm::ModulePassManager createGenerationModulePass( PassBuilder& pass_builder, OptimizationLevel const& optimisation_level, bool debug) override; + + /// Currently not supported. This function throws an exception. llvm::ModulePassManager createValidationModulePass( PassBuilder& pass_builder, OptimizationLevel const& optimisation_level, bool debug) override; + + /// Currently not supported. This function throws an exception. void addFunctionAnalyses(FunctionAnalysisManager& fam) override; + + /// @} + private: }; } // namespace quantum diff --git a/src/Passes/Source/Profiles/RuleSetProfile.cpp b/src/Passes/Source/Profiles/RuleSetProfile.cpp index d813279c93..70c6bf2e8b 100644 --- a/src/Passes/Source/Profiles/RuleSetProfile.cpp +++ b/src/Passes/Source/Profiles/RuleSetProfile.cpp @@ -1,9 +1,9 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -#include "Passes/QirAllocationAnalysis/QirAllocationAnalysis.hpp" -#include "Passes/TransformationRule/TransformationRule.hpp" +#include "ProfilePass/Profile.hpp" #include "Profiles/RuleSetProfile.hpp" +#include "Rules/Factory.hpp" #include "Rules/RuleSet.hpp" #include "Llvm/Llvm.hpp" @@ -15,8 +15,8 @@ namespace microsoft namespace quantum { - RuleSetProfile::RuleSetProfile(ConfigureFunction const& f) - : configure_{f} + RuleSetProfile::RuleSetProfile(ConfigureFunction const& configure) + : configure_{configure} { } llvm::ModulePassManager RuleSetProfile::createGenerationModulePass( @@ -24,29 +24,33 @@ namespace quantum OptimizationLevel const& optimisation_level, bool debug) { - auto ret = pass_builder.buildPerModuleDefaultPipeline(optimisation_level); - auto function_pass_manager = pass_builder.buildFunctionSimplificationPipeline( + llvm::ModulePassManager ret = pass_builder.buildPerModuleDefaultPipeline(optimisation_level); + auto function_pass_manager = pass_builder.buildFunctionSimplificationPipeline( optimisation_level, llvm::PassBuilder::ThinLTOPhase::None, debug); + auto inliner_pass = + pass_builder.buildInlinerPipeline(optimisation_level, llvm::PassBuilder::ThinLTOPhase::None, debug); + // Defining the mapping RuleSet rule_set; configure_(rule_set); - function_pass_manager.addPass(TransformationRulePass(std::move(rule_set))); - ret.addPass(createModuleToFunctionPassAdaptor(std::move(function_pass_manager))); + ret.addPass(ProfilePass(std::move(rule_set), false, false, true)); + // ret.addPass(llvm::AlwaysInlinerPass()); + // ret.addPass(std::move(inliner_pass)); return ret; } - llvm::ModulePassManager RuleSetProfile::createValidationModulePass(PassBuilder&, OptimizationLevel const&, bool) + llvm::ModulePassManager RuleSetProfile::createValidationModulePass( + PassBuilder& pass_builder, + OptimizationLevel const& optimisation_level, + bool) { - throw std::runtime_error("Validator not supported for rule set"); + return pass_builder.buildPerModuleDefaultPipeline(optimisation_level); } - void RuleSetProfile::addFunctionAnalyses(FunctionAnalysisManager&) - { - throw std::runtime_error("Function analysis not supported for rule set"); - } + void RuleSetProfile::addFunctionAnalyses(FunctionAnalysisManager&) {} } // namespace quantum } // namespace microsoft diff --git a/src/Passes/Source/Profiles/RuleSetProfile.hpp b/src/Passes/Source/Profiles/RuleSetProfile.hpp index 7412434abb..50d3f3cebe 100644 --- a/src/Passes/Source/Profiles/RuleSetProfile.hpp +++ b/src/Passes/Source/Profiles/RuleSetProfile.hpp @@ -23,7 +23,7 @@ namespace quantum /// @{ /// The constructor takes a lambda function which configures the ruleset. This /// function is invoked during the creation of the generation module. - explicit RuleSetProfile(ConfigureFunction const& f); + explicit RuleSetProfile(ConfigureFunction const& configure); /// @} /// Interface functions diff --git a/src/Passes/Source/Rules/Factory.cpp b/src/Passes/Source/Rules/Factory.cpp index 4b418ea3ef..66a2f502f2 100644 --- a/src/Passes/Source/Rules/Factory.cpp +++ b/src/Passes/Source/Rules/Factory.cpp @@ -114,11 +114,17 @@ namespace quantum // Computing the index by getting the current index value and offseting by // the offset at which the qubit array is allocated. - auto llvm_size = cst->getValue(); - auto offset = qubit_alloc_manager->getOffset(cap["arrayName"]->getName().str()); + auto offset_cst = llvm::dyn_cast(cap["arrayName"]); + if (offset_cst == nullptr) + { + return false; + } + auto llvm_offset = offset_cst->getValue(); + auto offset = llvm_offset.getZExtValue(); // Creating a new index APInt that is shifted by the offset of the allocation - auto idx = llvm::APInt(llvm_size.getBitWidth(), llvm_size.getZExtValue() + offset); + auto llvm_size = cst->getValue(); + auto idx = llvm::APInt(llvm_size.getBitWidth(), llvm_size.getZExtValue() + offset); // Computing offset auto new_index = llvm::ConstantInt::get(builder.getContext(), idx); @@ -137,7 +143,10 @@ namespace quantum return true; }; - auto get_element = call("__quantum__rt__array_get_element_ptr_1d", "arrayName"_cap = _, "index"_cap = _); + // Casted const + auto get_element = call( + "__quantum__rt__array_get_element_ptr_1d", intToPtr("arrayName"_cap = constInt()), + "index"_cap = constInt()); auto cast_pattern = bitCast("getElement"_cap = get_element); auto load_pattern = load("cast"_cap = cast_pattern); @@ -145,14 +154,24 @@ namespace quantum /// Release replacement auto deleter = deleteInstruction(); + addRule( - {call("__quantum__rt__qubit_release_array", "name"_cap = _), + {call("__quantum__rt__qubit_release_array", intToPtr("const"_cap = constInt())), [qubit_alloc_manager, deleter](Builder& builder, Value* val, Captures& cap, Replacements& rep) { - qubit_alloc_manager->release(cap["name"]->getName().str()); - return deleter(builder, val, cap, rep); - } + // Recovering the qubit id + auto cst = llvm::dyn_cast(cap["const"]); + if (cst == nullptr) + { + return false; + } + auto address = cst->getValue().getZExtValue(); - }); + // Releasing + qubit_alloc_manager->release(address); + + // Deleting instruction + return deleter(builder, val, cap, rep); + }}); } void RuleFactory::useStaticQubitAllocation() diff --git a/src/Passes/Source/Rules/Notation/BasicBlock.cpp b/src/Passes/Source/Rules/Notation/BasicBlock.cpp new file mode 100644 index 0000000000..2047350264 --- /dev/null +++ b/src/Passes/Source/Rules/Notation/BasicBlock.cpp @@ -0,0 +1,30 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "Rules/Notation/Notation.hpp" +#include "Rules/Operands/Instruction.hpp" + +#include "Llvm/Llvm.hpp" + +#include +#include + +namespace microsoft +{ +namespace quantum +{ + namespace notation + { + + using IOperandPrototypePtr = std::shared_ptr; + + IOperandPrototypePtr basicBlock() + { + auto ret = std::make_shared(); + + return static_cast(ret); + } + + } // namespace notation +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Rules/Notation/Notation.hpp b/src/Passes/Source/Rules/Notation/Notation.hpp index 22b14f9b28..72f636959c 100644 --- a/src/Passes/Source/Rules/Notation/Notation.hpp +++ b/src/Passes/Source/Rules/Notation/Notation.hpp @@ -5,9 +5,11 @@ /// @defgroup shorthandNotation Shorthand Notation #include "Rules/Notation/Call.ipp" +#include "Rules/Notation/Phi.ipp" #include "Rules/Operands/Any.hpp" #include "Rules/Operands/Call.hpp" #include "Rules/Operands/Instruction.hpp" +#include "Rules/Operands/Phi.hpp" #include "Llvm/Llvm.hpp" @@ -89,6 +91,9 @@ namespace quantum /// matches a call to the function `foo` with exactly two arguments. template IOperandPrototypePtr call(std::string const& name, Args... args); + /// Matches a phi node. TODO(tfr): More description + template IOperandPrototypePtr phi(Args... args); + /// Shorthand notation to match an instruction with a specified name. /// Unlike call, this pattern matches by name only and ignore /// the arguments. @@ -126,6 +131,9 @@ namespace quantum /// value came about. In this case, we may want to capture the values to, for instance, make /// assignment at compile time. IOperandPrototypePtr store(IOperandPrototypePtr const& target, IOperandPrototypePtr const& value); + + /// Matches a load instruction with one argument. + IOperandPrototypePtr basicBlock(); /// @} /// @addtogroup shorthandNotation diff --git a/src/Passes/Source/Rules/Notation/Phi.ipp b/src/Passes/Source/Rules/Notation/Phi.ipp new file mode 100644 index 0000000000..77e4f45ef1 --- /dev/null +++ b/src/Passes/Source/Rules/Notation/Phi.ipp @@ -0,0 +1,38 @@ +#pragma once +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "Llvm/Llvm.hpp" +#include "Rules/Notation/Notation.hpp" +#include "Rules/Operands/Any.hpp" +#include "Rules/Operands/Instruction.hpp" +#include "Rules/Operands/Phi.hpp" +#include "Rules/ReplacementRule.hpp" + +#include +#include + +namespace microsoft { +namespace quantum { +namespace notation { + +using IOperandPrototypePtr = std::shared_ptr; + +template +IOperandPrototypePtr phi(Args... args) +{ + IOperandPrototypePtr ret = std::make_shared(); + std::vector arguments{args...}; + + // Adding arguments to matching + for (auto &a : arguments) + { + ret->addChild(a); + } + + return ret; +} + +} // namespace notation +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Rules/OperandPrototype.hpp b/src/Passes/Source/Rules/OperandPrototype.hpp index 1b0269f76d..57b91384c0 100644 --- a/src/Passes/Source/Rules/OperandPrototype.hpp +++ b/src/Passes/Source/Rules/OperandPrototype.hpp @@ -78,6 +78,7 @@ namespace quantum children_ = other.children_; } /// @} + private: /// Data variables for common matching functionality /// @{ diff --git a/src/Passes/Source/Rules/Operands/Instruction.cpp b/src/Passes/Source/Rules/Operands/Instruction.cpp index 7079216d83..01cadffd1c 100644 --- a/src/Passes/Source/Rules/Operands/Instruction.cpp +++ b/src/Passes/Source/Rules/Operands/Instruction.cpp @@ -46,6 +46,7 @@ namespace quantum template class InstructionPattern; template class InstructionPattern; template class InstructionPattern; + template class InstructionPattern; #pragma clang diagnostic pop } // namespace quantum diff --git a/src/Passes/Source/Rules/Operands/Instruction.hpp b/src/Passes/Source/Rules/Operands/Instruction.hpp index 037dec2d16..c0caf78e42 100644 --- a/src/Passes/Source/Rules/Operands/Instruction.hpp +++ b/src/Passes/Source/Rules/Operands/Instruction.hpp @@ -23,12 +23,12 @@ namespace quantum Child copy() const override; }; - using StorePattern = InstructionPattern; - using LoadPattern = InstructionPattern; - using BitCastPattern = InstructionPattern; - using IntToPtrPattern = InstructionPattern; - using ConstIntPattern = InstructionPattern; - using BranchPattern = InstructionPattern; - + using StorePattern = InstructionPattern; + using LoadPattern = InstructionPattern; + using BitCastPattern = InstructionPattern; + using IntToPtrPattern = InstructionPattern; + using ConstIntPattern = InstructionPattern; + using BranchPattern = InstructionPattern; + using BasicBlockPattern = InstructionPattern; } // namespace quantum } // namespace microsoft diff --git a/src/Passes/Source/Rules/Operands/Phi.cpp b/src/Passes/Source/Rules/Operands/Phi.cpp new file mode 100644 index 0000000000..705b59b387 --- /dev/null +++ b/src/Passes/Source/Rules/Operands/Phi.cpp @@ -0,0 +1,33 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "Rules/OperandPrototype.hpp" +#include "Rules/Operands/Phi.hpp" + +namespace microsoft +{ +namespace quantum +{ + + PhiPattern::~PhiPattern() = default; + + bool PhiPattern::match(Value* instr, Captures& captures) const + { + auto* phi_node = llvm::dyn_cast(instr); + if (phi_node == nullptr) + { + return fail(instr, captures); + } + + return success(instr, captures); + } + + PhiPattern::Child PhiPattern::copy() const + { + auto ret = std::make_shared(); + ret->copyPropertiesFrom(*this); + return std::move(ret); + } + +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Rules/Operands/Phi.hpp b/src/Passes/Source/Rules/Operands/Phi.hpp new file mode 100644 index 0000000000..61ca7c8f8f --- /dev/null +++ b/src/Passes/Source/Rules/Operands/Phi.hpp @@ -0,0 +1,49 @@ +#pragma once +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "Rules/OperandPrototype.hpp" + +#include "Llvm/Llvm.hpp" + +#include +#include + +namespace microsoft +{ +namespace quantum +{ + + class PhiPattern : public IOperandPrototype + { + public: + using String = std::string; + + /// Construction of the call pattern by name or move only. + /// @{ + /// Construction by name. + PhiPattern() = default; + + /// Copy construction prohibited. + PhiPattern(PhiPattern const& other) = delete; + + /// Move construction allowed. + PhiPattern(PhiPattern&& other) = default; + + /// Destructor implementation. + ~PhiPattern() override; + /// @} + + /// Phi implmenetation of the member functions in IOperandPrototype. + /// @{ + + /// Matches the phi node. + bool match(Value* instr, Captures& captures) const override; + + /// Creates a copy of itself. + Child copy() const override; + /// @} + }; + +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Rules/RuleSet.cpp b/src/Passes/Source/Rules/RuleSet.cpp index 817864159c..151f9bc0e9 100644 --- a/src/Passes/Source/Rules/RuleSet.cpp +++ b/src/Passes/Source/Rules/RuleSet.cpp @@ -30,6 +30,10 @@ namespace quantum { return true; } + else + { + captures.clear(); + } } } return false; @@ -40,5 +44,14 @@ namespace quantum rules_.push_back(rule); } + void RuleSet::clear() + { + rules_.clear(); + } + + uint64_t RuleSet::size() const + { + return rules_.size(); + } } // namespace quantum } // namespace microsoft diff --git a/src/Passes/Source/Rules/RuleSet.hpp b/src/Passes/Source/Rules/RuleSet.hpp index 44571fe4b0..71f2a92cf1 100644 --- a/src/Passes/Source/Rules/RuleSet.hpp +++ b/src/Passes/Source/Rules/RuleSet.hpp @@ -60,6 +60,10 @@ namespace quantum /// Adds a new replacement rule to the set. void addRule(ReplacementRulePtr const& rule); /// @} + + void clear(); + uint64_t size() const; + private: Rules rules_; ///< Rules that describes QIR mappings }; diff --git a/src/Passes/Source/Rules/Tests/Unit/BranchOnOne.cpp b/src/Passes/Source/Rules/Tests/Unit/BranchOnOne.cpp index 65f611a39f..539867991a 100644 --- a/src/Passes/Source/Rules/Tests/Unit/BranchOnOne.cpp +++ b/src/Passes/Source/Rules/Tests/Unit/BranchOnOne.cpp @@ -1,11 +1,9 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -#include "Passes/ExpandStaticAllocation/ExpandStaticAllocation.hpp" -#include "Passes/QirAllocationAnalysis/QirAllocationAnalysis.hpp" -#include "Passes/TransformationRule/TransformationRule.hpp" #include "Profiles/RuleSetProfile.hpp" #include "Rules/Factory.hpp" +#include "Rules/ReplacementRule.hpp" #include "TestTools/IrManipulationTestHelper.hpp" #include "gtest/gtest.h" @@ -69,12 +67,12 @@ TEST(RuleSetTestSuite, BranchOnOne) auto configure_profile = [](RuleSet& rule_set) { auto factory = RuleFactory(rule_set); // factory.useStaticResultAllocation(); + factory.optimiseBranchQuatumOne(); }; auto profile = std::make_shared(std::move(configure_profile)); ir_manip->applyProfile(profile); - llvm::errs() << *ir_manip->module() << "\n"; // This optimistation is specific to the the __quantum__qir__read_result which // returns 1 or 0 depending on the result. We expect that diff --git a/src/Passes/Source/Rules/Tests/Unit/DisableAliasCounting.cpp b/src/Passes/Source/Rules/Tests/Unit/DisableAliasCounting.cpp index 9ab1cc0a29..5f00f933de 100644 --- a/src/Passes/Source/Rules/Tests/Unit/DisableAliasCounting.cpp +++ b/src/Passes/Source/Rules/Tests/Unit/DisableAliasCounting.cpp @@ -1,9 +1,6 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -#include "Passes/ExpandStaticAllocation/ExpandStaticAllocation.hpp" -#include "Passes/QirAllocationAnalysis/QirAllocationAnalysis.hpp" -#include "Passes/TransformationRule/TransformationRule.hpp" #include "Profiles/RuleSetProfile.hpp" #include "Rules/Factory.hpp" #include "TestTools/IrManipulationTestHelper.hpp" diff --git a/src/Passes/Source/Rules/Tests/Unit/DisableReferenceCounting.cpp b/src/Passes/Source/Rules/Tests/Unit/DisableReferenceCounting.cpp index 86c85b6908..7b1f42e1bd 100644 --- a/src/Passes/Source/Rules/Tests/Unit/DisableReferenceCounting.cpp +++ b/src/Passes/Source/Rules/Tests/Unit/DisableReferenceCounting.cpp @@ -1,9 +1,6 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -#include "Passes/ExpandStaticAllocation/ExpandStaticAllocation.hpp" -#include "Passes/QirAllocationAnalysis/QirAllocationAnalysis.hpp" -#include "Passes/TransformationRule/TransformationRule.hpp" #include "Profiles/RuleSetProfile.hpp" #include "Rules/Factory.hpp" #include "TestTools/IrManipulationTestHelper.hpp" diff --git a/src/Passes/Source/Rules/Tests/Unit/DisableStrings.cpp b/src/Passes/Source/Rules/Tests/Unit/DisableStrings.cpp index 6ac30f1793..a6b73f0413 100644 --- a/src/Passes/Source/Rules/Tests/Unit/DisableStrings.cpp +++ b/src/Passes/Source/Rules/Tests/Unit/DisableStrings.cpp @@ -1,9 +1,6 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -#include "Passes/ExpandStaticAllocation/ExpandStaticAllocation.hpp" -#include "Passes/QirAllocationAnalysis/QirAllocationAnalysis.hpp" -#include "Passes/TransformationRule/TransformationRule.hpp" #include "Profiles/RuleSetProfile.hpp" #include "Rules/Factory.hpp" #include "TestTools/IrManipulationTestHelper.hpp" diff --git a/src/Passes/Source/Rules/Tests/Unit/RemoveFunctionCall.cpp b/src/Passes/Source/Rules/Tests/Unit/RemoveFunctionCall.cpp index 9b2ae53dfd..03f900a55c 100644 --- a/src/Passes/Source/Rules/Tests/Unit/RemoveFunctionCall.cpp +++ b/src/Passes/Source/Rules/Tests/Unit/RemoveFunctionCall.cpp @@ -1,9 +1,6 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -#include "Passes/ExpandStaticAllocation/ExpandStaticAllocation.hpp" -#include "Passes/QirAllocationAnalysis/QirAllocationAnalysis.hpp" -#include "Passes/TransformationRule/TransformationRule.hpp" #include "Profiles/RuleSetProfile.hpp" #include "Rules/Factory.hpp" #include "TestTools/IrManipulationTestHelper.hpp" diff --git a/src/Passes/Source/Rules/Tests/Unit/SingleQubitAllocation.cpp b/src/Passes/Source/Rules/Tests/Unit/SingleQubitAllocation.cpp index 355289fd58..7f166034c8 100644 --- a/src/Passes/Source/Rules/Tests/Unit/SingleQubitAllocation.cpp +++ b/src/Passes/Source/Rules/Tests/Unit/SingleQubitAllocation.cpp @@ -1,9 +1,6 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -#include "Passes/ExpandStaticAllocation/ExpandStaticAllocation.hpp" -#include "Passes/QirAllocationAnalysis/QirAllocationAnalysis.hpp" -#include "Passes/TransformationRule/TransformationRule.hpp" #include "Profiles/RuleSetProfile.hpp" #include "Rules/Factory.hpp" #include "TestTools/IrManipulationTestHelper.hpp" @@ -52,7 +49,6 @@ TEST(RuleSetTestSuite, AllocationActionRelease) auto configure_profile = [](RuleSet& rule_set) { auto factory = RuleFactory(rule_set); - factory.useStaticQubitAllocation(); }; @@ -138,10 +134,10 @@ TEST(RuleSetTestSuite, AllocateReleaseMultipleTimes) // this require more thought with regards to the qubit allocation EXPECT_TRUE(ir_manip->hasInstructionSequence({ "%qubit1 = inttoptr i64 0 to %Qubit*", - "%qubit2 = inttoptr i64 1 to %Qubit*", - "%qubit3 = inttoptr i64 2 to %Qubit*", - "%qubit4 = inttoptr i64 3 to %Qubit*", - "%qubit5 = inttoptr i64 4 to %Qubit*", + "%qubit2 = inttoptr i64 0 to %Qubit*", + "%qubit3 = inttoptr i64 0 to %Qubit*", + "%qubit4 = inttoptr i64 0 to %Qubit*", + "%qubit5 = inttoptr i64 0 to %Qubit*", })); // Checking that dynamic allocations were removed diff --git a/src/Passes/Source/Rules/Tests/Unit/StaticQubitArrayAllocation.cpp b/src/Passes/Source/Rules/Tests/Unit/StaticQubitArrayAllocation.cpp index 33ab60e8fc..b8db6a1440 100644 --- a/src/Passes/Source/Rules/Tests/Unit/StaticQubitArrayAllocation.cpp +++ b/src/Passes/Source/Rules/Tests/Unit/StaticQubitArrayAllocation.cpp @@ -1,9 +1,6 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -#include "Passes/ExpandStaticAllocation/ExpandStaticAllocation.hpp" -#include "Passes/QirAllocationAnalysis/QirAllocationAnalysis.hpp" -#include "Passes/TransformationRule/TransformationRule.hpp" #include "Profiles/RuleSetProfile.hpp" #include "Rules/Factory.hpp" #include "TestTools/IrManipulationTestHelper.hpp" diff --git a/src/Passes/Source/Rules/Tests/Unit/StaticResultAllocation.cpp b/src/Passes/Source/Rules/Tests/Unit/StaticResultAllocation.cpp index 15450a2072..8a8d2886f7 100644 --- a/src/Passes/Source/Rules/Tests/Unit/StaticResultAllocation.cpp +++ b/src/Passes/Source/Rules/Tests/Unit/StaticResultAllocation.cpp @@ -1,9 +1,6 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -#include "Passes/ExpandStaticAllocation/ExpandStaticAllocation.hpp" -#include "Passes/QirAllocationAnalysis/QirAllocationAnalysis.hpp" -#include "Passes/TransformationRule/TransformationRule.hpp" #include "Profiles/RuleSetProfile.hpp" #include "Rules/Factory.hpp" #include "TestTools/IrManipulationTestHelper.hpp" diff --git a/src/Passes/default.profraw b/src/Passes/default.profraw deleted file mode 100644 index 617a2793aa..0000000000 Binary files a/src/Passes/default.profraw and /dev/null differ diff --git a/src/Passes/docs/src/DeveloperGuide/QuickStart.md b/src/Passes/docs/src/DeveloperGuide/QuickStart.md index 03ad07493b..773160eb02 100644 --- a/src/Passes/docs/src/DeveloperGuide/QuickStart.md +++ b/src/Passes/docs/src/DeveloperGuide/QuickStart.md @@ -72,7 +72,7 @@ namespace TeleportChain { } ``` -The corresponding QIR can be generated by going to `examples/QubitAllocationAnalysis` and run `make analysis-example.ll`. This step requires that you have a working installation of Q#. Once compiled and the initial QIR is generated and saved in the file `analysis-example.ll`, we execute the command +The corresponding QIR can be generated by going to `examples/TeleportChain` and run `make analysis-example.ll`. This step requires that you have a working installation of Q#. Once compiled and the initial QIR is generated and saved in the file `analysis-example.ll`, we execute the command ``` ./Source/Apps/qat --generate --profile baseProfile -S ./analysis-example.ll diff --git a/src/Passes/docs/src/DiscussionDocs/ThoughtsOnQubitManagement.md b/src/Passes/docs/src/DiscussionDocs/ThoughtsOnQubitManagement.md index bc9f652e48..9dba709b74 100644 --- a/src/Passes/docs/src/DiscussionDocs/ThoughtsOnQubitManagement.md +++ b/src/Passes/docs/src/DiscussionDocs/ThoughtsOnQubitManagement.md @@ -135,7 +135,7 @@ Compiling this to LLVM IR, produces ;; Note that this is correctly placed right before the last ;; __four__ dealloactions (two in the array + the two allocated in the beginning). - tail call void @__quantum__rt__h_body(%struct.QubitId* %11) #2 + tail call void @__quantum__qis__h__body(%struct.QubitId* %11) #2 tail call void @__quantum__rt__qubit_release(%struct.QubitId* %12) #2 tail call void @__quantum__rt__qubit_release(%struct.QubitId* %11) #2 tail call void @__quantum__rt__qubit_release(%struct.QubitId* %2) #2 @@ -164,15 +164,15 @@ struct QubitId int64_t value; }; -extern "C" QubitId __quantum__qis__qubit_allocate(); +extern "C" QubitId __quantum__rt__qubit_allocate(); extern "C" void __quantum__rt__qubit_release(QubitId id); -extern "C" void __quantum__qis__h_body(QubitId id); +extern "C" void __quantum__qis__h__body(QubitId id); int32_t main() { - auto qubit = __quantum__qis__qubit_allocate(); + auto qubit = __quantum__rt__qubit_allocate(); - __quantum__qis__h_body(qubit); + __quantum__qis__h__body(qubit); __quantum__rt__qubit_release(qubit); return 0; @@ -187,7 +187,7 @@ struct QubitId; extern "C" QubitId *__quantum__rt__qubit_allocate() noexcept; extern "C" void __quantum__rt__qubit_release(QubitId *id) noexcept; -extern "C" void __quantum__rt__h_body(QubitId *id) noexcept; +extern "C" void __quantum__rt__h__body(QubitId *id) noexcept; class Qubit { @@ -225,7 +225,7 @@ private: inline void H(Qubit &qubit) noexcept { - __quantum__rt__h_body(qubit.id()); + __quantum__rt__h__body(qubit.id()); } ``` @@ -261,7 +261,7 @@ define i32 @main() local_unnamed_addr #0 personality i32 (...)* @__gxx_personali %2 = tail call %struct.QubitId* @__quantum__rt__qubit_allocate() #2, !noalias !6 %3 = tail call %struct.QubitId* @__quantum__rt__qubit_allocate() #2, !noalias !9 %4 = tail call %struct.QubitId* @__quantum__rt__qubit_allocate() #2, !noalias !12 - tail call void @__quantum__rt__h_body(%struct.QubitId* %2) #2 + tail call void @__quantum__rt__h__body(%struct.QubitId* %2) #2 tail call void @__quantum__rt__qubit_release(%struct.QubitId* %4) #2 tail call void @__quantum__rt__qubit_release(%struct.QubitId* %3) #2 tail call void @__quantum__rt__qubit_release(%struct.QubitId* %2) #2 diff --git a/src/Passes/examples/ClassicalIrCommandline/Makefile b/src/Passes/examples/ClassicalIrCommandline/Makefile deleted file mode 100644 index 35f0e05627..0000000000 --- a/src/Passes/examples/ClassicalIrCommandline/Makefile +++ /dev/null @@ -1,15 +0,0 @@ -emit-llvm: - clang -O0 -fno-inline -S -emit-llvm classical-program.c -o classical-program.ll - -emit-llvm-bc: - clang -O0 -c -emit-llvm classical-program.c -o classical-program.bc - - -debug-ng-pass-mac: emit-llvm-bc - opt -load-pass-plugin ../../Debug/Source/Passes/libOpsCounter.dylib --passes="print" -disable-output classical-program.bc - - -clean: - rm -f classical-program.ll - rm -f classical-program.bc - diff --git a/src/Passes/examples/ClassicalIrCommandline/README.md b/src/Passes/examples/ClassicalIrCommandline/README.md deleted file mode 100644 index 67a9133371..0000000000 --- a/src/Passes/examples/ClassicalIrCommandline/README.md +++ /dev/null @@ -1,30 +0,0 @@ -# Emitting classical IRs - -This example demonstrates how to emit a classical IR and run a custom -pass on it. The purpose of this example is to teach the user how to apply -a pass to a IR using commandline tools only. - -IRs can be represented either by a human readible language or through bytecode. For -C programs former is generated by - -```sh - clang -O1 -S -emit-llvm classical-program.c -o classical-program.ll -``` - -whereas the latter is generated by executing: - -```sh - clang -O1 -c -emit-llvm classical-program.c -o classical-program.bc -``` - -This generates a nice and short IR which makes not too overwhelming to understand what is going on. - -## Next-gen passes - -This part assumes that you have built the Passes library. - -```sh -opt -load-pass-plugin ../../{Debug,Release}/libs/libOpsCounter.{dylib,so} --passes="print" -disable-output classical-program.bc -``` - -opt -O3 -S classical-program.ll diff --git a/src/Passes/examples/ClassicalIrCommandline/classical-program.c b/src/Passes/examples/ClassicalIrCommandline/classical-program.c deleted file mode 100644 index 7de7c1287c..0000000000 --- a/src/Passes/examples/ClassicalIrCommandline/classical-program.c +++ /dev/null @@ -1,17 +0,0 @@ -int foo(int x) -{ - return x; -} - -inline void bar(int x, int y) -{ - foo(x + y); -} - -int main() -{ - foo(2); - bar(3, 2); - - return 0; -} diff --git a/src/Passes/examples/ClassicalIrCommandline/classical-program.ll b/src/Passes/examples/ClassicalIrCommandline/classical-program.ll deleted file mode 100644 index d7464c030d..0000000000 --- a/src/Passes/examples/ClassicalIrCommandline/classical-program.ll +++ /dev/null @@ -1,58 +0,0 @@ -; ModuleID = 'classical-program.c' -source_filename = "classical-program.c" -target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" -target triple = "x86_64-apple-macosx11.0.0" - -; Function Attrs: noinline nounwind optnone ssp uwtable -define i32 @foo(i32 %0) #0 !dbg !8 { - %2 = alloca i32, align 4 - store i32 %0, i32* %2, align 4 - call void @llvm.dbg.declare(metadata i32* %2, metadata !12, metadata !DIExpression()), !dbg !13 - %3 = load i32, i32* %2, align 4, !dbg !14 - ret i32 %3, !dbg !15 -} - -; Function Attrs: nounwind readnone speculatable willreturn -declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 - -; Function Attrs: noinline nounwind optnone ssp uwtable -define i32 @main() #0 !dbg !16 { - %1 = alloca i32, align 4 - store i32 0, i32* %1, align 4 - %2 = call i32 @foo(i32 2), !dbg !19 - call void @bar(i32 3, i32 2), !dbg !20 - ret i32 0, !dbg !21 -} - -declare void @bar(i32, i32) #2 - -attributes #0 = { noinline nounwind optnone ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } -attributes #1 = { nounwind readnone speculatable willreturn } -attributes #2 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } - -!llvm.dbg.cu = !{!0} -!llvm.module.flags = !{!3, !4, !5, !6} -!llvm.ident = !{!7} - -!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 11.1.0", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: None, sysroot: "/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk", sdk: "MacOSX.sdk") -!1 = !DIFile(filename: "classical-program.c", directory: "/Users/tfr/Documents/Projects/qsharp-compiler/src/Passes/examples/ClassicalIrCommandline") -!2 = !{} -!3 = !{i32 7, !"Dwarf Version", i32 4} -!4 = !{i32 2, !"Debug Info Version", i32 3} -!5 = !{i32 1, !"wchar_size", i32 4} -!6 = !{i32 7, !"PIC Level", i32 2} -!7 = !{!"clang version 11.1.0"} -!8 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 1, type: !9, scopeLine: 2, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) -!9 = !DISubroutineType(types: !10) -!10 = !{!11, !11} -!11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) -!12 = !DILocalVariable(name: "x", arg: 1, scope: !8, file: !1, line: 1, type: !11) -!13 = !DILocation(line: 1, column: 13, scope: !8) -!14 = !DILocation(line: 3, column: 10, scope: !8) -!15 = !DILocation(line: 3, column: 3, scope: !8) -!16 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 11, type: !17, scopeLine: 12, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) -!17 = !DISubroutineType(types: !18) -!18 = !{!11} -!19 = !DILocation(line: 13, column: 3, scope: !16) -!20 = !DILocation(line: 14, column: 3, scope: !16) -!21 = !DILocation(line: 16, column: 3, scope: !16) diff --git a/src/Passes/examples/LoopRecursion/Makefile b/src/Passes/examples/LoopRecursion/Makefile new file mode 100644 index 0000000000..fca79ce285 --- /dev/null +++ b/src/Passes/examples/LoopRecursion/Makefile @@ -0,0 +1,17 @@ +all: qat-qsharp + +qat-qsharp: build-qat QSharpVersion/qir/Example.ll + ../../Debug/Source/Apps/qat --generate -S --verify-module --profile baseProfile QSharpVersion/qir/Example.ll + +build-qat: build-prepare + pushd ../../Debug && make qat && popd || popd + +build-prepare: + pushd ../../ && mkdir -p Debug && cd Debug && cmake ..&& popd || popd + +QSharpVersion/qir/Example.ll: + cd QSharpVersion && make qir/Example.ll + +clean: + cd QSharpVersion && make clean + diff --git a/src/Passes/examples/QubitAllocationAnalysis/TeleportChain/TeleportChain.csproj b/src/Passes/examples/LoopRecursion/QSharpVersion/Example.csproj similarity index 100% rename from src/Passes/examples/QubitAllocationAnalysis/TeleportChain/TeleportChain.csproj rename to src/Passes/examples/LoopRecursion/QSharpVersion/Example.csproj diff --git a/src/Passes/examples/LoopRecursion/QSharpVersion/Example.qs b/src/Passes/examples/LoopRecursion/QSharpVersion/Example.qs new file mode 100644 index 0000000000..20141e506d --- /dev/null +++ b/src/Passes/examples/LoopRecursion/QSharpVersion/Example.qs @@ -0,0 +1,38 @@ +namespace TeleportChain { + open Microsoft.Quantum.Intrinsic; + open Microsoft.Quantum.Canon; + open Microsoft.Quantum.Arrays; + open Microsoft.Quantum.Measurement; + open Microsoft.Quantum.Preparation; + + @EntryPoint() + operation Main(): Int + { + use q = Qubit(); + + mutable ret = 1; + for i in 0..5 + { + set ret = ret + Calculate(4, q); + } + + return ret; + } + + operation Calculate(n: Int, c: Qubit): Int + { + use q = Qubit(); + mutable ret = 2; + + H(q); + CNOT(c,q); + + if(n != 0) + { + set ret = Calculate(n - 1, q) + 2; + } + + return ret; + } + +} \ No newline at end of file diff --git a/src/Passes/examples/LoopRecursion/QSharpVersion/Makefile b/src/Passes/examples/LoopRecursion/QSharpVersion/Makefile new file mode 100644 index 0000000000..7779eca10d --- /dev/null +++ b/src/Passes/examples/LoopRecursion/QSharpVersion/Makefile @@ -0,0 +1,13 @@ +qir/Example.ll: + dotnet build Example.csproj + make partial-clean + +partial-clean: + rm -rf bin + rm -rf obj + +clean: + rm -rf bin + rm -rf obj + rm -rf qir + \ No newline at end of file diff --git a/src/Passes/examples/Makefile b/src/Passes/examples/Makefile new file mode 100644 index 0000000000..8b46156b86 --- /dev/null +++ b/src/Passes/examples/Makefile @@ -0,0 +1,7 @@ +all: + cd TeleportChain && make all && make clean + cd LoopRecursion && make all && make clean + +clean: + cd TeleportChain && make clean + cd LoopRecursion && make clean diff --git a/src/Passes/examples/OptimisationUsingOpt/README.md b/src/Passes/examples/OptimisationUsingOpt/README.md deleted file mode 100644 index 1b4a4f851f..0000000000 --- a/src/Passes/examples/OptimisationUsingOpt/README.md +++ /dev/null @@ -1,56 +0,0 @@ -# Optimisation Using Opt - -In this document, we give a brief introduction on how to perform IR optimisations -using `opt`. - -## Stripping dead code - -We start out by considering a simple case of a program that just returns 0: - -```qsharp -namespace Example { - @EntryPoint() - operation OurAwesomeQuantumProgram(nQubits : Int) : Int { - - return 0; - } -} -``` - -You find the code for this in the folder `SimpleExample`. To generate a QIR for this code, go to the folder and run - -```sh -cd SimpleExample/ -dotnet clean SimpleExample.csproj -(...) -dotnet build SimpleExample.csproj -c Debug -``` - -If everything went well, you should now have a subdirectory called `qir` and inside `qir`, you will find `SimpleExample.ll`. Depending on your compiler, -the generated QIR will vary, but in general, it will be relatively long. Looking at this file, you will see -that the total length is a little above 2000 lines of code. That is pretty extensive for a program which essentially -does nothing so obviously, most of the generated QIR must be dead code. We can now use `opt` to get rid of the dead code and we do this by invoking: - -```sh -opt -S qir/SimpleExample.ll -O3 > qir/SimpleExample-O3.ll -``` - -All going well, this should reduce your QIR to - -```language -; Function Attrs: norecurse nounwind readnone willreturn -define i64 @Example__QuantumFunction__Interop(i64 %nQubits) local_unnamed_addr #0 { -entry: - ret i64 0 -} - -define void @Example__QuantumFunction(i64 %nQubits) local_unnamed_addr #1 { -entry: - %0 = tail call %String* @__quantum__rt__int_to_string(i64 0) - tail call void @__quantum__rt__message(%String* %0) - tail call void @__quantum__rt__string_update_reference_count(%String* %0, i32 -1) - ret void -} -``` - -with a few additional declarations. diff --git a/src/Passes/examples/OptimisationUsingOpt/SimpleExample/Makefile b/src/Passes/examples/OptimisationUsingOpt/SimpleExample/Makefile deleted file mode 100644 index 293d2a5d0d..0000000000 --- a/src/Passes/examples/OptimisationUsingOpt/SimpleExample/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -all: qir/SimpleExample.ll - -qir/SimpleExample.ll: - dotnet build SimpleExample.csproj -c Debug - -clean: - rm -rf bin - rm -rf obj - rm -rf qir - diff --git a/src/Passes/examples/OptimisationUsingOpt/SimpleExample/SimpleExample.csproj b/src/Passes/examples/OptimisationUsingOpt/SimpleExample/SimpleExample.csproj deleted file mode 100644 index eeab572589..0000000000 --- a/src/Passes/examples/OptimisationUsingOpt/SimpleExample/SimpleExample.csproj +++ /dev/null @@ -1,9 +0,0 @@ - - - - Exe - netcoreapp3.1 - true - - - diff --git a/src/Passes/examples/OptimisationUsingOpt/SimpleExample/SimpleExample.qs b/src/Passes/examples/OptimisationUsingOpt/SimpleExample/SimpleExample.qs deleted file mode 100644 index 5578530c60..0000000000 --- a/src/Passes/examples/OptimisationUsingOpt/SimpleExample/SimpleExample.qs +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -namespace Example { - @EntryPoint() - operation QuantumFunction(nQubits : Int) : Int { - - return 0; - } -} diff --git a/src/Passes/examples/QubitAllocationAnalysis/Makefile b/src/Passes/examples/QubitAllocationAnalysis/Makefile deleted file mode 100644 index 14de572355..0000000000 --- a/src/Passes/examples/QubitAllocationAnalysis/Makefile +++ /dev/null @@ -1,45 +0,0 @@ - -qat: build-qat analysis-example.ll - ../../Debug/Source/Apps/qat --generate --profile ruleSet -S analysis-example.ll - -run-expand: build-qaa build-esa analysis-example.ll - opt -load-pass-plugin ../../Debug/Source/Passes/libQirAllocationAnalysis.dylib \ - -load-pass-plugin ../../Debug/Source/Passes/libExpandStaticAllocation.dylib --passes="expand-static-allocation" -S analysis-example.ll - - -run: build-qaa analysis-example.ll - # TODO(tfr): Add comments - opt -load-pass-plugin ../../Debug/Source/Passes/libQirAllocationAnalysis.dylib --passes="print" -disable-output analysis-example.ll - -run-replace: build-ir build-qaa build-esa analysis-example.ll -# opt -loop-unroll -unroll-count=3 -unroll-allow-partial - opt -load-pass-plugin ../../Debug/Source/Passes/libQirAllocationAnalysis.dylib \ - -load-pass-plugin ../../Debug/Source/Passes/libExpandStaticAllocation.dylib --passes="expand-static-allocation" -S analysis-example.ll > analysis-example-step1.ll - opt -load-pass-plugin ../../Debug/Source/Passes/libTransformationRule.dylib --passes="loop-simplify,loop-unroll,restrict-qir" -S analysis-example-step1.ll > analysis-example-final.ll - opt --passes="inline" -S test2.ll | opt -O1 -S - -build-qat: build-prepare - pushd ../../Debug && make qat && popd || popd - - -build-prepare: - pushd ../../ && mkdir -p Debug && cd Debug && cmake ..&& popd || popd - -build-qaa: build-prepare - pushd ../../Debug && make QirAllocationAnalysis && popd || popd - -build-esa: build-prepare - pushd ../../Debug && make ExpandStaticAllocation && popd || popd - -build-ir: build-prepare - pushd ../../Debug && make TransformationRule && popd || popd - - -analysis-example.ll: - cd TeleportChain && make analysis-example.ll - -clean: - cd TeleportChain && make clean - rm -f analysis-example.ll - rm -f analysis-example-step1.ll - rm -f analysis-example-final.ll diff --git a/src/Passes/examples/QubitAllocationAnalysis/README.md b/src/Passes/examples/QubitAllocationAnalysis/README.md deleted file mode 100644 index e704f2a85c..0000000000 --- a/src/Passes/examples/QubitAllocationAnalysis/README.md +++ /dev/null @@ -1,209 +0,0 @@ -# QirAllocationAnalysis - -## Quick start - -The following depnds on: - -- A working LLVM installation, including paths correctly setup -- CMake -- C#, Q# and the .NET framework - -Running following command - -```sh -make run -``` - -will first build the pass, then build the QIR using Q# following by removing the noise using `opt` with optimisation level 1. Finally, it will execute the analysis pass and should provide you with information about qubit allocation in the Q# program defined in `TeleportChain/TeleportChain.qs`. - -## Detailed run - -From the Passes root (two levels up from this directory), make a new build - -```sh -mkdir Debug -cd Debug -cmake .. -``` - -and then compile the `QirAllocationAnalysis`: - -```sh -make QirAllocationAnalysis -``` - -Next return `examples/QirAllocationAnalysis` and enter the directory `TeleportChain` to build the QIR: - -```sh -make analysis-example.ll -``` - -or execute the commands manually, - -```sh -dotnet build TeleportChain.csproj -opt -S qir/TeleportChain.ll -O1 > ../analysis-example.ll -make clean -``` - -Returning to `examples/QirAllocationAnalysis`, the pass can now be ran by executing: - -```sh -opt -load-pass-plugin ../../Debug/libs/libQirAllocationAnalysis.dylib --passes="print" -disable-output analysis-example.ll -``` - -## Example cases - -Below we will consider a few different examples. You can run them by updating the code in `TeleportChain/TeleportChain.qs` and executing `make run` from the `examples/QirAllocationAnalysis` folder subsequently. You will need to delete `analysis-example.ll` between runs. - -### Trivially constant - -This is the simplest example we can think of: - -```qsharp -namespace Example { - @EntryPoint() - operation QuantumProgram() : Unit { - use qubits = Qubit[3]; - } -} -``` - -The corresponding QIR is: - -``` -; ModuleID = 'qir/TeleportChain.ll' -source_filename = "qir/TeleportChain.ll" - -%Array = type opaque - -define internal fastcc void @Example__QuantumProgram__body() unnamed_addr { -entry: - %qubits = call %Array* @__quantum__rt__qubit_allocate_array(i64 3) - call void @__quantum__rt__array_update_alias_count(%Array* %qubits, i32 1) - call void @__quantum__rt__array_update_alias_count(%Array* %qubits, i32 -1) - call void @__quantum__rt__qubit_release_array(%Array* %qubits) - ret void -} - -; (...) -``` - -Running the pass procudes following output: - -``` -opt -load-pass-plugin ../../Debug/libs/libQirAllocationAnalysis.dylib --passes="print" -disable-output analysis-example.ll - -Example__QuantumProgram__body -==================== - -qubits is trivially static with 3 qubits. -``` - -### Dependency case - -In some cases, a qubit array will be compile time constant in size if the function arguments -provided are compile-time constants. One example of this is: - -``` -namespace Example { - @EntryPoint() - operation Main() : Int - { - QuantumProgram(3); - QuantumProgram(4); - return 0; - } - - operation QuantumProgram(x: Int) : Unit { - use qubits = Qubit[x]; - } -} -``` - -The corresponding QIR is - -``` -; ModuleID = 'qir/TeleportChain.ll' -source_filename = "qir/TeleportChain.ll" - -%Array = type opaque -%String = type opaque - -define internal fastcc void @Example__Main__body() unnamed_addr { -entry: - call fastcc void @Example__QuantumProgram__body(i64 3) - call fastcc void @Example__QuantumProgram__body(i64 4) - ret void -} - -define internal fastcc void @Example__QuantumProgram__body(i64 %x) unnamed_addr { -entry: - %qubits = call %Array* @__quantum__rt__qubit_allocate_array(i64 %x) - call void @__quantum__rt__array_update_alias_count(%Array* %qubits, i32 1) - call void @__quantum__rt__array_update_alias_count(%Array* %qubits, i32 -1) - call void @__quantum__rt__qubit_release_array(%Array* %qubits) - ret void -} -; ( ... ) - -``` - -The analyser returns following output: - -``` -opt -load-pass-plugin ../../Debug/libs/libQirAllocationAnalysis.dylib --passes="print" -disable-output analysis-example.ll - -Example__QuantumProgram__body -==================== - -qubits depends on x being constant to be static. - -``` - -### Summary case - -Finally, we do a summary case that demonstrates some of the more elaborate cases: - -``` -namespace Example { - @EntryPoint() - operation Main() : Int - { - QuantumProgram(3,2,1); - QuantumProgram(4,9,4); - return 0; - } - - function X(value: Int): Int - { - return 3 * value; - } - - operation QuantumProgram(x: Int, h: Int, g: Int) : Unit { - let z = x * (x + 1) - 47; - let y = 3 * x; - - use qubits0 = Qubit[9]; - use qubits1 = Qubit[(y - 2)/2-z]; - use qubits2 = Qubit[y - g]; - use qubits3 = Qubit[h]; - use qubits4 = Qubit[X(x)]; - } -} -``` - -We will omit the QIR in the documenation as it is a long. The output of the anaysis is: - -``` -opt -load-pass-plugin ../../Debug/libs/libQirAllocationAnalysis.dylib --passes="print" -disable-output analysis-example.ll - -Example__QuantumProgram__body -==================== - -qubits0 is trivially static with 9 qubits. -qubits1 depends on x being constant to be static. -qubits2 depends on x, g being constant to be static. -qubits3 depends on h being constant to be static. -qubits4 is dynamic. -``` diff --git a/src/Passes/examples/QubitAllocationAnalysis/TeleportChain/Makefile b/src/Passes/examples/QubitAllocationAnalysis/TeleportChain/Makefile deleted file mode 100644 index e5af26dbf1..0000000000 --- a/src/Passes/examples/QubitAllocationAnalysis/TeleportChain/Makefile +++ /dev/null @@ -1,13 +0,0 @@ -analysis-example.ll: - dotnet build TeleportChain.csproj - opt -S qir/TeleportChain.ll -O1 > ../analysis-example.ll - make clean - -comparison: - clang++ -S -emit-llvm -std=c++14 -stdlib=libc++ Comparison.cpp -o comparison.ll - -clean: - rm -rf bin - rm -rf obj - rm -rf qir - \ No newline at end of file diff --git a/src/Passes/examples/QubitAllocationAnalysis/analysis-example.ll b/src/Passes/examples/QubitAllocationAnalysis/analysis-example.ll deleted file mode 100644 index 610287c80c..0000000000 --- a/src/Passes/examples/QubitAllocationAnalysis/analysis-example.ll +++ /dev/null @@ -1,215 +0,0 @@ -; ModuleID = 'qir/TeleportChain.ll' -source_filename = "qir/TeleportChain.ll" - -%Qubit = type opaque -%Result = type opaque -%Array = type opaque -%String = type opaque - -define internal fastcc void @TeleportChain__ApplyCorrection__body(%Qubit* %src, %Qubit* %intermediary, %Qubit* %dest) unnamed_addr { -entry: - %0 = call fastcc %Result* @Microsoft__Quantum__Measurement__MResetZ__body(%Qubit* %src) - %1 = call %Result* @__quantum__rt__result_get_one() - %2 = call i1 @__quantum__rt__result_equal(%Result* %0, %Result* %1) - call void @__quantum__rt__result_update_reference_count(%Result* %0, i32 -1) - br i1 %2, label %then0__1, label %continue__1 - -then0__1: ; preds = %entry - call fastcc void @Microsoft__Quantum__Intrinsic__Z__body(%Qubit* %dest) - br label %continue__1 - -continue__1: ; preds = %then0__1, %entry - %3 = call fastcc %Result* @Microsoft__Quantum__Measurement__MResetZ__body(%Qubit* %intermediary) - %4 = call %Result* @__quantum__rt__result_get_one() - %5 = call i1 @__quantum__rt__result_equal(%Result* %3, %Result* %4) - call void @__quantum__rt__result_update_reference_count(%Result* %3, i32 -1) - br i1 %5, label %then0__2, label %continue__2 - -then0__2: ; preds = %continue__1 - call fastcc void @Microsoft__Quantum__Intrinsic__X__body(%Qubit* %dest) - br label %continue__2 - -continue__2: ; preds = %then0__2, %continue__1 - ret void -} - -define internal fastcc %Result* @Microsoft__Quantum__Measurement__MResetZ__body(%Qubit* %target) unnamed_addr { -entry: - %result = call %Result* @__quantum__qis__m__body(%Qubit* %target) - call void @__quantum__qis__reset__body(%Qubit* %target) - ret %Result* %result -} - -declare %Result* @__quantum__rt__result_get_one() local_unnamed_addr - -declare i1 @__quantum__rt__result_equal(%Result*, %Result*) local_unnamed_addr - -declare void @__quantum__rt__result_update_reference_count(%Result*, i32) local_unnamed_addr - -define internal fastcc void @Microsoft__Quantum__Intrinsic__Z__body(%Qubit* %qubit) unnamed_addr { -entry: - call void @__quantum__qis__z__body(%Qubit* %qubit) - ret void -} - -define internal fastcc void @Microsoft__Quantum__Intrinsic__X__body(%Qubit* %qubit) unnamed_addr { -entry: - call void @__quantum__qis__x__body(%Qubit* %qubit) - ret void -} - -define internal fastcc %Result* @TeleportChain__DemonstrateTeleportationUsingPresharedEntanglement__body() unnamed_addr { -entry: - %leftMessage = call %Qubit* @__quantum__rt__qubit_allocate() - %rightMessage = call %Qubit* @__quantum__rt__qubit_allocate() - %leftPreshared = call %Array* @__quantum__rt__qubit_allocate_array(i64 2) - call void @__quantum__rt__array_update_alias_count(%Array* %leftPreshared, i32 1) - %rightPreshared = call %Array* @__quantum__rt__qubit_allocate_array(i64 2) - call void @__quantum__rt__array_update_alias_count(%Array* %rightPreshared, i32 1) - call fastcc void @TeleportChain__PrepareEntangledPair__body(%Qubit* %leftMessage, %Qubit* %rightMessage) - %0 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %leftPreshared, i64 0) - %1 = bitcast i8* %0 to %Qubit** - %2 = load %Qubit*, %Qubit** %1, align 8 - %3 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %rightPreshared, i64 0) - %4 = bitcast i8* %3 to %Qubit** - %5 = load %Qubit*, %Qubit** %4, align 8 - call fastcc void @TeleportChain__PrepareEntangledPair__body(%Qubit* %2, %Qubit* %5) - %6 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %leftPreshared, i64 1) - %7 = bitcast i8* %6 to %Qubit** - %8 = load %Qubit*, %Qubit** %7, align 8 - %9 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %rightPreshared, i64 1) - %10 = bitcast i8* %9 to %Qubit** - %11 = load %Qubit*, %Qubit** %10, align 8 - call fastcc void @TeleportChain__PrepareEntangledPair__body(%Qubit* %8, %Qubit* %11) - %12 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %leftPreshared, i64 0) - %13 = bitcast i8* %12 to %Qubit** - %14 = load %Qubit*, %Qubit** %13, align 8 - %15 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %rightPreshared, i64 0) - %16 = bitcast i8* %15 to %Qubit** - %17 = load %Qubit*, %Qubit** %16, align 8 - call fastcc void @TeleportChain__TeleportQubitUsingPresharedEntanglement__body(%Qubit* %rightMessage, %Qubit* %14, %Qubit* %17) - %18 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %rightPreshared, i64 0) - %19 = bitcast i8* %18 to %Qubit** - %20 = load %Qubit*, %Qubit** %19, align 8 - %21 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %leftPreshared, i64 1) - %22 = bitcast i8* %21 to %Qubit** - %23 = load %Qubit*, %Qubit** %22, align 8 - %24 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %rightPreshared, i64 1) - %25 = bitcast i8* %24 to %Qubit** - %26 = load %Qubit*, %Qubit** %25, align 8 - call fastcc void @TeleportChain__TeleportQubitUsingPresharedEntanglement__body(%Qubit* %20, %Qubit* %23, %Qubit* %26) - %27 = call fastcc %Result* @Microsoft__Quantum__Measurement__MResetZ__body(%Qubit* %leftMessage) - %28 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %rightPreshared, i64 1) - %29 = bitcast i8* %28 to %Qubit** - %30 = load %Qubit*, %Qubit** %29, align 8 - %31 = call fastcc %Result* @Microsoft__Quantum__Measurement__MResetZ__body(%Qubit* %30) - call void @__quantum__rt__array_update_alias_count(%Array* %leftPreshared, i32 -1) - call void @__quantum__rt__array_update_alias_count(%Array* %rightPreshared, i32 -1) - call void @__quantum__rt__result_update_reference_count(%Result* %27, i32 -1) - call void @__quantum__rt__qubit_release(%Qubit* %leftMessage) - call void @__quantum__rt__qubit_release(%Qubit* %rightMessage) - call void @__quantum__rt__qubit_release_array(%Array* %leftPreshared) - call void @__quantum__rt__qubit_release_array(%Array* %rightPreshared) - ret %Result* %31 -} - -declare %Qubit* @__quantum__rt__qubit_allocate() local_unnamed_addr - -declare %Array* @__quantum__rt__qubit_allocate_array(i64) local_unnamed_addr - -declare void @__quantum__rt__qubit_release(%Qubit*) local_unnamed_addr - -declare void @__quantum__rt__qubit_release_array(%Array*) local_unnamed_addr - -declare void @__quantum__rt__array_update_alias_count(%Array*, i32) local_unnamed_addr - -define internal fastcc void @TeleportChain__PrepareEntangledPair__body(%Qubit* %left, %Qubit* %right) unnamed_addr { -entry: - call fastcc void @Microsoft__Quantum__Intrinsic__H__body(%Qubit* %left) - call fastcc void @Microsoft__Quantum__Intrinsic__CNOT__body(%Qubit* %left, %Qubit* %right) - ret void -} - -declare i8* @__quantum__rt__array_get_element_ptr_1d(%Array*, i64) local_unnamed_addr - -define internal fastcc void @TeleportChain__TeleportQubitUsingPresharedEntanglement__body(%Qubit* %src, %Qubit* %intermediary, %Qubit* %dest) unnamed_addr { -entry: - call fastcc void @TeleportChain__PrepareEntangledPair__adj(%Qubit* %src, %Qubit* %intermediary) - call fastcc void @TeleportChain__ApplyCorrection__body(%Qubit* %src, %Qubit* %intermediary, %Qubit* %dest) - ret void -} - -define internal fastcc void @Microsoft__Quantum__Intrinsic__H__body(%Qubit* %qubit) unnamed_addr { -entry: - call void @__quantum__qis__h__body(%Qubit* %qubit) - ret void -} - -define internal fastcc void @Microsoft__Quantum__Intrinsic__CNOT__body(%Qubit* %control, %Qubit* %target) unnamed_addr { -entry: - call void @__quantum__qis__cnot__body(%Qubit* %control, %Qubit* %target) - ret void -} - -define internal fastcc void @TeleportChain__PrepareEntangledPair__adj(%Qubit* %left, %Qubit* %right) unnamed_addr { -entry: - call fastcc void @Microsoft__Quantum__Intrinsic__CNOT__adj(%Qubit* %left, %Qubit* %right) - call fastcc void @Microsoft__Quantum__Intrinsic__H__adj(%Qubit* %left) - ret void -} - -define internal fastcc void @Microsoft__Quantum__Intrinsic__CNOT__adj(%Qubit* %control, %Qubit* %target) unnamed_addr { -entry: - call fastcc void @Microsoft__Quantum__Intrinsic__CNOT__body(%Qubit* %control, %Qubit* %target) - ret void -} - -define internal fastcc void @Microsoft__Quantum__Intrinsic__H__adj(%Qubit* %qubit) unnamed_addr { -entry: - call fastcc void @Microsoft__Quantum__Intrinsic__H__body(%Qubit* %qubit) - ret void -} - -declare void @__quantum__qis__cnot__body(%Qubit*, %Qubit*) local_unnamed_addr - -declare void @__quantum__qis__h__body(%Qubit*) local_unnamed_addr - -declare void @__quantum__qis__x__body(%Qubit*) local_unnamed_addr - -declare void @__quantum__qis__z__body(%Qubit*) local_unnamed_addr - -declare %Result* @__quantum__qis__m__body(%Qubit*) local_unnamed_addr - -declare void @__quantum__qis__reset__body(%Qubit*) local_unnamed_addr - -define i8 @TeleportChain__DemonstrateTeleportationUsingPresharedEntanglement__Interop() local_unnamed_addr #0 { -entry: - %0 = call fastcc %Result* @TeleportChain__DemonstrateTeleportationUsingPresharedEntanglement__body() - %1 = call %Result* @__quantum__rt__result_get_zero() - %2 = call i1 @__quantum__rt__result_equal(%Result* %0, %Result* %1) - %not. = xor i1 %2, true - %3 = sext i1 %not. to i8 - call void @__quantum__rt__result_update_reference_count(%Result* %0, i32 -1) - ret i8 %3 -} - -declare %Result* @__quantum__rt__result_get_zero() local_unnamed_addr - -define void @TeleportChain__DemonstrateTeleportationUsingPresharedEntanglement() local_unnamed_addr #1 { -entry: - %0 = call fastcc %Result* @TeleportChain__DemonstrateTeleportationUsingPresharedEntanglement__body() - %1 = call %String* @__quantum__rt__result_to_string(%Result* %0) - call void @__quantum__rt__message(%String* %1) - call void @__quantum__rt__result_update_reference_count(%Result* %0, i32 -1) - call void @__quantum__rt__string_update_reference_count(%String* %1, i32 -1) - ret void -} - -declare void @__quantum__rt__message(%String*) local_unnamed_addr - -declare %String* @__quantum__rt__result_to_string(%Result*) local_unnamed_addr - -declare void @__quantum__rt__string_update_reference_count(%String*, i32) local_unnamed_addr - -attributes #0 = { "InteropFriendly" } -attributes #1 = { "EntryPoint" } diff --git a/src/Passes/examples/TeleportChain/Makefile b/src/Passes/examples/TeleportChain/Makefile new file mode 100644 index 0000000000..fca79ce285 --- /dev/null +++ b/src/Passes/examples/TeleportChain/Makefile @@ -0,0 +1,17 @@ +all: qat-qsharp + +qat-qsharp: build-qat QSharpVersion/qir/Example.ll + ../../Debug/Source/Apps/qat --generate -S --verify-module --profile baseProfile QSharpVersion/qir/Example.ll + +build-qat: build-prepare + pushd ../../Debug && make qat && popd || popd + +build-prepare: + pushd ../../ && mkdir -p Debug && cd Debug && cmake ..&& popd || popd + +QSharpVersion/qir/Example.ll: + cd QSharpVersion && make qir/Example.ll + +clean: + cd QSharpVersion && make clean + diff --git a/src/Passes/examples/TeleportChain/QSharpVersion/Example.csproj b/src/Passes/examples/TeleportChain/QSharpVersion/Example.csproj new file mode 100644 index 0000000000..3d247e664d --- /dev/null +++ b/src/Passes/examples/TeleportChain/QSharpVersion/Example.csproj @@ -0,0 +1,13 @@ + + + + Exe + netcoreapp3.1 + true + + + + + + + diff --git a/src/Passes/examples/QubitAllocationAnalysis/TeleportChain/TeleportChain.qs b/src/Passes/examples/TeleportChain/QSharpVersion/Example.qs similarity index 97% rename from src/Passes/examples/QubitAllocationAnalysis/TeleportChain/TeleportChain.qs rename to src/Passes/examples/TeleportChain/QSharpVersion/Example.qs index 02ce7699a2..c5bfe1d844 100644 --- a/src/Passes/examples/QubitAllocationAnalysis/TeleportChain/TeleportChain.qs +++ b/src/Passes/examples/TeleportChain/QSharpVersion/Example.qs @@ -3,8 +3,7 @@ namespace TeleportChain { open Microsoft.Quantum.Canon; open Microsoft.Quantum.Arrays; open Microsoft.Quantum.Measurement; - open Microsoft.Quantum.Preparation; - + open Microsoft.Quantum.Preparation; operation PrepareEntangledPair(left : Qubit, right : Qubit) : Unit is Adj + Ctl { H(left); @@ -39,4 +38,5 @@ namespace TeleportChain { return MResetZ(rightPreshared[nPairs-1]); } + } \ No newline at end of file diff --git a/src/Passes/examples/TeleportChain/QSharpVersion/Makefile b/src/Passes/examples/TeleportChain/QSharpVersion/Makefile new file mode 100644 index 0000000000..7779eca10d --- /dev/null +++ b/src/Passes/examples/TeleportChain/QSharpVersion/Makefile @@ -0,0 +1,13 @@ +qir/Example.ll: + dotnet build Example.csproj + make partial-clean + +partial-clean: + rm -rf bin + rm -rf obj + +clean: + rm -rf bin + rm -rf obj + rm -rf qir + \ No newline at end of file diff --git a/src/Passes/site-packages/TasksCI/cli.py b/src/Passes/site-packages/TasksCI/cli.py index 6b5bf8195d..c72ed63bf2 100644 --- a/src/Passes/site-packages/TasksCI/cli.py +++ b/src/Passes/site-packages/TasksCI/cli.py @@ -10,7 +10,6 @@ import logging import sys import os -import re from typing import Union OptionalInt = Union[int, None] @@ -18,7 +17,6 @@ # Important directories LIB_DIR = os.path.abspath(os.path.dirname((__file__))) -TEMPLATE_DIR = os.path.join(LIB_DIR, "templates") SOURCE_DIR = os.path.abspath(os.path.dirname(os.path.dirname(LIB_DIR))) # Logging configuration @@ -166,109 +164,5 @@ def coverage(output: OptionalStr, format: str) -> None: coverage_main(build_dir, output, format) -@cli.command() -@click.argument( - "name" -) -@click.option( - "--template", - default=None, -) -def create_pass(name: str, template: OptionalStr) -> None: - """ - Helper command to create a new pass from a template. Templates - can be found in the template directory of the TasksCI tool. - """ - - # Checking whether the target already exists - target_dir = os.path.join(SOURCE_DIR, "Source", name) - if os.path.exists(target_dir): - logger.error("Pass '{}' already exists".format(name)) - exit(-1) - - # In case no template was specified, we list the option - # such that the user can choose one - if template is None: - - # Listing options - options = [] - print("Available templates:") - print("") - for template_name in os.listdir(TEMPLATE_DIR): - if os.path.isdir(os.path.join(TEMPLATE_DIR, template_name)): - options.append(template_name) - - # Printing option - pretty_template_name = re.sub(r'(? len(options) + 1: - try: - n = input("Select a template:") - - if n == "q" or n == "quit": - logger.info("User aborted.") - exit(0) - - n = int(n) - except: # noqa: E722 - logger.error("Invalid choice") - exit(-1) - - # Getting the template - template = options[n - 1] - - # Checking that the template is valid. Note that even though - # we list the templates above, the user may have specified an - # invalid template via the command line. - template_dir = os.path.join(TEMPLATE_DIR, template) - if not os.path.exists(template_dir): - logger.error("Template does not exist") - exit(-1) - - # Creating an operation name by transforming the original name - # from "CamelCase" to "camel-case" - operation_name = re.sub(r'(? -#include - -namespace { -// Interface to plugin -llvm::PassPluginLibraryInfo get{name}PluginInfo() -{ - using namespace microsoft::quantum; - using namespace llvm; - - return { - LLVM_PLUGIN_API_VERSION, "{name}", LLVM_VERSION_STRING, [](PassBuilder &pb) { - // Registering a printer for the anaylsis - pb.registerPipelineParsingCallback([](StringRef name, FunctionPassManager &fpm, - ArrayRef /*unused*/) { - if (name == "print<{operation_name}>") - { - fpm.addPass({name}Printer(llvm::errs())); - return true; - } - return false; - }); - - pb.registerVectorizerStartEPCallback( - [](llvm::FunctionPassManager &fpm, llvm::PassBuilder::OptimizationLevel /*level*/) { - fpm.addPass({name}Printer(llvm::errs())); - }); - - // Registering the analysis module - pb.registerAnalysisRegistrationCallback([](FunctionAnalysisManager &fam) { - fam.registerPass([] { return {name}Analytics(); }); - }); - }}; -} - -} // namespace - -extern "C" LLVM_ATTRIBUTE_WEAK ::llvm::PassPluginLibraryInfo llvmGetPassPluginInfo() -{ - return get{name}PluginInfo(); -} diff --git a/src/Passes/site-packages/TasksCI/templates/FunctionAnalysis/SPECIFICATION.md b/src/Passes/site-packages/TasksCI/templates/FunctionAnalysis/SPECIFICATION.md deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/src/Passes/site-packages/TasksCI/templates/FunctionAnalysis/{name}.cpp.tpl b/src/Passes/site-packages/TasksCI/templates/FunctionAnalysis/{name}.cpp.tpl deleted file mode 100644 index 1d0eea61b4..0000000000 --- a/src/Passes/site-packages/TasksCI/templates/FunctionAnalysis/{name}.cpp.tpl +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -#include "{name}/{name}.hpp" - -#include "Llvm.hpp" - -#include -#include - -namespace microsoft { -namespace quantum { -{name}Analytics::Result {name}Analytics::run(llvm::Function &/*function*/, - llvm::FunctionAnalysisManager & /*unused*/) -{ - {name}Analytics::Result result; - - // Collect analytics here - - return result; -} - - -{name}Printer::{name}Printer(llvm::raw_ostream& out_stream) - : out_stream_(out_stream) -{ -} - -llvm::PreservedAnalyses {name}Printer::run(llvm::Function & /*function*/, - llvm::FunctionAnalysisManager & /*fam*/) -{ - // auto &results = fam.getResult<{name}Analytics>(function); - - // Use analytics here - out_stream_ << "Analysis results are printed using this stream\n"; - - return llvm::PreservedAnalyses::all(); -} - -bool {name}Printer::isRequired() -{ - return true; -} - -llvm::AnalysisKey {name}Analytics::Key; - -} // namespace quantum -} // namespace microsoft diff --git a/src/Passes/site-packages/TasksCI/templates/FunctionAnalysis/{name}.hpp.tpl b/src/Passes/site-packages/TasksCI/templates/FunctionAnalysis/{name}.hpp.tpl deleted file mode 100644 index 5dd8e664d9..0000000000 --- a/src/Passes/site-packages/TasksCI/templates/FunctionAnalysis/{name}.hpp.tpl +++ /dev/null @@ -1,67 +0,0 @@ -#pragma once -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -#include "Llvm.hpp" - -namespace microsoft { -namespace quantum { - -class {name}Analytics : public llvm::AnalysisInfoMixin<{name}Analytics> -{ -public: - using Result = llvm::StringMap; ///< Change the type of the collected date here - - /// Constructors and destructors - /// @{ - {name}Analytics() = default; - {name}Analytics({name}Analytics const &) = delete; - {name}Analytics({name}Analytics &&) = default; - ~{name}Analytics() = default; - /// @} - - /// Operators - /// @{ - {name}Analytics &operator=({name}Analytics const &) = delete; - {name}Analytics &operator=({name}Analytics &&) = delete; - /// @} - - /// Functions required by LLVM - /// @{ - Result run(llvm::Function & function, llvm::FunctionAnalysisManager & /*unused*/); - /// @} - -private: - static llvm::AnalysisKey Key; // NOLINT - friend struct llvm::AnalysisInfoMixin<{name}Analytics>; -}; - -class {name}Printer : public llvm::PassInfoMixin<{name}Printer> -{ -public: - /// Constructors and destructors - /// @{ - explicit {name}Printer(llvm::raw_ostream& out_stream); - {name}Printer() = delete; - {name}Printer({name}Printer const &) = delete; - {name}Printer({name}Printer &&) = default; - ~{name}Printer() = default; - /// @} - - /// Operators - /// @{ - {name}Printer &operator=({name}Printer const &) = delete; - {name}Printer &operator=({name}Printer &&) = delete; - /// @} - - /// Functions required by LLVM - /// @{ - llvm::PreservedAnalyses run(llvm::Function & function, llvm::FunctionAnalysisManager & fam); - static bool isRequired(); - /// @} -private: - llvm::raw_ostream& out_stream_; -}; - -} // namespace quantum -} // namespace microsoft diff --git a/src/Passes/site-packages/TasksCI/templates/FunctionPass/Lib{name}.cpp.tpl b/src/Passes/site-packages/TasksCI/templates/FunctionPass/Lib{name}.cpp.tpl deleted file mode 100644 index 3986121e81..0000000000 --- a/src/Passes/site-packages/TasksCI/templates/FunctionPass/Lib{name}.cpp.tpl +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -#include "{name}/{name}.hpp" - -#include "Llvm.hpp" - -#include -#include - -namespace { -llvm::PassPluginLibraryInfo get{name}PluginInfo() -{ - using namespace microsoft::quantum; - using namespace llvm; - - return { - LLVM_PLUGIN_API_VERSION, "{name}", LLVM_VERSION_STRING, [](PassBuilder &pb) { - // Registering the pass - pb.registerPipelineParsingCallback([](StringRef name, FunctionPassManager &fpm, - ArrayRef /*unused*/) { - if (name == "{operation_name}") - { - fpm.addPass({name}Pass()); - return true; - } - - return false; - }); - }}; -} -} // namespace - -// Interface for loading the plugin -extern "C" LLVM_ATTRIBUTE_WEAK ::llvm::PassPluginLibraryInfo llvmGetPassPluginInfo() -{ - return get{name}PluginInfo(); -} diff --git a/src/Passes/site-packages/TasksCI/templates/FunctionPass/SPECIFICATION.md b/src/Passes/site-packages/TasksCI/templates/FunctionPass/SPECIFICATION.md deleted file mode 100644 index f051462f55..0000000000 --- a/src/Passes/site-packages/TasksCI/templates/FunctionPass/SPECIFICATION.md +++ /dev/null @@ -1 +0,0 @@ -# {{name}} Specification diff --git a/src/Passes/site-packages/TasksCI/templates/FunctionPass/{name}.cpp.tpl b/src/Passes/site-packages/TasksCI/templates/FunctionPass/{name}.cpp.tpl deleted file mode 100644 index 27804b5c1c..0000000000 --- a/src/Passes/site-packages/TasksCI/templates/FunctionPass/{name}.cpp.tpl +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -#include "{name}/{name}.hpp" - -#include "Llvm.hpp" - -#include -#include - -namespace microsoft -{ -namespace quantum -{ -llvm::PreservedAnalyses {name}Pass::run(llvm::Function &function, llvm::FunctionAnalysisManager &/*fam*/) -{ - // Pass body - - llvm::errs() << "Implement your pass here: " << function.getName() << "\n"; - - return llvm::PreservedAnalyses::all(); -} - -bool {name}Pass::isRequired() -{ - return true; -} - -} // namespace quantum -} // namespace microsoft - diff --git a/src/Passes/site-packages/TasksCI/templates/FunctionPass/{name}.hpp.tpl b/src/Passes/site-packages/TasksCI/templates/FunctionPass/{name}.hpp.tpl deleted file mode 100644 index 24e5beaa7b..0000000000 --- a/src/Passes/site-packages/TasksCI/templates/FunctionPass/{name}.hpp.tpl +++ /dev/null @@ -1,37 +0,0 @@ -#pragma once -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -#include "Llvm.hpp" - -namespace microsoft -{ -namespace quantum -{ - -class {name}Pass : public llvm::PassInfoMixin<{name}Pass> -{ -public: - /// Constructors and destructors - /// @{ - {name}Pass() = default; - {name}Pass({name}Pass const &) = default; - {name}Pass({name}Pass &&) = default; - ~{name}Pass() = default; - /// @} - - /// Operators - /// @{ - {name}Pass &operator=({name}Pass const &) = default; - {name}Pass &operator=({name}Pass &&) = default; - /// @} - - /// Functions required by LLVM - /// @{ - llvm::PreservedAnalyses run(llvm::Function &function, llvm::FunctionAnalysisManager &fam); - static bool isRequired(); - /// @} -}; - -} // namespace quantum -} // namespace microsoft diff --git a/src/Passes/tests/CMakeLists.txt b/src/Passes/tests/CMakeLists.txt deleted file mode 100644 index 6a794c01a9..0000000000 --- a/src/Passes/tests/CMakeLists.txt +++ /dev/null @@ -1,10 +0,0 @@ -set(LT_TEST_SHLIBEXT "${CMAKE_SHARED_LIBRARY_SUFFIX}") - -set(LT_TEST_SITE_CFG_INPUT "${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.py.in") -set(LT_TEST_SRC_DIR "${CMAKE_CURRENT_SOURCE_DIR}") - -set(LIT_SITE_CFG_IN_HEADER "## Autogenerated from ${LT_TEST_SITE_CFG_INPUT}\n## Do not edit!") - -configure_file("${LT_TEST_SITE_CFG_INPUT}" - "${CMAKE_CURRENT_BINARY_DIR}/lit.cfg.py" @ONLY -) diff --git a/src/Passes/tests/QubitAllocationAnalysis/case1.deprecated b/src/Passes/tests/QubitAllocationAnalysis/case1.deprecated deleted file mode 100644 index 230a3dac66..0000000000 --- a/src/Passes/tests/QubitAllocationAnalysis/case1.deprecated +++ /dev/null @@ -1,15 +0,0 @@ -; RUN: opt -load-pass-plugin %shlibdir/libQirAllocationAnalysis%shlibext -passes="print" %S/inputs/static-qubit-arrays-1.ll -disable-output 2>&1\ -; RUN: | FileCheck %s - -;------------------------------------------------------------------------------ -; EXPECTED OUTPUT -;------------------------------------------------------------------------------ - -; CHECK: Example__QuantumProgram__body -; CHECK: ==================== - -; CHECK: qubits depends on x being constant to be static. - - - - diff --git a/src/Passes/tests/QubitAllocationAnalysis/case2.deprecrated b/src/Passes/tests/QubitAllocationAnalysis/case2.deprecrated deleted file mode 100644 index 3a13a71027..0000000000 --- a/src/Passes/tests/QubitAllocationAnalysis/case2.deprecrated +++ /dev/null @@ -1,14 +0,0 @@ -; RUN: opt -load-pass-plugin %shlibdir/libQirAllocationAnalysis%shlibext -passes="print" %S/inputs/static-qubit-arrays-2.ll -disable-output 2>&1\ -; RUN: | FileCheck %s - -;------------------------------------------------------------------------------ -; EXPECTED OUTPUT -;------------------------------------------------------------------------------ - -; CHECK: Example__QuantumProgram__body -; CHECK: ==================== -; CHECK: qubits0 is trivially static with 9 qubits. -; CHECK: qubits1 depends on x being constant to be static. -; CHECK: qubits2 depends on x, g being constant to be static. -; CHECK: qubits3 depends on h being constant to be static. -; CHECK: qubits4 is dynamic. diff --git a/src/Passes/tests/QubitAllocationAnalysis/inputs/static-qubit-arrays-1.deprecated b/src/Passes/tests/QubitAllocationAnalysis/inputs/static-qubit-arrays-1.deprecated deleted file mode 100644 index 5c9c6ade0c..0000000000 --- a/src/Passes/tests/QubitAllocationAnalysis/inputs/static-qubit-arrays-1.deprecated +++ /dev/null @@ -1,51 +0,0 @@ -; ModuleID = 'qir/TeleportChain.ll' -source_filename = "qir/TeleportChain.ll" - -%Array = type opaque -%String = type opaque - -define internal fastcc void @Example__Main__body() unnamed_addr { -entry: - call fastcc void @Example__QuantumProgram__body(i64 3) - call fastcc void @Example__QuantumProgram__body(i64 4) - ret void -} - -define internal fastcc void @Example__QuantumProgram__body(i64 %x) unnamed_addr { -entry: - %qubits = call %Array* @__quantum__rt__qubit_allocate_array(i64 %x) - call void @__quantum__rt__array_update_alias_count(%Array* %qubits, i32 1) - call void @__quantum__rt__array_update_alias_count(%Array* %qubits, i32 -1) - call void @__quantum__rt__qubit_release_array(%Array* %qubits) - ret void -} - -declare %Array* @__quantum__rt__qubit_allocate_array(i64) local_unnamed_addr - -declare void @__quantum__rt__qubit_release_array(%Array*) local_unnamed_addr - -declare void @__quantum__rt__array_update_alias_count(%Array*, i32) local_unnamed_addr - -declare void @__quantum__rt__string_update_reference_count(%String*, i32) local_unnamed_addr - -define i64 @Example__Main__Interop() local_unnamed_addr #0 { -entry: - call fastcc void @Example__Main__body() - ret i64 0 -} - -define void @Example__Main() local_unnamed_addr #1 { -entry: - call fastcc void @Example__Main__body() - %0 = call %String* @__quantum__rt__int_to_string(i64 0) - call void @__quantum__rt__message(%String* %0) - call void @__quantum__rt__string_update_reference_count(%String* %0, i32 -1) - ret void -} - -declare void @__quantum__rt__message(%String*) local_unnamed_addr - -declare %String* @__quantum__rt__int_to_string(i64) local_unnamed_addr - -attributes #0 = { "InteropFriendly" } -attributes #1 = { "EntryPoint" } diff --git a/src/Passes/tests/QubitAllocationAnalysis/inputs/static-qubit-arrays-2.deprecated b/src/Passes/tests/QubitAllocationAnalysis/inputs/static-qubit-arrays-2.deprecated deleted file mode 100644 index 2ac826a845..0000000000 --- a/src/Passes/tests/QubitAllocationAnalysis/inputs/static-qubit-arrays-2.deprecated +++ /dev/null @@ -1,84 +0,0 @@ -; ModuleID = 'qir/TeleportChain.ll' -source_filename = "qir/TeleportChain.ll" - -%Array = type opaque -%String = type opaque - -define internal fastcc void @Example__Main__body() unnamed_addr { -entry: - call fastcc void @Example__QuantumProgram__body(i64 3, i64 2, i64 1) - call fastcc void @Example__QuantumProgram__body(i64 4, i64 9, i64 4) - ret void -} - -define internal fastcc void @Example__QuantumProgram__body(i64 %x, i64 %h, i64 %g) unnamed_addr { -entry: - %.neg = xor i64 %x, -1 - %.neg1 = mul i64 %.neg, %x - %z.neg = add i64 %.neg1, 47 - %y = mul i64 %x, 3 - %qubits0 = call %Array* @__quantum__rt__qubit_allocate_array(i64 9) - call void @__quantum__rt__array_update_alias_count(%Array* %qubits0, i32 1) - %0 = add i64 %y, -2 - %1 = lshr i64 %0, 1 - %2 = add i64 %z.neg, %1 - %qubits1 = call %Array* @__quantum__rt__qubit_allocate_array(i64 %2) - call void @__quantum__rt__array_update_alias_count(%Array* %qubits1, i32 1) - %3 = sub i64 %y, %g - %qubits2 = call %Array* @__quantum__rt__qubit_allocate_array(i64 %3) - call void @__quantum__rt__array_update_alias_count(%Array* %qubits2, i32 1) - %qubits3 = call %Array* @__quantum__rt__qubit_allocate_array(i64 %h) - call void @__quantum__rt__array_update_alias_count(%Array* %qubits3, i32 1) - %4 = call fastcc i64 @Example__X__body(i64 %x) - %qubits4 = call %Array* @__quantum__rt__qubit_allocate_array(i64 %4) - call void @__quantum__rt__array_update_alias_count(%Array* %qubits4, i32 1) - call void @__quantum__rt__array_update_alias_count(%Array* %qubits4, i32 -1) - call void @__quantum__rt__qubit_release_array(%Array* %qubits4) - call void @__quantum__rt__array_update_alias_count(%Array* %qubits3, i32 -1) - call void @__quantum__rt__qubit_release_array(%Array* %qubits3) - call void @__quantum__rt__array_update_alias_count(%Array* %qubits2, i32 -1) - call void @__quantum__rt__qubit_release_array(%Array* %qubits2) - call void @__quantum__rt__array_update_alias_count(%Array* %qubits1, i32 -1) - call void @__quantum__rt__qubit_release_array(%Array* %qubits1) - call void @__quantum__rt__array_update_alias_count(%Array* %qubits0, i32 -1) - call void @__quantum__rt__qubit_release_array(%Array* %qubits0) - ret void -} - -declare %Array* @__quantum__rt__qubit_allocate_array(i64) local_unnamed_addr - -declare void @__quantum__rt__qubit_release_array(%Array*) local_unnamed_addr - -declare void @__quantum__rt__array_update_alias_count(%Array*, i32) local_unnamed_addr - -; Function Attrs: norecurse nounwind readnone willreturn -define internal fastcc i64 @Example__X__body(i64 %value) unnamed_addr #0 { -entry: - %0 = mul i64 %value, 3 - ret i64 %0 -} - -declare void @__quantum__rt__string_update_reference_count(%String*, i32) local_unnamed_addr - -define i64 @Example__Main__Interop() local_unnamed_addr #1 { -entry: - call fastcc void @Example__Main__body() - ret i64 0 -} - -define void @Example__Main() local_unnamed_addr #2 { -entry: - call fastcc void @Example__Main__body() - %0 = call %String* @__quantum__rt__int_to_string(i64 0) - call void @__quantum__rt__message(%String* %0) - call void @__quantum__rt__string_update_reference_count(%String* %0, i32 -1) - ret void -} - -declare void @__quantum__rt__message(%String*) local_unnamed_addr - -declare %String* @__quantum__rt__int_to_string(i64) local_unnamed_addr - -attributes #0 = { norecurse nounwind readnone willreturn } -attributes #1 = { "InteropFriendly" } -attributes #2 = { "EntryPoint" } diff --git a/src/Passes/tests/lit.cfg.py b/src/Passes/tests/lit.cfg.py deleted file mode 100644 index 68e1c797f7..0000000000 --- a/src/Passes/tests/lit.cfg.py +++ /dev/null @@ -1,37 +0,0 @@ -# -*- Python -*- -import platform -import lit.formats -from lit.llvm import llvm_config -from lit.llvm.subst import ToolSubst -import shutil - -config.llvm_tools_dir = os.path.dirname(shutil.which("opt")) -config.name = 'Quantum-Passes' -config.test_format = lit.formats.ShTest(not llvm_config.use_lit_shell) -config.suffixes = ['.ll'] -config.test_source_root = os.path.dirname(__file__) -config.excludes = ['inputs', "*/inputs", "**/inputs"] - -if platform.system() == 'Darwin': - tool_substitutions = [ - ToolSubst('%clang', "clang", - extra_args=["-isysroot", - "`xcrun --show-sdk-path`", - "-mlinker-version=0"]), - ] -else: - tool_substitutions = [ - ToolSubst('%clang', "clang", - ) - ] -llvm_config.add_tool_substitutions(tool_substitutions) -tools = ["opt", "lli", "not", "FileCheck", "clang"] -llvm_config.add_tool_substitutions(tools, config.llvm_tools_dir) -config.substitutions.append(('%shlibext', config.llvm_shlib_ext)) -config.substitutions.append(('%shlibdir', config.llvm_shlib_dir)) - - -# References: -# https://github.com/banach-space/llvm-tutor -# http://lists.llvm.org/pipermail/cfe-dev/2016-July/049868.html -# https://github.com/Homebrew/homebrew-core/issues/52461 diff --git a/src/Passes/tests/lit.site.cfg.py.in b/src/Passes/tests/lit.site.cfg.py.in deleted file mode 100644 index c6888bfbf2..0000000000 --- a/src/Passes/tests/lit.site.cfg.py.in +++ /dev/null @@ -1,15 +0,0 @@ -import sys - -config.llvm_tools_dir = "@LT_LLVM_INSTALL_DIR@/bin" -config.llvm_shlib_ext = "@LT_TEST_SHLIBEXT@" -config.llvm_shlib_dir = "@CMAKE_BINARY_DIR@/libs" - -import lit.llvm -# lit_config is a global instance of LitConfig -lit.llvm.initialize(lit_config, config) - -# test_exec_root: The root path where tests should be run. -config.test_exec_root = os.path.join("@CMAKE_CURRENT_BINARY_DIR@") - -# Let the main config do the real work. -lit_config.load_config(config, "@LT_TEST_SRC_DIR@/lit.cfg.py")