Skip to content

Commit e7cefb0

Browse files
authored
Convert duration units (#163)
This PR adds a pass to convert the units of all operations/types within a QUIR program to a target unit type.
1 parent a9f7b82 commit e7cefb0

File tree

8 files changed

+628
-12
lines changed

8 files changed

+628
-12
lines changed

include/Dialect/QUIR/IR/QUIRAttributes.td

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,24 @@ def QUIR_DurationAttr : QUIR_Attr<"Duration", "duration"> {
5858
"APFloat":$duration);
5959

6060
let extraClassDeclaration = [{
61+
62+
/// Get the scheduling timestep length (in seconds) from the input scheduling rate (in seconds).
63+
static double getDtFromSchedulingRate(const double schedulingRate);
64+
/// Get the scheduling rate (in seconds) from the input scheduling timestep length (in seconds).
65+
static double getSchedulingRateFromDt(const double dt);
66+
67+
/// Convert duration of inputUnits to outputUnits
68+
static double convertUnitsToUnits(double value, TimeUnits inputUnits, TimeUnits outputUnits, const double dt);
69+
70+
/// Convert the duration attribute to an integer number
71+
/// of scheduling samples based on the input scheduling
72+
/// timestep length, dt.
6173
uint64_t getSchedulingCycles(const double dt);
74+
/// Convert this duration attribute's value to the target units.
75+
double convertUnits(const TimeUnits targetUnits, const double dt);
76+
/// Convert this duration attribute to a new duration attribute
77+
/// with the target units.
78+
DurationAttr getConvertedDurationAttr(const TimeUnits targetUnits, const double dt);
6279
}];
6380

6481
let assemblyFormat = "`<` $duration `:` $type `>`";
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
//===- ConvertDurationUnits.h - Convert Duration Unis ----------*- C++ -*-===//
2+
//
3+
// (C) Copyright IBM 2023.
4+
//
5+
// This code is part of Qiskit.
6+
//
7+
// This code is licensed under the Apache License, Version 2.0 with LLVM
8+
// Exceptions. You may obtain a copy of this license in the LICENSE.txt
9+
// file in the root directory of this source tree.
10+
//
11+
// Any modifications or derivative works of this code must retain this
12+
// copyright notice, and modified files need to carry a notice indicating
13+
// that they have been altered from the originals.
14+
//
15+
//===----------------------------------------------------------------------===//
16+
///
17+
/// This file declares the pass for converting the units of Durations
18+
///
19+
//===----------------------------------------------------------------------===//
20+
21+
#ifndef QUIR_CONVERT_DURATION_UNITS_H
22+
#define QUIR_CONVERT_DURATION_UNITS_H
23+
24+
#include "Dialect/QUIR/IR/QUIREnums.h"
25+
26+
#include "mlir/Pass/Pass.h"
27+
28+
#include "llvm/ADT/StringRef.h"
29+
#include "llvm/Support/CommandLine.h"
30+
31+
namespace mlir::quir {
32+
33+
/// @brief This pass will convert all standard usage of durations
34+
/// within QUIR to the input target units. It is useful for canonicalizing
35+
/// durations within a program to uniform base unit such as the target
36+
/// timestep "dt".
37+
struct ConvertDurationUnitsPass
38+
: public PassWrapper<ConvertDurationUnitsPass, OperationPass<>> {
39+
40+
ConvertDurationUnitsPass() = default;
41+
ConvertDurationUnitsPass(const ConvertDurationUnitsPass &pass)
42+
: PassWrapper(pass) {}
43+
ConvertDurationUnitsPass(const TimeUnits inUnits,
44+
const double inDtTimestep = 1.) {
45+
units = inUnits;
46+
dtTimestep = inDtTimestep;
47+
}
48+
49+
Option<TimeUnits> units{
50+
*this,
51+
"units",
52+
llvm::cl::desc("Target units to convert to"),
53+
llvm::cl::values(
54+
clEnumValN(TimeUnits::dt, "dt", "Scheduling sample rate"),
55+
clEnumValN(TimeUnits::s, "s", "seconds"),
56+
clEnumValN(TimeUnits::ms, "ms", "milliseconds"),
57+
clEnumValN(TimeUnits::us, "us", "microseconds"),
58+
clEnumValN(TimeUnits::ns, "ns", "nanoseconds"),
59+
clEnumValN(TimeUnits::ps, "ps", "picoseconds"),
60+
clEnumValN(TimeUnits::fs, "fs", "femtoseconds")),
61+
llvm::cl::value_desc("enum"),
62+
llvm::cl::init(TimeUnits::dt)};
63+
64+
Option<double> dtTimestep{
65+
*this, "dt-timestep",
66+
llvm::cl::desc("Duration of dt (the scheduling timestep) in seconds. "
67+
"Defaults to 1s."),
68+
llvm::cl::value_desc("num"), llvm::cl::init(1.)};
69+
70+
void runOnOperation() override;
71+
72+
virtual TimeUnits getTargetConvertUnits() const;
73+
virtual double getDtTimestep();
74+
llvm::StringRef getArgument() const override;
75+
llvm::StringRef getDescription() const override;
76+
77+
}; // struct ConvertDurationUnitsPass
78+
79+
} // end namespace mlir::quir
80+
81+
#endif // QUIR_CONVERT_DURATION_UNITS_H

include/Dialect/QUIR/Transforms/Passes.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "AddShotLoop.h"
2121
#include "AngleConversion.h"
2222
#include "BreakReset.h"
23+
#include "ConvertDurationUnits.h"
2324
#include "FunctionArgumentSpecialization.h"
2425
#include "LoadElimination.h"
2526
#include "MergeCircuits.h"

lib/Dialect/QUIR/IR/QUIRAttributes.cpp

Lines changed: 84 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -22,34 +22,106 @@
2222
using namespace mlir;
2323
using namespace mlir::quir;
2424

25-
uint64_t mlir::quir::DurationAttr::getSchedulingCycles(const double dt) {
26-
double duration = getDuration().convertToDouble();
25+
//===----------------------------------------------------------------------===//
26+
// DurationAttr
27+
//===----------------------------------------------------------------------===//
2728

28-
auto type = getType().dyn_cast<DurationType>();
29+
namespace {
30+
/// Convert input value (in units of inputUnits) to target units
31+
double convertToSeconds(const double value, const TimeUnits inputUnits,
32+
const double dt = 1.) {
33+
switch (inputUnits) {
34+
case TimeUnits::dt:
35+
return value * dt;
36+
break;
37+
case TimeUnits::fs:
38+
return value / 1.e15;
39+
break;
40+
case TimeUnits::ps:
41+
return value / 1.e12;
42+
break;
43+
case TimeUnits::ns:
44+
return value / 1.e9;
45+
break;
46+
case TimeUnits::us:
47+
return value / 1.e6;
48+
break;
49+
case TimeUnits::ms:
50+
return value / 1.e3;
51+
break;
52+
case TimeUnits::s:
53+
return value;
54+
break;
55+
}
56+
llvm_unreachable("unhandled TimeUnits conversion.");
57+
}
2958

30-
// Convert through int64_t first to handle platform dependence
31-
switch (type.getUnits()) {
59+
/// Convert input value (in units of seconds) to target outputUnits
60+
double convertFromSeconds(const double value, const TimeUnits outputUnits,
61+
const double dt = 1.) {
62+
switch (outputUnits) {
3263
case TimeUnits::dt:
33-
return static_cast<int64_t>(duration);
64+
return value / dt;
3465
break;
3566
case TimeUnits::fs:
36-
return static_cast<int64_t>(duration / (1e15 * dt));
67+
return value * 1.e15;
3768
break;
3869
case TimeUnits::ps:
39-
return static_cast<int64_t>(duration / (1e12 * dt));
70+
return value * 1.e12;
4071
break;
4172
case TimeUnits::ns:
42-
return static_cast<int64_t>(duration / (1e9 * dt));
73+
return value * 1.e9;
4374
break;
4475
case TimeUnits::us:
45-
return static_cast<int64_t>(duration / (1e6 * dt));
76+
return value * 1.e6;
4677
break;
4778
case TimeUnits::ms:
48-
return static_cast<int64_t>(duration / (1e3 * dt));
79+
return value * 1.e3;
4980
break;
5081
case TimeUnits::s:
51-
return static_cast<int64_t>(duration / dt);
82+
return value;
5283
break;
5384
}
5485
llvm_unreachable("unhandled TimeUnits conversion.");
5586
}
87+
88+
} // anonymous namespace
89+
90+
double DurationAttr::getDtFromSchedulingRate(const double schedulingRate) {
91+
return 1. / schedulingRate;
92+
}
93+
94+
double DurationAttr::getSchedulingRateFromDt(const double dt) {
95+
return 1. / dt;
96+
}
97+
98+
double DurationAttr::convertUnitsToUnits(double value, TimeUnits inputUnits,
99+
TimeUnits outputUnits,
100+
const double dt) {
101+
// Check if we can avoid the conversion.
102+
if (inputUnits == outputUnits)
103+
return value;
104+
double seconds = convertToSeconds(value, inputUnits, dt);
105+
return convertFromSeconds(seconds, outputUnits, dt);
106+
}
107+
108+
uint64_t DurationAttr::getSchedulingCycles(const double dt) {
109+
double duration = convertUnits(TimeUnits::dt, dt);
110+
111+
// Convert through int64_t first to handle platform dependence
112+
return static_cast<int64_t>(duration);
113+
}
114+
115+
double DurationAttr::convertUnits(const TimeUnits targetUnits,
116+
const double dt) {
117+
double duration = getDuration().convertToDouble();
118+
return DurationAttr::convertUnitsToUnits(
119+
duration, getType().dyn_cast<DurationType>().getUnits(), targetUnits, dt);
120+
}
121+
122+
DurationAttr DurationAttr::getConvertedDurationAttr(const TimeUnits targetUnits,
123+
const double dt) {
124+
return DurationAttr::get(getContext(),
125+
DurationType::get(getContext(), targetUnits),
126+
llvm::APFloat(convertUnits(targetUnits, dt)));
127+
}

lib/Dialect/QUIR/Transforms/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ add_mlir_dialect_library(MLIRQUIRTransforms
1515
AddShotLoop.cpp
1616
AngleConversion.cpp
1717
BreakReset.cpp
18+
ConvertDurationUnits.cpp
1819
FunctionArgumentSpecialization.cpp
1920
LoadElimination.cpp
2021
MergeCircuits.cpp

0 commit comments

Comments
 (0)