Skip to content
This repository was archived by the owner on Jan 12, 2024. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion global.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"msbuild-sdks": {
"Microsoft.Quantum.Sdk": "0.15.210324735-alpha"
"Microsoft.Quantum.Sdk": "0.15.210425594-alpha"
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">

<Import Project="..\Common\AssemblyCommon.props" />

Expand Down
2 changes: 1 addition & 1 deletion src/Qir/.gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
# Ignore the generated qir files from Q# compiler
qir/
**/qsharp/qir/
7 changes: 3 additions & 4 deletions src/Qir/Runtime/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -145,8 +145,9 @@ There are two ways to compile and run the QIR files against the runtime.

QIR's architecture assumes a single target, whether that be hardware or a particular simulator. As a result, there is no
provision in the QIR specifications to choose a target dynamically. To connect QIR to the simulators from this runtime,
we provide `InitializeQirContext` and `ReleaseQirContext` methods. Switching contexts while executing QIR isn't
supported and would yield undefined behavior.
we provide `QirExecutionContext::Init()` (earlier `InitializeQirContext`)
and `QirExecutionContext::Deinit()` (earlier `ReleaseQirContext`) methods.
Switching contexts while executing QIR isn't supported and would yield undefined behavior.

### Building from IR files

Expand All @@ -166,8 +167,6 @@ CMake doesn't support using LLVM's IR files as input so instead we invoke Clang
1. Variadic functions (e.g. `__quantum__rt__array_create`) require platform specific bridges. The currently implemented
bridge is for Windows.
1. Qubit borrowing NYI (needs both bridge and simulator's support).
1. `@ResultZero` and `@ResultOne` global variables, used in QIR generated from Q#, cannot be treated in a
platform-agnostic way when linking against the shared qdk library.

## Coding style and conventions

Expand Down
4 changes: 3 additions & 1 deletion src/Qir/Runtime/lib/QIR/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,16 @@
# create qir-rt-support lib from the C++ sources
#
set(rt_sup_source_files
QirRange.cpp
OutputStream.cpp
Output.cpp
allocationsTracker.cpp
arrays.cpp
callables.cpp
context.cpp
delegated.cpp
strings.cpp
utils.cpp
rtOut.cpp
)

# Produce object lib we'll use to create a shared lib (so/dll) later on
Expand Down
13 changes: 13 additions & 0 deletions src/Qir/Runtime/lib/QIR/Output.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#include <ostream> // std::endl
#include "QirTypes.hpp"
#include "QirRuntime.hpp" // QIR_SHARED_API for quantum__rt__message.
#include "OutputStream.hpp"

// Public API:
extern "C"
{
void quantum__rt__message(QirString* qstr) // NOLINT
{
Microsoft::Quantum::OutputStream::Get() << qstr->str << std::endl;
}
} // extern "C"
46 changes: 46 additions & 0 deletions src/Qir/Runtime/lib/QIR/OutputStream.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

// https://stackoverflow.com/a/5419388/6362941 redirect std::cout to a string
// Discussion/history and some more info about the output redirection:
// https://github.com/microsoft/qsharp-runtime/pull/511#discussion_r574170031
// https://github.com/microsoft/qsharp-runtime/pull/511#discussion_r574194191

#include <iostream>
#include "QirRuntime.hpp"
#include "OutputStream.hpp"

namespace Microsoft // Replace with `namespace Microsoft::Quantum` after migration to C++17.
{
namespace Quantum
{
std::ostream* OutputStream::currentOutputStream = &std::cout; // Output to std::cout by default.

std::ostream& OutputStream::Get()
{
return *currentOutputStream;
}

std::ostream& OutputStream::Set(std::ostream& newOStream)
{
std::ostream& oldOStream = *currentOutputStream;
currentOutputStream = &newOStream;
return oldOStream;
}

OutputStream::ScopedRedirector::ScopedRedirector(std::ostream& newOstream)
: old(OutputStream::Set(newOstream))
{}

OutputStream::ScopedRedirector::~ScopedRedirector()
{
OutputStream::Set(old);
}

std::ostream& SetOutputStream(std::ostream & newOStream)
{
return OutputStream::Set(newOStream);
}

} // namespace Quantum
} // namespace Microsoft
19 changes: 19 additions & 0 deletions src/Qir/Runtime/lib/QIR/QirRange.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

#include <cstdint>
#include "QirTypes.hpp"

QirRange::QirRange()
: start(0)
, step(0)
, end(0)
{
}

QirRange::QirRange(int64_t st, int64_t sp, int64_t en)
: start(st)
, step(sp)
, end(en)
{
}
66 changes: 66 additions & 0 deletions src/Qir/Runtime/lib/QIR/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# API Dependency

(Try to keep the readability balance between the web view and raw file, give the preference to the raw file)

The listed earlier ones provide the functionality to the listed later ones
(the listed later ones include and/or call the listed earlier ones,
the listed later ones cannot be compiled into an executable without the listed earlier ones).

Same-level entities are independent of each other (unless specified otherwise). Entities depend on the levels listed earlier only.


## Level 0. External To This Directory

**public\CoreTypes.hpp** Defines `QIR_SHARED_API`, `QUBIT`, `Qubit`, `RESULT`, `Result`, `ResultValue`, `PauliId`.
Does not depend on anything of our code.

**public\QirTypes.hpp** Defines `QirArray`, `QirString`, `PTuple`, `QirTupleHeader`, `TupleWithControls`, `QirCallable`, `QirRange`.
Depends on the listed earlier ones.

**public\QirRuntime.hpp** Declares `quantum__rt__*()`. Depends on the listed earlier ones.


## Level 1

**allocationsTracker.hpp** Defines `Microsoft::Quantum::AllocationsTracker` that tracks the allocations and detects the mem leaks.
Does not depend on anything of our code.

**utils.cpp** Implements `quantum__rt__fail()`, `quantum__rt__memory_allocate()`, `quantum__rt__heap_{alloc,free}()`.
`quantum__rt__heap_alloc()` calls **strings.cpp**'s `quantum__rt__string_create()` - cyclical dependency.

**strings.cpp** Implements `QirString`, `quantum__rt__string_*()`, `quantum__rt__<type>_to_string()` (except `qubit_to_string` and `result_to_string`).
Depends on **utils.cpp**'s `quantum__rt__fail()` - cyclical dependency.


## Level 2

**allocationsTracker.cpp** Implements the internals of `Microsoft::Quantum::AllocationsTracker`.
Depends on `quantum__rt__fail()`, `quantum__rt__string_create()`

**context.cpp** Implements the internals of `Microsoft::Quantum::QirExecutionContext`,
Depends on **allocationsTracker.hpp**'s `Microsoft::Quantum::AllocationsTracker`.
Gets/returns `IRuntimeDriver *`.

## Level 3

**delegated.cpp** Implements `quantum__rt__result_*()`, `quantum__rt__qubit_{allocate,release,to_string}()`.
Each API depends on `Microsoft::Quantum::GlobalContext()[->GetDriver()]`,
`quantum__rt__qubit_to_string()` also depends on strings.cpp's `quantum__rt__string_create()`.
`quantum__rt__result_to_string()` also depends on strings.cpp's `quantum__rt__string_create()`.

**arrays.cpp** Implements {the internals of `QirArray`} and `quantum__rt__*array*`.
Depends on `Microsoft::Quantum::GlobalContext()`, `quantum__rt__fail()`, `quantum__rt__string_create()`,
**delegated.cpp**'s `quantum__rt__qubit_allocate()`

## Level 4

**callables.cpp** Defines the {internals of `QirTupleHeader`, `QirCallable`}, `quantum__rt__tuple_*()`, `quantum__rt__callable_*()`
Depends on `QirArray`, `Microsoft::Quantum::GlobalContext()`, `quantum__rt__fail()`, `quantum__rt__string_create()`, `TupleWithControls`,
Consider breaking up into **Tuples.cpp** and **Callables.cpp**.

## Level 5

**bridge-rt.ll** Defines the `@__quantum__rt__*` entry points (to be called by the `.ll` files generated from users' `.qs` files).
The C++ Standard reserves the identifiers starting with double underscores `__`, that is why the definitions of `@__quantum__rt__*`
have been put to `.ll` file rather than `.cpp` file.
Depends on `quantum__rt__*` implementations (in **utils.cpp**, **strings.cpp**, **delegated.cpp**, **arrays.cpp**, **callables.cpp**).
9 changes: 4 additions & 5 deletions src/Qir/Runtime/lib/QIR/allocationsTracker.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,24 +5,23 @@

#include <unordered_map>

#include "CoreTypes.hpp"

namespace Microsoft
{
namespace Quantum
{
// The tracker keeps a list of pointers to all qir objects that have been allocated during the lifetime of an
// execution context and their reference counts, which allows us to check for double-releases and leaks when the
// actual objects have been released.
struct QIR_SHARED_API AllocationsTracker
struct AllocationsTracker
{
std::unordered_map<void*, int> allocatedObjects;

void OnAllocate(void* object);
void OnAddRef(void* object);
void OnRelease(void* object);

void CheckForLeaks() const;

private:
std::unordered_map<void*, int> allocatedObjects;
};

} // namespace Quantum
Expand Down
21 changes: 10 additions & 11 deletions src/Qir/Runtime/lib/QIR/arrays.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,15 @@
#include "CoreTypes.hpp"
#include "QirContext.hpp"
#include "QirTypes.hpp"
#include "allocationsTracker.hpp"
#include "QirRuntime.hpp"

using namespace Microsoft::Quantum;

int QirArray::AddRef()
{
if (g_context != nullptr && g_context->trackAllocatedObjects)
if (GlobalContext() != nullptr)
{
g_context->allocationsTracker->OnAddRef(this);
GlobalContext()->OnAddRef(this);
}

assert(this->refCount != 0 && "Cannot resurrect released array!");
Expand All @@ -33,9 +32,9 @@ int QirArray::AddRef()
// should delete it, if allocated from the heap.
int QirArray::Release()
{
if (g_context != nullptr && g_context->trackAllocatedObjects)
if (GlobalContext() != nullptr)
{
g_context->allocationsTracker->OnRelease(this);
GlobalContext()->OnRelease(this);
}

assert(this->refCount != 0 && "Cannot release already released array!");
Expand Down Expand Up @@ -69,9 +68,9 @@ QirArray::QirArray(int64_t qubits_count)
}
this->dimensionSizes.push_back(this->count);

if (g_context != nullptr && g_context->trackAllocatedObjects)
if (GlobalContext() != nullptr)
{
g_context->allocationsTracker->OnAllocate(this);
GlobalContext()->OnAllocate(this);
}
}

Expand All @@ -85,9 +84,9 @@ QirArray::QirArray(int64_t count_items, int item_size_bytes, int dimCount, std::
{
assert(dimCount > 0);

if (g_context != nullptr && g_context->trackAllocatedObjects)
if (GlobalContext() != nullptr)
{
g_context->allocationsTracker->OnAllocate(this);
GlobalContext()->OnAllocate(this);
}

if (dimCount == 1)
Expand Down Expand Up @@ -119,9 +118,9 @@ QirArray::QirArray(const QirArray* other)
, ownsQubits(false)
, refCount(1)
{
if (g_context != nullptr && g_context->trackAllocatedObjects)
if (GlobalContext() != nullptr)
{
g_context->allocationsTracker->OnAllocate(this);
GlobalContext()->OnAllocate(this);
}

const int64_t size = this->count * this->itemSizeInBytes;
Expand Down
2 changes: 0 additions & 2 deletions src/Qir/Runtime/lib/QIR/bridge-rt.ll
Original file line number Diff line number Diff line change
Expand Up @@ -233,13 +233,11 @@ define dllexport %Array* @__quantum__rt__array_copy(%Array* %.ar, i1 %force) {

; TODO: This bridge isn't cross-platform!
; it works on Windows but on Linux %args ends up not being a valid pointer.
declare void @DebugLogPtr(i8*)
define dllexport %Array* @__quantum__rt__array_create(i32 %item_size, i32 %dim_count, ...) {
%args1 = alloca i8*, align 8
%args2 = bitcast i8** %args1 to i8*
call void @llvm.va_start(i8* %args2)
%args = load i8*, i8** %args1, align 8
;call void @DebugLogPtr(i8* %args)
%ar = call %"struct.QirArray"* @quantum__rt__array_create_nonvariadic(i32 %item_size, i32 %dim_count, i8* %args)
call void @llvm.va_end(i8* %args2)
%.ar = bitcast %"struct.QirArray"* %ar to %Array*
Expand Down
Loading