Skip to content
This repository was archived by the owner on Jan 12, 2024. It is now read-only.
Merged
2 changes: 1 addition & 1 deletion bootstrap.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ Push-Location (Join-Path $PSScriptRoot "./src/Simulation/qdk_sim_rs")
--version $Env:NUGET_VERSION;
Pop-Location

if (-not (Test-Path Env:AGENT_OS)) { # If not CI build, i.e. local build (if AGENT_OS envvar is not defined)
if (-not (Test-Path Env:/AGENT_OS)) { # If not CI build, i.e. local build (if AGENT_OS envvar is not defined)
if ($Env:ENABLE_NATIVE -ne "false") {
Write-Host "Build release flavor of the native simulator"
$Env:BUILD_CONFIGURATION = "Release"
Expand Down
8 changes: 7 additions & 1 deletion src/Qir/.clang-tidy
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
Checks:
'-*,bugprone-*,-readability-*,readability-identifier-*,readability-braces-around-statements'
'bugprone-*,readability-identifier-*,readability-braces-around-statements,cert*,\
-llvmlibc-callee-namespace,-llvmlibc-implementation-in-namespace,\
-llvmlibc-restrict-system-libc-headers,-modernize-use-trailing-return-type,\
-fuchsia-default-arguments-calls,-fuchsia-default-arguments-declarations,
-google-readability-casting'
# TODO(rokuzmin): '*, . . .'

WarningsAsErrors: '*'
HeaderFilterRegex: '.*'

Expand Down
1 change: 0 additions & 1 deletion src/Qir/Runtime/lib/QIR/.clang-tidy

This file was deleted.

6 changes: 3 additions & 3 deletions src/Qir/Runtime/lib/QIR/QubitManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -181,8 +181,8 @@ namespace Quantum
sharedQubitStatusArray = new QubitIdType[(size_t)qubitCapacity];

// These objects are passed by value (copies are created)
QubitListInSharedArray FreeQubitsFresh(0, qubitCapacity - 1, sharedQubitStatusArray);
RestrictedReuseArea outermostArea(FreeQubitsFresh);
QubitListInSharedArray freeQubitsFresh(0, qubitCapacity - 1, sharedQubitStatusArray);
RestrictedReuseArea outermostArea(freeQubitsFresh);
freeQubitsInAreas.PushToBack(outermostArea);

freeQubitCount = qubitCapacity;
Expand Down Expand Up @@ -431,7 +431,7 @@ namespace Quantum
// existing values (NonMarker or indexes in the array).

// Prepare new shared status array
QubitIdType* newStatusArray = new QubitIdType[(size_t)requestedCapacity];
auto* newStatusArray = new QubitIdType[(size_t)requestedCapacity];
memcpy(newStatusArray, sharedQubitStatusArray, (size_t)qubitCapacity * sizeof(newStatusArray[0]));
QubitListInSharedArray newFreeQubits(qubitCapacity, requestedCapacity - 1, newStatusArray);

Expand Down
64 changes: 36 additions & 28 deletions src/Qir/Runtime/lib/QIR/arrays.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,8 @@ int QirArray::Release()
return rc;
}

QirArray::QirArray(TItemCount qubits_count)
: count(qubits_count)
QirArray::QirArray(TItemCount qubitsCount)
: count(qubitsCount)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it worthwhile that we use same style for variable names? In the passes code, we use snake case for variables.

Copy link
Contributor Author

@kuzminrobin kuzminrobin Sep 7, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe everybody would benefit from the same coding style in QIR RT and Passes. I personally don't have particular preference. I'm fine with camelBack or snake_case or other.
Added #817.

, itemSizeInBytes((TItemSize)sizeof(void*))
, ownsQubits(true)
, refCount(1)
Expand All @@ -81,25 +81,25 @@ QirArray::QirArray(TItemCount qubits_count)
}
}

QirArray::QirArray(TItemCount count_items, TItemSize item_size_bytes, TDimCount dimCount, TDimContainer&& dimSizes)
: count(count_items)
QirArray::QirArray(TItemCount countItems, TItemSize itemSizeBytes, TDimCount dimCount, TDimContainer&& dimSizes)
: count(countItems)

// Each array item needs to be properly aligned. Let's align them by correcting the `itemSizeInBytes`.
, itemSizeInBytes(
((item_size_bytes == 1) || (item_size_bytes == 2) || (item_size_bytes == 4) ||
((item_size_bytes % sizeof(size_t)) == 0) // For built-in types or multiples of architecture alignment
((itemSizeBytes == 1) || (itemSizeBytes == 2) || (itemSizeBytes == 4) ||
((itemSizeBytes % sizeof(size_t)) == 0) // For built-in types or multiples of architecture alignment
)
? item_size_bytes // leave their natural alignment.
// Other types align on the architecture boundary `sizeof(size_t)`:
// 4 bytes on 32-bit arch, 8 on 64-bit arch.
: item_size_bytes + sizeof(size_t) - (item_size_bytes % sizeof(size_t)))
? itemSizeBytes // leave their natural alignment.
// Other types align on the architecture boundary `sizeof(size_t)`:
// 4 bytes on 32-bit arch, 8 on 64-bit arch.
: itemSizeBytes + sizeof(size_t) - (itemSizeBytes % sizeof(size_t)))

, dimensions(dimCount)
, dimensionSizes(std::move(dimSizes))
, ownsQubits(false)
, refCount(1)
{
assert(item_size_bytes != 0);
assert(itemSizeBytes != 0);
assert(dimCount > 0);

if (GlobalContext() != nullptr)
Expand All @@ -112,18 +112,18 @@ QirArray::QirArray(TItemCount count_items, TItemSize item_size_bytes, TDimCount
assert(this->dimensionSizes.empty() || this->dimensionSizes[0] == this->count);
if (this->dimensionSizes.empty())
{
this->dimensionSizes.push_back(count_items);
this->dimensionSizes.push_back(countItems);
}
}

assert(this->count * (TBufSize)itemSizeInBytes < std::numeric_limits<TBufSize>::max());
// Using `<` rather than `<=` to calm down the compiler on 32-bit arch.
const TBufSize buffer_size = this->count * itemSizeInBytes;
if (buffer_size > 0)
const TBufSize bufferSize = this->count * itemSizeInBytes;
if (bufferSize > 0)
{
this->buffer = new char[buffer_size];
assert(buffer_size <= std::numeric_limits<size_t>::max());
memset(this->buffer, 0, (size_t)buffer_size);
this->buffer = new char[bufferSize];
assert(bufferSize <= std::numeric_limits<size_t>::max());
memset(this->buffer, 0, (size_t)bufferSize);
}
else
{
Expand Down Expand Up @@ -178,26 +178,26 @@ void QirArray::Append(const QirArray* other)

assert((TBufSize)(other->count) * other->itemSizeInBytes < std::numeric_limits<TBufSize>::max());
// Using `<` rather than `<=` to calm down the compiler on 32-bit arch.
const TBufSize other_size = other->count * other->itemSizeInBytes;
const TBufSize otherSize = other->count * other->itemSizeInBytes;

if (other_size == 0)
if (otherSize == 0)
{
return;
}

assert((TBufSize)(this->count) * this->itemSizeInBytes < std::numeric_limits<TBufSize>::max());
// Using `<` rather than `<=` to calm down the compiler on 32-bit arch.
const TBufSize this_size = this->count * this->itemSizeInBytes;
const TBufSize thisSize = this->count * this->itemSizeInBytes;

char* new_buffer = new char[this_size + other_size];
if (this_size)
char* newBuffer = new char[thisSize + otherSize];
if (thisSize)
{
memcpy(new_buffer, this->buffer, this_size);
memcpy(newBuffer, this->buffer, thisSize);
}
memcpy(&new_buffer[this_size], other->buffer, other_size);
memcpy(&newBuffer[thisSize], other->buffer, otherSize);

delete[] this->buffer;
this->buffer = new_buffer;
this->buffer = newBuffer;
this->count += other->count;
this->dimensionSizes[0] = this->count;
}
Expand Down Expand Up @@ -279,11 +279,10 @@ extern "C"
__quantum__rt__qubit_release_array(qa);
}

// TODO: Use `QirArray::TItemSize itemSizeInBytes, QirArray::TItemCount count_items` (breaking change):
QirArray* __quantum__rt__array_create_1d(int32_t itemSizeInBytes, int64_t count_items)
QirArray* __quantum__rt__array_create_1d(int32_t itemSizeInBytes, int64_t countItems)
{
assert(itemSizeInBytes > 0);
return new QirArray((QirArray::TItemCount)count_items, (QirArray::TItemSize)itemSizeInBytes);
return new QirArray((QirArray::TItemCount)countItems, (QirArray::TItemSize)itemSizeInBytes);
}

// Bucketing of addref/release is non-standard so for now we'll keep the more traditional addref/release semantics
Expand Down Expand Up @@ -560,6 +559,10 @@ extern "C"
const QirArray::TItemCount sliceItemsCount = std::accumulate(
sliceDims.begin(), sliceDims.end(), (QirArray::TItemCount)1, std::multiplies<QirArray::TItemCount>());
QirArray* slice = new QirArray(sliceItemsCount, itemSizeInBytes, dimensions, std::move(sliceDims));
if (nullptr == slice->buffer)
{
return slice;
}
const QirArray::TItemCount singleIndexRunCount = RunCount(array->dimensionSizes, (QirArray::TDimCount)dim);
const QirArray::TItemCount rowCount = singleIndexRunCount * array->dimensionSizes[(size_t)dim];

Expand Down Expand Up @@ -636,13 +639,18 @@ extern "C"
const QirArray::TItemCount projectItemsCount = std::accumulate(
projectDims.begin(), projectDims.end(), (QirArray::TItemCount)1, std::multiplies<QirArray::TItemCount>());
QirArray* project = new QirArray(projectItemsCount, itemSizeInBytes, dimensions - 1, std::move(projectDims));
if (nullptr == project->buffer)
{
return project;
}

const QirArray::TItemCount singleIndexRunCount = RunCount(array->dimensionSizes, (QirArray::TDimCount)dim);
const QirArray::TItemCount rowCount = singleIndexRunCount * array->dimensionSizes[(size_t)dim];

assert((QirArray::TBufSize)singleIndexRunCount * itemSizeInBytes <
std::numeric_limits<QirArray::TBufSize>::max());
// Using `<` rather than `<=` to calm down the compiler on 32-bit arch.

const QirArray::TBufSize chunkSize = singleIndexRunCount * itemSizeInBytes;

QirArray::TItemCount dst = 0;
Expand Down
6 changes: 5 additions & 1 deletion src/Qir/Runtime/lib/QIR/callables.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,11 @@ extern "C"
{
for (int i = increment; i < 0; i++)
{
(void)callable->Release();
if (0 == callable->Release())
{
assert(-1 == i && "Attempting to decrement reference count below zero!");
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: I'm not sure I like this pattern, though honestly there isn't anything functionally wrong here. It just seems odd that this assert message would show up only if the reference count was updated with a decrement value less than -1, where if the decrement is exactly -1 (our compiler's QIR default) on an item of 0 references then the assert from within Release will fire instead. That assert already protected us from decrementing below zero, so this new one is arguably extraneous, though not harmful.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm totally with you on our scenario.

But looks like the static analyzer has considered a different scenario and complained for a possible released (dangling) pointer dereference. I'll try to tell what I remember.

Let's consider a callable with callable->refCount equal 1. And someone calls __quantum__rt__callable_update_reference_count() with increment parameter -2. During the first most iteration of this for loop (i == -2) the callable->Release() is invoked. It decrements the callable->refCount to 0, deallocates the callable, and returns 0. After the first call to callable->Release() the callable becomes a dangling pointer.

Before this change, the value 0 returned by callable->Release() was not analyzed, and another iteration of the loop was starting. At the moment of the second call callable->Release() a dangling pointer was accessed which immediately resulted in the undefined behavior (UB), before the execution reached an assert inside of QirCallable::Release().

I agreed with the complaint from the static analyzer and tried to prevent the UB with an assert (in green line 107). I don't state that my change is the best fix (e.g. the break in the green line 108 can be redundant ;-) ), feel free to propose a better fix.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, that's a great point! I had incorrectly assumed Release would clean up internal structures but not invalidate the callable pointer itself, but looking at the implementation that is not the case. Score one for the analyzer ;)

break;
}
}
}
}
Expand Down
6 changes: 3 additions & 3 deletions src/Qir/Runtime/lib/QIR/strings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ static QirString* CreateOrReuseAlreadyAllocated(std::string&& str)
if (alreadyAllocated != AllocatedStrings().end())
{
qstr = alreadyAllocated->second;
assert(qstr->str.compare(str) == 0);
assert(qstr->str == str);
qstr->refCount++;
}
else
Expand Down Expand Up @@ -95,7 +95,7 @@ extern "C"
// Returns true if the two strings are equal, false otherwise.
bool __quantum__rt__string_equal(QirString* left, QirString* right) // NOLINT
{
assert((left == right) == (left->str.compare(right->str) == 0));
assert((left == right) == (left->str == right->str));
return left == right;
}

Expand All @@ -115,7 +115,7 @@ extern "C"

// Remove padding zeros from the decimal part (relies on the fact that the output for integers always contains
// period).
std::size_t pos1 = str.find_last_not_of("0");
std::size_t pos1 = str.find_last_not_of('0');
if (pos1 != std::string::npos)
{
str.erase(pos1 + 1);
Expand Down
1 change: 0 additions & 1 deletion src/Qir/Runtime/lib/QSharpCore/.clang-tidy

This file was deleted.

6 changes: 3 additions & 3 deletions src/Qir/Runtime/prerequisites.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
#Requires -Version 6.0

if ($Env:ENABLE_QIRRUNTIME -ne "false") {
if (($IsWindows) -or ((Test-Path Env:AGENT_OS) -and ($Env:AGENT_OS.StartsWith("Win")))) {
if (($IsWindows) -or ((Test-Path Env:/AGENT_OS) -and ($Env:AGENT_OS.StartsWith("Win")))) {
if (!(Get-Command clang -ErrorAction SilentlyContinue) -or `
!(Get-Command clang-format -ErrorAction SilentlyContinue)) {
choco install llvm --version=11.1.0
Expand All @@ -29,10 +29,10 @@ if ($Env:ENABLE_QIRRUNTIME -ne "false") {
} else {
if (Get-Command sudo -ErrorAction SilentlyContinue) {
sudo apt update
sudo apt-get install -y ninja-build clang-11 clang-tidy-11
sudo apt-get install -y ninja-build clang-11 clang-tidy-11 clang-format-11
} else {
apt update
apt-get install -y ninja-build clang-11 clang-tidy-11
apt-get install -y ninja-build clang-11 clang-tidy-11 clang-format-11
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/Qir/Runtime/public/CoreTypes.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ class QUBIT;
typedef QUBIT* Qubit; // Not a pointer to a memory location, just an integer - qubit id.

class RESULT;
typedef RESULT* Result; // TODO: Replace with `typedef uintXX_t Result`, where XX is 8|16|32|64.
typedef RESULT* Result; // TODO(rokuzmin): Replace with `typedef uintXX_t Result`, where XX is 8|16|32|64.
// Remove all the `RESULT`.

enum ResultValue
Expand Down
8 changes: 7 additions & 1 deletion src/Qir/Runtime/public/OutputStream.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,15 @@ namespace Quantum
{
struct QIR_SHARED_API ScopedRedirector
{
ScopedRedirector(std::ostream& newOstream);
explicit ScopedRedirector(std::ostream& newOstream);
~ScopedRedirector();

private:
ScopedRedirector(const ScopedRedirector&) = delete;
ScopedRedirector& operator=(const ScopedRedirector&) = delete;
ScopedRedirector(ScopedRedirector&&) = delete;
ScopedRedirector& operator=(ScopedRedirector&&) = delete;

private:
std::ostream& old;
};
Expand Down
4 changes: 2 additions & 2 deletions src/Qir/Runtime/public/QirRuntime.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
#pragma once

#include <cstdint>
#include <stdarg.h> // for va_list
#include <cstdarg> // for va_list

#include "CoreTypes.hpp"
#include "QirTypes.hpp"
Expand Down Expand Up @@ -310,7 +310,7 @@ extern "C"
// TODO QIR_SHARED_API bool __quantum__rt__bigint_greater_eq(QirBigInt*, QirBigInt*); // NOLINT
}

// TODO: Consider separating the `extern "C"` exports and C++ exports.
// TODO(rokuzmin): Consider separating the `extern "C"` exports and C++ exports.
namespace Microsoft // Replace with `namespace Microsoft::Quantum` after migration to C++17.
{
namespace Quantum
Expand Down
22 changes: 11 additions & 11 deletions src/Qir/Runtime/public/QirTypes.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,13 @@ struct QIR_SHARED_API QirArray
int AddRef();
int Release();

QirArray(TItemCount cQubits);
explicit QirArray(TItemCount cQubits);
QirArray(TItemCount cItems, TItemSize itemSizeInBytes, TDimCount dimCount = 1, TDimContainer&& dimSizes = {});
QirArray(const QirArray& other);

~QirArray();

char* GetItemPointer(TItemCount index) const;
[[nodiscard]] char* GetItemPointer(TItemCount index) const;
void Append(const QirArray* other);
};

Expand All @@ -61,8 +61,8 @@ struct QIR_SHARED_API QirString
long refCount = 1;
std::string str;

QirString(std::string&& str);
QirString(const char* cstr);
explicit QirString(std::string&& str);
explicit QirString(const char* cstr);
};

/*======================================================================================================================
Expand All @@ -72,10 +72,10 @@ struct QIR_SHARED_API QirString
a header that contains the relevant data. The header immediately precedes the tuple's buffer in memory when the
tuple is created.
======================================================================================================================*/
// TODO: Move these types to inside of `QirTupleHeader`.
// TODO (rokuzmin): Move these types to inside of `QirTupleHeader`.
using PTuplePointedType = uint8_t;
using PTuple = PTuplePointedType*; // TODO: consider replacing `uint8_t*` with `void*` in order to block the accidental
// {dereferencing and pointer arithmtic}.
using PTuple = PTuplePointedType*; // TODO(rokuzmin): consider replacing `uint8_t*` with `void*` in order to block
// the accidental {dereferencing and pointer arithmetic}.
// Much pointer arithmetic in tests. GetHeader() uses the pointer arithmetic.
struct QIR_SHARED_API QirTupleHeader
{
Expand All @@ -90,7 +90,7 @@ struct QIR_SHARED_API QirTupleHeader

PTuple AsTuple()
{
return data;
return (PTuple)data;
}

int AddRef();
Expand Down Expand Up @@ -139,12 +139,12 @@ static_assert(sizeof(TupleWithControls) == 2 * sizeof(void*),
/*======================================================================================================================
QirCallable
======================================================================================================================*/
typedef void (*t_CallableEntry)(PTuple, PTuple, PTuple); // TODO: Move to `QirCallable::t_CallableEntry`.
typedef void (*t_CaptureCallback)(PTuple, int32_t); // TODO: Move to `QirCallable::t_CaptureCallback`.
typedef void (*t_CallableEntry)(PTuple, PTuple, PTuple); // TODO(rokuzmin): Move to `QirCallable::t_CallableEntry`.
typedef void (*t_CaptureCallback)(PTuple, int32_t); // TODO(rokuzmin): Move to `QirCallable::t_CaptureCallback`.
struct QIR_SHARED_API QirCallable
{
static int constexpr Adjoint = 1;
static int constexpr Controlled = 1 << 1;
static int constexpr Controlled = 1u << 1;

private:
static int constexpr TableSize = 4;
Expand Down
Loading