Loading mlir/parsers/qasm3/CMakeLists.txt +2 −1 Original line number Diff line number Diff line Loading @@ -44,3 +44,4 @@ endif() install(TARGETS ${LIBRARY_NAME} DESTINATION ${CMAKE_INSTALL_PREFIX}/lib) add_subdirectory(tests) add_subdirectory(handler) No newline at end of file mlir/parsers/qasm3/handler/CMakeLists.txt 0 → 100644 +31 −0 Original line number Diff line number Diff line set(ANTLR_LIB ${XACC_ROOT}/lib/libantlr4-runtime.so) if (APPLE) set(ANTLR_LIB ${XACC_ROOT}/lib/libantlr4-runtime.dylib) endif() set(LIBRARY_NAME qasm3-syntax-handler) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti") add_library(${LIBRARY_NAME} SHARED qasm3_handler.cpp) target_include_directories(${LIBRARY_NAME} PUBLIC . .. ${CMAKE_SOURCE_DIR}/mlir/parsers/qasm3/antlr/generated/ ${CMAKE_SOURCE_DIR}/mlir/parsers/qasm3/utils/ ${XACC_ROOT}/include/antlr4-runtime ${CMAKE_SOURCE_DIR}/mlir/dialect/include ${CMAKE_BINARY_DIR}/mlir/dialect/include ${CLANG_INCLUDE_DIRS} ${LLVM_INCLUDE_DIRS} ) target_link_libraries(${LIBRARY_NAME} PRIVATE ${CLANG_LIBS} ${LLVM_LIBS} MLIRQuantum MLIRIR MLIRStandard qcor-mlir-api) if(APPLE) set_target_properties(${LIBRARY_NAME} PROPERTIES INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib;${XACC_ROOT}/lib;${LLVM_INSTALL_PREFIX}/lib") set_target_properties(${LIBRARY_NAME} PROPERTIES LINK_FLAGS "-undefined dynamic_lookup") else() set_target_properties(${LIBRARY_NAME} PROPERTIES INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib:${XACC_ROOT}/lib:${LLVM_INSTALL_PREFIX}/lib") set_target_properties(${LIBRARY_NAME} PROPERTIES LINK_FLAGS "-shared") endif() install(TARGETS ${LIBRARY_NAME} DESTINATION clang-plugins) mlir/parsers/qasm3/handler/examples/qasm3_handler_test.cpp 0 → 100644 +51 −0 Original line number Diff line number Diff line #include "qir-qrt.hpp" using qubit = Qubit*; [[clang::syntax(qasm3)]] int test(int i, qubit q, qubit r) { int ten = 10 * i; h q; cx q, r; bit c[2]; c[0] = measure q; c[1] = measure r; reset q; reset r; return int[32](c); } // Run with... // clang++ -std=c++17 -fplugin=/path/to/libqasm3-syntax-handler.so -I /path/to/qcor/include/qcor -I/path/to/xacc/include/xacc -c qasm3_test.cpp // llc -filetype=obj test.bc (test comes from kernel name, so will need to do this for all kernels) // clang++ -L /path/to/install/lib -lqir-qrt -lqcor -lxacc -lqrt -lCppMicroServices test.o qasm3_test.o // ./a.out int main(int argc, char** argv) { int x = 10; // Figure out how to initialize automatically __quantum__rt__initialize(argc, reinterpret_cast<int8_t**>(argv)); // Connect this to qalloc(...) auto qreg = __quantum__rt__qubit_allocate_array(2); // Should be able to get qubit from operator[] on qreg auto qbit_mem = __quantum__rt__array_get_element_ptr_1d(qreg, 0); auto qbit = reinterpret_cast<Qubit**>(qbit_mem)[0]; auto qbit_mem2 = __quantum__rt__array_get_element_ptr_1d(qreg, 1); auto qbit2 = reinterpret_cast<Qubit**>(qbit_mem2)[0]; // Run bell test... int ones = 0, zeros = 0; for (int i = 0; i < 50; i++) { auto y = test(x, qbit, qbit2); // should be binary-as-int 00 = 0, or 11 = 3 if (y == 3) { ones++; } else { zeros++; } } printf("Result: 11:%d, 00:%d\n", ones, zeros); return 0; } No newline at end of file mlir/parsers/qasm3/handler/qasm3_handler.cpp 0 → 100644 +169 −0 Original line number Diff line number Diff line #include "qasm3_handler.hpp" #include <iostream> #include <regex> #include <sstream> #include "qasm3_handler_utils.hpp" #include "openqasmv3_mlir_generator.hpp" #include "quantum_to_llvm.hpp" using namespace clang; namespace qcor { void Qasm3SyntaxHandler::GetReplacement(Preprocessor &PP, Declarator &D, CachedTokens &Toks, llvm::raw_string_ostream &OS) { // Get the function name auto kernel_name = D.getName().Identifier->getName().str(); // Create the MLIRContext and load the dialects mlir::MLIRContext context; context .loadDialect<mlir::quantum::QuantumDialect, mlir::StandardOpsDialect>(); // Create the mlir generator for qasm3 OpenQasmV3MLIRGenerator mlir_generator(context); // Build up the function source code std::stringstream ss; for (auto &Tok : Toks) { ss << " "; ss << PP.getSpelling(Tok); } std::string src = ss.str(); // Loop through function arguments and // build up associated mlir::Type arguments, // For vectors use Array * std::vector<mlir::Type> arg_types; std::vector<std::string> program_parameters, arg_type_strs; const DeclaratorChunk::FunctionTypeInfo &FTI = D.getFunctionTypeInfo(); for (unsigned int ii = 0; ii < FTI.NumParams; ii++) { // Get parameters as a ParmVarDecl auto ¶mInfo = FTI.Params[ii]; auto &decl = paramInfo.Param; auto parm_var_decl = cast<ParmVarDecl>(decl); // Get the type pointer auto type = parm_var_decl->getType().getTypePtr(); // Get VarName and Type as strings Token IdentToken, TypeToken; PP.getRawToken(paramInfo.IdentLoc, IdentToken); PP.getRawToken(decl->getBeginLoc(), TypeToken); auto var = PP.getSpelling(IdentToken); auto type_str = PP.getSpelling(TypeToken); // Add them to the vectors program_parameters.push_back(var); arg_type_strs.push_back(type_str); // Convert type to a mlir type mlir::Type t = convertClangType(type, type_str, context); arg_types.push_back(t); } // std::cout << "SRC:\n" << ss.str() << "\n"; // Get the return type as an mlir type, // as well as a string std::string ret_type_str = ""; mlir::Type return_type = convertReturnType(D.getDeclSpec(), ret_type_str, context); // Init the MLIRGen mlir_generator.initialize_mlirgen(kernel_name, arg_types, program_parameters, return_type); // Run the MLIRGen mlir_generator.mlirgen(src); // Finalize and get the Module mlir_generator.finalize_mlirgen(); auto module = mlir_generator.get_module(); // module->dump(); // Lower the module to LLVM IR bit code file DiagnosticEngine &engine = context.getDiagEngine(); // Handle the reported diagnostic. // Return success to signal that the diagnostic has either been fully // processed, or failure if the diagnostic should be propagated to the // previous handlers. engine.registerHandler([&](mlir::Diagnostic &diag) -> LogicalResult { std::cout << "Dumping Module after error.\n"; module->dump(); for (auto &n : diag.getNotes()) { std::string s; llvm::raw_string_ostream os(s); n.print(os); os.flush(); std::cout << "DiagnosticEngine Note: " << s << "\n"; } bool should_propagate_diagnostic = true; return failure(should_propagate_diagnostic); }); // Create the PassManager for lowering to LLVM MLIR and run it std::vector<std::string> unique_f_names{kernel_name}; mlir::PassManager pm(&context); applyPassManagerCLOptions(pm); pm.addPass(std::make_unique<qcor::QuantumToLLVMLoweringPass>(unique_f_names)); auto module_op = (*module).getOperation(); if (mlir::failed(pm.run(module_op))) { std::cout << "Pass Manager Failed\n"; } // Now lower MLIR to LLVM IR llvm::LLVMContext llvmContext; auto llvmModule = mlir::translateModuleToLLVMIR(*module, llvmContext); // Optimize the LLVM IR llvm::InitializeNativeTarget(); llvm::InitializeNativeTargetAsmPrinter(); auto optPipeline = mlir::makeOptimizingTransformer(3, 0, nullptr); if (auto err = optPipeline(llvmModule.get())) { llvm::errs() << "Failed to optimize LLVM IR " << err << "\n"; } // llvmModule->dump(); // Write the LLVM IR to a bitcode file std::error_code ec; llvm::ToolOutputFile result(kernel_name + ".bc", ec, llvm::sys::fs::F_None); WriteBitcodeToFile(*llvmModule, result.os()); result.keep(); // Update the source code std::stringstream sss; sss << "extern \"C\" { " << ret_type_str << " __internal_mlir_" << kernel_name << "(" << arg_type_strs[0]; for (int i = 1; i < arg_type_strs.size(); i++) { sss << ", " << arg_type_strs[i]; } sss << ");}\n"; // Rewrite the function to call the internal function sss << getDeclText(PP, D).str() << "{\n"; sss << "return __internal_mlir_" << kernel_name << "(" << program_parameters[0]; for (int i = 1; i < program_parameters.size(); i++) { sss << ", " << program_parameters[i]; } sss << ");\n"; sss << "}\n"; // std::cout << "NEW CODE:\n" << sss.str() << "\n"; OS << sss.str(); return; } void Qasm3SyntaxHandler::AddToPredefines(llvm::raw_string_ostream &OS) {} } // namespace qcor static SyntaxHandlerRegistry::Add<qcor::Qasm3SyntaxHandler> X( "qasm3", "qasm3 quantum kernel syntax handler"); // /usr/local/aideqc/llvm/bin/clang++ -std=c++17 // -fplugin=/home/cades/.xacc/clang-plugins/libqasm3-syntax-handler.so -c // qasm3_test.cpp /usr/local/aideqc/llvm/bin/llc -filetype=obj test.bc // /usr/local/aideqc/llvm/bin/clang++ test.o qasm3_test.o // ./a.out No newline at end of file mlir/parsers/qasm3/handler/qasm3_handler.hpp 0 → 100644 +19 −0 Original line number Diff line number Diff line #pragma once #include "clang/Parse/Parser.h" using namespace clang; namespace qcor { class Qasm3SyntaxHandler : public SyntaxHandler { public: Qasm3SyntaxHandler() : SyntaxHandler("qasm3") {} void GetReplacement(Preprocessor &PP, Declarator &D, CachedTokens &Toks, llvm::raw_string_ostream &OS) override; void AddToPredefines(llvm::raw_string_ostream &OS) override; }; } // namespace qcor No newline at end of file Loading
mlir/parsers/qasm3/CMakeLists.txt +2 −1 Original line number Diff line number Diff line Loading @@ -44,3 +44,4 @@ endif() install(TARGETS ${LIBRARY_NAME} DESTINATION ${CMAKE_INSTALL_PREFIX}/lib) add_subdirectory(tests) add_subdirectory(handler) No newline at end of file
mlir/parsers/qasm3/handler/CMakeLists.txt 0 → 100644 +31 −0 Original line number Diff line number Diff line set(ANTLR_LIB ${XACC_ROOT}/lib/libantlr4-runtime.so) if (APPLE) set(ANTLR_LIB ${XACC_ROOT}/lib/libantlr4-runtime.dylib) endif() set(LIBRARY_NAME qasm3-syntax-handler) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti") add_library(${LIBRARY_NAME} SHARED qasm3_handler.cpp) target_include_directories(${LIBRARY_NAME} PUBLIC . .. ${CMAKE_SOURCE_DIR}/mlir/parsers/qasm3/antlr/generated/ ${CMAKE_SOURCE_DIR}/mlir/parsers/qasm3/utils/ ${XACC_ROOT}/include/antlr4-runtime ${CMAKE_SOURCE_DIR}/mlir/dialect/include ${CMAKE_BINARY_DIR}/mlir/dialect/include ${CLANG_INCLUDE_DIRS} ${LLVM_INCLUDE_DIRS} ) target_link_libraries(${LIBRARY_NAME} PRIVATE ${CLANG_LIBS} ${LLVM_LIBS} MLIRQuantum MLIRIR MLIRStandard qcor-mlir-api) if(APPLE) set_target_properties(${LIBRARY_NAME} PROPERTIES INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib;${XACC_ROOT}/lib;${LLVM_INSTALL_PREFIX}/lib") set_target_properties(${LIBRARY_NAME} PROPERTIES LINK_FLAGS "-undefined dynamic_lookup") else() set_target_properties(${LIBRARY_NAME} PROPERTIES INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib:${XACC_ROOT}/lib:${LLVM_INSTALL_PREFIX}/lib") set_target_properties(${LIBRARY_NAME} PROPERTIES LINK_FLAGS "-shared") endif() install(TARGETS ${LIBRARY_NAME} DESTINATION clang-plugins)
mlir/parsers/qasm3/handler/examples/qasm3_handler_test.cpp 0 → 100644 +51 −0 Original line number Diff line number Diff line #include "qir-qrt.hpp" using qubit = Qubit*; [[clang::syntax(qasm3)]] int test(int i, qubit q, qubit r) { int ten = 10 * i; h q; cx q, r; bit c[2]; c[0] = measure q; c[1] = measure r; reset q; reset r; return int[32](c); } // Run with... // clang++ -std=c++17 -fplugin=/path/to/libqasm3-syntax-handler.so -I /path/to/qcor/include/qcor -I/path/to/xacc/include/xacc -c qasm3_test.cpp // llc -filetype=obj test.bc (test comes from kernel name, so will need to do this for all kernels) // clang++ -L /path/to/install/lib -lqir-qrt -lqcor -lxacc -lqrt -lCppMicroServices test.o qasm3_test.o // ./a.out int main(int argc, char** argv) { int x = 10; // Figure out how to initialize automatically __quantum__rt__initialize(argc, reinterpret_cast<int8_t**>(argv)); // Connect this to qalloc(...) auto qreg = __quantum__rt__qubit_allocate_array(2); // Should be able to get qubit from operator[] on qreg auto qbit_mem = __quantum__rt__array_get_element_ptr_1d(qreg, 0); auto qbit = reinterpret_cast<Qubit**>(qbit_mem)[0]; auto qbit_mem2 = __quantum__rt__array_get_element_ptr_1d(qreg, 1); auto qbit2 = reinterpret_cast<Qubit**>(qbit_mem2)[0]; // Run bell test... int ones = 0, zeros = 0; for (int i = 0; i < 50; i++) { auto y = test(x, qbit, qbit2); // should be binary-as-int 00 = 0, or 11 = 3 if (y == 3) { ones++; } else { zeros++; } } printf("Result: 11:%d, 00:%d\n", ones, zeros); return 0; } No newline at end of file
mlir/parsers/qasm3/handler/qasm3_handler.cpp 0 → 100644 +169 −0 Original line number Diff line number Diff line #include "qasm3_handler.hpp" #include <iostream> #include <regex> #include <sstream> #include "qasm3_handler_utils.hpp" #include "openqasmv3_mlir_generator.hpp" #include "quantum_to_llvm.hpp" using namespace clang; namespace qcor { void Qasm3SyntaxHandler::GetReplacement(Preprocessor &PP, Declarator &D, CachedTokens &Toks, llvm::raw_string_ostream &OS) { // Get the function name auto kernel_name = D.getName().Identifier->getName().str(); // Create the MLIRContext and load the dialects mlir::MLIRContext context; context .loadDialect<mlir::quantum::QuantumDialect, mlir::StandardOpsDialect>(); // Create the mlir generator for qasm3 OpenQasmV3MLIRGenerator mlir_generator(context); // Build up the function source code std::stringstream ss; for (auto &Tok : Toks) { ss << " "; ss << PP.getSpelling(Tok); } std::string src = ss.str(); // Loop through function arguments and // build up associated mlir::Type arguments, // For vectors use Array * std::vector<mlir::Type> arg_types; std::vector<std::string> program_parameters, arg_type_strs; const DeclaratorChunk::FunctionTypeInfo &FTI = D.getFunctionTypeInfo(); for (unsigned int ii = 0; ii < FTI.NumParams; ii++) { // Get parameters as a ParmVarDecl auto ¶mInfo = FTI.Params[ii]; auto &decl = paramInfo.Param; auto parm_var_decl = cast<ParmVarDecl>(decl); // Get the type pointer auto type = parm_var_decl->getType().getTypePtr(); // Get VarName and Type as strings Token IdentToken, TypeToken; PP.getRawToken(paramInfo.IdentLoc, IdentToken); PP.getRawToken(decl->getBeginLoc(), TypeToken); auto var = PP.getSpelling(IdentToken); auto type_str = PP.getSpelling(TypeToken); // Add them to the vectors program_parameters.push_back(var); arg_type_strs.push_back(type_str); // Convert type to a mlir type mlir::Type t = convertClangType(type, type_str, context); arg_types.push_back(t); } // std::cout << "SRC:\n" << ss.str() << "\n"; // Get the return type as an mlir type, // as well as a string std::string ret_type_str = ""; mlir::Type return_type = convertReturnType(D.getDeclSpec(), ret_type_str, context); // Init the MLIRGen mlir_generator.initialize_mlirgen(kernel_name, arg_types, program_parameters, return_type); // Run the MLIRGen mlir_generator.mlirgen(src); // Finalize and get the Module mlir_generator.finalize_mlirgen(); auto module = mlir_generator.get_module(); // module->dump(); // Lower the module to LLVM IR bit code file DiagnosticEngine &engine = context.getDiagEngine(); // Handle the reported diagnostic. // Return success to signal that the diagnostic has either been fully // processed, or failure if the diagnostic should be propagated to the // previous handlers. engine.registerHandler([&](mlir::Diagnostic &diag) -> LogicalResult { std::cout << "Dumping Module after error.\n"; module->dump(); for (auto &n : diag.getNotes()) { std::string s; llvm::raw_string_ostream os(s); n.print(os); os.flush(); std::cout << "DiagnosticEngine Note: " << s << "\n"; } bool should_propagate_diagnostic = true; return failure(should_propagate_diagnostic); }); // Create the PassManager for lowering to LLVM MLIR and run it std::vector<std::string> unique_f_names{kernel_name}; mlir::PassManager pm(&context); applyPassManagerCLOptions(pm); pm.addPass(std::make_unique<qcor::QuantumToLLVMLoweringPass>(unique_f_names)); auto module_op = (*module).getOperation(); if (mlir::failed(pm.run(module_op))) { std::cout << "Pass Manager Failed\n"; } // Now lower MLIR to LLVM IR llvm::LLVMContext llvmContext; auto llvmModule = mlir::translateModuleToLLVMIR(*module, llvmContext); // Optimize the LLVM IR llvm::InitializeNativeTarget(); llvm::InitializeNativeTargetAsmPrinter(); auto optPipeline = mlir::makeOptimizingTransformer(3, 0, nullptr); if (auto err = optPipeline(llvmModule.get())) { llvm::errs() << "Failed to optimize LLVM IR " << err << "\n"; } // llvmModule->dump(); // Write the LLVM IR to a bitcode file std::error_code ec; llvm::ToolOutputFile result(kernel_name + ".bc", ec, llvm::sys::fs::F_None); WriteBitcodeToFile(*llvmModule, result.os()); result.keep(); // Update the source code std::stringstream sss; sss << "extern \"C\" { " << ret_type_str << " __internal_mlir_" << kernel_name << "(" << arg_type_strs[0]; for (int i = 1; i < arg_type_strs.size(); i++) { sss << ", " << arg_type_strs[i]; } sss << ");}\n"; // Rewrite the function to call the internal function sss << getDeclText(PP, D).str() << "{\n"; sss << "return __internal_mlir_" << kernel_name << "(" << program_parameters[0]; for (int i = 1; i < program_parameters.size(); i++) { sss << ", " << program_parameters[i]; } sss << ");\n"; sss << "}\n"; // std::cout << "NEW CODE:\n" << sss.str() << "\n"; OS << sss.str(); return; } void Qasm3SyntaxHandler::AddToPredefines(llvm::raw_string_ostream &OS) {} } // namespace qcor static SyntaxHandlerRegistry::Add<qcor::Qasm3SyntaxHandler> X( "qasm3", "qasm3 quantum kernel syntax handler"); // /usr/local/aideqc/llvm/bin/clang++ -std=c++17 // -fplugin=/home/cades/.xacc/clang-plugins/libqasm3-syntax-handler.so -c // qasm3_test.cpp /usr/local/aideqc/llvm/bin/llc -filetype=obj test.bc // /usr/local/aideqc/llvm/bin/clang++ test.o qasm3_test.o // ./a.out No newline at end of file
mlir/parsers/qasm3/handler/qasm3_handler.hpp 0 → 100644 +19 −0 Original line number Diff line number Diff line #pragma once #include "clang/Parse/Parser.h" using namespace clang; namespace qcor { class Qasm3SyntaxHandler : public SyntaxHandler { public: Qasm3SyntaxHandler() : SyntaxHandler("qasm3") {} void GetReplacement(Preprocessor &PP, Declarator &D, CachedTokens &Toks, llvm::raw_string_ostream &OS) override; void AddToPredefines(llvm::raw_string_ostream &OS) override; }; } // namespace qcor No newline at end of file