From 8cfed276104e36fb59ae2088cb77a6f222a51f6e Mon Sep 17 00:00:00 2001 From: "Troels F. Roennow" Date: Mon, 8 Nov 2021 08:46:13 +0100 Subject: [PATCH 01/17] Type renaming --- .../AllocationManager/IAllocationManager.hpp | 98 +++-- src/Passes/Source/Apps/Qat/QatConfig.hpp | 114 +++--- .../Commandline/ConfigurationManager.hpp | 363 +++++++++-------- src/Passes/Source/Commandline/IConfigBind.hpp | 169 ++++---- .../Source/Commandline/ParameterParser.hpp | 140 ++++--- .../Source/Generators/ProfileGenerator.hpp | 234 ++++++----- src/Passes/Source/Logging/ILogger.hpp | 74 ++-- .../Source/ModuleLoader/ModuleLoader.hpp | 240 ++++++----- src/Passes/Source/Profile/Profile.hpp | 257 ++++++------ .../Types.hpp => QatTypes/QatTypes.hpp} | 0 .../RemoveDisallowedAttributesPass.hpp | 92 ++--- src/Passes/Source/Rules/Factory.hpp | 369 +++++++++-------- .../TransformationRulesPass.hpp | 382 +++++++++--------- .../Source/ValidationPass/ValidationPass.hpp | 66 ++- .../ValidationPassConfiguration.hpp | 150 ++++--- 15 files changed, 1356 insertions(+), 1392 deletions(-) rename src/Passes/Source/{Types/Types.hpp => QatTypes/QatTypes.hpp} (100%) diff --git a/src/Passes/Source/AllocationManager/IAllocationManager.hpp b/src/Passes/Source/AllocationManager/IAllocationManager.hpp index cf06bdcffa..d9276f2721 100644 --- a/src/Passes/Source/AllocationManager/IAllocationManager.hpp +++ b/src/Passes/Source/AllocationManager/IAllocationManager.hpp @@ -2,70 +2,68 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -#include "Types/Types.hpp" +#include "QatTypes/QatTypes.hpp" #include #include -namespace microsoft +namespace microsoft { +namespace quantum { +/// Interface class for allocation management. This interface provides means to allocate and release +/// statically allocated resources such as qubits and results. In a future version, it may be +/// extended with get and store in order to support Arrays and Tuples. +class IAllocationManager { -namespace quantum -{ - /// Interface class for allocation management. This interface provides means to allocate and release - /// statically allocated resources such as qubits and results. In a future version, it may be - /// extended with get and store in order to support Arrays and Tuples. - class IAllocationManager - { - public: - using Address = uint64_t; ///< Value type for address - using Index = uint64_t; ///< Index type used to access an array element. - using AllocationManagerPtr = std::shared_ptr; ///< Pointer interface. +public: + using Address = uint64_t; ///< Value type for address + using Index = uint64_t; ///< Index type used to access an array element. + using AllocationManagerPtr = std::shared_ptr; ///< Pointer interface. - // Construction, moves and copies - // - IAllocationManager(IAllocationManager const&) = delete; - IAllocationManager(IAllocationManager&&) = delete; - IAllocationManager& operator=(IAllocationManager const&) = delete; - IAllocationManager& operator=(IAllocationManager&&) = delete; + // Construction, moves and copies + // + IAllocationManager(IAllocationManager const &) = delete; + IAllocationManager(IAllocationManager &&) = delete; + IAllocationManager &operator=(IAllocationManager const &) = delete; + IAllocationManager &operator=(IAllocationManager &&) = delete; - virtual ~IAllocationManager(); + virtual ~IAllocationManager(); - // Interface - // + // Interface + // - /// Abstract member function to allocate an element or sequence of elements. The developer - /// should not assume continuity of the address segment as this is not guaranteed. Note this - /// function may throw if allocation is not possible. - virtual Address allocate(String const& name = "", Index const& count = 1) = 0; + /// Abstract member function to allocate an element or sequence of elements. The developer + /// should not assume continuity of the address segment as this is not guaranteed. Note this + /// function may throw if allocation is not possible. + virtual Address allocate(String const &name = "", Index const &count = 1) = 0; - /// Abstract member function to release a previously allocated function. Note this function may - /// throw if an invalid address is passed. - virtual void release(Address const& address) = 0; + /// Abstract member function to release a previously allocated function. Note this function may + /// throw if an invalid address is passed. + virtual void release(Address const &address) = 0; - /// Abstract member function to reset the allocation manager. This function clears all allocations - /// and resets all statistics. - virtual void reset() = 0; + /// Abstract member function to reset the allocation manager. This function clears all allocations + /// and resets all statistics. + virtual void reset() = 0; - // Statistics - // + // Statistics + // - /// Current number of registers in use. This function is used to inquire about the current number - /// registers/resources in use. - uint64_t allocationsInUse() const; + /// Current number of registers in use. This function is used to inquire about the current number + /// registers/resources in use. + uint64_t allocationsInUse() const; - /// Maximum number of registers in use at any one time. The maximum number of registers used at - /// any one time. As an example of usage, this function is useful to calculate the total number of - /// qubits required to execute the entry function. - uint64_t maxAllocationsUsed() const; + /// Maximum number of registers in use at any one time. The maximum number of registers used at + /// any one time. As an example of usage, this function is useful to calculate the total number of + /// qubits required to execute the entry function. + uint64_t maxAllocationsUsed() const; - protected: - IAllocationManager() = default; - void updateRegistersInUse(uint64_t n); +protected: + IAllocationManager() = default; + void updateRegistersInUse(uint64_t n); - private: - uint64_t registers_in_use_{0}; ///< Used to track the number of registers in use - uint64_t max_registers_used_{0}; ///< Used to track the max number of registers used - }; +private: + uint64_t registers_in_use_{0}; ///< Used to track the number of registers in use + uint64_t max_registers_used_{0}; ///< Used to track the max number of registers used +}; -} // namespace quantum -} // namespace microsoft +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Apps/Qat/QatConfig.hpp b/src/Passes/Source/Apps/Qat/QatConfig.hpp index aa63287159..849b2a0bc1 100644 --- a/src/Passes/Source/Apps/Qat/QatConfig.hpp +++ b/src/Passes/Source/Apps/Qat/QatConfig.hpp @@ -3,79 +3,77 @@ // Licensed under the MIT License. #include "Commandline/ConfigurationManager.hpp" -#include "Types/Types.hpp" +#include "QatTypes/QatTypes.hpp" -namespace microsoft -{ -namespace quantum -{ +namespace microsoft { +namespace quantum { - /// Main configuration class for the qat command-line program. - class QatConfig - { - public: - // Functions required by configuration manager - // +/// Main configuration class for the qat command-line program. +class QatConfig +{ +public: + // Functions required by configuration manager + // - /// Setup function that binds instance variables to the command-line/configuration entries. - /// This function also provide descriptions of each of the properties below. - void setup(ConfigurationManager& config); + /// Setup function that binds instance variables to the command-line/configuration entries. + /// This function also provide descriptions of each of the properties below. + void setup(ConfigurationManager &config); - // Flags and options - // + // Flags and options + // - /// List of dynamic libraries to load. - String load() const; + /// List of dynamic libraries to load. + String load() const; - /// Flag that indicates whether or not we are generating a new QIR by applying a profile. - bool shouldGenerate() const; + /// Flag that indicates whether or not we are generating a new QIR by applying a profile. + bool shouldGenerate() const; - /// Flag to indicate whether or not to verify that the (Q)IR is a valid LLVM IR. - bool verifyModule() const; + /// Flag to indicate whether or not to verify that the (Q)IR is a valid LLVM IR. + bool verifyModule() const; - /// Flag to indicate whether or not to validate the compliance with the QIR profile. - bool shouldValidate() const; + /// Flag to indicate whether or not to validate the compliance with the QIR profile. + bool shouldValidate() const; - /// String to request a specific profile name. Default is base. - String profile() const; + /// String to request a specific profile name. Default is base. + String profile() const; - /// Indicates whether or not the QIR adaptor tool should emit LLVM IR to the standard output. - bool shouldEmitLlvm() const; + /// Indicates whether or not the QIR adaptor tool should emit LLVM IR to the standard output. + bool shouldEmitLlvm() const; - /// Tells if the optimisation level 0 is enabled. Note higher OX override lower ones. - bool isOpt0Enabled() const; + /// Tells if the optimisation level 0 is enabled. Note higher OX override lower ones. + bool isOpt0Enabled() const; - /// Tells if the optimisation level 1 is enabled. Note higher OX override lower ones. - bool isOpt1Enabled() const; + /// Tells if the optimisation level 1 is enabled. Note higher OX override lower ones. + bool isOpt1Enabled() const; - /// Tells if the optimisation level 2 is enabled. Note higher OX override lower ones. - bool isOpt2Enabled() const; + /// Tells if the optimisation level 2 is enabled. Note higher OX override lower ones. + bool isOpt2Enabled() const; - /// Tells if the optimisation level 3 is enabled. Note higher OX override lower ones. - bool isOpt3Enabled() const; + /// Tells if the optimisation level 3 is enabled. Note higher OX override lower ones. + bool isOpt3Enabled() const; - /// Enables debug output. - bool isDebugMode() const; + /// Enables debug output. + bool isDebugMode() const; - /// Request the full configuration to be dumped to the screen. - bool shouldDumpConfig() const; + /// Request the full configuration to be dumped to the screen. + bool shouldDumpConfig() const; - private: - // Variables to be bound to the configuration manager - // - String load_{""}; - bool generate_{false}; - bool validate_{false}; - String profile_{"generic"}; - bool emit_llvm_{false}; - bool opt0_{false}; - bool opt1_{false}; - bool opt2_{false}; - bool opt3_{false}; - bool verify_module_{false}; +private: + // Variables to be bound to the configuration manager + // + String load_{""}; + bool generate_{false}; + bool validate_{false}; + String profile_{"generic"}; + bool emit_llvm_{false}; + bool opt0_{false}; + bool opt1_{false}; + bool opt2_{false}; + bool opt3_{false}; + bool verify_module_{false}; - bool debug_{false}; - bool dump_config_{false}; - }; -} // namespace quantum -} // namespace microsoft + bool debug_{false}; + bool dump_config_{false}; +}; +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Commandline/ConfigurationManager.hpp b/src/Passes/Source/Commandline/ConfigurationManager.hpp index 4fa5cc626d..845b735277 100644 --- a/src/Passes/Source/Commandline/ConfigurationManager.hpp +++ b/src/Passes/Source/Commandline/ConfigurationManager.hpp @@ -5,9 +5,8 @@ #include "Commandline/ConfigBind.hpp" #include "Commandline/IConfigBind.hpp" #include "Commandline/ParameterParser.hpp" -#include "Types/Types.hpp" - #include "Llvm/Llvm.hpp" +#include "QatTypes/QatTypes.hpp" #include #include @@ -15,194 +14,202 @@ #include #include -namespace microsoft +namespace microsoft { +namespace quantum { + +/// ConfigurationManager is a class that holds a collection of configurations (sections). Each of +/// these sections are embodied in their own class with a one-to-one mapping between configuration +/// section and the configuration type. As an example, if one wishes to make a configuration for the +/// class Foo, one would create a class FooConfig which would hold all the variables that are +/// configurable and then add FooConfig to the ConfigurationManager using `addConfig()`. For +/// FooConfig to fulfill the concept of a configuration, it must implement a setup functions whose +/// first argument is the ConfigurationManager. +class ConfigurationManager { -namespace quantum +public: + using IConfigBindPtr = + std::shared_ptr; ///< Pointer class used to bind a parameter to a value. + using ConfigList = std::vector; ///< List of bound variables. + using VoidPtr = std::shared_ptr; ///< Type-erased configuration pointer. + using TypeId = std::type_index; ///< Type index class. + using BoolPtr = std::shared_ptr; + + /// Section defines a section in the configuration. It holds the type of the configuration class, + /// the name of the section a description, the instance of the configuration class itself and list + /// of parameter bindings. + struct Section + { + TypeId type{TypeId(typeid(std::nullptr_t))}; ///< Type of the configuration. + String name{}; ///< Name of the section. + String description{}; ///< Description of the section. + VoidPtr configuration{}; ///< Configuration class instance. + ConfigList settings{}; ///< List of parameter bindings. + BoolPtr active{nullptr}; ///< Whether or not this component is active; + String id{}; ///< Id referring to this component. + }; + using Sections = std::vector
; ///< List of available sections + + // Constructors, copy and move operators, destructor + // + + /// Configuration manager is default constructible, non-copyable and non-movable. + ConfigurationManager() = default; + ConfigurationManager(ConfigurationManager const &) = delete; + ConfigurationManager(ConfigurationManager &&) = delete; + ConfigurationManager &operator=(ConfigurationManager const &) = delete; + ConfigurationManager &operator=(ConfigurationManager &&) = delete; + + // Configuration setup + // + + /// Adds all bound variables as parser arguments. + void setupArguments(ParameterParser &parser); + + /// Configures the value of each bound variable given a parser instance. + void configure(ParameterParser const &parser); + + // Managing configuration + // + + /// Given an instance of the ConfigurationManager, this method override settings of class T. + template + inline void setConfig(T const &value); + + /// Gets the configuration instance of type T. + template + inline T const &get() const; + + // Support functions + // + + /// Prints options for configurability to the terminal. + void printHelp() const; + + /// Prints the configuration to the terminal. The configuration print is LLVM IR compatible + /// meaning that every line starts with a semicolon ; to ensure that it is interpreted as a + /// comment. + void printConfiguration() const; + + // Configuration functions + // + + /// Adds a new configuration of type T. + template + inline void addConfig(String const &id = "", T const &default_value = T()); + + /// Whether or not the component associated with T is active. + template + inline bool isActive(); + + /// Sets the section name. This method is used by the configuration class to set a section + /// name. + void setSectionName(String const &name, String const &description); + + /// Adds a new parameter with a default value to the configuration section. This function should + /// be used by the configuration class. + template + inline void addParameter(T &bind, T default_value, String const &name, String const &description); + + /// Adds a new parameter to the configuration section. This method uses the bound variable value + /// as default value. This function should be used by the configuration class. + template + inline void addParameter(T &bind, String const &name, String const &description); + +private: + /// Helper function to get a reference to the configuration of type T. + template + inline T &getInternal() const; + + Sections config_sections_{}; ///< All available sections within the ConfigurationManager instance +}; + +template +inline void ConfigurationManager::addConfig(String const &id, T const &default_value) { + Section new_section{std::type_index(typeid(T))}; - /// ConfigurationManager is a class that holds a collection of configurations (sections). Each of - /// these sections are embodied in their own class with a one-to-one mapping between configuration - /// section and the configuration type. As an example, if one wishes to make a configuration for the - /// class Foo, one would create a class FooConfig which would hold all the variables that are - /// configurable and then add FooConfig to the ConfigurationManager using `addConfig()`. For - /// FooConfig to fulfill the concept of a configuration, it must implement a setup functions whose - /// first argument is the ConfigurationManager. - class ConfigurationManager - { - public: - using IConfigBindPtr = std::shared_ptr; ///< Pointer class used to bind a parameter to a value. - using ConfigList = std::vector; ///< List of bound variables. - using VoidPtr = std::shared_ptr; ///< Type-erased configuration pointer. - using TypeId = std::type_index; ///< Type index class. - using BoolPtr = std::shared_ptr; - - /// Section defines a section in the configuration. It holds the type of the configuration class, - /// the name of the section a description, the instance of the configuration class itself and list - /// of parameter bindings. - struct Section - { - TypeId type{TypeId(typeid(std::nullptr_t))}; ///< Type of the configuration. - String name{}; ///< Name of the section. - String description{}; ///< Description of the section. - VoidPtr configuration{}; ///< Configuration class instance. - ConfigList settings{}; ///< List of parameter bindings. - BoolPtr active{nullptr}; ///< Whether or not this component is active; - String id{}; ///< Id referring to this component. - }; - using Sections = std::vector
; ///< List of available sections - - // Constructors, copy and move operators, destructor - // - - /// Configuration manager is default constructible, non-copyable and non-movable. - ConfigurationManager() = default; - ConfigurationManager(ConfigurationManager const&) = delete; - ConfigurationManager(ConfigurationManager&&) = delete; - ConfigurationManager& operator=(ConfigurationManager const&) = delete; - ConfigurationManager& operator=(ConfigurationManager&&) = delete; - - // Configuration setup - // - - /// Adds all bound variables as parser arguments. - void setupArguments(ParameterParser& parser); - - /// Configures the value of each bound variable given a parser instance. - void configure(ParameterParser const& parser); - - // Managing configuration - // - - /// Given an instance of the ConfigurationManager, this method override settings of class T. - template inline void setConfig(T const& value); - - /// Gets the configuration instance of type T. - template inline T const& get() const; - - // Support functions - // - - /// Prints options for configurability to the terminal. - void printHelp() const; - - /// Prints the configuration to the terminal. The configuration print is LLVM IR compatible - /// meaning that every line starts with a semicolon ; to ensure that it is interpreted as a - /// comment. - void printConfiguration() const; - - // Configuration functions - // - - /// Adds a new configuration of type T. - template inline void addConfig(String const& id = "", T const& default_value = T()); - - /// Whether or not the component associated with T is active. - template inline bool isActive(); - - /// Sets the section name. This method is used by the configuration class to set a section - /// name. - void setSectionName(String const& name, String const& description); - - /// Adds a new parameter with a default value to the configuration section. This function should - /// be used by the configuration class. - template - inline void addParameter(T& bind, T default_value, String const& name, String const& description); - - /// Adds a new parameter to the configuration section. This method uses the bound variable value - /// as default value. This function should be used by the configuration class. - template inline void addParameter(T& bind, String const& name, String const& description); - - private: - /// Helper function to get a reference to the configuration of type T. - template inline T& getInternal() const; - - Sections config_sections_{}; ///< All available sections within the ConfigurationManager instance - }; - - template inline void ConfigurationManager::addConfig(String const& id, T const& default_value) - { - Section new_section{std::type_index(typeid(T))}; + auto ptr = std::make_shared(default_value); + new_section.configuration = ptr; + new_section.active = std::make_shared(true); + new_section.id = id; - auto ptr = std::make_shared(default_value); - new_section.configuration = ptr; - new_section.active = std::make_shared(true); - new_section.id = id; + config_sections_.emplace_back(std::move(new_section)); + ptr->setup(*this); +} - config_sections_.emplace_back(std::move(new_section)); - ptr->setup(*this); - } +template +inline T &ConfigurationManager::getInternal() const +{ + VoidPtr ptr{nullptr}; + auto type = std::type_index(typeid(T)); - template inline T& ConfigurationManager::getInternal() const + for (auto §ion : config_sections_) + { + if (section.type == type) { - VoidPtr ptr{nullptr}; - auto type = std::type_index(typeid(T)); - - for (auto& section : config_sections_) - { - if (section.type == type) - { - ptr = section.configuration; - break; - } - } - - if (ptr == nullptr) - { - throw std::runtime_error("Could not find configuration class."); - } - - return *static_cast(ptr.get()); + ptr = section.configuration; + break; } + } - template inline void ConfigurationManager::setConfig(T const& value) - { - auto& config = getInternal(); - config = value; - } + if (ptr == nullptr) + { + throw std::runtime_error("Could not find configuration class."); + } - template inline T const& ConfigurationManager::get() const - { - return getInternal(); - } + return *static_cast(ptr.get()); +} - template inline bool ConfigurationManager::isActive() - { - BoolPtr ptr{nullptr}; - auto type = std::type_index(typeid(T)); - - for (auto& section : config_sections_) - { - if (section.type == type) - { - ptr = section.active; - break; - } - } - - if (ptr == nullptr) - { - throw std::runtime_error("Could not find configuration class."); - } - - return *ptr; - } +template +inline void ConfigurationManager::setConfig(T const &value) +{ + auto &config = getInternal(); + config = value; +} - template - inline void ConfigurationManager::addParameter( - T& bind, - T default_value, - String const& name, - String const& description) - { - auto ptr = std::make_shared>(bind, default_value, name, description); - config_sections_.back().settings.push_back(ptr); - } +template +inline T const &ConfigurationManager::get() const +{ + return getInternal(); +} - template - inline void ConfigurationManager::addParameter(T& bind, String const& name, String const& description) +template +inline bool ConfigurationManager::isActive() +{ + BoolPtr ptr{nullptr}; + auto type = std::type_index(typeid(T)); + + for (auto §ion : config_sections_) + { + if (section.type == type) { - auto ptr = std::make_shared>(bind, T(bind), name, description); - config_sections_.back().settings.push_back(ptr); + ptr = section.active; + break; } -} // namespace quantum -} // namespace microsoft + } + + if (ptr == nullptr) + { + throw std::runtime_error("Could not find configuration class."); + } + + return *ptr; +} + +template +inline void ConfigurationManager::addParameter(T &bind, T default_value, String const &name, + String const &description) +{ + auto ptr = std::make_shared>(bind, default_value, name, description); + config_sections_.back().settings.push_back(ptr); +} + +template +inline void ConfigurationManager::addParameter(T &bind, String const &name, + String const &description) +{ + auto ptr = std::make_shared>(bind, T(bind), name, description); + config_sections_.back().settings.push_back(ptr); +} +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Commandline/IConfigBind.hpp b/src/Passes/Source/Commandline/IConfigBind.hpp index bdae6479b4..149b3d7fea 100644 --- a/src/Passes/Source/Commandline/IConfigBind.hpp +++ b/src/Passes/Source/Commandline/IConfigBind.hpp @@ -3,9 +3,8 @@ // Licensed under the MIT License. #include "Commandline/ParameterParser.hpp" -#include "Types/Types.hpp" - #include "Llvm/Llvm.hpp" +#include "QatTypes/QatTypes.hpp" #include #include @@ -13,88 +12,86 @@ #include #include -namespace microsoft -{ -namespace quantum -{ +namespace microsoft { +namespace quantum { - /// Interface class to bind a variable to a configuration flag. This class provides - /// the necessary interface to bind variables and populate their value based on given command-line - /// arguments. - class IConfigBind - { - public: - // Deleted constructors and deleted operators - // - // Strictly speaking the code would remain correct if we allowed copy and/or move, but - // we have chosen to ban them by choice as potential bugs arising from allowing copy and/or - // move can be difficult to find. We consider this behaviour a part of the interface definition. - IConfigBind(IConfigBind const&) = delete; - IConfigBind(IConfigBind&&) = delete; - IConfigBind& operator=(IConfigBind const&) = delete; - IConfigBind& operator=(IConfigBind&&) = delete; - - // Virtual destructor - // - virtual ~IConfigBind(); - - // Interface - // - - /// Interface function to register configuration in the parser. This function - /// register the configuration to the parameter parser. This makes the configuration - /// available in the parameter parsers help function. This method should return true if arguments - /// were successfully setup. - virtual bool setupArguments(ParameterParser& parser) = 0; - - /// Interface function to extract configuration from the command line arguments. Given an instance - /// of the command line parameter parser, this function is meant to read the command line - /// arguments, interpret it and set the bound variable value (if present). This method should - /// return true if configure operation was successful. - virtual bool configure(ParameterParser const& parser) = 0; - - /// Interface function to return a string representation of the current value of the - /// bound variable. - virtual String value() = 0; - - // Properties - // - - /// Returns the name of the bound configuration variable. - String name() const; - - /// Returns the description of the configuration variable. - String description() const; - - /// Indicates whether or not this - bool isFlag() const; - - /// Returns the default value for the flag. - String defaultValue() const; - - protected: - // Constructor - // - IConfigBind(String const& name, String const& description); - - // Configuration - // - - /// Sets the name of the configuration variable. - void setName(String const& name); - - /// Marks the variable as a flag. - void markAsFlag(); - - /// Sets the default value as a string. - void setDefault(String const& v); - - private: - String name_; ///< Name that which sets the value. - String description_; ///< Description of the option or flag. - bool is_flag_{false}; ///< Whether or not the variable is a flag. - String str_default_value_; ///< Default value represented as a string. - }; - -} // namespace quantum -} // namespace microsoft +/// Interface class to bind a variable to a configuration flag. This class provides +/// the necessary interface to bind variables and populate their value based on given command-line +/// arguments. +class IConfigBind +{ +public: + // Deleted constructors and deleted operators + // + // Strictly speaking the code would remain correct if we allowed copy and/or move, but + // we have chosen to ban them by choice as potential bugs arising from allowing copy and/or + // move can be difficult to find. We consider this behaviour a part of the interface definition. + IConfigBind(IConfigBind const &) = delete; + IConfigBind(IConfigBind &&) = delete; + IConfigBind &operator=(IConfigBind const &) = delete; + IConfigBind &operator=(IConfigBind &&) = delete; + + // Virtual destructor + // + virtual ~IConfigBind(); + + // Interface + // + + /// Interface function to register configuration in the parser. This function + /// register the configuration to the parameter parser. This makes the configuration + /// available in the parameter parsers help function. This method should return true if arguments + /// were successfully setup. + virtual bool setupArguments(ParameterParser &parser) = 0; + + /// Interface function to extract configuration from the command line arguments. Given an instance + /// of the command line parameter parser, this function is meant to read the command line + /// arguments, interpret it and set the bound variable value (if present). This method should + /// return true if configure operation was successful. + virtual bool configure(ParameterParser const &parser) = 0; + + /// Interface function to return a string representation of the current value of the + /// bound variable. + virtual String value() = 0; + + // Properties + // + + /// Returns the name of the bound configuration variable. + String name() const; + + /// Returns the description of the configuration variable. + String description() const; + + /// Indicates whether or not this + bool isFlag() const; + + /// Returns the default value for the flag. + String defaultValue() const; + +protected: + // Constructor + // + IConfigBind(String const &name, String const &description); + + // Configuration + // + + /// Sets the name of the configuration variable. + void setName(String const &name); + + /// Marks the variable as a flag. + void markAsFlag(); + + /// Sets the default value as a string. + void setDefault(String const &v); + +private: + String name_; ///< Name that which sets the value. + String description_; ///< Description of the option or flag. + bool is_flag_{false}; ///< Whether or not the variable is a flag. + String str_default_value_; ///< Default value represented as a string. +}; + +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Commandline/ParameterParser.hpp b/src/Passes/Source/Commandline/ParameterParser.hpp index 0d0f74e49e..5fe5599e37 100644 --- a/src/Passes/Source/Commandline/ParameterParser.hpp +++ b/src/Passes/Source/Commandline/ParameterParser.hpp @@ -2,102 +2,100 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -#include "Types/Types.hpp" +#include "QatTypes/QatTypes.hpp" #include #include #include #include -namespace microsoft -{ -namespace quantum -{ +namespace microsoft { +namespace quantum { - /// Parameter parser class which allows the developer to specify a set of default settings and - /// update those using the commandline argc and argv. - class ParameterParser - { - public: - using Arguments = std::vector; - using Flags = std::unordered_set; - using SettingsMap = std::unordered_map; +/// Parameter parser class which allows the developer to specify a set of default settings and +/// update those using the commandline argc and argv. +class ParameterParser +{ +public: + using Arguments = std::vector; + using Flags = std::unordered_set; + using SettingsMap = std::unordered_map; - // Construction and deconstrution configuration - // + // Construction and deconstrution configuration + // - ParameterParser() = default; + ParameterParser() = default; - // No copy construction. - ParameterParser(ParameterParser const& other) = delete; + // No copy construction. + ParameterParser(ParameterParser const &other) = delete; - // Allow move semantics. - ParameterParser(ParameterParser&& other) = default; + // Allow move semantics. + ParameterParser(ParameterParser &&other) = default; - // Default destruction. - ~ParameterParser() = default; + // Default destruction. + ~ParameterParser() = default; - // Configuration - // + // Configuration + // - /// Marks a name as a flag (as opposed to an option). - /// This ensures that no parameter is expected after - /// the flag is specified. For instance `--debug` is - /// a flag as opposed to `--log-level 3` which is an - /// option. - void addFlag(String const& v); + /// Marks a name as a flag (as opposed to an option). + /// This ensures that no parameter is expected after + /// the flag is specified. For instance `--debug` is + /// a flag as opposed to `--log-level 3` which is an + /// option. + void addFlag(String const &v); - // Operation - // + // Operation + // - /// Parses the command line arguments given the argc and argv - /// from the main function. - void parseArgs(int argc, char** argv); + /// Parses the command line arguments given the argc and argv + /// from the main function. + void parseArgs(int argc, char **argv); - /// Returns list of arguments without flags and/or options - /// included. - Arguments const& arguments() const; + /// Returns list of arguments without flags and/or options + /// included. + Arguments const &arguments() const; - /// Returns the n'th commandline argument. - String const& getArg(Arguments::size_type const& n) const; + /// Returns the n'th commandline argument. + String const &getArg(Arguments::size_type const &n) const; - /// Gets a named setting, falling back to a default if the key is not found. - String const& get(String const& name, String const& default_value) const noexcept; + /// Gets a named setting, falling back to a default if the key is not found. + String const &get(String const &name, String const &default_value) const noexcept; - /// Gets a named setting. This method throws if the setting is not present. - String const& get(String const& name) const; + /// Gets a named setting. This method throws if the setting is not present. + String const &get(String const &name) const; - /// Checks whether or not a given parameter is present. - bool has(String const& name) const noexcept; + /// Checks whether or not a given parameter is present. + bool has(String const &name) const noexcept; - /// Resets the state of the parser to its construction state - void reset(); + /// Resets the state of the parser to its construction state + void reset(); - private: - /// Struct that contains parsed and interpreted values of command line arguments. - struct ParsedValue - { - bool is_key{false}; ///< Whether or not a parsed value should be considered a key - String value; ///< Value after parsing. - }; +private: + /// Struct that contains parsed and interpreted values of command line arguments. + struct ParsedValue + { + bool is_key{false}; ///< Whether or not a parsed value should be considered a key + String value; ///< Value after parsing. + }; - // Helper functions - // + // Helper functions + // - // Parses a single argument and returns the parsed value. This function - // determines if the string was specified to be a key or a value. - ParsedValue parseSingleArg(String key); + // Parses a single argument and returns the parsed value. This function + // determines if the string was specified to be a key or a value. + ParsedValue parseSingleArg(String key); - /// Checks whether a key is an option (or a flag). Returns true if it is - /// and option and false if it is a flags. - bool isOption(String const& key); + /// Checks whether a key is an option (or a flag). Returns true if it is + /// and option and false if it is a flags. + bool isOption(String const &key); - // Storage of parsed data - // - Flags flags_{}; ///< Set of flags - Arguments arguments_{}; ///< List of remaining arguments - SettingsMap settings_; ///< Settings map that keeps all specified settings. - }; + // Storage of parsed data + // + Flags flags_{}; ///< Set of flags + Arguments arguments_{}; ///< List of remaining arguments + SettingsMap settings_; ///< Settings map that keeps all specified settings. +}; -} // namespace quantum -} // namespace microsoft +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Generators/ProfileGenerator.hpp b/src/Passes/Source/Generators/ProfileGenerator.hpp index a79c9104b9..4cfb9db5a0 100644 --- a/src/Passes/Source/Generators/ProfileGenerator.hpp +++ b/src/Passes/Source/Generators/ProfileGenerator.hpp @@ -3,131 +3,129 @@ // Licensed under the MIT License. #include "Commandline/ConfigurationManager.hpp" +#include "Llvm/Llvm.hpp" #include "Profile/Profile.hpp" -#include "Types/Types.hpp" +#include "QatTypes/QatTypes.hpp" -#include "Llvm/Llvm.hpp" +namespace microsoft { +namespace quantum { -namespace microsoft +class ProfileGenerator { -namespace quantum +public: + // LLVM types + // + using PassBuilder = llvm::PassBuilder; + using OptimizationLevel = PassBuilder::OptimizationLevel; + using FunctionAnalysisManager = llvm::FunctionAnalysisManager; + + /// Setup function that uses a configuration type R to + /// configure the profile and/or generator. + template + using SetupFunction = std::function; + + /// Wrapper function type for invoking the profile setup function + using SetupFunctionWrapper = std::function; + + /// List of components to be configured. + using Components = std::vector>; + + // Construction, moves and copies + // + + ProfileGenerator() = default; + ~ProfileGenerator() = default; + ProfileGenerator(ProfileGenerator const &) = delete; + ProfileGenerator(ProfileGenerator &&) = delete; + ProfileGenerator &operator=(ProfileGenerator const &) = delete; + ProfileGenerator &operator=(ProfileGenerator &&) = delete; + + // Profile generation interface + // + + /// Reference to configuration manager. This property allows to access and modify configurations + /// of the generator. This property is intended for managing the configuration. + ConfigurationManager &configurationManager(); + + /// Constant reference to the configuration manager. This property allows read access to the + /// configuration manager and is intended for profile generation. + ConfigurationManager const &configurationManager() const; + + /// Creates a new profile based on the registered components, optimisation level and debug + /// requirements. The returned profile can be applied to an IR to transform it in accordance with + /// the configurations given. + Profile newProfile(String const &name, OptimizationLevel const &optimisation_level, bool debug); + + // Defining the generator + // + + /// Registers a new profile component with a given configuration R. The profile component is given + /// a name and a setup function which is responsible for configuring the profile in accordance + /// with the configuration. + template + void registerProfileComponent(String const &id, SetupFunction setup); + + // Support properties for generators + // + + /// Returns the module pass manager. + llvm::ModulePassManager &modulePassManager(); + + /// Returns the pass builder. + llvm::PassBuilder &passBuilder(); + + /// Returns the optimisation level. + OptimizationLevel optimisationLevel() const; + + /// Flag indicating whether we are operating in debug mode or not. + bool isDebugMode() const; + +protected: + /// Internal function that creates a module pass for QIR transformation. The module pass is + /// defined through the profile, the optimisation level and whether or not we are in debug mode. + llvm::ModulePassManager createGenerationModulePassManager( + Profile &profile, OptimizationLevel const &optimisation_level, bool debug); + + /// Internal function that creates a module pass for QIR validation. At the moment, this function + /// is a placeholder for future functionality. + llvm::ModulePassManager createValidationModulePass(PassBuilder & pass_builder, + OptimizationLevel const &optimisation_level, + bool debug); + +private: + ConfigurationManager + configuration_manager_; ///< Holds the configuration that defines the profile + Components components_; ///< List of registered components that configures the profile + + /// Pointer to the module pass manager the profile will use + llvm::ModulePassManager *module_pass_manager_{nullptr}; + + /// Pointer to the pass builder the profile is based on + llvm::PassBuilder *pass_builder_{nullptr}; + + /// Optimisation level used by LLVM + OptimizationLevel optimisation_level_{OptimizationLevel::O0}; + + /// Whether or not we are in debug mode + bool debug_{false}; +}; + +template +void ProfileGenerator::registerProfileComponent(String const &id, SetupFunction setup) { + configuration_manager_.addConfig(id); - class ProfileGenerator - { - public: - // LLVM types - // - using PassBuilder = llvm::PassBuilder; - using OptimizationLevel = PassBuilder::OptimizationLevel; - using FunctionAnalysisManager = llvm::FunctionAnalysisManager; - - /// Setup function that uses a configuration type R to - /// configure the profile and/or generator. - template using SetupFunction = std::function; - - /// Wrapper function type for invoking the profile setup function - using SetupFunctionWrapper = std::function; - - /// List of components to be configured. - using Components = std::vector>; - - // Construction, moves and copies - // - - ProfileGenerator() = default; - ~ProfileGenerator() = default; - ProfileGenerator(ProfileGenerator const&) = delete; - ProfileGenerator(ProfileGenerator&&) = delete; - ProfileGenerator& operator=(ProfileGenerator const&) = delete; - ProfileGenerator& operator=(ProfileGenerator&&) = delete; - - // Profile generation interface - // - - /// Reference to configuration manager. This property allows to access and modify configurations - /// of the generator. This property is intended for managing the configuration. - ConfigurationManager& configurationManager(); - - /// Constant reference to the configuration manager. This property allows read access to the - /// configuration manager and is intended for profile generation. - ConfigurationManager const& configurationManager() const; - - /// Creates a new profile based on the registered components, optimisation level and debug - /// requirements. The returned profile can be applied to an IR to transform it in accordance with - /// the configurations given. - Profile newProfile(String const& name, OptimizationLevel const& optimisation_level, bool debug); - - // Defining the generator - // - - /// Registers a new profile component with a given configuration R. The profile component is given - /// a name and a setup function which is responsible for configuring the profile in accordance - /// with the configuration. - template void registerProfileComponent(String const& id, SetupFunction setup); - - // Support properties for generators - // - - /// Returns the module pass manager. - llvm::ModulePassManager& modulePassManager(); - - /// Returns the pass builder. - llvm::PassBuilder& passBuilder(); - - /// Returns the optimisation level. - OptimizationLevel optimisationLevel() const; - - /// Flag indicating whether we are operating in debug mode or not. - bool isDebugMode() const; - - protected: - /// Internal function that creates a module pass for QIR transformation. The module pass is - /// defined through the profile, the optimisation level and whether or not we are in debug mode. - llvm::ModulePassManager createGenerationModulePassManager( - Profile& profile, - OptimizationLevel const& optimisation_level, - bool debug); - - /// Internal function that creates a module pass for QIR validation. At the moment, this function - /// is a placeholder for future functionality. - llvm::ModulePassManager createValidationModulePass( - PassBuilder& pass_builder, - OptimizationLevel const& optimisation_level, - bool debug); - - private: - ConfigurationManager configuration_manager_; ///< Holds the configuration that defines the profile - Components components_; ///< List of registered components that configures the profile - - /// Pointer to the module pass manager the profile will use - llvm::ModulePassManager* module_pass_manager_{nullptr}; - - /// Pointer to the pass builder the profile is based on - llvm::PassBuilder* pass_builder_{nullptr}; - - /// Optimisation level used by LLVM - OptimizationLevel optimisation_level_{OptimizationLevel::O0}; - - /// Whether or not we are in debug mode - bool debug_{false}; - }; - - template void ProfileGenerator::registerProfileComponent(String const& id, SetupFunction setup) + auto setup_wrapper = [setup](ProfileGenerator *ptr, Profile &profile) { + if (ptr->configuration_manager_.isActive()) { - configuration_manager_.addConfig(id); + auto &config = ptr->configuration_manager_.get(); - auto setup_wrapper = [setup](ProfileGenerator* ptr, Profile& profile) { - if (ptr->configuration_manager_.isActive()) - { - auto& config = ptr->configuration_manager_.get(); - - setup(config, ptr, profile); - } - }; - - components_.push_back({id, std::move(setup_wrapper)}); + setup(config, ptr, profile); } + }; + + components_.push_back({id, std::move(setup_wrapper)}); +} -} // namespace quantum -} // namespace microsoft +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Logging/ILogger.hpp b/src/Passes/Source/Logging/ILogger.hpp index ca58198788..738124137d 100644 --- a/src/Passes/Source/Logging/ILogger.hpp +++ b/src/Passes/Source/Logging/ILogger.hpp @@ -2,56 +2,54 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -#include "Types/Types.hpp" +#include "QatTypes/QatTypes.hpp" #include #include -namespace microsoft -{ -namespace quantum -{ +namespace microsoft { +namespace quantum { - /// Logger interface to allow the collection of different types of messages during QIR - /// transformation and/or validation. - class ILogger - { - public: - // Constructors, copy and move operators and destructors - // +/// Logger interface to allow the collection of different types of messages during QIR +/// transformation and/or validation. +class ILogger +{ +public: + // Constructors, copy and move operators and destructors + // - ILogger() = default; - ILogger(ILogger const&) = default; - ILogger(ILogger&&) = default; - ILogger& operator=(ILogger const&) = default; - ILogger& operator=(ILogger&&) = default; + ILogger() = default; + ILogger(ILogger const &) = default; + ILogger(ILogger &&) = default; + ILogger &operator=(ILogger const &) = default; + ILogger &operator=(ILogger &&) = default; - virtual ~ILogger() = default; + virtual ~ILogger() = default; - // Abstract interface methods - // + // Abstract interface methods + // - /// Reports a debug message. - virtual void debug(String const& message) = 0; + /// Reports a debug message. + virtual void debug(String const &message) = 0; - /// Reports an info message. - virtual void info(String const& message) = 0; + /// Reports an info message. + virtual void info(String const &message) = 0; - /// Reports a warning message. - virtual void warning(String const& message) = 0; + /// Reports a warning message. + virtual void warning(String const &message) = 0; - /// Reports an error message. - virtual void error(String const& message) = 0; + /// Reports an error message. + virtual void error(String const &message) = 0; - /// Reports an internal error message. - virtual void internalError(String const& message) = 0; + /// Reports an internal error message. + virtual void internalError(String const &message) = 0; - /// Sets the current location. Importantly, the location can be set independently of the reported - /// messages. This allows one to update the location upon updating the cursor position without - /// having to worry about keeping a copy of the location to pass when reporting messages. - /// The most obvious case of this is file path (name) with a line and character (row, col). - virtual void setLocation(String const& name, uint64_t row, uint64_t col) = 0; - }; + /// Sets the current location. Importantly, the location can be set independently of the reported + /// messages. This allows one to update the location upon updating the cursor position without + /// having to worry about keeping a copy of the location to pass when reporting messages. + /// The most obvious case of this is file path (name) with a line and character (row, col). + virtual void setLocation(String const &name, uint64_t row, uint64_t col) = 0; +}; -} // namespace quantum -} // namespace microsoft +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/ModuleLoader/ModuleLoader.hpp b/src/Passes/Source/ModuleLoader/ModuleLoader.hpp index ef1234765f..e03151c52c 100644 --- a/src/Passes/Source/ModuleLoader/ModuleLoader.hpp +++ b/src/Passes/Source/ModuleLoader/ModuleLoader.hpp @@ -2,132 +2,126 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. +#include "Llvm/Llvm.hpp" +#include "QatTypes/QatTypes.hpp" #include "RemoveDisallowedAttributesPass/RemoveDisallowedAttributesPass.hpp" -#include "Types/Types.hpp" -#include "Llvm/Llvm.hpp" +namespace microsoft { +namespace quantum { -namespace microsoft -{ -namespace quantum +class ModuleLoader { +public: + using Module = llvm::Module; + using Linker = llvm::Linker; + using SMDiagnostic = llvm::SMDiagnostic; + + explicit ModuleLoader(Module *final_module) + : final_module_{final_module} + , linker_{*final_module} + + {} + + bool addModule(std::unique_ptr &&module, String const &filename = "unknown") + { + if (llvm::verifyModule(*module, &llvm::errs())) + { + llvm::errs() << filename << ": " + << "input module is broken!\n"; + return false; + } + + return !linker_.linkInModule(std::move(module), Linker::Flags::None); + } + + bool addIrFile(String const &filename) + { + + // Loading module + SMDiagnostic err; + std::unique_ptr module = llvm::parseIRFile(filename, err, final_module_->getContext()); + if (!module) + { + llvm::errs() << "Failed to load " << filename << "\n"; + return false; + } + + // Transforming module + SingleModuleTransformation transformation; + if (!transformation.apply(module.get())) + { + llvm::errs() << "Failed to transform " << filename << "\n"; + return false; + } + + // Linking + return addModule(std::move(module), filename); + } + +private: + Module *final_module_; + Linker linker_; + + // Single Module Transformation + // + + class SingleModuleTransformation + { + public: + using PassBuilder = llvm::PassBuilder; + using OptimizationLevel = PassBuilder::OptimizationLevel; + using FunctionAnalysisManager = llvm::FunctionAnalysisManager; + + explicit SingleModuleTransformation( + OptimizationLevel const &optimisation_level = OptimizationLevel::O0, bool debug = false) + : loop_analysis_manager_{debug} + , function_analysis_manager_{debug} + , gscc_analysis_manager_{debug} + , module_analysis_manager_{debug} + , optimisation_level_{optimisation_level} + , debug_{debug} + { + + pass_builder_.registerModuleAnalyses(module_analysis_manager_); + pass_builder_.registerCGSCCAnalyses(gscc_analysis_manager_); + pass_builder_.registerFunctionAnalyses(function_analysis_manager_); + pass_builder_.registerLoopAnalyses(loop_analysis_manager_); + + pass_builder_.crossRegisterProxies(loop_analysis_manager_, function_analysis_manager_, + gscc_analysis_manager_, module_analysis_manager_); + + module_pass_manager_.addPass(RemoveDisallowedAttributesPass()); + } + + bool apply(llvm::Module *module) + { + module_pass_manager_.run(*module, module_analysis_manager_); + + if (llvm::verifyModule(*module, &llvm::errs())) + { + return false; + } + + return true; + } - class ModuleLoader + bool isDebugMode() const { - public: - using Module = llvm::Module; - using Linker = llvm::Linker; - using SMDiagnostic = llvm::SMDiagnostic; - - explicit ModuleLoader(Module* final_module) - : final_module_{final_module} - , linker_{*final_module} - - { - } - - bool addModule(std::unique_ptr&& module, String const& filename = "unknown") - { - if (llvm::verifyModule(*module, &llvm::errs())) - { - llvm::errs() << filename << ": " - << "input module is broken!\n"; - return false; - } - - return !linker_.linkInModule(std::move(module), Linker::Flags::None); - } - - bool addIrFile(String const& filename) - { - - // Loading module - SMDiagnostic err; - std::unique_ptr module = llvm::parseIRFile(filename, err, final_module_->getContext()); - if (!module) - { - llvm::errs() << "Failed to load " << filename << "\n"; - return false; - } - - // Transforming module - SingleModuleTransformation transformation; - if (!transformation.apply(module.get())) - { - llvm::errs() << "Failed to transform " << filename << "\n"; - return false; - } - - // Linking - return addModule(std::move(module), filename); - } - - private: - Module* final_module_; - Linker linker_; - - // Single Module Transformation - // - - class SingleModuleTransformation - { - public: - using PassBuilder = llvm::PassBuilder; - using OptimizationLevel = PassBuilder::OptimizationLevel; - using FunctionAnalysisManager = llvm::FunctionAnalysisManager; - - explicit SingleModuleTransformation( - OptimizationLevel const& optimisation_level = OptimizationLevel::O0, - bool debug = false) - : loop_analysis_manager_{debug} - , function_analysis_manager_{debug} - , gscc_analysis_manager_{debug} - , module_analysis_manager_{debug} - , optimisation_level_{optimisation_level} - , debug_{debug} - { - - pass_builder_.registerModuleAnalyses(module_analysis_manager_); - pass_builder_.registerCGSCCAnalyses(gscc_analysis_manager_); - pass_builder_.registerFunctionAnalyses(function_analysis_manager_); - pass_builder_.registerLoopAnalyses(loop_analysis_manager_); - - pass_builder_.crossRegisterProxies( - loop_analysis_manager_, function_analysis_manager_, gscc_analysis_manager_, - module_analysis_manager_); - - module_pass_manager_.addPass(RemoveDisallowedAttributesPass()); - } - - bool apply(llvm::Module* module) - { - module_pass_manager_.run(*module, module_analysis_manager_); - - if (llvm::verifyModule(*module, &llvm::errs())) - { - return false; - } - - return true; - } - - bool isDebugMode() const - { - return debug_; - } - - private: - llvm::PassBuilder pass_builder_; - llvm::LoopAnalysisManager loop_analysis_manager_; - llvm::FunctionAnalysisManager function_analysis_manager_; - llvm::CGSCCAnalysisManager gscc_analysis_manager_; - llvm::ModuleAnalysisManager module_analysis_manager_; - - llvm::ModulePassManager module_pass_manager_{}; - OptimizationLevel optimisation_level_{}; - bool debug_{false}; - }; - }; - -} // namespace quantum -} // namespace microsoft + return debug_; + } + + private: + llvm::PassBuilder pass_builder_; + llvm::LoopAnalysisManager loop_analysis_manager_; + llvm::FunctionAnalysisManager function_analysis_manager_; + llvm::CGSCCAnalysisManager gscc_analysis_manager_; + llvm::ModuleAnalysisManager module_analysis_manager_; + + llvm::ModulePassManager module_pass_manager_{}; + OptimizationLevel optimisation_level_{}; + bool debug_{false}; + }; +}; + +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Profile/Profile.hpp b/src/Passes/Source/Profile/Profile.hpp index 70e560b6cb..6d27e0f57d 100644 --- a/src/Passes/Source/Profile/Profile.hpp +++ b/src/Passes/Source/Profile/Profile.hpp @@ -4,161 +4,156 @@ #include "AllocationManager/AllocationManager.hpp" #include "AllocationManager/IAllocationManager.hpp" -#include "Types/Types.hpp" -#include "Validator/Validator.hpp" - #include "Llvm/Llvm.hpp" +#include "QatTypes/QatTypes.hpp" +#include "Validator/Validator.hpp" -namespace microsoft -{ -namespace quantum -{ - - class ProfileGenerator; - - /// Profile class that defines a set of rules which constitutes the profile definition. Each of the - /// rules can be used to transform a generic QIR and/or validate that the QIR is compliant with said - /// rule. - class Profile - { - public: - /// Allocation manager pointer type. Used to reference to concrete allocation manager - /// implementations which defines the allocation logic of the profile. - using AllocationManagerPtr = IAllocationManager::AllocationManagerPtr; - - /// Validator class used to check that an IR fulfils a given specification - using ValidatorPtr = Validator::ValidatorPtr; - - // Constructors - // - - explicit Profile( - String const& name, - bool debug, - llvm::TargetMachine* target_machine = nullptr, - AllocationManagerPtr qubit_allocation_manager = BasicAllocationManager::createNew(), - AllocationManagerPtr result_allocation_manager = BasicAllocationManager::createNew()); - - // Default construction not allowed as this leads to invalid configuration of the allocation - // managers. - - Profile() = delete; - Profile(Profile const&) = delete; - Profile(Profile&&) = default; - Profile& operator=(Profile const&) = delete; - Profile& operator=(Profile&&) = default; - ~Profile() = default; - - // Profile methods - // - - /// Applies the profile to a module. - void apply(llvm::Module& module); - - /// Verifies that a module is a valid LLVM IR. - bool verify(llvm::Module& module); - - /// Validates that a module complies with the specified QIR profile. - bool validate(llvm::Module& module); - - AllocationManagerPtr getQubitAllocationManager(); - AllocationManagerPtr getResultAllocationManager(); +namespace microsoft { +namespace quantum { - String const& name() const; +class ProfileGenerator; - protected: - // Ensuring that ProfileGenerator has access to following protected functions. - friend class ProfileGenerator; +/// Profile class that defines a set of rules which constitutes the profile definition. Each of the +/// rules can be used to transform a generic QIR and/or validate that the QIR is compliant with said +/// rule. +class Profile +{ +public: + /// Allocation manager pointer type. Used to reference to concrete allocation manager + /// implementations which defines the allocation logic of the profile. + using AllocationManagerPtr = IAllocationManager::AllocationManagerPtr; - /// Sets the module pass manager used for the transformation of the IR. - void setModulePassManager(llvm::ModulePassManager&& manager); + /// Validator class used to check that an IR fulfils a given specification + using ValidatorPtr = Validator::ValidatorPtr; - /// Sets the validator - void setValidator(ValidatorPtr&& validator); + // Constructors + // - /// Returns a reference to the pass builder. - llvm::PassBuilder& passBuilder(); + explicit Profile( + String const &name, bool debug, llvm::TargetMachine *target_machine = nullptr, + AllocationManagerPtr qubit_allocation_manager = BasicAllocationManager::createNew(), + AllocationManagerPtr result_allocation_manager = BasicAllocationManager::createNew()); - /// Returns a reference to the loop analysis manager. - llvm::LoopAnalysisManager& loopAnalysisManager(); + // Default construction not allowed as this leads to invalid configuration of the allocation + // managers. - /// Returns a reference to the function analysis manager. - llvm::FunctionAnalysisManager& functionAnalysisManager(); + Profile() = delete; + Profile(Profile const &) = delete; + Profile(Profile &&) = default; + Profile &operator=(Profile const &) = delete; + Profile &operator=(Profile &&) = default; + ~Profile() = default; - /// Returns a reference to the GSCC analysis manager. - llvm::CGSCCAnalysisManager& gsccAnalysisManager(); + // Profile methods + // - /// Returns a reference to the module analysis manager. - llvm::ModuleAnalysisManager& moduleAnalysisManager(); + /// Applies the profile to a module. + void apply(llvm::Module &module); - private: - using PassInstrumentationCallbacksPtr = std::unique_ptr; - using StandardInstrumentationsPtr = std::unique_ptr; - using PassBuilderPtr = std::unique_ptr; + /// Verifies that a module is a valid LLVM IR. + bool verify(llvm::Module &module); - void registerEPCallbacks(bool verify_each_pass, bool debug); + /// Validates that a module complies with the specified QIR profile. + bool validate(llvm::Module &module); - template - bool tryParsePipelineText(llvm::PassBuilder& pass_builder, std::string const& pipeline_options) - { - if (pipeline_options.empty()) - { - return false; - } + AllocationManagerPtr getQubitAllocationManager(); + AllocationManagerPtr getResultAllocationManager(); - PassManager pass_manager; - if (auto err = pass_builder.parsePassPipeline(pass_manager, pipeline_options)) - { - llvm::errs() << "Could not parse -" << pipeline_options << " pipeline: " << toString(std::move(err)) - << "\n"; - return false; - } - return true; - } + String const &name() const; - /// Name of the selected profile - String name_{}; +protected: + // Ensuring that ProfileGenerator has access to following protected functions. + friend class ProfileGenerator; - // LLVM logic to run the passes - // + /// Sets the module pass manager used for the transformation of the IR. + void setModulePassManager(llvm::ModulePassManager &&manager); - llvm::LoopAnalysisManager loop_analysis_manager_; - llvm::FunctionAnalysisManager function_analysis_manager_; - llvm::CGSCCAnalysisManager gscc_analysis_manager_; - llvm::ModuleAnalysisManager module_analysis_manager_; + /// Sets the validator + void setValidator(ValidatorPtr &&validator); - llvm::Optional pgo_options_; - PassInstrumentationCallbacksPtr pass_instrumentation_callbacks_; - StandardInstrumentationsPtr standard_instrumentations_; - llvm::PipelineTuningOptions pipeline_tuning_options_; + /// Returns a reference to the pass builder. + llvm::PassBuilder &passBuilder(); - PassBuilderPtr pass_builder_; + /// Returns a reference to the loop analysis manager. + llvm::LoopAnalysisManager &loopAnalysisManager(); - llvm::ModulePassManager module_pass_manager_{}; + /// Returns a reference to the function analysis manager. + llvm::FunctionAnalysisManager &functionAnalysisManager(); - // Allocation management - // + /// Returns a reference to the GSCC analysis manager. + llvm::CGSCCAnalysisManager &gsccAnalysisManager(); - /// Interface pointer to the qubit allocation manager. Mode of operation depends on the concrete - /// implementation of the manager which is swappable through the interface. - AllocationManagerPtr qubit_allocation_manager_{}; + /// Returns a reference to the module analysis manager. + llvm::ModuleAnalysisManager &moduleAnalysisManager(); - /// Interface pointer to the results allocation manager. Again here the manager behaviour is - /// determined by its implementation details. - AllocationManagerPtr result_allocation_manager_{}; +private: + using PassInstrumentationCallbacksPtr = std::unique_ptr; + using StandardInstrumentationsPtr = std::unique_ptr; + using PassBuilderPtr = std::unique_ptr; - /// - ValidatorPtr validator_{}; + void registerEPCallbacks(bool verify_each_pass, bool debug); - std::string peephole_ep_pipeline_{""}; - std::string late_loop_optimizations_ep_pipeline_{""}; - std::string loop_optimizer_end_ep_pipeline_{""}; - std::string scalar_optimizer_late_ep_pipeline_{""}; - std::string cgscc_optimizer_late_ep_pipeline_{""}; - std::string vectorizer_start_ep_pipeline_{""}; - std::string pipeline_start_ep_pipeline_{""}; - std::string optimizer_last_ep_pipeline_{""}; - }; + template + bool tryParsePipelineText(llvm::PassBuilder &pass_builder, std::string const &pipeline_options) + { + if (pipeline_options.empty()) + { + return false; + } -} // namespace quantum -} // namespace microsoft + PassManager pass_manager; + if (auto err = pass_builder.parsePassPipeline(pass_manager, pipeline_options)) + { + llvm::errs() << "Could not parse -" << pipeline_options + << " pipeline: " << toString(std::move(err)) << "\n"; + return false; + } + return true; + } + + /// Name of the selected profile + String name_{}; + + // LLVM logic to run the passes + // + + llvm::LoopAnalysisManager loop_analysis_manager_; + llvm::FunctionAnalysisManager function_analysis_manager_; + llvm::CGSCCAnalysisManager gscc_analysis_manager_; + llvm::ModuleAnalysisManager module_analysis_manager_; + + llvm::Optional pgo_options_; + PassInstrumentationCallbacksPtr pass_instrumentation_callbacks_; + StandardInstrumentationsPtr standard_instrumentations_; + llvm::PipelineTuningOptions pipeline_tuning_options_; + + PassBuilderPtr pass_builder_; + + llvm::ModulePassManager module_pass_manager_{}; + + // Allocation management + // + + /// Interface pointer to the qubit allocation manager. Mode of operation depends on the concrete + /// implementation of the manager which is swappable through the interface. + AllocationManagerPtr qubit_allocation_manager_{}; + + /// Interface pointer to the results allocation manager. Again here the manager behaviour is + /// determined by its implementation details. + AllocationManagerPtr result_allocation_manager_{}; + + /// + ValidatorPtr validator_{}; + + std::string peephole_ep_pipeline_{""}; + std::string late_loop_optimizations_ep_pipeline_{""}; + std::string loop_optimizer_end_ep_pipeline_{""}; + std::string scalar_optimizer_late_ep_pipeline_{""}; + std::string cgscc_optimizer_late_ep_pipeline_{""}; + std::string vectorizer_start_ep_pipeline_{""}; + std::string pipeline_start_ep_pipeline_{""}; + std::string optimizer_last_ep_pipeline_{""}; +}; + +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Types/Types.hpp b/src/Passes/Source/QatTypes/QatTypes.hpp similarity index 100% rename from src/Passes/Source/Types/Types.hpp rename to src/Passes/Source/QatTypes/QatTypes.hpp diff --git a/src/Passes/Source/RemoveDisallowedAttributesPass/RemoveDisallowedAttributesPass.hpp b/src/Passes/Source/RemoveDisallowedAttributesPass/RemoveDisallowedAttributesPass.hpp index 08ea43b6b3..06fe678804 100644 --- a/src/Passes/Source/RemoveDisallowedAttributesPass/RemoveDisallowedAttributesPass.hpp +++ b/src/Passes/Source/RemoveDisallowedAttributesPass/RemoveDisallowedAttributesPass.hpp @@ -2,68 +2,64 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -#include "Types/Types.hpp" - #include "Llvm/Llvm.hpp" +#include "QatTypes/QatTypes.hpp" #include #include #include -namespace microsoft -{ -namespace quantum +namespace microsoft { +namespace quantum { + +class RemoveDisallowedAttributesPass : public llvm::PassInfoMixin { +public: + RemoveDisallowedAttributesPass() + : allowed_attrs_{{static_cast("EntryPoint"), static_cast("InteropFriendly")}} + {} - class RemoveDisallowedAttributesPass : public llvm::PassInfoMixin + llvm::PreservedAnalyses run(llvm::Module &module, llvm::ModuleAnalysisManager & /*mam*/) + { + for (auto &fnc : module) { - public: - RemoveDisallowedAttributesPass() - : allowed_attrs_{{static_cast("EntryPoint"), static_cast("InteropFriendly")}} - { - } + std::unordered_set to_keep; - llvm::PreservedAnalyses run(llvm::Module& module, llvm::ModuleAnalysisManager& /*mam*/) + // Finding all valid attributes + for (auto &attrset : fnc.getAttributes()) + { + for (auto &attr : attrset) { - for (auto& fnc : module) - { - std::unordered_set to_keep; - - // Finding all valid attributes - for (auto& attrset : fnc.getAttributes()) - { - for (auto& attr : attrset) - { - auto r = static_cast(attr.getAsString()); + auto r = static_cast(attr.getAsString()); - // Stripping quotes - if (r.size() >= 2 && r[0] == '"' && r[r.size() - 1] == '"') - { - r = r.substr(1, r.size() - 2); - } + // Stripping quotes + if (r.size() >= 2 && r[0] == '"' && r[r.size() - 1] == '"') + { + r = r.substr(1, r.size() - 2); + } - // Inserting if allowed - if (allowed_attrs_.find(r) != allowed_attrs_.end()) - { - to_keep.insert(r); - } - } - } + // Inserting if allowed + if (allowed_attrs_.find(r) != allowed_attrs_.end()) + { + to_keep.insert(r); + } + } + } - // Deleting every - fnc.setAttributes({}); - for (auto& attr : to_keep) - { - fnc.addFnAttr(attr); - } - } + // Deleting every + fnc.setAttributes({}); + for (auto &attr : to_keep) + { + fnc.addFnAttr(attr); + } + } - return llvm::PreservedAnalyses::none(); - } + return llvm::PreservedAnalyses::none(); + } - private: - std::unordered_set allowed_attrs_; - }; +private: + std::unordered_set allowed_attrs_; +}; -} // namespace quantum -} // namespace microsoft +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Rules/Factory.hpp b/src/Passes/Source/Rules/Factory.hpp index c8254569ce..426b92518d 100644 --- a/src/Passes/Source/Rules/Factory.hpp +++ b/src/Passes/Source/Rules/Factory.hpp @@ -4,197 +4,192 @@ #include "AllocationManager/AllocationManager.hpp" #include "Commandline/ConfigurationManager.hpp" +#include "Llvm/Llvm.hpp" +#include "QatTypes/QatTypes.hpp" #include "Rules/FactoryConfig.hpp" #include "Rules/ReplacementRule.hpp" #include "Rules/RuleSet.hpp" -#include "Types/Types.hpp" - -#include "Llvm/Llvm.hpp" #include -namespace microsoft -{ -namespace quantum -{ +namespace microsoft { +namespace quantum { - /// Rule factory provides a high-level methods to build a rule set that - /// enforces certain aspects of QIR transformation. - class RuleFactory - { - public: - /// ReplacementRule pointer type used for the construction of replacement rules - using ReplacementRulePtr = std::shared_ptr; - - /// Allocation manager pointer used to hold allocation managers - using AllocationManagerPtr = IAllocationManager::AllocationManagerPtr; - - // Constructor configuration. Explicit construction with - // rule set to be configured, which can be moved using move - // semantics. No copy allowed. - // - - RuleFactory( - RuleSet& rule_set, - AllocationManagerPtr qubit_alloc_manager, - AllocationManagerPtr result_alloc_manager); - RuleFactory() = delete; - RuleFactory(RuleFactory const&) = delete; - RuleFactory(RuleFactory&&) = default; - ~RuleFactory() = default; - - // - // - - /// This takes a FactoryConfiguration as argument and enable rules accordingly. - void usingConfiguration(FactoryConfiguration const& config); - - // Generic rules - // - - /// Removes all calls to functions with a specified name. - /// This function matches on name alone and ignores function - /// arguments. - void removeFunctionCall(String const& name); - - // Conventions - // - - /// Static qubit array allocation identifies allocations, array access and releases. Each of these - /// are replaced with static values. Patterns recognised include - /// - /// ``` - /// %array = call %Array* @__quantum__rt__qubit_allocate_array(i64 10) - /// ``` - /// - /// which is replaced by a constant pointer - /// - /// ``` - /// %array = inttoptr i64 0 to %Array* - /// ``` - /// - /// The array allocation is managed through the qubit allocation manager. Access to qubit arrays - /// - /// ``` - /// %0 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %array, i64 7) - /// %1 = bitcast i8* %0 to %Qubit** - /// %qubit = load %Qubit*, %Qubit** %1, align 8 - /// ``` - /// - /// is replaced by off-setting the array value by 7 to get - /// - /// ``` - /// %qubit = inttoptr i64 7 to %Qubit* - /// ``` - /// - /// Finally, release is recognised and the allocation manager is invoked accordingly. - void useStaticQubitArrayAllocation(); - - /// Static qubit allocation identifies allocation and release of single qubits. It uses the qubit - /// allocation manager to track allocation and releases of qubits. It translates - /// - /// ``` - /// %qubit1 = call %Qubit* @__quantum__rt__qubit_allocate() - /// %qubit2 = call %Qubit* @__quantum__rt__qubit_allocate() - /// %qubit3 = call %Qubit* @__quantum__rt__qubit_allocate() - /// %qubit4 = call %Qubit* @__quantum__rt__qubit_allocate() - /// %qubit5 = call %Qubit* @__quantum__rt__qubit_allocate() - /// ``` - /// - /// to - /// - /// ``` - /// %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* - /// ``` - /// if the BasicAllocationManager is used. - void useStaticQubitAllocation(); - - /// Static allocation of results. This feature is similar to `useStaticQubitAllocation` but uses - /// the result allocation manager. - void useStaticResultAllocation(); - - void resolveConstantArraySizes(); - - void inlineCallables(); - - // Optimisations - // - - /// Replaces branching of quantum results compared to one. This is a relatively advanced pattern, - /// intended for base profile-like constructs where - /// - /// ``` - /// %1 = tail call %Result* @__quantum__rt__result_get_one() - /// %2 = tail call i1 @__quantum__rt__result_equal(%Result* %0, %Result* %1) - /// br i1 %2, label %then0__1, label %continue__1 - /// ``` - /// - /// is mapped into - /// - /// ``` - /// %1 = call i1 @__quantum__qis__read_result__body(%Result* %0) - /// br i1 %1, label %then0__1, label %continue__1 - /// ``` - /// - /// which removes the need for constant one. - void optimiseResultOne(); - - /// Replaces branching of quantum results compared to zero. This method is not implemented yet. - void optimiseResultZero(); - - // Disabling by feature - // - - /// This method disables reference counting for arrays, strings and results. It does so by simply - /// removing the instructions and the resulting code is expected to be executed either on a stack - /// VM or with shared pointer logic. - void disableReferenceCounting(); - - /// This method disables alias counting for arrays, strings and results. - void disableAliasCounting(); - - /// Removes string support by removing string related instructions. At the moment these include - /// `__quantum__rt__string_create`, - /// `__quantum__rt__string_update_reference_count`, `__quantum__rt__string_update_alias_count` and - /// `__quantum__rt__message`. - void disableStringSupport(); - - // Configuration - // - - /// Sets the integer width used when it cannot be deducted from the context of the transformation. - void setDefaultIntegerWidth(uint32_t v); - - private: - /// Helper function that moves a replacement rule into a shared pointer, adds it to the rule set - /// and returns a copy of it. - ReplacementRulePtr addRule(ReplacementRule&& rule); - - // Affected artefacts - // - - RuleSet& rule_set_; ///< The rule set we are building - - // Allocation managers. - // - - /// Qubit allocation manager which is used in the case of static qubit allocation. - AllocationManagerPtr qubit_alloc_manager_{nullptr}; - - /// Result allocation manager which is used in the case of static results allocation. - AllocationManagerPtr result_alloc_manager_{nullptr}; - - /// Configuration - // - - /// The default integer width. This value is used whenever the width within the context cannot be - /// inferred. - uint32_t default_integer_width_{64}; - }; - -} // namespace quantum -} // namespace microsoft +/// Rule factory provides a high-level methods to build a rule set that +/// enforces certain aspects of QIR transformation. +class RuleFactory +{ +public: + /// ReplacementRule pointer type used for the construction of replacement rules + using ReplacementRulePtr = std::shared_ptr; + + /// Allocation manager pointer used to hold allocation managers + using AllocationManagerPtr = IAllocationManager::AllocationManagerPtr; + + // Constructor configuration. Explicit construction with + // rule set to be configured, which can be moved using move + // semantics. No copy allowed. + // + + RuleFactory(RuleSet &rule_set, AllocationManagerPtr qubit_alloc_manager, + AllocationManagerPtr result_alloc_manager); + RuleFactory() = delete; + RuleFactory(RuleFactory const &) = delete; + RuleFactory(RuleFactory &&) = default; + ~RuleFactory() = default; + + // + // + + /// This takes a FactoryConfiguration as argument and enable rules accordingly. + void usingConfiguration(FactoryConfiguration const &config); + + // Generic rules + // + + /// Removes all calls to functions with a specified name. + /// This function matches on name alone and ignores function + /// arguments. + void removeFunctionCall(String const &name); + + // Conventions + // + + /// Static qubit array allocation identifies allocations, array access and releases. Each of these + /// are replaced with static values. Patterns recognised include + /// + /// ``` + /// %array = call %Array* @__quantum__rt__qubit_allocate_array(i64 10) + /// ``` + /// + /// which is replaced by a constant pointer + /// + /// ``` + /// %array = inttoptr i64 0 to %Array* + /// ``` + /// + /// The array allocation is managed through the qubit allocation manager. Access to qubit arrays + /// + /// ``` + /// %0 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %array, i64 7) + /// %1 = bitcast i8* %0 to %Qubit** + /// %qubit = load %Qubit*, %Qubit** %1, align 8 + /// ``` + /// + /// is replaced by off-setting the array value by 7 to get + /// + /// ``` + /// %qubit = inttoptr i64 7 to %Qubit* + /// ``` + /// + /// Finally, release is recognised and the allocation manager is invoked accordingly. + void useStaticQubitArrayAllocation(); + + /// Static qubit allocation identifies allocation and release of single qubits. It uses the qubit + /// allocation manager to track allocation and releases of qubits. It translates + /// + /// ``` + /// %qubit1 = call %Qubit* @__quantum__rt__qubit_allocate() + /// %qubit2 = call %Qubit* @__quantum__rt__qubit_allocate() + /// %qubit3 = call %Qubit* @__quantum__rt__qubit_allocate() + /// %qubit4 = call %Qubit* @__quantum__rt__qubit_allocate() + /// %qubit5 = call %Qubit* @__quantum__rt__qubit_allocate() + /// ``` + /// + /// to + /// + /// ``` + /// %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* + /// ``` + /// if the BasicAllocationManager is used. + void useStaticQubitAllocation(); + + /// Static allocation of results. This feature is similar to `useStaticQubitAllocation` but uses + /// the result allocation manager. + void useStaticResultAllocation(); + + void resolveConstantArraySizes(); + + void inlineCallables(); + + // Optimisations + // + + /// Replaces branching of quantum results compared to one. This is a relatively advanced pattern, + /// intended for base profile-like constructs where + /// + /// ``` + /// %1 = tail call %Result* @__quantum__rt__result_get_one() + /// %2 = tail call i1 @__quantum__rt__result_equal(%Result* %0, %Result* %1) + /// br i1 %2, label %then0__1, label %continue__1 + /// ``` + /// + /// is mapped into + /// + /// ``` + /// %1 = call i1 @__quantum__qis__read_result__body(%Result* %0) + /// br i1 %1, label %then0__1, label %continue__1 + /// ``` + /// + /// which removes the need for constant one. + void optimiseResultOne(); + + /// Replaces branching of quantum results compared to zero. This method is not implemented yet. + void optimiseResultZero(); + + // Disabling by feature + // + + /// This method disables reference counting for arrays, strings and results. It does so by simply + /// removing the instructions and the resulting code is expected to be executed either on a stack + /// VM or with shared pointer logic. + void disableReferenceCounting(); + + /// This method disables alias counting for arrays, strings and results. + void disableAliasCounting(); + + /// Removes string support by removing string related instructions. At the moment these include + /// `__quantum__rt__string_create`, + /// `__quantum__rt__string_update_reference_count`, `__quantum__rt__string_update_alias_count` and + /// `__quantum__rt__message`. + void disableStringSupport(); + + // Configuration + // + + /// Sets the integer width used when it cannot be deducted from the context of the transformation. + void setDefaultIntegerWidth(uint32_t v); + +private: + /// Helper function that moves a replacement rule into a shared pointer, adds it to the rule set + /// and returns a copy of it. + ReplacementRulePtr addRule(ReplacementRule &&rule); + + // Affected artefacts + // + + RuleSet &rule_set_; ///< The rule set we are building + + // Allocation managers. + // + + /// Qubit allocation manager which is used in the case of static qubit allocation. + AllocationManagerPtr qubit_alloc_manager_{nullptr}; + + /// Result allocation manager which is used in the case of static results allocation. + AllocationManagerPtr result_alloc_manager_{nullptr}; + + /// Configuration + // + + /// The default integer width. This value is used whenever the width within the context cannot be + /// inferred. + uint32_t default_integer_width_{64}; +}; + +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/TransformationRulesPass/TransformationRulesPass.hpp b/src/Passes/Source/TransformationRulesPass/TransformationRulesPass.hpp index e9e49395ea..2a964fc9b4 100644 --- a/src/Passes/Source/TransformationRulesPass/TransformationRulesPass.hpp +++ b/src/Passes/Source/TransformationRulesPass/TransformationRulesPass.hpp @@ -2,232 +2,228 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. +#include "Llvm/Llvm.hpp" #include "Logging/ILogger.hpp" #include "Profile/Profile.hpp" +#include "QatTypes/QatTypes.hpp" #include "Rules/RuleSet.hpp" #include "TransformationRulesPass/TransformationRulesPassConfiguration.hpp" -#include "Types/Types.hpp" - -#include "Llvm/Llvm.hpp" #include #include #include -namespace microsoft -{ -namespace quantum +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 │◀─┘ +/// └───────────────────────────────┘ +/// +/// Copying and expanding functions identifies function calls and identifies compile time constants +/// passed to the function. It then copies the full implementation of the function, replacing all +/// compile-time constants (and hence changing the function signature). That is, if a function call +/// `f(x, 9)` is identified, it is replaced with `f.1(x)` where `f.1` is a copy of `f` with second +/// argument written into the function. +/// +class TransformationRulesPass : 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 = IAllocationManager::AllocationManagerPtr; + using Captures = RuleSet::Captures; + using ConstantArguments = std::unordered_map; + using ILoggerPtr = std::shared_ptr; + + // Construction and destruction configuration. + // + + /// Custom default constructor + TransformationRulesPass(RuleSet &&rule_set, TransformationRulesPassConfiguration const &config, + Profile *profile); + + /// Copy construction is banned. + TransformationRulesPass(TransformationRulesPass const &) = delete; + + /// We allow move semantics. + TransformationRulesPass(TransformationRulesPass &&) = default; + + /// Default destruction. + ~TransformationRulesPass() = default; + + // Operators + // + + /// Copy assignment is banned. + TransformationRulesPass &operator=(TransformationRulesPass const &) = delete; + + /// Move assignment is permitted. + TransformationRulesPass &operator=(TransformationRulesPass &&) = 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 functions + // + + /// Generic function to apply a instructionModifier (lambda function) to every instruction in the + /// function `function`. This method follows the execution path to the extend possible and deals + /// with branching if the branch statement can be evaluated at compile time. + bool runOnFunction(llvm::Function &function, InstructionModifier const &modifier); + + /// Applies each of the replacements in the `replacements_` variable. + void processReplacements(); + + // Copy and expand + // + + /// Configuration function for copy and expand to setup the necessary rules. + void setupCopyAndExpand(); + + /// Main function for running the copy and expand functionality. This function first identifies + /// the entry point and then follows every execution path to copy the callee function for every + /// call instruction encountered. This makes that every call in the code has its own unique callee + /// function which ensures that when allocating qubits or results, the assigned registers are not + /// accidentally reused. + void runCopyAndExpand(llvm::Module &module, llvm::ModuleAnalysisManager &mam); + + /// Test whether the instruction is a call instruction and copy the callee in case it is. This + /// function collects instructions which are scheduled for deletion at a later point. + llvm::Value *copyAndExpand(llvm::Value *input, DeletableInstructions &); + + /// Copies the function body and replace function arguments whenever arguments are constant. + llvm::Function *expandFunctionCall(llvm::Function & callee, + ConstantArguments const &const_args = {}); + + /// Folds all constant expression in function. + void constantFoldFunction(llvm::Function &callee); + + /// Helper function to create replacements for constant expressions. + void addConstExprRule(ReplacementRule &&rule); - /// 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 │◀─┘ - /// └───────────────────────────────┘ - /// - /// Copying and expanding functions identifies function calls and identifies compile time constants - /// passed to the function. It then copies the full implementation of the function, replacing all - /// compile-time constants (and hence changing the function signature). That is, if a function call - /// `f(x, 9)` is identified, it is replaced with `f.1(x)` where `f.1` is a copy of `f` with second - /// argument written into the function. - /// - class TransformationRulesPass : 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 = IAllocationManager::AllocationManagerPtr; - using Captures = RuleSet::Captures; - using ConstantArguments = std::unordered_map; - using ILoggerPtr = std::shared_ptr; - - // Construction and destruction configuration. - // - - /// Custom default constructor - TransformationRulesPass( - RuleSet&& rule_set, - TransformationRulesPassConfiguration const& config, - Profile* profile); - - /// Copy construction is banned. - TransformationRulesPass(TransformationRulesPass const&) = delete; - - /// We allow move semantics. - TransformationRulesPass(TransformationRulesPass&&) = default; - - /// Default destruction. - ~TransformationRulesPass() = default; - - // Operators - // - - /// Copy assignment is banned. - TransformationRulesPass& operator=(TransformationRulesPass const&) = delete; - - /// Move assignment is permitted. - TransformationRulesPass& operator=(TransformationRulesPass&&) = 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 functions - // - - /// Generic function to apply a instructionModifier (lambda function) to every instruction in the - /// function `function`. This method follows the execution path to the extend possible and deals - /// with branching if the branch statement can be evaluated at compile time. - bool runOnFunction(llvm::Function& function, InstructionModifier const& modifier); - - /// Applies each of the replacements in the `replacements_` variable. - void processReplacements(); - - // Copy and expand - // - - /// Configuration function for copy and expand to setup the necessary rules. - void setupCopyAndExpand(); - - /// Main function for running the copy and expand functionality. This function first identifies - /// the entry point and then follows every execution path to copy the callee function for every - /// call instruction encountered. This makes that every call in the code has its own unique callee - /// function which ensures that when allocating qubits or results, the assigned registers are not - /// accidentally reused. - void runCopyAndExpand(llvm::Module& module, llvm::ModuleAnalysisManager& mam); - - /// Test whether the instruction is a call instruction and copy the callee in case it is. This - /// function collects instructions which are scheduled for deletion at a later point. - llvm::Value* copyAndExpand(llvm::Value* input, DeletableInstructions&); - - /// Copies the function body and replace function arguments whenever arguments are constant. - llvm::Function* expandFunctionCall(llvm::Function& callee, ConstantArguments const& const_args = {}); - - /// Folds all constant expression in function. - void constantFoldFunction(llvm::Function& callee); - - /// Helper function to create replacements for constant expressions. - void addConstExprRule(ReplacementRule&& rule); - - // 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; + // 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 followUsers(llvm::Value* value); + void followUsers(llvm::Value *value); - // Phi replacement - // + // Phi replacement + // - /// Function which replaces phi nodes which refer to inactive blocks. That is, in cases where - /// branch statement evaluates at compile time, only one block will be marked as active. For those - /// case we can eliminate the phi nodes. In the case where branch statements cannot be evaluated - /// all are marked as active. In this case, phi nodes are left unchanged. - void runReplacePhi(llvm::Module& module, llvm::ModuleAnalysisManager& mam); + /// Function which replaces phi nodes which refer to inactive blocks. That is, in cases where + /// branch statement evaluates at compile time, only one block will be marked as active. For those + /// case we can eliminate the phi nodes. In the case where branch statements cannot be evaluated + /// all are marked as active. In this case, phi nodes are left unchanged. + void runReplacePhi(llvm::Module &module, llvm::ModuleAnalysisManager &mam); - // Rules - // + // Rules + // - void runApplyRules(llvm::Module& module, llvm::ModuleAnalysisManager& mam); - bool onQubitRelease(llvm::Instruction* instruction, Captures& captures); - bool onQubitAllocate(llvm::Instruction* instruction, Captures& captures); + 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(); + /// Whether or not this pass is required to run. + static bool isRequired(); - // Logger - // - void setLogger(ILoggerPtr logger); + // Logger + // + void setLogger(ILoggerPtr logger); - private: - // Pass configuration - // +private: + // Pass configuration + // - /// Rule set which describes a set of transformations to apply to the QIR. - RuleSet rule_set_{}; + /// Rule set which describes a set of transformations to apply to the QIR. + RuleSet rule_set_{}; - /// Configuration with enabled or disabled features, recursion limits etc. - TransformationRulesPassConfiguration config_{}; + /// Configuration with enabled or disabled features, recursion limits etc. + TransformationRulesPassConfiguration config_{}; - // Logging and data collection - // + // Logging and data collection + // - /// Logger which is used to collect information, debug info, warnings, errors and internal errors. - ILoggerPtr logger_{nullptr}; + /// Logger which is used to collect information, debug info, warnings, errors and internal errors. + ILoggerPtr logger_{nullptr}; - // Execution path unrolling - // + // Execution path unrolling + // - /// Current recursion depth which is used to prevent unbound (at compile time) recursion. - uint64_t depth_{0}; + /// Current recursion depth which is used to prevent unbound (at compile time) recursion. + uint64_t depth_{0}; - // Copy and expand - // + // Copy and expand + // - /// Rule set which is used to collapse compile-time constant expressions. - RuleSet const_expr_replacements_{}; + /// Rule set which is used to collapse compile-time constant expressions. + RuleSet const_expr_replacements_{}; - // Dead code elimination - // + // Dead code elimination + // - /// Set to track active Values in the code. - std::unordered_set active_pieces_{}; + /// Set to track active Values in the code. + std::unordered_set active_pieces_{}; - /// Vector with block pointers to delete - std::vector blocks_to_delete_{}; + /// Vector with block pointers to delete + std::vector blocks_to_delete_{}; - /// Vector of function pointers to delete - std::vector functions_to_delete_{}; + /// Vector of function pointers to delete + std::vector functions_to_delete_{}; - // Phi detection - // + // Phi detection + // - /// Registered replacements to be executed. - Replacements replacements_; + /// Registered replacements to be executed. + Replacements replacements_; - // Profile - // + // Profile + // - /// Pointer to the current profile. This pointer is used to annotate top level functions with - /// regards to how many qubits they require. TODO(tfr): Consider moving into its own component. - Profile* profile_{nullptr}; - }; + /// Pointer to the current profile. This pointer is used to annotate top level functions with + /// regards to how many qubits they require. TODO(tfr): Consider moving into its own component. + Profile *profile_{nullptr}; +}; -} // namespace quantum -} // namespace microsoft +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/ValidationPass/ValidationPass.hpp b/src/Passes/Source/ValidationPass/ValidationPass.hpp index ee46bab4ae..9e1b96d2a4 100644 --- a/src/Passes/Source/ValidationPass/ValidationPass.hpp +++ b/src/Passes/Source/ValidationPass/ValidationPass.hpp @@ -2,56 +2,52 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. +#include "Llvm/Llvm.hpp" #include "Logging/ILogger.hpp" #include "Profile/Profile.hpp" -#include "Types/Types.hpp" +#include "QatTypes/QatTypes.hpp" #include "ValidationPass/ValidationPassConfiguration.hpp" -#include "Llvm/Llvm.hpp" - #include #include #include -namespace microsoft -{ -namespace quantum -{ +namespace microsoft { +namespace quantum { - class ValidationPass : public llvm::PassInfoMixin - { - public: - using Instruction = llvm::Instruction; - using Value = llvm::Value; +class ValidationPass : public llvm::PassInfoMixin +{ +public: + using Instruction = llvm::Instruction; + using Value = llvm::Value; - // Construction and destruction configuration. - // + // Construction and destruction configuration. + // - explicit ValidationPass(ValidationPassConfiguration const& cfg) - : config_{cfg} - { - } + explicit ValidationPass(ValidationPassConfiguration const &cfg) + : config_{cfg} + {} - /// Copy construction is banned. - ValidationPass(ValidationPass const&) = delete; + /// Copy construction is banned. + ValidationPass(ValidationPass const &) = delete; - /// We allow move semantics. - ValidationPass(ValidationPass&&) = default; + /// We allow move semantics. + ValidationPass(ValidationPass &&) = default; - /// Default destruction. - ~ValidationPass() = default; + /// Default destruction. + ~ValidationPass() = default; - llvm::PreservedAnalyses run(llvm::Module& module, llvm::ModuleAnalysisManager& mam); - /// Whether or not this pass is required to run. - static bool isRequired(); + llvm::PreservedAnalyses run(llvm::Module &module, llvm::ModuleAnalysisManager &mam); + /// Whether or not this pass is required to run. + static bool isRequired(); - private: - ValidationPassConfiguration config_{}; +private: + ValidationPassConfiguration config_{}; - std::unordered_map opcodes_; - std::unordered_map external_calls_; - std::unordered_map internal_calls_; - }; + std::unordered_map opcodes_; + std::unordered_map external_calls_; + std::unordered_map internal_calls_; +}; -} // namespace quantum -} // namespace microsoft +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/ValidationPass/ValidationPassConfiguration.hpp b/src/Passes/Source/ValidationPass/ValidationPassConfiguration.hpp index e619619b3b..1ba035d892 100644 --- a/src/Passes/Source/ValidationPass/ValidationPassConfiguration.hpp +++ b/src/Passes/Source/ValidationPass/ValidationPassConfiguration.hpp @@ -3,91 +3,89 @@ // Licensed under the MIT License. #include "Commandline/ConfigurationManager.hpp" -#include "Types/Types.hpp" +#include "QatTypes/QatTypes.hpp" -namespace microsoft -{ -namespace quantum -{ +namespace microsoft { +namespace quantum { - class ValidationPassConfiguration - { - public: - using Set = std::unordered_set; - // Setup and construction - // +class ValidationPassConfiguration +{ +public: + using Set = std::unordered_set; + // Setup and construction + // - /// Setup function that attached the configuration to the ConfigurationManager. - void setup(ConfigurationManager& config) - { - config.setSectionName("Validation configuration", ""); - config.addParameter( - allow_internal_calls_, "allow-internal-calls", "Whether or not internal calls are allowed."); - } + /// Setup function that attached the configuration to the ConfigurationManager. + void setup(ConfigurationManager &config) + { + config.setSectionName("Validation configuration", ""); + config.addParameter(allow_internal_calls_, "allow-internal-calls", + "Whether or not internal calls are allowed."); + } - static ValidationPassConfiguration fromProfileName(String const& name) - { - auto ret = ValidationPassConfiguration(); - if (name == "generic") - { - ret.allow_internal_calls_ = true; - ret.whitelist_external_calls_ = false; - ret.whitelist_opcodes_ = false; - } - else if (name == "base") - { - ret.allow_internal_calls_ = false; - ret.whitelist_external_calls_ = true; - ret.whitelist_opcodes_ = true; - ret.opcodes_ = Set{"br", "call", "unreachable", "ret"}; - ret.external_calls_ = Set{"__quantum__qis__mz__body", "__quantum__qis__read_result__body", - "__quantum__qis__reset__body", "__quantum__qis__z__body", - "__quantum__qis__s__adj", "__quantum__qis__dumpregister__body", - "__quantum__qis__y__body", "__quantum__qis__x__body", - "__quantum__qis__t__body", "__quantum__qis__cz__body", - "__quantum__qis__s__body", "__quantum__qis__h__body", - "__quantum__qis__cnot__body", "__quantum__qis__sqrt__body"}; - } - else - { - throw std::runtime_error("Invalid profile " + name); - } - return ret; - } + static ValidationPassConfiguration fromProfileName(String const &name) + { + auto ret = ValidationPassConfiguration(); + if (name == "generic") + { + ret.allow_internal_calls_ = true; + ret.whitelist_external_calls_ = false; + ret.whitelist_opcodes_ = false; + } + else if (name == "base") + { + ret.allow_internal_calls_ = false; + ret.whitelist_external_calls_ = true; + ret.whitelist_opcodes_ = true; + ret.opcodes_ = Set{"br", "call", "unreachable", "ret"}; + ret.external_calls_ = Set{"__quantum__qis__mz__body", "__quantum__qis__read_result__body", + "__quantum__qis__reset__body", "__quantum__qis__z__body", + "__quantum__qis__s__adj", "__quantum__qis__dumpregister__body", + "__quantum__qis__y__body", "__quantum__qis__x__body", + "__quantum__qis__t__body", "__quantum__qis__cz__body", + "__quantum__qis__s__body", "__quantum__qis__h__body", + "__quantum__qis__cnot__body", "__quantum__qis__sqrt__body"}; + } + else + { + throw std::runtime_error("Invalid profile " + name); + } + return ret; + } - Set const& allowedOpcodes() const - { - return opcodes_; - } + Set const &allowedOpcodes() const + { + return opcodes_; + } - Set const& allowedExternalCallNames() const - { - return external_calls_; - } + Set const &allowedExternalCallNames() const + { + return external_calls_; + } - bool allowInternalCalls() const - { - return allow_internal_calls_; - } + bool allowInternalCalls() const + { + return allow_internal_calls_; + } - bool whitelistOpcodes() const - { - return whitelist_opcodes_; - } + bool whitelistOpcodes() const + { + return whitelist_opcodes_; + } - bool whitelistExternalCalls() const - { - return whitelist_external_calls_; - } + bool whitelistExternalCalls() const + { + return whitelist_external_calls_; + } - private: - Set opcodes_{}; - Set external_calls_{}; +private: + Set opcodes_{}; + Set external_calls_{}; - bool whitelist_opcodes_{true}; - bool whitelist_external_calls_{true}; - bool allow_internal_calls_{false}; - }; + bool whitelist_opcodes_{true}; + bool whitelist_external_calls_{true}; + bool allow_internal_calls_{false}; +}; -} // namespace quantum -} // namespace microsoft +} // namespace quantum +} // namespace microsoft From dc34effb37364ba132e9dd02b3d1cd8a500f8bea Mon Sep 17 00:00:00 2001 From: "Troels F. Roennow" Date: Mon, 8 Nov 2021 08:49:56 +0100 Subject: [PATCH 02/17] Removing redudant setModulePassManager --- src/Passes/Source/Validator/Validator.cpp | 128 +++++++++++----------- src/Passes/Source/Validator/Validator.hpp | 110 +++++++++---------- 2 files changed, 112 insertions(+), 126 deletions(-) diff --git a/src/Passes/Source/Validator/Validator.cpp b/src/Passes/Source/Validator/Validator.cpp index 758c052602..cd0a4e38cc 100644 --- a/src/Passes/Source/Validator/Validator.cpp +++ b/src/Passes/Source/Validator/Validator.cpp @@ -1,84 +1,78 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -#include "ValidationPass/ValidationPass.hpp" #include "Validator/Validator.hpp" #include "Llvm/Llvm.hpp" +#include "ValidationPass/ValidationPass.hpp" -namespace microsoft -{ -namespace quantum -{ - - Validator::Validator(ValidationPassConfiguration const& cfg, bool debug, llvm::TargetMachine* target_machine) - : loop_analysis_manager_{debug} - , function_analysis_manager_{debug} - , gscc_analysis_manager_{debug} - , module_analysis_manager_{debug} - { +namespace microsoft { +namespace quantum { - pass_builder_ = std::make_unique(target_machine); +Validator::Validator(ValidationPassConfiguration const &cfg, bool debug, + llvm::TargetMachine *target_machine) + : loop_analysis_manager_{debug} + , function_analysis_manager_{debug} + , gscc_analysis_manager_{debug} + , module_analysis_manager_{debug} +{ - pass_builder_->registerModuleAnalyses(module_analysis_manager_); - pass_builder_->registerCGSCCAnalyses(gscc_analysis_manager_); - pass_builder_->registerFunctionAnalyses(function_analysis_manager_); - pass_builder_->registerLoopAnalyses(loop_analysis_manager_); + pass_builder_ = std::make_unique(target_machine); - pass_builder_->crossRegisterProxies( - loop_analysis_manager_, function_analysis_manager_, gscc_analysis_manager_, module_analysis_manager_); + pass_builder_->registerModuleAnalyses(module_analysis_manager_); + pass_builder_->registerCGSCCAnalyses(gscc_analysis_manager_); + pass_builder_->registerFunctionAnalyses(function_analysis_manager_); + pass_builder_->registerLoopAnalyses(loop_analysis_manager_); - module_pass_manager_.addPass(ValidationPass(cfg)); - } + pass_builder_->crossRegisterProxies(loop_analysis_manager_, function_analysis_manager_, + gscc_analysis_manager_, module_analysis_manager_); - bool Validator::validate(llvm::Module& module) - { - llvm::VerifierAnalysis verifier; - auto result = verifier.run(module, module_analysis_manager_); + module_pass_manager_.addPass(ValidationPass(cfg)); +} - if (result.IRBroken) - { - llvm::errs() << "; Fatal error: Invalid IR.\n"; - return false; - } +bool Validator::validate(llvm::Module &module) +{ + llvm::VerifierAnalysis verifier; + auto result = verifier.run(module, module_analysis_manager_); - try - { - module_pass_manager_.run(module, module_analysis_manager_); - } - catch (std::exception const& e) - { - llvm::errs() << "; Fatal error: " << e.what() << "\n"; - return false; - } - return true; - } + if (result.IRBroken) + { + llvm::errs() << "; Fatal error: Invalid IR.\n"; + return false; + } - void Validator::setModulePassManager(llvm::ModulePassManager&& manager) - { - module_pass_manager_ = std::move(manager); - } + try + { + module_pass_manager_.run(module, module_analysis_manager_); + } + catch (std::exception const &e) + { + llvm::errs() << "; Fatal error: " << e.what() << "\n"; + return false; + } + return true; +} - llvm::PassBuilder& Validator::passBuilder() - { - return *pass_builder_; - } - llvm::LoopAnalysisManager& Validator::loopAnalysisManager() - { - return loop_analysis_manager_; - } - llvm::FunctionAnalysisManager& Validator::functionAnalysisManager() - { - return function_analysis_manager_; - } - llvm::CGSCCAnalysisManager& Validator::gsccAnalysisManager() - { - return gscc_analysis_manager_; - } - llvm::ModuleAnalysisManager& Validator::moduleAnalysisManager() - { - return module_analysis_manager_; - } +llvm::PassBuilder &Validator::passBuilder() +{ + return *pass_builder_; +} +llvm::LoopAnalysisManager &Validator::loopAnalysisManager() +{ + return loop_analysis_manager_; +} +llvm::FunctionAnalysisManager &Validator::functionAnalysisManager() +{ + return function_analysis_manager_; +} +llvm::CGSCCAnalysisManager &Validator::gsccAnalysisManager() +{ + return gscc_analysis_manager_; +} +llvm::ModuleAnalysisManager &Validator::moduleAnalysisManager() +{ + return module_analysis_manager_; +} -} // namespace quantum -} // namespace microsoft +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Validator/Validator.hpp b/src/Passes/Source/Validator/Validator.hpp index b62872ffc7..578d6ba1b9 100644 --- a/src/Passes/Source/Validator/Validator.hpp +++ b/src/Passes/Source/Validator/Validator.hpp @@ -4,84 +4,76 @@ #include "AllocationManager/AllocationManager.hpp" #include "AllocationManager/IAllocationManager.hpp" -#include "ValidationPass/ValidationPassConfiguration.hpp" - #include "Llvm/Llvm.hpp" +#include "ValidationPass/ValidationPassConfiguration.hpp" #include -namespace microsoft -{ -namespace quantum -{ - - /// Validator class that defines a set of rules which constitutes the profile definition. Each of - /// the rules can be used to transform a generic QIR and/or validate that the QIR is compliant with - /// said rule. - class Validator - { - public: - using ValidatorPtr = std::unique_ptr; +namespace microsoft { +namespace quantum { - // Constructors - // +/// Validator class that defines a set of rules which constitutes the profile definition. Each of +/// the rules can be used to transform a generic QIR and/or validate that the QIR is compliant with +/// said rule. +class Validator +{ +public: + using ValidatorPtr = std::unique_ptr; - explicit Validator( - ValidationPassConfiguration const& cfg, - bool debug, - llvm::TargetMachine* target_machine = nullptr); + // Constructors + // - // Default construction not allowed to ensure that LLVM modules and passes are set up correctly. - // Copy construction is prohibited due to restriction on classes held by Validator. + explicit Validator(ValidationPassConfiguration const &cfg, bool debug, + llvm::TargetMachine *target_machine = nullptr); - Validator() = delete; - Validator(Validator const&) = delete; - Validator(Validator&&) = default; - Validator& operator=(Validator const&) = delete; - Validator& operator=(Validator&&) = default; - ~Validator() = default; + // Default construction not allowed to ensure that LLVM modules and passes are set up correctly. + // Copy construction is prohibited due to restriction on classes held by Validator. - // Validator methods - // + Validator() = delete; + Validator(Validator const &) = delete; + Validator(Validator &&) = default; + Validator &operator=(Validator const &) = delete; + Validator &operator=(Validator &&) = default; + ~Validator() = default; - /// Validates that a module complies with the specified QIR profile. Returns true if the module is - /// valid and false otherwise. - bool validate(llvm::Module& module); + // Validator methods + // - protected: - using PassBuilderPtr = std::unique_ptr; + /// Validates that a module complies with the specified QIR profile. Returns true if the module is + /// valid and false otherwise. + bool validate(llvm::Module &module); - /// Sets the module pass manager used for the transformation of the IR. - void setModulePassManager(llvm::ModulePassManager&& manager); +protected: + using PassBuilderPtr = std::unique_ptr; - /// Returns a reference to the pass builder. - llvm::PassBuilder& passBuilder(); + /// Returns a reference to the pass builder. + llvm::PassBuilder &passBuilder(); - /// Returns a reference to the loop analysis manager. - llvm::LoopAnalysisManager& loopAnalysisManager(); + /// Returns a reference to the loop analysis manager. + llvm::LoopAnalysisManager &loopAnalysisManager(); - /// Returns a reference to the function analysis manager. - llvm::FunctionAnalysisManager& functionAnalysisManager(); + /// Returns a reference to the function analysis manager. + llvm::FunctionAnalysisManager &functionAnalysisManager(); - /// Returns a reference to the GSCC analysis manager. - llvm::CGSCCAnalysisManager& gsccAnalysisManager(); + /// Returns a reference to the GSCC analysis manager. + llvm::CGSCCAnalysisManager &gsccAnalysisManager(); - /// Returns a reference to the module analysis manager. - llvm::ModuleAnalysisManager& moduleAnalysisManager(); + /// Returns a reference to the module analysis manager. + llvm::ModuleAnalysisManager &moduleAnalysisManager(); - private: - // LLVM logic to run the passes - // +private: + // LLVM logic to run the passes + // - llvm::LoopAnalysisManager loop_analysis_manager_; - llvm::FunctionAnalysisManager function_analysis_manager_; - llvm::CGSCCAnalysisManager gscc_analysis_manager_; - llvm::ModuleAnalysisManager module_analysis_manager_; + llvm::LoopAnalysisManager loop_analysis_manager_; + llvm::FunctionAnalysisManager function_analysis_manager_; + llvm::CGSCCAnalysisManager gscc_analysis_manager_; + llvm::ModuleAnalysisManager module_analysis_manager_; - PassBuilderPtr pass_builder_; + PassBuilderPtr pass_builder_; - llvm::ModulePassManager module_pass_manager_{}; - }; + llvm::ModulePassManager module_pass_manager_{}; +}; -} // namespace quantum -} // namespace microsoft +} // namespace quantum +} // namespace microsoft From b74007d6657a3d1482eed4d89aff587c43fbdd02 Mon Sep 17 00:00:00 2001 From: "Troels F. Roennow" Date: Mon, 8 Nov 2021 08:55:06 +0100 Subject: [PATCH 03/17] Fixing recursion --- src/Passes/Source/Rules/Notation/Call.ipp | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/Passes/Source/Rules/Notation/Call.ipp b/src/Passes/Source/Rules/Notation/Call.ipp index 1c2ade7517..ce949902c0 100644 --- a/src/Passes/Source/Rules/Notation/Call.ipp +++ b/src/Passes/Source/Rules/Notation/Call.ipp @@ -3,11 +3,8 @@ // Licensed under the MIT License. #include "Llvm/Llvm.hpp" -#include "Rules/Notation/Notation.hpp" #include "Rules/Operands/Any.hpp" #include "Rules/Operands/Call.hpp" -#include "Rules/Operands/Instruction.hpp" -#include "Rules/ReplacementRule.hpp" #include #include From a7ba6247b535c243b59141f00fe416cbf55fc837 Mon Sep 17 00:00:00 2001 From: "Troels F. Roennow" Date: Mon, 8 Nov 2021 09:27:49 +0100 Subject: [PATCH 04/17] Refactoring filenames --- src/Passes/Source/Rules/Notation/BitCast.cpp | 36 +- src/Passes/Source/Rules/Notation/Branch.cpp | 44 +-- src/Passes/Source/Rules/Notation/Call.ipp | 4 +- .../Source/Rules/Notation/CallByNameOnly.cpp | 34 +- src/Passes/Source/Rules/Notation/Capture.cpp | 57 ++- src/Passes/Source/Rules/Notation/ConstInt.cpp | 34 +- src/Passes/Source/Rules/Notation/IntToPtr.cpp | 36 +- src/Passes/Source/Rules/Notation/Load.cpp | 36 +- src/Passes/Source/Rules/Notation/Notation.cpp | 37 +- src/Passes/Source/Rules/Notation/Notation.hpp | 366 +++++++++--------- src/Passes/Source/Rules/Notation/Phi.ipp | 4 +- src/Passes/Source/Rules/Notation/Select.cpp | 44 +-- src/Passes/Source/Rules/Notation/Switch.cpp | 47 +-- .../Source/Rules/Notation/UnnamedInvoke.cpp | 32 +- src/Passes/Source/Rules/Operands/Any.cpp | 25 -- .../Source/Rules/Operands/AnyPattern.cpp | 23 ++ .../Operands/{Any.hpp => AnyPattern.hpp} | 0 src/Passes/Source/Rules/Operands/Call.cpp | 51 --- src/Passes/Source/Rules/Operands/Call.hpp | 51 --- .../Source/Rules/Operands/CallPattern.cpp | 48 +++ .../Source/Rules/Operands/CallPattern.hpp | 48 +++ src/Passes/Source/Rules/Operands/Phi.cpp | 33 -- .../Source/Rules/Operands/PhiPattern.cpp | 31 ++ .../Operands/{Phi.hpp => PhiPattern.hpp} | 0 .../Source/Rules/Operands/UnnamedInvoke.cpp | 33 -- .../Rules/Operands/UnnamedInvokePattern.cpp | 31 ++ ...medInvoke.hpp => UnnamedInvokePattern.hpp} | 0 src/Passes/Source/Rules/ReplacementRule.hpp | 102 +++-- .../ValidationPassConfiguration.hpp | 3 +- 29 files changed, 609 insertions(+), 681 deletions(-) delete mode 100644 src/Passes/Source/Rules/Operands/Any.cpp create mode 100644 src/Passes/Source/Rules/Operands/AnyPattern.cpp rename src/Passes/Source/Rules/Operands/{Any.hpp => AnyPattern.hpp} (100%) delete mode 100644 src/Passes/Source/Rules/Operands/Call.cpp delete mode 100644 src/Passes/Source/Rules/Operands/Call.hpp create mode 100644 src/Passes/Source/Rules/Operands/CallPattern.cpp create mode 100644 src/Passes/Source/Rules/Operands/CallPattern.hpp delete mode 100644 src/Passes/Source/Rules/Operands/Phi.cpp create mode 100644 src/Passes/Source/Rules/Operands/PhiPattern.cpp rename src/Passes/Source/Rules/Operands/{Phi.hpp => PhiPattern.hpp} (100%) delete mode 100644 src/Passes/Source/Rules/Operands/UnnamedInvoke.cpp create mode 100644 src/Passes/Source/Rules/Operands/UnnamedInvokePattern.cpp rename src/Passes/Source/Rules/Operands/{UnnamedInvoke.hpp => UnnamedInvokePattern.hpp} (100%) diff --git a/src/Passes/Source/Rules/Notation/BitCast.cpp b/src/Passes/Source/Rules/Notation/BitCast.cpp index 5493b80bd8..2cf79e865a 100644 --- a/src/Passes/Source/Rules/Notation/BitCast.cpp +++ b/src/Passes/Source/Rules/Notation/BitCast.cpp @@ -1,33 +1,29 @@ // 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/Call.hpp" +#include "Rules/Operands/AnyPattern.hpp" +#include "Rules/Operands/CallPattern.hpp" #include "Rules/Operands/Instruction.hpp" -#include "Llvm/Llvm.hpp" - #include #include -namespace microsoft -{ -namespace quantum -{ - namespace notation - { +namespace microsoft { +namespace quantum { +namespace notation { - using IOperandPrototypePtr = std::shared_ptr; +using IOperandPrototypePtr = std::shared_ptr; - IOperandPrototypePtr bitCast(IOperandPrototypePtr const& arg) - { - auto cast_pattern = std::make_shared(); +IOperandPrototypePtr bitCast(IOperandPrototypePtr const &arg) +{ + auto cast_pattern = std::make_shared(); - cast_pattern->addChild(arg); - return static_cast(cast_pattern); - } + cast_pattern->addChild(arg); + return static_cast(cast_pattern); +} - } // namespace notation -} // namespace quantum -} // namespace microsoft +} // namespace notation +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Rules/Notation/Branch.cpp b/src/Passes/Source/Rules/Notation/Branch.cpp index bc7aecae9c..2b63b805d6 100644 --- a/src/Passes/Source/Rules/Notation/Branch.cpp +++ b/src/Passes/Source/Rules/Notation/Branch.cpp @@ -1,39 +1,33 @@ // 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/Call.hpp" +#include "Rules/Operands/AnyPattern.hpp" +#include "Rules/Operands/CallPattern.hpp" #include "Rules/Operands/Instruction.hpp" -#include "Llvm/Llvm.hpp" - #include #include -namespace microsoft -{ -namespace quantum -{ - namespace notation - { +namespace microsoft { +namespace quantum { +namespace notation { - using IOperandPrototypePtr = std::shared_ptr; +using IOperandPrototypePtr = std::shared_ptr; - IOperandPrototypePtr branch( - IOperandPrototypePtr const& cond, - IOperandPrototypePtr const& arg1, - IOperandPrototypePtr const& arg2) - { - auto branch_pattern = std::make_shared(); +IOperandPrototypePtr branch(IOperandPrototypePtr const &cond, IOperandPrototypePtr const &arg1, + IOperandPrototypePtr const &arg2) +{ + auto branch_pattern = std::make_shared(); - branch_pattern->addChild(cond); - branch_pattern->addChild(arg1); - branch_pattern->addChild(arg2); + branch_pattern->addChild(cond); + branch_pattern->addChild(arg1); + branch_pattern->addChild(arg2); - return static_cast(branch_pattern); - } + return static_cast(branch_pattern); +} - } // namespace notation -} // namespace quantum -} // namespace microsoft +} // namespace notation +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Rules/Notation/Call.ipp b/src/Passes/Source/Rules/Notation/Call.ipp index ce949902c0..33d7fca372 100644 --- a/src/Passes/Source/Rules/Notation/Call.ipp +++ b/src/Passes/Source/Rules/Notation/Call.ipp @@ -3,8 +3,8 @@ // Licensed under the MIT License. #include "Llvm/Llvm.hpp" -#include "Rules/Operands/Any.hpp" -#include "Rules/Operands/Call.hpp" +#include "Rules/Operands/AnyPattern.hpp" +#include "Rules/Operands/CallPattern.hpp" #include #include diff --git a/src/Passes/Source/Rules/Notation/CallByNameOnly.cpp b/src/Passes/Source/Rules/Notation/CallByNameOnly.cpp index c48b64ad1b..208d2c04a0 100644 --- a/src/Passes/Source/Rules/Notation/CallByNameOnly.cpp +++ b/src/Passes/Source/Rules/Notation/CallByNameOnly.cpp @@ -1,31 +1,27 @@ // 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/Call.hpp" +#include "Rules/Operands/AnyPattern.hpp" +#include "Rules/Operands/CallPattern.hpp" #include "Rules/Operands/Instruction.hpp" -#include "Llvm/Llvm.hpp" - #include #include -namespace microsoft -{ -namespace quantum -{ - namespace notation - { +namespace microsoft { +namespace quantum { +namespace notation { - using IOperandPrototypePtr = std::shared_ptr; +using IOperandPrototypePtr = std::shared_ptr; - IOperandPrototypePtr callByNameOnly(std::string const& name) - { - IOperandPrototypePtr ret = std::make_shared(name); - return ret; - } +IOperandPrototypePtr callByNameOnly(std::string const &name) +{ + IOperandPrototypePtr ret = std::make_shared(name); + return ret; +} - } // namespace notation -} // namespace quantum -} // namespace microsoft +} // namespace notation +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Rules/Notation/Capture.cpp b/src/Passes/Source/Rules/Notation/Capture.cpp index 6f92bf78ff..96b38ed1e4 100644 --- a/src/Passes/Source/Rules/Notation/Capture.cpp +++ b/src/Passes/Source/Rules/Notation/Capture.cpp @@ -1,42 +1,37 @@ // 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/Call.hpp" +#include "Rules/Operands/AnyPattern.hpp" +#include "Rules/Operands/CallPattern.hpp" #include "Rules/Operands/Instruction.hpp" -#include "Llvm/Llvm.hpp" - #include #include -namespace microsoft +namespace microsoft { +namespace quantum { +namespace notation { + +using IOperandPrototypePtr = std::shared_ptr; + +Capture::Capture(std::string const &name) + : name_{name} +{} + +IOperandPrototypePtr Capture::operator=(IOperandPrototypePtr const &other) // NOLINT { -namespace quantum + auto ret = other->copy(); + ret->captureAs(name_); + return ret; +} + +Capture operator""_cap(char const *name, std::size_t) { - namespace notation - { - - using IOperandPrototypePtr = std::shared_ptr; - - Capture::Capture(std::string const& name) - : name_{name} - { - } - - IOperandPrototypePtr Capture::operator=(IOperandPrototypePtr const& other) // NOLINT - { - auto ret = other->copy(); - ret->captureAs(name_); - return ret; - } - - Capture operator""_cap(char const* name, std::size_t) - { - return Capture(name); - } - - } // namespace notation -} // namespace quantum -} // namespace microsoft + return Capture(name); +} + +} // namespace notation +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Rules/Notation/ConstInt.cpp b/src/Passes/Source/Rules/Notation/ConstInt.cpp index 38fef3fa83..f10620b839 100644 --- a/src/Passes/Source/Rules/Notation/ConstInt.cpp +++ b/src/Passes/Source/Rules/Notation/ConstInt.cpp @@ -1,32 +1,28 @@ // 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/Call.hpp" +#include "Rules/Operands/AnyPattern.hpp" +#include "Rules/Operands/CallPattern.hpp" #include "Rules/Operands/Instruction.hpp" -#include "Llvm/Llvm.hpp" - #include #include -namespace microsoft -{ -namespace quantum -{ - namespace notation - { +namespace microsoft { +namespace quantum { +namespace notation { - using IOperandPrototypePtr = std::shared_ptr; +using IOperandPrototypePtr = std::shared_ptr; - IOperandPrototypePtr constInt() - { - auto cast_pattern = std::make_shared(); +IOperandPrototypePtr constInt() +{ + auto cast_pattern = std::make_shared(); - return static_cast(cast_pattern); - } + return static_cast(cast_pattern); +} - } // namespace notation -} // namespace quantum -} // namespace microsoft +} // namespace notation +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Rules/Notation/IntToPtr.cpp b/src/Passes/Source/Rules/Notation/IntToPtr.cpp index bc8282a37c..a7bdea8c66 100644 --- a/src/Passes/Source/Rules/Notation/IntToPtr.cpp +++ b/src/Passes/Source/Rules/Notation/IntToPtr.cpp @@ -1,33 +1,29 @@ // 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/Call.hpp" +#include "Rules/Operands/AnyPattern.hpp" +#include "Rules/Operands/CallPattern.hpp" #include "Rules/Operands/Instruction.hpp" -#include "Llvm/Llvm.hpp" - #include #include -namespace microsoft -{ -namespace quantum -{ - namespace notation - { +namespace microsoft { +namespace quantum { +namespace notation { - using IOperandPrototypePtr = std::shared_ptr; +using IOperandPrototypePtr = std::shared_ptr; - IOperandPrototypePtr intToPtr(IOperandPrototypePtr const& arg) - { - auto cast_pattern = std::make_shared(); +IOperandPrototypePtr intToPtr(IOperandPrototypePtr const &arg) +{ + auto cast_pattern = std::make_shared(); - cast_pattern->addChild(arg); - return static_cast(cast_pattern); - } + cast_pattern->addChild(arg); + return static_cast(cast_pattern); +} - } // namespace notation -} // namespace quantum -} // namespace microsoft +} // namespace notation +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Rules/Notation/Load.cpp b/src/Passes/Source/Rules/Notation/Load.cpp index 9b91c10435..61974ec021 100644 --- a/src/Passes/Source/Rules/Notation/Load.cpp +++ b/src/Passes/Source/Rules/Notation/Load.cpp @@ -1,33 +1,29 @@ // 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/Call.hpp" +#include "Rules/Operands/AnyPattern.hpp" +#include "Rules/Operands/CallPattern.hpp" #include "Rules/Operands/Instruction.hpp" -#include "Llvm/Llvm.hpp" - #include #include -namespace microsoft -{ -namespace quantum -{ - namespace notation - { +namespace microsoft { +namespace quantum { +namespace notation { - using IOperandPrototypePtr = std::shared_ptr; +using IOperandPrototypePtr = std::shared_ptr; - IOperandPrototypePtr load(IOperandPrototypePtr const& arg) - { - auto ret = std::make_shared(); +IOperandPrototypePtr load(IOperandPrototypePtr const &arg) +{ + auto ret = std::make_shared(); - ret->addChild(arg); - return static_cast(ret); - } + ret->addChild(arg); + return static_cast(ret); +} - } // namespace notation -} // namespace quantum -} // namespace microsoft +} // namespace notation +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Rules/Notation/Notation.cpp b/src/Passes/Source/Rules/Notation/Notation.cpp index 3acf9569d8..33927e3975 100644 --- a/src/Passes/Source/Rules/Notation/Notation.cpp +++ b/src/Passes/Source/Rules/Notation/Notation.cpp @@ -2,31 +2,28 @@ // Licensed under the MIT License. #include "Rules/Notation/Notation.hpp" -#include "Rules/Operands/Any.hpp" -#include "Rules/Operands/Call.hpp" -#include "Rules/Operands/Instruction.hpp" #include "Llvm/Llvm.hpp" +#include "Rules/Operands/AnyPattern.hpp" +#include "Rules/Operands/CallPattern.hpp" +#include "Rules/Operands/Instruction.hpp" #include #include -namespace microsoft -{ -namespace quantum -{ - namespace notation - { +namespace microsoft { +namespace quantum { +namespace notation { - ReplacerFunction deleteInstruction() - { - return [](ReplacementRule::Builder&, ReplacementRule::Value* val, ReplacementRule::Captures&, - ReplacementRule::Replacements& replacements) { - replacements.push_back({llvm::dyn_cast(val), nullptr}); - return true; - }; - } +ReplacerFunction deleteInstruction() +{ + return [](ReplacementRule::Builder &, ReplacementRule::Value *val, ReplacementRule::Captures &, + ReplacementRule::Replacements &replacements) { + replacements.push_back({llvm::dyn_cast(val), nullptr}); + return true; + }; +} - } // namespace notation -} // namespace quantum -} // namespace microsoft +} // 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 c7e3e0b72a..c989034085 100644 --- a/src/Passes/Source/Rules/Notation/Notation.hpp +++ b/src/Passes/Source/Rules/Notation/Notation.hpp @@ -4,199 +4,189 @@ /// @defgroup shorthandNotation Shorthand Notation +#include "Llvm/Llvm.hpp" #include "Rules/Notation/Call.ipp" #include "Rules/Notation/Phi.ipp" -#include "Rules/Operands/Any.hpp" -#include "Rules/Operands/Call.hpp" +#include "Rules/Operands/AnyPattern.hpp" +#include "Rules/Operands/CallPattern.hpp" #include "Rules/Operands/Instruction.hpp" -#include "Rules/Operands/Phi.hpp" - -#include "Llvm/Llvm.hpp" +#include "Rules/Operands/PhiPattern.hpp" #include #include -namespace microsoft -{ -namespace quantum +namespace microsoft { +namespace quantum { +/// Shorthand notations to make it easy and readible to create patterns. +/// +/// +namespace notation { + +using IOperandPrototypePtr = std::shared_ptr; +using ReplacerFunction = + std::function; + +/// Helper class to enable literals for IR patterns. The main purpose of this class +/// is to enable notation that allows one write `"name"_cap = operandGenerator()` where +/// the operand generator is a function which creates a IOperandPrototypePtr. This notation +/// means that whenever a operand is matched, the matched value is stored under "name". +class Capture { - /// Shorthand notations to make it easy and readible to create patterns. - /// - /// - namespace notation - { - - using IOperandPrototypePtr = std::shared_ptr; - using ReplacerFunction = std::function; - - /// Helper class to enable literals for IR patterns. The main purpose of this class - /// is to enable notation that allows one write `"name"_cap = operandGenerator()` where - /// the operand generator is a function which creates a IOperandPrototypePtr. This notation - /// means that whenever a operand is matched, the matched value is stored under "name". - class Capture - { - public: - /// Explicit creation using string name constructor. - explicit Capture(std::string const& name); - - // Note that this operator is delibrately unconventional - IOperandPrototypePtr operator=(IOperandPrototypePtr const& other); // NOLINT - - private: - std::string name_{}; ///< Name that is assigned to the IOperandPrototype - }; - - /// @addtogroup shorthandNotation - /// @{ - /// Shorthand notations are made to make it possible to match patterns in the QIR. This part of the - /// library focuses on making it easy to express advance patterns in just a few lines and specify - /// what parts of the IR is of interest to the replacer function. An example is following pattern - /// - /// ``` - /// auto get_one = call("__quantum__rt__result_get_one"); - /// addRule( - /// {branch("cond"_cap = call("__quantum__rt__result_equal", "result"_cap = _, "one"_cap = - /// get_one), _, _), - /// replace_branch_positive}); - /// - /// ``` - /// - /// which matches IRs of the form - /// - /// ``` - /// %1 = call %Result* @__quantum__rt__result_get_one() - /// %2 = call i1 @__quantum__rt__result_equal(%Result* %0, %Result* %1) - /// br i1 %2, label %then0__1, label %continue__1 - /// ``` - /// - /// The pattern futher specifies that as a successful match is obtained, a table capturing - /// certain values must be created. In the above example, the table would contain three - /// entries: `cond`, `result` and `one` each of which would point to a a llvm::Value* - /// in the QIR. This allows the replacement function to easily manipulate the DAG in these - /// three places (four if you include the main captured value which is always passed to the - /// replacement function). - - /// Shorthand notation to match an instruction for a function call. - /// The resulting IOperandPrototype matches a function call with arguments - /// as specified by the arguments given. For instance, - /// - /// ``` - /// addRule({call("foo", _, _), deleteInstruction()}); - /// ``` - /// - /// matches a call to the function `foo` with exactly two arguments. - template IOperandPrototypePtr call(std::string const& name, Args... args); - - /// Matches a invoke instruction - IOperandPrototypePtr unnamedInvoke(); - - /// Matches a phi node with N arguments. - 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. - /// - /// ``` - /// addRule({callByNameOnly("foo"), deleteInstruction()}); - /// ``` - /// - /// matches calls to the function `foo` regardless of the number of arguments. - IOperandPrototypePtr callByNameOnly(std::string const& name); - - /// Matches the llvm::BitCast instructruction. - IOperandPrototypePtr bitCast(IOperandPrototypePtr const& arg); - - /// Matches the llvm::IntToPtr instructruction. - IOperandPrototypePtr intToPtr(IOperandPrototypePtr const& arg); - - /// Matches the llvm::ConstantInt instructruction. - IOperandPrototypePtr constInt(); - - /// Matches a branch instruction given a condition and two arguments. - IOperandPrototypePtr branch( - IOperandPrototypePtr const& cond, - IOperandPrototypePtr const& arg1, - IOperandPrototypePtr const& arg2); - - IOperandPrototypePtr switchOp( - IOperandPrototypePtr const& cond, - IOperandPrototypePtr const& arg1, - IOperandPrototypePtr const& arg2); - - /// Matches a select instruction given a condition and two arguments. - IOperandPrototypePtr select( - IOperandPrototypePtr const& cond, - IOperandPrototypePtr const& arg1, - IOperandPrototypePtr const& arg2); - - /// Matches a load instruction with one argument. - IOperandPrototypePtr load(IOperandPrototypePtr const& arg); - - /// Matches a store instruction with a target and a value. - /// ``` - /// addRule({store("target"_cap = _, "value"_cap = _), replaceConstExpr}); - /// ``` - /// where we want to match all store instructions and do not really care about how the target or - /// 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 - /// @{ - /// The module further has shorthand notation for often encountered patterns such as any operand. - - /// Shorthand notation for a wildcard which matches anything. This value - /// is useful when for instance capturing the arguments of a function call where the - /// origin of the value does not matter to the pattern. - static std::shared_ptr const _ = std::make_shared(); // NOLINT - - /// @} - - /// @addtogroup shorthandNotation - /// @{ - /// The module also implements shorthand notation for common replacers. - - /// Shorthand notation to delete an instruction. If passed as the replacement function, this - /// function generates a replacer that deletes the instruction. This is a shorthand notation for - /// deleting an instruction that can be used with a custom rule when building a ruleset. This - /// function can be used with shorthand notation for patterns as follows: - /// ``` - /// addRule({callByNameOnly(name), deleteInstruction()}); - /// ``` - /// to delete the instructions that calls functions with the name `name`. - ReplacerFunction deleteInstruction(); - /// @} - - /// @addtogroup shorthandNotation - /// @{ - /// Literals which ease the burned of capturing values and increase readibility of the code. - - /// Literal for specifying the capture of a llvm::Value*. This literal calls the - /// IOperandPrototype::enableCapture through the assignment of a IOperandPrototypePtr to the class - /// Capture. - /// - /// As an example, one may want to match the pattern `foo(bar(baz(x)), y)` and extract the variable - /// `x` to add meta data to it. The corresponding IR could look like: - /// ``` - /// %1 = call %Type* @baz(%Type* %0) - /// %2 = call %Type* @bar(%Type* %1) - /// call void @foo(%Type* %2, %Type* %3) - /// ``` - /// To match this pattern, one would create the pattern `call("foo", call("bar", call("baz", "x"_cap - /// = _)), _)`. This pattern would ensure that at the time where the replacer function is called, - /// the value stored in `%0` is captured under the name `x`. - /// - Capture operator""_cap(char const* name, std::size_t); - /// @} - - } // namespace notation -} // namespace quantum -} // namespace microsoft +public: + /// Explicit creation using string name constructor. + explicit Capture(std::string const &name); + + // Note that this operator is delibrately unconventional + IOperandPrototypePtr operator=(IOperandPrototypePtr const &other); // NOLINT + +private: + std::string name_{}; ///< Name that is assigned to the IOperandPrototype +}; + +/// @addtogroup shorthandNotation +/// @{ +/// Shorthand notations are made to make it possible to match patterns in the QIR. This part of the +/// library focuses on making it easy to express advance patterns in just a few lines and specify +/// what parts of the IR is of interest to the replacer function. An example is following pattern +/// +/// ``` +/// auto get_one = call("__quantum__rt__result_get_one"); +/// addRule( +/// {branch("cond"_cap = call("__quantum__rt__result_equal", "result"_cap = _, "one"_cap = +/// get_one), _, _), +/// replace_branch_positive}); +/// +/// ``` +/// +/// which matches IRs of the form +/// +/// ``` +/// %1 = call %Result* @__quantum__rt__result_get_one() +/// %2 = call i1 @__quantum__rt__result_equal(%Result* %0, %Result* %1) +/// br i1 %2, label %then0__1, label %continue__1 +/// ``` +/// +/// The pattern futher specifies that as a successful match is obtained, a table capturing +/// certain values must be created. In the above example, the table would contain three +/// entries: `cond`, `result` and `one` each of which would point to a a llvm::Value* +/// in the QIR. This allows the replacement function to easily manipulate the DAG in these +/// three places (four if you include the main captured value which is always passed to the +/// replacement function). + +/// Shorthand notation to match an instruction for a function call. +/// The resulting IOperandPrototype matches a function call with arguments +/// as specified by the arguments given. For instance, +/// +/// ``` +/// addRule({call("foo", _, _), deleteInstruction()}); +/// ``` +/// +/// matches a call to the function `foo` with exactly two arguments. +template +IOperandPrototypePtr call(std::string const &name, Args... args); + +/// Matches a invoke instruction +IOperandPrototypePtr unnamedInvoke(); + +/// Matches a phi node with N arguments. +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. +/// +/// ``` +/// addRule({callByNameOnly("foo"), deleteInstruction()}); +/// ``` +/// +/// matches calls to the function `foo` regardless of the number of arguments. +IOperandPrototypePtr callByNameOnly(std::string const &name); + +/// Matches the llvm::BitCast instructruction. +IOperandPrototypePtr bitCast(IOperandPrototypePtr const &arg); + +/// Matches the llvm::IntToPtr instructruction. +IOperandPrototypePtr intToPtr(IOperandPrototypePtr const &arg); + +/// Matches the llvm::ConstantInt instructruction. +IOperandPrototypePtr constInt(); + +/// Matches a branch instruction given a condition and two arguments. +IOperandPrototypePtr branch(IOperandPrototypePtr const &cond, IOperandPrototypePtr const &arg1, + IOperandPrototypePtr const &arg2); + +IOperandPrototypePtr switchOp(IOperandPrototypePtr const &cond, IOperandPrototypePtr const &arg1, + IOperandPrototypePtr const &arg2); + +/// Matches a select instruction given a condition and two arguments. +IOperandPrototypePtr select(IOperandPrototypePtr const &cond, IOperandPrototypePtr const &arg1, + IOperandPrototypePtr const &arg2); + +/// Matches a load instruction with one argument. +IOperandPrototypePtr load(IOperandPrototypePtr const &arg); + +/// Matches a store instruction with a target and a value. +/// ``` +/// addRule({store("target"_cap = _, "value"_cap = _), replaceConstExpr}); +/// ``` +/// where we want to match all store instructions and do not really care about how the target or +/// 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 +/// @{ +/// The module further has shorthand notation for often encountered patterns such as any operand. + +/// Shorthand notation for a wildcard which matches anything. This value +/// is useful when for instance capturing the arguments of a function call where the +/// origin of the value does not matter to the pattern. +static std::shared_ptr const _ = std::make_shared(); // NOLINT + +/// @} + +/// @addtogroup shorthandNotation +/// @{ +/// The module also implements shorthand notation for common replacers. + +/// Shorthand notation to delete an instruction. If passed as the replacement function, this +/// function generates a replacer that deletes the instruction. This is a shorthand notation for +/// deleting an instruction that can be used with a custom rule when building a ruleset. This +/// function can be used with shorthand notation for patterns as follows: +/// ``` +/// addRule({callByNameOnly(name), deleteInstruction()}); +/// ``` +/// to delete the instructions that calls functions with the name `name`. +ReplacerFunction deleteInstruction(); +/// @} + +/// @addtogroup shorthandNotation +/// @{ +/// Literals which ease the burned of capturing values and increase readibility of the code. + +/// Literal for specifying the capture of a llvm::Value*. This literal calls the +/// IOperandPrototype::enableCapture through the assignment of a IOperandPrototypePtr to the class +/// Capture. +/// +/// As an example, one may want to match the pattern `foo(bar(baz(x)), y)` and extract the variable +/// `x` to add meta data to it. The corresponding IR could look like: +/// ``` +/// %1 = call %Type* @baz(%Type* %0) +/// %2 = call %Type* @bar(%Type* %1) +/// call void @foo(%Type* %2, %Type* %3) +/// ``` +/// To match this pattern, one would create the pattern `call("foo", call("bar", call("baz", "x"_cap +/// = _)), _)`. This pattern would ensure that at the time where the replacer function is called, +/// the value stored in `%0` is captured under the name `x`. +/// +Capture operator""_cap(char const *name, std::size_t); +/// @} + +} // namespace notation +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Rules/Notation/Phi.ipp b/src/Passes/Source/Rules/Notation/Phi.ipp index 77e4f45ef1..b2659e7663 100644 --- a/src/Passes/Source/Rules/Notation/Phi.ipp +++ b/src/Passes/Source/Rules/Notation/Phi.ipp @@ -4,9 +4,9 @@ #include "Llvm/Llvm.hpp" #include "Rules/Notation/Notation.hpp" -#include "Rules/Operands/Any.hpp" +#include "Rules/Operands/AnyPattern.hpp" #include "Rules/Operands/Instruction.hpp" -#include "Rules/Operands/Phi.hpp" +#include "Rules/Operands/PhiPattern.hpp" #include "Rules/ReplacementRule.hpp" #include diff --git a/src/Passes/Source/Rules/Notation/Select.cpp b/src/Passes/Source/Rules/Notation/Select.cpp index 07c2e3b11f..cf8776e7ac 100644 --- a/src/Passes/Source/Rules/Notation/Select.cpp +++ b/src/Passes/Source/Rules/Notation/Select.cpp @@ -1,39 +1,33 @@ // 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/Call.hpp" +#include "Rules/Operands/AnyPattern.hpp" +#include "Rules/Operands/CallPattern.hpp" #include "Rules/Operands/Instruction.hpp" -#include "Llvm/Llvm.hpp" - #include #include -namespace microsoft -{ -namespace quantum -{ - namespace notation - { +namespace microsoft { +namespace quantum { +namespace notation { - using IOperandPrototypePtr = std::shared_ptr; +using IOperandPrototypePtr = std::shared_ptr; - IOperandPrototypePtr select( - IOperandPrototypePtr const& cond, - IOperandPrototypePtr const& arg1, - IOperandPrototypePtr const& arg2) - { - auto select_pattern = std::make_shared(); +IOperandPrototypePtr select(IOperandPrototypePtr const &cond, IOperandPrototypePtr const &arg1, + IOperandPrototypePtr const &arg2) +{ + auto select_pattern = std::make_shared(); - select_pattern->addChild(cond); - select_pattern->addChild(arg1); - select_pattern->addChild(arg2); + select_pattern->addChild(cond); + select_pattern->addChild(arg1); + select_pattern->addChild(arg2); - return static_cast(select_pattern); - } + return static_cast(select_pattern); +} - } // namespace notation -} // namespace quantum -} // namespace microsoft +} // namespace notation +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Rules/Notation/Switch.cpp b/src/Passes/Source/Rules/Notation/Switch.cpp index 0810c2f90f..5cf6525674 100644 --- a/src/Passes/Source/Rules/Notation/Switch.cpp +++ b/src/Passes/Source/Rules/Notation/Switch.cpp @@ -1,40 +1,35 @@ // 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/Call.hpp" +#include "Rules/Operands/AnyPattern.hpp" +#include "Rules/Operands/CallPattern.hpp" #include "Rules/Operands/Instruction.hpp" -#include "Llvm/Llvm.hpp" - #include #include -namespace microsoft -{ -namespace quantum -{ - namespace notation - { +namespace microsoft { +namespace quantum { +namespace notation { - using IOperandPrototypePtr = std::shared_ptr; +using IOperandPrototypePtr = std::shared_ptr; - IOperandPrototypePtr switchOp( - IOperandPrototypePtr const& /*cond*/, - IOperandPrototypePtr const& /*arg1*/, - IOperandPrototypePtr const& /*arg2*/) - { - auto switch_pattern = std::make_shared(); +IOperandPrototypePtr switchOp(IOperandPrototypePtr const & /*cond*/, + IOperandPrototypePtr const & /*arg1*/, + IOperandPrototypePtr const & /*arg2*/) +{ + auto switch_pattern = std::make_shared(); - // TODO(tfr): finish switch pattern - // switch_pattern->addChild(cond); - // switch_pattern->addChild(arg1); - // switch_pattern->addChild(arg2); + // TODO(tfr): finish switch pattern + // switch_pattern->addChild(cond); + // switch_pattern->addChild(arg1); + // switch_pattern->addChild(arg2); - return static_cast(switch_pattern); - } + return static_cast(switch_pattern); +} - } // namespace notation -} // namespace quantum -} // namespace microsoft +} // namespace notation +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Rules/Notation/UnnamedInvoke.cpp b/src/Passes/Source/Rules/Notation/UnnamedInvoke.cpp index 5b273b1ae7..ed08b475d7 100644 --- a/src/Passes/Source/Rules/Notation/UnnamedInvoke.cpp +++ b/src/Passes/Source/Rules/Notation/UnnamedInvoke.cpp @@ -1,30 +1,26 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -#include "Rules/Notation/Notation.hpp" -#include "Rules/Operands/UnnamedInvoke.hpp" - #include "Llvm/Llvm.hpp" +#include "Rules/Notation/Notation.hpp" +#include "Rules/Operands/UnnamedInvokePattern.hpp" #include #include -namespace microsoft -{ -namespace quantum -{ - namespace notation - { +namespace microsoft { +namespace quantum { +namespace notation { - using IOperandPrototypePtr = std::shared_ptr; +using IOperandPrototypePtr = std::shared_ptr; - IOperandPrototypePtr unnamedInvoke() - { - auto ret = std::make_shared(); +IOperandPrototypePtr unnamedInvoke() +{ + auto ret = std::make_shared(); - return static_cast(ret); - } + return static_cast(ret); +} - } // namespace notation -} // namespace quantum -} // namespace microsoft +} // namespace notation +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Rules/Operands/Any.cpp b/src/Passes/Source/Rules/Operands/Any.cpp deleted file mode 100644 index 5c13ac5bdb..0000000000 --- a/src/Passes/Source/Rules/Operands/Any.cpp +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -#include "Rules/IOperandPrototype.hpp" -#include "Rules/Operands/Any.hpp" - -namespace microsoft -{ -namespace quantum -{ - - AnyPattern::AnyPattern() = default; - AnyPattern::~AnyPattern() = default; - bool AnyPattern::match(Value* instr, Captures& captures) const - { - return success(instr, captures); - } - - AnyPattern::Child AnyPattern::copy() const - { - return std::make_shared(); - } - -} // namespace quantum -} // namespace microsoft diff --git a/src/Passes/Source/Rules/Operands/AnyPattern.cpp b/src/Passes/Source/Rules/Operands/AnyPattern.cpp new file mode 100644 index 0000000000..cb5246807c --- /dev/null +++ b/src/Passes/Source/Rules/Operands/AnyPattern.cpp @@ -0,0 +1,23 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "Rules/IOperandPrototype.hpp" +#include "Rules/Operands/AnyPattern.hpp" + +namespace microsoft { +namespace quantum { + +AnyPattern::AnyPattern() = default; +AnyPattern::~AnyPattern() = default; +bool AnyPattern::match(Value *instr, Captures &captures) const +{ + return success(instr, captures); +} + +AnyPattern::Child AnyPattern::copy() const +{ + return std::make_shared(); +} + +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Rules/Operands/Any.hpp b/src/Passes/Source/Rules/Operands/AnyPattern.hpp similarity index 100% rename from src/Passes/Source/Rules/Operands/Any.hpp rename to src/Passes/Source/Rules/Operands/AnyPattern.hpp diff --git a/src/Passes/Source/Rules/Operands/Call.cpp b/src/Passes/Source/Rules/Operands/Call.cpp deleted file mode 100644 index afe6f3aafa..0000000000 --- a/src/Passes/Source/Rules/Operands/Call.cpp +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -#include "Rules/IOperandPrototype.hpp" -#include "Rules/Operands/Call.hpp" - -namespace microsoft -{ -namespace quantum -{ - - CallPattern::CallPattern(String const& name) - : name_{name} - { - } - - CallPattern::~CallPattern() = default; - - bool CallPattern::match(Value* instr, Captures& captures) const - { - auto* call_instr = llvm::dyn_cast(instr); - if (call_instr == nullptr) - { - return fail(instr, captures); - } - - auto target_function = call_instr->getCalledFunction(); - if (target_function == nullptr) - { - return fail(instr, captures); - } - - auto name = target_function->getName(); - - if (name != name_) - { - return fail(instr, captures); - } - - return success(instr, captures); - } - - CallPattern::Child CallPattern::copy() const - { - auto ret = std::make_shared(name_); - ret->copyPropertiesFrom(*this); - return std::move(ret); - } - -} // namespace quantum -} // namespace microsoft diff --git a/src/Passes/Source/Rules/Operands/Call.hpp b/src/Passes/Source/Rules/Operands/Call.hpp deleted file mode 100644 index d25c8a7ff2..0000000000 --- a/src/Passes/Source/Rules/Operands/Call.hpp +++ /dev/null @@ -1,51 +0,0 @@ -#pragma once -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -#include "Rules/IOperandPrototype.hpp" - -#include "Llvm/Llvm.hpp" - -#include -#include - -namespace microsoft -{ -namespace quantum -{ - - class CallPattern : public IOperandPrototype - { - public: - using String = std::string; - - // Construction of the call pattern by name or move only. - // - - /// Construction by name. - explicit CallPattern(String const& name); - - /// Copy construction prohibited. - CallPattern(CallPattern const& other) = delete; - - /// Move construction allowed. - CallPattern(CallPattern&& other) = default; - - /// Destructor implementation. - ~CallPattern() override; - - // Call implmenetation of the member functions in IOperandPrototype. - // - - /// Matches the callee by name. - bool match(Value* instr, Captures& captures) const override; - - /// Creates a copy of itself. - Child copy() const override; - - private: - String name_{}; ///< Name of the callee to match against. - }; - -} // namespace quantum -} // namespace microsoft diff --git a/src/Passes/Source/Rules/Operands/CallPattern.cpp b/src/Passes/Source/Rules/Operands/CallPattern.cpp new file mode 100644 index 0000000000..9de186055b --- /dev/null +++ b/src/Passes/Source/Rules/Operands/CallPattern.cpp @@ -0,0 +1,48 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "Rules/IOperandPrototype.hpp" +#include "Rules/Operands/CallPattern.hpp" + +namespace microsoft { +namespace quantum { + +CallPattern::CallPattern(String const &name) + : name_{name} +{} + +CallPattern::~CallPattern() = default; + +bool CallPattern::match(Value *instr, Captures &captures) const +{ + auto *call_instr = llvm::dyn_cast(instr); + if (call_instr == nullptr) + { + return fail(instr, captures); + } + + auto target_function = call_instr->getCalledFunction(); + if (target_function == nullptr) + { + return fail(instr, captures); + } + + auto name = target_function->getName(); + + if (name != name_) + { + return fail(instr, captures); + } + + return success(instr, captures); +} + +CallPattern::Child CallPattern::copy() const +{ + auto ret = std::make_shared(name_); + ret->copyPropertiesFrom(*this); + return std::move(ret); +} + +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Rules/Operands/CallPattern.hpp b/src/Passes/Source/Rules/Operands/CallPattern.hpp new file mode 100644 index 0000000000..d13f822247 --- /dev/null +++ b/src/Passes/Source/Rules/Operands/CallPattern.hpp @@ -0,0 +1,48 @@ +#pragma once +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "Llvm/Llvm.hpp" +#include "Rules/IOperandPrototype.hpp" + +#include +#include + +namespace microsoft { +namespace quantum { + +class CallPattern : public IOperandPrototype +{ +public: + using String = std::string; + + // Construction of the call pattern by name or move only. + // + + /// Construction by name. + explicit CallPattern(String const &name); + + /// Copy construction prohibited. + CallPattern(CallPattern const &other) = delete; + + /// Move construction allowed. + CallPattern(CallPattern &&other) = default; + + /// Destructor implementation. + ~CallPattern() override; + + // Call implmenetation of the member functions in IOperandPrototype. + // + + /// Matches the callee by name. + bool match(Value *instr, Captures &captures) const override; + + /// Creates a copy of itself. + Child copy() const override; + +private: + String name_{}; ///< Name of the callee to match against. +}; + +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Rules/Operands/Phi.cpp b/src/Passes/Source/Rules/Operands/Phi.cpp deleted file mode 100644 index 1dcffd1c02..0000000000 --- a/src/Passes/Source/Rules/Operands/Phi.cpp +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -#include "Rules/IOperandPrototype.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/PhiPattern.cpp b/src/Passes/Source/Rules/Operands/PhiPattern.cpp new file mode 100644 index 0000000000..89af2cac7e --- /dev/null +++ b/src/Passes/Source/Rules/Operands/PhiPattern.cpp @@ -0,0 +1,31 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "Rules/IOperandPrototype.hpp" +#include "Rules/Operands/PhiPattern.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/PhiPattern.hpp similarity index 100% rename from src/Passes/Source/Rules/Operands/Phi.hpp rename to src/Passes/Source/Rules/Operands/PhiPattern.hpp diff --git a/src/Passes/Source/Rules/Operands/UnnamedInvoke.cpp b/src/Passes/Source/Rules/Operands/UnnamedInvoke.cpp deleted file mode 100644 index 4cb40e7b70..0000000000 --- a/src/Passes/Source/Rules/Operands/UnnamedInvoke.cpp +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -#include "Rules/IOperandPrototype.hpp" -#include "Rules/Operands/UnnamedInvoke.hpp" - -namespace microsoft -{ -namespace quantum -{ - - UnnamedInvokePattern::~UnnamedInvokePattern() = default; - - bool UnnamedInvokePattern::match(Value* instr, Captures& captures) const - { - auto* call_instr = llvm::dyn_cast(instr); - if (call_instr == nullptr) - { - return fail(instr, captures); - } - - return success(instr, captures); - } - - UnnamedInvokePattern::Child UnnamedInvokePattern::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/UnnamedInvokePattern.cpp b/src/Passes/Source/Rules/Operands/UnnamedInvokePattern.cpp new file mode 100644 index 0000000000..e290ab2ffb --- /dev/null +++ b/src/Passes/Source/Rules/Operands/UnnamedInvokePattern.cpp @@ -0,0 +1,31 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "Rules/IOperandPrototype.hpp" +#include "Rules/Operands/UnnamedInvokePattern.hpp" + +namespace microsoft { +namespace quantum { + +UnnamedInvokePattern::~UnnamedInvokePattern() = default; + +bool UnnamedInvokePattern::match(Value *instr, Captures &captures) const +{ + auto *call_instr = llvm::dyn_cast(instr); + if (call_instr == nullptr) + { + return fail(instr, captures); + } + + return success(instr, captures); +} + +UnnamedInvokePattern::Child UnnamedInvokePattern::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/UnnamedInvoke.hpp b/src/Passes/Source/Rules/Operands/UnnamedInvokePattern.hpp similarity index 100% rename from src/Passes/Source/Rules/Operands/UnnamedInvoke.hpp rename to src/Passes/Source/Rules/Operands/UnnamedInvokePattern.hpp diff --git a/src/Passes/Source/Rules/ReplacementRule.hpp b/src/Passes/Source/Rules/ReplacementRule.hpp index 9e4e0a8c57..8773d759fe 100644 --- a/src/Passes/Source/Rules/ReplacementRule.hpp +++ b/src/Passes/Source/Rules/ReplacementRule.hpp @@ -2,76 +2,74 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -#include "Rules/Operands/Any.hpp" -#include "Rules/Operands/Call.hpp" -#include "Rules/Operands/Instruction.hpp" - #include "Llvm/Llvm.hpp" +#include "Rules/Operands/AnyPattern.hpp" +#include "Rules/Operands/CallPattern.hpp" +#include "Rules/Operands/Instruction.hpp" #include #include -namespace microsoft -{ -namespace quantum -{ +namespace microsoft { +namespace quantum { - /// Rule that describes a pattern and how to make a replacement of the matched values. - /// The class contains a OperandPrototype which is used to test whether an LLVM IR value - /// follows a specific pattern. The class also holds a function pointer to logic that - /// allows replacement of the specified value. - class ReplacementRule - { - public: - /// Table to store LLVM values using a name. - using Captures = IOperandPrototype::Captures; +/// Rule that describes a pattern and how to make a replacement of the matched values. +/// The class contains a OperandPrototype which is used to test whether an LLVM IR value +/// follows a specific pattern. The class also holds a function pointer to logic that +/// allows replacement of the specified value. +class ReplacementRule +{ +public: + /// Table to store LLVM values using a name. + using Captures = IOperandPrototype::Captures; - /// Value alias for shorthand usage. - using Value = llvm::Value; + /// Value alias for shorthand usage. + using Value = llvm::Value; - /// Pointer to the pattern type. - using IOperandPrototypePtr = std::shared_ptr; + /// Pointer to the pattern type. + using IOperandPrototypePtr = std::shared_ptr; - /// Builder alias for shorthand notation. - using Builder = llvm::IRBuilder<>; + /// Builder alias for shorthand notation. + using Builder = llvm::IRBuilder<>; - /// List of replacements. - using Replacements = std::vector>; + /// List of replacements. + using Replacements = std::vector>; - /// Function to perform replacements. - using ReplaceFunction = std::function; + /// Function to perform replacements. + using ReplaceFunction = std::function; - // Constructors and destructors - // + // Constructors and destructors + // - ReplacementRule() = default; - ReplacementRule(IOperandPrototypePtr&& pattern, ReplaceFunction&& replacer); + ReplacementRule() = default; + ReplacementRule(IOperandPrototypePtr &&pattern, ReplaceFunction &&replacer); - // Rule configuration - // + // Rule configuration + // - /// Sets the pattern describing logic to be replaced. - void setPattern(IOperandPrototypePtr&& pattern); + /// Sets the pattern describing logic to be replaced. + void setPattern(IOperandPrototypePtr &&pattern); - /// Sets the replacer logic which given a successful match will perform - /// a replacement on the IR. - void setReplacer(ReplaceFunction const& replacer); + /// Sets the replacer logic which given a successful match will perform + /// a replacement on the IR. + void setReplacer(ReplaceFunction const &replacer); - // Operation - // + // Operation + // - /// Tests whether a given value matches the rule pattern and store captures. - /// The function returns true if the match was successful in which case captures - /// are recorded. - bool match(Value* value, Captures& captures) const; + /// Tests whether a given value matches the rule pattern and store captures. + /// The function returns true if the match was successful in which case captures + /// are recorded. + bool match(Value *value, Captures &captures) const; - /// Invokes the replacer given a matched value and its corresponding captures - bool replace(Builder& builder, Value* value, Captures& captures, Replacements& replacements) const; + /// Invokes the replacer given a matched value and its corresponding captures + bool replace(Builder &builder, Value *value, Captures &captures, + Replacements &replacements) const; - private: - IOperandPrototypePtr pattern_{nullptr}; ///< Pattern to be matched against - ReplaceFunction replacer_{nullptr}; ///< Function to perform replacement upon match. - }; +private: + IOperandPrototypePtr pattern_{nullptr}; ///< Pattern to be matched against + ReplaceFunction replacer_{nullptr}; ///< Function to perform replacement upon match. +}; -} // namespace quantum -} // namespace microsoft +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/ValidationPass/ValidationPassConfiguration.hpp b/src/Passes/Source/ValidationPass/ValidationPassConfiguration.hpp index 1ba035d892..164ba1b353 100644 --- a/src/Passes/Source/ValidationPass/ValidationPassConfiguration.hpp +++ b/src/Passes/Source/ValidationPass/ValidationPassConfiguration.hpp @@ -15,7 +15,8 @@ class ValidationPassConfiguration // Setup and construction // - /// Setup function that attached the configuration to the ConfigurationManager. + /// Setup function that adds the configuration flags to the ConfigurationManager. See the + /// ConfigurationManager documentation for more details on how the setup process is implemented. void setup(ConfigurationManager &config) { config.setSectionName("Validation configuration", ""); From 9270b34dad0d3fd5a905ff7f185f9bd8d2a38d97 Mon Sep 17 00:00:00 2001 From: "Troels F. Roennow" Date: Mon, 8 Nov 2021 09:31:20 +0100 Subject: [PATCH 05/17] Renaming directory --- .../Source/Rules/Notation/BasicBlock.cpp | 32 ++- src/Passes/Source/Rules/Notation/BitCast.cpp | 6 +- src/Passes/Source/Rules/Notation/Branch.cpp | 6 +- src/Passes/Source/Rules/Notation/Call.ipp | 4 +- .../Source/Rules/Notation/CallByNameOnly.cpp | 6 +- src/Passes/Source/Rules/Notation/Capture.cpp | 6 +- src/Passes/Source/Rules/Notation/ConstInt.cpp | 6 +- src/Passes/Source/Rules/Notation/IntToPtr.cpp | 6 +- src/Passes/Source/Rules/Notation/Load.cpp | 6 +- src/Passes/Source/Rules/Notation/Notation.cpp | 6 +- src/Passes/Source/Rules/Notation/Notation.hpp | 8 +- src/Passes/Source/Rules/Notation/Phi.ipp | 6 +- src/Passes/Source/Rules/Notation/Select.cpp | 6 +- src/Passes/Source/Rules/Notation/Store.cpp | 36 ++-- src/Passes/Source/Rules/Notation/Switch.cpp | 6 +- .../Source/Rules/Notation/UnnamedInvoke.cpp | 2 +- .../Source/Rules/Operands/Instruction.cpp | 184 ------------------ .../{Operands => Patterns}/AnyPattern.cpp | 3 +- .../{Operands => Patterns}/AnyPattern.hpp | 0 .../{Operands => Patterns}/CallPattern.cpp | 3 +- .../{Operands => Patterns}/CallPattern.hpp | 0 .../Source/Rules/Patterns/Instruction.cpp | 183 +++++++++++++++++ .../{Operands => Patterns}/Instruction.hpp | 0 .../{Operands => Patterns}/PhiPattern.cpp | 3 +- .../{Operands => Patterns}/PhiPattern.hpp | 0 .../UnnamedInvokePattern.cpp | 3 +- .../UnnamedInvokePattern.hpp | 0 src/Passes/Source/Rules/ReplacementRule.hpp | 6 +- 28 files changed, 264 insertions(+), 269 deletions(-) delete mode 100644 src/Passes/Source/Rules/Operands/Instruction.cpp rename src/Passes/Source/Rules/{Operands => Patterns}/AnyPattern.cpp (91%) rename src/Passes/Source/Rules/{Operands => Patterns}/AnyPattern.hpp (100%) rename src/Passes/Source/Rules/{Operands => Patterns}/CallPattern.cpp (95%) rename src/Passes/Source/Rules/{Operands => Patterns}/CallPattern.hpp (100%) create mode 100644 src/Passes/Source/Rules/Patterns/Instruction.cpp rename src/Passes/Source/Rules/{Operands => Patterns}/Instruction.hpp (100%) rename src/Passes/Source/Rules/{Operands => Patterns}/PhiPattern.cpp (93%) rename src/Passes/Source/Rules/{Operands => Patterns}/PhiPattern.hpp (100%) rename src/Passes/Source/Rules/{Operands => Patterns}/UnnamedInvokePattern.cpp (93%) rename src/Passes/Source/Rules/{Operands => Patterns}/UnnamedInvokePattern.hpp (100%) diff --git a/src/Passes/Source/Rules/Notation/BasicBlock.cpp b/src/Passes/Source/Rules/Notation/BasicBlock.cpp index 2047350264..8eb67dd3fb 100644 --- a/src/Passes/Source/Rules/Notation/BasicBlock.cpp +++ b/src/Passes/Source/Rules/Notation/BasicBlock.cpp @@ -1,30 +1,26 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -#include "Rules/Notation/Notation.hpp" -#include "Rules/Operands/Instruction.hpp" - #include "Llvm/Llvm.hpp" +#include "Rules/Notation/Notation.hpp" +#include "Rules/Patterns/Instruction.hpp" #include #include -namespace microsoft -{ -namespace quantum -{ - namespace notation - { +namespace microsoft { +namespace quantum { +namespace notation { - using IOperandPrototypePtr = std::shared_ptr; +using IOperandPrototypePtr = std::shared_ptr; - IOperandPrototypePtr basicBlock() - { - auto ret = std::make_shared(); +IOperandPrototypePtr basicBlock() +{ + auto ret = std::make_shared(); - return static_cast(ret); - } + return static_cast(ret); +} - } // namespace notation -} // namespace quantum -} // namespace microsoft +} // namespace notation +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Rules/Notation/BitCast.cpp b/src/Passes/Source/Rules/Notation/BitCast.cpp index 2cf79e865a..b841dc0492 100644 --- a/src/Passes/Source/Rules/Notation/BitCast.cpp +++ b/src/Passes/Source/Rules/Notation/BitCast.cpp @@ -3,9 +3,9 @@ #include "Llvm/Llvm.hpp" #include "Rules/Notation/Notation.hpp" -#include "Rules/Operands/AnyPattern.hpp" -#include "Rules/Operands/CallPattern.hpp" -#include "Rules/Operands/Instruction.hpp" +#include "Rules/Patterns/AnyPattern.hpp" +#include "Rules/Patterns/CallPattern.hpp" +#include "Rules/Patterns/Instruction.hpp" #include #include diff --git a/src/Passes/Source/Rules/Notation/Branch.cpp b/src/Passes/Source/Rules/Notation/Branch.cpp index 2b63b805d6..bcfc986b75 100644 --- a/src/Passes/Source/Rules/Notation/Branch.cpp +++ b/src/Passes/Source/Rules/Notation/Branch.cpp @@ -3,9 +3,9 @@ #include "Llvm/Llvm.hpp" #include "Rules/Notation/Notation.hpp" -#include "Rules/Operands/AnyPattern.hpp" -#include "Rules/Operands/CallPattern.hpp" -#include "Rules/Operands/Instruction.hpp" +#include "Rules/Patterns/AnyPattern.hpp" +#include "Rules/Patterns/CallPattern.hpp" +#include "Rules/Patterns/Instruction.hpp" #include #include diff --git a/src/Passes/Source/Rules/Notation/Call.ipp b/src/Passes/Source/Rules/Notation/Call.ipp index 33d7fca372..8cefccbacc 100644 --- a/src/Passes/Source/Rules/Notation/Call.ipp +++ b/src/Passes/Source/Rules/Notation/Call.ipp @@ -3,8 +3,8 @@ // Licensed under the MIT License. #include "Llvm/Llvm.hpp" -#include "Rules/Operands/AnyPattern.hpp" -#include "Rules/Operands/CallPattern.hpp" +#include "Rules/Patterns/AnyPattern.hpp" +#include "Rules/Patterns/CallPattern.hpp" #include #include diff --git a/src/Passes/Source/Rules/Notation/CallByNameOnly.cpp b/src/Passes/Source/Rules/Notation/CallByNameOnly.cpp index 208d2c04a0..ad12ab815b 100644 --- a/src/Passes/Source/Rules/Notation/CallByNameOnly.cpp +++ b/src/Passes/Source/Rules/Notation/CallByNameOnly.cpp @@ -3,9 +3,9 @@ #include "Llvm/Llvm.hpp" #include "Rules/Notation/Notation.hpp" -#include "Rules/Operands/AnyPattern.hpp" -#include "Rules/Operands/CallPattern.hpp" -#include "Rules/Operands/Instruction.hpp" +#include "Rules/Patterns/AnyPattern.hpp" +#include "Rules/Patterns/CallPattern.hpp" +#include "Rules/Patterns/Instruction.hpp" #include #include diff --git a/src/Passes/Source/Rules/Notation/Capture.cpp b/src/Passes/Source/Rules/Notation/Capture.cpp index 96b38ed1e4..ab8d753bbc 100644 --- a/src/Passes/Source/Rules/Notation/Capture.cpp +++ b/src/Passes/Source/Rules/Notation/Capture.cpp @@ -3,9 +3,9 @@ #include "Llvm/Llvm.hpp" #include "Rules/Notation/Notation.hpp" -#include "Rules/Operands/AnyPattern.hpp" -#include "Rules/Operands/CallPattern.hpp" -#include "Rules/Operands/Instruction.hpp" +#include "Rules/Patterns/AnyPattern.hpp" +#include "Rules/Patterns/CallPattern.hpp" +#include "Rules/Patterns/Instruction.hpp" #include #include diff --git a/src/Passes/Source/Rules/Notation/ConstInt.cpp b/src/Passes/Source/Rules/Notation/ConstInt.cpp index f10620b839..71a9d5f92d 100644 --- a/src/Passes/Source/Rules/Notation/ConstInt.cpp +++ b/src/Passes/Source/Rules/Notation/ConstInt.cpp @@ -3,9 +3,9 @@ #include "Llvm/Llvm.hpp" #include "Rules/Notation/Notation.hpp" -#include "Rules/Operands/AnyPattern.hpp" -#include "Rules/Operands/CallPattern.hpp" -#include "Rules/Operands/Instruction.hpp" +#include "Rules/Patterns/AnyPattern.hpp" +#include "Rules/Patterns/CallPattern.hpp" +#include "Rules/Patterns/Instruction.hpp" #include #include diff --git a/src/Passes/Source/Rules/Notation/IntToPtr.cpp b/src/Passes/Source/Rules/Notation/IntToPtr.cpp index a7bdea8c66..be6ae78a39 100644 --- a/src/Passes/Source/Rules/Notation/IntToPtr.cpp +++ b/src/Passes/Source/Rules/Notation/IntToPtr.cpp @@ -3,9 +3,9 @@ #include "Llvm/Llvm.hpp" #include "Rules/Notation/Notation.hpp" -#include "Rules/Operands/AnyPattern.hpp" -#include "Rules/Operands/CallPattern.hpp" -#include "Rules/Operands/Instruction.hpp" +#include "Rules/Patterns/AnyPattern.hpp" +#include "Rules/Patterns/CallPattern.hpp" +#include "Rules/Patterns/Instruction.hpp" #include #include diff --git a/src/Passes/Source/Rules/Notation/Load.cpp b/src/Passes/Source/Rules/Notation/Load.cpp index 61974ec021..925a280cec 100644 --- a/src/Passes/Source/Rules/Notation/Load.cpp +++ b/src/Passes/Source/Rules/Notation/Load.cpp @@ -3,9 +3,9 @@ #include "Llvm/Llvm.hpp" #include "Rules/Notation/Notation.hpp" -#include "Rules/Operands/AnyPattern.hpp" -#include "Rules/Operands/CallPattern.hpp" -#include "Rules/Operands/Instruction.hpp" +#include "Rules/Patterns/AnyPattern.hpp" +#include "Rules/Patterns/CallPattern.hpp" +#include "Rules/Patterns/Instruction.hpp" #include #include diff --git a/src/Passes/Source/Rules/Notation/Notation.cpp b/src/Passes/Source/Rules/Notation/Notation.cpp index 33927e3975..1ba4f5371f 100644 --- a/src/Passes/Source/Rules/Notation/Notation.cpp +++ b/src/Passes/Source/Rules/Notation/Notation.cpp @@ -4,9 +4,9 @@ #include "Rules/Notation/Notation.hpp" #include "Llvm/Llvm.hpp" -#include "Rules/Operands/AnyPattern.hpp" -#include "Rules/Operands/CallPattern.hpp" -#include "Rules/Operands/Instruction.hpp" +#include "Rules/Patterns/AnyPattern.hpp" +#include "Rules/Patterns/CallPattern.hpp" +#include "Rules/Patterns/Instruction.hpp" #include #include diff --git a/src/Passes/Source/Rules/Notation/Notation.hpp b/src/Passes/Source/Rules/Notation/Notation.hpp index c989034085..f428abbfca 100644 --- a/src/Passes/Source/Rules/Notation/Notation.hpp +++ b/src/Passes/Source/Rules/Notation/Notation.hpp @@ -7,10 +7,10 @@ #include "Llvm/Llvm.hpp" #include "Rules/Notation/Call.ipp" #include "Rules/Notation/Phi.ipp" -#include "Rules/Operands/AnyPattern.hpp" -#include "Rules/Operands/CallPattern.hpp" -#include "Rules/Operands/Instruction.hpp" -#include "Rules/Operands/PhiPattern.hpp" +#include "Rules/Patterns/AnyPattern.hpp" +#include "Rules/Patterns/CallPattern.hpp" +#include "Rules/Patterns/Instruction.hpp" +#include "Rules/Patterns/PhiPattern.hpp" #include #include diff --git a/src/Passes/Source/Rules/Notation/Phi.ipp b/src/Passes/Source/Rules/Notation/Phi.ipp index b2659e7663..0217b4c95a 100644 --- a/src/Passes/Source/Rules/Notation/Phi.ipp +++ b/src/Passes/Source/Rules/Notation/Phi.ipp @@ -4,9 +4,9 @@ #include "Llvm/Llvm.hpp" #include "Rules/Notation/Notation.hpp" -#include "Rules/Operands/AnyPattern.hpp" -#include "Rules/Operands/Instruction.hpp" -#include "Rules/Operands/PhiPattern.hpp" +#include "Rules/Patterns/AnyPattern.hpp" +#include "Rules/Patterns/Instruction.hpp" +#include "Rules/Patterns/PhiPattern.hpp" #include "Rules/ReplacementRule.hpp" #include diff --git a/src/Passes/Source/Rules/Notation/Select.cpp b/src/Passes/Source/Rules/Notation/Select.cpp index cf8776e7ac..21ebe4b02e 100644 --- a/src/Passes/Source/Rules/Notation/Select.cpp +++ b/src/Passes/Source/Rules/Notation/Select.cpp @@ -3,9 +3,9 @@ #include "Llvm/Llvm.hpp" #include "Rules/Notation/Notation.hpp" -#include "Rules/Operands/AnyPattern.hpp" -#include "Rules/Operands/CallPattern.hpp" -#include "Rules/Operands/Instruction.hpp" +#include "Rules/Patterns/AnyPattern.hpp" +#include "Rules/Patterns/CallPattern.hpp" +#include "Rules/Patterns/Instruction.hpp" #include #include diff --git a/src/Passes/Source/Rules/Notation/Store.cpp b/src/Passes/Source/Rules/Notation/Store.cpp index f772d9c013..060a2438b2 100644 --- a/src/Passes/Source/Rules/Notation/Store.cpp +++ b/src/Passes/Source/Rules/Notation/Store.cpp @@ -1,32 +1,28 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -#include "Rules/Notation/Notation.hpp" -#include "Rules/Operands/Instruction.hpp" - #include "Llvm/Llvm.hpp" +#include "Rules/Notation/Notation.hpp" +#include "Rules/Patterns/Instruction.hpp" #include #include -namespace microsoft -{ -namespace quantum -{ - namespace notation - { +namespace microsoft { +namespace quantum { +namespace notation { - using IOperandPrototypePtr = std::shared_ptr; +using IOperandPrototypePtr = std::shared_ptr; - IOperandPrototypePtr store(IOperandPrototypePtr const& target, IOperandPrototypePtr const& value) - { - auto ret = std::make_shared(); +IOperandPrototypePtr store(IOperandPrototypePtr const &target, IOperandPrototypePtr const &value) +{ + auto ret = std::make_shared(); - ret->addChild(target); - ret->addChild(value); - return static_cast(ret); - } + ret->addChild(target); + ret->addChild(value); + return static_cast(ret); +} - } // namespace notation -} // namespace quantum -} // namespace microsoft +} // namespace notation +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Rules/Notation/Switch.cpp b/src/Passes/Source/Rules/Notation/Switch.cpp index 5cf6525674..169783a03f 100644 --- a/src/Passes/Source/Rules/Notation/Switch.cpp +++ b/src/Passes/Source/Rules/Notation/Switch.cpp @@ -3,9 +3,9 @@ #include "Llvm/Llvm.hpp" #include "Rules/Notation/Notation.hpp" -#include "Rules/Operands/AnyPattern.hpp" -#include "Rules/Operands/CallPattern.hpp" -#include "Rules/Operands/Instruction.hpp" +#include "Rules/Patterns/AnyPattern.hpp" +#include "Rules/Patterns/CallPattern.hpp" +#include "Rules/Patterns/Instruction.hpp" #include #include diff --git a/src/Passes/Source/Rules/Notation/UnnamedInvoke.cpp b/src/Passes/Source/Rules/Notation/UnnamedInvoke.cpp index ed08b475d7..1f29750d20 100644 --- a/src/Passes/Source/Rules/Notation/UnnamedInvoke.cpp +++ b/src/Passes/Source/Rules/Notation/UnnamedInvoke.cpp @@ -3,7 +3,7 @@ #include "Llvm/Llvm.hpp" #include "Rules/Notation/Notation.hpp" -#include "Rules/Operands/UnnamedInvokePattern.hpp" +#include "Rules/Patterns/UnnamedInvokePattern.hpp" #include #include diff --git a/src/Passes/Source/Rules/Operands/Instruction.cpp b/src/Passes/Source/Rules/Operands/Instruction.cpp deleted file mode 100644 index c32065dd05..0000000000 --- a/src/Passes/Source/Rules/Operands/Instruction.cpp +++ /dev/null @@ -1,184 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -#include "Rules/IOperandPrototype.hpp" -#include "Rules/Operands/Instruction.hpp" - -namespace microsoft -{ -namespace quantum -{ - - StorePattern::~StorePattern() = default; - bool StorePattern::match(Value* instr, Captures& captures) const - { - auto* load_instr = llvm::dyn_cast(instr); - if (load_instr == nullptr) - { - return fail(instr, captures); - } - - return success(instr, captures); - } - - StorePattern::Child StorePattern::copy() const - { - auto ret = std::make_shared(); - ret->copyPropertiesFrom(*this); - return std::move(ret); - } - - LoadPattern::~LoadPattern() = default; - bool LoadPattern::match(Value* instr, Captures& captures) const - { - auto* load_instr = llvm::dyn_cast(instr); - if (load_instr == nullptr) - { - return fail(instr, captures); - } - - return success(instr, captures); - } - - LoadPattern::Child LoadPattern::copy() const - { - auto ret = std::make_shared(); - ret->copyPropertiesFrom(*this); - return std::move(ret); - } - - BitCastPattern::~BitCastPattern() = default; - bool BitCastPattern::match(Value* instr, Captures& captures) const - { - auto* load_instr = llvm::dyn_cast(instr); - if (load_instr == nullptr) - { - return fail(instr, captures); - } - - return success(instr, captures); - } - - BitCastPattern::Child BitCastPattern::copy() const - { - auto ret = std::make_shared(); - ret->copyPropertiesFrom(*this); - return std::move(ret); - } - - IntToPtrPattern::~IntToPtrPattern() = default; - bool IntToPtrPattern::match(Value* instr, Captures& captures) const - { - auto* load_instr = llvm::dyn_cast(instr); - if (load_instr == nullptr) - { - return fail(instr, captures); - } - - return success(instr, captures); - } - - IntToPtrPattern::Child IntToPtrPattern::copy() const - { - auto ret = std::make_shared(); - ret->copyPropertiesFrom(*this); - return std::move(ret); - } - - ConstIntPattern::~ConstIntPattern() = default; - bool ConstIntPattern::match(Value* instr, Captures& captures) const - { - auto* load_instr = llvm::dyn_cast(instr); - if (load_instr == nullptr) - { - return fail(instr, captures); - } - - return success(instr, captures); - } - - ConstIntPattern::Child ConstIntPattern::copy() const - { - auto ret = std::make_shared(); - ret->copyPropertiesFrom(*this); - return std::move(ret); - } - - BranchPattern::~BranchPattern() = default; - bool BranchPattern::match(Value* instr, Captures& captures) const - { - auto* load_instr = llvm::dyn_cast(instr); - if (load_instr == nullptr) - { - return fail(instr, captures); - } - - return success(instr, captures); - } - - BranchPattern::Child BranchPattern::copy() const - { - auto ret = std::make_shared(); - ret->copyPropertiesFrom(*this); - return std::move(ret); - } - - SelectPattern::~SelectPattern() = default; - bool SelectPattern::match(Value* instr, Captures& captures) const - { - auto* load_instr = llvm::dyn_cast(instr); - if (load_instr == nullptr) - { - return fail(instr, captures); - } - - return success(instr, captures); - } - - SelectPattern::Child SelectPattern::copy() const - { - auto ret = std::make_shared(); - ret->copyPropertiesFrom(*this); - return std::move(ret); - } - - BasicBlockPattern::~BasicBlockPattern() = default; - bool BasicBlockPattern::match(Value* instr, Captures& captures) const - { - auto* load_instr = llvm::dyn_cast(instr); - if (load_instr == nullptr) - { - return fail(instr, captures); - } - - return success(instr, captures); - } - - BasicBlockPattern::Child BasicBlockPattern::copy() const - { - auto ret = std::make_shared(); - ret->copyPropertiesFrom(*this); - return std::move(ret); - } - - SwitchPattern::~SwitchPattern() = default; - bool SwitchPattern::match(Value* instr, Captures& captures) const - { - auto* load_instr = llvm::dyn_cast(instr); - if (load_instr == nullptr) - { - return fail(instr, captures); - } - - return success(instr, captures); - } - - SwitchPattern::Child SwitchPattern::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/AnyPattern.cpp b/src/Passes/Source/Rules/Patterns/AnyPattern.cpp similarity index 91% rename from src/Passes/Source/Rules/Operands/AnyPattern.cpp rename to src/Passes/Source/Rules/Patterns/AnyPattern.cpp index cb5246807c..19bafa1ec8 100644 --- a/src/Passes/Source/Rules/Operands/AnyPattern.cpp +++ b/src/Passes/Source/Rules/Patterns/AnyPattern.cpp @@ -1,8 +1,9 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. +#include "Rules/Patterns/AnyPattern.hpp" + #include "Rules/IOperandPrototype.hpp" -#include "Rules/Operands/AnyPattern.hpp" namespace microsoft { namespace quantum { diff --git a/src/Passes/Source/Rules/Operands/AnyPattern.hpp b/src/Passes/Source/Rules/Patterns/AnyPattern.hpp similarity index 100% rename from src/Passes/Source/Rules/Operands/AnyPattern.hpp rename to src/Passes/Source/Rules/Patterns/AnyPattern.hpp diff --git a/src/Passes/Source/Rules/Operands/CallPattern.cpp b/src/Passes/Source/Rules/Patterns/CallPattern.cpp similarity index 95% rename from src/Passes/Source/Rules/Operands/CallPattern.cpp rename to src/Passes/Source/Rules/Patterns/CallPattern.cpp index 9de186055b..4dae3ddf10 100644 --- a/src/Passes/Source/Rules/Operands/CallPattern.cpp +++ b/src/Passes/Source/Rules/Patterns/CallPattern.cpp @@ -1,8 +1,9 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. +#include "Rules/Patterns/CallPattern.hpp" + #include "Rules/IOperandPrototype.hpp" -#include "Rules/Operands/CallPattern.hpp" namespace microsoft { namespace quantum { diff --git a/src/Passes/Source/Rules/Operands/CallPattern.hpp b/src/Passes/Source/Rules/Patterns/CallPattern.hpp similarity index 100% rename from src/Passes/Source/Rules/Operands/CallPattern.hpp rename to src/Passes/Source/Rules/Patterns/CallPattern.hpp diff --git a/src/Passes/Source/Rules/Patterns/Instruction.cpp b/src/Passes/Source/Rules/Patterns/Instruction.cpp new file mode 100644 index 0000000000..d3124d4a11 --- /dev/null +++ b/src/Passes/Source/Rules/Patterns/Instruction.cpp @@ -0,0 +1,183 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "Rules/Patterns/Instruction.hpp" + +#include "Rules/IOperandPrototype.hpp" + +namespace microsoft { +namespace quantum { + +StorePattern::~StorePattern() = default; +bool StorePattern::match(Value *instr, Captures &captures) const +{ + auto *load_instr = llvm::dyn_cast(instr); + if (load_instr == nullptr) + { + return fail(instr, captures); + } + + return success(instr, captures); +} + +StorePattern::Child StorePattern::copy() const +{ + auto ret = std::make_shared(); + ret->copyPropertiesFrom(*this); + return std::move(ret); +} + +LoadPattern::~LoadPattern() = default; +bool LoadPattern::match(Value *instr, Captures &captures) const +{ + auto *load_instr = llvm::dyn_cast(instr); + if (load_instr == nullptr) + { + return fail(instr, captures); + } + + return success(instr, captures); +} + +LoadPattern::Child LoadPattern::copy() const +{ + auto ret = std::make_shared(); + ret->copyPropertiesFrom(*this); + return std::move(ret); +} + +BitCastPattern::~BitCastPattern() = default; +bool BitCastPattern::match(Value *instr, Captures &captures) const +{ + auto *load_instr = llvm::dyn_cast(instr); + if (load_instr == nullptr) + { + return fail(instr, captures); + } + + return success(instr, captures); +} + +BitCastPattern::Child BitCastPattern::copy() const +{ + auto ret = std::make_shared(); + ret->copyPropertiesFrom(*this); + return std::move(ret); +} + +IntToPtrPattern::~IntToPtrPattern() = default; +bool IntToPtrPattern::match(Value *instr, Captures &captures) const +{ + auto *load_instr = llvm::dyn_cast(instr); + if (load_instr == nullptr) + { + return fail(instr, captures); + } + + return success(instr, captures); +} + +IntToPtrPattern::Child IntToPtrPattern::copy() const +{ + auto ret = std::make_shared(); + ret->copyPropertiesFrom(*this); + return std::move(ret); +} + +ConstIntPattern::~ConstIntPattern() = default; +bool ConstIntPattern::match(Value *instr, Captures &captures) const +{ + auto *load_instr = llvm::dyn_cast(instr); + if (load_instr == nullptr) + { + return fail(instr, captures); + } + + return success(instr, captures); +} + +ConstIntPattern::Child ConstIntPattern::copy() const +{ + auto ret = std::make_shared(); + ret->copyPropertiesFrom(*this); + return std::move(ret); +} + +BranchPattern::~BranchPattern() = default; +bool BranchPattern::match(Value *instr, Captures &captures) const +{ + auto *load_instr = llvm::dyn_cast(instr); + if (load_instr == nullptr) + { + return fail(instr, captures); + } + + return success(instr, captures); +} + +BranchPattern::Child BranchPattern::copy() const +{ + auto ret = std::make_shared(); + ret->copyPropertiesFrom(*this); + return std::move(ret); +} + +SelectPattern::~SelectPattern() = default; +bool SelectPattern::match(Value *instr, Captures &captures) const +{ + auto *load_instr = llvm::dyn_cast(instr); + if (load_instr == nullptr) + { + return fail(instr, captures); + } + + return success(instr, captures); +} + +SelectPattern::Child SelectPattern::copy() const +{ + auto ret = std::make_shared(); + ret->copyPropertiesFrom(*this); + return std::move(ret); +} + +BasicBlockPattern::~BasicBlockPattern() = default; +bool BasicBlockPattern::match(Value *instr, Captures &captures) const +{ + auto *load_instr = llvm::dyn_cast(instr); + if (load_instr == nullptr) + { + return fail(instr, captures); + } + + return success(instr, captures); +} + +BasicBlockPattern::Child BasicBlockPattern::copy() const +{ + auto ret = std::make_shared(); + ret->copyPropertiesFrom(*this); + return std::move(ret); +} + +SwitchPattern::~SwitchPattern() = default; +bool SwitchPattern::match(Value *instr, Captures &captures) const +{ + auto *load_instr = llvm::dyn_cast(instr); + if (load_instr == nullptr) + { + return fail(instr, captures); + } + + return success(instr, captures); +} + +SwitchPattern::Child SwitchPattern::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/Instruction.hpp b/src/Passes/Source/Rules/Patterns/Instruction.hpp similarity index 100% rename from src/Passes/Source/Rules/Operands/Instruction.hpp rename to src/Passes/Source/Rules/Patterns/Instruction.hpp diff --git a/src/Passes/Source/Rules/Operands/PhiPattern.cpp b/src/Passes/Source/Rules/Patterns/PhiPattern.cpp similarity index 93% rename from src/Passes/Source/Rules/Operands/PhiPattern.cpp rename to src/Passes/Source/Rules/Patterns/PhiPattern.cpp index 89af2cac7e..6b2dcb0ce4 100644 --- a/src/Passes/Source/Rules/Operands/PhiPattern.cpp +++ b/src/Passes/Source/Rules/Patterns/PhiPattern.cpp @@ -1,8 +1,9 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. +#include "Rules/Patterns/PhiPattern.hpp" + #include "Rules/IOperandPrototype.hpp" -#include "Rules/Operands/PhiPattern.hpp" namespace microsoft { namespace quantum { diff --git a/src/Passes/Source/Rules/Operands/PhiPattern.hpp b/src/Passes/Source/Rules/Patterns/PhiPattern.hpp similarity index 100% rename from src/Passes/Source/Rules/Operands/PhiPattern.hpp rename to src/Passes/Source/Rules/Patterns/PhiPattern.hpp diff --git a/src/Passes/Source/Rules/Operands/UnnamedInvokePattern.cpp b/src/Passes/Source/Rules/Patterns/UnnamedInvokePattern.cpp similarity index 93% rename from src/Passes/Source/Rules/Operands/UnnamedInvokePattern.cpp rename to src/Passes/Source/Rules/Patterns/UnnamedInvokePattern.cpp index e290ab2ffb..93df15dac1 100644 --- a/src/Passes/Source/Rules/Operands/UnnamedInvokePattern.cpp +++ b/src/Passes/Source/Rules/Patterns/UnnamedInvokePattern.cpp @@ -1,8 +1,9 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. +#include "Rules/Patterns/UnnamedInvokePattern.hpp" + #include "Rules/IOperandPrototype.hpp" -#include "Rules/Operands/UnnamedInvokePattern.hpp" namespace microsoft { namespace quantum { diff --git a/src/Passes/Source/Rules/Operands/UnnamedInvokePattern.hpp b/src/Passes/Source/Rules/Patterns/UnnamedInvokePattern.hpp similarity index 100% rename from src/Passes/Source/Rules/Operands/UnnamedInvokePattern.hpp rename to src/Passes/Source/Rules/Patterns/UnnamedInvokePattern.hpp diff --git a/src/Passes/Source/Rules/ReplacementRule.hpp b/src/Passes/Source/Rules/ReplacementRule.hpp index 8773d759fe..3d700f7f07 100644 --- a/src/Passes/Source/Rules/ReplacementRule.hpp +++ b/src/Passes/Source/Rules/ReplacementRule.hpp @@ -3,9 +3,9 @@ // Licensed under the MIT License. #include "Llvm/Llvm.hpp" -#include "Rules/Operands/AnyPattern.hpp" -#include "Rules/Operands/CallPattern.hpp" -#include "Rules/Operands/Instruction.hpp" +#include "Rules/Patterns/AnyPattern.hpp" +#include "Rules/Patterns/CallPattern.hpp" +#include "Rules/Patterns/Instruction.hpp" #include #include From dd2403a73a83598e9a7e502cf42106d62204760d Mon Sep 17 00:00:00 2001 From: "Troels F. Roennow" Date: Mon, 8 Nov 2021 10:12:16 +0100 Subject: [PATCH 06/17] Updating names and files --- src/Passes/Source/Rules/Notation/Call.hpp | 66 +++++++++ src/Passes/Source/Rules/Notation/Notation.hpp | 1 + .../Source/Rules/Patterns/Instruction.cpp | 9 -- .../Source/Rules/Patterns/Instruction.hpp | 139 ++++++++---------- 4 files changed, 126 insertions(+), 89 deletions(-) create mode 100644 src/Passes/Source/Rules/Notation/Call.hpp diff --git a/src/Passes/Source/Rules/Notation/Call.hpp b/src/Passes/Source/Rules/Notation/Call.hpp new file mode 100644 index 0000000000..916cc79498 --- /dev/null +++ b/src/Passes/Source/Rules/Notation/Call.hpp @@ -0,0 +1,66 @@ +#pragma once +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +/// @defgroup shorthandNotation Shorthand Notation + +#include "Llvm/Llvm.hpp" +#include "Rules/Notation/Call.ipp" +#include "Rules/Notation/Phi.ipp" +#include "Rules/Patterns/AnyPattern.hpp" +#include "Rules/Patterns/CallPattern.hpp" +#include "Rules/Patterns/Instruction.hpp" +#include "Rules/Patterns/PhiPattern.hpp" + +#include +#include + +namespace microsoft { +namespace quantum { +namespace notation { + +using IOperandPrototypePtr = std::shared_ptr; + +/// Shorthand notations are made to make it possible to match patterns in the QIR. This part of the +/// library focuses on making it easy to express advance patterns in just a few lines and specify +/// what parts of the IR is of interest to the replacer function. An example is following pattern +/// +/// ``` +/// auto get_one = call("__quantum__rt__result_get_one"); +/// addRule( +/// {branch("cond"_cap = call("__quantum__rt__result_equal", "result"_cap = _, "one"_cap = +/// get_one), _, _), +/// replace_branch_positive}); +/// +/// ``` +/// +/// which matches IRs of the form +/// +/// ``` +/// %1 = call %Result* @__quantum__rt__result_get_one() +/// %2 = call i1 @__quantum__rt__result_equal(%Result* %0, %Result* %1) +/// br i1 %2, label %then0__1, label %continue__1 +/// ``` +/// +/// The pattern futher specifies that as a successful match is obtained, a table capturing +/// certain values must be created. In the above example, the table would contain three +/// entries: `cond`, `result` and `one` each of which would point to a a llvm::Value* +/// in the QIR. This allows the replacement function to easily manipulate the DAG in these +/// three places (four if you include the main captured value which is always passed to the +/// replacement function). + +/// Shorthand notation to match an instruction for a function call. +/// The resulting IOperandPrototype matches a function call with arguments +/// as specified by the arguments given. For instance, +/// +/// ``` +/// addRule({call("foo", _, _), deleteInstruction()}); +/// ``` +/// +/// matches a call to the function `foo` with exactly two arguments. +template +IOperandPrototypePtr call(std::string const &name, Args... args); + +} // 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 f428abbfca..a2634194db 100644 --- a/src/Passes/Source/Rules/Notation/Notation.hpp +++ b/src/Passes/Source/Rules/Notation/Notation.hpp @@ -5,6 +5,7 @@ /// @defgroup shorthandNotation Shorthand Notation #include "Llvm/Llvm.hpp" +#include "Rules/Notation/Call.hpp" #include "Rules/Notation/Call.ipp" #include "Rules/Notation/Phi.ipp" #include "Rules/Patterns/AnyPattern.hpp" diff --git a/src/Passes/Source/Rules/Patterns/Instruction.cpp b/src/Passes/Source/Rules/Patterns/Instruction.cpp index d3124d4a11..8b9dca6870 100644 --- a/src/Passes/Source/Rules/Patterns/Instruction.cpp +++ b/src/Passes/Source/Rules/Patterns/Instruction.cpp @@ -8,7 +8,6 @@ namespace microsoft { namespace quantum { -StorePattern::~StorePattern() = default; bool StorePattern::match(Value *instr, Captures &captures) const { auto *load_instr = llvm::dyn_cast(instr); @@ -27,7 +26,6 @@ StorePattern::Child StorePattern::copy() const return std::move(ret); } -LoadPattern::~LoadPattern() = default; bool LoadPattern::match(Value *instr, Captures &captures) const { auto *load_instr = llvm::dyn_cast(instr); @@ -46,7 +44,6 @@ LoadPattern::Child LoadPattern::copy() const return std::move(ret); } -BitCastPattern::~BitCastPattern() = default; bool BitCastPattern::match(Value *instr, Captures &captures) const { auto *load_instr = llvm::dyn_cast(instr); @@ -65,7 +62,6 @@ BitCastPattern::Child BitCastPattern::copy() const return std::move(ret); } -IntToPtrPattern::~IntToPtrPattern() = default; bool IntToPtrPattern::match(Value *instr, Captures &captures) const { auto *load_instr = llvm::dyn_cast(instr); @@ -84,7 +80,6 @@ IntToPtrPattern::Child IntToPtrPattern::copy() const return std::move(ret); } -ConstIntPattern::~ConstIntPattern() = default; bool ConstIntPattern::match(Value *instr, Captures &captures) const { auto *load_instr = llvm::dyn_cast(instr); @@ -103,7 +98,6 @@ ConstIntPattern::Child ConstIntPattern::copy() const return std::move(ret); } -BranchPattern::~BranchPattern() = default; bool BranchPattern::match(Value *instr, Captures &captures) const { auto *load_instr = llvm::dyn_cast(instr); @@ -122,7 +116,6 @@ BranchPattern::Child BranchPattern::copy() const return std::move(ret); } -SelectPattern::~SelectPattern() = default; bool SelectPattern::match(Value *instr, Captures &captures) const { auto *load_instr = llvm::dyn_cast(instr); @@ -141,7 +134,6 @@ SelectPattern::Child SelectPattern::copy() const return std::move(ret); } -BasicBlockPattern::~BasicBlockPattern() = default; bool BasicBlockPattern::match(Value *instr, Captures &captures) const { auto *load_instr = llvm::dyn_cast(instr); @@ -160,7 +152,6 @@ BasicBlockPattern::Child BasicBlockPattern::copy() const return std::move(ret); } -SwitchPattern::~SwitchPattern() = default; bool SwitchPattern::match(Value *instr, Captures &captures) const { auto *load_instr = llvm::dyn_cast(instr); diff --git a/src/Passes/Source/Rules/Patterns/Instruction.hpp b/src/Passes/Source/Rules/Patterns/Instruction.hpp index 99f0b41df7..7e1c7c9cf1 100644 --- a/src/Passes/Source/Rules/Patterns/Instruction.hpp +++ b/src/Passes/Source/Rules/Patterns/Instruction.hpp @@ -2,98 +2,77 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -#include "Rules/IOperandPrototype.hpp" - #include "Llvm/Llvm.hpp" +#include "Rules/IOperandPrototype.hpp" #include #include -namespace microsoft -{ -namespace quantum -{ +namespace microsoft { +namespace quantum { - class StorePattern : public IOperandPrototype - { - public: - using IOperandPrototype::IOperandPrototype; - ~StorePattern() override; - bool match(Value* instr, Captures& captures) const override; - Child copy() const override; - }; +class StorePattern : public IOperandPrototype +{ +public: + bool match(Value *instr, Captures &captures) const override; + Child copy() const override; +}; - class LoadPattern : public IOperandPrototype - { - public: - using IOperandPrototype::IOperandPrototype; - ~LoadPattern() override; - bool match(Value* instr, Captures& captures) const override; - Child copy() const override; - }; +class LoadPattern : public IOperandPrototype +{ +public: + bool match(Value *instr, Captures &captures) const override; + Child copy() const override; +}; - class BitCastPattern : public IOperandPrototype - { - public: - using IOperandPrototype::IOperandPrototype; - ~BitCastPattern() override; - bool match(Value* instr, Captures& captures) const override; - Child copy() const override; - }; +class BitCastPattern : public IOperandPrototype +{ +public: + bool match(Value *instr, Captures &captures) const override; + Child copy() const override; +}; - class IntToPtrPattern : public IOperandPrototype - { - public: - using IOperandPrototype::IOperandPrototype; - ~IntToPtrPattern() override; - bool match(Value* instr, Captures& captures) const override; - Child copy() const override; - }; +class IntToPtrPattern : public IOperandPrototype +{ +public: + bool match(Value *instr, Captures &captures) const override; + Child copy() const override; +}; - class ConstIntPattern : public IOperandPrototype - { - public: - using IOperandPrototype::IOperandPrototype; - ~ConstIntPattern() override; - bool match(Value* instr, Captures& captures) const override; - Child copy() const override; - }; +class ConstIntPattern : public IOperandPrototype +{ +public: + bool match(Value *instr, Captures &captures) const override; + Child copy() const override; +}; - class BranchPattern : public IOperandPrototype - { - public: - using IOperandPrototype::IOperandPrototype; - ~BranchPattern() override; - bool match(Value* instr, Captures& captures) const override; - Child copy() const override; - }; +class BranchPattern : public IOperandPrototype +{ +public: + bool match(Value *instr, Captures &captures) const override; + Child copy() const override; +}; - class SelectPattern : public IOperandPrototype - { - public: - using IOperandPrototype::IOperandPrototype; - ~SelectPattern() override; - bool match(Value* instr, Captures& captures) const override; - Child copy() const override; - }; +class SelectPattern : public IOperandPrototype +{ +public: + bool match(Value *instr, Captures &captures) const override; + Child copy() const override; +}; - class BasicBlockPattern : public IOperandPrototype - { - public: - using IOperandPrototype::IOperandPrototype; - ~BasicBlockPattern() override; - bool match(Value* instr, Captures& captures) const override; - Child copy() const override; - }; +class BasicBlockPattern : public IOperandPrototype +{ +public: + bool match(Value *instr, Captures &captures) const override; + Child copy() const override; +}; - class SwitchPattern : public IOperandPrototype - { - public: - using IOperandPrototype::IOperandPrototype; - ~SwitchPattern() override; - bool match(Value* instr, Captures& captures) const override; - Child copy() const override; - }; +class SwitchPattern : public IOperandPrototype +{ +public: + bool match(Value *instr, Captures &captures) const override; + Child copy() const override; +}; -} // namespace quantum -} // namespace microsoft +} // namespace quantum +} // namespace microsoft From d8dcd6f8dc7c5218ce79770c6e061d21fa6702dc Mon Sep 17 00:00:00 2001 From: "Troels F. Roennow" Date: Mon, 8 Nov 2021 10:17:27 +0100 Subject: [PATCH 07/17] Formatting --- .../AllocationManager/IAllocationManager.hpp | 96 ++--- src/Passes/Source/Apps/Qat/QatConfig.hpp | 112 +++--- .../Commandline/ConfigurationManager.hpp | 363 ++++++++--------- src/Passes/Source/Commandline/IConfigBind.hpp | 169 ++++---- .../Source/Commandline/ParameterParser.hpp | 138 +++---- .../Source/Generators/ProfileGenerator.hpp | 232 +++++------ src/Passes/Source/Logging/ILogger.hpp | 72 ++-- .../Source/ModuleLoader/ModuleLoader.hpp | 238 +++++------ src/Passes/Source/Profile/Profile.hpp | 255 ++++++------ .../RemoveDisallowedAttributesPass.hpp | 92 +++-- src/Passes/Source/Rules/Factory.hpp | 367 ++++++++--------- .../Source/Rules/Notation/BasicBlock.cpp | 30 +- src/Passes/Source/Rules/Notation/BitCast.cpp | 32 +- src/Passes/Source/Rules/Notation/Branch.cpp | 40 +- src/Passes/Source/Rules/Notation/Call.hpp | 95 ++--- .../Source/Rules/Notation/CallByNameOnly.cpp | 30 +- src/Passes/Source/Rules/Notation/Capture.cpp | 53 +-- src/Passes/Source/Rules/Notation/ConstInt.cpp | 30 +- src/Passes/Source/Rules/Notation/IntToPtr.cpp | 32 +- src/Passes/Source/Rules/Notation/Load.cpp | 32 +- src/Passes/Source/Rules/Notation/Notation.cpp | 35 +- src/Passes/Source/Rules/Notation/Notation.hpp | 360 +++++++++-------- src/Passes/Source/Rules/Notation/Select.cpp | 40 +- src/Passes/Source/Rules/Notation/Store.cpp | 34 +- src/Passes/Source/Rules/Notation/Switch.cpp | 43 +- .../Source/Rules/Notation/UnnamedInvoke.cpp | 30 +- .../Source/Rules/Patterns/AnyPattern.cpp | 33 +- .../Source/Rules/Patterns/CallPattern.cpp | 84 ++-- .../Source/Rules/Patterns/CallPattern.hpp | 59 +-- .../Source/Rules/Patterns/Instruction.cpp | 339 ++++++++-------- .../Source/Rules/Patterns/Instruction.hpp | 121 +++--- .../Source/Rules/Patterns/PhiPattern.cpp | 45 ++- .../Rules/Patterns/UnnamedInvokePattern.cpp | 45 ++- src/Passes/Source/Rules/ReplacementRule.hpp | 98 ++--- .../TransformationRulesPass.hpp | 380 +++++++++--------- .../Source/ValidationPass/ValidationPass.hpp | 64 +-- .../ValidationPassConfiguration.hpp | 150 +++---- src/Passes/Source/Validator/Validator.cpp | 123 +++--- src/Passes/Source/Validator/Validator.hpp | 107 ++--- 39 files changed, 2412 insertions(+), 2286 deletions(-) diff --git a/src/Passes/Source/AllocationManager/IAllocationManager.hpp b/src/Passes/Source/AllocationManager/IAllocationManager.hpp index d9276f2721..a60fd0936a 100644 --- a/src/Passes/Source/AllocationManager/IAllocationManager.hpp +++ b/src/Passes/Source/AllocationManager/IAllocationManager.hpp @@ -7,63 +7,65 @@ #include #include -namespace microsoft { -namespace quantum { -/// Interface class for allocation management. This interface provides means to allocate and release -/// statically allocated resources such as qubits and results. In a future version, it may be -/// extended with get and store in order to support Arrays and Tuples. -class IAllocationManager +namespace microsoft { -public: - using Address = uint64_t; ///< Value type for address - using Index = uint64_t; ///< Index type used to access an array element. - using AllocationManagerPtr = std::shared_ptr; ///< Pointer interface. +namespace quantum +{ + /// Interface class for allocation management. This interface provides means to allocate and release + /// statically allocated resources such as qubits and results. In a future version, it may be + /// extended with get and store in order to support Arrays and Tuples. + class IAllocationManager + { + public: + using Address = uint64_t; ///< Value type for address + using Index = uint64_t; ///< Index type used to access an array element. + using AllocationManagerPtr = std::shared_ptr; ///< Pointer interface. - // Construction, moves and copies - // - IAllocationManager(IAllocationManager const &) = delete; - IAllocationManager(IAllocationManager &&) = delete; - IAllocationManager &operator=(IAllocationManager const &) = delete; - IAllocationManager &operator=(IAllocationManager &&) = delete; + // Construction, moves and copies + // + IAllocationManager(IAllocationManager const&) = delete; + IAllocationManager(IAllocationManager&&) = delete; + IAllocationManager& operator=(IAllocationManager const&) = delete; + IAllocationManager& operator=(IAllocationManager&&) = delete; - virtual ~IAllocationManager(); + virtual ~IAllocationManager(); - // Interface - // + // Interface + // - /// Abstract member function to allocate an element or sequence of elements. The developer - /// should not assume continuity of the address segment as this is not guaranteed. Note this - /// function may throw if allocation is not possible. - virtual Address allocate(String const &name = "", Index const &count = 1) = 0; + /// Abstract member function to allocate an element or sequence of elements. The developer + /// should not assume continuity of the address segment as this is not guaranteed. Note this + /// function may throw if allocation is not possible. + virtual Address allocate(String const& name = "", Index const& count = 1) = 0; - /// Abstract member function to release a previously allocated function. Note this function may - /// throw if an invalid address is passed. - virtual void release(Address const &address) = 0; + /// Abstract member function to release a previously allocated function. Note this function may + /// throw if an invalid address is passed. + virtual void release(Address const& address) = 0; - /// Abstract member function to reset the allocation manager. This function clears all allocations - /// and resets all statistics. - virtual void reset() = 0; + /// Abstract member function to reset the allocation manager. This function clears all allocations + /// and resets all statistics. + virtual void reset() = 0; - // Statistics - // + // Statistics + // - /// Current number of registers in use. This function is used to inquire about the current number - /// registers/resources in use. - uint64_t allocationsInUse() const; + /// Current number of registers in use. This function is used to inquire about the current number + /// registers/resources in use. + uint64_t allocationsInUse() const; - /// Maximum number of registers in use at any one time. The maximum number of registers used at - /// any one time. As an example of usage, this function is useful to calculate the total number of - /// qubits required to execute the entry function. - uint64_t maxAllocationsUsed() const; + /// Maximum number of registers in use at any one time. The maximum number of registers used at + /// any one time. As an example of usage, this function is useful to calculate the total number of + /// qubits required to execute the entry function. + uint64_t maxAllocationsUsed() const; -protected: - IAllocationManager() = default; - void updateRegistersInUse(uint64_t n); + protected: + IAllocationManager() = default; + void updateRegistersInUse(uint64_t n); -private: - uint64_t registers_in_use_{0}; ///< Used to track the number of registers in use - uint64_t max_registers_used_{0}; ///< Used to track the max number of registers used -}; + private: + uint64_t registers_in_use_{0}; ///< Used to track the number of registers in use + uint64_t max_registers_used_{0}; ///< Used to track the max number of registers used + }; -} // namespace quantum -} // namespace microsoft +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Apps/Qat/QatConfig.hpp b/src/Passes/Source/Apps/Qat/QatConfig.hpp index 849b2a0bc1..90b7d3aabd 100644 --- a/src/Passes/Source/Apps/Qat/QatConfig.hpp +++ b/src/Passes/Source/Apps/Qat/QatConfig.hpp @@ -5,75 +5,77 @@ #include "Commandline/ConfigurationManager.hpp" #include "QatTypes/QatTypes.hpp" -namespace microsoft { -namespace quantum { - -/// Main configuration class for the qat command-line program. -class QatConfig +namespace microsoft +{ +namespace quantum { -public: - // Functions required by configuration manager - // - /// Setup function that binds instance variables to the command-line/configuration entries. - /// This function also provide descriptions of each of the properties below. - void setup(ConfigurationManager &config); + /// Main configuration class for the qat command-line program. + class QatConfig + { + public: + // Functions required by configuration manager + // + + /// Setup function that binds instance variables to the command-line/configuration entries. + /// This function also provide descriptions of each of the properties below. + void setup(ConfigurationManager& config); - // Flags and options - // + // Flags and options + // - /// List of dynamic libraries to load. - String load() const; + /// List of dynamic libraries to load. + String load() const; - /// Flag that indicates whether or not we are generating a new QIR by applying a profile. - bool shouldGenerate() const; + /// Flag that indicates whether or not we are generating a new QIR by applying a profile. + bool shouldGenerate() const; - /// Flag to indicate whether or not to verify that the (Q)IR is a valid LLVM IR. - bool verifyModule() const; + /// Flag to indicate whether or not to verify that the (Q)IR is a valid LLVM IR. + bool verifyModule() const; - /// Flag to indicate whether or not to validate the compliance with the QIR profile. - bool shouldValidate() const; + /// Flag to indicate whether or not to validate the compliance with the QIR profile. + bool shouldValidate() const; - /// String to request a specific profile name. Default is base. - String profile() const; + /// String to request a specific profile name. Default is base. + String profile() const; - /// Indicates whether or not the QIR adaptor tool should emit LLVM IR to the standard output. - bool shouldEmitLlvm() const; + /// Indicates whether or not the QIR adaptor tool should emit LLVM IR to the standard output. + bool shouldEmitLlvm() const; - /// Tells if the optimisation level 0 is enabled. Note higher OX override lower ones. - bool isOpt0Enabled() const; + /// Tells if the optimisation level 0 is enabled. Note higher OX override lower ones. + bool isOpt0Enabled() const; - /// Tells if the optimisation level 1 is enabled. Note higher OX override lower ones. - bool isOpt1Enabled() const; + /// Tells if the optimisation level 1 is enabled. Note higher OX override lower ones. + bool isOpt1Enabled() const; - /// Tells if the optimisation level 2 is enabled. Note higher OX override lower ones. - bool isOpt2Enabled() const; + /// Tells if the optimisation level 2 is enabled. Note higher OX override lower ones. + bool isOpt2Enabled() const; - /// Tells if the optimisation level 3 is enabled. Note higher OX override lower ones. - bool isOpt3Enabled() const; + /// Tells if the optimisation level 3 is enabled. Note higher OX override lower ones. + bool isOpt3Enabled() const; - /// Enables debug output. - bool isDebugMode() const; + /// Enables debug output. + bool isDebugMode() const; - /// Request the full configuration to be dumped to the screen. - bool shouldDumpConfig() const; + /// Request the full configuration to be dumped to the screen. + bool shouldDumpConfig() const; -private: - // Variables to be bound to the configuration manager - // - String load_{""}; - bool generate_{false}; - bool validate_{false}; - String profile_{"generic"}; - bool emit_llvm_{false}; - bool opt0_{false}; - bool opt1_{false}; - bool opt2_{false}; - bool opt3_{false}; - bool verify_module_{false}; + private: + // Variables to be bound to the configuration manager + // + String load_{""}; + bool generate_{false}; + bool validate_{false}; + String profile_{"generic"}; + bool emit_llvm_{false}; + bool opt0_{false}; + bool opt1_{false}; + bool opt2_{false}; + bool opt3_{false}; + bool verify_module_{false}; - bool debug_{false}; - bool dump_config_{false}; -}; -} // namespace quantum -} // namespace microsoft + bool debug_{false}; + bool dump_config_{false}; + }; +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Commandline/ConfigurationManager.hpp b/src/Passes/Source/Commandline/ConfigurationManager.hpp index 845b735277..f228cfd2a1 100644 --- a/src/Passes/Source/Commandline/ConfigurationManager.hpp +++ b/src/Passes/Source/Commandline/ConfigurationManager.hpp @@ -5,211 +5,204 @@ #include "Commandline/ConfigBind.hpp" #include "Commandline/IConfigBind.hpp" #include "Commandline/ParameterParser.hpp" -#include "Llvm/Llvm.hpp" #include "QatTypes/QatTypes.hpp" +#include "Llvm/Llvm.hpp" + #include #include #include #include #include -namespace microsoft { -namespace quantum { - -/// ConfigurationManager is a class that holds a collection of configurations (sections). Each of -/// these sections are embodied in their own class with a one-to-one mapping between configuration -/// section and the configuration type. As an example, if one wishes to make a configuration for the -/// class Foo, one would create a class FooConfig which would hold all the variables that are -/// configurable and then add FooConfig to the ConfigurationManager using `addConfig()`. For -/// FooConfig to fulfill the concept of a configuration, it must implement a setup functions whose -/// first argument is the ConfigurationManager. -class ConfigurationManager +namespace microsoft { -public: - using IConfigBindPtr = - std::shared_ptr; ///< Pointer class used to bind a parameter to a value. - using ConfigList = std::vector; ///< List of bound variables. - using VoidPtr = std::shared_ptr; ///< Type-erased configuration pointer. - using TypeId = std::type_index; ///< Type index class. - using BoolPtr = std::shared_ptr; - - /// Section defines a section in the configuration. It holds the type of the configuration class, - /// the name of the section a description, the instance of the configuration class itself and list - /// of parameter bindings. - struct Section - { - TypeId type{TypeId(typeid(std::nullptr_t))}; ///< Type of the configuration. - String name{}; ///< Name of the section. - String description{}; ///< Description of the section. - VoidPtr configuration{}; ///< Configuration class instance. - ConfigList settings{}; ///< List of parameter bindings. - BoolPtr active{nullptr}; ///< Whether or not this component is active; - String id{}; ///< Id referring to this component. - }; - using Sections = std::vector
; ///< List of available sections - - // Constructors, copy and move operators, destructor - // - - /// Configuration manager is default constructible, non-copyable and non-movable. - ConfigurationManager() = default; - ConfigurationManager(ConfigurationManager const &) = delete; - ConfigurationManager(ConfigurationManager &&) = delete; - ConfigurationManager &operator=(ConfigurationManager const &) = delete; - ConfigurationManager &operator=(ConfigurationManager &&) = delete; - - // Configuration setup - // - - /// Adds all bound variables as parser arguments. - void setupArguments(ParameterParser &parser); - - /// Configures the value of each bound variable given a parser instance. - void configure(ParameterParser const &parser); - - // Managing configuration - // - - /// Given an instance of the ConfigurationManager, this method override settings of class T. - template - inline void setConfig(T const &value); - - /// Gets the configuration instance of type T. - template - inline T const &get() const; - - // Support functions - // - - /// Prints options for configurability to the terminal. - void printHelp() const; - - /// Prints the configuration to the terminal. The configuration print is LLVM IR compatible - /// meaning that every line starts with a semicolon ; to ensure that it is interpreted as a - /// comment. - void printConfiguration() const; - - // Configuration functions - // - - /// Adds a new configuration of type T. - template - inline void addConfig(String const &id = "", T const &default_value = T()); - - /// Whether or not the component associated with T is active. - template - inline bool isActive(); - - /// Sets the section name. This method is used by the configuration class to set a section - /// name. - void setSectionName(String const &name, String const &description); - - /// Adds a new parameter with a default value to the configuration section. This function should - /// be used by the configuration class. - template - inline void addParameter(T &bind, T default_value, String const &name, String const &description); - - /// Adds a new parameter to the configuration section. This method uses the bound variable value - /// as default value. This function should be used by the configuration class. - template - inline void addParameter(T &bind, String const &name, String const &description); - -private: - /// Helper function to get a reference to the configuration of type T. - template - inline T &getInternal() const; - - Sections config_sections_{}; ///< All available sections within the ConfigurationManager instance -}; - -template -inline void ConfigurationManager::addConfig(String const &id, T const &default_value) +namespace quantum { - Section new_section{std::type_index(typeid(T))}; - auto ptr = std::make_shared(default_value); - new_section.configuration = ptr; - new_section.active = std::make_shared(true); - new_section.id = id; + /// ConfigurationManager is a class that holds a collection of configurations (sections). Each of + /// these sections are embodied in their own class with a one-to-one mapping between configuration + /// section and the configuration type. As an example, if one wishes to make a configuration for the + /// class Foo, one would create a class FooConfig which would hold all the variables that are + /// configurable and then add FooConfig to the ConfigurationManager using `addConfig()`. For + /// FooConfig to fulfill the concept of a configuration, it must implement a setup functions whose + /// first argument is the ConfigurationManager. + class ConfigurationManager + { + public: + using IConfigBindPtr = std::shared_ptr; ///< Pointer class used to bind a parameter to a value. + using ConfigList = std::vector; ///< List of bound variables. + using VoidPtr = std::shared_ptr; ///< Type-erased configuration pointer. + using TypeId = std::type_index; ///< Type index class. + using BoolPtr = std::shared_ptr; + + /// Section defines a section in the configuration. It holds the type of the configuration class, + /// the name of the section a description, the instance of the configuration class itself and list + /// of parameter bindings. + struct Section + { + TypeId type{TypeId(typeid(std::nullptr_t))}; ///< Type of the configuration. + String name{}; ///< Name of the section. + String description{}; ///< Description of the section. + VoidPtr configuration{}; ///< Configuration class instance. + ConfigList settings{}; ///< List of parameter bindings. + BoolPtr active{nullptr}; ///< Whether or not this component is active; + String id{}; ///< Id referring to this component. + }; + using Sections = std::vector
; ///< List of available sections + + // Constructors, copy and move operators, destructor + // + + /// Configuration manager is default constructible, non-copyable and non-movable. + ConfigurationManager() = default; + ConfigurationManager(ConfigurationManager const&) = delete; + ConfigurationManager(ConfigurationManager&&) = delete; + ConfigurationManager& operator=(ConfigurationManager const&) = delete; + ConfigurationManager& operator=(ConfigurationManager&&) = delete; + + // Configuration setup + // + + /// Adds all bound variables as parser arguments. + void setupArguments(ParameterParser& parser); + + /// Configures the value of each bound variable given a parser instance. + void configure(ParameterParser const& parser); + + // Managing configuration + // + + /// Given an instance of the ConfigurationManager, this method override settings of class T. + template inline void setConfig(T const& value); + + /// Gets the configuration instance of type T. + template inline T const& get() const; + + // Support functions + // + + /// Prints options for configurability to the terminal. + void printHelp() const; + + /// Prints the configuration to the terminal. The configuration print is LLVM IR compatible + /// meaning that every line starts with a semicolon ; to ensure that it is interpreted as a + /// comment. + void printConfiguration() const; + + // Configuration functions + // + + /// Adds a new configuration of type T. + template inline void addConfig(String const& id = "", T const& default_value = T()); + + /// Whether or not the component associated with T is active. + template inline bool isActive(); + + /// Sets the section name. This method is used by the configuration class to set a section + /// name. + void setSectionName(String const& name, String const& description); + + /// Adds a new parameter with a default value to the configuration section. This function should + /// be used by the configuration class. + template + inline void addParameter(T& bind, T default_value, String const& name, String const& description); + + /// Adds a new parameter to the configuration section. This method uses the bound variable value + /// as default value. This function should be used by the configuration class. + template inline void addParameter(T& bind, String const& name, String const& description); + + private: + /// Helper function to get a reference to the configuration of type T. + template inline T& getInternal() const; + + Sections config_sections_{}; ///< All available sections within the ConfigurationManager instance + }; + + template inline void ConfigurationManager::addConfig(String const& id, T const& default_value) + { + Section new_section{std::type_index(typeid(T))}; - config_sections_.emplace_back(std::move(new_section)); - ptr->setup(*this); -} + auto ptr = std::make_shared(default_value); + new_section.configuration = ptr; + new_section.active = std::make_shared(true); + new_section.id = id; -template -inline T &ConfigurationManager::getInternal() const -{ - VoidPtr ptr{nullptr}; - auto type = std::type_index(typeid(T)); + config_sections_.emplace_back(std::move(new_section)); + ptr->setup(*this); + } - for (auto §ion : config_sections_) - { - if (section.type == type) + template inline T& ConfigurationManager::getInternal() const { - ptr = section.configuration; - break; + VoidPtr ptr{nullptr}; + auto type = std::type_index(typeid(T)); + + for (auto& section : config_sections_) + { + if (section.type == type) + { + ptr = section.configuration; + break; + } + } + + if (ptr == nullptr) + { + throw std::runtime_error("Could not find configuration class."); + } + + return *static_cast(ptr.get()); } - } - - if (ptr == nullptr) - { - throw std::runtime_error("Could not find configuration class."); - } - - return *static_cast(ptr.get()); -} - -template -inline void ConfigurationManager::setConfig(T const &value) -{ - auto &config = getInternal(); - config = value; -} - -template -inline T const &ConfigurationManager::get() const -{ - return getInternal(); -} -template -inline bool ConfigurationManager::isActive() -{ - BoolPtr ptr{nullptr}; - auto type = std::type_index(typeid(T)); - - for (auto §ion : config_sections_) - { - if (section.type == type) + template inline void ConfigurationManager::setConfig(T const& value) { - ptr = section.active; - break; + auto& config = getInternal(); + config = value; } - } - if (ptr == nullptr) - { - throw std::runtime_error("Could not find configuration class."); - } + template inline T const& ConfigurationManager::get() const + { + return getInternal(); + } - return *ptr; -} + template inline bool ConfigurationManager::isActive() + { + BoolPtr ptr{nullptr}; + auto type = std::type_index(typeid(T)); + + for (auto& section : config_sections_) + { + if (section.type == type) + { + ptr = section.active; + break; + } + } + + if (ptr == nullptr) + { + throw std::runtime_error("Could not find configuration class."); + } + + return *ptr; + } -template -inline void ConfigurationManager::addParameter(T &bind, T default_value, String const &name, - String const &description) -{ - auto ptr = std::make_shared>(bind, default_value, name, description); - config_sections_.back().settings.push_back(ptr); -} + template + inline void ConfigurationManager::addParameter( + T& bind, + T default_value, + String const& name, + String const& description) + { + auto ptr = std::make_shared>(bind, default_value, name, description); + config_sections_.back().settings.push_back(ptr); + } -template -inline void ConfigurationManager::addParameter(T &bind, String const &name, - String const &description) -{ - auto ptr = std::make_shared>(bind, T(bind), name, description); - config_sections_.back().settings.push_back(ptr); -} -} // namespace quantum -} // namespace microsoft + template + inline void ConfigurationManager::addParameter(T& bind, String const& name, String const& description) + { + auto ptr = std::make_shared>(bind, T(bind), name, description); + config_sections_.back().settings.push_back(ptr); + } +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Commandline/IConfigBind.hpp b/src/Passes/Source/Commandline/IConfigBind.hpp index 149b3d7fea..2153eac7d6 100644 --- a/src/Passes/Source/Commandline/IConfigBind.hpp +++ b/src/Passes/Source/Commandline/IConfigBind.hpp @@ -3,95 +3,98 @@ // Licensed under the MIT License. #include "Commandline/ParameterParser.hpp" -#include "Llvm/Llvm.hpp" #include "QatTypes/QatTypes.hpp" +#include "Llvm/Llvm.hpp" + #include #include #include #include #include -namespace microsoft { -namespace quantum { - -/// Interface class to bind a variable to a configuration flag. This class provides -/// the necessary interface to bind variables and populate their value based on given command-line -/// arguments. -class IConfigBind +namespace microsoft +{ +namespace quantum { -public: - // Deleted constructors and deleted operators - // - // Strictly speaking the code would remain correct if we allowed copy and/or move, but - // we have chosen to ban them by choice as potential bugs arising from allowing copy and/or - // move can be difficult to find. We consider this behaviour a part of the interface definition. - IConfigBind(IConfigBind const &) = delete; - IConfigBind(IConfigBind &&) = delete; - IConfigBind &operator=(IConfigBind const &) = delete; - IConfigBind &operator=(IConfigBind &&) = delete; - - // Virtual destructor - // - virtual ~IConfigBind(); - - // Interface - // - - /// Interface function to register configuration in the parser. This function - /// register the configuration to the parameter parser. This makes the configuration - /// available in the parameter parsers help function. This method should return true if arguments - /// were successfully setup. - virtual bool setupArguments(ParameterParser &parser) = 0; - - /// Interface function to extract configuration from the command line arguments. Given an instance - /// of the command line parameter parser, this function is meant to read the command line - /// arguments, interpret it and set the bound variable value (if present). This method should - /// return true if configure operation was successful. - virtual bool configure(ParameterParser const &parser) = 0; - - /// Interface function to return a string representation of the current value of the - /// bound variable. - virtual String value() = 0; - - // Properties - // - - /// Returns the name of the bound configuration variable. - String name() const; - - /// Returns the description of the configuration variable. - String description() const; - - /// Indicates whether or not this - bool isFlag() const; - - /// Returns the default value for the flag. - String defaultValue() const; - -protected: - // Constructor - // - IConfigBind(String const &name, String const &description); - - // Configuration - // - - /// Sets the name of the configuration variable. - void setName(String const &name); - - /// Marks the variable as a flag. - void markAsFlag(); - - /// Sets the default value as a string. - void setDefault(String const &v); - -private: - String name_; ///< Name that which sets the value. - String description_; ///< Description of the option or flag. - bool is_flag_{false}; ///< Whether or not the variable is a flag. - String str_default_value_; ///< Default value represented as a string. -}; - -} // namespace quantum -} // namespace microsoft + + /// Interface class to bind a variable to a configuration flag. This class provides + /// the necessary interface to bind variables and populate their value based on given command-line + /// arguments. + class IConfigBind + { + public: + // Deleted constructors and deleted operators + // + // Strictly speaking the code would remain correct if we allowed copy and/or move, but + // we have chosen to ban them by choice as potential bugs arising from allowing copy and/or + // move can be difficult to find. We consider this behaviour a part of the interface definition. + IConfigBind(IConfigBind const&) = delete; + IConfigBind(IConfigBind&&) = delete; + IConfigBind& operator=(IConfigBind const&) = delete; + IConfigBind& operator=(IConfigBind&&) = delete; + + // Virtual destructor + // + virtual ~IConfigBind(); + + // Interface + // + + /// Interface function to register configuration in the parser. This function + /// register the configuration to the parameter parser. This makes the configuration + /// available in the parameter parsers help function. This method should return true if arguments + /// were successfully setup. + virtual bool setupArguments(ParameterParser& parser) = 0; + + /// Interface function to extract configuration from the command line arguments. Given an instance + /// of the command line parameter parser, this function is meant to read the command line + /// arguments, interpret it and set the bound variable value (if present). This method should + /// return true if configure operation was successful. + virtual bool configure(ParameterParser const& parser) = 0; + + /// Interface function to return a string representation of the current value of the + /// bound variable. + virtual String value() = 0; + + // Properties + // + + /// Returns the name of the bound configuration variable. + String name() const; + + /// Returns the description of the configuration variable. + String description() const; + + /// Indicates whether or not this + bool isFlag() const; + + /// Returns the default value for the flag. + String defaultValue() const; + + protected: + // Constructor + // + IConfigBind(String const& name, String const& description); + + // Configuration + // + + /// Sets the name of the configuration variable. + void setName(String const& name); + + /// Marks the variable as a flag. + void markAsFlag(); + + /// Sets the default value as a string. + void setDefault(String const& v); + + private: + String name_; ///< Name that which sets the value. + String description_; ///< Description of the option or flag. + bool is_flag_{false}; ///< Whether or not the variable is a flag. + String str_default_value_; ///< Default value represented as a string. + }; + +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Commandline/ParameterParser.hpp b/src/Passes/Source/Commandline/ParameterParser.hpp index 5fe5599e37..faf0bef17e 100644 --- a/src/Passes/Source/Commandline/ParameterParser.hpp +++ b/src/Passes/Source/Commandline/ParameterParser.hpp @@ -9,93 +9,95 @@ #include #include -namespace microsoft { -namespace quantum { - -/// Parameter parser class which allows the developer to specify a set of default settings and -/// update those using the commandline argc and argv. -class ParameterParser +namespace microsoft +{ +namespace quantum { -public: - using Arguments = std::vector; - using Flags = std::unordered_set; - using SettingsMap = std::unordered_map; - // Construction and deconstrution configuration - // + /// Parameter parser class which allows the developer to specify a set of default settings and + /// update those using the commandline argc and argv. + class ParameterParser + { + public: + using Arguments = std::vector; + using Flags = std::unordered_set; + using SettingsMap = std::unordered_map; + + // Construction and deconstrution configuration + // - ParameterParser() = default; + ParameterParser() = default; - // No copy construction. - ParameterParser(ParameterParser const &other) = delete; + // No copy construction. + ParameterParser(ParameterParser const& other) = delete; - // Allow move semantics. - ParameterParser(ParameterParser &&other) = default; + // Allow move semantics. + ParameterParser(ParameterParser&& other) = default; - // Default destruction. - ~ParameterParser() = default; + // Default destruction. + ~ParameterParser() = default; - // Configuration - // + // Configuration + // - /// Marks a name as a flag (as opposed to an option). - /// This ensures that no parameter is expected after - /// the flag is specified. For instance `--debug` is - /// a flag as opposed to `--log-level 3` which is an - /// option. - void addFlag(String const &v); + /// Marks a name as a flag (as opposed to an option). + /// This ensures that no parameter is expected after + /// the flag is specified. For instance `--debug` is + /// a flag as opposed to `--log-level 3` which is an + /// option. + void addFlag(String const& v); - // Operation - // + // Operation + // - /// Parses the command line arguments given the argc and argv - /// from the main function. - void parseArgs(int argc, char **argv); + /// Parses the command line arguments given the argc and argv + /// from the main function. + void parseArgs(int argc, char** argv); - /// Returns list of arguments without flags and/or options - /// included. - Arguments const &arguments() const; + /// Returns list of arguments without flags and/or options + /// included. + Arguments const& arguments() const; - /// Returns the n'th commandline argument. - String const &getArg(Arguments::size_type const &n) const; + /// Returns the n'th commandline argument. + String const& getArg(Arguments::size_type const& n) const; - /// Gets a named setting, falling back to a default if the key is not found. - String const &get(String const &name, String const &default_value) const noexcept; + /// Gets a named setting, falling back to a default if the key is not found. + String const& get(String const& name, String const& default_value) const noexcept; - /// Gets a named setting. This method throws if the setting is not present. - String const &get(String const &name) const; + /// Gets a named setting. This method throws if the setting is not present. + String const& get(String const& name) const; - /// Checks whether or not a given parameter is present. - bool has(String const &name) const noexcept; + /// Checks whether or not a given parameter is present. + bool has(String const& name) const noexcept; - /// Resets the state of the parser to its construction state - void reset(); + /// Resets the state of the parser to its construction state + void reset(); -private: - /// Struct that contains parsed and interpreted values of command line arguments. - struct ParsedValue - { - bool is_key{false}; ///< Whether or not a parsed value should be considered a key - String value; ///< Value after parsing. - }; + private: + /// Struct that contains parsed and interpreted values of command line arguments. + struct ParsedValue + { + bool is_key{false}; ///< Whether or not a parsed value should be considered a key + String value; ///< Value after parsing. + }; - // Helper functions - // + // Helper functions + // - // Parses a single argument and returns the parsed value. This function - // determines if the string was specified to be a key or a value. - ParsedValue parseSingleArg(String key); + // Parses a single argument and returns the parsed value. This function + // determines if the string was specified to be a key or a value. + ParsedValue parseSingleArg(String key); - /// Checks whether a key is an option (or a flag). Returns true if it is - /// and option and false if it is a flags. - bool isOption(String const &key); + /// Checks whether a key is an option (or a flag). Returns true if it is + /// and option and false if it is a flags. + bool isOption(String const& key); - // Storage of parsed data - // - Flags flags_{}; ///< Set of flags - Arguments arguments_{}; ///< List of remaining arguments - SettingsMap settings_; ///< Settings map that keeps all specified settings. -}; + // Storage of parsed data + // + Flags flags_{}; ///< Set of flags + Arguments arguments_{}; ///< List of remaining arguments + SettingsMap settings_; ///< Settings map that keeps all specified settings. + }; -} // namespace quantum -} // namespace microsoft +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Generators/ProfileGenerator.hpp b/src/Passes/Source/Generators/ProfileGenerator.hpp index 4cfb9db5a0..5c36224041 100644 --- a/src/Passes/Source/Generators/ProfileGenerator.hpp +++ b/src/Passes/Source/Generators/ProfileGenerator.hpp @@ -3,129 +3,131 @@ // Licensed under the MIT License. #include "Commandline/ConfigurationManager.hpp" -#include "Llvm/Llvm.hpp" #include "Profile/Profile.hpp" #include "QatTypes/QatTypes.hpp" -namespace microsoft { -namespace quantum { +#include "Llvm/Llvm.hpp" -class ProfileGenerator +namespace microsoft { -public: - // LLVM types - // - using PassBuilder = llvm::PassBuilder; - using OptimizationLevel = PassBuilder::OptimizationLevel; - using FunctionAnalysisManager = llvm::FunctionAnalysisManager; - - /// Setup function that uses a configuration type R to - /// configure the profile and/or generator. - template - using SetupFunction = std::function; - - /// Wrapper function type for invoking the profile setup function - using SetupFunctionWrapper = std::function; - - /// List of components to be configured. - using Components = std::vector>; - - // Construction, moves and copies - // - - ProfileGenerator() = default; - ~ProfileGenerator() = default; - ProfileGenerator(ProfileGenerator const &) = delete; - ProfileGenerator(ProfileGenerator &&) = delete; - ProfileGenerator &operator=(ProfileGenerator const &) = delete; - ProfileGenerator &operator=(ProfileGenerator &&) = delete; - - // Profile generation interface - // - - /// Reference to configuration manager. This property allows to access and modify configurations - /// of the generator. This property is intended for managing the configuration. - ConfigurationManager &configurationManager(); - - /// Constant reference to the configuration manager. This property allows read access to the - /// configuration manager and is intended for profile generation. - ConfigurationManager const &configurationManager() const; - - /// Creates a new profile based on the registered components, optimisation level and debug - /// requirements. The returned profile can be applied to an IR to transform it in accordance with - /// the configurations given. - Profile newProfile(String const &name, OptimizationLevel const &optimisation_level, bool debug); - - // Defining the generator - // - - /// Registers a new profile component with a given configuration R. The profile component is given - /// a name and a setup function which is responsible for configuring the profile in accordance - /// with the configuration. - template - void registerProfileComponent(String const &id, SetupFunction setup); - - // Support properties for generators - // - - /// Returns the module pass manager. - llvm::ModulePassManager &modulePassManager(); - - /// Returns the pass builder. - llvm::PassBuilder &passBuilder(); - - /// Returns the optimisation level. - OptimizationLevel optimisationLevel() const; - - /// Flag indicating whether we are operating in debug mode or not. - bool isDebugMode() const; - -protected: - /// Internal function that creates a module pass for QIR transformation. The module pass is - /// defined through the profile, the optimisation level and whether or not we are in debug mode. - llvm::ModulePassManager createGenerationModulePassManager( - Profile &profile, OptimizationLevel const &optimisation_level, bool debug); - - /// Internal function that creates a module pass for QIR validation. At the moment, this function - /// is a placeholder for future functionality. - llvm::ModulePassManager createValidationModulePass(PassBuilder & pass_builder, - OptimizationLevel const &optimisation_level, - bool debug); - -private: - ConfigurationManager - configuration_manager_; ///< Holds the configuration that defines the profile - Components components_; ///< List of registered components that configures the profile - - /// Pointer to the module pass manager the profile will use - llvm::ModulePassManager *module_pass_manager_{nullptr}; - - /// Pointer to the pass builder the profile is based on - llvm::PassBuilder *pass_builder_{nullptr}; - - /// Optimisation level used by LLVM - OptimizationLevel optimisation_level_{OptimizationLevel::O0}; - - /// Whether or not we are in debug mode - bool debug_{false}; -}; - -template -void ProfileGenerator::registerProfileComponent(String const &id, SetupFunction setup) +namespace quantum { - configuration_manager_.addConfig(id); - auto setup_wrapper = [setup](ProfileGenerator *ptr, Profile &profile) { - if (ptr->configuration_manager_.isActive()) + class ProfileGenerator { - auto &config = ptr->configuration_manager_.get(); + public: + // LLVM types + // + using PassBuilder = llvm::PassBuilder; + using OptimizationLevel = PassBuilder::OptimizationLevel; + using FunctionAnalysisManager = llvm::FunctionAnalysisManager; - setup(config, ptr, profile); - } - }; + /// Setup function that uses a configuration type R to + /// configure the profile and/or generator. + template using SetupFunction = std::function; + + /// Wrapper function type for invoking the profile setup function + using SetupFunctionWrapper = std::function; + + /// List of components to be configured. + using Components = std::vector>; + + // Construction, moves and copies + // + + ProfileGenerator() = default; + ~ProfileGenerator() = default; + ProfileGenerator(ProfileGenerator const&) = delete; + ProfileGenerator(ProfileGenerator&&) = delete; + ProfileGenerator& operator=(ProfileGenerator const&) = delete; + ProfileGenerator& operator=(ProfileGenerator&&) = delete; + + // Profile generation interface + // + + /// Reference to configuration manager. This property allows to access and modify configurations + /// of the generator. This property is intended for managing the configuration. + ConfigurationManager& configurationManager(); + + /// Constant reference to the configuration manager. This property allows read access to the + /// configuration manager and is intended for profile generation. + ConfigurationManager const& configurationManager() const; + + /// Creates a new profile based on the registered components, optimisation level and debug + /// requirements. The returned profile can be applied to an IR to transform it in accordance with + /// the configurations given. + Profile newProfile(String const& name, OptimizationLevel const& optimisation_level, bool debug); + + // Defining the generator + // + + /// Registers a new profile component with a given configuration R. The profile component is given + /// a name and a setup function which is responsible for configuring the profile in accordance + /// with the configuration. + template void registerProfileComponent(String const& id, SetupFunction setup); + + // Support properties for generators + // + + /// Returns the module pass manager. + llvm::ModulePassManager& modulePassManager(); - components_.push_back({id, std::move(setup_wrapper)}); -} + /// Returns the pass builder. + llvm::PassBuilder& passBuilder(); + + /// Returns the optimisation level. + OptimizationLevel optimisationLevel() const; + + /// Flag indicating whether we are operating in debug mode or not. + bool isDebugMode() const; + + protected: + /// Internal function that creates a module pass for QIR transformation. The module pass is + /// defined through the profile, the optimisation level and whether or not we are in debug mode. + llvm::ModulePassManager createGenerationModulePassManager( + Profile& profile, + OptimizationLevel const& optimisation_level, + bool debug); + + /// Internal function that creates a module pass for QIR validation. At the moment, this function + /// is a placeholder for future functionality. + llvm::ModulePassManager createValidationModulePass( + PassBuilder& pass_builder, + OptimizationLevel const& optimisation_level, + bool debug); + + private: + ConfigurationManager configuration_manager_; ///< Holds the configuration that defines the profile + Components components_; ///< List of registered components that configures the profile + + /// Pointer to the module pass manager the profile will use + llvm::ModulePassManager* module_pass_manager_{nullptr}; + + /// Pointer to the pass builder the profile is based on + llvm::PassBuilder* pass_builder_{nullptr}; + + /// Optimisation level used by LLVM + OptimizationLevel optimisation_level_{OptimizationLevel::O0}; + + /// Whether or not we are in debug mode + bool debug_{false}; + }; + + template void ProfileGenerator::registerProfileComponent(String const& id, SetupFunction setup) + { + configuration_manager_.addConfig(id); + + auto setup_wrapper = [setup](ProfileGenerator* ptr, Profile& profile) { + if (ptr->configuration_manager_.isActive()) + { + auto& config = ptr->configuration_manager_.get(); + + setup(config, ptr, profile); + } + }; + + components_.push_back({id, std::move(setup_wrapper)}); + } -} // namespace quantum -} // namespace microsoft +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Logging/ILogger.hpp b/src/Passes/Source/Logging/ILogger.hpp index 738124137d..e2db436aa7 100644 --- a/src/Passes/Source/Logging/ILogger.hpp +++ b/src/Passes/Source/Logging/ILogger.hpp @@ -7,49 +7,51 @@ #include #include -namespace microsoft { -namespace quantum { - -/// Logger interface to allow the collection of different types of messages during QIR -/// transformation and/or validation. -class ILogger +namespace microsoft +{ +namespace quantum { -public: - // Constructors, copy and move operators and destructors - // - ILogger() = default; - ILogger(ILogger const &) = default; - ILogger(ILogger &&) = default; - ILogger &operator=(ILogger const &) = default; - ILogger &operator=(ILogger &&) = default; + /// Logger interface to allow the collection of different types of messages during QIR + /// transformation and/or validation. + class ILogger + { + public: + // Constructors, copy and move operators and destructors + // + + ILogger() = default; + ILogger(ILogger const&) = default; + ILogger(ILogger&&) = default; + ILogger& operator=(ILogger const&) = default; + ILogger& operator=(ILogger&&) = default; - virtual ~ILogger() = default; + virtual ~ILogger() = default; - // Abstract interface methods - // + // Abstract interface methods + // - /// Reports a debug message. - virtual void debug(String const &message) = 0; + /// Reports a debug message. + virtual void debug(String const& message) = 0; - /// Reports an info message. - virtual void info(String const &message) = 0; + /// Reports an info message. + virtual void info(String const& message) = 0; - /// Reports a warning message. - virtual void warning(String const &message) = 0; + /// Reports a warning message. + virtual void warning(String const& message) = 0; - /// Reports an error message. - virtual void error(String const &message) = 0; + /// Reports an error message. + virtual void error(String const& message) = 0; - /// Reports an internal error message. - virtual void internalError(String const &message) = 0; + /// Reports an internal error message. + virtual void internalError(String const& message) = 0; - /// Sets the current location. Importantly, the location can be set independently of the reported - /// messages. This allows one to update the location upon updating the cursor position without - /// having to worry about keeping a copy of the location to pass when reporting messages. - /// The most obvious case of this is file path (name) with a line and character (row, col). - virtual void setLocation(String const &name, uint64_t row, uint64_t col) = 0; -}; + /// Sets the current location. Importantly, the location can be set independently of the reported + /// messages. This allows one to update the location upon updating the cursor position without + /// having to worry about keeping a copy of the location to pass when reporting messages. + /// The most obvious case of this is file path (name) with a line and character (row, col). + virtual void setLocation(String const& name, uint64_t row, uint64_t col) = 0; + }; -} // namespace quantum -} // namespace microsoft +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/ModuleLoader/ModuleLoader.hpp b/src/Passes/Source/ModuleLoader/ModuleLoader.hpp index e03151c52c..b83983004d 100644 --- a/src/Passes/Source/ModuleLoader/ModuleLoader.hpp +++ b/src/Passes/Source/ModuleLoader/ModuleLoader.hpp @@ -2,126 +2,132 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -#include "Llvm/Llvm.hpp" #include "QatTypes/QatTypes.hpp" #include "RemoveDisallowedAttributesPass/RemoveDisallowedAttributesPass.hpp" -namespace microsoft { -namespace quantum { +#include "Llvm/Llvm.hpp" -class ModuleLoader +namespace microsoft +{ +namespace quantum { -public: - using Module = llvm::Module; - using Linker = llvm::Linker; - using SMDiagnostic = llvm::SMDiagnostic; - - explicit ModuleLoader(Module *final_module) - : final_module_{final_module} - , linker_{*final_module} - - {} - - bool addModule(std::unique_ptr &&module, String const &filename = "unknown") - { - if (llvm::verifyModule(*module, &llvm::errs())) - { - llvm::errs() << filename << ": " - << "input module is broken!\n"; - return false; - } - - return !linker_.linkInModule(std::move(module), Linker::Flags::None); - } - - bool addIrFile(String const &filename) - { - - // Loading module - SMDiagnostic err; - std::unique_ptr module = llvm::parseIRFile(filename, err, final_module_->getContext()); - if (!module) - { - llvm::errs() << "Failed to load " << filename << "\n"; - return false; - } - - // Transforming module - SingleModuleTransformation transformation; - if (!transformation.apply(module.get())) - { - llvm::errs() << "Failed to transform " << filename << "\n"; - return false; - } - - // Linking - return addModule(std::move(module), filename); - } - -private: - Module *final_module_; - Linker linker_; - - // Single Module Transformation - // - - class SingleModuleTransformation - { - public: - using PassBuilder = llvm::PassBuilder; - using OptimizationLevel = PassBuilder::OptimizationLevel; - using FunctionAnalysisManager = llvm::FunctionAnalysisManager; - - explicit SingleModuleTransformation( - OptimizationLevel const &optimisation_level = OptimizationLevel::O0, bool debug = false) - : loop_analysis_manager_{debug} - , function_analysis_manager_{debug} - , gscc_analysis_manager_{debug} - , module_analysis_manager_{debug} - , optimisation_level_{optimisation_level} - , debug_{debug} - { - - pass_builder_.registerModuleAnalyses(module_analysis_manager_); - pass_builder_.registerCGSCCAnalyses(gscc_analysis_manager_); - pass_builder_.registerFunctionAnalyses(function_analysis_manager_); - pass_builder_.registerLoopAnalyses(loop_analysis_manager_); - - pass_builder_.crossRegisterProxies(loop_analysis_manager_, function_analysis_manager_, - gscc_analysis_manager_, module_analysis_manager_); - - module_pass_manager_.addPass(RemoveDisallowedAttributesPass()); - } - - bool apply(llvm::Module *module) - { - module_pass_manager_.run(*module, module_analysis_manager_); - - if (llvm::verifyModule(*module, &llvm::errs())) - { - return false; - } - - return true; - } - bool isDebugMode() const + class ModuleLoader { - return debug_; - } - - private: - llvm::PassBuilder pass_builder_; - llvm::LoopAnalysisManager loop_analysis_manager_; - llvm::FunctionAnalysisManager function_analysis_manager_; - llvm::CGSCCAnalysisManager gscc_analysis_manager_; - llvm::ModuleAnalysisManager module_analysis_manager_; - - llvm::ModulePassManager module_pass_manager_{}; - OptimizationLevel optimisation_level_{}; - bool debug_{false}; - }; -}; - -} // namespace quantum -} // namespace microsoft + public: + using Module = llvm::Module; + using Linker = llvm::Linker; + using SMDiagnostic = llvm::SMDiagnostic; + + explicit ModuleLoader(Module* final_module) + : final_module_{final_module} + , linker_{*final_module} + + { + } + + bool addModule(std::unique_ptr&& module, String const& filename = "unknown") + { + if (llvm::verifyModule(*module, &llvm::errs())) + { + llvm::errs() << filename << ": " + << "input module is broken!\n"; + return false; + } + + return !linker_.linkInModule(std::move(module), Linker::Flags::None); + } + + bool addIrFile(String const& filename) + { + + // Loading module + SMDiagnostic err; + std::unique_ptr module = llvm::parseIRFile(filename, err, final_module_->getContext()); + if (!module) + { + llvm::errs() << "Failed to load " << filename << "\n"; + return false; + } + + // Transforming module + SingleModuleTransformation transformation; + if (!transformation.apply(module.get())) + { + llvm::errs() << "Failed to transform " << filename << "\n"; + return false; + } + + // Linking + return addModule(std::move(module), filename); + } + + private: + Module* final_module_; + Linker linker_; + + // Single Module Transformation + // + + class SingleModuleTransformation + { + public: + using PassBuilder = llvm::PassBuilder; + using OptimizationLevel = PassBuilder::OptimizationLevel; + using FunctionAnalysisManager = llvm::FunctionAnalysisManager; + + explicit SingleModuleTransformation( + OptimizationLevel const& optimisation_level = OptimizationLevel::O0, + bool debug = false) + : loop_analysis_manager_{debug} + , function_analysis_manager_{debug} + , gscc_analysis_manager_{debug} + , module_analysis_manager_{debug} + , optimisation_level_{optimisation_level} + , debug_{debug} + { + + pass_builder_.registerModuleAnalyses(module_analysis_manager_); + pass_builder_.registerCGSCCAnalyses(gscc_analysis_manager_); + pass_builder_.registerFunctionAnalyses(function_analysis_manager_); + pass_builder_.registerLoopAnalyses(loop_analysis_manager_); + + pass_builder_.crossRegisterProxies( + loop_analysis_manager_, function_analysis_manager_, gscc_analysis_manager_, + module_analysis_manager_); + + module_pass_manager_.addPass(RemoveDisallowedAttributesPass()); + } + + bool apply(llvm::Module* module) + { + module_pass_manager_.run(*module, module_analysis_manager_); + + if (llvm::verifyModule(*module, &llvm::errs())) + { + return false; + } + + return true; + } + + bool isDebugMode() const + { + return debug_; + } + + private: + llvm::PassBuilder pass_builder_; + llvm::LoopAnalysisManager loop_analysis_manager_; + llvm::FunctionAnalysisManager function_analysis_manager_; + llvm::CGSCCAnalysisManager gscc_analysis_manager_; + llvm::ModuleAnalysisManager module_analysis_manager_; + + llvm::ModulePassManager module_pass_manager_{}; + OptimizationLevel optimisation_level_{}; + bool debug_{false}; + }; + }; + +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Profile/Profile.hpp b/src/Passes/Source/Profile/Profile.hpp index 6d27e0f57d..0e3a1ea09d 100644 --- a/src/Passes/Source/Profile/Profile.hpp +++ b/src/Passes/Source/Profile/Profile.hpp @@ -4,156 +4,161 @@ #include "AllocationManager/AllocationManager.hpp" #include "AllocationManager/IAllocationManager.hpp" -#include "Llvm/Llvm.hpp" #include "QatTypes/QatTypes.hpp" #include "Validator/Validator.hpp" -namespace microsoft { -namespace quantum { - -class ProfileGenerator; +#include "Llvm/Llvm.hpp" -/// Profile class that defines a set of rules which constitutes the profile definition. Each of the -/// rules can be used to transform a generic QIR and/or validate that the QIR is compliant with said -/// rule. -class Profile +namespace microsoft +{ +namespace quantum { -public: - /// Allocation manager pointer type. Used to reference to concrete allocation manager - /// implementations which defines the allocation logic of the profile. - using AllocationManagerPtr = IAllocationManager::AllocationManagerPtr; - /// Validator class used to check that an IR fulfils a given specification - using ValidatorPtr = Validator::ValidatorPtr; + class ProfileGenerator; - // Constructors - // + /// Profile class that defines a set of rules which constitutes the profile definition. Each of the + /// rules can be used to transform a generic QIR and/or validate that the QIR is compliant with said + /// rule. + class Profile + { + public: + /// Allocation manager pointer type. Used to reference to concrete allocation manager + /// implementations which defines the allocation logic of the profile. + using AllocationManagerPtr = IAllocationManager::AllocationManagerPtr; - explicit Profile( - String const &name, bool debug, llvm::TargetMachine *target_machine = nullptr, - AllocationManagerPtr qubit_allocation_manager = BasicAllocationManager::createNew(), - AllocationManagerPtr result_allocation_manager = BasicAllocationManager::createNew()); + /// Validator class used to check that an IR fulfils a given specification + using ValidatorPtr = Validator::ValidatorPtr; - // Default construction not allowed as this leads to invalid configuration of the allocation - // managers. + // Constructors + // - Profile() = delete; - Profile(Profile const &) = delete; - Profile(Profile &&) = default; - Profile &operator=(Profile const &) = delete; - Profile &operator=(Profile &&) = default; - ~Profile() = default; + explicit Profile( + String const& name, + bool debug, + llvm::TargetMachine* target_machine = nullptr, + AllocationManagerPtr qubit_allocation_manager = BasicAllocationManager::createNew(), + AllocationManagerPtr result_allocation_manager = BasicAllocationManager::createNew()); - // Profile methods - // + // Default construction not allowed as this leads to invalid configuration of the allocation + // managers. - /// Applies the profile to a module. - void apply(llvm::Module &module); + Profile() = delete; + Profile(Profile const&) = delete; + Profile(Profile&&) = default; + Profile& operator=(Profile const&) = delete; + Profile& operator=(Profile&&) = default; + ~Profile() = default; - /// Verifies that a module is a valid LLVM IR. - bool verify(llvm::Module &module); + // Profile methods + // - /// Validates that a module complies with the specified QIR profile. - bool validate(llvm::Module &module); + /// Applies the profile to a module. + void apply(llvm::Module& module); - AllocationManagerPtr getQubitAllocationManager(); - AllocationManagerPtr getResultAllocationManager(); + /// Verifies that a module is a valid LLVM IR. + bool verify(llvm::Module& module); - String const &name() const; + /// Validates that a module complies with the specified QIR profile. + bool validate(llvm::Module& module); -protected: - // Ensuring that ProfileGenerator has access to following protected functions. - friend class ProfileGenerator; + AllocationManagerPtr getQubitAllocationManager(); + AllocationManagerPtr getResultAllocationManager(); - /// Sets the module pass manager used for the transformation of the IR. - void setModulePassManager(llvm::ModulePassManager &&manager); + String const& name() const; - /// Sets the validator - void setValidator(ValidatorPtr &&validator); + protected: + // Ensuring that ProfileGenerator has access to following protected functions. + friend class ProfileGenerator; - /// Returns a reference to the pass builder. - llvm::PassBuilder &passBuilder(); + /// Sets the module pass manager used for the transformation of the IR. + void setModulePassManager(llvm::ModulePassManager&& manager); - /// Returns a reference to the loop analysis manager. - llvm::LoopAnalysisManager &loopAnalysisManager(); + /// Sets the validator + void setValidator(ValidatorPtr&& validator); - /// Returns a reference to the function analysis manager. - llvm::FunctionAnalysisManager &functionAnalysisManager(); + /// Returns a reference to the pass builder. + llvm::PassBuilder& passBuilder(); - /// Returns a reference to the GSCC analysis manager. - llvm::CGSCCAnalysisManager &gsccAnalysisManager(); + /// Returns a reference to the loop analysis manager. + llvm::LoopAnalysisManager& loopAnalysisManager(); - /// Returns a reference to the module analysis manager. - llvm::ModuleAnalysisManager &moduleAnalysisManager(); + /// Returns a reference to the function analysis manager. + llvm::FunctionAnalysisManager& functionAnalysisManager(); -private: - using PassInstrumentationCallbacksPtr = std::unique_ptr; - using StandardInstrumentationsPtr = std::unique_ptr; - using PassBuilderPtr = std::unique_ptr; + /// Returns a reference to the GSCC analysis manager. + llvm::CGSCCAnalysisManager& gsccAnalysisManager(); - void registerEPCallbacks(bool verify_each_pass, bool debug); + /// Returns a reference to the module analysis manager. + llvm::ModuleAnalysisManager& moduleAnalysisManager(); - template - bool tryParsePipelineText(llvm::PassBuilder &pass_builder, std::string const &pipeline_options) - { - if (pipeline_options.empty()) - { - return false; - } + private: + using PassInstrumentationCallbacksPtr = std::unique_ptr; + using StandardInstrumentationsPtr = std::unique_ptr; + using PassBuilderPtr = std::unique_ptr; - PassManager pass_manager; - if (auto err = pass_builder.parsePassPipeline(pass_manager, pipeline_options)) - { - llvm::errs() << "Could not parse -" << pipeline_options - << " pipeline: " << toString(std::move(err)) << "\n"; - return false; - } - return true; - } - - /// Name of the selected profile - String name_{}; - - // LLVM logic to run the passes - // - - llvm::LoopAnalysisManager loop_analysis_manager_; - llvm::FunctionAnalysisManager function_analysis_manager_; - llvm::CGSCCAnalysisManager gscc_analysis_manager_; - llvm::ModuleAnalysisManager module_analysis_manager_; - - llvm::Optional pgo_options_; - PassInstrumentationCallbacksPtr pass_instrumentation_callbacks_; - StandardInstrumentationsPtr standard_instrumentations_; - llvm::PipelineTuningOptions pipeline_tuning_options_; - - PassBuilderPtr pass_builder_; - - llvm::ModulePassManager module_pass_manager_{}; - - // Allocation management - // - - /// Interface pointer to the qubit allocation manager. Mode of operation depends on the concrete - /// implementation of the manager which is swappable through the interface. - AllocationManagerPtr qubit_allocation_manager_{}; - - /// Interface pointer to the results allocation manager. Again here the manager behaviour is - /// determined by its implementation details. - AllocationManagerPtr result_allocation_manager_{}; - - /// - ValidatorPtr validator_{}; - - std::string peephole_ep_pipeline_{""}; - std::string late_loop_optimizations_ep_pipeline_{""}; - std::string loop_optimizer_end_ep_pipeline_{""}; - std::string scalar_optimizer_late_ep_pipeline_{""}; - std::string cgscc_optimizer_late_ep_pipeline_{""}; - std::string vectorizer_start_ep_pipeline_{""}; - std::string pipeline_start_ep_pipeline_{""}; - std::string optimizer_last_ep_pipeline_{""}; -}; - -} // namespace quantum -} // namespace microsoft + void registerEPCallbacks(bool verify_each_pass, bool debug); + + template + bool tryParsePipelineText(llvm::PassBuilder& pass_builder, std::string const& pipeline_options) + { + if (pipeline_options.empty()) + { + return false; + } + + PassManager pass_manager; + if (auto err = pass_builder.parsePassPipeline(pass_manager, pipeline_options)) + { + llvm::errs() << "Could not parse -" << pipeline_options << " pipeline: " << toString(std::move(err)) + << "\n"; + return false; + } + return true; + } + + /// Name of the selected profile + String name_{}; + + // LLVM logic to run the passes + // + + llvm::LoopAnalysisManager loop_analysis_manager_; + llvm::FunctionAnalysisManager function_analysis_manager_; + llvm::CGSCCAnalysisManager gscc_analysis_manager_; + llvm::ModuleAnalysisManager module_analysis_manager_; + + llvm::Optional pgo_options_; + PassInstrumentationCallbacksPtr pass_instrumentation_callbacks_; + StandardInstrumentationsPtr standard_instrumentations_; + llvm::PipelineTuningOptions pipeline_tuning_options_; + + PassBuilderPtr pass_builder_; + + llvm::ModulePassManager module_pass_manager_{}; + + // Allocation management + // + + /// Interface pointer to the qubit allocation manager. Mode of operation depends on the concrete + /// implementation of the manager which is swappable through the interface. + AllocationManagerPtr qubit_allocation_manager_{}; + + /// Interface pointer to the results allocation manager. Again here the manager behaviour is + /// determined by its implementation details. + AllocationManagerPtr result_allocation_manager_{}; + + /// + ValidatorPtr validator_{}; + + std::string peephole_ep_pipeline_{""}; + std::string late_loop_optimizations_ep_pipeline_{""}; + std::string loop_optimizer_end_ep_pipeline_{""}; + std::string scalar_optimizer_late_ep_pipeline_{""}; + std::string cgscc_optimizer_late_ep_pipeline_{""}; + std::string vectorizer_start_ep_pipeline_{""}; + std::string pipeline_start_ep_pipeline_{""}; + std::string optimizer_last_ep_pipeline_{""}; + }; + +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/RemoveDisallowedAttributesPass/RemoveDisallowedAttributesPass.hpp b/src/Passes/Source/RemoveDisallowedAttributesPass/RemoveDisallowedAttributesPass.hpp index 06fe678804..2b0e242d91 100644 --- a/src/Passes/Source/RemoveDisallowedAttributesPass/RemoveDisallowedAttributesPass.hpp +++ b/src/Passes/Source/RemoveDisallowedAttributesPass/RemoveDisallowedAttributesPass.hpp @@ -2,64 +2,68 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -#include "Llvm/Llvm.hpp" #include "QatTypes/QatTypes.hpp" +#include "Llvm/Llvm.hpp" + #include #include #include -namespace microsoft { -namespace quantum { - -class RemoveDisallowedAttributesPass : public llvm::PassInfoMixin +namespace microsoft +{ +namespace quantum { -public: - RemoveDisallowedAttributesPass() - : allowed_attrs_{{static_cast("EntryPoint"), static_cast("InteropFriendly")}} - {} - llvm::PreservedAnalyses run(llvm::Module &module, llvm::ModuleAnalysisManager & /*mam*/) - { - for (auto &fnc : module) + class RemoveDisallowedAttributesPass : public llvm::PassInfoMixin { - std::unordered_set to_keep; + public: + RemoveDisallowedAttributesPass() + : allowed_attrs_{{static_cast("EntryPoint"), static_cast("InteropFriendly")}} + { + } - // Finding all valid attributes - for (auto &attrset : fnc.getAttributes()) - { - for (auto &attr : attrset) + llvm::PreservedAnalyses run(llvm::Module& module, llvm::ModuleAnalysisManager& /*mam*/) { - auto r = static_cast(attr.getAsString()); + for (auto& fnc : module) + { + std::unordered_set to_keep; - // Stripping quotes - if (r.size() >= 2 && r[0] == '"' && r[r.size() - 1] == '"') - { - r = r.substr(1, r.size() - 2); - } + // Finding all valid attributes + for (auto& attrset : fnc.getAttributes()) + { + for (auto& attr : attrset) + { + auto r = static_cast(attr.getAsString()); - // Inserting if allowed - if (allowed_attrs_.find(r) != allowed_attrs_.end()) - { - to_keep.insert(r); - } - } - } + // Stripping quotes + if (r.size() >= 2 && r[0] == '"' && r[r.size() - 1] == '"') + { + r = r.substr(1, r.size() - 2); + } - // Deleting every - fnc.setAttributes({}); - for (auto &attr : to_keep) - { - fnc.addFnAttr(attr); - } - } + // Inserting if allowed + if (allowed_attrs_.find(r) != allowed_attrs_.end()) + { + to_keep.insert(r); + } + } + } - return llvm::PreservedAnalyses::none(); - } + // Deleting every + fnc.setAttributes({}); + for (auto& attr : to_keep) + { + fnc.addFnAttr(attr); + } + } + + return llvm::PreservedAnalyses::none(); + } -private: - std::unordered_set allowed_attrs_; -}; + private: + std::unordered_set allowed_attrs_; + }; -} // namespace quantum -} // namespace microsoft +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Rules/Factory.hpp b/src/Passes/Source/Rules/Factory.hpp index 426b92518d..083411cc53 100644 --- a/src/Passes/Source/Rules/Factory.hpp +++ b/src/Passes/Source/Rules/Factory.hpp @@ -4,192 +4,197 @@ #include "AllocationManager/AllocationManager.hpp" #include "Commandline/ConfigurationManager.hpp" -#include "Llvm/Llvm.hpp" #include "QatTypes/QatTypes.hpp" #include "Rules/FactoryConfig.hpp" #include "Rules/ReplacementRule.hpp" #include "Rules/RuleSet.hpp" -#include +#include "Llvm/Llvm.hpp" -namespace microsoft { -namespace quantum { +#include -/// Rule factory provides a high-level methods to build a rule set that -/// enforces certain aspects of QIR transformation. -class RuleFactory +namespace microsoft +{ +namespace quantum { -public: - /// ReplacementRule pointer type used for the construction of replacement rules - using ReplacementRulePtr = std::shared_ptr; - - /// Allocation manager pointer used to hold allocation managers - using AllocationManagerPtr = IAllocationManager::AllocationManagerPtr; - - // Constructor configuration. Explicit construction with - // rule set to be configured, which can be moved using move - // semantics. No copy allowed. - // - - RuleFactory(RuleSet &rule_set, AllocationManagerPtr qubit_alloc_manager, - AllocationManagerPtr result_alloc_manager); - RuleFactory() = delete; - RuleFactory(RuleFactory const &) = delete; - RuleFactory(RuleFactory &&) = default; - ~RuleFactory() = default; - - // - // - - /// This takes a FactoryConfiguration as argument and enable rules accordingly. - void usingConfiguration(FactoryConfiguration const &config); - - // Generic rules - // - - /// Removes all calls to functions with a specified name. - /// This function matches on name alone and ignores function - /// arguments. - void removeFunctionCall(String const &name); - - // Conventions - // - - /// Static qubit array allocation identifies allocations, array access and releases. Each of these - /// are replaced with static values. Patterns recognised include - /// - /// ``` - /// %array = call %Array* @__quantum__rt__qubit_allocate_array(i64 10) - /// ``` - /// - /// which is replaced by a constant pointer - /// - /// ``` - /// %array = inttoptr i64 0 to %Array* - /// ``` - /// - /// The array allocation is managed through the qubit allocation manager. Access to qubit arrays - /// - /// ``` - /// %0 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %array, i64 7) - /// %1 = bitcast i8* %0 to %Qubit** - /// %qubit = load %Qubit*, %Qubit** %1, align 8 - /// ``` - /// - /// is replaced by off-setting the array value by 7 to get - /// - /// ``` - /// %qubit = inttoptr i64 7 to %Qubit* - /// ``` - /// - /// Finally, release is recognised and the allocation manager is invoked accordingly. - void useStaticQubitArrayAllocation(); - - /// Static qubit allocation identifies allocation and release of single qubits. It uses the qubit - /// allocation manager to track allocation and releases of qubits. It translates - /// - /// ``` - /// %qubit1 = call %Qubit* @__quantum__rt__qubit_allocate() - /// %qubit2 = call %Qubit* @__quantum__rt__qubit_allocate() - /// %qubit3 = call %Qubit* @__quantum__rt__qubit_allocate() - /// %qubit4 = call %Qubit* @__quantum__rt__qubit_allocate() - /// %qubit5 = call %Qubit* @__quantum__rt__qubit_allocate() - /// ``` - /// - /// to - /// - /// ``` - /// %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* - /// ``` - /// if the BasicAllocationManager is used. - void useStaticQubitAllocation(); - - /// Static allocation of results. This feature is similar to `useStaticQubitAllocation` but uses - /// the result allocation manager. - void useStaticResultAllocation(); - - void resolveConstantArraySizes(); - - void inlineCallables(); - - // Optimisations - // - - /// Replaces branching of quantum results compared to one. This is a relatively advanced pattern, - /// intended for base profile-like constructs where - /// - /// ``` - /// %1 = tail call %Result* @__quantum__rt__result_get_one() - /// %2 = tail call i1 @__quantum__rt__result_equal(%Result* %0, %Result* %1) - /// br i1 %2, label %then0__1, label %continue__1 - /// ``` - /// - /// is mapped into - /// - /// ``` - /// %1 = call i1 @__quantum__qis__read_result__body(%Result* %0) - /// br i1 %1, label %then0__1, label %continue__1 - /// ``` - /// - /// which removes the need for constant one. - void optimiseResultOne(); - - /// Replaces branching of quantum results compared to zero. This method is not implemented yet. - void optimiseResultZero(); - - // Disabling by feature - // - - /// This method disables reference counting for arrays, strings and results. It does so by simply - /// removing the instructions and the resulting code is expected to be executed either on a stack - /// VM or with shared pointer logic. - void disableReferenceCounting(); - - /// This method disables alias counting for arrays, strings and results. - void disableAliasCounting(); - - /// Removes string support by removing string related instructions. At the moment these include - /// `__quantum__rt__string_create`, - /// `__quantum__rt__string_update_reference_count`, `__quantum__rt__string_update_alias_count` and - /// `__quantum__rt__message`. - void disableStringSupport(); - - // Configuration - // - - /// Sets the integer width used when it cannot be deducted from the context of the transformation. - void setDefaultIntegerWidth(uint32_t v); - -private: - /// Helper function that moves a replacement rule into a shared pointer, adds it to the rule set - /// and returns a copy of it. - ReplacementRulePtr addRule(ReplacementRule &&rule); - - // Affected artefacts - // - - RuleSet &rule_set_; ///< The rule set we are building - - // Allocation managers. - // - - /// Qubit allocation manager which is used in the case of static qubit allocation. - AllocationManagerPtr qubit_alloc_manager_{nullptr}; - - /// Result allocation manager which is used in the case of static results allocation. - AllocationManagerPtr result_alloc_manager_{nullptr}; - - /// Configuration - // - - /// The default integer width. This value is used whenever the width within the context cannot be - /// inferred. - uint32_t default_integer_width_{64}; -}; - -} // namespace quantum -} // namespace microsoft + + /// Rule factory provides a high-level methods to build a rule set that + /// enforces certain aspects of QIR transformation. + class RuleFactory + { + public: + /// ReplacementRule pointer type used for the construction of replacement rules + using ReplacementRulePtr = std::shared_ptr; + + /// Allocation manager pointer used to hold allocation managers + using AllocationManagerPtr = IAllocationManager::AllocationManagerPtr; + + // Constructor configuration. Explicit construction with + // rule set to be configured, which can be moved using move + // semantics. No copy allowed. + // + + RuleFactory( + RuleSet& rule_set, + AllocationManagerPtr qubit_alloc_manager, + AllocationManagerPtr result_alloc_manager); + RuleFactory() = delete; + RuleFactory(RuleFactory const&) = delete; + RuleFactory(RuleFactory&&) = default; + ~RuleFactory() = default; + + // + // + + /// This takes a FactoryConfiguration as argument and enable rules accordingly. + void usingConfiguration(FactoryConfiguration const& config); + + // Generic rules + // + + /// Removes all calls to functions with a specified name. + /// This function matches on name alone and ignores function + /// arguments. + void removeFunctionCall(String const& name); + + // Conventions + // + + /// Static qubit array allocation identifies allocations, array access and releases. Each of these + /// are replaced with static values. Patterns recognised include + /// + /// ``` + /// %array = call %Array* @__quantum__rt__qubit_allocate_array(i64 10) + /// ``` + /// + /// which is replaced by a constant pointer + /// + /// ``` + /// %array = inttoptr i64 0 to %Array* + /// ``` + /// + /// The array allocation is managed through the qubit allocation manager. Access to qubit arrays + /// + /// ``` + /// %0 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %array, i64 7) + /// %1 = bitcast i8* %0 to %Qubit** + /// %qubit = load %Qubit*, %Qubit** %1, align 8 + /// ``` + /// + /// is replaced by off-setting the array value by 7 to get + /// + /// ``` + /// %qubit = inttoptr i64 7 to %Qubit* + /// ``` + /// + /// Finally, release is recognised and the allocation manager is invoked accordingly. + void useStaticQubitArrayAllocation(); + + /// Static qubit allocation identifies allocation and release of single qubits. It uses the qubit + /// allocation manager to track allocation and releases of qubits. It translates + /// + /// ``` + /// %qubit1 = call %Qubit* @__quantum__rt__qubit_allocate() + /// %qubit2 = call %Qubit* @__quantum__rt__qubit_allocate() + /// %qubit3 = call %Qubit* @__quantum__rt__qubit_allocate() + /// %qubit4 = call %Qubit* @__quantum__rt__qubit_allocate() + /// %qubit5 = call %Qubit* @__quantum__rt__qubit_allocate() + /// ``` + /// + /// to + /// + /// ``` + /// %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* + /// ``` + /// if the BasicAllocationManager is used. + void useStaticQubitAllocation(); + + /// Static allocation of results. This feature is similar to `useStaticQubitAllocation` but uses + /// the result allocation manager. + void useStaticResultAllocation(); + + void resolveConstantArraySizes(); + + void inlineCallables(); + + // Optimisations + // + + /// Replaces branching of quantum results compared to one. This is a relatively advanced pattern, + /// intended for base profile-like constructs where + /// + /// ``` + /// %1 = tail call %Result* @__quantum__rt__result_get_one() + /// %2 = tail call i1 @__quantum__rt__result_equal(%Result* %0, %Result* %1) + /// br i1 %2, label %then0__1, label %continue__1 + /// ``` + /// + /// is mapped into + /// + /// ``` + /// %1 = call i1 @__quantum__qis__read_result__body(%Result* %0) + /// br i1 %1, label %then0__1, label %continue__1 + /// ``` + /// + /// which removes the need for constant one. + void optimiseResultOne(); + + /// Replaces branching of quantum results compared to zero. This method is not implemented yet. + void optimiseResultZero(); + + // Disabling by feature + // + + /// This method disables reference counting for arrays, strings and results. It does so by simply + /// removing the instructions and the resulting code is expected to be executed either on a stack + /// VM or with shared pointer logic. + void disableReferenceCounting(); + + /// This method disables alias counting for arrays, strings and results. + void disableAliasCounting(); + + /// Removes string support by removing string related instructions. At the moment these include + /// `__quantum__rt__string_create`, + /// `__quantum__rt__string_update_reference_count`, `__quantum__rt__string_update_alias_count` and + /// `__quantum__rt__message`. + void disableStringSupport(); + + // Configuration + // + + /// Sets the integer width used when it cannot be deducted from the context of the transformation. + void setDefaultIntegerWidth(uint32_t v); + + private: + /// Helper function that moves a replacement rule into a shared pointer, adds it to the rule set + /// and returns a copy of it. + ReplacementRulePtr addRule(ReplacementRule&& rule); + + // Affected artefacts + // + + RuleSet& rule_set_; ///< The rule set we are building + + // Allocation managers. + // + + /// Qubit allocation manager which is used in the case of static qubit allocation. + AllocationManagerPtr qubit_alloc_manager_{nullptr}; + + /// Result allocation manager which is used in the case of static results allocation. + AllocationManagerPtr result_alloc_manager_{nullptr}; + + /// Configuration + // + + /// The default integer width. This value is used whenever the width within the context cannot be + /// inferred. + uint32_t default_integer_width_{64}; + }; + +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Rules/Notation/BasicBlock.cpp b/src/Passes/Source/Rules/Notation/BasicBlock.cpp index 8eb67dd3fb..ba11c8a085 100644 --- a/src/Passes/Source/Rules/Notation/BasicBlock.cpp +++ b/src/Passes/Source/Rules/Notation/BasicBlock.cpp @@ -1,26 +1,30 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -#include "Llvm/Llvm.hpp" #include "Rules/Notation/Notation.hpp" #include "Rules/Patterns/Instruction.hpp" +#include "Llvm/Llvm.hpp" + #include #include -namespace microsoft { -namespace quantum { -namespace notation { +namespace microsoft +{ +namespace quantum +{ + namespace notation + { -using IOperandPrototypePtr = std::shared_ptr; + using IOperandPrototypePtr = std::shared_ptr; -IOperandPrototypePtr basicBlock() -{ - auto ret = std::make_shared(); + IOperandPrototypePtr basicBlock() + { + auto ret = std::make_shared(); - return static_cast(ret); -} + return static_cast(ret); + } -} // namespace notation -} // namespace quantum -} // namespace microsoft + } // namespace notation +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Rules/Notation/BitCast.cpp b/src/Passes/Source/Rules/Notation/BitCast.cpp index b841dc0492..8467cac505 100644 --- a/src/Passes/Source/Rules/Notation/BitCast.cpp +++ b/src/Passes/Source/Rules/Notation/BitCast.cpp @@ -1,29 +1,33 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -#include "Llvm/Llvm.hpp" #include "Rules/Notation/Notation.hpp" #include "Rules/Patterns/AnyPattern.hpp" #include "Rules/Patterns/CallPattern.hpp" #include "Rules/Patterns/Instruction.hpp" +#include "Llvm/Llvm.hpp" + #include #include -namespace microsoft { -namespace quantum { -namespace notation { +namespace microsoft +{ +namespace quantum +{ + namespace notation + { -using IOperandPrototypePtr = std::shared_ptr; + using IOperandPrototypePtr = std::shared_ptr; -IOperandPrototypePtr bitCast(IOperandPrototypePtr const &arg) -{ - auto cast_pattern = std::make_shared(); + IOperandPrototypePtr bitCast(IOperandPrototypePtr const& arg) + { + auto cast_pattern = std::make_shared(); - cast_pattern->addChild(arg); - return static_cast(cast_pattern); -} + cast_pattern->addChild(arg); + return static_cast(cast_pattern); + } -} // namespace notation -} // namespace quantum -} // namespace microsoft + } // namespace notation +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Rules/Notation/Branch.cpp b/src/Passes/Source/Rules/Notation/Branch.cpp index bcfc986b75..97e75b8f9c 100644 --- a/src/Passes/Source/Rules/Notation/Branch.cpp +++ b/src/Passes/Source/Rules/Notation/Branch.cpp @@ -1,33 +1,39 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -#include "Llvm/Llvm.hpp" #include "Rules/Notation/Notation.hpp" #include "Rules/Patterns/AnyPattern.hpp" #include "Rules/Patterns/CallPattern.hpp" #include "Rules/Patterns/Instruction.hpp" +#include "Llvm/Llvm.hpp" + #include #include -namespace microsoft { -namespace quantum { -namespace notation { +namespace microsoft +{ +namespace quantum +{ + namespace notation + { -using IOperandPrototypePtr = std::shared_ptr; + using IOperandPrototypePtr = std::shared_ptr; -IOperandPrototypePtr branch(IOperandPrototypePtr const &cond, IOperandPrototypePtr const &arg1, - IOperandPrototypePtr const &arg2) -{ - auto branch_pattern = std::make_shared(); + IOperandPrototypePtr branch( + IOperandPrototypePtr const& cond, + IOperandPrototypePtr const& arg1, + IOperandPrototypePtr const& arg2) + { + auto branch_pattern = std::make_shared(); - branch_pattern->addChild(cond); - branch_pattern->addChild(arg1); - branch_pattern->addChild(arg2); + branch_pattern->addChild(cond); + branch_pattern->addChild(arg1); + branch_pattern->addChild(arg2); - return static_cast(branch_pattern); -} + return static_cast(branch_pattern); + } -} // namespace notation -} // namespace quantum -} // namespace microsoft + } // namespace notation +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Rules/Notation/Call.hpp b/src/Passes/Source/Rules/Notation/Call.hpp index 916cc79498..329fb19113 100644 --- a/src/Passes/Source/Rules/Notation/Call.hpp +++ b/src/Passes/Source/Rules/Notation/Call.hpp @@ -4,7 +4,6 @@ /// @defgroup shorthandNotation Shorthand Notation -#include "Llvm/Llvm.hpp" #include "Rules/Notation/Call.ipp" #include "Rules/Notation/Phi.ipp" #include "Rules/Patterns/AnyPattern.hpp" @@ -12,55 +11,59 @@ #include "Rules/Patterns/Instruction.hpp" #include "Rules/Patterns/PhiPattern.hpp" +#include "Llvm/Llvm.hpp" + #include #include -namespace microsoft { -namespace quantum { -namespace notation { +namespace microsoft +{ +namespace quantum +{ + namespace notation + { -using IOperandPrototypePtr = std::shared_ptr; + using IOperandPrototypePtr = std::shared_ptr; -/// Shorthand notations are made to make it possible to match patterns in the QIR. This part of the -/// library focuses on making it easy to express advance patterns in just a few lines and specify -/// what parts of the IR is of interest to the replacer function. An example is following pattern -/// -/// ``` -/// auto get_one = call("__quantum__rt__result_get_one"); -/// addRule( -/// {branch("cond"_cap = call("__quantum__rt__result_equal", "result"_cap = _, "one"_cap = -/// get_one), _, _), -/// replace_branch_positive}); -/// -/// ``` -/// -/// which matches IRs of the form -/// -/// ``` -/// %1 = call %Result* @__quantum__rt__result_get_one() -/// %2 = call i1 @__quantum__rt__result_equal(%Result* %0, %Result* %1) -/// br i1 %2, label %then0__1, label %continue__1 -/// ``` -/// -/// The pattern futher specifies that as a successful match is obtained, a table capturing -/// certain values must be created. In the above example, the table would contain three -/// entries: `cond`, `result` and `one` each of which would point to a a llvm::Value* -/// in the QIR. This allows the replacement function to easily manipulate the DAG in these -/// three places (four if you include the main captured value which is always passed to the -/// replacement function). + /// Shorthand notations are made to make it possible to match patterns in the QIR. This part of the + /// library focuses on making it easy to express advance patterns in just a few lines and specify + /// what parts of the IR is of interest to the replacer function. An example is following pattern + /// + /// ``` + /// auto get_one = call("__quantum__rt__result_get_one"); + /// addRule( + /// {branch("cond"_cap = call("__quantum__rt__result_equal", "result"_cap = _, "one"_cap = + /// get_one), _, _), + /// replace_branch_positive}); + /// + /// ``` + /// + /// which matches IRs of the form + /// + /// ``` + /// %1 = call %Result* @__quantum__rt__result_get_one() + /// %2 = call i1 @__quantum__rt__result_equal(%Result* %0, %Result* %1) + /// br i1 %2, label %then0__1, label %continue__1 + /// ``` + /// + /// The pattern futher specifies that as a successful match is obtained, a table capturing + /// certain values must be created. In the above example, the table would contain three + /// entries: `cond`, `result` and `one` each of which would point to a a llvm::Value* + /// in the QIR. This allows the replacement function to easily manipulate the DAG in these + /// three places (four if you include the main captured value which is always passed to the + /// replacement function). -/// Shorthand notation to match an instruction for a function call. -/// The resulting IOperandPrototype matches a function call with arguments -/// as specified by the arguments given. For instance, -/// -/// ``` -/// addRule({call("foo", _, _), deleteInstruction()}); -/// ``` -/// -/// matches a call to the function `foo` with exactly two arguments. -template -IOperandPrototypePtr call(std::string const &name, Args... args); + /// Shorthand notation to match an instruction for a function call. + /// The resulting IOperandPrototype matches a function call with arguments + /// as specified by the arguments given. For instance, + /// + /// ``` + /// addRule({call("foo", _, _), deleteInstruction()}); + /// ``` + /// + /// matches a call to the function `foo` with exactly two arguments. + template IOperandPrototypePtr call(std::string const& name, Args... args); -} // namespace notation -} // namespace quantum -} // namespace microsoft + } // namespace notation +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Rules/Notation/CallByNameOnly.cpp b/src/Passes/Source/Rules/Notation/CallByNameOnly.cpp index ad12ab815b..601daed46d 100644 --- a/src/Passes/Source/Rules/Notation/CallByNameOnly.cpp +++ b/src/Passes/Source/Rules/Notation/CallByNameOnly.cpp @@ -1,27 +1,31 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -#include "Llvm/Llvm.hpp" #include "Rules/Notation/Notation.hpp" #include "Rules/Patterns/AnyPattern.hpp" #include "Rules/Patterns/CallPattern.hpp" #include "Rules/Patterns/Instruction.hpp" +#include "Llvm/Llvm.hpp" + #include #include -namespace microsoft { -namespace quantum { -namespace notation { +namespace microsoft +{ +namespace quantum +{ + namespace notation + { -using IOperandPrototypePtr = std::shared_ptr; + using IOperandPrototypePtr = std::shared_ptr; -IOperandPrototypePtr callByNameOnly(std::string const &name) -{ - IOperandPrototypePtr ret = std::make_shared(name); - return ret; -} + IOperandPrototypePtr callByNameOnly(std::string const& name) + { + IOperandPrototypePtr ret = std::make_shared(name); + return ret; + } -} // namespace notation -} // namespace quantum -} // namespace microsoft + } // namespace notation +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Rules/Notation/Capture.cpp b/src/Passes/Source/Rules/Notation/Capture.cpp index ab8d753bbc..2381b0c83f 100644 --- a/src/Passes/Source/Rules/Notation/Capture.cpp +++ b/src/Passes/Source/Rules/Notation/Capture.cpp @@ -1,37 +1,42 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -#include "Llvm/Llvm.hpp" #include "Rules/Notation/Notation.hpp" #include "Rules/Patterns/AnyPattern.hpp" #include "Rules/Patterns/CallPattern.hpp" #include "Rules/Patterns/Instruction.hpp" +#include "Llvm/Llvm.hpp" + #include #include -namespace microsoft { -namespace quantum { -namespace notation { - -using IOperandPrototypePtr = std::shared_ptr; - -Capture::Capture(std::string const &name) - : name_{name} -{} - -IOperandPrototypePtr Capture::operator=(IOperandPrototypePtr const &other) // NOLINT +namespace microsoft { - auto ret = other->copy(); - ret->captureAs(name_); - return ret; -} - -Capture operator""_cap(char const *name, std::size_t) +namespace quantum { - return Capture(name); -} - -} // namespace notation -} // namespace quantum -} // namespace microsoft + namespace notation + { + + using IOperandPrototypePtr = std::shared_ptr; + + Capture::Capture(std::string const& name) + : name_{name} + { + } + + IOperandPrototypePtr Capture::operator=(IOperandPrototypePtr const& other) // NOLINT + { + auto ret = other->copy(); + ret->captureAs(name_); + return ret; + } + + Capture operator""_cap(char const* name, std::size_t) + { + return Capture(name); + } + + } // namespace notation +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Rules/Notation/ConstInt.cpp b/src/Passes/Source/Rules/Notation/ConstInt.cpp index 71a9d5f92d..22802a5e79 100644 --- a/src/Passes/Source/Rules/Notation/ConstInt.cpp +++ b/src/Passes/Source/Rules/Notation/ConstInt.cpp @@ -1,28 +1,32 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -#include "Llvm/Llvm.hpp" #include "Rules/Notation/Notation.hpp" #include "Rules/Patterns/AnyPattern.hpp" #include "Rules/Patterns/CallPattern.hpp" #include "Rules/Patterns/Instruction.hpp" +#include "Llvm/Llvm.hpp" + #include #include -namespace microsoft { -namespace quantum { -namespace notation { +namespace microsoft +{ +namespace quantum +{ + namespace notation + { -using IOperandPrototypePtr = std::shared_ptr; + using IOperandPrototypePtr = std::shared_ptr; -IOperandPrototypePtr constInt() -{ - auto cast_pattern = std::make_shared(); + IOperandPrototypePtr constInt() + { + auto cast_pattern = std::make_shared(); - return static_cast(cast_pattern); -} + return static_cast(cast_pattern); + } -} // namespace notation -} // namespace quantum -} // namespace microsoft + } // namespace notation +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Rules/Notation/IntToPtr.cpp b/src/Passes/Source/Rules/Notation/IntToPtr.cpp index be6ae78a39..523d49ffef 100644 --- a/src/Passes/Source/Rules/Notation/IntToPtr.cpp +++ b/src/Passes/Source/Rules/Notation/IntToPtr.cpp @@ -1,29 +1,33 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -#include "Llvm/Llvm.hpp" #include "Rules/Notation/Notation.hpp" #include "Rules/Patterns/AnyPattern.hpp" #include "Rules/Patterns/CallPattern.hpp" #include "Rules/Patterns/Instruction.hpp" +#include "Llvm/Llvm.hpp" + #include #include -namespace microsoft { -namespace quantum { -namespace notation { +namespace microsoft +{ +namespace quantum +{ + namespace notation + { -using IOperandPrototypePtr = std::shared_ptr; + using IOperandPrototypePtr = std::shared_ptr; -IOperandPrototypePtr intToPtr(IOperandPrototypePtr const &arg) -{ - auto cast_pattern = std::make_shared(); + IOperandPrototypePtr intToPtr(IOperandPrototypePtr const& arg) + { + auto cast_pattern = std::make_shared(); - cast_pattern->addChild(arg); - return static_cast(cast_pattern); -} + cast_pattern->addChild(arg); + return static_cast(cast_pattern); + } -} // namespace notation -} // namespace quantum -} // namespace microsoft + } // namespace notation +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Rules/Notation/Load.cpp b/src/Passes/Source/Rules/Notation/Load.cpp index 925a280cec..3cde8d858e 100644 --- a/src/Passes/Source/Rules/Notation/Load.cpp +++ b/src/Passes/Source/Rules/Notation/Load.cpp @@ -1,29 +1,33 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -#include "Llvm/Llvm.hpp" #include "Rules/Notation/Notation.hpp" #include "Rules/Patterns/AnyPattern.hpp" #include "Rules/Patterns/CallPattern.hpp" #include "Rules/Patterns/Instruction.hpp" +#include "Llvm/Llvm.hpp" + #include #include -namespace microsoft { -namespace quantum { -namespace notation { +namespace microsoft +{ +namespace quantum +{ + namespace notation + { -using IOperandPrototypePtr = std::shared_ptr; + using IOperandPrototypePtr = std::shared_ptr; -IOperandPrototypePtr load(IOperandPrototypePtr const &arg) -{ - auto ret = std::make_shared(); + IOperandPrototypePtr load(IOperandPrototypePtr const& arg) + { + auto ret = std::make_shared(); - ret->addChild(arg); - return static_cast(ret); -} + ret->addChild(arg); + return static_cast(ret); + } -} // namespace notation -} // namespace quantum -} // namespace microsoft + } // namespace notation +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Rules/Notation/Notation.cpp b/src/Passes/Source/Rules/Notation/Notation.cpp index 1ba4f5371f..c6e8cfb158 100644 --- a/src/Passes/Source/Rules/Notation/Notation.cpp +++ b/src/Passes/Source/Rules/Notation/Notation.cpp @@ -2,28 +2,31 @@ // Licensed under the MIT License. #include "Rules/Notation/Notation.hpp" - -#include "Llvm/Llvm.hpp" #include "Rules/Patterns/AnyPattern.hpp" #include "Rules/Patterns/CallPattern.hpp" #include "Rules/Patterns/Instruction.hpp" +#include "Llvm/Llvm.hpp" + #include #include -namespace microsoft { -namespace quantum { -namespace notation { - -ReplacerFunction deleteInstruction() +namespace microsoft +{ +namespace quantum { - return [](ReplacementRule::Builder &, ReplacementRule::Value *val, ReplacementRule::Captures &, - ReplacementRule::Replacements &replacements) { - replacements.push_back({llvm::dyn_cast(val), nullptr}); - return true; - }; -} + namespace notation + { + + ReplacerFunction deleteInstruction() + { + return [](ReplacementRule::Builder&, ReplacementRule::Value* val, ReplacementRule::Captures&, + ReplacementRule::Replacements& replacements) { + replacements.push_back({llvm::dyn_cast(val), nullptr}); + return true; + }; + } -} // namespace notation -} // namespace quantum -} // namespace microsoft + } // 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 a2634194db..d194577f39 100644 --- a/src/Passes/Source/Rules/Notation/Notation.hpp +++ b/src/Passes/Source/Rules/Notation/Notation.hpp @@ -4,7 +4,6 @@ /// @defgroup shorthandNotation Shorthand Notation -#include "Llvm/Llvm.hpp" #include "Rules/Notation/Call.hpp" #include "Rules/Notation/Call.ipp" #include "Rules/Notation/Phi.ipp" @@ -13,181 +12,192 @@ #include "Rules/Patterns/Instruction.hpp" #include "Rules/Patterns/PhiPattern.hpp" +#include "Llvm/Llvm.hpp" + #include #include -namespace microsoft { -namespace quantum { -/// Shorthand notations to make it easy and readible to create patterns. -/// -/// -namespace notation { - -using IOperandPrototypePtr = std::shared_ptr; -using ReplacerFunction = - std::function; - -/// Helper class to enable literals for IR patterns. The main purpose of this class -/// is to enable notation that allows one write `"name"_cap = operandGenerator()` where -/// the operand generator is a function which creates a IOperandPrototypePtr. This notation -/// means that whenever a operand is matched, the matched value is stored under "name". -class Capture +namespace microsoft +{ +namespace quantum { -public: - /// Explicit creation using string name constructor. - explicit Capture(std::string const &name); - - // Note that this operator is delibrately unconventional - IOperandPrototypePtr operator=(IOperandPrototypePtr const &other); // NOLINT - -private: - std::string name_{}; ///< Name that is assigned to the IOperandPrototype -}; - -/// @addtogroup shorthandNotation -/// @{ -/// Shorthand notations are made to make it possible to match patterns in the QIR. This part of the -/// library focuses on making it easy to express advance patterns in just a few lines and specify -/// what parts of the IR is of interest to the replacer function. An example is following pattern -/// -/// ``` -/// auto get_one = call("__quantum__rt__result_get_one"); -/// addRule( -/// {branch("cond"_cap = call("__quantum__rt__result_equal", "result"_cap = _, "one"_cap = -/// get_one), _, _), -/// replace_branch_positive}); -/// -/// ``` -/// -/// which matches IRs of the form -/// -/// ``` -/// %1 = call %Result* @__quantum__rt__result_get_one() -/// %2 = call i1 @__quantum__rt__result_equal(%Result* %0, %Result* %1) -/// br i1 %2, label %then0__1, label %continue__1 -/// ``` -/// -/// The pattern futher specifies that as a successful match is obtained, a table capturing -/// certain values must be created. In the above example, the table would contain three -/// entries: `cond`, `result` and `one` each of which would point to a a llvm::Value* -/// in the QIR. This allows the replacement function to easily manipulate the DAG in these -/// three places (four if you include the main captured value which is always passed to the -/// replacement function). - -/// Shorthand notation to match an instruction for a function call. -/// The resulting IOperandPrototype matches a function call with arguments -/// as specified by the arguments given. For instance, -/// -/// ``` -/// addRule({call("foo", _, _), deleteInstruction()}); -/// ``` -/// -/// matches a call to the function `foo` with exactly two arguments. -template -IOperandPrototypePtr call(std::string const &name, Args... args); - -/// Matches a invoke instruction -IOperandPrototypePtr unnamedInvoke(); - -/// Matches a phi node with N arguments. -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. -/// -/// ``` -/// addRule({callByNameOnly("foo"), deleteInstruction()}); -/// ``` -/// -/// matches calls to the function `foo` regardless of the number of arguments. -IOperandPrototypePtr callByNameOnly(std::string const &name); - -/// Matches the llvm::BitCast instructruction. -IOperandPrototypePtr bitCast(IOperandPrototypePtr const &arg); - -/// Matches the llvm::IntToPtr instructruction. -IOperandPrototypePtr intToPtr(IOperandPrototypePtr const &arg); - -/// Matches the llvm::ConstantInt instructruction. -IOperandPrototypePtr constInt(); - -/// Matches a branch instruction given a condition and two arguments. -IOperandPrototypePtr branch(IOperandPrototypePtr const &cond, IOperandPrototypePtr const &arg1, - IOperandPrototypePtr const &arg2); - -IOperandPrototypePtr switchOp(IOperandPrototypePtr const &cond, IOperandPrototypePtr const &arg1, - IOperandPrototypePtr const &arg2); - -/// Matches a select instruction given a condition and two arguments. -IOperandPrototypePtr select(IOperandPrototypePtr const &cond, IOperandPrototypePtr const &arg1, - IOperandPrototypePtr const &arg2); - -/// Matches a load instruction with one argument. -IOperandPrototypePtr load(IOperandPrototypePtr const &arg); - -/// Matches a store instruction with a target and a value. -/// ``` -/// addRule({store("target"_cap = _, "value"_cap = _), replaceConstExpr}); -/// ``` -/// where we want to match all store instructions and do not really care about how the target or -/// 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 -/// @{ -/// The module further has shorthand notation for often encountered patterns such as any operand. - -/// Shorthand notation for a wildcard which matches anything. This value -/// is useful when for instance capturing the arguments of a function call where the -/// origin of the value does not matter to the pattern. -static std::shared_ptr const _ = std::make_shared(); // NOLINT - -/// @} - -/// @addtogroup shorthandNotation -/// @{ -/// The module also implements shorthand notation for common replacers. - -/// Shorthand notation to delete an instruction. If passed as the replacement function, this -/// function generates a replacer that deletes the instruction. This is a shorthand notation for -/// deleting an instruction that can be used with a custom rule when building a ruleset. This -/// function can be used with shorthand notation for patterns as follows: -/// ``` -/// addRule({callByNameOnly(name), deleteInstruction()}); -/// ``` -/// to delete the instructions that calls functions with the name `name`. -ReplacerFunction deleteInstruction(); -/// @} - -/// @addtogroup shorthandNotation -/// @{ -/// Literals which ease the burned of capturing values and increase readibility of the code. - -/// Literal for specifying the capture of a llvm::Value*. This literal calls the -/// IOperandPrototype::enableCapture through the assignment of a IOperandPrototypePtr to the class -/// Capture. -/// -/// As an example, one may want to match the pattern `foo(bar(baz(x)), y)` and extract the variable -/// `x` to add meta data to it. The corresponding IR could look like: -/// ``` -/// %1 = call %Type* @baz(%Type* %0) -/// %2 = call %Type* @bar(%Type* %1) -/// call void @foo(%Type* %2, %Type* %3) -/// ``` -/// To match this pattern, one would create the pattern `call("foo", call("bar", call("baz", "x"_cap -/// = _)), _)`. This pattern would ensure that at the time where the replacer function is called, -/// the value stored in `%0` is captured under the name `x`. -/// -Capture operator""_cap(char const *name, std::size_t); -/// @} - -} // namespace notation -} // namespace quantum -} // namespace microsoft + /// Shorthand notations to make it easy and readible to create patterns. + /// + /// + namespace notation + { + + using IOperandPrototypePtr = std::shared_ptr; + using ReplacerFunction = std::function; + + /// Helper class to enable literals for IR patterns. The main purpose of this class + /// is to enable notation that allows one write `"name"_cap = operandGenerator()` where + /// the operand generator is a function which creates a IOperandPrototypePtr. This notation + /// means that whenever a operand is matched, the matched value is stored under "name". + class Capture + { + public: + /// Explicit creation using string name constructor. + explicit Capture(std::string const& name); + + // Note that this operator is delibrately unconventional + IOperandPrototypePtr operator=(IOperandPrototypePtr const& other); // NOLINT + + private: + std::string name_{}; ///< Name that is assigned to the IOperandPrototype + }; + + /// @addtogroup shorthandNotation + /// @{ + /// Shorthand notations are made to make it possible to match patterns in the QIR. This part of the + /// library focuses on making it easy to express advance patterns in just a few lines and specify + /// what parts of the IR is of interest to the replacer function. An example is following pattern + /// + /// ``` + /// auto get_one = call("__quantum__rt__result_get_one"); + /// addRule( + /// {branch("cond"_cap = call("__quantum__rt__result_equal", "result"_cap = _, "one"_cap = + /// get_one), _, _), + /// replace_branch_positive}); + /// + /// ``` + /// + /// which matches IRs of the form + /// + /// ``` + /// %1 = call %Result* @__quantum__rt__result_get_one() + /// %2 = call i1 @__quantum__rt__result_equal(%Result* %0, %Result* %1) + /// br i1 %2, label %then0__1, label %continue__1 + /// ``` + /// + /// The pattern futher specifies that as a successful match is obtained, a table capturing + /// certain values must be created. In the above example, the table would contain three + /// entries: `cond`, `result` and `one` each of which would point to a a llvm::Value* + /// in the QIR. This allows the replacement function to easily manipulate the DAG in these + /// three places (four if you include the main captured value which is always passed to the + /// replacement function). + + /// Shorthand notation to match an instruction for a function call. + /// The resulting IOperandPrototype matches a function call with arguments + /// as specified by the arguments given. For instance, + /// + /// ``` + /// addRule({call("foo", _, _), deleteInstruction()}); + /// ``` + /// + /// matches a call to the function `foo` with exactly two arguments. + template IOperandPrototypePtr call(std::string const& name, Args... args); + + /// Matches a invoke instruction + IOperandPrototypePtr unnamedInvoke(); + + /// Matches a phi node with N arguments. + 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. + /// + /// ``` + /// addRule({callByNameOnly("foo"), deleteInstruction()}); + /// ``` + /// + /// matches calls to the function `foo` regardless of the number of arguments. + IOperandPrototypePtr callByNameOnly(std::string const& name); + + /// Matches the llvm::BitCast instructruction. + IOperandPrototypePtr bitCast(IOperandPrototypePtr const& arg); + + /// Matches the llvm::IntToPtr instructruction. + IOperandPrototypePtr intToPtr(IOperandPrototypePtr const& arg); + + /// Matches the llvm::ConstantInt instructruction. + IOperandPrototypePtr constInt(); + + /// Matches a branch instruction given a condition and two arguments. + IOperandPrototypePtr branch( + IOperandPrototypePtr const& cond, + IOperandPrototypePtr const& arg1, + IOperandPrototypePtr const& arg2); + + IOperandPrototypePtr switchOp( + IOperandPrototypePtr const& cond, + IOperandPrototypePtr const& arg1, + IOperandPrototypePtr const& arg2); + + /// Matches a select instruction given a condition and two arguments. + IOperandPrototypePtr select( + IOperandPrototypePtr const& cond, + IOperandPrototypePtr const& arg1, + IOperandPrototypePtr const& arg2); + + /// Matches a load instruction with one argument. + IOperandPrototypePtr load(IOperandPrototypePtr const& arg); + + /// Matches a store instruction with a target and a value. + /// ``` + /// addRule({store("target"_cap = _, "value"_cap = _), replaceConstExpr}); + /// ``` + /// where we want to match all store instructions and do not really care about how the target or + /// 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 + /// @{ + /// The module further has shorthand notation for often encountered patterns such as any operand. + + /// Shorthand notation for a wildcard which matches anything. This value + /// is useful when for instance capturing the arguments of a function call where the + /// origin of the value does not matter to the pattern. + static std::shared_ptr const _ = std::make_shared(); // NOLINT + + /// @} + + /// @addtogroup shorthandNotation + /// @{ + /// The module also implements shorthand notation for common replacers. + + /// Shorthand notation to delete an instruction. If passed as the replacement function, this + /// function generates a replacer that deletes the instruction. This is a shorthand notation for + /// deleting an instruction that can be used with a custom rule when building a ruleset. This + /// function can be used with shorthand notation for patterns as follows: + /// ``` + /// addRule({callByNameOnly(name), deleteInstruction()}); + /// ``` + /// to delete the instructions that calls functions with the name `name`. + ReplacerFunction deleteInstruction(); + /// @} + + /// @addtogroup shorthandNotation + /// @{ + /// Literals which ease the burned of capturing values and increase readibility of the code. + + /// Literal for specifying the capture of a llvm::Value*. This literal calls the + /// IOperandPrototype::enableCapture through the assignment of a IOperandPrototypePtr to the class + /// Capture. + /// + /// As an example, one may want to match the pattern `foo(bar(baz(x)), y)` and extract the variable + /// `x` to add meta data to it. The corresponding IR could look like: + /// ``` + /// %1 = call %Type* @baz(%Type* %0) + /// %2 = call %Type* @bar(%Type* %1) + /// call void @foo(%Type* %2, %Type* %3) + /// ``` + /// To match this pattern, one would create the pattern `call("foo", call("bar", call("baz", "x"_cap + /// = _)), _)`. This pattern would ensure that at the time where the replacer function is called, + /// the value stored in `%0` is captured under the name `x`. + /// + Capture operator""_cap(char const* name, std::size_t); + /// @} + + } // namespace notation +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Rules/Notation/Select.cpp b/src/Passes/Source/Rules/Notation/Select.cpp index 21ebe4b02e..63b03d363c 100644 --- a/src/Passes/Source/Rules/Notation/Select.cpp +++ b/src/Passes/Source/Rules/Notation/Select.cpp @@ -1,33 +1,39 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -#include "Llvm/Llvm.hpp" #include "Rules/Notation/Notation.hpp" #include "Rules/Patterns/AnyPattern.hpp" #include "Rules/Patterns/CallPattern.hpp" #include "Rules/Patterns/Instruction.hpp" +#include "Llvm/Llvm.hpp" + #include #include -namespace microsoft { -namespace quantum { -namespace notation { +namespace microsoft +{ +namespace quantum +{ + namespace notation + { -using IOperandPrototypePtr = std::shared_ptr; + using IOperandPrototypePtr = std::shared_ptr; -IOperandPrototypePtr select(IOperandPrototypePtr const &cond, IOperandPrototypePtr const &arg1, - IOperandPrototypePtr const &arg2) -{ - auto select_pattern = std::make_shared(); + IOperandPrototypePtr select( + IOperandPrototypePtr const& cond, + IOperandPrototypePtr const& arg1, + IOperandPrototypePtr const& arg2) + { + auto select_pattern = std::make_shared(); - select_pattern->addChild(cond); - select_pattern->addChild(arg1); - select_pattern->addChild(arg2); + select_pattern->addChild(cond); + select_pattern->addChild(arg1); + select_pattern->addChild(arg2); - return static_cast(select_pattern); -} + return static_cast(select_pattern); + } -} // namespace notation -} // namespace quantum -} // namespace microsoft + } // namespace notation +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Rules/Notation/Store.cpp b/src/Passes/Source/Rules/Notation/Store.cpp index 060a2438b2..e13931154b 100644 --- a/src/Passes/Source/Rules/Notation/Store.cpp +++ b/src/Passes/Source/Rules/Notation/Store.cpp @@ -1,28 +1,32 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -#include "Llvm/Llvm.hpp" #include "Rules/Notation/Notation.hpp" #include "Rules/Patterns/Instruction.hpp" +#include "Llvm/Llvm.hpp" + #include #include -namespace microsoft { -namespace quantum { -namespace notation { +namespace microsoft +{ +namespace quantum +{ + namespace notation + { -using IOperandPrototypePtr = std::shared_ptr; + using IOperandPrototypePtr = std::shared_ptr; -IOperandPrototypePtr store(IOperandPrototypePtr const &target, IOperandPrototypePtr const &value) -{ - auto ret = std::make_shared(); + IOperandPrototypePtr store(IOperandPrototypePtr const& target, IOperandPrototypePtr const& value) + { + auto ret = std::make_shared(); - ret->addChild(target); - ret->addChild(value); - return static_cast(ret); -} + ret->addChild(target); + ret->addChild(value); + return static_cast(ret); + } -} // namespace notation -} // namespace quantum -} // namespace microsoft + } // namespace notation +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Rules/Notation/Switch.cpp b/src/Passes/Source/Rules/Notation/Switch.cpp index 169783a03f..a8ce472889 100644 --- a/src/Passes/Source/Rules/Notation/Switch.cpp +++ b/src/Passes/Source/Rules/Notation/Switch.cpp @@ -1,35 +1,40 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -#include "Llvm/Llvm.hpp" #include "Rules/Notation/Notation.hpp" #include "Rules/Patterns/AnyPattern.hpp" #include "Rules/Patterns/CallPattern.hpp" #include "Rules/Patterns/Instruction.hpp" +#include "Llvm/Llvm.hpp" + #include #include -namespace microsoft { -namespace quantum { -namespace notation { +namespace microsoft +{ +namespace quantum +{ + namespace notation + { -using IOperandPrototypePtr = std::shared_ptr; + using IOperandPrototypePtr = std::shared_ptr; -IOperandPrototypePtr switchOp(IOperandPrototypePtr const & /*cond*/, - IOperandPrototypePtr const & /*arg1*/, - IOperandPrototypePtr const & /*arg2*/) -{ - auto switch_pattern = std::make_shared(); + IOperandPrototypePtr switchOp( + IOperandPrototypePtr const& /*cond*/, + IOperandPrototypePtr const& /*arg1*/, + IOperandPrototypePtr const& /*arg2*/) + { + auto switch_pattern = std::make_shared(); - // TODO(tfr): finish switch pattern - // switch_pattern->addChild(cond); - // switch_pattern->addChild(arg1); - // switch_pattern->addChild(arg2); + // TODO(tfr): finish switch pattern + // switch_pattern->addChild(cond); + // switch_pattern->addChild(arg1); + // switch_pattern->addChild(arg2); - return static_cast(switch_pattern); -} + return static_cast(switch_pattern); + } -} // namespace notation -} // namespace quantum -} // namespace microsoft + } // namespace notation +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Rules/Notation/UnnamedInvoke.cpp b/src/Passes/Source/Rules/Notation/UnnamedInvoke.cpp index 1f29750d20..551b1833a2 100644 --- a/src/Passes/Source/Rules/Notation/UnnamedInvoke.cpp +++ b/src/Passes/Source/Rules/Notation/UnnamedInvoke.cpp @@ -1,26 +1,30 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -#include "Llvm/Llvm.hpp" #include "Rules/Notation/Notation.hpp" #include "Rules/Patterns/UnnamedInvokePattern.hpp" +#include "Llvm/Llvm.hpp" + #include #include -namespace microsoft { -namespace quantum { -namespace notation { +namespace microsoft +{ +namespace quantum +{ + namespace notation + { -using IOperandPrototypePtr = std::shared_ptr; + using IOperandPrototypePtr = std::shared_ptr; -IOperandPrototypePtr unnamedInvoke() -{ - auto ret = std::make_shared(); + IOperandPrototypePtr unnamedInvoke() + { + auto ret = std::make_shared(); - return static_cast(ret); -} + return static_cast(ret); + } -} // namespace notation -} // namespace quantum -} // namespace microsoft + } // namespace notation +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Rules/Patterns/AnyPattern.cpp b/src/Passes/Source/Rules/Patterns/AnyPattern.cpp index 19bafa1ec8..71efeb962c 100644 --- a/src/Passes/Source/Rules/Patterns/AnyPattern.cpp +++ b/src/Passes/Source/Rules/Patterns/AnyPattern.cpp @@ -1,24 +1,25 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -#include "Rules/Patterns/AnyPattern.hpp" - #include "Rules/IOperandPrototype.hpp" +#include "Rules/Patterns/AnyPattern.hpp" -namespace microsoft { -namespace quantum { - -AnyPattern::AnyPattern() = default; -AnyPattern::~AnyPattern() = default; -bool AnyPattern::match(Value *instr, Captures &captures) const +namespace microsoft { - return success(instr, captures); -} - -AnyPattern::Child AnyPattern::copy() const +namespace quantum { - return std::make_shared(); -} -} // namespace quantum -} // namespace microsoft + AnyPattern::AnyPattern() = default; + AnyPattern::~AnyPattern() = default; + bool AnyPattern::match(Value* instr, Captures& captures) const + { + return success(instr, captures); + } + + AnyPattern::Child AnyPattern::copy() const + { + return std::make_shared(); + } + +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Rules/Patterns/CallPattern.cpp b/src/Passes/Source/Rules/Patterns/CallPattern.cpp index 4dae3ddf10..f921e69e54 100644 --- a/src/Passes/Source/Rules/Patterns/CallPattern.cpp +++ b/src/Passes/Source/Rules/Patterns/CallPattern.cpp @@ -1,49 +1,51 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -#include "Rules/Patterns/CallPattern.hpp" - #include "Rules/IOperandPrototype.hpp" +#include "Rules/Patterns/CallPattern.hpp" -namespace microsoft { -namespace quantum { - -CallPattern::CallPattern(String const &name) - : name_{name} -{} - -CallPattern::~CallPattern() = default; - -bool CallPattern::match(Value *instr, Captures &captures) const +namespace microsoft { - auto *call_instr = llvm::dyn_cast(instr); - if (call_instr == nullptr) - { - return fail(instr, captures); - } - - auto target_function = call_instr->getCalledFunction(); - if (target_function == nullptr) - { - return fail(instr, captures); - } - - auto name = target_function->getName(); - - if (name != name_) - { - return fail(instr, captures); - } - - return success(instr, captures); -} - -CallPattern::Child CallPattern::copy() const +namespace quantum { - auto ret = std::make_shared(name_); - ret->copyPropertiesFrom(*this); - return std::move(ret); -} -} // namespace quantum -} // namespace microsoft + CallPattern::CallPattern(String const& name) + : name_{name} + { + } + + CallPattern::~CallPattern() = default; + + bool CallPattern::match(Value* instr, Captures& captures) const + { + auto* call_instr = llvm::dyn_cast(instr); + if (call_instr == nullptr) + { + return fail(instr, captures); + } + + auto target_function = call_instr->getCalledFunction(); + if (target_function == nullptr) + { + return fail(instr, captures); + } + + auto name = target_function->getName(); + + if (name != name_) + { + return fail(instr, captures); + } + + return success(instr, captures); + } + + CallPattern::Child CallPattern::copy() const + { + auto ret = std::make_shared(name_); + ret->copyPropertiesFrom(*this); + return std::move(ret); + } + +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Rules/Patterns/CallPattern.hpp b/src/Passes/Source/Rules/Patterns/CallPattern.hpp index d13f822247..d25c8a7ff2 100644 --- a/src/Passes/Source/Rules/Patterns/CallPattern.hpp +++ b/src/Passes/Source/Rules/Patterns/CallPattern.hpp @@ -2,47 +2,50 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -#include "Llvm/Llvm.hpp" #include "Rules/IOperandPrototype.hpp" +#include "Llvm/Llvm.hpp" + #include #include -namespace microsoft { -namespace quantum { - -class CallPattern : public IOperandPrototype +namespace microsoft +{ +namespace quantum { -public: - using String = std::string; - // Construction of the call pattern by name or move only. - // + class CallPattern : public IOperandPrototype + { + public: + using String = std::string; + + // Construction of the call pattern by name or move only. + // - /// Construction by name. - explicit CallPattern(String const &name); + /// Construction by name. + explicit CallPattern(String const& name); - /// Copy construction prohibited. - CallPattern(CallPattern const &other) = delete; + /// Copy construction prohibited. + CallPattern(CallPattern const& other) = delete; - /// Move construction allowed. - CallPattern(CallPattern &&other) = default; + /// Move construction allowed. + CallPattern(CallPattern&& other) = default; - /// Destructor implementation. - ~CallPattern() override; + /// Destructor implementation. + ~CallPattern() override; - // Call implmenetation of the member functions in IOperandPrototype. - // + // Call implmenetation of the member functions in IOperandPrototype. + // - /// Matches the callee by name. - bool match(Value *instr, Captures &captures) const override; + /// Matches the callee by name. + bool match(Value* instr, Captures& captures) const override; - /// Creates a copy of itself. - Child copy() const override; + /// Creates a copy of itself. + Child copy() const override; -private: - String name_{}; ///< Name of the callee to match against. -}; + private: + String name_{}; ///< Name of the callee to match against. + }; -} // namespace quantum -} // namespace microsoft +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Rules/Patterns/Instruction.cpp b/src/Passes/Source/Rules/Patterns/Instruction.cpp index 8b9dca6870..03c05a8fe4 100644 --- a/src/Passes/Source/Rules/Patterns/Instruction.cpp +++ b/src/Passes/Source/Rules/Patterns/Instruction.cpp @@ -1,174 +1,175 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -#include "Rules/Patterns/Instruction.hpp" - #include "Rules/IOperandPrototype.hpp" +#include "Rules/Patterns/Instruction.hpp" -namespace microsoft { -namespace quantum { - -bool StorePattern::match(Value *instr, Captures &captures) const -{ - auto *load_instr = llvm::dyn_cast(instr); - if (load_instr == nullptr) - { - return fail(instr, captures); - } - - return success(instr, captures); -} - -StorePattern::Child StorePattern::copy() const -{ - auto ret = std::make_shared(); - ret->copyPropertiesFrom(*this); - return std::move(ret); -} - -bool LoadPattern::match(Value *instr, Captures &captures) const -{ - auto *load_instr = llvm::dyn_cast(instr); - if (load_instr == nullptr) - { - return fail(instr, captures); - } - - return success(instr, captures); -} - -LoadPattern::Child LoadPattern::copy() const -{ - auto ret = std::make_shared(); - ret->copyPropertiesFrom(*this); - return std::move(ret); -} - -bool BitCastPattern::match(Value *instr, Captures &captures) const -{ - auto *load_instr = llvm::dyn_cast(instr); - if (load_instr == nullptr) - { - return fail(instr, captures); - } - - return success(instr, captures); -} - -BitCastPattern::Child BitCastPattern::copy() const -{ - auto ret = std::make_shared(); - ret->copyPropertiesFrom(*this); - return std::move(ret); -} - -bool IntToPtrPattern::match(Value *instr, Captures &captures) const -{ - auto *load_instr = llvm::dyn_cast(instr); - if (load_instr == nullptr) - { - return fail(instr, captures); - } - - return success(instr, captures); -} - -IntToPtrPattern::Child IntToPtrPattern::copy() const -{ - auto ret = std::make_shared(); - ret->copyPropertiesFrom(*this); - return std::move(ret); -} - -bool ConstIntPattern::match(Value *instr, Captures &captures) const -{ - auto *load_instr = llvm::dyn_cast(instr); - if (load_instr == nullptr) - { - return fail(instr, captures); - } - - return success(instr, captures); -} - -ConstIntPattern::Child ConstIntPattern::copy() const -{ - auto ret = std::make_shared(); - ret->copyPropertiesFrom(*this); - return std::move(ret); -} - -bool BranchPattern::match(Value *instr, Captures &captures) const -{ - auto *load_instr = llvm::dyn_cast(instr); - if (load_instr == nullptr) - { - return fail(instr, captures); - } - - return success(instr, captures); -} - -BranchPattern::Child BranchPattern::copy() const -{ - auto ret = std::make_shared(); - ret->copyPropertiesFrom(*this); - return std::move(ret); -} - -bool SelectPattern::match(Value *instr, Captures &captures) const -{ - auto *load_instr = llvm::dyn_cast(instr); - if (load_instr == nullptr) - { - return fail(instr, captures); - } - - return success(instr, captures); -} - -SelectPattern::Child SelectPattern::copy() const -{ - auto ret = std::make_shared(); - ret->copyPropertiesFrom(*this); - return std::move(ret); -} - -bool BasicBlockPattern::match(Value *instr, Captures &captures) const -{ - auto *load_instr = llvm::dyn_cast(instr); - if (load_instr == nullptr) - { - return fail(instr, captures); - } - - return success(instr, captures); -} - -BasicBlockPattern::Child BasicBlockPattern::copy() const -{ - auto ret = std::make_shared(); - ret->copyPropertiesFrom(*this); - return std::move(ret); -} - -bool SwitchPattern::match(Value *instr, Captures &captures) const -{ - auto *load_instr = llvm::dyn_cast(instr); - if (load_instr == nullptr) - { - return fail(instr, captures); - } - - return success(instr, captures); -} - -SwitchPattern::Child SwitchPattern::copy() const -{ - auto ret = std::make_shared(); - ret->copyPropertiesFrom(*this); - return std::move(ret); -} - -} // namespace quantum -} // namespace microsoft +namespace microsoft +{ +namespace quantum +{ + + bool StorePattern::match(Value* instr, Captures& captures) const + { + auto* load_instr = llvm::dyn_cast(instr); + if (load_instr == nullptr) + { + return fail(instr, captures); + } + + return success(instr, captures); + } + + StorePattern::Child StorePattern::copy() const + { + auto ret = std::make_shared(); + ret->copyPropertiesFrom(*this); + return std::move(ret); + } + + bool LoadPattern::match(Value* instr, Captures& captures) const + { + auto* load_instr = llvm::dyn_cast(instr); + if (load_instr == nullptr) + { + return fail(instr, captures); + } + + return success(instr, captures); + } + + LoadPattern::Child LoadPattern::copy() const + { + auto ret = std::make_shared(); + ret->copyPropertiesFrom(*this); + return std::move(ret); + } + + bool BitCastPattern::match(Value* instr, Captures& captures) const + { + auto* load_instr = llvm::dyn_cast(instr); + if (load_instr == nullptr) + { + return fail(instr, captures); + } + + return success(instr, captures); + } + + BitCastPattern::Child BitCastPattern::copy() const + { + auto ret = std::make_shared(); + ret->copyPropertiesFrom(*this); + return std::move(ret); + } + + bool IntToPtrPattern::match(Value* instr, Captures& captures) const + { + auto* load_instr = llvm::dyn_cast(instr); + if (load_instr == nullptr) + { + return fail(instr, captures); + } + + return success(instr, captures); + } + + IntToPtrPattern::Child IntToPtrPattern::copy() const + { + auto ret = std::make_shared(); + ret->copyPropertiesFrom(*this); + return std::move(ret); + } + + bool ConstIntPattern::match(Value* instr, Captures& captures) const + { + auto* load_instr = llvm::dyn_cast(instr); + if (load_instr == nullptr) + { + return fail(instr, captures); + } + + return success(instr, captures); + } + + ConstIntPattern::Child ConstIntPattern::copy() const + { + auto ret = std::make_shared(); + ret->copyPropertiesFrom(*this); + return std::move(ret); + } + + bool BranchPattern::match(Value* instr, Captures& captures) const + { + auto* load_instr = llvm::dyn_cast(instr); + if (load_instr == nullptr) + { + return fail(instr, captures); + } + + return success(instr, captures); + } + + BranchPattern::Child BranchPattern::copy() const + { + auto ret = std::make_shared(); + ret->copyPropertiesFrom(*this); + return std::move(ret); + } + + bool SelectPattern::match(Value* instr, Captures& captures) const + { + auto* load_instr = llvm::dyn_cast(instr); + if (load_instr == nullptr) + { + return fail(instr, captures); + } + + return success(instr, captures); + } + + SelectPattern::Child SelectPattern::copy() const + { + auto ret = std::make_shared(); + ret->copyPropertiesFrom(*this); + return std::move(ret); + } + + bool BasicBlockPattern::match(Value* instr, Captures& captures) const + { + auto* load_instr = llvm::dyn_cast(instr); + if (load_instr == nullptr) + { + return fail(instr, captures); + } + + return success(instr, captures); + } + + BasicBlockPattern::Child BasicBlockPattern::copy() const + { + auto ret = std::make_shared(); + ret->copyPropertiesFrom(*this); + return std::move(ret); + } + + bool SwitchPattern::match(Value* instr, Captures& captures) const + { + auto* load_instr = llvm::dyn_cast(instr); + if (load_instr == nullptr) + { + return fail(instr, captures); + } + + return success(instr, captures); + } + + SwitchPattern::Child SwitchPattern::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/Patterns/Instruction.hpp b/src/Passes/Source/Rules/Patterns/Instruction.hpp index 7e1c7c9cf1..3d4e3ed37b 100644 --- a/src/Passes/Source/Rules/Patterns/Instruction.hpp +++ b/src/Passes/Source/Rules/Patterns/Instruction.hpp @@ -2,77 +2,80 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -#include "Llvm/Llvm.hpp" #include "Rules/IOperandPrototype.hpp" +#include "Llvm/Llvm.hpp" + #include #include -namespace microsoft { -namespace quantum { - -class StorePattern : public IOperandPrototype +namespace microsoft { -public: - bool match(Value *instr, Captures &captures) const override; - Child copy() const override; -}; - -class LoadPattern : public IOperandPrototype +namespace quantum { -public: - bool match(Value *instr, Captures &captures) const override; - Child copy() const override; -}; -class BitCastPattern : public IOperandPrototype -{ -public: - bool match(Value *instr, Captures &captures) const override; - Child copy() const override; -}; + class StorePattern : public IOperandPrototype + { + public: + bool match(Value* instr, Captures& captures) const override; + Child copy() const override; + }; -class IntToPtrPattern : public IOperandPrototype -{ -public: - bool match(Value *instr, Captures &captures) const override; - Child copy() const override; -}; + class LoadPattern : public IOperandPrototype + { + public: + bool match(Value* instr, Captures& captures) const override; + Child copy() const override; + }; -class ConstIntPattern : public IOperandPrototype -{ -public: - bool match(Value *instr, Captures &captures) const override; - Child copy() const override; -}; + class BitCastPattern : public IOperandPrototype + { + public: + bool match(Value* instr, Captures& captures) const override; + Child copy() const override; + }; -class BranchPattern : public IOperandPrototype -{ -public: - bool match(Value *instr, Captures &captures) const override; - Child copy() const override; -}; + class IntToPtrPattern : public IOperandPrototype + { + public: + bool match(Value* instr, Captures& captures) const override; + Child copy() const override; + }; -class SelectPattern : public IOperandPrototype -{ -public: - bool match(Value *instr, Captures &captures) const override; - Child copy() const override; -}; + class ConstIntPattern : public IOperandPrototype + { + public: + bool match(Value* instr, Captures& captures) const override; + Child copy() const override; + }; -class BasicBlockPattern : public IOperandPrototype -{ -public: - bool match(Value *instr, Captures &captures) const override; - Child copy() const override; -}; + class BranchPattern : public IOperandPrototype + { + public: + bool match(Value* instr, Captures& captures) const override; + Child copy() const override; + }; -class SwitchPattern : public IOperandPrototype -{ -public: - bool match(Value *instr, Captures &captures) const override; - Child copy() const override; -}; + class SelectPattern : public IOperandPrototype + { + public: + bool match(Value* instr, Captures& captures) const override; + Child copy() const override; + }; + + class BasicBlockPattern : public IOperandPrototype + { + public: + bool match(Value* instr, Captures& captures) const override; + Child copy() const override; + }; + + class SwitchPattern : public IOperandPrototype + { + public: + bool match(Value* instr, Captures& captures) const override; + Child copy() const override; + }; -} // namespace quantum -} // namespace microsoft +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Rules/Patterns/PhiPattern.cpp b/src/Passes/Source/Rules/Patterns/PhiPattern.cpp index 6b2dcb0ce4..d18f2931da 100644 --- a/src/Passes/Source/Rules/Patterns/PhiPattern.cpp +++ b/src/Passes/Source/Rules/Patterns/PhiPattern.cpp @@ -1,32 +1,33 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -#include "Rules/Patterns/PhiPattern.hpp" - #include "Rules/IOperandPrototype.hpp" +#include "Rules/Patterns/PhiPattern.hpp" -namespace microsoft { -namespace quantum { +namespace microsoft +{ +namespace quantum +{ -PhiPattern::~PhiPattern() = default; + 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); - } + 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); -} + return success(instr, captures); + } -PhiPattern::Child PhiPattern::copy() const -{ - auto ret = std::make_shared(); - ret->copyPropertiesFrom(*this); - return std::move(ret); -} + PhiPattern::Child PhiPattern::copy() const + { + auto ret = std::make_shared(); + ret->copyPropertiesFrom(*this); + return std::move(ret); + } -} // namespace quantum -} // namespace microsoft +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Rules/Patterns/UnnamedInvokePattern.cpp b/src/Passes/Source/Rules/Patterns/UnnamedInvokePattern.cpp index 93df15dac1..b517f27b64 100644 --- a/src/Passes/Source/Rules/Patterns/UnnamedInvokePattern.cpp +++ b/src/Passes/Source/Rules/Patterns/UnnamedInvokePattern.cpp @@ -1,32 +1,33 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -#include "Rules/Patterns/UnnamedInvokePattern.hpp" - #include "Rules/IOperandPrototype.hpp" +#include "Rules/Patterns/UnnamedInvokePattern.hpp" -namespace microsoft { -namespace quantum { +namespace microsoft +{ +namespace quantum +{ -UnnamedInvokePattern::~UnnamedInvokePattern() = default; + UnnamedInvokePattern::~UnnamedInvokePattern() = default; -bool UnnamedInvokePattern::match(Value *instr, Captures &captures) const -{ - auto *call_instr = llvm::dyn_cast(instr); - if (call_instr == nullptr) - { - return fail(instr, captures); - } + bool UnnamedInvokePattern::match(Value* instr, Captures& captures) const + { + auto* call_instr = llvm::dyn_cast(instr); + if (call_instr == nullptr) + { + return fail(instr, captures); + } - return success(instr, captures); -} + return success(instr, captures); + } -UnnamedInvokePattern::Child UnnamedInvokePattern::copy() const -{ - auto ret = std::make_shared(); - ret->copyPropertiesFrom(*this); - return std::move(ret); -} + UnnamedInvokePattern::Child UnnamedInvokePattern::copy() const + { + auto ret = std::make_shared(); + ret->copyPropertiesFrom(*this); + return std::move(ret); + } -} // namespace quantum -} // namespace microsoft +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Rules/ReplacementRule.hpp b/src/Passes/Source/Rules/ReplacementRule.hpp index 3d700f7f07..6a3e6ae398 100644 --- a/src/Passes/Source/Rules/ReplacementRule.hpp +++ b/src/Passes/Source/Rules/ReplacementRule.hpp @@ -2,74 +2,76 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -#include "Llvm/Llvm.hpp" #include "Rules/Patterns/AnyPattern.hpp" #include "Rules/Patterns/CallPattern.hpp" #include "Rules/Patterns/Instruction.hpp" +#include "Llvm/Llvm.hpp" + #include #include -namespace microsoft { -namespace quantum { - -/// Rule that describes a pattern and how to make a replacement of the matched values. -/// The class contains a OperandPrototype which is used to test whether an LLVM IR value -/// follows a specific pattern. The class also holds a function pointer to logic that -/// allows replacement of the specified value. -class ReplacementRule +namespace microsoft +{ +namespace quantum { -public: - /// Table to store LLVM values using a name. - using Captures = IOperandPrototype::Captures; - /// Value alias for shorthand usage. - using Value = llvm::Value; + /// Rule that describes a pattern and how to make a replacement of the matched values. + /// The class contains a OperandPrototype which is used to test whether an LLVM IR value + /// follows a specific pattern. The class also holds a function pointer to logic that + /// allows replacement of the specified value. + class ReplacementRule + { + public: + /// Table to store LLVM values using a name. + using Captures = IOperandPrototype::Captures; + + /// Value alias for shorthand usage. + using Value = llvm::Value; - /// Pointer to the pattern type. - using IOperandPrototypePtr = std::shared_ptr; + /// Pointer to the pattern type. + using IOperandPrototypePtr = std::shared_ptr; - /// Builder alias for shorthand notation. - using Builder = llvm::IRBuilder<>; + /// Builder alias for shorthand notation. + using Builder = llvm::IRBuilder<>; - /// List of replacements. - using Replacements = std::vector>; + /// List of replacements. + using Replacements = std::vector>; - /// Function to perform replacements. - using ReplaceFunction = std::function; + /// Function to perform replacements. + using ReplaceFunction = std::function; - // Constructors and destructors - // + // Constructors and destructors + // - ReplacementRule() = default; - ReplacementRule(IOperandPrototypePtr &&pattern, ReplaceFunction &&replacer); + ReplacementRule() = default; + ReplacementRule(IOperandPrototypePtr&& pattern, ReplaceFunction&& replacer); - // Rule configuration - // + // Rule configuration + // - /// Sets the pattern describing logic to be replaced. - void setPattern(IOperandPrototypePtr &&pattern); + /// Sets the pattern describing logic to be replaced. + void setPattern(IOperandPrototypePtr&& pattern); - /// Sets the replacer logic which given a successful match will perform - /// a replacement on the IR. - void setReplacer(ReplaceFunction const &replacer); + /// Sets the replacer logic which given a successful match will perform + /// a replacement on the IR. + void setReplacer(ReplaceFunction const& replacer); - // Operation - // + // Operation + // - /// Tests whether a given value matches the rule pattern and store captures. - /// The function returns true if the match was successful in which case captures - /// are recorded. - bool match(Value *value, Captures &captures) const; + /// Tests whether a given value matches the rule pattern and store captures. + /// The function returns true if the match was successful in which case captures + /// are recorded. + bool match(Value* value, Captures& captures) const; - /// Invokes the replacer given a matched value and its corresponding captures - bool replace(Builder &builder, Value *value, Captures &captures, - Replacements &replacements) const; + /// Invokes the replacer given a matched value and its corresponding captures + bool replace(Builder& builder, Value* value, Captures& captures, Replacements& replacements) const; -private: - IOperandPrototypePtr pattern_{nullptr}; ///< Pattern to be matched against - ReplaceFunction replacer_{nullptr}; ///< Function to perform replacement upon match. -}; + private: + IOperandPrototypePtr pattern_{nullptr}; ///< Pattern to be matched against + ReplaceFunction replacer_{nullptr}; ///< Function to perform replacement upon match. + }; -} // namespace quantum -} // namespace microsoft +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/TransformationRulesPass/TransformationRulesPass.hpp b/src/Passes/Source/TransformationRulesPass/TransformationRulesPass.hpp index 2a964fc9b4..3c003d011f 100644 --- a/src/Passes/Source/TransformationRulesPass/TransformationRulesPass.hpp +++ b/src/Passes/Source/TransformationRulesPass/TransformationRulesPass.hpp @@ -2,228 +2,232 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -#include "Llvm/Llvm.hpp" #include "Logging/ILogger.hpp" #include "Profile/Profile.hpp" #include "QatTypes/QatTypes.hpp" #include "Rules/RuleSet.hpp" #include "TransformationRulesPass/TransformationRulesPassConfiguration.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 │◀─┘ -/// └───────────────────────────────┘ -/// -/// Copying and expanding functions identifies function calls and identifies compile time constants -/// passed to the function. It then copies the full implementation of the function, replacing all -/// compile-time constants (and hence changing the function signature). That is, if a function call -/// `f(x, 9)` is identified, it is replaced with `f.1(x)` where `f.1` is a copy of `f` with second -/// argument written into the function. -/// -class TransformationRulesPass : public llvm::PassInfoMixin +namespace microsoft +{ +namespace quantum { -public: - using Replacements = ReplacementRule::Replacements; - using Instruction = llvm::Instruction; - using Rules = std::vector; - using Value = llvm::Value; - using Builder = ReplacementRule::Builder; - using AllocationManagerPtr = IAllocationManager::AllocationManagerPtr; - using Captures = RuleSet::Captures; - using ConstantArguments = std::unordered_map; - using ILoggerPtr = std::shared_ptr; - - // Construction and destruction configuration. - // - - /// Custom default constructor - TransformationRulesPass(RuleSet &&rule_set, TransformationRulesPassConfiguration const &config, - Profile *profile); - - /// Copy construction is banned. - TransformationRulesPass(TransformationRulesPass const &) = delete; - - /// We allow move semantics. - TransformationRulesPass(TransformationRulesPass &&) = default; - - /// Default destruction. - ~TransformationRulesPass() = default; - - // Operators - // - - /// Copy assignment is banned. - TransformationRulesPass &operator=(TransformationRulesPass const &) = delete; - - /// Move assignment is permitted. - TransformationRulesPass &operator=(TransformationRulesPass &&) = 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 functions - // - - /// Generic function to apply a instructionModifier (lambda function) to every instruction in the - /// function `function`. This method follows the execution path to the extend possible and deals - /// with branching if the branch statement can be evaluated at compile time. - bool runOnFunction(llvm::Function &function, InstructionModifier const &modifier); - - /// Applies each of the replacements in the `replacements_` variable. - void processReplacements(); - - // Copy and expand - // - - /// Configuration function for copy and expand to setup the necessary rules. - void setupCopyAndExpand(); - - /// Main function for running the copy and expand functionality. This function first identifies - /// the entry point and then follows every execution path to copy the callee function for every - /// call instruction encountered. This makes that every call in the code has its own unique callee - /// function which ensures that when allocating qubits or results, the assigned registers are not - /// accidentally reused. - void runCopyAndExpand(llvm::Module &module, llvm::ModuleAnalysisManager &mam); - - /// Test whether the instruction is a call instruction and copy the callee in case it is. This - /// function collects instructions which are scheduled for deletion at a later point. - llvm::Value *copyAndExpand(llvm::Value *input, DeletableInstructions &); - - /// Copies the function body and replace function arguments whenever arguments are constant. - llvm::Function *expandFunctionCall(llvm::Function & callee, - ConstantArguments const &const_args = {}); - - /// Folds all constant expression in function. - void constantFoldFunction(llvm::Function &callee); - - /// Helper function to create replacements for constant expressions. - void addConstExprRule(ReplacementRule &&rule); - // 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; + /// 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 │◀─┘ + /// └───────────────────────────────┘ + /// + /// Copying and expanding functions identifies function calls and identifies compile time constants + /// passed to the function. It then copies the full implementation of the function, replacing all + /// compile-time constants (and hence changing the function signature). That is, if a function call + /// `f(x, 9)` is identified, it is replaced with `f.1(x)` where `f.1` is a copy of `f` with second + /// argument written into the function. + /// + class TransformationRulesPass : 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 = IAllocationManager::AllocationManagerPtr; + using Captures = RuleSet::Captures; + using ConstantArguments = std::unordered_map; + using ILoggerPtr = std::shared_ptr; + + // Construction and destruction configuration. + // + + /// Custom default constructor + TransformationRulesPass( + RuleSet&& rule_set, + TransformationRulesPassConfiguration const& config, + Profile* profile); + + /// Copy construction is banned. + TransformationRulesPass(TransformationRulesPass const&) = delete; + + /// We allow move semantics. + TransformationRulesPass(TransformationRulesPass&&) = default; + + /// Default destruction. + ~TransformationRulesPass() = default; + + // Operators + // + + /// Copy assignment is banned. + TransformationRulesPass& operator=(TransformationRulesPass const&) = delete; + + /// Move assignment is permitted. + TransformationRulesPass& operator=(TransformationRulesPass&&) = 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 functions + // + + /// Generic function to apply a instructionModifier (lambda function) to every instruction in the + /// function `function`. This method follows the execution path to the extend possible and deals + /// with branching if the branch statement can be evaluated at compile time. + bool runOnFunction(llvm::Function& function, InstructionModifier const& modifier); + + /// Applies each of the replacements in the `replacements_` variable. + void processReplacements(); + + // Copy and expand + // + + /// Configuration function for copy and expand to setup the necessary rules. + void setupCopyAndExpand(); + + /// Main function for running the copy and expand functionality. This function first identifies + /// the entry point and then follows every execution path to copy the callee function for every + /// call instruction encountered. This makes that every call in the code has its own unique callee + /// function which ensures that when allocating qubits or results, the assigned registers are not + /// accidentally reused. + void runCopyAndExpand(llvm::Module& module, llvm::ModuleAnalysisManager& mam); + + /// Test whether the instruction is a call instruction and copy the callee in case it is. This + /// function collects instructions which are scheduled for deletion at a later point. + llvm::Value* copyAndExpand(llvm::Value* input, DeletableInstructions&); + + /// Copies the function body and replace function arguments whenever arguments are constant. + llvm::Function* expandFunctionCall(llvm::Function& callee, ConstantArguments const& const_args = {}); + + /// Folds all constant expression in function. + void constantFoldFunction(llvm::Function& callee); + + /// Helper function to create replacements for constant expressions. + void addConstExprRule(ReplacementRule&& rule); + + // 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 followUsers(llvm::Value *value); + void followUsers(llvm::Value* value); - // Phi replacement - // + // Phi replacement + // - /// Function which replaces phi nodes which refer to inactive blocks. That is, in cases where - /// branch statement evaluates at compile time, only one block will be marked as active. For those - /// case we can eliminate the phi nodes. In the case where branch statements cannot be evaluated - /// all are marked as active. In this case, phi nodes are left unchanged. - void runReplacePhi(llvm::Module &module, llvm::ModuleAnalysisManager &mam); + /// Function which replaces phi nodes which refer to inactive blocks. That is, in cases where + /// branch statement evaluates at compile time, only one block will be marked as active. For those + /// case we can eliminate the phi nodes. In the case where branch statements cannot be evaluated + /// all are marked as active. In this case, phi nodes are left unchanged. + void runReplacePhi(llvm::Module& module, llvm::ModuleAnalysisManager& mam); - // Rules - // + // Rules + // - void runApplyRules(llvm::Module &module, llvm::ModuleAnalysisManager &mam); - bool onQubitRelease(llvm::Instruction *instruction, Captures &captures); - bool onQubitAllocate(llvm::Instruction *instruction, Captures &captures); + 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(); + /// Whether or not this pass is required to run. + static bool isRequired(); - // Logger - // - void setLogger(ILoggerPtr logger); + // Logger + // + void setLogger(ILoggerPtr logger); -private: - // Pass configuration - // + private: + // Pass configuration + // - /// Rule set which describes a set of transformations to apply to the QIR. - RuleSet rule_set_{}; + /// Rule set which describes a set of transformations to apply to the QIR. + RuleSet rule_set_{}; - /// Configuration with enabled or disabled features, recursion limits etc. - TransformationRulesPassConfiguration config_{}; + /// Configuration with enabled or disabled features, recursion limits etc. + TransformationRulesPassConfiguration config_{}; - // Logging and data collection - // + // Logging and data collection + // - /// Logger which is used to collect information, debug info, warnings, errors and internal errors. - ILoggerPtr logger_{nullptr}; + /// Logger which is used to collect information, debug info, warnings, errors and internal errors. + ILoggerPtr logger_{nullptr}; - // Execution path unrolling - // + // Execution path unrolling + // - /// Current recursion depth which is used to prevent unbound (at compile time) recursion. - uint64_t depth_{0}; + /// Current recursion depth which is used to prevent unbound (at compile time) recursion. + uint64_t depth_{0}; - // Copy and expand - // + // Copy and expand + // - /// Rule set which is used to collapse compile-time constant expressions. - RuleSet const_expr_replacements_{}; + /// Rule set which is used to collapse compile-time constant expressions. + RuleSet const_expr_replacements_{}; - // Dead code elimination - // + // Dead code elimination + // - /// Set to track active Values in the code. - std::unordered_set active_pieces_{}; + /// Set to track active Values in the code. + std::unordered_set active_pieces_{}; - /// Vector with block pointers to delete - std::vector blocks_to_delete_{}; + /// Vector with block pointers to delete + std::vector blocks_to_delete_{}; - /// Vector of function pointers to delete - std::vector functions_to_delete_{}; + /// Vector of function pointers to delete + std::vector functions_to_delete_{}; - // Phi detection - // + // Phi detection + // - /// Registered replacements to be executed. - Replacements replacements_; + /// Registered replacements to be executed. + Replacements replacements_; - // Profile - // + // Profile + // - /// Pointer to the current profile. This pointer is used to annotate top level functions with - /// regards to how many qubits they require. TODO(tfr): Consider moving into its own component. - Profile *profile_{nullptr}; -}; + /// Pointer to the current profile. This pointer is used to annotate top level functions with + /// regards to how many qubits they require. TODO(tfr): Consider moving into its own component. + Profile* profile_{nullptr}; + }; -} // namespace quantum -} // namespace microsoft +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/ValidationPass/ValidationPass.hpp b/src/Passes/Source/ValidationPass/ValidationPass.hpp index 9e1b96d2a4..03948b198b 100644 --- a/src/Passes/Source/ValidationPass/ValidationPass.hpp +++ b/src/Passes/Source/ValidationPass/ValidationPass.hpp @@ -2,52 +2,56 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -#include "Llvm/Llvm.hpp" #include "Logging/ILogger.hpp" #include "Profile/Profile.hpp" #include "QatTypes/QatTypes.hpp" #include "ValidationPass/ValidationPassConfiguration.hpp" +#include "Llvm/Llvm.hpp" + #include #include #include -namespace microsoft { -namespace quantum { - -class ValidationPass : public llvm::PassInfoMixin +namespace microsoft +{ +namespace quantum { -public: - using Instruction = llvm::Instruction; - using Value = llvm::Value; - // Construction and destruction configuration. - // + class ValidationPass : public llvm::PassInfoMixin + { + public: + using Instruction = llvm::Instruction; + using Value = llvm::Value; + + // Construction and destruction configuration. + // - explicit ValidationPass(ValidationPassConfiguration const &cfg) - : config_{cfg} - {} + explicit ValidationPass(ValidationPassConfiguration const& cfg) + : config_{cfg} + { + } - /// Copy construction is banned. - ValidationPass(ValidationPass const &) = delete; + /// Copy construction is banned. + ValidationPass(ValidationPass const&) = delete; - /// We allow move semantics. - ValidationPass(ValidationPass &&) = default; + /// We allow move semantics. + ValidationPass(ValidationPass&&) = default; - /// Default destruction. - ~ValidationPass() = default; + /// Default destruction. + ~ValidationPass() = default; - llvm::PreservedAnalyses run(llvm::Module &module, llvm::ModuleAnalysisManager &mam); - /// Whether or not this pass is required to run. - static bool isRequired(); + llvm::PreservedAnalyses run(llvm::Module& module, llvm::ModuleAnalysisManager& mam); + /// Whether or not this pass is required to run. + static bool isRequired(); -private: - ValidationPassConfiguration config_{}; + private: + ValidationPassConfiguration config_{}; - std::unordered_map opcodes_; - std::unordered_map external_calls_; - std::unordered_map internal_calls_; -}; + std::unordered_map opcodes_; + std::unordered_map external_calls_; + std::unordered_map internal_calls_; + }; -} // namespace quantum -} // namespace microsoft +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/ValidationPass/ValidationPassConfiguration.hpp b/src/Passes/Source/ValidationPass/ValidationPassConfiguration.hpp index 164ba1b353..0bf3fbd1ba 100644 --- a/src/Passes/Source/ValidationPass/ValidationPassConfiguration.hpp +++ b/src/Passes/Source/ValidationPass/ValidationPassConfiguration.hpp @@ -5,88 +5,90 @@ #include "Commandline/ConfigurationManager.hpp" #include "QatTypes/QatTypes.hpp" -namespace microsoft { -namespace quantum { - -class ValidationPassConfiguration +namespace microsoft +{ +namespace quantum { -public: - using Set = std::unordered_set; - // Setup and construction - // - - /// Setup function that adds the configuration flags to the ConfigurationManager. See the - /// ConfigurationManager documentation for more details on how the setup process is implemented. - void setup(ConfigurationManager &config) - { - config.setSectionName("Validation configuration", ""); - config.addParameter(allow_internal_calls_, "allow-internal-calls", - "Whether or not internal calls are allowed."); - } - static ValidationPassConfiguration fromProfileName(String const &name) - { - auto ret = ValidationPassConfiguration(); - if (name == "generic") - { - ret.allow_internal_calls_ = true; - ret.whitelist_external_calls_ = false; - ret.whitelist_opcodes_ = false; - } - else if (name == "base") + class ValidationPassConfiguration { - ret.allow_internal_calls_ = false; - ret.whitelist_external_calls_ = true; - ret.whitelist_opcodes_ = true; - ret.opcodes_ = Set{"br", "call", "unreachable", "ret"}; - ret.external_calls_ = Set{"__quantum__qis__mz__body", "__quantum__qis__read_result__body", - "__quantum__qis__reset__body", "__quantum__qis__z__body", - "__quantum__qis__s__adj", "__quantum__qis__dumpregister__body", - "__quantum__qis__y__body", "__quantum__qis__x__body", - "__quantum__qis__t__body", "__quantum__qis__cz__body", - "__quantum__qis__s__body", "__quantum__qis__h__body", - "__quantum__qis__cnot__body", "__quantum__qis__sqrt__body"}; - } - else - { - throw std::runtime_error("Invalid profile " + name); - } - return ret; - } + public: + using Set = std::unordered_set; + // Setup and construction + // + + /// Setup function that adds the configuration flags to the ConfigurationManager. See the + /// ConfigurationManager documentation for more details on how the setup process is implemented. + void setup(ConfigurationManager& config) + { + config.setSectionName("Validation configuration", ""); + config.addParameter( + allow_internal_calls_, "allow-internal-calls", "Whether or not internal calls are allowed."); + } + + static ValidationPassConfiguration fromProfileName(String const& name) + { + auto ret = ValidationPassConfiguration(); + if (name == "generic") + { + ret.allow_internal_calls_ = true; + ret.whitelist_external_calls_ = false; + ret.whitelist_opcodes_ = false; + } + else if (name == "base") + { + ret.allow_internal_calls_ = false; + ret.whitelist_external_calls_ = true; + ret.whitelist_opcodes_ = true; + ret.opcodes_ = Set{"br", "call", "unreachable", "ret"}; + ret.external_calls_ = Set{"__quantum__qis__mz__body", "__quantum__qis__read_result__body", + "__quantum__qis__reset__body", "__quantum__qis__z__body", + "__quantum__qis__s__adj", "__quantum__qis__dumpregister__body", + "__quantum__qis__y__body", "__quantum__qis__x__body", + "__quantum__qis__t__body", "__quantum__qis__cz__body", + "__quantum__qis__s__body", "__quantum__qis__h__body", + "__quantum__qis__cnot__body", "__quantum__qis__sqrt__body"}; + } + else + { + throw std::runtime_error("Invalid profile " + name); + } + return ret; + } - Set const &allowedOpcodes() const - { - return opcodes_; - } + Set const& allowedOpcodes() const + { + return opcodes_; + } - Set const &allowedExternalCallNames() const - { - return external_calls_; - } + Set const& allowedExternalCallNames() const + { + return external_calls_; + } - bool allowInternalCalls() const - { - return allow_internal_calls_; - } + bool allowInternalCalls() const + { + return allow_internal_calls_; + } - bool whitelistOpcodes() const - { - return whitelist_opcodes_; - } + bool whitelistOpcodes() const + { + return whitelist_opcodes_; + } - bool whitelistExternalCalls() const - { - return whitelist_external_calls_; - } + bool whitelistExternalCalls() const + { + return whitelist_external_calls_; + } -private: - Set opcodes_{}; - Set external_calls_{}; + private: + Set opcodes_{}; + Set external_calls_{}; - bool whitelist_opcodes_{true}; - bool whitelist_external_calls_{true}; - bool allow_internal_calls_{false}; -}; + bool whitelist_opcodes_{true}; + bool whitelist_external_calls_{true}; + bool allow_internal_calls_{false}; + }; -} // namespace quantum -} // namespace microsoft +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Validator/Validator.cpp b/src/Passes/Source/Validator/Validator.cpp index cd0a4e38cc..966a97976e 100644 --- a/src/Passes/Source/Validator/Validator.cpp +++ b/src/Passes/Source/Validator/Validator.cpp @@ -1,78 +1,79 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. +#include "ValidationPass/ValidationPass.hpp" #include "Validator/Validator.hpp" #include "Llvm/Llvm.hpp" -#include "ValidationPass/ValidationPass.hpp" - -namespace microsoft { -namespace quantum { -Validator::Validator(ValidationPassConfiguration const &cfg, bool debug, - llvm::TargetMachine *target_machine) - : loop_analysis_manager_{debug} - , function_analysis_manager_{debug} - , gscc_analysis_manager_{debug} - , module_analysis_manager_{debug} +namespace microsoft +{ +namespace quantum { - pass_builder_ = std::make_unique(target_machine); + Validator::Validator(ValidationPassConfiguration const& cfg, bool debug, llvm::TargetMachine* target_machine) + : loop_analysis_manager_{debug} + , function_analysis_manager_{debug} + , gscc_analysis_manager_{debug} + , module_analysis_manager_{debug} + { - pass_builder_->registerModuleAnalyses(module_analysis_manager_); - pass_builder_->registerCGSCCAnalyses(gscc_analysis_manager_); - pass_builder_->registerFunctionAnalyses(function_analysis_manager_); - pass_builder_->registerLoopAnalyses(loop_analysis_manager_); + pass_builder_ = std::make_unique(target_machine); - pass_builder_->crossRegisterProxies(loop_analysis_manager_, function_analysis_manager_, - gscc_analysis_manager_, module_analysis_manager_); + pass_builder_->registerModuleAnalyses(module_analysis_manager_); + pass_builder_->registerCGSCCAnalyses(gscc_analysis_manager_); + pass_builder_->registerFunctionAnalyses(function_analysis_manager_); + pass_builder_->registerLoopAnalyses(loop_analysis_manager_); - module_pass_manager_.addPass(ValidationPass(cfg)); -} + pass_builder_->crossRegisterProxies( + loop_analysis_manager_, function_analysis_manager_, gscc_analysis_manager_, module_analysis_manager_); -bool Validator::validate(llvm::Module &module) -{ - llvm::VerifierAnalysis verifier; - auto result = verifier.run(module, module_analysis_manager_); + module_pass_manager_.addPass(ValidationPass(cfg)); + } - if (result.IRBroken) - { - llvm::errs() << "; Fatal error: Invalid IR.\n"; - return false; - } + bool Validator::validate(llvm::Module& module) + { + llvm::VerifierAnalysis verifier; + auto result = verifier.run(module, module_analysis_manager_); - try - { - module_pass_manager_.run(module, module_analysis_manager_); - } - catch (std::exception const &e) - { - llvm::errs() << "; Fatal error: " << e.what() << "\n"; - return false; - } - return true; -} + if (result.IRBroken) + { + llvm::errs() << "; Fatal error: Invalid IR.\n"; + return false; + } -llvm::PassBuilder &Validator::passBuilder() -{ - return *pass_builder_; -} -llvm::LoopAnalysisManager &Validator::loopAnalysisManager() -{ - return loop_analysis_manager_; -} -llvm::FunctionAnalysisManager &Validator::functionAnalysisManager() -{ - return function_analysis_manager_; -} -llvm::CGSCCAnalysisManager &Validator::gsccAnalysisManager() -{ - return gscc_analysis_manager_; -} -llvm::ModuleAnalysisManager &Validator::moduleAnalysisManager() -{ - return module_analysis_manager_; -} + try + { + module_pass_manager_.run(module, module_analysis_manager_); + } + catch (std::exception const& e) + { + llvm::errs() << "; Fatal error: " << e.what() << "\n"; + return false; + } + return true; + } + + llvm::PassBuilder& Validator::passBuilder() + { + return *pass_builder_; + } + llvm::LoopAnalysisManager& Validator::loopAnalysisManager() + { + return loop_analysis_manager_; + } + llvm::FunctionAnalysisManager& Validator::functionAnalysisManager() + { + return function_analysis_manager_; + } + llvm::CGSCCAnalysisManager& Validator::gsccAnalysisManager() + { + return gscc_analysis_manager_; + } + llvm::ModuleAnalysisManager& Validator::moduleAnalysisManager() + { + return module_analysis_manager_; + } -} // namespace quantum -} // namespace microsoft +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Validator/Validator.hpp b/src/Passes/Source/Validator/Validator.hpp index 578d6ba1b9..6848691e1f 100644 --- a/src/Passes/Source/Validator/Validator.hpp +++ b/src/Passes/Source/Validator/Validator.hpp @@ -4,76 +4,81 @@ #include "AllocationManager/AllocationManager.hpp" #include "AllocationManager/IAllocationManager.hpp" -#include "Llvm/Llvm.hpp" #include "ValidationPass/ValidationPassConfiguration.hpp" -#include +#include "Llvm/Llvm.hpp" -namespace microsoft { -namespace quantum { +#include -/// Validator class that defines a set of rules which constitutes the profile definition. Each of -/// the rules can be used to transform a generic QIR and/or validate that the QIR is compliant with -/// said rule. -class Validator +namespace microsoft +{ +namespace quantum { -public: - using ValidatorPtr = std::unique_ptr; - // Constructors - // + /// Validator class that defines a set of rules which constitutes the profile definition. Each of + /// the rules can be used to transform a generic QIR and/or validate that the QIR is compliant with + /// said rule. + class Validator + { + public: + using ValidatorPtr = std::unique_ptr; + + // Constructors + // - explicit Validator(ValidationPassConfiguration const &cfg, bool debug, - llvm::TargetMachine *target_machine = nullptr); + explicit Validator( + ValidationPassConfiguration const& cfg, + bool debug, + llvm::TargetMachine* target_machine = nullptr); - // Default construction not allowed to ensure that LLVM modules and passes are set up correctly. - // Copy construction is prohibited due to restriction on classes held by Validator. + // Default construction not allowed to ensure that LLVM modules and passes are set up correctly. + // Copy construction is prohibited due to restriction on classes held by Validator. - Validator() = delete; - Validator(Validator const &) = delete; - Validator(Validator &&) = default; - Validator &operator=(Validator const &) = delete; - Validator &operator=(Validator &&) = default; - ~Validator() = default; + Validator() = delete; + Validator(Validator const&) = delete; + Validator(Validator&&) = default; + Validator& operator=(Validator const&) = delete; + Validator& operator=(Validator&&) = default; + ~Validator() = default; - // Validator methods - // + // Validator methods + // - /// Validates that a module complies with the specified QIR profile. Returns true if the module is - /// valid and false otherwise. - bool validate(llvm::Module &module); + /// Validates that a module complies with the specified QIR profile. Returns true if the module is + /// valid and false otherwise. + bool validate(llvm::Module& module); -protected: - using PassBuilderPtr = std::unique_ptr; + protected: + using PassBuilderPtr = std::unique_ptr; - /// Returns a reference to the pass builder. - llvm::PassBuilder &passBuilder(); + /// Returns a reference to the pass builder. + llvm::PassBuilder& passBuilder(); - /// Returns a reference to the loop analysis manager. - llvm::LoopAnalysisManager &loopAnalysisManager(); + /// Returns a reference to the loop analysis manager. + llvm::LoopAnalysisManager& loopAnalysisManager(); - /// Returns a reference to the function analysis manager. - llvm::FunctionAnalysisManager &functionAnalysisManager(); + /// Returns a reference to the function analysis manager. + llvm::FunctionAnalysisManager& functionAnalysisManager(); - /// Returns a reference to the GSCC analysis manager. - llvm::CGSCCAnalysisManager &gsccAnalysisManager(); + /// Returns a reference to the GSCC analysis manager. + llvm::CGSCCAnalysisManager& gsccAnalysisManager(); - /// Returns a reference to the module analysis manager. - llvm::ModuleAnalysisManager &moduleAnalysisManager(); + /// Returns a reference to the module analysis manager. + llvm::ModuleAnalysisManager& moduleAnalysisManager(); -private: - // LLVM logic to run the passes - // + private: + // LLVM logic to run the passes + // - llvm::LoopAnalysisManager loop_analysis_manager_; - llvm::FunctionAnalysisManager function_analysis_manager_; - llvm::CGSCCAnalysisManager gscc_analysis_manager_; - llvm::ModuleAnalysisManager module_analysis_manager_; + llvm::LoopAnalysisManager loop_analysis_manager_; + llvm::FunctionAnalysisManager function_analysis_manager_; + llvm::CGSCCAnalysisManager gscc_analysis_manager_; + llvm::ModuleAnalysisManager module_analysis_manager_; - PassBuilderPtr pass_builder_; + PassBuilderPtr pass_builder_; - llvm::ModulePassManager module_pass_manager_{}; -}; + llvm::ModulePassManager module_pass_manager_{}; + }; -} // namespace quantum -} // namespace microsoft +} // namespace quantum +} // namespace microsoft From b39b173a8631a8156a51aaf3ac27d006b286efa6 Mon Sep 17 00:00:00 2001 From: "Troels F. Roennow" Date: Mon, 8 Nov 2021 11:26:10 +0100 Subject: [PATCH 08/17] Changing default to interop friendly --- .../TransformationRulesPassConfiguration.hpp | 150 +++++++++-------- .../ValidationPassConfiguration.hpp | 151 +++++++++--------- 2 files changed, 149 insertions(+), 152 deletions(-) diff --git a/src/Passes/Source/TransformationRulesPass/TransformationRulesPassConfiguration.hpp b/src/Passes/Source/TransformationRulesPass/TransformationRulesPassConfiguration.hpp index e027c56957..cc48bdd35f 100644 --- a/src/Passes/Source/TransformationRulesPass/TransformationRulesPassConfiguration.hpp +++ b/src/Passes/Source/TransformationRulesPass/TransformationRulesPassConfiguration.hpp @@ -4,106 +4,104 @@ #include "Commandline/ConfigurationManager.hpp" -namespace microsoft +namespace microsoft { +namespace quantum { +/// Configuration class for the RuleTransformation pass. +class TransformationRulesPassConfiguration { -namespace quantum -{ - /// Configuration class for the RuleTransformation pass. - class TransformationRulesPassConfiguration - { - public: - // Setup and construction - // +public: + // Setup and construction + // - /// Setup function that attached the configuration to the ConfigurationManager. - void setup(ConfigurationManager& config); + /// Setup function that attached the configuration to the ConfigurationManager. + void setup(ConfigurationManager &config); - /// Creates a configuration where all functionality is disabled. - static TransformationRulesPassConfiguration createDisabled(); + /// Creates a configuration where all functionality is disabled. + static TransformationRulesPassConfiguration createDisabled(); - // Configuration classes - // + // Configuration classes + // - /// Tests whether all functionality is disabled for this component. - bool isDisabled() const; + /// Tests whether all functionality is disabled for this component. + bool isDisabled() const; - /// Testing equality of two configurations - bool operator==(TransformationRulesPassConfiguration const& ref) const; + /// Testing equality of two configurations + bool operator==(TransformationRulesPassConfiguration const &ref) const; - // Properties - // + // Properties + // - /// Whether or not the component should delete dead code. - bool shouldDeleteDeadCode() const; + /// Whether or not the component should delete dead code. + bool shouldDeleteDeadCode() const; - /// Whether or not the component should clone functions. This is relevant in relation to qubit - /// allocation if execution paths are expanded. - bool shouldCloneFunctions() const; + /// Whether or not the component should clone functions. This is relevant in relation to qubit + /// allocation if execution paths are expanded. + bool shouldCloneFunctions() const; - /// Whether or not we assume that the code does not throw at runtime. - bool assumeNoExceptions() const; + /// Whether or not we assume that the code does not throw at runtime. + bool assumeNoExceptions() const; - /// Whether or not the component should follow the execution path only or it should be applied to - /// all parts of the code. For statically allocated qubits one generally wants to follow the - /// execution path whereas it makes more sense to apply to all parts of the code for dynamic qubit - /// allocation. - bool shouldTransformExecutionPathOnly() const; + /// Whether or not the component should follow the execution path only or it should be applied to + /// all parts of the code. For statically allocated qubits one generally wants to follow the + /// execution path whereas it makes more sense to apply to all parts of the code for dynamic qubit + /// allocation. + bool shouldTransformExecutionPathOnly() const; - /// The maximum recursion acceptable when unrolling the execution path. - uint64_t maxRecursion() const; + /// The maximum recursion acceptable when unrolling the execution path. + uint64_t maxRecursion() const; - /// Whether or not to reuse qubits. - bool shouldReuseQubits() const; + /// Whether or not to reuse qubits. + bool shouldReuseQubits() const; - /// Whether or not to annotate entry point with the number of qubits they use. - bool shouldAnnotateQubitUse() const; + /// Whether or not to annotate entry point with the number of qubits they use. + bool shouldAnnotateQubitUse() const; - /// Whether or not to reuse result registers. - bool shouldReuseResults() const; + /// Whether or not to reuse result registers. + bool shouldReuseResults() const; - /// Whether or not to annotate entry point with the number of results they use. - bool shouldAnnotateResultUse() const; + /// Whether or not to annotate entry point with the number of results they use. + bool shouldAnnotateResultUse() const; - /// Whether or not the component should attempt to group measurements. - bool shouldGroupMeasurements() const; + /// Whether or not the component should attempt to group measurements. + bool shouldGroupMeasurements() const; - /// Whether or not the target supports measurement (and result interpretation) during the circuit - /// execution. - bool oneShotMeasurement() const; + /// Whether or not the target supports measurement (and result interpretation) during the circuit + /// execution. + bool oneShotMeasurement() const; - /// Whether or not simplify the IR using LLVM passes prior to transforming the IR. - bool shouldSimplifyPriorTransform() const; + /// Whether or not simplify the IR using LLVM passes prior to transforming the IR. + bool shouldSimplifyPriorTransform() const; - /// Attribute which indicate that a function is the entry point. - std::string entryPointAttr() const; + /// Attribute which indicate that a function is the entry point. + std::string entryPointAttr() const; - private: - // Code expansion and trimming - // +private: + // Code expansion and trimming + // - bool delete_dead_code_{true}; - bool clone_functions_{true}; - bool transform_execution_path_only_{true}; - uint64_t max_recursion_{512}; - std::string entry_point_attr_{"EntryPoint"}; + bool delete_dead_code_{true}; + bool clone_functions_{true}; + bool transform_execution_path_only_{true}; + uint64_t max_recursion_{512}; + std::string entry_point_attr_{"InteropFriendly"}; - bool simplify_prior_transformation_{true}; + bool simplify_prior_transformation_{true}; - // Branching - bool assume_no_exceptions_{false}; + // Branching + bool assume_no_exceptions_{false}; - // Allocation options - // - bool reuse_qubits_{true}; - bool annotate_qubit_use_{true}; - bool reuse_results_{true}; - bool annotate_result_use_{true}; + // Allocation options + // + bool reuse_qubits_{true}; + bool annotate_qubit_use_{true}; + bool reuse_results_{true}; + bool annotate_result_use_{true}; - // Measurement - // - bool group_measurements_{false}; - bool one_shot_measurement_{true}; - }; + // Measurement + // + bool group_measurements_{false}; + bool one_shot_measurement_{true}; +}; -} // namespace quantum -} // namespace microsoft +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/ValidationPass/ValidationPassConfiguration.hpp b/src/Passes/Source/ValidationPass/ValidationPassConfiguration.hpp index 0bf3fbd1ba..d413d22b15 100644 --- a/src/Passes/Source/ValidationPass/ValidationPassConfiguration.hpp +++ b/src/Passes/Source/ValidationPass/ValidationPassConfiguration.hpp @@ -5,90 +5,89 @@ #include "Commandline/ConfigurationManager.hpp" #include "QatTypes/QatTypes.hpp" -namespace microsoft -{ -namespace quantum -{ +namespace microsoft { +namespace quantum { - class ValidationPassConfiguration - { - public: - using Set = std::unordered_set; - // Setup and construction - // +class ValidationPassConfiguration +{ +public: + using Set = std::unordered_set; + // Setup and construction + // - /// Setup function that adds the configuration flags to the ConfigurationManager. See the - /// ConfigurationManager documentation for more details on how the setup process is implemented. - void setup(ConfigurationManager& config) - { - config.setSectionName("Validation configuration", ""); - config.addParameter( - allow_internal_calls_, "allow-internal-calls", "Whether or not internal calls are allowed."); - } + /// Setup function that adds the configuration flags to the ConfigurationManager. See the + /// ConfigurationManager documentation for more details on how the setup process is implemented. + void setup(ConfigurationManager &config) + { + config.setSectionName("Validation configuration", ""); + config.addParameter(allow_internal_calls_, "allow-internal-calls", + "Whether or not internal calls are allowed."); + } - static ValidationPassConfiguration fromProfileName(String const& name) - { - auto ret = ValidationPassConfiguration(); - if (name == "generic") - { - ret.allow_internal_calls_ = true; - ret.whitelist_external_calls_ = false; - ret.whitelist_opcodes_ = false; - } - else if (name == "base") - { - ret.allow_internal_calls_ = false; - ret.whitelist_external_calls_ = true; - ret.whitelist_opcodes_ = true; - ret.opcodes_ = Set{"br", "call", "unreachable", "ret"}; - ret.external_calls_ = Set{"__quantum__qis__mz__body", "__quantum__qis__read_result__body", - "__quantum__qis__reset__body", "__quantum__qis__z__body", - "__quantum__qis__s__adj", "__quantum__qis__dumpregister__body", - "__quantum__qis__y__body", "__quantum__qis__x__body", - "__quantum__qis__t__body", "__quantum__qis__cz__body", - "__quantum__qis__s__body", "__quantum__qis__h__body", - "__quantum__qis__cnot__body", "__quantum__qis__sqrt__body"}; - } - else - { - throw std::runtime_error("Invalid profile " + name); - } - return ret; - } + static ValidationPassConfiguration fromProfileName(String const &name) + { + auto ret = ValidationPassConfiguration(); + if (name == "generic") + { + ret.allow_internal_calls_ = true; + ret.whitelist_external_calls_ = false; + ret.whitelist_opcodes_ = false; + } + else if (name == "base") + { + ret.allow_internal_calls_ = false; + ret.whitelist_external_calls_ = true; + ret.whitelist_opcodes_ = true; + ret.opcodes_ = Set{"br", "call", "unreachable", "ret"}; + ret.external_calls_ = Set{"__quantum__qis__mz__body", "__quantum__qis__read_result__body", + "__quantum__qis__reset__body", "__quantum__qis__z__body", + "__quantum__qis__s__adj", "__quantum__qis__dumpregister__body", + "__quantum__qis__y__body", "__quantum__qis__x__body", + "__quantum__qis__t__body", "__quantum__qis__cz__body", + "__quantum__qis__s__body", "__quantum__qis__h__body", + "__quantum__qis__cnot__body", "__quantum__qis__sqrt__body", + "__quantum__qis__crz__body", "__quantum__qis__rz__body"}; + } + else + { + throw std::runtime_error("Invalid profile " + name); + } + return ret; + } - Set const& allowedOpcodes() const - { - return opcodes_; - } + Set const &allowedOpcodes() const + { + return opcodes_; + } - Set const& allowedExternalCallNames() const - { - return external_calls_; - } + Set const &allowedExternalCallNames() const + { + return external_calls_; + } - bool allowInternalCalls() const - { - return allow_internal_calls_; - } + bool allowInternalCalls() const + { + return allow_internal_calls_; + } - bool whitelistOpcodes() const - { - return whitelist_opcodes_; - } + bool whitelistOpcodes() const + { + return whitelist_opcodes_; + } - bool whitelistExternalCalls() const - { - return whitelist_external_calls_; - } + bool whitelistExternalCalls() const + { + return whitelist_external_calls_; + } - private: - Set opcodes_{}; - Set external_calls_{}; +private: + Set opcodes_{}; + Set external_calls_{}; - bool whitelist_opcodes_{true}; - bool whitelist_external_calls_{true}; - bool allow_internal_calls_{false}; - }; + bool whitelist_opcodes_{true}; + bool whitelist_external_calls_{true}; + bool allow_internal_calls_{false}; +}; -} // namespace quantum -} // namespace microsoft +} // namespace quantum +} // namespace microsoft From 0c485967b17ad9fcbef77439ce4cd748ec6408e9 Mon Sep 17 00:00:00 2001 From: "Troels F. Roennow" Date: Mon, 8 Nov 2021 11:38:31 +0100 Subject: [PATCH 09/17] Updating base profile --- .../Source/ValidationPass/ValidationPassConfiguration.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Passes/Source/ValidationPass/ValidationPassConfiguration.hpp b/src/Passes/Source/ValidationPass/ValidationPassConfiguration.hpp index d413d22b15..ab37b3f8a1 100644 --- a/src/Passes/Source/ValidationPass/ValidationPassConfiguration.hpp +++ b/src/Passes/Source/ValidationPass/ValidationPassConfiguration.hpp @@ -38,7 +38,7 @@ class ValidationPassConfiguration ret.allow_internal_calls_ = false; ret.whitelist_external_calls_ = true; ret.whitelist_opcodes_ = true; - ret.opcodes_ = Set{"br", "call", "unreachable", "ret"}; + ret.opcodes_ = Set{"br", "call", "unreachable", "ret", "phi", "select"}; ret.external_calls_ = Set{"__quantum__qis__mz__body", "__quantum__qis__read_result__body", "__quantum__qis__reset__body", "__quantum__qis__z__body", "__quantum__qis__s__adj", "__quantum__qis__dumpregister__body", From 82c11d35346103b79c3f689ce83056c518b4d654 Mon Sep 17 00:00:00 2001 From: "Troels F. Roennow" Date: Mon, 8 Nov 2021 16:03:04 +0100 Subject: [PATCH 10/17] Styling --- .../TransformationRulesPassConfiguration.hpp | 150 ++++++++--------- .../ValidationPassConfiguration.hpp | 152 +++++++++--------- .../site-packages/tasks_ci/formatting.py | 1 + 3 files changed, 154 insertions(+), 149 deletions(-) diff --git a/src/Passes/Source/TransformationRulesPass/TransformationRulesPassConfiguration.hpp b/src/Passes/Source/TransformationRulesPass/TransformationRulesPassConfiguration.hpp index cc48bdd35f..67a958228e 100644 --- a/src/Passes/Source/TransformationRulesPass/TransformationRulesPassConfiguration.hpp +++ b/src/Passes/Source/TransformationRulesPass/TransformationRulesPassConfiguration.hpp @@ -4,104 +4,106 @@ #include "Commandline/ConfigurationManager.hpp" -namespace microsoft { -namespace quantum { -/// Configuration class for the RuleTransformation pass. -class TransformationRulesPassConfiguration +namespace microsoft { -public: - // Setup and construction - // +namespace quantum +{ + /// Configuration class for the RuleTransformation pass. + class TransformationRulesPassConfiguration + { + public: + // Setup and construction + // - /// Setup function that attached the configuration to the ConfigurationManager. - void setup(ConfigurationManager &config); + /// Setup function that attached the configuration to the ConfigurationManager. + void setup(ConfigurationManager& config); - /// Creates a configuration where all functionality is disabled. - static TransformationRulesPassConfiguration createDisabled(); + /// Creates a configuration where all functionality is disabled. + static TransformationRulesPassConfiguration createDisabled(); - // Configuration classes - // + // Configuration classes + // - /// Tests whether all functionality is disabled for this component. - bool isDisabled() const; + /// Tests whether all functionality is disabled for this component. + bool isDisabled() const; - /// Testing equality of two configurations - bool operator==(TransformationRulesPassConfiguration const &ref) const; + /// Testing equality of two configurations + bool operator==(TransformationRulesPassConfiguration const& ref) const; - // Properties - // + // Properties + // - /// Whether or not the component should delete dead code. - bool shouldDeleteDeadCode() const; + /// Whether or not the component should delete dead code. + bool shouldDeleteDeadCode() const; - /// Whether or not the component should clone functions. This is relevant in relation to qubit - /// allocation if execution paths are expanded. - bool shouldCloneFunctions() const; + /// Whether or not the component should clone functions. This is relevant in relation to qubit + /// allocation if execution paths are expanded. + bool shouldCloneFunctions() const; - /// Whether or not we assume that the code does not throw at runtime. - bool assumeNoExceptions() const; + /// Whether or not we assume that the code does not throw at runtime. + bool assumeNoExceptions() const; - /// Whether or not the component should follow the execution path only or it should be applied to - /// all parts of the code. For statically allocated qubits one generally wants to follow the - /// execution path whereas it makes more sense to apply to all parts of the code for dynamic qubit - /// allocation. - bool shouldTransformExecutionPathOnly() const; + /// Whether or not the component should follow the execution path only or it should be applied to + /// all parts of the code. For statically allocated qubits one generally wants to follow the + /// execution path whereas it makes more sense to apply to all parts of the code for dynamic qubit + /// allocation. + bool shouldTransformExecutionPathOnly() const; - /// The maximum recursion acceptable when unrolling the execution path. - uint64_t maxRecursion() const; + /// The maximum recursion acceptable when unrolling the execution path. + uint64_t maxRecursion() const; - /// Whether or not to reuse qubits. - bool shouldReuseQubits() const; + /// Whether or not to reuse qubits. + bool shouldReuseQubits() const; - /// Whether or not to annotate entry point with the number of qubits they use. - bool shouldAnnotateQubitUse() const; + /// Whether or not to annotate entry point with the number of qubits they use. + bool shouldAnnotateQubitUse() const; - /// Whether or not to reuse result registers. - bool shouldReuseResults() const; + /// Whether or not to reuse result registers. + bool shouldReuseResults() const; - /// Whether or not to annotate entry point with the number of results they use. - bool shouldAnnotateResultUse() const; + /// Whether or not to annotate entry point with the number of results they use. + bool shouldAnnotateResultUse() const; - /// Whether or not the component should attempt to group measurements. - bool shouldGroupMeasurements() const; + /// Whether or not the component should attempt to group measurements. + bool shouldGroupMeasurements() const; - /// Whether or not the target supports measurement (and result interpretation) during the circuit - /// execution. - bool oneShotMeasurement() const; + /// Whether or not the target supports measurement (and result interpretation) during the circuit + /// execution. + bool oneShotMeasurement() const; - /// Whether or not simplify the IR using LLVM passes prior to transforming the IR. - bool shouldSimplifyPriorTransform() const; + /// Whether or not simplify the IR using LLVM passes prior to transforming the IR. + bool shouldSimplifyPriorTransform() const; - /// Attribute which indicate that a function is the entry point. - std::string entryPointAttr() const; + /// Attribute which indicate that a function is the entry point. + std::string entryPointAttr() const; -private: - // Code expansion and trimming - // + private: + // Code expansion and trimming + // - bool delete_dead_code_{true}; - bool clone_functions_{true}; - bool transform_execution_path_only_{true}; - uint64_t max_recursion_{512}; - std::string entry_point_attr_{"InteropFriendly"}; + bool delete_dead_code_{true}; + bool clone_functions_{true}; + bool transform_execution_path_only_{true}; + uint64_t max_recursion_{512}; + std::string entry_point_attr_{"InteropFriendly"}; - bool simplify_prior_transformation_{true}; + bool simplify_prior_transformation_{true}; - // Branching - bool assume_no_exceptions_{false}; + // Branching + bool assume_no_exceptions_{false}; - // Allocation options - // - bool reuse_qubits_{true}; - bool annotate_qubit_use_{true}; - bool reuse_results_{true}; - bool annotate_result_use_{true}; + // Allocation options + // + bool reuse_qubits_{true}; + bool annotate_qubit_use_{true}; + bool reuse_results_{true}; + bool annotate_result_use_{true}; - // Measurement - // - bool group_measurements_{false}; - bool one_shot_measurement_{true}; -}; + // Measurement + // + bool group_measurements_{false}; + bool one_shot_measurement_{true}; + }; -} // namespace quantum -} // namespace microsoft +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/ValidationPass/ValidationPassConfiguration.hpp b/src/Passes/Source/ValidationPass/ValidationPassConfiguration.hpp index ab37b3f8a1..44acedfc01 100644 --- a/src/Passes/Source/ValidationPass/ValidationPassConfiguration.hpp +++ b/src/Passes/Source/ValidationPass/ValidationPassConfiguration.hpp @@ -5,89 +5,91 @@ #include "Commandline/ConfigurationManager.hpp" #include "QatTypes/QatTypes.hpp" -namespace microsoft { -namespace quantum { - -class ValidationPassConfiguration +namespace microsoft +{ +namespace quantum { -public: - using Set = std::unordered_set; - // Setup and construction - // - - /// Setup function that adds the configuration flags to the ConfigurationManager. See the - /// ConfigurationManager documentation for more details on how the setup process is implemented. - void setup(ConfigurationManager &config) - { - config.setSectionName("Validation configuration", ""); - config.addParameter(allow_internal_calls_, "allow-internal-calls", - "Whether or not internal calls are allowed."); - } - static ValidationPassConfiguration fromProfileName(String const &name) - { - auto ret = ValidationPassConfiguration(); - if (name == "generic") - { - ret.allow_internal_calls_ = true; - ret.whitelist_external_calls_ = false; - ret.whitelist_opcodes_ = false; - } - else if (name == "base") + class ValidationPassConfiguration { - ret.allow_internal_calls_ = false; - ret.whitelist_external_calls_ = true; - ret.whitelist_opcodes_ = true; - ret.opcodes_ = Set{"br", "call", "unreachable", "ret", "phi", "select"}; - ret.external_calls_ = Set{"__quantum__qis__mz__body", "__quantum__qis__read_result__body", - "__quantum__qis__reset__body", "__quantum__qis__z__body", - "__quantum__qis__s__adj", "__quantum__qis__dumpregister__body", - "__quantum__qis__y__body", "__quantum__qis__x__body", - "__quantum__qis__t__body", "__quantum__qis__cz__body", - "__quantum__qis__s__body", "__quantum__qis__h__body", - "__quantum__qis__cnot__body", "__quantum__qis__sqrt__body", - "__quantum__qis__crz__body", "__quantum__qis__rz__body"}; - } - else - { - throw std::runtime_error("Invalid profile " + name); - } - return ret; - } + public: + using Set = std::unordered_set; + // Setup and construction + // + + /// Setup function that adds the configuration flags to the ConfigurationManager. See the + /// ConfigurationManager documentation for more details on how the setup process is implemented. + void setup(ConfigurationManager& config) + { + config.setSectionName("Validation configuration", ""); + config.addParameter( + allow_internal_calls_, "allow-internal-calls", "Whether or not internal calls are allowed."); + } + + static ValidationPassConfiguration fromProfileName(String const& name) + { + auto ret = ValidationPassConfiguration(); + if (name == "generic") + { + ret.allow_internal_calls_ = true; + ret.whitelist_external_calls_ = false; + ret.whitelist_opcodes_ = false; + } + else if (name == "base") + { + ret.allow_internal_calls_ = false; + ret.whitelist_external_calls_ = true; + ret.whitelist_opcodes_ = true; + ret.opcodes_ = Set{"br", "call", "unreachable", "ret", "phi", "select"}; + ret.external_calls_ = Set{"__quantum__qis__mz__body", "__quantum__qis__read_result__body", + "__quantum__qis__reset__body", "__quantum__qis__z__body", + "__quantum__qis__s__adj", "__quantum__qis__dumpregister__body", + "__quantum__qis__y__body", "__quantum__qis__x__body", + "__quantum__qis__t__body", "__quantum__qis__cz__body", + "__quantum__qis__s__body", "__quantum__qis__h__body", + "__quantum__qis__cnot__body", "__quantum__qis__sqrt__body", + "__quantum__qis__crz__body", "__quantum__qis__rz__body"}; + } + else + { + throw std::runtime_error("Invalid profile " + name); + } + return ret; + } - Set const &allowedOpcodes() const - { - return opcodes_; - } + Set const& allowedOpcodes() const + { + return opcodes_; + } - Set const &allowedExternalCallNames() const - { - return external_calls_; - } + Set const& allowedExternalCallNames() const + { + return external_calls_; + } - bool allowInternalCalls() const - { - return allow_internal_calls_; - } + bool allowInternalCalls() const + { + return allow_internal_calls_; + } - bool whitelistOpcodes() const - { - return whitelist_opcodes_; - } + bool whitelistOpcodes() const + { + return whitelist_opcodes_; + } - bool whitelistExternalCalls() const - { - return whitelist_external_calls_; - } + bool whitelistExternalCalls() const + { + return whitelist_external_calls_; + } -private: - Set opcodes_{}; - Set external_calls_{}; + private: + Set opcodes_{}; + Set external_calls_{}; - bool whitelist_opcodes_{true}; - bool whitelist_external_calls_{true}; - bool allow_internal_calls_{false}; -}; + bool whitelist_opcodes_{true}; + bool whitelist_external_calls_{true}; + bool allow_internal_calls_{false}; + }; -} // namespace quantum -} // namespace microsoft +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/site-packages/tasks_ci/formatting.py b/src/Passes/site-packages/tasks_ci/formatting.py index d6957315b9..c0217ae590 100644 --- a/src/Passes/site-packages/tasks_ci/formatting.py +++ b/src/Passes/site-packages/tasks_ci/formatting.py @@ -36,6 +36,7 @@ "rx", "ry", "reset", + "crz", "m", "t", "sqrt", From 8c645948eea7eb31e2a380261e0400f989406815 Mon Sep 17 00:00:00 2001 From: "Troels F. Roennow" Date: Tue, 9 Nov 2021 09:56:37 +0100 Subject: [PATCH 11/17] Updating logger --- src/Passes/Source/Apps/CMakeLists.txt | 2 +- src/Passes/Source/CMakeLists.txt | 6 +- src/Passes/Source/Logging/CommentLogger.cpp | 50 +++++ src/Passes/Source/Logging/CommentLogger.hpp | 44 +++++ src/Passes/Source/Logging/ILogger.cpp | 13 ++ src/Passes/Source/Logging/ILogger.hpp | 72 ++++--- src/Passes/Source/Logging/LogCollection.hpp | 130 +++++++------ .../Source/ValidationPass/ValidationPass.cpp | 176 +++++++++--------- .../Source/ValidationPass/ValidationPass.hpp | 67 +++---- .../ValidationPassConfiguration.hpp | 158 ++++++++-------- src/Passes/Source/Validator/Validator.cpp | 125 +++++++------ src/Passes/Source/Validator/Validator.hpp | 109 ++++++----- 12 files changed, 533 insertions(+), 419 deletions(-) create mode 100644 src/Passes/Source/Logging/CommentLogger.cpp create mode 100644 src/Passes/Source/Logging/CommentLogger.hpp create mode 100644 src/Passes/Source/Logging/ILogger.cpp diff --git a/src/Passes/Source/Apps/CMakeLists.txt b/src/Passes/Source/Apps/CMakeLists.txt index a8dcf31059..4ec3771104 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/QatConfig.cpp) target_link_libraries(qat ${llvm_libs}) -target_link_libraries(qat TransformationRulesPass Rules AllocationManager Commandline Generators Profile Validator ValidationPass) +target_link_libraries(qat TransformationRulesPass Rules AllocationManager Commandline Generators Profile Validator ValidationPass Logging) diff --git a/src/Passes/Source/CMakeLists.txt b/src/Passes/Source/CMakeLists.txt index 7f882d392b..64bde26bc2 100644 --- a/src/Passes/Source/CMakeLists.txt +++ b/src/Passes/Source/CMakeLists.txt @@ -9,9 +9,11 @@ microsoft_add_library_tests(Commandline) microsoft_add_library(Profile) microsoft_add_library_tests(Profile) -microsoft_add_library(Validator) +microsoft_add_library(Logging) + +microsoft_add_library(Validator Logging) microsoft_add_library_tests(Validator ValidationPass) -microsoft_add_library(ValidationPass) +microsoft_add_library(ValidationPass Logging) microsoft_add_library(AllocationManager) microsoft_add_library_tests(AllocationManager) diff --git a/src/Passes/Source/Logging/CommentLogger.cpp b/src/Passes/Source/Logging/CommentLogger.cpp new file mode 100644 index 0000000000..adc4e225a1 --- /dev/null +++ b/src/Passes/Source/Logging/CommentLogger.cpp @@ -0,0 +1,50 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +#include "Logging/CommentLogger.hpp" + +#include "Llvm/Llvm.hpp" + +#include + +namespace microsoft { +namespace quantum { + +void CommentLogger::debug(String const &message) +{ + llvm::errs() << "debug - " << location_name_ << ":" << location_row_ << "," << location_col_ + << " - " << message << "\n"; +} + +void CommentLogger::info(String const &message) +{ + llvm::errs() << "info - " << location_name_ << ":" << location_row_ << "," << location_col_ + << " - " << message << "\n"; +} + +void CommentLogger::warning(String const &message) +{ + llvm::errs() << "warning - " << location_name_ << ":" << location_row_ << "," << location_col_ + << " - " << message << "\n"; +} + +void CommentLogger::error(String const &message) +{ + llvm::errs() << "error - " << location_name_ << ":" << location_row_ << "," << location_col_ + << " - " << message << "\n"; +} + +void CommentLogger::internalError(String const &message) +{ + llvm::errs() << "internal error - " << location_name_ << ":" << location_row_ << "," + << location_col_ << " - " << message << "\n"; +} + +void CommentLogger::setLocation(String const &name, uint64_t row, uint64_t col) +{ + location_name_ = name; + location_row_ = row; + location_col_ = col; +} + +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Logging/CommentLogger.hpp b/src/Passes/Source/Logging/CommentLogger.hpp new file mode 100644 index 0000000000..53db96a003 --- /dev/null +++ b/src/Passes/Source/Logging/CommentLogger.hpp @@ -0,0 +1,44 @@ +#pragma once +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "Logging/ILogger.hpp" + +#include + +namespace microsoft { +namespace quantum { + +/// Concrete ILogger implementation that prints all messages as IR comments to llvm::errs(). +class CommentLogger : public ILogger +{ +public: + // Interface implementation + // + + /// Adds a debug message to the list. + void debug(String const &message) override; + + /// Adds an info message to the list. + void info(String const &message) override; + + /// Adds a warning message to the list. + void warning(String const &message) override; + + /// Adds an error message to the list. + void error(String const &message) override; + + /// Adds an internal error message to the list. + void internalError(String const &message) override; + + /// Function that allows to set the current location. + void setLocation(String const &name, uint64_t row, uint64_t col) override; + +private: + String location_name_{""}; + uint64_t location_row_{0}; + uint64_t location_col_{0}; +}; + +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Logging/ILogger.cpp b/src/Passes/Source/Logging/ILogger.cpp new file mode 100644 index 0000000000..f528f9c3f7 --- /dev/null +++ b/src/Passes/Source/Logging/ILogger.cpp @@ -0,0 +1,13 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "Logging/ILogger.hpp" + +#include +#include + +namespace microsoft { +namespace quantum { +ILogger::~ILogger() = default; +} +} // namespace microsoft diff --git a/src/Passes/Source/Logging/ILogger.hpp b/src/Passes/Source/Logging/ILogger.hpp index e2db436aa7..2c66a1e446 100644 --- a/src/Passes/Source/Logging/ILogger.hpp +++ b/src/Passes/Source/Logging/ILogger.hpp @@ -7,51 +7,49 @@ #include #include -namespace microsoft -{ -namespace quantum -{ +namespace microsoft { +namespace quantum { - /// Logger interface to allow the collection of different types of messages during QIR - /// transformation and/or validation. - class ILogger - { - public: - // Constructors, copy and move operators and destructors - // +/// Logger interface to allow the collection of different types of messages during QIR +/// transformation and/or validation. +class ILogger +{ +public: + // Constructors, copy and move operators and destructors + // - ILogger() = default; - ILogger(ILogger const&) = default; - ILogger(ILogger&&) = default; - ILogger& operator=(ILogger const&) = default; - ILogger& operator=(ILogger&&) = default; + ILogger() = default; + ILogger(ILogger const &) = default; + ILogger(ILogger &&) = default; + ILogger &operator=(ILogger const &) = default; + ILogger &operator=(ILogger &&) = default; - virtual ~ILogger() = default; + virtual ~ILogger(); - // Abstract interface methods - // + // Abstract interface methods + // - /// Reports a debug message. - virtual void debug(String const& message) = 0; + /// Reports a debug message. + virtual void debug(String const &message) = 0; - /// Reports an info message. - virtual void info(String const& message) = 0; + /// Reports an info message. + virtual void info(String const &message) = 0; - /// Reports a warning message. - virtual void warning(String const& message) = 0; + /// Reports a warning message. + virtual void warning(String const &message) = 0; - /// Reports an error message. - virtual void error(String const& message) = 0; + /// Reports an error message. + virtual void error(String const &message) = 0; - /// Reports an internal error message. - virtual void internalError(String const& message) = 0; + /// Reports an internal error message. + virtual void internalError(String const &message) = 0; - /// Sets the current location. Importantly, the location can be set independently of the reported - /// messages. This allows one to update the location upon updating the cursor position without - /// having to worry about keeping a copy of the location to pass when reporting messages. - /// The most obvious case of this is file path (name) with a line and character (row, col). - virtual void setLocation(String const& name, uint64_t row, uint64_t col) = 0; - }; + /// Sets the current location. Importantly, the location can be set independently of the reported + /// messages. This allows one to update the location upon updating the cursor position without + /// having to worry about keeping a copy of the location to pass when reporting messages. + /// The most obvious case of this is file path (name) with a line and character (row, col). + virtual void setLocation(String const &name, uint64_t row, uint64_t col) = 0; +}; -} // namespace quantum -} // namespace microsoft +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Logging/LogCollection.hpp b/src/Passes/Source/Logging/LogCollection.hpp index 1e8b97f09f..7e3c3b98b6 100644 --- a/src/Passes/Source/Logging/LogCollection.hpp +++ b/src/Passes/Source/Logging/LogCollection.hpp @@ -6,70 +6,68 @@ #include -namespace microsoft -{ -namespace quantum -{ +namespace microsoft { +namespace quantum { - /// Concrete ILogger implementation that collects all messages and their corresponding location in a - /// list that can be traversed later on. - class LogCollection : public ILogger - { - public: - /// Class that holds the location of where the incident happened. - struct Location - { - String name{}; - uint64_t row{0}; - uint64_t col{0}; - }; - - /// Enum description what type of information we are conveying. - enum class Type - { - Debug, - Info, - Warning, - Error, - InternalError, - }; - - /// Struct to hold a message together with its type and location - struct Message - { - Type type; - Location location; - String message; - }; - - /// List of messages defined as alias. - using Messages = std::vector; - - // Interface implementation - // - - /// Adds a debug message to the list. - void debug(String const& message) override; - - /// Adds an info message to the list. - void info(String const& message) override; - - /// Adds a warning message to the list. - void warning(String const& message) override; - - /// Adds an error message to the list. - void error(String const& message) override; - - /// Adds an internal error message to the list. - void internalError(String const& message) override; - - /// Function that allows to set the current location. - void setLocation(String const& name, uint64_t row, uint64_t col) override; - - private: - Location current_location_{}; ///< Holds current location. - Messages messages_; ///< All messages emitted. - }; - -} // namespace quantum -} // namespace microsoft +/// Concrete ILogger implementation that collects all messages and their corresponding location in a +/// list that can be traversed later on. +class LogCollection : public ILogger +{ +public: + /// Class that holds the location of where the incident happened. + struct Location + { + String name{}; + uint64_t row{0}; + uint64_t col{0}; + }; + + /// Enum description what type of information we are conveying. + enum class Type + { + Debug, + Info, + Warning, + Error, + InternalError, + }; + + /// Struct to hold a message together with its type and location + struct Message + { + Type type; + Location location; + String message; + }; + + /// List of messages defined as alias. + using Messages = std::vector; + + // Interface implementation + // + + /// Adds a debug message to the list. + void debug(String const &message) override; + + /// Adds an info message to the list. + void info(String const &message) override; + + /// Adds a warning message to the list. + void warning(String const &message) override; + + /// Adds an error message to the list. + void error(String const &message) override; + + /// Adds an internal error message to the list. + void internalError(String const &message) override; + + /// Function that allows to set the current location. + void setLocation(String const &name, uint64_t row, uint64_t col) override; + +private: + Location current_location_{}; ///< Holds current location. + Messages messages_; ///< All messages emitted. +}; + +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/ValidationPass/ValidationPass.cpp b/src/Passes/Source/ValidationPass/ValidationPass.cpp index 84c6400dd4..70619afa95 100644 --- a/src/Passes/Source/ValidationPass/ValidationPass.cpp +++ b/src/Passes/Source/ValidationPass/ValidationPass.cpp @@ -8,108 +8,108 @@ #include #include -namespace microsoft +namespace microsoft { +namespace quantum { +llvm::PreservedAnalyses ValidationPass::run(llvm::Module &module, + llvm::ModuleAnalysisManager & /*mam*/) { -namespace quantum -{ - llvm::PreservedAnalyses ValidationPass::run(llvm::Module& module, llvm::ModuleAnalysisManager& /*mam*/) - { - for (auto& function : module) + for (auto &function : module) + { + for (auto &block : function) + { + for (auto &instr : block) + { + auto opname = instr.getOpcodeName(); + if (opcodes_.find(opname) != opcodes_.end()) { - for (auto& block : function) - { - for (auto& instr : block) - { - auto opname = instr.getOpcodeName(); - if (opcodes_.find(opname) != opcodes_.end()) - { - ++opcodes_[opname]; - } - else - { - opcodes_[opname] = 1; - } - auto call_instr = llvm::dyn_cast(&instr); - if (call_instr != nullptr) - { - auto f = call_instr->getCalledFunction(); - if (f == nullptr) - { - continue; - } - - auto name = static_cast(f->getName()); - if (f->isDeclaration()) - { - if (external_calls_.find(name) != external_calls_.end()) - { - ++external_calls_[name]; - } - else - { - external_calls_[name] = 1; - } - } - else - { - if (internal_calls_.find(name) != internal_calls_.end()) - { - ++internal_calls_[name]; - } - else - { - internal_calls_[name] = 1; - } - } - } - } - } + ++opcodes_[opname]; } - - bool raise_exception = false; - if (config_.whitelistOpcodes()) + else { - auto const& allowed_ops = config_.allowedOpcodes(); - for (auto const& k : opcodes_) - { - if (allowed_ops.find(k.first) == allowed_ops.end()) - { - llvm::errs() << "; Error: '" << k.first << "' is not allowed for this profile.\n"; - } - } + opcodes_[opname] = 1; } - if (config_.whitelistOpcodes()) + auto call_instr = llvm::dyn_cast(&instr); + if (call_instr != nullptr) { - auto const& allowed_functions = config_.allowedExternalCallNames(); - for (auto const& k : external_calls_) + auto f = call_instr->getCalledFunction(); + if (f == nullptr) + { + continue; + } + + auto name = static_cast(f->getName()); + if (f->isDeclaration()) + { + if (external_calls_.find(name) != external_calls_.end()) { - if (allowed_functions.find(k.first) == allowed_functions.end()) - { - llvm::errs() << "; Error: '" << k.first << "' is not allowed for this profile.\n"; - } + ++external_calls_[name]; } + else + { + external_calls_[name] = 1; + } + } + else + { + if (internal_calls_.find(name) != internal_calls_.end()) + { + ++internal_calls_[name]; + } + else + { + internal_calls_[name] = 1; + } + } } + } + } + } - if (!config_.allowInternalCalls() && !internal_calls_.empty()) - { - llvm::errs() << "; Error: Calls to custom defined functions not allowed\n"; - raise_exception = true; - } - - if (raise_exception) - { - throw std::runtime_error("QIR is not valid within the defined profile"); - } - - return llvm::PreservedAnalyses::all(); + bool raise_exception = false; + if (config_.whitelistOpcodes()) + { + auto const &allowed_ops = config_.allowedOpcodes(); + for (auto const &k : opcodes_) + { + if (allowed_ops.find(k.first) == allowed_ops.end()) + { + logger_->error("'" + k.first + "' is not allowed for this profile."); + } } + } - bool ValidationPass::isRequired() + if (config_.whitelistOpcodes()) + { + auto const &allowed_functions = config_.allowedExternalCallNames(); + for (auto const &k : external_calls_) { - return true; + if (allowed_functions.find(k.first) == allowed_functions.end()) + { + logger_->error("'" + k.first + "' is not allowed for this profile."); + } } + } + + if (!config_.allowInternalCalls() && !internal_calls_.empty()) + { + logger_->error("Calls to custom defined functions not allowed."); + raise_exception = true; + } + + if (raise_exception) + { + throw std::runtime_error("QIR is not valid within the defined profile"); + } + + return llvm::PreservedAnalyses::all(); +} + +bool ValidationPass::isRequired() +{ + return true; +} -} // namespace quantum -} // namespace microsoft +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/ValidationPass/ValidationPass.hpp b/src/Passes/Source/ValidationPass/ValidationPass.hpp index 03948b198b..3340be2f4a 100644 --- a/src/Passes/Source/ValidationPass/ValidationPass.hpp +++ b/src/Passes/Source/ValidationPass/ValidationPass.hpp @@ -2,56 +2,57 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. +#include "Llvm/Llvm.hpp" #include "Logging/ILogger.hpp" #include "Profile/Profile.hpp" #include "QatTypes/QatTypes.hpp" #include "ValidationPass/ValidationPassConfiguration.hpp" -#include "Llvm/Llvm.hpp" - #include #include #include -namespace microsoft -{ -namespace quantum +namespace microsoft { +namespace quantum { + +class ValidationPass : public llvm::PassInfoMixin { +public: + using Instruction = llvm::Instruction; + using Value = llvm::Value; + using ILoggerPtr = std::shared_ptr; - class ValidationPass : public llvm::PassInfoMixin - { - public: - using Instruction = llvm::Instruction; - using Value = llvm::Value; + // Construction and destruction configuration. + // - // Construction and destruction configuration. - // + explicit ValidationPass(ValidationPassConfiguration const &cfg, + ILoggerPtr const & logger = nullptr) + : config_{cfg} + , logger_{logger} + {} - explicit ValidationPass(ValidationPassConfiguration const& cfg) - : config_{cfg} - { - } + /// Copy construction is banned. + ValidationPass(ValidationPass const &) = delete; - /// Copy construction is banned. - ValidationPass(ValidationPass const&) = delete; + /// We allow move semantics. + ValidationPass(ValidationPass &&) = default; - /// We allow move semantics. - ValidationPass(ValidationPass&&) = default; + /// Default destruction. + ~ValidationPass() = default; - /// Default destruction. - ~ValidationPass() = default; + llvm::PreservedAnalyses run(llvm::Module &module, llvm::ModuleAnalysisManager &mam); + /// Whether or not this pass is required to run. + static bool isRequired(); - llvm::PreservedAnalyses run(llvm::Module& module, llvm::ModuleAnalysisManager& mam); - /// Whether or not this pass is required to run. - static bool isRequired(); +private: + ValidationPassConfiguration config_{}; - private: - ValidationPassConfiguration config_{}; + std::unordered_map opcodes_; + std::unordered_map external_calls_; + std::unordered_map internal_calls_; - std::unordered_map opcodes_; - std::unordered_map external_calls_; - std::unordered_map internal_calls_; - }; + ILoggerPtr logger_{nullptr}; +}; -} // namespace quantum -} // namespace microsoft +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/ValidationPass/ValidationPassConfiguration.hpp b/src/Passes/Source/ValidationPass/ValidationPassConfiguration.hpp index 44acedfc01..b9dcfe847e 100644 --- a/src/Passes/Source/ValidationPass/ValidationPassConfiguration.hpp +++ b/src/Passes/Source/ValidationPass/ValidationPassConfiguration.hpp @@ -5,91 +5,97 @@ #include "Commandline/ConfigurationManager.hpp" #include "QatTypes/QatTypes.hpp" -namespace microsoft -{ -namespace quantum +namespace microsoft { +namespace quantum { + +class ValidationPassConfiguration { +public: + using Set = std::unordered_set; + // Setup and construction + // - class ValidationPassConfiguration - { - public: - using Set = std::unordered_set; - // Setup and construction - // + /// Setup function that adds the configuration flags to the ConfigurationManager. See the + /// ConfigurationManager documentation for more details on how the setup process is implemented. + void setup(ConfigurationManager &config) + { + config.setSectionName("Validation configuration", ""); + config.addParameter(allow_internal_calls_, "allow-internal-calls", + "Whether or not internal calls are allowed."); + config.addParameter(allow_internal_calls_, "save-validation-report", + "Saves the validation report to specified filename."); + } - /// Setup function that adds the configuration flags to the ConfigurationManager. See the - /// ConfigurationManager documentation for more details on how the setup process is implemented. - void setup(ConfigurationManager& config) - { - config.setSectionName("Validation configuration", ""); - config.addParameter( - allow_internal_calls_, "allow-internal-calls", "Whether or not internal calls are allowed."); - } + static ValidationPassConfiguration fromProfileName(String const &name) + { + auto ret = ValidationPassConfiguration(); + if (name == "generic") + { + ret.allow_internal_calls_ = true; + ret.whitelist_external_calls_ = false; + ret.whitelist_opcodes_ = false; + } + else if (name == "base") + { + ret.allow_internal_calls_ = false; + ret.whitelist_external_calls_ = true; + ret.whitelist_opcodes_ = true; + ret.opcodes_ = Set{"br", "call", "unreachable", "ret", "phi", "select"}; + ret.external_calls_ = Set{"__quantum__qis__mz__body", "__quantum__qis__read_result__body", + "__quantum__qis__reset__body", "__quantum__qis__z__body", + "__quantum__qis__s__adj", "__quantum__qis__dumpregister__body", + "__quantum__qis__y__body", "__quantum__qis__x__body", + "__quantum__qis__t__body", "__quantum__qis__cz__body", + "__quantum__qis__s__body", "__quantum__qis__h__body", + "__quantum__qis__cnot__body", "__quantum__qis__sqrt__body", + "__quantum__qis__crz__body", "__quantum__qis__rz__body"}; + } + else + { + throw std::runtime_error("Invalid profile " + name); + } + return ret; + } - static ValidationPassConfiguration fromProfileName(String const& name) - { - auto ret = ValidationPassConfiguration(); - if (name == "generic") - { - ret.allow_internal_calls_ = true; - ret.whitelist_external_calls_ = false; - ret.whitelist_opcodes_ = false; - } - else if (name == "base") - { - ret.allow_internal_calls_ = false; - ret.whitelist_external_calls_ = true; - ret.whitelist_opcodes_ = true; - ret.opcodes_ = Set{"br", "call", "unreachable", "ret", "phi", "select"}; - ret.external_calls_ = Set{"__quantum__qis__mz__body", "__quantum__qis__read_result__body", - "__quantum__qis__reset__body", "__quantum__qis__z__body", - "__quantum__qis__s__adj", "__quantum__qis__dumpregister__body", - "__quantum__qis__y__body", "__quantum__qis__x__body", - "__quantum__qis__t__body", "__quantum__qis__cz__body", - "__quantum__qis__s__body", "__quantum__qis__h__body", - "__quantum__qis__cnot__body", "__quantum__qis__sqrt__body", - "__quantum__qis__crz__body", "__quantum__qis__rz__body"}; - } - else - { - throw std::runtime_error("Invalid profile " + name); - } - return ret; - } + Set const &allowedOpcodes() const + { + return opcodes_; + } - Set const& allowedOpcodes() const - { - return opcodes_; - } + Set const &allowedExternalCallNames() const + { + return external_calls_; + } - Set const& allowedExternalCallNames() const - { - return external_calls_; - } + bool allowInternalCalls() const + { + return allow_internal_calls_; + } - bool allowInternalCalls() const - { - return allow_internal_calls_; - } + bool whitelistOpcodes() const + { + return whitelist_opcodes_; + } - bool whitelistOpcodes() const - { - return whitelist_opcodes_; - } + bool whitelistExternalCalls() const + { + return whitelist_external_calls_; + } - bool whitelistExternalCalls() const - { - return whitelist_external_calls_; - } + String const &saveReportTo() const + { + return save_report_to_; + } - private: - Set opcodes_{}; - Set external_calls_{}; +private: + Set opcodes_{}; + Set external_calls_{}; + String save_report_to_{""}; - bool whitelist_opcodes_{true}; - bool whitelist_external_calls_{true}; - bool allow_internal_calls_{false}; - }; + bool whitelist_opcodes_{true}; + bool whitelist_external_calls_{true}; + bool allow_internal_calls_{false}; +}; -} // namespace quantum -} // namespace microsoft +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Validator/Validator.cpp b/src/Passes/Source/Validator/Validator.cpp index 966a97976e..76a9e92d7c 100644 --- a/src/Passes/Source/Validator/Validator.cpp +++ b/src/Passes/Source/Validator/Validator.cpp @@ -1,79 +1,82 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -#include "ValidationPass/ValidationPass.hpp" #include "Validator/Validator.hpp" #include "Llvm/Llvm.hpp" +#include "Logging/CommentLogger.hpp" +#include "Logging/ILogger.hpp" +#include "ValidationPass/ValidationPass.hpp" -namespace microsoft -{ -namespace quantum +namespace microsoft { +namespace quantum { + +Validator::Validator(ValidationPassConfiguration const &cfg, bool debug, + llvm::TargetMachine *target_machine) + : loop_analysis_manager_{debug} + , function_analysis_manager_{debug} + , gscc_analysis_manager_{debug} + , module_analysis_manager_{debug} + , logger_{std::make_shared()} { - Validator::Validator(ValidationPassConfiguration const& cfg, bool debug, llvm::TargetMachine* target_machine) - : loop_analysis_manager_{debug} - , function_analysis_manager_{debug} - , gscc_analysis_manager_{debug} - , module_analysis_manager_{debug} - { + pass_builder_ = std::make_unique(target_machine); - pass_builder_ = std::make_unique(target_machine); + pass_builder_->registerModuleAnalyses(module_analysis_manager_); + pass_builder_->registerCGSCCAnalyses(gscc_analysis_manager_); + pass_builder_->registerFunctionAnalyses(function_analysis_manager_); + pass_builder_->registerLoopAnalyses(loop_analysis_manager_); - pass_builder_->registerModuleAnalyses(module_analysis_manager_); - pass_builder_->registerCGSCCAnalyses(gscc_analysis_manager_); - pass_builder_->registerFunctionAnalyses(function_analysis_manager_); - pass_builder_->registerLoopAnalyses(loop_analysis_manager_); + pass_builder_->crossRegisterProxies(loop_analysis_manager_, function_analysis_manager_, + gscc_analysis_manager_, module_analysis_manager_); - pass_builder_->crossRegisterProxies( - loop_analysis_manager_, function_analysis_manager_, gscc_analysis_manager_, module_analysis_manager_); + module_pass_manager_.addPass(ValidationPass(cfg, logger_)); +} - module_pass_manager_.addPass(ValidationPass(cfg)); - } +bool Validator::validate(llvm::Module &module) +{ + llvm::VerifierAnalysis verifier; + auto result = verifier.run(module, module_analysis_manager_); - bool Validator::validate(llvm::Module& module) - { - llvm::VerifierAnalysis verifier; - auto result = verifier.run(module, module_analysis_manager_); + if (result.IRBroken) + { + llvm::errs() << "; Fatal error: Invalid IR.\n"; + return false; + } - if (result.IRBroken) - { - llvm::errs() << "; Fatal error: Invalid IR.\n"; - return false; - } + try + { + module_pass_manager_.run(module, module_analysis_manager_); + } + catch (std::exception const &e) + { + llvm::errs() << "; Fatal error: " << e.what() << "\n"; + return false; + } - try - { - module_pass_manager_.run(module, module_analysis_manager_); - } - catch (std::exception const& e) - { - llvm::errs() << "; Fatal error: " << e.what() << "\n"; - return false; - } - return true; - } + return true; +} - llvm::PassBuilder& Validator::passBuilder() - { - return *pass_builder_; - } - llvm::LoopAnalysisManager& Validator::loopAnalysisManager() - { - return loop_analysis_manager_; - } - llvm::FunctionAnalysisManager& Validator::functionAnalysisManager() - { - return function_analysis_manager_; - } - llvm::CGSCCAnalysisManager& Validator::gsccAnalysisManager() - { - return gscc_analysis_manager_; - } - llvm::ModuleAnalysisManager& Validator::moduleAnalysisManager() - { - return module_analysis_manager_; - } +llvm::PassBuilder &Validator::passBuilder() +{ + return *pass_builder_; +} +llvm::LoopAnalysisManager &Validator::loopAnalysisManager() +{ + return loop_analysis_manager_; +} +llvm::FunctionAnalysisManager &Validator::functionAnalysisManager() +{ + return function_analysis_manager_; +} +llvm::CGSCCAnalysisManager &Validator::gsccAnalysisManager() +{ + return gscc_analysis_manager_; +} +llvm::ModuleAnalysisManager &Validator::moduleAnalysisManager() +{ + return module_analysis_manager_; +} -} // namespace quantum -} // namespace microsoft +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Validator/Validator.hpp b/src/Passes/Source/Validator/Validator.hpp index 6848691e1f..77723f3d59 100644 --- a/src/Passes/Source/Validator/Validator.hpp +++ b/src/Passes/Source/Validator/Validator.hpp @@ -4,81 +4,80 @@ #include "AllocationManager/AllocationManager.hpp" #include "AllocationManager/IAllocationManager.hpp" -#include "ValidationPass/ValidationPassConfiguration.hpp" - #include "Llvm/Llvm.hpp" +#include "Logging/ILogger.hpp" +#include "ValidationPass/ValidationPassConfiguration.hpp" #include -namespace microsoft -{ -namespace quantum +namespace microsoft { +namespace quantum { + +/// Validator class that defines a set of rules which constitutes the profile definition. Each of +/// the rules can be used to transform a generic QIR and/or validate that the QIR is compliant with +/// said rule. +class Validator { +public: + using ValidatorPtr = std::unique_ptr; + using ILoggerPtr = std::shared_ptr; - /// Validator class that defines a set of rules which constitutes the profile definition. Each of - /// the rules can be used to transform a generic QIR and/or validate that the QIR is compliant with - /// said rule. - class Validator - { - public: - using ValidatorPtr = std::unique_ptr; + // Constructors + // - // Constructors - // + explicit Validator(ValidationPassConfiguration const &cfg, bool debug, + llvm::TargetMachine *target_machine = nullptr); - explicit Validator( - ValidationPassConfiguration const& cfg, - bool debug, - llvm::TargetMachine* target_machine = nullptr); + // Default construction not allowed to ensure that LLVM modules and passes are set up correctly. + // Copy construction is prohibited due to restriction on classes held by Validator. - // Default construction not allowed to ensure that LLVM modules and passes are set up correctly. - // Copy construction is prohibited due to restriction on classes held by Validator. + Validator() = delete; + Validator(Validator const &) = delete; + Validator(Validator &&) = default; + Validator &operator=(Validator const &) = delete; + Validator &operator=(Validator &&) = default; + ~Validator() = default; - Validator() = delete; - Validator(Validator const&) = delete; - Validator(Validator&&) = default; - Validator& operator=(Validator const&) = delete; - Validator& operator=(Validator&&) = default; - ~Validator() = default; + // Validator methods + // - // Validator methods - // + /// Validates that a module complies with the specified QIR profile. Returns true if the module is + /// valid and false otherwise. + bool validate(llvm::Module &module); - /// Validates that a module complies with the specified QIR profile. Returns true if the module is - /// valid and false otherwise. - bool validate(llvm::Module& module); +protected: + using PassBuilderPtr = std::unique_ptr; - protected: - using PassBuilderPtr = std::unique_ptr; + /// Returns a reference to the pass builder. + llvm::PassBuilder &passBuilder(); - /// Returns a reference to the pass builder. - llvm::PassBuilder& passBuilder(); + /// Returns a reference to the loop analysis manager. + llvm::LoopAnalysisManager &loopAnalysisManager(); - /// Returns a reference to the loop analysis manager. - llvm::LoopAnalysisManager& loopAnalysisManager(); + /// Returns a reference to the function analysis manager. + llvm::FunctionAnalysisManager &functionAnalysisManager(); - /// Returns a reference to the function analysis manager. - llvm::FunctionAnalysisManager& functionAnalysisManager(); + /// Returns a reference to the GSCC analysis manager. + llvm::CGSCCAnalysisManager &gsccAnalysisManager(); - /// Returns a reference to the GSCC analysis manager. - llvm::CGSCCAnalysisManager& gsccAnalysisManager(); + /// Returns a reference to the module analysis manager. + llvm::ModuleAnalysisManager &moduleAnalysisManager(); - /// Returns a reference to the module analysis manager. - llvm::ModuleAnalysisManager& moduleAnalysisManager(); +private: + // LLVM logic to run the passes + // - private: - // LLVM logic to run the passes - // + llvm::LoopAnalysisManager loop_analysis_manager_; + llvm::FunctionAnalysisManager function_analysis_manager_; + llvm::CGSCCAnalysisManager gscc_analysis_manager_; + llvm::ModuleAnalysisManager module_analysis_manager_; - llvm::LoopAnalysisManager loop_analysis_manager_; - llvm::FunctionAnalysisManager function_analysis_manager_; - llvm::CGSCCAnalysisManager gscc_analysis_manager_; - llvm::ModuleAnalysisManager module_analysis_manager_; + PassBuilderPtr pass_builder_; - PassBuilderPtr pass_builder_; + llvm::ModulePassManager module_pass_manager_{}; - llvm::ModulePassManager module_pass_manager_{}; - }; + ILoggerPtr logger_{}; +}; -} // namespace quantum -} // namespace microsoft +} // namespace quantum +} // namespace microsoft From 96f8c9c6079b17035288b8f90b7d05a1648db244 Mon Sep 17 00:00:00 2001 From: "Troels F. Roennow" Date: Wed, 10 Nov 2021 09:04:04 +0100 Subject: [PATCH 12/17] Fixing style --- src/Passes/Source/Logging/CommentLogger.cpp | 81 +++---- src/Passes/Source/Logging/CommentLogger.hpp | 56 ++--- src/Passes/Source/Logging/ILogger.cpp | 10 +- src/Passes/Source/Logging/ILogger.hpp | 72 +++--- src/Passes/Source/Logging/LogCollection.cpp | 5 + src/Passes/Source/Logging/LogCollection.hpp | 133 +++++------ src/Passes/Source/Rules/Factory.cpp | 13 +- src/Passes/Source/Rules/Notation/Notation.cpp | 2 + .../TransformationRulesPass.cpp | 35 +++ .../Source/ValidationPass/ValidationPass.cpp | 177 +++++++------- .../Source/ValidationPass/ValidationPass.hpp | 71 +++--- .../ValidationPassConfiguration.hpp | 172 +++++++------- src/Passes/Source/Validator/Validator.cpp | 216 ++++++++++++------ src/Passes/Source/Validator/Validator.hpp | 115 +++++----- .../site-packages/tasks_ci/formatting.py | 4 +- 15 files changed, 664 insertions(+), 498 deletions(-) diff --git a/src/Passes/Source/Logging/CommentLogger.cpp b/src/Passes/Source/Logging/CommentLogger.cpp index adc4e225a1..524be18561 100644 --- a/src/Passes/Source/Logging/CommentLogger.cpp +++ b/src/Passes/Source/Logging/CommentLogger.cpp @@ -1,50 +1,53 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. + #include "Logging/CommentLogger.hpp" #include "Llvm/Llvm.hpp" #include -namespace microsoft { -namespace quantum { - -void CommentLogger::debug(String const &message) -{ - llvm::errs() << "debug - " << location_name_ << ":" << location_row_ << "," << location_col_ - << " - " << message << "\n"; -} - -void CommentLogger::info(String const &message) -{ - llvm::errs() << "info - " << location_name_ << ":" << location_row_ << "," << location_col_ - << " - " << message << "\n"; -} - -void CommentLogger::warning(String const &message) +namespace microsoft { - llvm::errs() << "warning - " << location_name_ << ":" << location_row_ << "," << location_col_ - << " - " << message << "\n"; -} - -void CommentLogger::error(String const &message) -{ - llvm::errs() << "error - " << location_name_ << ":" << location_row_ << "," << location_col_ - << " - " << message << "\n"; -} - -void CommentLogger::internalError(String const &message) -{ - llvm::errs() << "internal error - " << location_name_ << ":" << location_row_ << "," - << location_col_ << " - " << message << "\n"; -} - -void CommentLogger::setLocation(String const &name, uint64_t row, uint64_t col) +namespace quantum { - location_name_ = name; - location_row_ = row; - location_col_ = col; -} -} // namespace quantum -} // namespace microsoft + void CommentLogger::debug(String const& message) + { + llvm::errs() << "debug - " << location_name_ << ":" << location_row_ << "," << location_col_ << " - " << message + << "\n"; + } + + void CommentLogger::info(String const& message) + { + llvm::errs() << "info - " << location_name_ << ":" << location_row_ << "," << location_col_ << " - " << message + << "\n"; + } + + void CommentLogger::warning(String const& message) + { + llvm::errs() << "warning - " << location_name_ << ":" << location_row_ << "," << location_col_ << " - " + << message << "\n"; + } + + void CommentLogger::error(String const& message) + { + llvm::errs() << "error - " << location_name_ << ":" << location_row_ << "," << location_col_ << " - " << message + << "\n"; + } + + void CommentLogger::internalError(String const& message) + { + llvm::errs() << "internal error - " << location_name_ << ":" << location_row_ << "," << location_col_ << " - " + << message << "\n"; + } + + void CommentLogger::setLocation(String const& name, uint64_t row, uint64_t col) + { + location_name_ = name; + location_row_ = row; + location_col_ = col; + } + +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Logging/CommentLogger.hpp b/src/Passes/Source/Logging/CommentLogger.hpp index 53db96a003..78705551b7 100644 --- a/src/Passes/Source/Logging/CommentLogger.hpp +++ b/src/Passes/Source/Logging/CommentLogger.hpp @@ -6,39 +6,41 @@ #include -namespace microsoft { -namespace quantum { - -/// Concrete ILogger implementation that prints all messages as IR comments to llvm::errs(). -class CommentLogger : public ILogger +namespace microsoft +{ +namespace quantum { -public: - // Interface implementation - // - /// Adds a debug message to the list. - void debug(String const &message) override; + /// Concrete ILogger implementation that prints all messages as IR comments to llvm::errs(). + class CommentLogger : public ILogger + { + public: + // Interface implementation + // + + /// Adds a debug message to the list. + void debug(String const& message) override; - /// Adds an info message to the list. - void info(String const &message) override; + /// Adds an info message to the list. + void info(String const& message) override; - /// Adds a warning message to the list. - void warning(String const &message) override; + /// Adds a warning message to the list. + void warning(String const& message) override; - /// Adds an error message to the list. - void error(String const &message) override; + /// Adds an error message to the list. + void error(String const& message) override; - /// Adds an internal error message to the list. - void internalError(String const &message) override; + /// Adds an internal error message to the list. + void internalError(String const& message) override; - /// Function that allows to set the current location. - void setLocation(String const &name, uint64_t row, uint64_t col) override; + /// Function that allows to set the current location. + void setLocation(String const& name, uint64_t row, uint64_t col) override; -private: - String location_name_{""}; - uint64_t location_row_{0}; - uint64_t location_col_{0}; -}; + private: + String location_name_{""}; + uint64_t location_row_{0}; + uint64_t location_col_{0}; + }; -} // namespace quantum -} // namespace microsoft +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Logging/ILogger.cpp b/src/Passes/Source/Logging/ILogger.cpp index f528f9c3f7..be896e7f01 100644 --- a/src/Passes/Source/Logging/ILogger.cpp +++ b/src/Passes/Source/Logging/ILogger.cpp @@ -6,8 +6,10 @@ #include #include -namespace microsoft { -namespace quantum { -ILogger::~ILogger() = default; +namespace microsoft +{ +namespace quantum +{ + ILogger::~ILogger() = default; } -} // namespace microsoft +} // namespace microsoft diff --git a/src/Passes/Source/Logging/ILogger.hpp b/src/Passes/Source/Logging/ILogger.hpp index 2c66a1e446..76a0dce977 100644 --- a/src/Passes/Source/Logging/ILogger.hpp +++ b/src/Passes/Source/Logging/ILogger.hpp @@ -7,49 +7,51 @@ #include #include -namespace microsoft { -namespace quantum { - -/// Logger interface to allow the collection of different types of messages during QIR -/// transformation and/or validation. -class ILogger +namespace microsoft +{ +namespace quantum { -public: - // Constructors, copy and move operators and destructors - // - ILogger() = default; - ILogger(ILogger const &) = default; - ILogger(ILogger &&) = default; - ILogger &operator=(ILogger const &) = default; - ILogger &operator=(ILogger &&) = default; + /// Logger interface to allow the collection of different types of messages during QIR + /// transformation and/or validation. + class ILogger + { + public: + // Constructors, copy and move operators and destructors + // + + ILogger() = default; + ILogger(ILogger const&) = default; + ILogger(ILogger&&) = default; + ILogger& operator=(ILogger const&) = default; + ILogger& operator=(ILogger&&) = default; - virtual ~ILogger(); + virtual ~ILogger(); - // Abstract interface methods - // + // Abstract interface methods + // - /// Reports a debug message. - virtual void debug(String const &message) = 0; + /// Reports a debug message. + virtual void debug(String const& message) = 0; - /// Reports an info message. - virtual void info(String const &message) = 0; + /// Reports an info message. + virtual void info(String const& message) = 0; - /// Reports a warning message. - virtual void warning(String const &message) = 0; + /// Reports a warning message. + virtual void warning(String const& message) = 0; - /// Reports an error message. - virtual void error(String const &message) = 0; + /// Reports an error message. + virtual void error(String const& message) = 0; - /// Reports an internal error message. - virtual void internalError(String const &message) = 0; + /// Reports an internal error message. + virtual void internalError(String const& message) = 0; - /// Sets the current location. Importantly, the location can be set independently of the reported - /// messages. This allows one to update the location upon updating the cursor position without - /// having to worry about keeping a copy of the location to pass when reporting messages. - /// The most obvious case of this is file path (name) with a line and character (row, col). - virtual void setLocation(String const &name, uint64_t row, uint64_t col) = 0; -}; + /// Sets the current location. Importantly, the location can be set independently of the reported + /// messages. This allows one to update the location upon updating the cursor position without + /// having to worry about keeping a copy of the location to pass when reporting messages. + /// The most obvious case of this is file path (name) with a line and character (row, col). + virtual void setLocation(String const& name, uint64_t row, uint64_t col) = 0; + }; -} // namespace quantum -} // namespace microsoft +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Logging/LogCollection.cpp b/src/Passes/Source/Logging/LogCollection.cpp index d935926dcf..9e59b90316 100644 --- a/src/Passes/Source/Logging/LogCollection.cpp +++ b/src/Passes/Source/Logging/LogCollection.cpp @@ -42,5 +42,10 @@ namespace quantum current_location_.col = col; } + LogCollection::Messages const& LogCollection::messages() const + { + return messages_; + } + } // namespace quantum } // namespace microsoft diff --git a/src/Passes/Source/Logging/LogCollection.hpp b/src/Passes/Source/Logging/LogCollection.hpp index 7e3c3b98b6..957de3a316 100644 --- a/src/Passes/Source/Logging/LogCollection.hpp +++ b/src/Passes/Source/Logging/LogCollection.hpp @@ -6,68 +6,73 @@ #include -namespace microsoft { -namespace quantum { - -/// Concrete ILogger implementation that collects all messages and their corresponding location in a -/// list that can be traversed later on. -class LogCollection : public ILogger +namespace microsoft +{ +namespace quantum { -public: - /// Class that holds the location of where the incident happened. - struct Location - { - String name{}; - uint64_t row{0}; - uint64_t col{0}; - }; - - /// Enum description what type of information we are conveying. - enum class Type - { - Debug, - Info, - Warning, - Error, - InternalError, - }; - - /// Struct to hold a message together with its type and location - struct Message - { - Type type; - Location location; - String message; - }; - - /// List of messages defined as alias. - using Messages = std::vector; - - // Interface implementation - // - - /// Adds a debug message to the list. - void debug(String const &message) override; - - /// Adds an info message to the list. - void info(String const &message) override; - - /// Adds a warning message to the list. - void warning(String const &message) override; - - /// Adds an error message to the list. - void error(String const &message) override; - - /// Adds an internal error message to the list. - void internalError(String const &message) override; - - /// Function that allows to set the current location. - void setLocation(String const &name, uint64_t row, uint64_t col) override; - -private: - Location current_location_{}; ///< Holds current location. - Messages messages_; ///< All messages emitted. -}; - -} // namespace quantum -} // namespace microsoft + + /// Concrete ILogger implementation that collects all messages and their corresponding location in a + /// list that can be traversed later on. + class LogCollection : public ILogger + { + public: + /// Class that holds the location of where the incident happened. + struct Location + { + String name{}; + uint64_t row{0}; + uint64_t col{0}; + }; + + /// Enum description what type of information we are conveying. + enum class Type + { + Debug, + Info, + Warning, + Error, + InternalError, + }; + + /// Struct to hold a message together with its type and location + struct Message + { + Type type; + Location location; + String message; + }; + + /// List of messages defined as alias. + using Messages = std::vector; + + // Interface implementation + // + + /// Adds a debug message to the list. + void debug(String const& message) override; + + /// Adds an info message to the list. + void info(String const& message) override; + + /// Adds a warning message to the list. + void warning(String const& message) override; + + /// Adds an error message to the list. + void error(String const& message) override; + + /// Adds an internal error message to the list. + void internalError(String const& message) override; + + /// Function that allows to set the current location. + void setLocation(String const& name, uint64_t row, uint64_t col) override; + + /// Accessor to the messages + Messages const& messages() const; + + private: + Location current_location_{}; ///< Holds current location. + Messages messages_; ///< All messages emitted. + }; + +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Rules/Factory.cpp b/src/Passes/Source/Rules/Factory.cpp index f8c7b19f31..7c4ae63469 100644 --- a/src/Passes/Source/Rules/Factory.cpp +++ b/src/Passes/Source/Rules/Factory.cpp @@ -632,11 +632,16 @@ namespace quantum void RuleFactory::disableStringSupport() { - removeFunctionCall("__quantum__rt__string_create"); - removeFunctionCall("__quantum__rt__string_update_reference_count"); - removeFunctionCall("__quantum__rt__string_update_alias_count"); - removeFunctionCall("__quantum__rt__message"); removeFunctionCall("__quantum__rt__fail"); + removeFunctionCall("__quantum__rt__message"); + removeFunctionCall("__quantum__rt__bool_to_string"); + removeFunctionCall("__quantum__rt__double_to_string"); + removeFunctionCall("__quantum__rt__pauli_to_string"); + removeFunctionCall("__quantum__rt__int_to_string"); + removeFunctionCall("__quantum__rt__string_concatenate"); + removeFunctionCall("__quantum__rt__string_update_alias_count"); + removeFunctionCall("__quantum__rt__string_update_reference_count"); + removeFunctionCall("__quantum__rt__string_create"); } ReplacementRulePtr RuleFactory::addRule(ReplacementRule&& rule) diff --git a/src/Passes/Source/Rules/Notation/Notation.cpp b/src/Passes/Source/Rules/Notation/Notation.cpp index c6e8cfb158..5ac8d7642d 100644 --- a/src/Passes/Source/Rules/Notation/Notation.cpp +++ b/src/Passes/Source/Rules/Notation/Notation.cpp @@ -22,6 +22,8 @@ namespace quantum { return [](ReplacementRule::Builder&, ReplacementRule::Value* val, ReplacementRule::Captures&, ReplacementRule::Replacements& replacements) { + auto type = val->getType(); + val->replaceAllUsesWith(llvm::UndefValue::get(type)); replacements.push_back({llvm::dyn_cast(val), nullptr}); return true; }; diff --git a/src/Passes/Source/TransformationRulesPass/TransformationRulesPass.cpp b/src/Passes/Source/TransformationRulesPass/TransformationRulesPass.cpp index 4ba2689e4e..74ebc9d7bf 100644 --- a/src/Passes/Source/TransformationRulesPass/TransformationRulesPass.cpp +++ b/src/Passes/Source/TransformationRulesPass/TransformationRulesPass.cpp @@ -773,6 +773,7 @@ namespace quantum } else { + // Otherwise we apply to all sections of the code. replacements_.clear(); for (auto& function : module) @@ -789,6 +790,40 @@ namespace quantum processReplacements(); } + /* + replacements_.clear(); + for (auto &function : module) + { + + std::vector blocks; + for (auto &block : function) + { + blocks.push_back(&block); + } + + for (auto it_block = blocks.rbegin(); it_block != blocks.rend(); ++it_block) + { + auto &block = **it_block; + + // Deleteing blocks in reverse order + std::vector instructions; + for (auto &instr : block) + { + instructions.push_back(&instr); + } + + // Removing backwards to avoid segfault + for (auto it_inst = instructions.rbegin(); it_inst != instructions.rend(); ++it_inst) + { + auto &instr = **it_inst; + rule_set_.matchAndReplace(&instr, replacements_); + } + } + } + + processReplacements(); + */ + return llvm::PreservedAnalyses::none(); } diff --git a/src/Passes/Source/ValidationPass/ValidationPass.cpp b/src/Passes/Source/ValidationPass/ValidationPass.cpp index 70619afa95..491d5bedb6 100644 --- a/src/Passes/Source/ValidationPass/ValidationPass.cpp +++ b/src/Passes/Source/ValidationPass/ValidationPass.cpp @@ -8,108 +8,109 @@ #include #include -namespace microsoft { -namespace quantum { -llvm::PreservedAnalyses ValidationPass::run(llvm::Module &module, - llvm::ModuleAnalysisManager & /*mam*/) +namespace microsoft { - - for (auto &function : module) - { - for (auto &block : function) +namespace quantum +{ + llvm::PreservedAnalyses ValidationPass::run(llvm::Module& module, llvm::ModuleAnalysisManager& /*mam*/) { - for (auto &instr : block) - { - auto opname = instr.getOpcodeName(); - if (opcodes_.find(opname) != opcodes_.end()) - { - ++opcodes_[opname]; - } - else - { - opcodes_[opname] = 1; - } - auto call_instr = llvm::dyn_cast(&instr); - if (call_instr != nullptr) + for (auto& function : module) { - auto f = call_instr->getCalledFunction(); - if (f == nullptr) - { - continue; - } - - auto name = static_cast(f->getName()); - if (f->isDeclaration()) - { - if (external_calls_.find(name) != external_calls_.end()) + for (auto& block : function) { - ++external_calls_[name]; - } - else - { - external_calls_[name] = 1; + for (auto& instr : block) + { + auto opname = instr.getOpcodeName(); + if (opcodes_.find(opname) != opcodes_.end()) + { + ++opcodes_[opname]; + } + else + { + opcodes_[opname] = 1; + } + + auto call_instr = llvm::dyn_cast(&instr); + if (call_instr != nullptr) + { + auto f = call_instr->getCalledFunction(); + if (f == nullptr) + { + continue; + } + + auto name = static_cast(f->getName()); + if (f->isDeclaration()) + { + if (external_calls_.find(name) != external_calls_.end()) + { + ++external_calls_[name]; + } + else + { + external_calls_[name] = 1; + } + } + else + { + if (internal_calls_.find(name) != internal_calls_.end()) + { + ++internal_calls_[name]; + } + else + { + internal_calls_[name] = 1; + } + } + } + } } - } - else - { - if (internal_calls_.find(name) != internal_calls_.end()) + } + + bool raise_exception = false; + if (config_.whitelistOpcodes()) + { + auto const& allowed_ops = config_.allowedOpcodes(); + for (auto const& k : opcodes_) { - ++internal_calls_[name]; + if (allowed_ops.find(k.first) == allowed_ops.end()) + { + logger_->error("'" + k.first + "' is not allowed for this profile."); + } } - else + } + + if (config_.whitelistOpcodes()) + { + auto const& allowed_functions = config_.allowedExternalCallNames(); + for (auto const& k : external_calls_) { - internal_calls_[name] = 1; + if (allowed_functions.find(k.first) == allowed_functions.end()) + { + logger_->error("'" + k.first + "' is not allowed for this profile."); + } } - } } - } - } - } - bool raise_exception = false; - if (config_.whitelistOpcodes()) - { - auto const &allowed_ops = config_.allowedOpcodes(); - for (auto const &k : opcodes_) - { - if (allowed_ops.find(k.first) == allowed_ops.end()) - { - logger_->error("'" + k.first + "' is not allowed for this profile."); - } + if (!config_.allowInternalCalls() && !internal_calls_.empty()) + { + logger_->error("Calls to custom defined functions not allowed."); + raise_exception = true; + } + + if (raise_exception) + { + throw std::runtime_error("QIR is not valid within the defined profile"); + } + + return llvm::PreservedAnalyses::all(); } - } - if (config_.whitelistOpcodes()) - { - auto const &allowed_functions = config_.allowedExternalCallNames(); - for (auto const &k : external_calls_) + bool ValidationPass::isRequired() { - if (allowed_functions.find(k.first) == allowed_functions.end()) - { - logger_->error("'" + k.first + "' is not allowed for this profile."); - } + return true; } - } - - if (!config_.allowInternalCalls() && !internal_calls_.empty()) - { - logger_->error("Calls to custom defined functions not allowed."); - raise_exception = true; - } - - if (raise_exception) - { - throw std::runtime_error("QIR is not valid within the defined profile"); - } - - return llvm::PreservedAnalyses::all(); -} - -bool ValidationPass::isRequired() -{ - return true; -} -} // namespace quantum -} // namespace microsoft +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/ValidationPass/ValidationPass.hpp b/src/Passes/Source/ValidationPass/ValidationPass.hpp index 3340be2f4a..80b807f2d9 100644 --- a/src/Passes/Source/ValidationPass/ValidationPass.hpp +++ b/src/Passes/Source/ValidationPass/ValidationPass.hpp @@ -2,57 +2,60 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -#include "Llvm/Llvm.hpp" #include "Logging/ILogger.hpp" #include "Profile/Profile.hpp" #include "QatTypes/QatTypes.hpp" #include "ValidationPass/ValidationPassConfiguration.hpp" +#include "Llvm/Llvm.hpp" + #include #include #include -namespace microsoft { -namespace quantum { - -class ValidationPass : public llvm::PassInfoMixin +namespace microsoft +{ +namespace quantum { -public: - using Instruction = llvm::Instruction; - using Value = llvm::Value; - using ILoggerPtr = std::shared_ptr; - // Construction and destruction configuration. - // + class ValidationPass : public llvm::PassInfoMixin + { + public: + using Instruction = llvm::Instruction; + using Value = llvm::Value; + using ILoggerPtr = std::shared_ptr; + + // Construction and destruction configuration. + // - explicit ValidationPass(ValidationPassConfiguration const &cfg, - ILoggerPtr const & logger = nullptr) - : config_{cfg} - , logger_{logger} - {} + explicit ValidationPass(ValidationPassConfiguration const& cfg, ILoggerPtr const& logger = nullptr) + : config_{cfg} + , logger_{logger} + { + } - /// Copy construction is banned. - ValidationPass(ValidationPass const &) = delete; + /// Copy construction is banned. + ValidationPass(ValidationPass const&) = delete; - /// We allow move semantics. - ValidationPass(ValidationPass &&) = default; + /// We allow move semantics. + ValidationPass(ValidationPass&&) = default; - /// Default destruction. - ~ValidationPass() = default; + /// Default destruction. + ~ValidationPass() = default; - llvm::PreservedAnalyses run(llvm::Module &module, llvm::ModuleAnalysisManager &mam); - /// Whether or not this pass is required to run. - static bool isRequired(); + llvm::PreservedAnalyses run(llvm::Module& module, llvm::ModuleAnalysisManager& mam); + /// Whether or not this pass is required to run. + static bool isRequired(); -private: - ValidationPassConfiguration config_{}; + private: + ValidationPassConfiguration config_{}; - std::unordered_map opcodes_; - std::unordered_map external_calls_; - std::unordered_map internal_calls_; + std::unordered_map opcodes_; + std::unordered_map external_calls_; + std::unordered_map internal_calls_; - ILoggerPtr logger_{nullptr}; -}; + ILoggerPtr logger_{nullptr}; + }; -} // namespace quantum -} // namespace microsoft +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/ValidationPass/ValidationPassConfiguration.hpp b/src/Passes/Source/ValidationPass/ValidationPassConfiguration.hpp index b9dcfe847e..44c86ecf20 100644 --- a/src/Passes/Source/ValidationPass/ValidationPassConfiguration.hpp +++ b/src/Passes/Source/ValidationPass/ValidationPassConfiguration.hpp @@ -5,97 +5,105 @@ #include "Commandline/ConfigurationManager.hpp" #include "QatTypes/QatTypes.hpp" -namespace microsoft { -namespace quantum { - -class ValidationPassConfiguration +namespace microsoft +{ +namespace quantum { -public: - using Set = std::unordered_set; - // Setup and construction - // - - /// Setup function that adds the configuration flags to the ConfigurationManager. See the - /// ConfigurationManager documentation for more details on how the setup process is implemented. - void setup(ConfigurationManager &config) - { - config.setSectionName("Validation configuration", ""); - config.addParameter(allow_internal_calls_, "allow-internal-calls", - "Whether or not internal calls are allowed."); - config.addParameter(allow_internal_calls_, "save-validation-report", - "Saves the validation report to specified filename."); - } - static ValidationPassConfiguration fromProfileName(String const &name) - { - auto ret = ValidationPassConfiguration(); - if (name == "generic") - { - ret.allow_internal_calls_ = true; - ret.whitelist_external_calls_ = false; - ret.whitelist_opcodes_ = false; - } - else if (name == "base") + class ValidationPassConfiguration { - ret.allow_internal_calls_ = false; - ret.whitelist_external_calls_ = true; - ret.whitelist_opcodes_ = true; - ret.opcodes_ = Set{"br", "call", "unreachable", "ret", "phi", "select"}; - ret.external_calls_ = Set{"__quantum__qis__mz__body", "__quantum__qis__read_result__body", - "__quantum__qis__reset__body", "__quantum__qis__z__body", - "__quantum__qis__s__adj", "__quantum__qis__dumpregister__body", - "__quantum__qis__y__body", "__quantum__qis__x__body", - "__quantum__qis__t__body", "__quantum__qis__cz__body", - "__quantum__qis__s__body", "__quantum__qis__h__body", - "__quantum__qis__cnot__body", "__quantum__qis__sqrt__body", - "__quantum__qis__crz__body", "__quantum__qis__rz__body"}; - } - else - { - throw std::runtime_error("Invalid profile " + name); - } - return ret; - } + public: + using Set = std::unordered_set; + // Setup and construction + // + + /// Setup function that adds the configuration flags to the ConfigurationManager. See the + /// ConfigurationManager documentation for more details on how the setup process is implemented. + void setup(ConfigurationManager& config) + { + config.setSectionName("Validation configuration", ""); + config.addParameter( + allow_internal_calls_, "allow-internal-calls", "Whether or not internal calls are allowed."); + config.addParameter( + save_report_to_, "save-validation-report", "Saves the validation report to specified filename."); + } + + static ValidationPassConfiguration fromProfileName(String const& name) + { + auto ret = ValidationPassConfiguration(); + if (name == "generic") + { + ret.allow_internal_calls_ = true; + ret.whitelist_external_calls_ = false; + ret.whitelist_opcodes_ = false; + } + else if (name == "base") + { + ret.allow_internal_calls_ = false; + ret.whitelist_external_calls_ = true; + ret.whitelist_opcodes_ = true; + ret.opcodes_ = Set{"br", "call", "unreachable", "ret", "phi", "select"}; + ret.external_calls_ = Set{ + "__quantum__qis__mz__body", "__quantum__qis__read_result__body", + "__quantum__qis__reset__body", "__quantum__qis__z__body", + "__quantum__qis__s__adj", "__quantum__qis__dumpregister__body", + "__quantum__qis__y__body", "__quantum__qis__x__body", + "__quantum__qis__t__body", "__quantum__qis__cz__body", + "__quantum__qis__s__body", "__quantum__qis__h__body", + "__quantum__qis__cnot__body", "__quantum__qis__sqrt__body", + "__quantum__qis__crz__body", "__quantum__qis__rz__body", + "__quantum__qis__arcsin__body", "__quantum__qis__drawrandomint__body", + "__quantum__qis__rx__body", "__quantum__qis__m__body", + "__quantum__qis__t__adj", + + }; + } + else + { + throw std::runtime_error("Invalid profile " + name); + } + return ret; + } - Set const &allowedOpcodes() const - { - return opcodes_; - } + Set const& allowedOpcodes() const + { + return opcodes_; + } - Set const &allowedExternalCallNames() const - { - return external_calls_; - } + Set const& allowedExternalCallNames() const + { + return external_calls_; + } - bool allowInternalCalls() const - { - return allow_internal_calls_; - } + bool allowInternalCalls() const + { + return allow_internal_calls_; + } - bool whitelistOpcodes() const - { - return whitelist_opcodes_; - } + bool whitelistOpcodes() const + { + return whitelist_opcodes_; + } - bool whitelistExternalCalls() const - { - return whitelist_external_calls_; - } + bool whitelistExternalCalls() const + { + return whitelist_external_calls_; + } - String const &saveReportTo() const - { - return save_report_to_; - } + String const& saveReportTo() const + { + return save_report_to_; + } -private: - Set opcodes_{}; - Set external_calls_{}; - String save_report_to_{""}; + private: + Set opcodes_{}; + Set external_calls_{}; + String save_report_to_{""}; - bool whitelist_opcodes_{true}; - bool whitelist_external_calls_{true}; - bool allow_internal_calls_{false}; -}; + bool whitelist_opcodes_{true}; + bool whitelist_external_calls_{true}; + bool allow_internal_calls_{false}; + }; -} // namespace quantum -} // namespace microsoft +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Validator/Validator.cpp b/src/Passes/Source/Validator/Validator.cpp index 76a9e92d7c..cb73344df1 100644 --- a/src/Passes/Source/Validator/Validator.cpp +++ b/src/Passes/Source/Validator/Validator.cpp @@ -1,82 +1,164 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -#include "Validator/Validator.hpp" - -#include "Llvm/Llvm.hpp" #include "Logging/CommentLogger.hpp" #include "Logging/ILogger.hpp" +#include "Logging/LogCollection.hpp" #include "ValidationPass/ValidationPass.hpp" +#include "Validator/Validator.hpp" -namespace microsoft { -namespace quantum { +#include "Llvm/Llvm.hpp" + +#include -Validator::Validator(ValidationPassConfiguration const &cfg, bool debug, - llvm::TargetMachine *target_machine) - : loop_analysis_manager_{debug} - , function_analysis_manager_{debug} - , gscc_analysis_manager_{debug} - , module_analysis_manager_{debug} - , logger_{std::make_shared()} +namespace microsoft +{ +namespace quantum { - pass_builder_ = std::make_unique(target_machine); + Validator::Validator(ValidationPassConfiguration const& cfg, bool debug, llvm::TargetMachine* target_machine) + : loop_analysis_manager_{debug} + , function_analysis_manager_{debug} + , gscc_analysis_manager_{debug} + , module_analysis_manager_{debug} + , logger_{nullptr} + { - pass_builder_->registerModuleAnalyses(module_analysis_manager_); - pass_builder_->registerCGSCCAnalyses(gscc_analysis_manager_); - pass_builder_->registerFunctionAnalyses(function_analysis_manager_); - pass_builder_->registerLoopAnalyses(loop_analysis_manager_); + pass_builder_ = std::make_unique(target_machine); - pass_builder_->crossRegisterProxies(loop_analysis_manager_, function_analysis_manager_, - gscc_analysis_manager_, module_analysis_manager_); + pass_builder_->registerModuleAnalyses(module_analysis_manager_); + pass_builder_->registerCGSCCAnalyses(gscc_analysis_manager_); + pass_builder_->registerFunctionAnalyses(function_analysis_manager_); + pass_builder_->registerLoopAnalyses(loop_analysis_manager_); - module_pass_manager_.addPass(ValidationPass(cfg, logger_)); -} + pass_builder_->crossRegisterProxies( + loop_analysis_manager_, function_analysis_manager_, gscc_analysis_manager_, module_analysis_manager_); -bool Validator::validate(llvm::Module &module) -{ - llvm::VerifierAnalysis verifier; - auto result = verifier.run(module, module_analysis_manager_); - - if (result.IRBroken) - { - llvm::errs() << "; Fatal error: Invalid IR.\n"; - return false; - } - - try - { - module_pass_manager_.run(module, module_analysis_manager_); - } - catch (std::exception const &e) - { - llvm::errs() << "; Fatal error: " << e.what() << "\n"; - return false; - } - - return true; -} - -llvm::PassBuilder &Validator::passBuilder() -{ - return *pass_builder_; -} -llvm::LoopAnalysisManager &Validator::loopAnalysisManager() -{ - return loop_analysis_manager_; -} -llvm::FunctionAnalysisManager &Validator::functionAnalysisManager() -{ - return function_analysis_manager_; -} -llvm::CGSCCAnalysisManager &Validator::gsccAnalysisManager() -{ - return gscc_analysis_manager_; -} -llvm::ModuleAnalysisManager &Validator::moduleAnalysisManager() -{ - return module_analysis_manager_; -} + // Checking if we need to save the log to a file + if (!cfg.saveReportTo().empty()) + { + logger_ = std::make_shared(); + save_to_filename_ = cfg.saveReportTo(); + + module_pass_manager_.addPass(ValidationPass(cfg, logger_)); + } + else + { + // Our default is a pass that logs errors via comments + module_pass_manager_.addPass(ValidationPass(cfg, std::make_shared())); + } + } + + bool Validator::validate(llvm::Module& module) + { + llvm::VerifierAnalysis verifier; + auto result = verifier.run(module, module_analysis_manager_); + + if (result.IRBroken) + { + if (logger_) + { + logger_->error("Fatal error: Invalid IR."); + } + + saveLogsToFileIfNeeded(); + return false; + } + + try + { + module_pass_manager_.run(module, module_analysis_manager_); + } + catch (std::exception const& e) + { + if (logger_) + { + logger_->error("Fatal error: " + static_cast(e.what())); + } + + saveLogsToFileIfNeeded(); + return false; + } + + saveLogsToFileIfNeeded(); + return true; + } + + llvm::PassBuilder& Validator::passBuilder() + { + return *pass_builder_; + } + + llvm::LoopAnalysisManager& Validator::loopAnalysisManager() + { + return loop_analysis_manager_; + } + + llvm::FunctionAnalysisManager& Validator::functionAnalysisManager() + { + return function_analysis_manager_; + } + + llvm::CGSCCAnalysisManager& Validator::gsccAnalysisManager() + { + return gscc_analysis_manager_; + } + + llvm::ModuleAnalysisManager& Validator::moduleAnalysisManager() + { + return module_analysis_manager_; + } + + void Validator::saveLogsToFileIfNeeded() + { + if (!save_to_filename_.empty() && logger_) + { + std::fstream fout(save_to_filename_, std::ios::out); + bool not_first = false; + + fout << "["; + for (auto& message : logger_->messages()) + { + if (not_first) + { + fout << ","; + } + fout << "\n"; + fout << " {\n"; + + switch (message.type) + { + case LogCollection::Type::Debug: + fout << " \"type\": \"debug\",\n"; + break; + case LogCollection::Type::Info: + fout << " \"type\": \"info\",\n"; + break; + case LogCollection::Type::Warning: + fout << " \"type\": \"warning\",\n"; + break; + case LogCollection::Type::Error: + fout << " \"type\": \"error\",\n"; + break; + case LogCollection::Type::InternalError: + fout << " \"type\": \"internalError\",\n"; + break; + } + + fout << " \"message\": \"" << message.message << "\",\n"; + fout << " \"location\": {\n"; + fout << " \"name\": \"" << message.location.name << "\",\n"; + fout << " \"row\": " << message.location.row << ",\n"; + fout << " \"col\": " << message.location.col << "\n"; + fout << " }\n"; + fout << " }"; + not_first = true; + } + fout << "\n]\n"; + + fout.close(); + } + } -} // namespace quantum -} // namespace microsoft +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Validator/Validator.hpp b/src/Passes/Source/Validator/Validator.hpp index 77723f3d59..b4649db41a 100644 --- a/src/Passes/Source/Validator/Validator.hpp +++ b/src/Passes/Source/Validator/Validator.hpp @@ -4,80 +4,89 @@ #include "AllocationManager/AllocationManager.hpp" #include "AllocationManager/IAllocationManager.hpp" -#include "Llvm/Llvm.hpp" #include "Logging/ILogger.hpp" +#include "Logging/LogCollection.hpp" #include "ValidationPass/ValidationPassConfiguration.hpp" -#include +#include "Llvm/Llvm.hpp" -namespace microsoft { -namespace quantum { +#include -/// Validator class that defines a set of rules which constitutes the profile definition. Each of -/// the rules can be used to transform a generic QIR and/or validate that the QIR is compliant with -/// said rule. -class Validator +namespace microsoft { -public: - using ValidatorPtr = std::unique_ptr; - using ILoggerPtr = std::shared_ptr; +namespace quantum +{ + + /// Validator class that defines a set of rules which constitutes the profile definition. Each of + /// the rules can be used to transform a generic QIR and/or validate that the QIR is compliant with + /// said rule. + class Validator + { + public: + using ValidatorPtr = std::unique_ptr; + using LogColloectionPtr = std::shared_ptr; + + // Constructors + // - // Constructors - // + explicit Validator( + ValidationPassConfiguration const& cfg, + bool debug, + llvm::TargetMachine* target_machine = nullptr); - explicit Validator(ValidationPassConfiguration const &cfg, bool debug, - llvm::TargetMachine *target_machine = nullptr); + // Default construction not allowed to ensure that LLVM modules and passes are set up correctly. + // Copy construction is prohibited due to restriction on classes held by Validator. - // Default construction not allowed to ensure that LLVM modules and passes are set up correctly. - // Copy construction is prohibited due to restriction on classes held by Validator. + Validator() = delete; + Validator(Validator const&) = delete; + Validator(Validator&&) = default; + Validator& operator=(Validator const&) = delete; + Validator& operator=(Validator&&) = default; + ~Validator() = default; - Validator() = delete; - Validator(Validator const &) = delete; - Validator(Validator &&) = default; - Validator &operator=(Validator const &) = delete; - Validator &operator=(Validator &&) = default; - ~Validator() = default; + // Validator methods + // - // Validator methods - // + /// Validates that a module complies with the specified QIR profile. Returns true if the module is + /// valid and false otherwise. + bool validate(llvm::Module& module); - /// Validates that a module complies with the specified QIR profile. Returns true if the module is - /// valid and false otherwise. - bool validate(llvm::Module &module); + protected: + using PassBuilderPtr = std::unique_ptr; -protected: - using PassBuilderPtr = std::unique_ptr; + /// Returns a reference to the pass builder. + llvm::PassBuilder& passBuilder(); - /// Returns a reference to the pass builder. - llvm::PassBuilder &passBuilder(); + /// Returns a reference to the loop analysis manager. + llvm::LoopAnalysisManager& loopAnalysisManager(); - /// Returns a reference to the loop analysis manager. - llvm::LoopAnalysisManager &loopAnalysisManager(); + /// Returns a reference to the function analysis manager. + llvm::FunctionAnalysisManager& functionAnalysisManager(); - /// Returns a reference to the function analysis manager. - llvm::FunctionAnalysisManager &functionAnalysisManager(); + /// Returns a reference to the GSCC analysis manager. + llvm::CGSCCAnalysisManager& gsccAnalysisManager(); - /// Returns a reference to the GSCC analysis manager. - llvm::CGSCCAnalysisManager &gsccAnalysisManager(); + /// Returns a reference to the module analysis manager. + llvm::ModuleAnalysisManager& moduleAnalysisManager(); - /// Returns a reference to the module analysis manager. - llvm::ModuleAnalysisManager &moduleAnalysisManager(); + private: + void saveLogsToFileIfNeeded(); -private: - // LLVM logic to run the passes - // + // LLVM logic to run the passes + // - llvm::LoopAnalysisManager loop_analysis_manager_; - llvm::FunctionAnalysisManager function_analysis_manager_; - llvm::CGSCCAnalysisManager gscc_analysis_manager_; - llvm::ModuleAnalysisManager module_analysis_manager_; + llvm::LoopAnalysisManager loop_analysis_manager_; + llvm::FunctionAnalysisManager function_analysis_manager_; + llvm::CGSCCAnalysisManager gscc_analysis_manager_; + llvm::ModuleAnalysisManager module_analysis_manager_; - PassBuilderPtr pass_builder_; + PassBuilderPtr pass_builder_; - llvm::ModulePassManager module_pass_manager_{}; + llvm::ModulePassManager module_pass_manager_{}; - ILoggerPtr logger_{}; -}; + LogColloectionPtr logger_{nullptr}; ///< Logger to keep track of errors and warnings occurring. + String save_to_filename_{""}; + }; -} // namespace quantum -} // namespace microsoft +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/site-packages/tasks_ci/formatting.py b/src/Passes/site-packages/tasks_ci/formatting.py index c0217ae590..68d83b74a8 100644 --- a/src/Passes/site-packages/tasks_ci/formatting.py +++ b/src/Passes/site-packages/tasks_ci/formatting.py @@ -41,7 +41,9 @@ "t", "sqrt", "dumpregister", - "read_result" + "read_result", + "arcsin", + "drawrandomint" ] From cdac282f8f7f76ed157ca0e1fd332c9192c782a9 Mon Sep 17 00:00:00 2001 From: "Troels F. Roennow" Date: Wed, 10 Nov 2021 09:29:38 +0100 Subject: [PATCH 13/17] Removing comment --- .../TransformationRulesPass.cpp | 34 ------------------- 1 file changed, 34 deletions(-) diff --git a/src/Passes/Source/TransformationRulesPass/TransformationRulesPass.cpp b/src/Passes/Source/TransformationRulesPass/TransformationRulesPass.cpp index 74ebc9d7bf..219922717c 100644 --- a/src/Passes/Source/TransformationRulesPass/TransformationRulesPass.cpp +++ b/src/Passes/Source/TransformationRulesPass/TransformationRulesPass.cpp @@ -790,40 +790,6 @@ namespace quantum processReplacements(); } - /* - replacements_.clear(); - for (auto &function : module) - { - - std::vector blocks; - for (auto &block : function) - { - blocks.push_back(&block); - } - - for (auto it_block = blocks.rbegin(); it_block != blocks.rend(); ++it_block) - { - auto &block = **it_block; - - // Deleteing blocks in reverse order - std::vector instructions; - for (auto &instr : block) - { - instructions.push_back(&instr); - } - - // Removing backwards to avoid segfault - for (auto it_inst = instructions.rbegin(); it_inst != instructions.rend(); ++it_inst) - { - auto &instr = **it_inst; - rule_set_.matchAndReplace(&instr, replacements_); - } - } - } - - processReplacements(); - */ - return llvm::PreservedAnalyses::none(); } From b0a66a1e1fe587f4d798b6c23d33bc9266b29b9e Mon Sep 17 00:00:00 2001 From: "Troels F. Roennow" Date: Wed, 10 Nov 2021 13:13:35 +0100 Subject: [PATCH 14/17] Moving testing to run before linting --- src/Passes/site-packages/tasks_ci/cli.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Passes/site-packages/tasks_ci/cli.py b/src/Passes/site-packages/tasks_ci/cli.py index be42af1137..9655d1f6e4 100644 --- a/src/Passes/site-packages/tasks_ci/cli.py +++ b/src/Passes/site-packages/tasks_ci/cli.py @@ -142,12 +142,12 @@ def runci() -> None: logger.info("Checking style") style_check_main(False) - logger.info("Static analysis") - lint_main(False) - logger.info("Testing") builder_main(build_dir, None, True) + logger.info("Static analysis") + lint_main(False) + @click.option( "--output", From 79b115999f1a373060ec9357f1c9466e7107d428 Mon Sep 17 00:00:00 2001 From: "Troels F. Roennow" Date: Wed, 10 Nov 2021 13:21:21 +0100 Subject: [PATCH 15/17] Updating CMake --- src/Passes/Source/CMakeLists.txt | 20 ++++++++++---------- src/Passes/manage.orig | 24 ------------------------ 2 files changed, 10 insertions(+), 34 deletions(-) delete mode 100755 src/Passes/manage.orig diff --git a/src/Passes/Source/CMakeLists.txt b/src/Passes/Source/CMakeLists.txt index 64bde26bc2..b026796330 100644 --- a/src/Passes/Source/CMakeLists.txt +++ b/src/Passes/Source/CMakeLists.txt @@ -1,35 +1,35 @@ cmake_minimum_required(VERSION 3.4.3) +microsoft_add_library(Logging) + microsoft_add_library(TestTools) -microsoft_add_library_tests(TestTools Generators) +microsoft_add_library_tests(TestTools Generators Logging) microsoft_add_library(Commandline) -microsoft_add_library_tests(Commandline) +microsoft_add_library_tests(Commandline Logging) microsoft_add_library(Profile) microsoft_add_library_tests(Profile) -microsoft_add_library(Logging) - microsoft_add_library(Validator Logging) -microsoft_add_library_tests(Validator ValidationPass) +microsoft_add_library_tests(Validator ValidationPass Logging) microsoft_add_library(ValidationPass Logging) microsoft_add_library(AllocationManager) -microsoft_add_library_tests(AllocationManager) +microsoft_add_library_tests(AllocationManager Logging) microsoft_add_library(TransformationRulesPass) target_link_libraries(TransformationRulesPass PRIVATE Rules Commandline AllocationManager) -microsoft_add_library_tests(TransformationRulesPass Rules TransformationRulesPass AllocationManager Commandline Generators Validator ValidationPass) +microsoft_add_library_tests(TransformationRulesPass Rules TransformationRulesPass AllocationManager Commandline Generators Validator ValidationPass Logging) microsoft_add_library(Rules) -microsoft_add_library_tests(Rules Rules TransformationRulesPass AllocationManager Commandline Generators) +microsoft_add_library_tests(Rules Rules TransformationRulesPass AllocationManager Commandline Generators Logging) target_link_libraries(Rules PRIVATE AllocationManager) microsoft_add_library(Generators) -target_link_libraries(Generators PRIVATE Rules Commandline AllocationManager TransformationRulesPass Profile Validator ValidationPass) -microsoft_add_library_tests(Generators Rules TransformationRulesPass AllocationManager Commandline Generators) +target_link_libraries(Generators PRIVATE Rules Commandline AllocationManager TransformationRulesPass Profile Validator ValidationPass Logging) +microsoft_add_library_tests(Generators Rules TransformationRulesPass AllocationManager Commandline Generators Logging) add_subdirectory(Apps) diff --git a/src/Passes/manage.orig b/src/Passes/manage.orig deleted file mode 100755 index 94044987e7..0000000000 --- a/src/Passes/manage.orig +++ /dev/null @@ -1,24 +0,0 @@ -#!/usr/bin/env python3 -# -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT License. - -import os -import sys - -# Adding the site-packages directory to our Python path -# in order to access the tasks_ci module -ROOT = os.path.dirname(__file__) -sys.path.insert(0, os.path.join(ROOT, "site-packages")) - -# Loading the CLI tool and running it -from tasks_ci.cli import cli # noqa: E402 - -<<<<<<< HEAD -# Running the CLI tool defined in site-packages/tasks_ci/cli -cli() -======= -# Running the CLI tool defined in site-packages/TasksCI/cli -if __name__ == "__main__": - cli() ->>>>>>> b21da15866d36ab40f1c4b9a8cb766b847e5df49 From f9f981e2800b75484945a8954245186962f4a97e Mon Sep 17 00:00:00 2001 From: "Troels F. Roennow" Date: Wed, 10 Nov 2021 15:21:16 +0100 Subject: [PATCH 16/17] Attempting to solve tests issue --- src/Passes/Makefile | 2 +- src/Passes/Source/Apps/CMakeLists.txt | 2 +- src/Passes/Source/CMakeLists.txt | 6 ++++-- src/Passes/Source/TestTools/IrManipulationTestHelper.cpp | 2 +- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/Passes/Makefile b/src/Passes/Makefile index 1c4adfaf45..b5ff0156a6 100644 --- a/src/Passes/Makefile +++ b/src/Passes/Makefile @@ -15,7 +15,7 @@ doxygen: linux-docker: - docker build -f Docker/CI.Ubuntu20.dockerfile -t qir-passes-ubuntu:latest . + docker build --no-cache -f Docker/CI.Ubuntu20.dockerfile -t qir-passes-ubuntu:latest . linux-ci: linux-docker docker run -it --rm -t qir-passes-ubuntu:latest ./manage runci diff --git a/src/Passes/Source/Apps/CMakeLists.txt b/src/Passes/Source/Apps/CMakeLists.txt index 4ec3771104..ea2f2338c9 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/QatConfig.cpp) target_link_libraries(qat ${llvm_libs}) -target_link_libraries(qat TransformationRulesPass Rules AllocationManager Commandline Generators Profile Validator ValidationPass Logging) +target_link_libraries(qat Logging TransformationRulesPass Rules AllocationManager Commandline Generators Profile Validator ValidationPass ) diff --git a/src/Passes/Source/CMakeLists.txt b/src/Passes/Source/CMakeLists.txt index b026796330..0dbabc01f0 100644 --- a/src/Passes/Source/CMakeLists.txt +++ b/src/Passes/Source/CMakeLists.txt @@ -11,7 +11,9 @@ microsoft_add_library_tests(Commandline Logging) microsoft_add_library(Profile) microsoft_add_library_tests(Profile) -microsoft_add_library(Validator Logging) +microsoft_add_library(Validator) +target_link_libraries(Validator PRIVATE Logging) + microsoft_add_library_tests(Validator ValidationPass Logging) microsoft_add_library(ValidationPass Logging) @@ -29,7 +31,7 @@ microsoft_add_library_tests(Rules Rules TransformationRulesPass AllocationManage target_link_libraries(Rules PRIVATE AllocationManager) microsoft_add_library(Generators) -target_link_libraries(Generators PRIVATE Rules Commandline AllocationManager TransformationRulesPass Profile Validator ValidationPass Logging) +target_link_libraries(Generators PRIVATE Rules Commandline AllocationManager TransformationRulesPass Profile Validator ValidationPass) microsoft_add_library_tests(Generators Rules TransformationRulesPass AllocationManager Commandline Generators Logging) add_subdirectory(Apps) diff --git a/src/Passes/Source/TestTools/IrManipulationTestHelper.cpp b/src/Passes/Source/TestTools/IrManipulationTestHelper.cpp index f3770ccad1..5388ea68e1 100644 --- a/src/Passes/Source/TestTools/IrManipulationTestHelper.cpp +++ b/src/Passes/Source/TestTools/IrManipulationTestHelper.cpp @@ -179,7 +179,7 @@ source_filename = "IrManipulationTestHelper.ll" { script += "declare " + op + "\n"; } - script += "\nattributes #0 = { \"EntryPoint\" }\n"; + script += "\nattributes #0 = { \"InteropFriendly\" }\n"; return script; } From a0a314f09ed512b430e5d2ace69c4830f66dea7d Mon Sep 17 00:00:00 2001 From: "Troels F. Roennow" Date: Thu, 11 Nov 2021 08:20:10 +0100 Subject: [PATCH 17/17] Updating according to PR comments --- src/Passes/Source/Rules/Factory.cpp | 21 +++++++++++++++------ src/Passes/Source/Validator/Validator.cpp | 8 ++++---- src/Passes/Source/Validator/Validator.hpp | 2 +- 3 files changed, 20 insertions(+), 11 deletions(-) diff --git a/src/Passes/Source/Rules/Factory.cpp b/src/Passes/Source/Rules/Factory.cpp index 7c4ae63469..836b09b39d 100644 --- a/src/Passes/Source/Rules/Factory.cpp +++ b/src/Passes/Source/Rules/Factory.cpp @@ -634,14 +634,23 @@ namespace quantum { removeFunctionCall("__quantum__rt__fail"); removeFunctionCall("__quantum__rt__message"); - removeFunctionCall("__quantum__rt__bool_to_string"); - removeFunctionCall("__quantum__rt__double_to_string"); - removeFunctionCall("__quantum__rt__pauli_to_string"); - removeFunctionCall("__quantum__rt__int_to_string"); - removeFunctionCall("__quantum__rt__string_concatenate"); removeFunctionCall("__quantum__rt__string_update_alias_count"); - removeFunctionCall("__quantum__rt__string_update_reference_count"); + removeFunctionCall("__quantum__rt__string_create"); + removeFunctionCall("__quantum__rt__string_get_data"); + removeFunctionCall("__quantum__rt__string_get_length"); + removeFunctionCall("__quantum__rt__string_update_reference_count"); + removeFunctionCall("__quantum__rt__string_concatenate"); + removeFunctionCall("__quantum__rt__string_equal"); + + removeFunctionCall("__quantum__rt__int_to_string"); + removeFunctionCall("__quantum__rt__double_to_string"); + removeFunctionCall("__quantum__rt__bool_to_string"); + removeFunctionCall("__quantum__rt__result_to_string"); + removeFunctionCall("__quantum__rt__pauli_to_string"); + removeFunctionCall("__quantum__rt__qubit_to_string"); + removeFunctionCall("__quantum__rt__range_to_string"); + removeFunctionCall("__quantum__rt__bigint_to_string"); } ReplacementRulePtr RuleFactory::addRule(ReplacementRule&& rule) diff --git a/src/Passes/Source/Validator/Validator.cpp b/src/Passes/Source/Validator/Validator.cpp index cb73344df1..43a91b5094 100644 --- a/src/Passes/Source/Validator/Validator.cpp +++ b/src/Passes/Source/Validator/Validator.cpp @@ -61,7 +61,7 @@ namespace quantum logger_->error("Fatal error: Invalid IR."); } - saveLogsToFileIfNeeded(); + saveReportToFileIfNeeded(); return false; } @@ -76,11 +76,11 @@ namespace quantum logger_->error("Fatal error: " + static_cast(e.what())); } - saveLogsToFileIfNeeded(); + saveReportToFileIfNeeded(); return false; } - saveLogsToFileIfNeeded(); + saveReportToFileIfNeeded(); return true; } @@ -109,7 +109,7 @@ namespace quantum return module_analysis_manager_; } - void Validator::saveLogsToFileIfNeeded() + void Validator::saveReportToFileIfNeeded() { if (!save_to_filename_.empty() && logger_) { diff --git a/src/Passes/Source/Validator/Validator.hpp b/src/Passes/Source/Validator/Validator.hpp index b4649db41a..ae2ff63309 100644 --- a/src/Passes/Source/Validator/Validator.hpp +++ b/src/Passes/Source/Validator/Validator.hpp @@ -70,7 +70,7 @@ namespace quantum llvm::ModuleAnalysisManager& moduleAnalysisManager(); private: - void saveLogsToFileIfNeeded(); + void saveReportToFileIfNeeded(); // LLVM logic to run the passes //