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
1 change: 1 addition & 0 deletions src/QirRuntime/lib/QIR/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ add_dependencies(qir-rt ${bridge_rt_target})
#
set(qis_sup_source_files
"intrinsics.cpp"
"intrinsicsMath.cpp"
)

add_library(qir-qis-support ${qis_sup_source_files})
Expand Down
103 changes: 79 additions & 24 deletions src/QirRuntime/lib/QIR/bridge-qis.ll
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
%Range = type { i64, i64, i64 }
%Result = type opaque
%String = type opaque
%Pauli = type {i2}
%Pauli = type i2

;=======================================================================================================================
; Native types
Expand All @@ -29,9 +29,7 @@
%struct.QirCallable = type opaque
%struct.QirRange = type { i64, i64, i64 }
%struct.QirString = type opaque

; Assumptions:
; %PauliId = type {i32}
%PauliId = type i32

;===============================================================================
; declarations of the native methods this bridge delegates to
Expand Down Expand Up @@ -139,53 +137,53 @@ define %Result* @__quantum__qis__measure__body(%Array* %.paulis, %Array* %.qubit
ret %Result* %.r
}

define void @__quantum__qis__r__body(i2 %.pauli, double %theta, %Qubit* %.q) {
define void @__quantum__qis__r__body(%Pauli %.pauli, double %theta, %Qubit* %.q) {
%q = bitcast %Qubit* %.q to %class.QUBIT*
%pauli = zext i2 %.pauli to i32
call void @quantum__qis__r__body(i32 %pauli, double %theta, %class.QUBIT* %q)
%pauli = zext %Pauli %.pauli to %PauliId
call void @quantum__qis__r__body(%PauliId %pauli, double %theta, %class.QUBIT* %q)
ret void
}

define void @__quantum__qis__r__adj(i2 %.pauli, double %theta, %Qubit* %.q) {
define void @__quantum__qis__r__adj(%Pauli %.pauli, double %theta, %Qubit* %.q) {
%q = bitcast %Qubit* %.q to %class.QUBIT*
%pauli = zext i2 %.pauli to i32
call void @quantum__qis__r__adj(i32 %pauli, double %theta, %class.QUBIT* %q)
%pauli = zext %Pauli %.pauli to %PauliId
call void @quantum__qis__r__adj(%PauliId %pauli, double %theta, %class.QUBIT* %q)
ret void
}

define void @__quantum__qis__r__ctl(%Array* %.ctls, {i2, double, %Qubit*}* %.args) {
define void @__quantum__qis__r__ctl(%Array* %.ctls, {%Pauli, double, %Qubit*}* %.args) {
%ctls = bitcast %Array* %.ctls to %struct.QirArray*

%.ppauli = getelementptr inbounds {i2, double, %Qubit*}, {i2, double, %Qubit*}* %.args, i32 0, i32 0
%.pauli = load i2, i2* %.ppauli
%pauli = zext i2 %.pauli to i32
%.ppauli = getelementptr inbounds {%Pauli, double, %Qubit*}, {%Pauli, double, %Qubit*}* %.args, i32 0, i32 0
%.pauli = load %Pauli, %Pauli* %.ppauli
%pauli = zext %Pauli %.pauli to %PauliId

%.ptheta = getelementptr inbounds {i2, double, %Qubit*}, {i2, double, %Qubit*}* %.args, i32 0, i32 1
%.ptheta = getelementptr inbounds {%Pauli, double, %Qubit*}, {%Pauli, double, %Qubit*}* %.args, i32 0, i32 1
%theta = load double, double* %.ptheta

%.pq = getelementptr inbounds {i2, double, %Qubit*}, {i2, double, %Qubit*}* %.args, i32 0, i32 2
%.pq = getelementptr inbounds {%Pauli, double, %Qubit*}, {%Pauli, double, %Qubit*}* %.args, i32 0, i32 2
%.q = load %Qubit*, %Qubit** %.pq
%q = bitcast %Qubit* %.q to %class.QUBIT*

call void @quantum__qis__r__ctl(%struct.QirArray* %ctls, i32 %pauli, double %theta, %class.QUBIT* %q)
call void @quantum__qis__r__ctl(%struct.QirArray* %ctls, %PauliId %pauli, double %theta, %class.QUBIT* %q)
ret void
}

define void @__quantum__qis__r__ctladj(%Array* %.ctls, {i2, double, %Qubit*}* %.args) {
define void @__quantum__qis__r__ctladj(%Array* %.ctls, {%Pauli, double, %Qubit*}* %.args) {
%ctls = bitcast %Array* %.ctls to %struct.QirArray*

%.ppauli = getelementptr inbounds {i2, double, %Qubit*}, {i2, double, %Qubit*}* %.args, i32 0, i32 0
%.pauli = load i2, i2* %.ppauli
%pauli = zext i2 %.pauli to i32
%.ppauli = getelementptr inbounds {%Pauli, double, %Qubit*}, {%Pauli, double, %Qubit*}* %.args, i32 0, i32 0
%.pauli = load %Pauli, %Pauli* %.ppauli
%pauli = zext %Pauli %.pauli to %PauliId

%.ptheta = getelementptr inbounds {i2, double, %Qubit*}, {i2, double, %Qubit*}* %.args, i32 0, i32 1
%.ptheta = getelementptr inbounds {%Pauli, double, %Qubit*}, {%Pauli, double, %Qubit*}* %.args, i32 0, i32 1
%theta = load double, double* %.ptheta

%.pq = getelementptr inbounds {i2, double, %Qubit*}, {i2, double, %Qubit*}* %.args, i32 0, i32 2
%.pq = getelementptr inbounds {%Pauli, double, %Qubit*}, {%Pauli, double, %Qubit*}* %.args, i32 0, i32 2
%.q = load %Qubit*, %Qubit** %.pq
%q = bitcast %Qubit* %.q to %class.QUBIT*

call void @quantum__qis__r__ctladj(%struct.QirArray* %ctls, i32 %pauli, double %theta, %class.QUBIT* %q)
call void @quantum__qis__r__ctladj(%struct.QirArray* %ctls, %PauliId %pauli, double %theta, %class.QUBIT* %q)
ret void
}

Expand Down Expand Up @@ -281,3 +279,60 @@ define void @__quantum__qis__z__ctl(%Array* %.ctls, %Qubit* %.q) {
}


;===============================================================================
; quantum.qis math functions
;

; LLVM intrinsics (https://llvm.org/docs/LangRef.html):
declare double @llvm.sqrt.f64(double %.val)
declare double @llvm.log.f64(double %Val)

; Native implementations:
declare i1 @quantum__qis__isnan__body(double %d)
declare double @quantum__qis__infinity__body()
declare i1 @quantum__qis__isinf__body(double %d)
declare double @quantum__qis__arctan2__body(double %y, double %x)

; API for the user code:
define double @__quantum__qis__nan__body() { ; Q#: function NAN() : Double http://www.cplusplus.com/reference/cmath/nan-function/
%result = call double @llvm.sqrt.f64(double -1.0) ; sqrt(<negative>) -> NaN
ret double %result
}

define i1 @__quantum__qis__isnan__body(double %d) { ; http://www.cplusplus.com/reference/cmath/isnan/
%result = call i1 @quantum__qis__isnan__body(double %d)
ret i1 %result
}

define double @__quantum__qis__infinity__body() { ; https://en.cppreference.com/w/c/numeric/math/INFINITY
%result = call double @quantum__qis__infinity__body()
ret double %result
}

define i1 @__quantum__qis__isinf__body(double %d) { ; https://en.cppreference.com/w/cpp/numeric/math/isinf
%result = call i1 @quantum__qis__isinf__body(double %d)
ret i1 %result
}

define double @__quantum__qis__sqrt__body(double %d) { ; https://en.cppreference.com/w/cpp/numeric/math/sqrt
%result = call double @llvm.sqrt.f64(double %d)
ret double %result
}

define double @__quantum__qis__log__body(double %d) { ; https://en.cppreference.com/w/cpp/numeric/math/log
%result = call double @llvm.log.f64(double %d)
ret double %result
}

define i1 @__quantum__qis__isnegativeinfinity__body(double %d) { ; Q#: function IsNegativeInfinity(d : Double) : Bool
; https://en.cppreference.com/w/cpp/numeric/math/log https://llvm.org/docs/LangRef.html#llvm-log-intrinsic
%negInf = call double @llvm.log.f64(double 0.0) ; ln(0) -> (-infinity)
%result = fcmp oeq double %negInf, %d ; %result = (%negInf == %d)
ret i1 %result
}

define double @__quantum__qis__arctan2__body(double %y, double %x) { ; Q#: function ArcTan2 (y : Double, x : Double) : Double
; https://en.cppreference.com/w/cpp/numeric/math/atan2
%result = call double @quantum__qis__arctan2__body(double %y, double %x)
ret double %result
}
16 changes: 11 additions & 5 deletions src/QirRuntime/lib/QIR/bridge-rt.ll
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
%Result = type opaque
%String = type opaque
%Tuple = type opaque
%Pauli = type {i2}
%Pauli = type i2

;=======================================================================================================================
; Native types
Expand All @@ -27,6 +27,7 @@
%"struct.QirCallable" = type opaque
%"struct.QirRange" = type { i64, i64, i64 }
%"struct.QirString" = type opaque
%PauliId = type i32
; %Tuple* is mapped to i8*

;=======================================================================================================================
Expand Down Expand Up @@ -97,7 +98,7 @@ declare %"struct.QirString"* @quantum__rt__int_to_string(i64)
declare %"struct.QirString"* @quantum__rt__double_to_string(double)
declare %"struct.QirString"* @quantum__rt__bool_to_string(i1)
declare %"struct.QirString"* @quantum__rt__result_to_string(%class.RESULT*)
declare %"struct.QirString"* @quantum__rt__pauli_to_string(i32)
declare %"struct.QirString"* @quantum__rt__pauli_to_string(%PauliId)
declare %"struct.QirString"* @quantum__rt__qubit_to_string(%class.QUBIT*)
declare %"struct.QirString"* @quantum__rt__range_to_string(%"struct.QirRange"* dereferenceable(24) %range)

Expand Down Expand Up @@ -378,10 +379,9 @@ define void @__quantum__rt__callable_memory_management(i32 %index, %Callable* %.
; strings bridge
;
; NYI:
;define %String* @__quantum__rt__pauli_to_string(%Pauli) ; need to check that the type is lowered correctly
;define %String* @__quantum__rt__bigint_to_string(%BigInt*)

define %String* @__quantum__rt__string_create(i8* %null_terminated_buffer) {
define %String* @__quantum__rt__string_create(i32 %ignoredStrLength, i8* %null_terminated_buffer) {
%str = call %"struct.QirString"* @quantum__rt__string_create(i8* %null_terminated_buffer)
%.str = bitcast %"struct.QirString"* %str to %String*
ret %String* %.str
Expand Down Expand Up @@ -435,6 +435,13 @@ define %String* @__quantum__rt__result_to_string(%Result* %.r) {
ret %String* %.str
}

define %String* @__quantum__rt__pauli_to_string(%Pauli %.pauli) {
%pauli = zext %Pauli %.pauli to %PauliId
%str = call %"struct.QirString"* @quantum__rt__pauli_to_string(%PauliId %pauli)
%.str = bitcast %"struct.QirString"* %str to %String*
ret %String* %.str
}

define %String* @__quantum__rt__qubit_to_string(%Qubit* %.q) {
%q = bitcast %Qubit* %.q to %"class.QUBIT"*
%str = call %"struct.QirString"* @quantum__rt__qubit_to_string(%"class.QUBIT"* %q)
Expand All @@ -451,7 +458,6 @@ define %String* @__quantum__rt__range_to_string(%Range %.range) {
ret %String* %.str
}


;------------------------------------------------------------------------------
; bigints bridge
;
Expand Down
31 changes: 31 additions & 0 deletions src/QirRuntime/lib/QIR/intrinsicsMath.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

#include <cmath>
#include "quantum__qis.hpp"

extern "C"
{

// Implementations:
bool quantum__qis__isnan__body(double d)
{
return std::isnan(d); // https://en.cppreference.com/w/cpp/numeric/math/isnan
}

double quantum__qis__infinity__body()
{
return INFINITY; // https://en.cppreference.com/w/c/numeric/math/INFINITY
}

bool quantum__qis__isinf__body(double d)
{
return std::isinf(d); // https://en.cppreference.com/w/cpp/numeric/math/isinf
}

double quantum__qis__arctan2__body(double y, double x)
{
return std::atan2(y, x); // https://en.cppreference.com/w/cpp/numeric/math/atan2
}

} // extern "C"
6 changes: 6 additions & 0 deletions src/QirRuntime/lib/QIR/quantum__qis.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,4 +59,10 @@ extern "C"
QIR_SHARED_API void quantum__qis__y__ctl(QirArray*, QUBIT*); // NOLINT
QIR_SHARED_API void quantum__qis__z__body(QUBIT*); // NOLINT
QIR_SHARED_API void quantum__qis__z__ctl(QirArray*, QUBIT*); // NOLINT

QIR_SHARED_API bool quantum__qis__isnan__body(double d); // NOLINT
QIR_SHARED_API double quantum__qis__infinity__body(); // NOLINT
QIR_SHARED_API bool quantum__qis__isinf__body(double d); // NOLINT
QIR_SHARED_API double quantum__qis__arctan2__body(double y, double x); // NOLINT

}
3 changes: 3 additions & 0 deletions src/QirRuntime/lib/QIR/strings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,10 @@ extern "C"
return quantum__rt__string_create("PauliY");
case PauliId_Z:
return quantum__rt__string_create("PauliZ");
default:
break;
}
return quantum__rt__string_create("<Unexpected Pauli Value>");
}

// Returns a string representation of the range.
Expand Down
4 changes: 3 additions & 1 deletion src/QirRuntime/public/CoreTypes.hpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#pragma once

#include <cstdint>

// The core types will be exposed in the C-interfaces for interop, thus no
// namespaces or scoped enums can be used to define them.

Expand Down Expand Up @@ -27,7 +29,7 @@ enum ResultValue
/*==============================================================================
PauliId matrices
==============================================================================*/
enum PauliId
enum PauliId : int32_t
{
PauliId_I = 0,
PauliId_X = 1,
Expand Down
5 changes: 4 additions & 1 deletion src/QirRuntime/test/QIR-static/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,10 @@ add_custom_target(qir_static_test_lib DEPENDS ${QIR_TESTS_LIBS})
# The executable target for QIR tests triggers the custom actions to compile ll files
#
add_executable(qir-static-tests
qir-driver.cpp)
qir-driver.cpp
qir-test-math.cpp
qir-test-strings.cpp
)

target_link_libraries(qir-static-tests PUBLIC
${QIR_TESTS_LIBS}
Expand Down
37 changes: 37 additions & 0 deletions src/QirRuntime/test/QIR-static/compiler/Constants.qs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

// these are all the static methods and const fields form System.Math class of .NET CLR
// that are not exposed as language operators and are relevant within type System.
// If there are two versions of the function for Int and Double types, the corresponding
// functions have suffix I or D. ExpD also has a suffix to avoid name clash with Primitives.Exp.

namespace Microsoft.Quantum.Math {

/// # Summary
/// Returns the natural logarithmic base to double-precision.
///
/// # Output
/// A double-precision approximation of the natural logarithic base,
/// $e \approx 2.7182818284590452354$.
///
/// # See Also
/// - Microsoft.Quantum.Math.PI
function E() : Double {
return 2.7182818284590452354;
}

/// # Summary
/// Represents the ratio of the circumference of a circle to its diameter.
///
/// # Ouptut
/// A double-precision approximation of the the circumference of a circle
/// to its diameter, $\pi \approx 3.14159265358979323846$.
///
/// # See Also
/// - Microsoft.Quantum.Math.E
function PI() : Double {
return 3.14159265358979323846;
}

}
41 changes: 41 additions & 0 deletions src/QirRuntime/test/QIR-static/compiler/QirTarget.qs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,47 @@ namespace Microsoft.Quantum.Intrinsic {

open Microsoft.Quantum.Targeting;

@Inline()
function NAN() : Double {
body intrinsic;
}

@Inline()
function IsNan(d: Double) : Bool {
body intrinsic;
}

@Inline()
function INFINITY() : Double {
body intrinsic;
}

@Inline()
function IsInf(d: Double) : Bool {
body intrinsic;
}

@Inline()
function IsNegativeInfinity(d : Double) : Bool {
body intrinsic;
}

@Inline()
function Sqrt(d : Double) : Double {
body intrinsic;
}

@Inline()
function Log(d : Double) : Double {
body intrinsic;
}

@Inline()
function ArcTan2(y : Double, x : Double) : Double {
body intrinsic;
}


operation X(qb : Qubit) : Unit
is Adj + Ctl {
body intrinsic;
Expand Down
Loading