@@ -1574,6 +1574,10 @@ namespace nil {
15741574 // Final return
15751575 finished = true ;
15761576
1577+ if (gen_mode.has_assignments ()) {
1578+ fill_return_value (llvm::cast<llvm::ReturnInst>(inst), frame);
1579+ }
1580+
15771581 if (print_output_format != no_print && gen_mode.has_assignments ()) {
15781582 if (print_output_format == hex) {
15791583 std::cout << std::hex;
@@ -1689,6 +1693,80 @@ namespace nil {
16891693 return detail::var_value<BlueprintFieldType, var>(input_var, assignments[currProverIdx], internal_storage, gen_mode.has_assignments ());
16901694 }
16911695
1696+ /* *
1697+ * @brief Fill return value of the circuit function.
1698+ *
1699+ * @param inst pointer to `ret` instruction of circuit function
1700+ * @param frame reference to frame of circuit function
1701+ */
1702+ void fill_return_value (const llvm::ReturnInst *inst, stack_frame<var> &frame) {
1703+ auto ret_val = inst->getReturnValue ();
1704+ if (ret_val == nullptr ) {
1705+ // Function returns void
1706+ return_value = {};
1707+ return ;
1708+ }
1709+ auto ret_type = ret_val->getType ();
1710+ switch (ret_type->getTypeID ()) {
1711+ case llvm::Type::IntegerTyID: {
1712+ return_value = {
1713+ typename BlueprintFieldType::integral_type (get_var_value (frame.scalars [ret_val]).data )
1714+ };
1715+ break ;
1716+ }
1717+ case llvm::Type::GaloisFieldTyID: {
1718+ auto field_type = llvm::cast<llvm::GaloisFieldType>(ret_type);
1719+ if (field_arg_num<BlueprintFieldType>(field_type) == 1 ) {
1720+ // Native field case
1721+ return_value = {
1722+ typename BlueprintFieldType::integral_type (get_var_value (frame.scalars [ret_val]).data )
1723+ };
1724+ } else {
1725+ llvm::GaloisFieldKind field_kind = field_type->getFieldKind ();
1726+ std::vector<var> res = frame.vectors [ret_val];
1727+ std::vector<typename BlueprintFieldType::value_type> chopped_field;
1728+ for (std::size_t i = 0 ; i < res.size (); i++) {
1729+ chopped_field.push_back (get_var_value (res[i]));
1730+ }
1731+ return_value = {
1732+ unmarshal_field_val<BlueprintFieldType>(field_kind, chopped_field)
1733+ };
1734+ }
1735+ break ;
1736+ }
1737+ case llvm::Type::EllipticCurveTyID: {
1738+ auto curve_type = llvm::cast<llvm::EllipticCurveType>(ret_type);
1739+ std::vector<var> res = frame.vectors [ret_val];
1740+ size_t curve_len = curve_arg_num<BlueprintFieldType>(ret_val->getType ());
1741+ if (curve_len == 2 ) {
1742+ // Native curve
1743+ return_value = {
1744+ typename BlueprintFieldType::integral_type (get_var_value (res[0 ]).data ),
1745+ typename BlueprintFieldType::integral_type (get_var_value (res[1 ]).data ),
1746+ };
1747+ } else {
1748+ // Non-native curve
1749+ llvm::GaloisFieldKind field_kind = curve_type->GetBaseFieldKind ();
1750+ std::vector<var> res = frame.vectors [ret_val];
1751+ column_type<BlueprintFieldType> chopped_field_x;
1752+ column_type<BlueprintFieldType> chopped_field_y;
1753+ for (std::size_t i = 0 ; i < curve_len / 2 ; i++) {
1754+ chopped_field_x.push_back (get_var_value (res[i]));
1755+ chopped_field_y.push_back (get_var_value (res[i + (curve_len / 2 )]));
1756+ }
1757+ return_value = {
1758+ unmarshal_field_val<BlueprintFieldType>(field_kind, chopped_field_x),
1759+ unmarshal_field_val<BlueprintFieldType>(field_kind, chopped_field_y),
1760+ };
1761+ }
1762+ }
1763+ default : {
1764+ // Do nothing, just leave return value empty.
1765+ return_value = {};
1766+ }
1767+ }
1768+ }
1769+
16921770 public:
16931771 bool parse_ir_file (const char *ir_file) {
16941772 llvm::SMDiagnostic diagnostic;
@@ -1804,6 +1882,25 @@ namespace nil {
18041882 }
18051883 }
18061884
1885+ /* *
1886+ * @brief Get return value of circuit function.
1887+ *
1888+ * Returns undefined value if evaluation did not finished successfully.
1889+ *
1890+ * Non-native field/curve types are represented with single value and truncated to
1891+ * match the native size.
1892+ */
1893+ std::vector<typename BlueprintFieldType::integral_type> get_return_value () {
1894+ // TODO: this must be removed after completing implementation of `fill_return_value`
1895+ auto ret_type = circuit_function->getReturnType ();
1896+ if (finished && !ret_type->isVoidTy () && return_value.empty ()) {
1897+ LLVM_PRINT (ret_type, str);
1898+ TODO_WITH_LINK (" accessing return value for " + str + " type" ,
1899+ " https://github.com/NilFoundation/zkllvm-assigner/issues/218" );
1900+ }
1901+ return return_value;
1902+ }
1903+
18071904 private:
18081905 llvm::LLVMContext context;
18091906 const llvm::BasicBlock *predecessor = nullptr ;
@@ -1834,6 +1931,7 @@ namespace nil {
18341931 * identified as constant column with special internal_storage_index = std::numeric_limits<std::size_t>::max()
18351932 ***/
18361933 column_type<BlueprintFieldType> internal_storage;
1934+ std::vector<typename BlueprintFieldType::integral_type> return_value;
18371935 };
18381936
18391937 } // namespace blueprint
0 commit comments