Loading mlir/dialect/include/Quantum/QuantumOps.td +5 −0 Original line number Diff line number Diff line Loading @@ -41,6 +41,11 @@ def ArraySliceOp : QuantumOp<"qarray_slice", []> { let arguments = (ins ArrayType:$qreg, Variadic<I64>:$slice_range); let results = (outs ArrayType:$array_slice); } // Array Concatenation def ArrayConcatOp : QuantumOp<"qarray_concat", []> { let arguments = (ins ArrayType:$qreg1, ArrayType:$qreg2); let results = (outs ArrayType:$concat_array); } def InstOp : QuantumOp<"inst", [AttrSizedOperandSegments]> { let arguments = (ins StrAttr:$name, Variadic<QubitType>:$qubits, Variadic<F64>:$params); Loading mlir/parsers/qasm3/examples/qubit_alias.qasmdeleted 100644 → 0 +0 −9 Original line number Diff line number Diff line OPENQASM 3; include "qelib1.inc"; qubit q[6]; // myreg[0] refers to the qubit q[1], myreg[1] -> q[3], etc. let myreg = q[1, 3, 5]; for i in [0:3] { x q[i]; } No newline at end of file mlir/parsers/qasm3/tests/test_alias_handler.cpp +63 −0 Original line number Diff line number Diff line Loading @@ -132,6 +132,69 @@ QCOR_EXPECT_TRUE(m6[2] == 0); QCOR_EXPECT_TRUE(m6[3] == 1); QCOR_EXPECT_TRUE(m6[4] == 1); QCOR_EXPECT_TRUE(m6[5] == 1); // Test concatenate: // Reset q to start next test reset q; let even_set = q[0:2:5]; let odd_set = q[1:2:5]; let both = even_set || odd_set; x both; // Measure all qubits bit m7[6]; m7 = measure q; for i in [0:6] { print(m7[i]); } // All ones QCOR_EXPECT_TRUE(m7[0] == 1); QCOR_EXPECT_TRUE(m7[1] == 1); QCOR_EXPECT_TRUE(m7[2] == 1); QCOR_EXPECT_TRUE(m7[3] == 1); QCOR_EXPECT_TRUE(m7[4] == 1); QCOR_EXPECT_TRUE(m7[5] == 1); // Test concatenate complex // Reset q to start next test reset q; // Inline concat: 0, 3, 1, 5 let concat_inline = q[0:3:5] || q[1:4:5]; x concat_inline; // Measure all qubits bit m8[6]; m8 = measure q; for i in [0:6] { print(m8[i]); } // 0, 3, 1, 5 ==> 1 QCOR_EXPECT_TRUE(m8[0] == 1); QCOR_EXPECT_TRUE(m8[1] == 1); QCOR_EXPECT_TRUE(m8[2] == 0); QCOR_EXPECT_TRUE(m8[3] == 1); QCOR_EXPECT_TRUE(m8[4] == 0); QCOR_EXPECT_TRUE(m8[5] == 1); // Reset q to start next test reset q; // Multi-concat: 0, 1, 2, 4, 5 (no 3) let concat_multiple = q[0:1:2] || q[4:4] || q[5]; x concat_multiple; // Measure all qubits bit m9[6]; m9 = measure q; for i in [0:6] { print(m9[i]); } // All ones except 3 QCOR_EXPECT_TRUE(m9[0] == 1); QCOR_EXPECT_TRUE(m9[1] == 1); QCOR_EXPECT_TRUE(m9[2] == 1); QCOR_EXPECT_TRUE(m9[3] == 0); QCOR_EXPECT_TRUE(m9[4] == 1); QCOR_EXPECT_TRUE(m9[5] == 1); )#"; auto mlir = qcor::mlir_compile("qasm3", alias_by_indicies, "test", qcor::OutputType::MLIR, true); Loading mlir/parsers/qasm3/visitor_handlers/alias_handler.cpp +226 −139 Original line number Diff line number Diff line Loading @@ -19,16 +19,15 @@ antlrcpp::Any qasm3_visitor::visitAliasStatement( // | indexIdentifier '||' indexIdentifier // ; // The name of the new alias register, pointing to previously allocated // register auto alias = context->Identifier()->getText(); // Get the name and symbol Value of the original register. // We need to determine the alias array size and cache it // for broadcast to work on the result array. auto allocated_variable = context->indexIdentifier()->Identifier()->getText(); auto allocated_symbol = symbol_table.get_symbol(allocated_variable); // Determine the first qreg size // Function to process the indexIdentifier block // We make this a function to allow re-entrance. const std::function<void(const std::string &, decltype(context->indexIdentifier()))> processIdentifierDef = [this, &location, &processIdentifierDef]( const std::string &in_aliasName, decltype(context->indexIdentifier()) in_indexIdentifierContext) { // Helper to determine the qreg size const auto get_qreg_size = [&](const std::string &qreg_name) { uint64_t nqubits; auto qreg_value = symbol_table.get_symbol(qreg_name); Loading @@ -40,53 +39,63 @@ antlrcpp::Any qasm3_visitor::visitAliasStatement( try { nqubits = std::stoi(attributes[0]); } catch (...) { printErrorMessage("Could not infer qubit[] size from block argument.", context); printErrorMessage( "Could not infer qubit[] size from block argument."); } } else { printErrorMessage( "Could not infer qubit[] size from block argument. No size " "attribute for variable in symbol table.", context); "attribute for variable in symbol table."); } } return nqubits; }; // The RHS has an Identifier (range- or index- based slicing) if (in_indexIdentifierContext->Identifier()) { // Get the name and symbol Value of the original register. // We need to determine the alias array size and cache it // for broadcast to work on the result array. auto allocated_variable = in_indexIdentifierContext->Identifier()->getText(); auto allocated_symbol = symbol_table.get_symbol(allocated_variable); // handle q[1, 3, 5] comma syntax if (context->indexIdentifier()->LBRACKET()) { if (in_indexIdentifierContext->LBRACKET()) { // get the comma expression, count how many elements there are auto expressions = context->indexIdentifier()->expressionList()->expression(); in_indexIdentifierContext->expressionList()->expression(); auto n_expressions = expressions.size(); // Create a qubit array of given size // which keeps alias references to Qubits in the original input array. auto str_attr = builder.getStringAttr(alias); // which keeps alias references to Qubits in the original input // array. auto str_attr = builder.getStringAttr(in_aliasName); auto integer_attr = mlir::IntegerAttr::get(builder.getI64Type(), n_expressions); mlir::Value alias_allocation = builder.create<mlir::quantum::QaliasArrayAllocOp>( location, array_type, integer_attr, str_attr); // Add the alias register to the symbol table symbol_table.add_symbol(alias, alias_allocation, symbol_table.add_symbol(in_aliasName, alias_allocation, {std::to_string(n_expressions)}); auto counter = 0; for (auto expr : expressions) { // GOAL HERE IS TO ASSIGN extracted qubits from original array // to the correct element of the alias array auto idx = symbol_table.evaluate_constant_integer_expression(expr->getText()); auto idx = symbol_table.evaluate_constant_integer_expression( expr->getText()); auto dest_idx = get_or_create_constant_integer_value( counter, location, builder.getI64Type(), symbol_table, builder); counter, location, builder.getI64Type(), symbol_table, builder); auto src_idx = get_or_create_constant_integer_value( idx, location, builder.getI64Type(), symbol_table, builder); ++counter; builder.create<mlir::quantum::AssignQubitOp>( location, alias_allocation, dest_idx, allocated_symbol, src_idx); location, alias_allocation, dest_idx, allocated_symbol, src_idx); } } else if (auto range_def = context->indexIdentifier()->rangeDefinition()) { } else if (auto range_def = in_indexIdentifierContext->rangeDefinition()) { // handle range definition const size_t n_expr = range_def->expression().size(); // Minimum is two expressions and not more than 3 Loading @@ -95,10 +104,11 @@ antlrcpp::Any qasm3_visitor::visitAliasStatement( } auto range_start_expr = range_def->expression(0); auto range_stop_expr = (n_expr == 2) ? range_def->expression(1) : range_def->expression(2); auto range_stop_expr = (n_expr == 2) ? range_def->expression(1) : range_def->expression(2); const auto resolve_range_value = [&](auto *range_item_expr) -> int64_t { const auto resolve_range_value = [&](auto *range_item_expr) -> int64_t { const std::string range_item_str = range_item_expr->getText(); try { return std::stoi(range_item_str); Loading @@ -111,7 +121,8 @@ antlrcpp::Any qasm3_visitor::visitAliasStatement( const int64_t range_start = resolve_range_value(range_start_expr); const int64_t range_stop = resolve_range_value(range_stop_expr); const int64_t range_step = (n_expr == 2) ? 1 : resolve_range_value(range_def->expression(1)); (n_expr == 2) ? 1 : resolve_range_value(range_def->expression(1)); // Step must not be zero: if (range_step == 0) { Loading @@ -121,25 +132,32 @@ antlrcpp::Any qasm3_visitor::visitAliasStatement( // std::cout << "Range: Start = " << range_start << "; Step = " << // range_step << "; Stop = " << range_stop << "\n"; auto range_start_mlir_val = get_or_create_constant_integer_value( range_start, location, builder.getI64Type(), symbol_table, builder); range_start, location, builder.getI64Type(), symbol_table, builder); auto range_step_mlir_val = get_or_create_constant_integer_value( range_step, location, builder.getI64Type(), symbol_table, builder); range_step, location, builder.getI64Type(), symbol_table, builder); auto range_stop_mlir_val = get_or_create_constant_integer_value( range_stop, location, builder.getI64Type(), symbol_table, builder); mlir::Value array_slice = builder.create<mlir::quantum::ArraySliceOp>( range_stop, location, builder.getI64Type(), symbol_table, builder); mlir::Value array_slice = builder.create<mlir::quantum::ArraySliceOp>( location, array_type, allocated_symbol, llvm::makeArrayRef(std::vector<mlir::Value>{ range_start_mlir_val, range_step_mlir_val, range_stop_mlir_val})); range_start_mlir_val, range_step_mlir_val, range_stop_mlir_val})); // Determine and cache the slice size for instruction broadcasting. const int64_t orig_size = get_qreg_size(allocated_variable); const auto slice_size_calc = [](int64_t orig_size, int64_t start, int64_t step, int64_t end) -> int64_t { // If step > 0 and lo > hi, or step < 0 and lo < hi, the range is empty. // Else for step > 0, if n values are in the range, the last one is // lo + (n-1)*step, which must be <= hi. Rearranging, // n <= (hi - lo)/step + 1, so taking the floor of the RHS gives // the proper value. int64_t step, int64_t end) -> int64_t { // If step > 0 and lo > hi, or step < 0 and lo < hi, the range is // empty. Else for step > 0, if n values are in the range, the // last one is lo + (n-1)*step, which must be <= hi. Rearranging, // n <= (hi // - lo)/step + 1, so taking the floor of the RHS gives the proper // value. assert(step != 0); // Convert to positive indices (if given as negative) const int64_t lo = start >= 0 ? start : orig_size + start; Loading @@ -155,11 +173,80 @@ antlrcpp::Any qasm3_visitor::visitAliasStatement( return 0; } }; const auto new_size = slice_size_calc(orig_size, range_start, range_step, range_stop); symbol_table.add_symbol(alias, array_slice, {std::to_string(new_size)}); const auto new_size = slice_size_calc(orig_size, range_start, range_step, range_stop); symbol_table.add_symbol(in_aliasName, array_slice, {std::to_string(new_size)}); } else { printErrorMessage("Could not parse the alias statement.", in_indexIdentifierContext); } } else if (in_indexIdentifierContext->indexIdentifier().size() == 2) { // handle concatenation // the RHS (is an indexIdentifier) is indexIdentifier || // indexIdentifier auto firstIdentifier = in_indexIdentifierContext->indexIdentifier(0); auto secondIdentifier = in_indexIdentifierContext->indexIdentifier(1); const auto isPureIdentifier = [](auto *indexIdentifier) { // This is a simple name identifier return !indexIdentifier->LBRACKET() && !indexIdentifier->rangeDefinition() && indexIdentifier->indexIdentifier().empty(); }; // STRATEGY: // If the indexIdentifier is *pure* (just a var name), // the concatenate the var directly. // Otherwise, create a local identifier for the nested block (could be // both sides) the traverse down recursively. const auto process_block_and_gen_var_name = [&](decltype( firstIdentifier) in_termIdentifierNode) -> std::string { static int64_t temp_var_counter = 0; if (isPureIdentifier(in_termIdentifierNode)) { return in_termIdentifierNode->Identifier()->getText(); } // This is a complex one: const std::string new_var_name = "__internal_concat_temp_" + std::to_string(temp_var_counter++); std::cout << "Process " << new_var_name << " = " << in_termIdentifierNode->getText() << "\n"; processIdentifierDef(new_var_name, in_termIdentifierNode); return new_var_name; }; // Process both blocks: const std::string lhs_temp_var = process_block_and_gen_var_name(firstIdentifier); const std::string rhs_temp_var = process_block_and_gen_var_name(secondIdentifier); auto first_reg_symbol = symbol_table.get_symbol(lhs_temp_var); auto second_reg_symbol = symbol_table.get_symbol(rhs_temp_var); const auto first_reg_size = get_qreg_size(lhs_temp_var); const auto second_reg_size = get_qreg_size(rhs_temp_var); mlir::Value array_concat = builder.create<mlir::quantum::ArrayConcatOp>( location, array_type, first_reg_symbol, second_reg_symbol); const auto new_size = first_reg_size + second_reg_size; // std::cout << "Concatenate " << lhs_temp_var << "[" << first_reg_size // << "] with " << rhs_temp_var << "[" << second_reg_size // << "] -> " << in_aliasName << "[" << new_size << "].\n"; symbol_table.add_symbol(in_aliasName, array_concat, {std::to_string(new_size)}); } else { printErrorMessage("Could not parse the alias statement.", in_indexIdentifierContext); } }; // The name of the new alias register (LHS of the alias statement) // This will be associated with an alias array. auto alias = context->Identifier()->getText(); // Main entrance: process top-level "alias = indexIdentifier" // This may call itself recursively if the RHS is a nested statement. // e.g. alias = q[1,3,5] || q[2] || q[4:2:8] processIdentifierDef(alias, context->indexIdentifier()); return 0; } } // namespace qcor No newline at end of file mlir/qir_qrt/quantum_rt_array.cpp +3 −2 Original line number Diff line number Diff line Loading @@ -86,11 +86,12 @@ Array *__quantum__rt__array_copy(Array *array, bool forceNewInstance) { } Array *__quantum__rt__array_concatenate(Array *head, Array *tail) { if (verbose) std::cout << "CALL: " << __PRETTY_FUNCTION__ << "\n"; if (head && tail) { auto resultArray = new Array(*head); resultArray->append(*tail); if (verbose) std::cout << "[qir-qrt] Concatenate two arrays of size " << head->size() << " and " << tail->size() << ".\n"; return resultArray; } Loading Loading
mlir/dialect/include/Quantum/QuantumOps.td +5 −0 Original line number Diff line number Diff line Loading @@ -41,6 +41,11 @@ def ArraySliceOp : QuantumOp<"qarray_slice", []> { let arguments = (ins ArrayType:$qreg, Variadic<I64>:$slice_range); let results = (outs ArrayType:$array_slice); } // Array Concatenation def ArrayConcatOp : QuantumOp<"qarray_concat", []> { let arguments = (ins ArrayType:$qreg1, ArrayType:$qreg2); let results = (outs ArrayType:$concat_array); } def InstOp : QuantumOp<"inst", [AttrSizedOperandSegments]> { let arguments = (ins StrAttr:$name, Variadic<QubitType>:$qubits, Variadic<F64>:$params); Loading
mlir/parsers/qasm3/examples/qubit_alias.qasmdeleted 100644 → 0 +0 −9 Original line number Diff line number Diff line OPENQASM 3; include "qelib1.inc"; qubit q[6]; // myreg[0] refers to the qubit q[1], myreg[1] -> q[3], etc. let myreg = q[1, 3, 5]; for i in [0:3] { x q[i]; } No newline at end of file
mlir/parsers/qasm3/tests/test_alias_handler.cpp +63 −0 Original line number Diff line number Diff line Loading @@ -132,6 +132,69 @@ QCOR_EXPECT_TRUE(m6[2] == 0); QCOR_EXPECT_TRUE(m6[3] == 1); QCOR_EXPECT_TRUE(m6[4] == 1); QCOR_EXPECT_TRUE(m6[5] == 1); // Test concatenate: // Reset q to start next test reset q; let even_set = q[0:2:5]; let odd_set = q[1:2:5]; let both = even_set || odd_set; x both; // Measure all qubits bit m7[6]; m7 = measure q; for i in [0:6] { print(m7[i]); } // All ones QCOR_EXPECT_TRUE(m7[0] == 1); QCOR_EXPECT_TRUE(m7[1] == 1); QCOR_EXPECT_TRUE(m7[2] == 1); QCOR_EXPECT_TRUE(m7[3] == 1); QCOR_EXPECT_TRUE(m7[4] == 1); QCOR_EXPECT_TRUE(m7[5] == 1); // Test concatenate complex // Reset q to start next test reset q; // Inline concat: 0, 3, 1, 5 let concat_inline = q[0:3:5] || q[1:4:5]; x concat_inline; // Measure all qubits bit m8[6]; m8 = measure q; for i in [0:6] { print(m8[i]); } // 0, 3, 1, 5 ==> 1 QCOR_EXPECT_TRUE(m8[0] == 1); QCOR_EXPECT_TRUE(m8[1] == 1); QCOR_EXPECT_TRUE(m8[2] == 0); QCOR_EXPECT_TRUE(m8[3] == 1); QCOR_EXPECT_TRUE(m8[4] == 0); QCOR_EXPECT_TRUE(m8[5] == 1); // Reset q to start next test reset q; // Multi-concat: 0, 1, 2, 4, 5 (no 3) let concat_multiple = q[0:1:2] || q[4:4] || q[5]; x concat_multiple; // Measure all qubits bit m9[6]; m9 = measure q; for i in [0:6] { print(m9[i]); } // All ones except 3 QCOR_EXPECT_TRUE(m9[0] == 1); QCOR_EXPECT_TRUE(m9[1] == 1); QCOR_EXPECT_TRUE(m9[2] == 1); QCOR_EXPECT_TRUE(m9[3] == 0); QCOR_EXPECT_TRUE(m9[4] == 1); QCOR_EXPECT_TRUE(m9[5] == 1); )#"; auto mlir = qcor::mlir_compile("qasm3", alias_by_indicies, "test", qcor::OutputType::MLIR, true); Loading
mlir/parsers/qasm3/visitor_handlers/alias_handler.cpp +226 −139 Original line number Diff line number Diff line Loading @@ -19,16 +19,15 @@ antlrcpp::Any qasm3_visitor::visitAliasStatement( // | indexIdentifier '||' indexIdentifier // ; // The name of the new alias register, pointing to previously allocated // register auto alias = context->Identifier()->getText(); // Get the name and symbol Value of the original register. // We need to determine the alias array size and cache it // for broadcast to work on the result array. auto allocated_variable = context->indexIdentifier()->Identifier()->getText(); auto allocated_symbol = symbol_table.get_symbol(allocated_variable); // Determine the first qreg size // Function to process the indexIdentifier block // We make this a function to allow re-entrance. const std::function<void(const std::string &, decltype(context->indexIdentifier()))> processIdentifierDef = [this, &location, &processIdentifierDef]( const std::string &in_aliasName, decltype(context->indexIdentifier()) in_indexIdentifierContext) { // Helper to determine the qreg size const auto get_qreg_size = [&](const std::string &qreg_name) { uint64_t nqubits; auto qreg_value = symbol_table.get_symbol(qreg_name); Loading @@ -40,53 +39,63 @@ antlrcpp::Any qasm3_visitor::visitAliasStatement( try { nqubits = std::stoi(attributes[0]); } catch (...) { printErrorMessage("Could not infer qubit[] size from block argument.", context); printErrorMessage( "Could not infer qubit[] size from block argument."); } } else { printErrorMessage( "Could not infer qubit[] size from block argument. No size " "attribute for variable in symbol table.", context); "attribute for variable in symbol table."); } } return nqubits; }; // The RHS has an Identifier (range- or index- based slicing) if (in_indexIdentifierContext->Identifier()) { // Get the name and symbol Value of the original register. // We need to determine the alias array size and cache it // for broadcast to work on the result array. auto allocated_variable = in_indexIdentifierContext->Identifier()->getText(); auto allocated_symbol = symbol_table.get_symbol(allocated_variable); // handle q[1, 3, 5] comma syntax if (context->indexIdentifier()->LBRACKET()) { if (in_indexIdentifierContext->LBRACKET()) { // get the comma expression, count how many elements there are auto expressions = context->indexIdentifier()->expressionList()->expression(); in_indexIdentifierContext->expressionList()->expression(); auto n_expressions = expressions.size(); // Create a qubit array of given size // which keeps alias references to Qubits in the original input array. auto str_attr = builder.getStringAttr(alias); // which keeps alias references to Qubits in the original input // array. auto str_attr = builder.getStringAttr(in_aliasName); auto integer_attr = mlir::IntegerAttr::get(builder.getI64Type(), n_expressions); mlir::Value alias_allocation = builder.create<mlir::quantum::QaliasArrayAllocOp>( location, array_type, integer_attr, str_attr); // Add the alias register to the symbol table symbol_table.add_symbol(alias, alias_allocation, symbol_table.add_symbol(in_aliasName, alias_allocation, {std::to_string(n_expressions)}); auto counter = 0; for (auto expr : expressions) { // GOAL HERE IS TO ASSIGN extracted qubits from original array // to the correct element of the alias array auto idx = symbol_table.evaluate_constant_integer_expression(expr->getText()); auto idx = symbol_table.evaluate_constant_integer_expression( expr->getText()); auto dest_idx = get_or_create_constant_integer_value( counter, location, builder.getI64Type(), symbol_table, builder); counter, location, builder.getI64Type(), symbol_table, builder); auto src_idx = get_or_create_constant_integer_value( idx, location, builder.getI64Type(), symbol_table, builder); ++counter; builder.create<mlir::quantum::AssignQubitOp>( location, alias_allocation, dest_idx, allocated_symbol, src_idx); location, alias_allocation, dest_idx, allocated_symbol, src_idx); } } else if (auto range_def = context->indexIdentifier()->rangeDefinition()) { } else if (auto range_def = in_indexIdentifierContext->rangeDefinition()) { // handle range definition const size_t n_expr = range_def->expression().size(); // Minimum is two expressions and not more than 3 Loading @@ -95,10 +104,11 @@ antlrcpp::Any qasm3_visitor::visitAliasStatement( } auto range_start_expr = range_def->expression(0); auto range_stop_expr = (n_expr == 2) ? range_def->expression(1) : range_def->expression(2); auto range_stop_expr = (n_expr == 2) ? range_def->expression(1) : range_def->expression(2); const auto resolve_range_value = [&](auto *range_item_expr) -> int64_t { const auto resolve_range_value = [&](auto *range_item_expr) -> int64_t { const std::string range_item_str = range_item_expr->getText(); try { return std::stoi(range_item_str); Loading @@ -111,7 +121,8 @@ antlrcpp::Any qasm3_visitor::visitAliasStatement( const int64_t range_start = resolve_range_value(range_start_expr); const int64_t range_stop = resolve_range_value(range_stop_expr); const int64_t range_step = (n_expr == 2) ? 1 : resolve_range_value(range_def->expression(1)); (n_expr == 2) ? 1 : resolve_range_value(range_def->expression(1)); // Step must not be zero: if (range_step == 0) { Loading @@ -121,25 +132,32 @@ antlrcpp::Any qasm3_visitor::visitAliasStatement( // std::cout << "Range: Start = " << range_start << "; Step = " << // range_step << "; Stop = " << range_stop << "\n"; auto range_start_mlir_val = get_or_create_constant_integer_value( range_start, location, builder.getI64Type(), symbol_table, builder); range_start, location, builder.getI64Type(), symbol_table, builder); auto range_step_mlir_val = get_or_create_constant_integer_value( range_step, location, builder.getI64Type(), symbol_table, builder); range_step, location, builder.getI64Type(), symbol_table, builder); auto range_stop_mlir_val = get_or_create_constant_integer_value( range_stop, location, builder.getI64Type(), symbol_table, builder); mlir::Value array_slice = builder.create<mlir::quantum::ArraySliceOp>( range_stop, location, builder.getI64Type(), symbol_table, builder); mlir::Value array_slice = builder.create<mlir::quantum::ArraySliceOp>( location, array_type, allocated_symbol, llvm::makeArrayRef(std::vector<mlir::Value>{ range_start_mlir_val, range_step_mlir_val, range_stop_mlir_val})); range_start_mlir_val, range_step_mlir_val, range_stop_mlir_val})); // Determine and cache the slice size for instruction broadcasting. const int64_t orig_size = get_qreg_size(allocated_variable); const auto slice_size_calc = [](int64_t orig_size, int64_t start, int64_t step, int64_t end) -> int64_t { // If step > 0 and lo > hi, or step < 0 and lo < hi, the range is empty. // Else for step > 0, if n values are in the range, the last one is // lo + (n-1)*step, which must be <= hi. Rearranging, // n <= (hi - lo)/step + 1, so taking the floor of the RHS gives // the proper value. int64_t step, int64_t end) -> int64_t { // If step > 0 and lo > hi, or step < 0 and lo < hi, the range is // empty. Else for step > 0, if n values are in the range, the // last one is lo + (n-1)*step, which must be <= hi. Rearranging, // n <= (hi // - lo)/step + 1, so taking the floor of the RHS gives the proper // value. assert(step != 0); // Convert to positive indices (if given as negative) const int64_t lo = start >= 0 ? start : orig_size + start; Loading @@ -155,11 +173,80 @@ antlrcpp::Any qasm3_visitor::visitAliasStatement( return 0; } }; const auto new_size = slice_size_calc(orig_size, range_start, range_step, range_stop); symbol_table.add_symbol(alias, array_slice, {std::to_string(new_size)}); const auto new_size = slice_size_calc(orig_size, range_start, range_step, range_stop); symbol_table.add_symbol(in_aliasName, array_slice, {std::to_string(new_size)}); } else { printErrorMessage("Could not parse the alias statement.", in_indexIdentifierContext); } } else if (in_indexIdentifierContext->indexIdentifier().size() == 2) { // handle concatenation // the RHS (is an indexIdentifier) is indexIdentifier || // indexIdentifier auto firstIdentifier = in_indexIdentifierContext->indexIdentifier(0); auto secondIdentifier = in_indexIdentifierContext->indexIdentifier(1); const auto isPureIdentifier = [](auto *indexIdentifier) { // This is a simple name identifier return !indexIdentifier->LBRACKET() && !indexIdentifier->rangeDefinition() && indexIdentifier->indexIdentifier().empty(); }; // STRATEGY: // If the indexIdentifier is *pure* (just a var name), // the concatenate the var directly. // Otherwise, create a local identifier for the nested block (could be // both sides) the traverse down recursively. const auto process_block_and_gen_var_name = [&](decltype( firstIdentifier) in_termIdentifierNode) -> std::string { static int64_t temp_var_counter = 0; if (isPureIdentifier(in_termIdentifierNode)) { return in_termIdentifierNode->Identifier()->getText(); } // This is a complex one: const std::string new_var_name = "__internal_concat_temp_" + std::to_string(temp_var_counter++); std::cout << "Process " << new_var_name << " = " << in_termIdentifierNode->getText() << "\n"; processIdentifierDef(new_var_name, in_termIdentifierNode); return new_var_name; }; // Process both blocks: const std::string lhs_temp_var = process_block_and_gen_var_name(firstIdentifier); const std::string rhs_temp_var = process_block_and_gen_var_name(secondIdentifier); auto first_reg_symbol = symbol_table.get_symbol(lhs_temp_var); auto second_reg_symbol = symbol_table.get_symbol(rhs_temp_var); const auto first_reg_size = get_qreg_size(lhs_temp_var); const auto second_reg_size = get_qreg_size(rhs_temp_var); mlir::Value array_concat = builder.create<mlir::quantum::ArrayConcatOp>( location, array_type, first_reg_symbol, second_reg_symbol); const auto new_size = first_reg_size + second_reg_size; // std::cout << "Concatenate " << lhs_temp_var << "[" << first_reg_size // << "] with " << rhs_temp_var << "[" << second_reg_size // << "] -> " << in_aliasName << "[" << new_size << "].\n"; symbol_table.add_symbol(in_aliasName, array_concat, {std::to_string(new_size)}); } else { printErrorMessage("Could not parse the alias statement.", in_indexIdentifierContext); } }; // The name of the new alias register (LHS of the alias statement) // This will be associated with an alias array. auto alias = context->Identifier()->getText(); // Main entrance: process top-level "alias = indexIdentifier" // This may call itself recursively if the RHS is a nested statement. // e.g. alias = q[1,3,5] || q[2] || q[4:2:8] processIdentifierDef(alias, context->indexIdentifier()); return 0; } } // namespace qcor No newline at end of file
mlir/qir_qrt/quantum_rt_array.cpp +3 −2 Original line number Diff line number Diff line Loading @@ -86,11 +86,12 @@ Array *__quantum__rt__array_copy(Array *array, bool forceNewInstance) { } Array *__quantum__rt__array_concatenate(Array *head, Array *tail) { if (verbose) std::cout << "CALL: " << __PRETTY_FUNCTION__ << "\n"; if (head && tail) { auto resultArray = new Array(*head); resultArray->append(*tail); if (verbose) std::cout << "[qir-qrt] Concatenate two arrays of size " << head->size() << " and " << tail->size() << ".\n"; return resultArray; } Loading