Commit f1da4861 authored by Nguyen, Thien Minh's avatar Nguyen, Thien Minh
Browse files

First example using Q# kernel in OpenQASM3



- Declare the subroutine in OpenQASM3 which will be provided at link time (from Q#)

- Fix a type resolution in OpenQASM3: int64_t string should be checked first before int.

- Update the qcor.in driver to support mixing different custom file types in one compilation, e.g. Q# and OpenQASM.

- Also, fix the Q# part in the driver script to remove the unused command line warning, i.e. let the script compile the cpp driver (if any) then link later.

Signed-off-by: default avatarThien Nguyen <nguyentm@ornl.gov>
parent 0173dea1
Loading
Loading
Loading
Loading
+13 −0
Original line number Diff line number Diff line
OPENQASM 3;

// Declare kernel:
// This one is from Q#...
kernel QCOR__GenerateRandomInt__Interop(int[64]) -> int64_t;


// Generate the random number (4 bits)
int64_t max_bits = 4;
int64_t n = QCOR__GenerateRandomInt__Interop(max_bits);

// Print the random number
print("[OpenQASM3]Random int (lsb): ", n);
 No newline at end of file
+23 −0
Original line number Diff line number Diff line
namespace QCOR 
{
open Microsoft.Quantum.Intrinsic;

@EntryPoint() 
operation GenerateRandomInt(maxBits: Int): Int {
  mutable rngNumber = 0;
  use qubit = Qubit() 
  {
    for idx in 1..maxBits {
      H(qubit);
      if (M(qubit) == One) {
        set rngNumber = rngNumber + (1 <<< (idx - 1));
        // Reset
        X(qubit);
      }
    }
  }
  Message($"Random number = {rngNumber}");
  return rngNumber;
}
}
+3 −2
Original line number Diff line number Diff line
@@ -421,14 +421,15 @@ antlrcpp::Any qasm3_visitor::visitKernelDeclaration(
    } else if (auto no_desig = classical_type->noDesignatorType()) {
      if (no_desig->getText().find("uint") != std::string::npos) {
        return_type = builder.getIntegerType(32, false);
      } else if (no_desig->getText().find("int64_t") != std::string::npos) {
        // This must be before "int"
        return_type = builder.getI64Type();
      } else if (no_desig->getText().find("int") != std::string::npos) {
        return_type = builder.getIntegerType(32);
      } else if (no_desig->getText().find("float") != std::string::npos) {
        return_type = builder.getF32Type();
      } else if (no_desig->getText().find("double") != std::string::npos) {
        return_type = builder.getF64Type();
      } else if (no_desig->getText().find("int64_t") != std::string::npos) {
        return_type = builder.getI64Type();
      } else {
        printErrorMessage("Invalid no-designator default type.", context);
      }
+25 −35
Original line number Diff line number Diff line
@@ -401,22 +401,12 @@ def main(argv=None):
    # Get the filename we are compiling or the object file
    filename = ''
    fileType = ''
    for arg in sys.argv[1:]:
        if os.path.isfile(arg) and mimetypes.guess_type(arg)[0] is not None:
            filename = arg
            fileType = mimetypes.guess_type(filename)[0]
            if fileType == 'text/x-c++src':
                break
        if os.path.isfile(arg) and os.path.splitext(arg)[1] == '.qasm':
            fileType = 'openqasm'
            filename = arg
    
        if os.path.isfile(arg) and os.path.splitext(arg)[1] == '.qs':
            fileType = 'qsharp'
            filename = arg
            break

    if fileType == 'openqasm':
    # Define custom compilation routines for OpenQASM and Q#
    # i.e. use custom tool to lower to LLVM IR -> LLVM assembler
    # To support mixing multiple file types in one compilation.
    # Util to compile QASM2/3 (MLIR)
    def compile_qasm(filename):
        # Convert to MLIR and then to LLVM QIR
        base_name = os.path.splitext(filename)[0]
        ll_file_name = base_name + '.ll'
@@ -442,7 +432,8 @@ def main(argv=None):
            os.remove(ll_file_name)
            os.remove(bc_file_name)
    
    if fileType == 'qsharp':
    # Util to compile Q#
    def compile_qsharp(filename):
        base_name = os.path.splitext(filename)[0]
        # Generate build command:
        build_cmd = generate_qsc_build_command(base_name, os.path.dirname(os.path.abspath(filename)), [filename, '@CMAKE_INSTALL_PREFIX@/include/qsharp/QirTarget.qs'])
@@ -480,23 +471,6 @@ def main(argv=None):
        fileType = None
        filename = None
        sys.argv.append(base_name+ '.o')     
        for arg in sys.argv[1:]:
            if os.path.isfile(arg) and mimetypes.guess_type(arg)[0] == 'text/x-c++src':
                # There is a driver C++ file as well.
                driver_file_name = arg
                sys.argv.remove(driver_file_name)
                cpp_compile_commands = [compiler] + defaultFlags + sHandlerArgs + baseIncludes + ['-c'] +[driver_file_name]
                cpp_compile_commands += sys.argv[1:]
                if verbose:
                    print('[qcor-exec]: ', ' '.join([c for c in cpp_compile_commands]))
                try:
                    result = subprocess.run(cpp_compile_commands, check=True)
                except subprocess.CalledProcessError as e:
                    print(e.output)
                    print(e.returncode)
                base_cpp_name = os.path.splitext(driver_file_name)[0]
                sys.argv.append(base_cpp_name + '.o')     
        
        if not keep_bit_code_files:
            # remove these temp files
            try:
@@ -505,6 +479,22 @@ def main(argv=None):
            except OSError:
                pass
    
    for arg in sys.argv[1:]:
        if os.path.isfile(arg) and mimetypes.guess_type(arg)[0] is not None:
            filename = arg
            fileType = mimetypes.guess_type(filename)[0]
            if fileType == 'text/x-c++src':
                break
        if os.path.isfile(arg) and os.path.splitext(arg)[1] == '.qasm':
            fileType = 'openqasm'
            filename = arg
            compile_qasm(filename)
        
        if os.path.isfile(arg) and os.path.splitext(arg)[1] == '.qs':
            fileType = 'qsharp'
            filename = arg
            compile_qsharp(filename)

    # If it is a C++ file
    if fileType != None and 'text/x-c' in fileType:
        fileIdx = sys.argv[1:].index(filename)