qir-alliance / qat

QIR compiler tools and optimization passes for targeting QIR to different hardware backends
https://qir-alliance.github.io/qat/
MIT License
26 stars 14 forks source link

Weak linker pass #127

Closed troelsfr closed 1 year ago

troelsfr commented 1 year ago

This PR introduces a pass that replaces a function with another if that function is present in the IR.

Given two files main.ll and library.ll, qat attempts to replace annotated functions with other functions. For instance, main.ll

; ModuleID = 'qat-link'
source_filename = "qat-link"
%Qubit = type opaque
%String = type opaque
@0 = internal constant [3 x i8] c"()\00"
declare %Qubit* @__quantum__rt__qubit_allocate()
declare void @__quantum__qis__cnot__body(%Qubit*, %Qubit*)
declare void @__quantum__qis__h__body(%Qubit*)
declare %String* @__quantum__rt__string_create(i8*)
declare void @__quantum__rt__message(%String*)
declare void @__quantum__rt__string_update_reference_count(%String*, i32)
declare void @__quantum__rt__qubit_release(%Qubit*)
define internal void @SimpleLoop__Main__body() {
entry:
  call void @SimpleLoop__MiniCircuit__body(%Qubit* null, %Qubit* nonnull inttoptr (i64 1 to %Qubit*))
  call void @SimpleLoop__MiniCircuit__body(%Qubit* null, %Qubit* nonnull inttoptr (i64 1 to %Qubit*))
  ret void
}
define internal void @SimpleLoop__MiniCircuit__body(%Qubit* %q1, %Qubit* %q2) {
entry:
  call void @Microsoft__Quantum__Intrinsic__H__body(%Qubit* %q1)
  call void @Microsoft__Quantum__Intrinsic__H__body(%Qubit* %q2)
  call void @Microsoft__Quantum__Intrinsic__CNOT__body(%Qubit* %q1, %Qubit* %q2)
  ret void
}
define internal void @Microsoft__Quantum__Intrinsic__H__body(%Qubit* %qubit) {
entry:
  call void @__quantum__qis__h__body(%Qubit* %qubit)
  ret void
}
define internal void @Microsoft__Quantum__Intrinsic__CNOT__body(%Qubit* %control, %Qubit* %target) #1 {
entry:
  call void @__quantum__qis__cnot__body(%Qubit* %control, %Qubit* %target)
  ret void
}
define void @SimpleLoop__Main() #0 {
entry:
  call void @SimpleLoop__Main__body()
  ret void
}
attributes #0 = { "EntryPoint" }
attributes #1 = { "replaceWith"="__hello_qubit" }

and library.ll

; ModuleID = 'library'
source_filename = "library"
%Qubit = type opaque
define void @__hello_qubit(%Qubit* %control, %Qubit* %target) {
entry:
  call void @__quantum__qis__h__body(%Qubit* %control)
  call void @__quantum__qis__h__body(%Qubit* %target)
  ret void
}
declare void @__quantum__qis__h__body(%Qubit*)

results in

; ModuleID = 'qat-link'
source_filename = "qat-link"
%Qubit = type opaque
%String = type opaque
@0 = internal constant [3 x i8] c"()\00"
declare %Qubit* @__quantum__rt__qubit_allocate()
declare void @__quantum__qis__cnot__body(%Qubit*, %Qubit*)
declare void @__quantum__qis__h__body(%Qubit*)
declare %String* @__quantum__rt__string_create(i8*)
declare void @__quantum__rt__message(%String*)
declare void @__quantum__rt__string_update_reference_count(%String*, i32)
declare void @__quantum__rt__qubit_release(%Qubit*)
define internal void @SimpleLoop__Main__body() {
entry:
  call void @SimpleLoop__MiniCircuit__body(%Qubit* null, %Qubit* nonnull inttoptr (i64 1 to %Qubit*))
  call void @SimpleLoop__MiniCircuit__body(%Qubit* null, %Qubit* nonnull inttoptr (i64 1 to %Qubit*))
  ret void
}
define internal void @SimpleLoop__MiniCircuit__body(%Qubit* %q1, %Qubit* %q2) {
entry:
  call void @Microsoft__Quantum__Intrinsic__H__body(%Qubit* %q1)
  call void @Microsoft__Quantum__Intrinsic__H__body(%Qubit* %q2)
  call void @__hello_qubit(%Qubit* %q1, %Qubit* %q2)
  ret void
}
define internal void @Microsoft__Quantum__Intrinsic__H__body(%Qubit* %qubit) {
entry:
  call void @__quantum__qis__h__body(%Qubit* %qubit)
  ret void
}
define void @SimpleLoop__Main() #0 {
entry:
  call void @SimpleLoop__Main__body()
  ret void
}
define void @__hello_qubit(%Qubit* %control, %Qubit* %target) {
entry:
  call void @__quantum__qis__h__body(%Qubit* %control)
  call void @__quantum__qis__h__body(%Qubit* %target)
  ret void
}
attributes #0 = { "EntryPoint" }
attributes #1 = { "replaceWith"="__hello_qubit" }