Handle basic character literals in xasm TokenCollector
Currently, if you write a char literal like '1' in a kernel, the single quotes get removed. This can cause confusing behavior if the programmer types something like if (my_string[0] == '1')
, which becomes if (my_string[0] == 1)
(likely always evaluating to false).
So add support for basic C++ character literals to the xasm TokenCollector grammar. This does not handle all cases of char
literals, such as wide character literals or character literals containing string escapes like \n
, but at least now the most common cases work.
I had to regenerate the antlr-generated code with ./generate.sh
, so I tried to use the same antlr version (4.9.2). If I regenerate without my change to the grammar, I get the same result, if that's reassuring about me possibly breaking everything.
Testing
I ran ctest
and everything passed. I also added a test for this to XASMTokenCollectorTester
which verifies that '1'
survives the xasm TokenCollector. It fails with the existing code and passes after this change. Here is the little program which failed before (the if statement marked with an arrow below never gets taken because secret_bits[...] == 1
is never true) but works with this change:
__qpu__ void bernstein_vazirani(qreg q, std::string &secret_bits) {
// prepare ancilla in |1>
X(q[secret_bits.size()]);
// input superpositions
for (int i = 0; i <= secret_bits.size(); i++) {
H(q[i]);
}
// oracle
for (int i = 0; i < secret_bits.size(); i++) {
if (secret_bits[i] == '1') { // <===================
CX(q[i], q[secret_bits.size()]);
}
}
for (int i = 0; i <= secret_bits.size(); i++) {
H(q[i]);
if (i < secret_bits.size())
Measure(q[i]);
}
}
int main(int argc, char **argv) {
if (argc-1 != 1) {
std::cerr << "usage: " << argv[0] << " <bits>\n";
return 1;
}
std::string secret_bits(argv[1]);
auto q = qalloc(secret_bits.size() + 1);
bernstein_vazirani(q, secret_bits);
q.print();
}
Before the change, -print-csp-source
prints:
class bernstein_vazirani : public qcor::QuantumKernel<class bernstein_vazirani, qreg, std::string &> {
friend class qcor::QuantumKernel<class bernstein_vazirani, qreg, std::string &>;
friend class qcor::KernelSignature<qreg, std::string &>;
protected:
void operator()(qreg q, std::string & secret_bits) {
if (!parent_kernel) {
parent_kernel = qcor::__internal__::create_composite(kernel_name);
}
quantum::set_current_program(parent_kernel);
if (runtime_env == QrtType::FTQC) {
quantum::set_current_buffer(q.results());
}
init_kernel_signature_args(parent_kernel, q, secret_bits);
quantum::x(q[secret_bits.size()]);
for ( int i = 0 ; i <= secret_bits.size() ; i ++ ) {
quantum::h(q[i]);
}
for ( int i = 0 ; i < secret_bits.size() ; i ++ ) {
if ( secret_bits[i] == 1 ) { <======================
quantum::cnot(q[i], q[secret_bits.size()]);
}
}
for ( int i = 0 ; i <= secret_bits.size() ; i ++ ) {
quantum::h(q[i]);
if ( i < secret_bits . size ( ) )
quantum::mz(q[i]);
}
}
After the change,
class bernstein_vazirani : public qcor::QuantumKernel<class bernstein_vazirani, qreg, std::string &> {
friend class qcor::QuantumKernel<class bernstein_vazirani, qreg, std::string &>;
friend class qcor::KernelSignature<qreg, std::string &>;
protected:
void operator()(qreg q, std::string & secret_bits) {
if (!parent_kernel) {
parent_kernel = qcor::__internal__::create_composite(kernel_name);
}
quantum::set_current_program(parent_kernel);
if (runtime_env == QrtType::FTQC) {
quantum::set_current_buffer(q.results());
}
init_kernel_signature_args(parent_kernel, q, secret_bits);
quantum::x(q[secret_bits.size()]);
for ( int i = 0 ; i <= secret_bits.size() ; i ++ ) {
quantum::h(q[i]);
}
for ( int i = 0 ; i < secret_bits.size() ; i ++ ) {
if ( secret_bits[i] == '1' ) { <====================
quantum::cnot(q[i], q[secret_bits.size()]);
}
}
for ( int i = 0 ; i <= secret_bits.size() ; i ++ ) {
quantum::h(q[i]);
if ( i < secret_bits . size ( ) )
quantum::mz(q[i]);
}
}