diff --git a/xls/contrib/xlscc/translate_block.cc b/xls/contrib/xlscc/translate_block.cc index 091c5da898..24853bf849 100644 --- a/xls/contrib/xlscc/translate_block.cc +++ b/xls/contrib/xlscc/translate_block.cc @@ -49,6 +49,7 @@ #include "xls/ir/function_builder.h" #include "xls/ir/lsb_or_msb.h" #include "xls/ir/nodes.h" +#include "xls/ir/op.h" #include "xls/ir/package.h" #include "xls/ir/source_location.h" #include "xls/ir/value.h" @@ -588,11 +589,17 @@ absl::Status Translator::GenerateDefaultIOOp( if (!is_send) { XLSCC_CHECK(channel->CanReceive(), loc); - xls::BValue tup = pb.ReceiveIf(channel, pb.GetTokenParam(), pred_0, loc); - token = pb.TupleIndex(tup, 0); + xls::BValue tup = pb.ReceiveIf( + channel, pb.GetTokenParam(), pred_0, loc, + /*name=*/absl::StrFormat("%s_default_op", channel->name())); + token = pb.TupleIndex( + tup, 0, loc, + /*name=*/absl::StrFormat("%s_default_op_token", channel->name())); } else if (is_send) { XLSCC_CHECK(channel->CanSend(), loc); - token = pb.SendIf(channel, pb.GetTokenParam(), pred_0, data_0, loc); + token = + pb.SendIf(channel, pb.GetTokenParam(), pred_0, data_0, loc, + /*name=*/absl::StrFormat("%s_default_op", channel->name())); } else { return absl::UnimplementedError(ErrorMessage( loc, "Don't know how to create default IO op for channel %s", @@ -622,31 +629,9 @@ absl::Status Translator::GenerateDefaultIOOps(PreparedBlock& prepared, return absl::OkStatus(); } -absl::StatusOr -Translator::GenerateFSMInvocation(PreparedBlock& prepared, xls::ProcBuilder& pb, - int nesting_level, - const xls::SourceInfo& body_loc) { - // Create a deterministic ordering for the last state elements - // (These store the received inputs for IO operations) - std::vector arg_indices_ordered_by_state_elems; - std::vector io_ops_with_args_ordered; - - for (const IOOp& op : prepared.xls_func->io_ops) { - // Don't copy direct-ins, statics, etc into FSM state - if (!prepared.arg_index_for_op.contains(&op)) { - continue; - } - // Don't copy context in/out for pipelined loops into the FSM state - if (prepared.xls_func->pipeline_loops_by_internal_channel.contains( - op.channel)) { - continue; - } - arg_indices_ordered_by_state_elems.push_back( - prepared.arg_index_for_op.at(&op)); - io_ops_with_args_ordered.push_back(&op); - } - - // Lay out the states for this FSM +absl::StatusOr Translator::LayoutFSMStates( + PreparedBlock& prepared, xls::ProcBuilder& pb, + const xls::SourceInfo& body_loc) { absl::flat_hash_map state_by_io_op; std::vector> states; @@ -763,13 +748,53 @@ Translator::GenerateFSMInvocation(PreparedBlock& prepared, xls::ProcBuilder& pb, state->sub_proc); for (const InvokeToGenerate& invoke : state->invokes_to_generate) { LOG(INFO) << absl::StrFormat( - "---- invoke ch %s\n", invoke.op.channel - ? invoke.op.channel->unique_name.c_str() - : "(null)"); + "---- invoke ch %s at %s\n", + invoke.op.channel ? invoke.op.channel->unique_name.c_str() + : "(null)", + LocString(invoke.op.op_location).c_str()); } } } + return LayoutFSMStatesReturn{.state_by_io_op = std::move(state_by_io_op), + .states = std::move(states), + .has_pipelined_loop = has_pipelined_loop}; +} + +absl::StatusOr +Translator::GenerateFSMInvocation(PreparedBlock& prepared, xls::ProcBuilder& pb, + int nesting_level, + const xls::SourceInfo& body_loc) { + // Create a deterministic ordering for the last state elements + // (These store the received inputs for IO operations) + std::vector arg_indices_ordered_by_state_elems; + std::vector io_ops_with_args_ordered; + + for (const IOOp& op : prepared.xls_func->io_ops) { + // Don't copy direct-ins, statics, etc into FSM state + if (!prepared.arg_index_for_op.contains(&op)) { + continue; + } + // Don't copy context in/out for pipelined loops into the FSM state + if (prepared.xls_func->pipeline_loops_by_internal_channel.contains( + op.channel)) { + continue; + } + arg_indices_ordered_by_state_elems.push_back( + prepared.arg_index_for_op.at(&op)); + io_ops_with_args_ordered.push_back(&op); + } + + // Lay out the states for this FSM + XLS_ASSIGN_OR_RETURN(LayoutFSMStatesReturn layout_states_return, + LayoutFSMStates(prepared, pb, body_loc)); + + absl::flat_hash_map state_by_io_op = + std::move(layout_states_return.state_by_io_op); + std::vector> states = + std::move(layout_states_return.states); + bool has_pipelined_loop = layout_states_return.has_pipelined_loop; + const std::string fsm_prefix = absl::StrFormat("__fsm_%s", prepared.xls_func->xls_func->name()); @@ -819,7 +844,9 @@ Translator::GenerateFSMInvocation(PreparedBlock& prepared, xls::ProcBuilder& pb, pb.TupleIndex(state_param, /*idx=*/0, body_loc, /*name=*/absl::StrFormat("%s_state_index", fsm_prefix)); - args_from_last_state = pb.TupleIndex(state_param, /*idx=*/1, body_loc); + args_from_last_state = + pb.TupleIndex(state_param, /*idx=*/1, body_loc, + /*name=*/absl::StrFormat("%s_state_args", fsm_prefix)); } xls::BValue origin_token = prepared.token; @@ -860,7 +887,10 @@ Translator::GenerateFSMInvocation(PreparedBlock& prepared, xls::ProcBuilder& pb, } const int64_t arg_idx = prepared.arg_index_for_op.at(op_ptr); prepared.args[arg_idx] = apply_to_state_elem( - pb, pb.TupleIndex(args_from_last_state, /*idx=*/state_elem_idx, loc), + pb, + pb.TupleIndex( + args_from_last_state, /*idx=*/state_elem_idx, loc, /*name=*/ + absl::StrFormat("arg_from_last_state_%s", Debug_OpName(*op_ptr))), op_ptr, loc); } return absl::OkStatus(); @@ -869,11 +899,26 @@ Translator::GenerateFSMInvocation(PreparedBlock& prepared, xls::ProcBuilder& pb, absl::btree_multimap sub_fsm_next_state_values; + absl::flat_hash_set prev_state_io_nodes; + absl::flat_hash_map op_tokens; + // Generate IR for the individual states for (std::unique_ptr& state : states) { XLSCC_CHECK_GE(state->index, 0, body_loc); + auto last_node_iter = pb.proc()->nodes().begin(); + + if (debug_ir_trace_flags_ & DebugIrTraceFlags_PrevStateIOReferences) { + // How to do this better? -- not supported + for (auto it = last_node_iter;; ++last_node_iter) { + ++it; + if (it == pb.proc()->nodes().end()) { + break; + } + } + } + // Set all op tokens from previous states to the input of this state absl::flat_hash_map op_tokens_prev = op_tokens; for (auto [op, _] : op_tokens_prev) { @@ -970,14 +1015,30 @@ Translator::GenerateFSMInvocation(PreparedBlock& prepared, xls::ProcBuilder& pb, XLSCC_CHECK(changed_state_last_activation.valid(), body_loc); XLSCC_CHECK(changed_state_last_activation.node()->Is(), body_loc); + + // This and is not strictly, logically necessary, however: + // - It gives the compiler the information to remove unnecessary + // data dependencies. + // - It should ensure that the logic remains inactive when its state + // is not active, which may save power. + xls::BValue before_loop_args_selector = pb.And( + changed_state_last_activation, state->in_this_state, body_loc, + /*name=*/ + absl::StrFormat("%s_state_%i_before_loop_args_selector", fsm_prefix, + state->index)); + auto select_elem = - [this, changed_state_last_activation, prepared]( + [this, before_loop_args_selector, prepared, fsm_prefix, &state]( xls::ProcBuilder& pb, const xls::BValue& state_elem, const IOOp* op_ptr, const xls::SourceInfo& loc) -> xls::BValue { const int64_t arg_idx = prepared.arg_index_for_op.at(op_ptr); - xls::BValue ret = pb.Select(changed_state_last_activation, - /*on_true=*/prepared.args.at(arg_idx), - /*on_false=*/state_elem, loc); + xls::BValue ret = pb.Select( + before_loop_args_selector, + /*on_true=*/prepared.args.at(arg_idx), + /*on_false=*/state_elem, loc, + /*name=*/ + absl::StrFormat("%s_state_%i_select_%s_before_loop", fsm_prefix, + state->index, Debug_OpName(*op_ptr))); XLSCC_CHECK(ret.valid(), loc); return ret; }; @@ -1116,6 +1177,37 @@ Translator::GenerateFSMInvocation(PreparedBlock& prepared, xls::ProcBuilder& pb, pb.Tuple(next_args_by_state_elems, body_loc); } + // Check for references to data from IO ops in previous states + if (debug_ir_trace_flags_ & DebugIrTraceFlags_PrevStateIOReferences) { + // Save, since prev_state_io_nodes is used in the loop + auto next_prev_state_io_nodes = prev_state_io_nodes; + + for (; last_node_iter != pb.proc()->nodes().end(); ++last_node_iter) { + const xls::Node* node = *last_node_iter; + + auto opt_path = + Debug_DeeplyCheckOperandsFromPrev(node, prev_state_io_nodes); + if (opt_path.has_value()) { + LOG(WARNING) << absl::StrFormat( + "This node in state %i references previous state's IO node\n", + state->index); + auto full_path = opt_path.value(); + full_path.push_front(node); + for (const xls::Node* path_node : full_path) { + LOG(WARNING) << absl::StrFormat("---- %s: %s\n", + path_node->GetName(), + xls::OpToString(path_node->op())); + } + } + + if (node->Is()) { + next_prev_state_io_nodes.insert(node); + } + } + + prev_state_io_nodes = next_prev_state_io_nodes; + } + // Set args to state elements for later states to use // (With only 1 state, FSM state elements will not exist) if (states.size() > 1) { @@ -1232,8 +1324,6 @@ Translator::GenerateFSMInvocation(PreparedBlock& prepared, xls::ProcBuilder& pb, fsm_next_state_values.insert({state_elem, bval}); } - XLSCC_CHECK(last_ret_val.valid(), body_loc); - if (generate_fsms_for_pipelined_loops_ && (debug_ir_trace_flags_ & DebugIrTraceFlags_LoopControl)) { xls::BValue literal_1 = pb.Literal(xls::UBits(1, 1), body_loc); @@ -1259,6 +1349,8 @@ Translator::GenerateFSMInvocation(PreparedBlock& prepared, xls::ProcBuilder& pb, XLSCC_CHECK(prepared.token.valid(), body_loc); } + XLSCC_CHECK(last_ret_val.valid(), body_loc); + return GenerateFSMInvocationReturn{ .return_value = last_ret_val, .returns_this_activation = returns_this_activation_vars, @@ -1341,9 +1433,12 @@ absl::StatusOr Translator::GenerateSubFSM( GetFlexTupleField(first_ret_val, context_out_ret_idx, outer_prepared.xls_func->return_value_count, body_loc); - xls::BValue context_out = pb.TupleIndex(ret_io_value, /*idx=*/0, body_loc); - xls::BValue enter_condition = - pb.TupleIndex(ret_io_value, /*idx=*/1, body_loc); + xls::BValue context_out = pb.TupleIndex( + ret_io_value, /*idx=*/0, body_loc, /*name=*/ + absl::StrFormat("%s_context_out", sub_proc_invoked->name_prefix)); + xls::BValue enter_condition = pb.TupleIndex( + ret_io_value, /*idx=*/1, body_loc, /*name=*/ + absl::StrFormat("%s_enter_condition", sub_proc_invoked->name_prefix)); CHECK_EQ(enter_condition.GetType()->GetFlatBitCount(), 1); if (generate_fsms_for_pipelined_loops_ && @@ -1461,18 +1556,29 @@ absl::StatusOr Translator::GenerateIOInvoke( condition = ConditionWithExtra(pb, condition, invoke, op_loc); xls::BValue receive; if (op.is_blocking) { - receive = pb.ReceiveIf(xls_channel, before_token, condition, op_loc); + receive = pb.ReceiveIf(xls_channel, before_token, condition, op_loc, + /*name=*/Debug_OpName(op)); } else { - receive = - pb.ReceiveIfNonBlocking(xls_channel, before_token, condition, op_loc); + receive = pb.ReceiveIfNonBlocking(xls_channel, before_token, condition, + op_loc, /*name=*/Debug_OpName(op)); } - new_token = pb.TupleIndex(receive, 0); + new_token = + pb.TupleIndex(receive, 0, op_loc, + /*name=*/absl::StrFormat("%s_token", Debug_OpName(op))); xls::BValue in_val; if (op.is_blocking) { - in_val = pb.TupleIndex(receive, 1); + in_val = + pb.TupleIndex(receive, 1, op_loc, + /*name=*/absl::StrFormat("%s_value", Debug_OpName(op))); } else { - in_val = pb.Tuple({pb.TupleIndex(receive, 1), pb.TupleIndex(receive, 2)}); + in_val = pb.Tuple( + {pb.TupleIndex( + receive, 1, op_loc, + /*name=*/absl::StrFormat("%s_value", Debug_OpName(op))), + pb.TupleIndex( + receive, 2, op_loc, + /*name=*/absl::StrFormat("%s_valid", Debug_OpName(op)))}); } arg_io_val = in_val; } else if (op.op == OpType::kSend) { @@ -1481,14 +1587,16 @@ absl::StatusOr Translator::GenerateIOInvoke( unused_xls_channel_ops_.remove({xls_channel, /*is_send=*/true}); CHECK_NE(xls_channel, nullptr); - xls::BValue val = pb.TupleIndex(ret_io_value, 0, op_loc); - xls::BValue condition = - pb.TupleIndex(ret_io_value, 1, op_loc, - absl::StrFormat("%s_pred", xls_channel->name())); + xls::BValue val = + pb.TupleIndex(ret_io_value, 0, op_loc, + /*name=*/absl::StrFormat("%s_value", Debug_OpName(op))); + xls::BValue condition = pb.TupleIndex( + ret_io_value, 1, op_loc, absl::StrFormat("%s_pred", Debug_OpName(op))); CHECK_EQ(condition.GetType()->GetFlatBitCount(), 1); condition = ConditionWithExtra(pb, condition, invoke, op_loc); - new_token = pb.SendIf(xls_channel, before_token, condition, val, op_loc); + new_token = pb.SendIf(xls_channel, before_token, condition, val, op_loc, + /*name=*/absl::StrFormat("%s", Debug_OpName(op))); } else if (op.op == OpType::kRead) { CHECK_EQ(bundle_ptr->regular, nullptr); CHECK_NE(bundle_ptr->read_request, nullptr); @@ -1499,8 +1607,12 @@ absl::StatusOr Translator::GenerateIOInvoke( unused_xls_channel_ops_.remove( {bundle_ptr->read_response, /*is_send=*/false}); - xls::BValue addr = pb.TupleIndex(ret_io_value, 0, op_loc); - xls::BValue condition = pb.TupleIndex(ret_io_value, 1, op_loc); + xls::BValue addr = + pb.TupleIndex(ret_io_value, 0, op_loc, + /*name=*/absl::StrFormat("%s_addr", Debug_OpName(op))); + xls::BValue condition = + pb.TupleIndex(ret_io_value, 1, op_loc, + /*name=*/absl::StrFormat("%s_cond", Debug_OpName(op))); CHECK_EQ(condition.GetType()->GetFlatBitCount(), 1); condition = ConditionWithExtra(pb, condition, invoke, op_loc); @@ -1508,14 +1620,22 @@ absl::StatusOr Translator::GenerateIOInvoke( xls::BValue mask = pb.Literal(xls::Value::Tuple({}), op_loc); xls::BValue send_tuple_with_mask = pb.Tuple({addr, mask}, op_loc); new_token = pb.SendIf(bundle_ptr->read_request, before_token, condition, - send_tuple_with_mask, op_loc); + send_tuple_with_mask, op_loc, + /*name=*/absl::StrFormat("%s", Debug_OpName(op))); xls::BValue receive = - pb.ReceiveIf(bundle_ptr->read_response, new_token, condition, op_loc); - - new_token = pb.TupleIndex(receive, 0); - xls::BValue response_tup = pb.TupleIndex(receive, 1, op_loc); - xls::BValue response = pb.TupleIndex(response_tup, 0, op_loc); + pb.ReceiveIf(bundle_ptr->read_response, new_token, condition, op_loc, + /*name=*/Debug_OpName(op)); + + new_token = + pb.TupleIndex(receive, 0, op_loc, + /*name=*/absl::StrFormat("%s_token", Debug_OpName(op))); + xls::BValue response_tup = pb.TupleIndex( + receive, 1, op_loc, + /*name=*/absl::StrFormat("%s_response_tup", Debug_OpName(op))); + xls::BValue response = pb.TupleIndex( + response_tup, 0, op_loc, + /*name=*/absl::StrFormat("%s_response", Debug_OpName(op))); arg_io_val = response; } else if (op.op == OpType::kWrite) { @@ -1529,25 +1649,34 @@ absl::StatusOr Translator::GenerateIOInvoke( {bundle_ptr->write_response, /*is_send=*/false}); // This has (addr, value) - xls::BValue send_tuple = pb.TupleIndex(ret_io_value, 0, op_loc); + xls::BValue send_tuple = pb.TupleIndex( + ret_io_value, 0, op_loc, + /*name=*/absl::StrFormat("%s_send_tup", Debug_OpName(op))); xls::BValue condition = pb.TupleIndex( - ret_io_value, 1, op_loc, - absl::StrFormat("%s_pred", bundle_ptr->write_request->name())); + ret_io_value, 1, op_loc, absl::StrFormat("%s_pred", Debug_OpName(op))); CHECK_EQ(condition.GetType()->GetFlatBitCount(), 1); condition = ConditionWithExtra(pb, condition, invoke, op_loc); // This has (addr, value, mask) - xls::BValue addr = pb.TupleIndex(send_tuple, 0, op_loc); - xls::BValue value = pb.TupleIndex(send_tuple, 1, op_loc); + xls::BValue addr = + pb.TupleIndex(send_tuple, 0, op_loc, + /*name=*/absl::StrFormat("%s_addr", Debug_OpName(op))); + xls::BValue value = + pb.TupleIndex(send_tuple, 1, op_loc, + /*name=*/absl::StrFormat("%s_value", Debug_OpName(op))); // TODO(google/xls#861): supported masked memory operations. xls::BValue mask = pb.Literal(xls::Value::Tuple({}), op_loc); xls::BValue send_tuple_with_mask = pb.Tuple({addr, value, mask}, op_loc); new_token = pb.SendIf(bundle_ptr->write_request, before_token, condition, - send_tuple_with_mask, op_loc); + send_tuple_with_mask, op_loc, + /*name=*/absl::StrFormat("%s", Debug_OpName(op))); xls::BValue receive = - pb.ReceiveIf(bundle_ptr->write_response, new_token, condition, op_loc); - new_token = pb.TupleIndex(receive, 0); + pb.ReceiveIf(bundle_ptr->write_response, new_token, condition, op_loc, + /*name=*/absl::StrFormat("%s", Debug_OpName(op))); + new_token = + pb.TupleIndex(receive, 0, op_loc, + /*name=*/absl::StrFormat("%s_token", Debug_OpName(op))); // Ignore received value, should be an empty tuple } else if (op.op == OpType::kTrace) { XLS_ASSIGN_OR_RETURN( @@ -1565,7 +1694,9 @@ absl::StatusOr Translator::GenerateIOInvoke( // The function is invoked again with the value received from the channel // for each read() Op. The final invocation will produce all complete // outputs. - last_ret_val = pb.Invoke(prepared.args, prepared.xls_func->xls_func, op_loc); + last_ret_val = + pb.Invoke(prepared.args, prepared.xls_func->xls_func, op_loc, + /*name=*/absl::StrFormat("invoke_%s", Debug_OpName(invoke.op))); XLSCC_CHECK(last_ret_val.valid(), op_loc); return new_token; } @@ -1630,13 +1761,16 @@ absl::StatusOr Translator::GenerateTrace( const uint64_t tuple_count = trace_out_value.GetType()->AsTupleOrDie()->size(); CHECK_GE(tuple_count, 1); - xls::BValue condition = pb.TupleIndex(trace_out_value, 0, op.op_location); + xls::BValue condition = + pb.TupleIndex(trace_out_value, 0, op.op_location, + /*name=*/absl::StrFormat("%s_cond", Debug_OpName(op))); CHECK_EQ(condition.GetType()->GetFlatBitCount(), 1); condition = ConditionWithExtra(pb, condition, invoke, op.op_location); std::vector args; for (int tuple_idx = 1; tuple_idx < tuple_count; ++tuple_idx) { - xls::BValue arg = - pb.TupleIndex(trace_out_value, tuple_idx, op.op_location); + xls::BValue arg = pb.TupleIndex( + trace_out_value, tuple_idx, op.op_location, + /*name=*/absl::StrFormat("%s_arg_%i", Debug_OpName(op), tuple_idx)); args.push_back(arg); } @@ -1847,8 +1981,12 @@ Translator::GenerateIRBlockPrepare( unused_xls_channel_ops_.remove({xls_channel, /*is_send=*/false}); xls::BValue receive = pb.Receive(xls_channel, prepared.token); - prepared.token = pb.TupleIndex(receive, 0); - xls::BValue direct_in_value = pb.TupleIndex(receive, 1); + prepared.token = pb.TupleIndex( + receive, 0, body_loc, + /*name=*/absl::StrFormat("%s_token", xls_channel->name())); + xls::BValue direct_in_value = pb.TupleIndex( + receive, 1, body_loc, + /*name=*/absl::StrFormat("%s_value", xls_channel->name())); prepared.args.push_back(direct_in_value); diff --git a/xls/contrib/xlscc/translate_loops.cc b/xls/contrib/xlscc/translate_loops.cc index 06468be3f2..351f5195c8 100644 --- a/xls/contrib/xlscc/translate_loops.cc +++ b/xls/contrib/xlscc/translate_loops.cc @@ -427,7 +427,8 @@ absl::Status Translator::GenerateIR_PipelinedLoop( } } - lvalue_conditions_tuple = context().fb->Tuple(lvalue_conditions, loc); + lvalue_conditions_tuple = context().fb->Tuple(lvalue_conditions, loc, + /*name=*/"lvalue_conditions"); std::vector> lvalue_conds_tuple_fields; lvalue_conds_tuple_fields.resize(lvalue_conditions.size(), std::make_shared()); @@ -547,7 +548,8 @@ absl::Status Translator::GenerateIR_PipelinedLoop( // Must match if(uses_on_reset) below context_tuple_out = CValue( context().fb->Tuple({outer_on_reset_value, context_struct_out.rvalue(), - lvalue_conditions_tuple}), + lvalue_conditions_tuple}, + loc, /*name=*/"context_out_tuple_inner"), context_tuple_type); } @@ -649,8 +651,13 @@ absl::Status Translator::GenerateIR_PipelinedLoop( context_tuple_out = CValue( context().fb->Tuple( {on_reset_cval.rvalue(), - context().fb->TupleIndex(context_tuple_out.rvalue(), 1, loc), - context().fb->TupleIndex(context_tuple_out.rvalue(), 2, loc)}), + context().fb->TupleIndex(context_tuple_out.rvalue(), 1, loc, + /*name=*/"context_out_outer_struct"), + context().fb->TupleIndex( + context_tuple_out.rvalue(), 2, loc, + /*name=*/"context_out_outer_lvalue_conditions")}, + loc, + /*name=*/"context_out_tuple_outer"), context_tuple_out.type()); } @@ -661,7 +668,8 @@ absl::Status Translator::GenerateIR_PipelinedLoop( op.op = OpType::kSend; std::vector sp = {context_tuple_out.rvalue(), context().full_condition_bval(loc)}; - op.ret_value = context().fb->Tuple(sp, loc); + op.ret_value = + context().fb->Tuple(sp, loc, /*name=*/"context_out_send_tup"); XLS_ASSIGN_OR_RETURN(ctx_out_op_ptr, AddOpToChannel(op, context_out_channel, loc)); } @@ -1055,9 +1063,14 @@ absl::Status Translator::GenerateIR_PipelinedLoopProc( xls::BValue receive = pb.ReceiveIf(context_out_channel->generated.value(), token, - /*pred=*/placeholder_cond, loc); - token = pb.TupleIndex(receive, 0); - xls::BValue received_context_tuple = pb.TupleIndex(receive, 1); + /*pred=*/placeholder_cond, loc, + /*name=*/absl::StrFormat("%s_receive_context", name_prefix)); + token = pb.TupleIndex( + receive, 0, loc, + /*name=*/absl::StrFormat("%s_receive_context_token", name_prefix)); + xls::BValue received_context_tuple = pb.TupleIndex( + receive, 1, loc, + /*name=*/absl::StrFormat("%s_receive_context_tup", name_prefix)); XLS_ASSIGN_OR_RETURN( PipelinedLoopContentsReturn contents_ret, @@ -1183,11 +1196,16 @@ Translator::GenerateIR_PipelinedLoopContents( xls::BValue token = token_in; - xls::BValue received_on_reset = pb.TupleIndex(received_context_tuple, 0, loc); - xls::BValue received_context = pb.TupleIndex(received_context_tuple, 1, loc); + xls::BValue received_on_reset = pb.TupleIndex( + received_context_tuple, 0, loc, + /*name=*/absl::StrFormat("%s_receive_on_reset", name_prefix)); + xls::BValue received_context = pb.TupleIndex( + received_context_tuple, 1, loc, + /*name=*/absl::StrFormat("%s_receive_context_data", name_prefix)); - xls::BValue received_lvalue_conds = - pb.TupleIndex(received_context_tuple, 2, loc); + xls::BValue received_lvalue_conds = pb.TupleIndex( + received_context_tuple, 2, loc, + /*name=*/absl::StrFormat("%s_receive_context_lvalues", name_prefix)); xls::BValue use_context_in = last_iter_broke_in; @@ -1401,7 +1419,10 @@ Translator::GenerateIR_PipelinedLoopContents( xls::BValue ret_next = pb.TupleIndex(fsm_ret.return_value, - prepared.return_index_for_static.at(namedecl), loc); + prepared.return_index_for_static.at(namedecl), loc, + /*name=*/ + absl::StrFormat("%s_fsm_ret_static_%s", name_prefix, + namedecl->getNameAsString())); xls::BValue state_elem_bval( prepared.state_element_for_variable.at(namedecl), &pb); diff --git a/xls/contrib/xlscc/translator.cc b/xls/contrib/xlscc/translator.cc index 101325505f..1ee773143e 100644 --- a/xls/contrib/xlscc/translator.cc +++ b/xls/contrib/xlscc/translator.cc @@ -44,6 +44,7 @@ #include "absl/status/statusor.h" #include "absl/strings/match.h" #include "absl/strings/str_format.h" +#include "absl/strings/str_join.h" #include "absl/strings/str_replace.h" #include "absl/types/span.h" #include "clang/include/clang/AST/APValue.h" @@ -5202,6 +5203,14 @@ std::string Debug_NodeToInfix(const xls::Node* node, int64_t& n_printed) { return absl::StrFormat("%s(%i)", Debug_NodeToInfix(tup, n_printed), ti->index()); } + if (node->Is()) { + const xls::Tuple* tp = node->As(); + std::vector operand_strings; + for (const xls::Node* op : tp->operands()) { + operand_strings.push_back(Debug_NodeToInfix(op, n_printed)); + } + return std::string("(") + absl::StrJoin(operand_strings, ", ") + ")"; + } if (node->Is()) { const xls::UnOp* op = node->As(); if (op->op() == xls::Op::kNot) { @@ -5259,6 +5268,37 @@ std::string Debug_NodeToInfix(const xls::Node* node, int64_t& n_printed) { typeid(*node).name()); } +std::string Debug_OpName(const IOOp& op) { + if (op.op == OpType::kTrace) { + return "trace"; + } + if (op.channel != nullptr) { + std::string op_type_name; + switch (op.op) { + case OpType::kSend: + op_type_name = "send"; + break; + case OpType::kRecv: + op_type_name = "recv"; + break; + case OpType::kRead: + op_type_name = "read"; + break; + case OpType::kWrite: + op_type_name = "write"; + break; + default: + CHECK_EQ("Op type doesn't make sense here", nullptr); + } + return absl::StrFormat("%s_%s", op.channel->unique_name, op_type_name); + } + if (!op.final_param_name.empty()) { + return op.final_param_name; + } + CHECK_EQ("Unable to form name for op", nullptr); + return "TODO_OpName"; +} + std::string Debug_VariablesChangedBetween(const TranslationContext& before, const TranslationContext& after) { std::ostringstream ostr; @@ -5284,6 +5324,24 @@ std::string Debug_VariablesChangedBetween(const TranslationContext& before, return ostr.str(); } +std::optional> Debug_DeeplyCheckOperandsFromPrev( + const xls::Node* node, + const absl::flat_hash_set& prev_state_io_nodes) { + for (const xls::Node* op : node->operands()) { + if (prev_state_io_nodes.contains(op)) { + return std::list({op}); + } + std::optional> opt_path = + Debug_DeeplyCheckOperandsFromPrev(op, prev_state_io_nodes); + if (opt_path.has_value()) { + std::list path = opt_path.value(); + path.push_front(op); + return path; + } + } + return std::nullopt; +} + absl::StatusOr Translator::CheckAssumptions( absl::Span positive_nodes, absl::Span negative_nodes, Z3_solver& solver, diff --git a/xls/contrib/xlscc/translator.h b/xls/contrib/xlscc/translator.h index 6435b405df..064c50cc41 100644 --- a/xls/contrib/xlscc/translator.h +++ b/xls/contrib/xlscc/translator.h @@ -111,8 +111,7 @@ class CVoidType : public CType { absl::Status GetMetadata(Translator& translator, xlscc_metadata::Type* output, absl::flat_hash_set& aliases_used) const override; - absl::Status GetMetadataValue(Translator& translator, - ConstValue const_value, + absl::Status GetMetadataValue(Translator& translator, ConstValue const_value, xlscc_metadata::Value* output) const override; bool operator==(const CType& o) const override; @@ -129,8 +128,7 @@ class CBitsType : public CType { absl::Status GetMetadata(Translator& translator, xlscc_metadata::Type* output, absl::flat_hash_set& aliases_used) const override; - absl::Status GetMetadataValue(Translator& translator, - ConstValue const_value, + absl::Status GetMetadataValue(Translator& translator, ConstValue const_value, xlscc_metadata::Value* output) const override; bool operator==(const CType& o) const override; @@ -151,8 +149,7 @@ class CIntType : public CType { absl::Status GetMetadata(Translator& translator, xlscc_metadata::Type* output, absl::flat_hash_set& aliases_used) const override; - absl::Status GetMetadataValue(Translator& translator, - ConstValue const_value, + absl::Status GetMetadataValue(Translator& translator, ConstValue const_value, xlscc_metadata::Value* output) const override; bool operator==(const CType& o) const override; @@ -213,8 +210,7 @@ class CEnumType : public CIntType { absl::Status GetMetadata(Translator& translator, xlscc_metadata::Type* output, absl::flat_hash_set& aliases_used) const override; - absl::Status GetMetadataValue(Translator& translator, - ConstValue const_value, + absl::Status GetMetadataValue(Translator& translator, ConstValue const_value, xlscc_metadata::Value* output) const override; bool operator==(const CType& o) const override; @@ -241,8 +237,7 @@ class CBoolType : public CType { absl::Status GetMetadata(Translator& translator, xlscc_metadata::Type* output, absl::flat_hash_set& aliases_used) const override; - absl::Status GetMetadataValue(Translator& translator, - ConstValue const_value, + absl::Status GetMetadataValue(Translator& translator, ConstValue const_value, xlscc_metadata::Value* output) const override; bool operator==(const CType& o) const override; bool StoredAsXLSBits() const override; @@ -279,8 +274,7 @@ class CStructType : public CType { absl::Status GetMetadata(Translator& translator, xlscc_metadata::Type* output, absl::flat_hash_set& aliases_used) const override; - absl::Status GetMetadataValue(Translator& translator, - ConstValue const_value, + absl::Status GetMetadataValue(Translator& translator, ConstValue const_value, xlscc_metadata::Value* output) const override; bool operator==(const CType& o) const override; absl::StatusOr ContainsLValues(Translator& translator) const override; @@ -314,8 +308,7 @@ class CInternalTuple : public CType { absl::Status GetMetadata(Translator& translator, xlscc_metadata::Type* output, absl::flat_hash_set& aliases_used) const override; - absl::Status GetMetadataValue(Translator& translator, - ConstValue const_value, + absl::Status GetMetadataValue(Translator& translator, ConstValue const_value, xlscc_metadata::Value* output) const override; bool operator==(const CType& o) const override; @@ -349,8 +342,7 @@ class CInstantiableTypeAlias : public CType { absl::Status GetMetadata(Translator& translator, xlscc_metadata::Type* output, absl::flat_hash_set& aliases_used) const override; - absl::Status GetMetadataValue(Translator& translator, - ConstValue const_value, + absl::Status GetMetadataValue(Translator& translator, ConstValue const_value, xlscc_metadata::Value* output) const override; explicit operator std::string() const override; int GetBitWidth() const override; @@ -370,8 +362,7 @@ class CArrayType : public CType { absl::Status GetMetadata(Translator& translator, xlscc_metadata::Type* output, absl::flat_hash_set& aliases_used) const override; - absl::Status GetMetadataValue(Translator& translator, - ConstValue const_value, + absl::Status GetMetadataValue(Translator& translator, ConstValue const_value, xlscc_metadata::Value* output) const override; absl::StatusOr ContainsLValues(Translator& translator) const override; @@ -393,8 +384,7 @@ class CPointerType : public CType { absl::Status GetMetadata(Translator& translator, xlscc_metadata::Type* output, absl::flat_hash_set& aliases_used) const override; - absl::Status GetMetadataValue(Translator& translator, - ConstValue const_value, + absl::Status GetMetadataValue(Translator& translator, ConstValue const_value, xlscc_metadata::Value* output) const override; absl::StatusOr ContainsLValues(Translator& translator) const override; @@ -414,8 +404,7 @@ class CReferenceType : public CType { absl::Status GetMetadata(Translator& translator, xlscc_metadata::Type* output, absl::flat_hash_set& aliases_used) const override; - absl::Status GetMetadataValue(Translator& translator, - ConstValue const_value, + absl::Status GetMetadataValue(Translator& translator, ConstValue const_value, xlscc_metadata::Value* output) const override; absl::StatusOr ContainsLValues(Translator& translator) const override; @@ -442,8 +431,7 @@ class CChannelType : public CType { absl::Status GetMetadata(Translator& translator, xlscc_metadata::Type* output, absl::flat_hash_set& aliases_used) const override; - absl::Status GetMetadataValue(Translator& translator, - ConstValue const_value, + absl::Status GetMetadataValue(Translator& translator, ConstValue const_value, xlscc_metadata::Value* output) const override; std::shared_ptr GetItemType() const; @@ -923,6 +911,7 @@ int Debug_CountNodes(const xls::Node* node, std::set& visited); std::string Debug_NodeToInfix(xls::BValue bval); std::string Debug_NodeToInfix(const xls::Node* node, int64_t& n_printed); +std::string Debug_OpName(const IOOp& op); // Encapsulates a context for translating Clang AST to XLS IR. // This is roughly equivalent to a "scope" in C++. There will typically @@ -1086,6 +1075,10 @@ struct TranslationContext { std::string Debug_VariablesChangedBetween(const TranslationContext& before, const TranslationContext& after); +std::optional> Debug_DeeplyCheckOperandsFromPrev( + const xls::Node* node, + const absl::flat_hash_set& prev_state_io_nodes); + enum IOOpOrdering { kNone = 0, kChannelWise = 1, @@ -1102,7 +1095,8 @@ enum DebugIrTraceFlags { DebugIrTraceFlags_None = 0, DebugIrTraceFlags_LoopContext = 1, DebugIrTraceFlags_LoopControl = 2, - DebugIrTraceFlags_FSMStates = 4 + DebugIrTraceFlags_FSMStates = 4, + DebugIrTraceFlags_PrevStateIOReferences = 8 }; class Translator { @@ -1706,6 +1700,16 @@ class Translator { PreparedBlock& prepared, xls::ProcBuilder& pb, int nesting_level, const xls::SourceInfo& body_loc); + struct LayoutFSMStatesReturn { + absl::flat_hash_map state_by_io_op; + std::vector> states; + bool has_pipelined_loop = false; + }; + + absl::StatusOr LayoutFSMStates( + PreparedBlock& prepared, xls::ProcBuilder& pb, + const xls::SourceInfo& body_loc); + std::set GetChannelsUsedByOp( const IOOp& op, const PipelinedLoopSubProc* sub_procp, const xls::SourceInfo& loc); @@ -1760,9 +1764,9 @@ class Translator { }; // Checks if an expression is an IO op, and if so, generates the value // to replace it in IR generation. - absl::StatusOr InterceptIOOp( - const clang::Expr* expr, const xls::SourceInfo& loc, - CValue assignment_value = CValue()); + absl::StatusOr InterceptIOOp(const clang::Expr* expr, + const xls::SourceInfo& loc, + CValue assignment_value = CValue()); // IOOp must have io_call, and op members filled in // This will add a parameter for IO input if needed, diff --git a/xls/contrib/xlscc/unit_tests/testdata/translator_verilog_test_IOProcComboGenNToOneMux.svtxt b/xls/contrib/xlscc/unit_tests/testdata/translator_verilog_test_IOProcComboGenNToOneMux.svtxt index d1a0c2f0cc..fc82bd8977 100644 --- a/xls/contrib/xlscc/unit_tests/testdata/translator_verilog_test_IOProcComboGenNToOneMux.svtxt +++ b/xls/contrib/xlscc/unit_tests/testdata/translator_verilog_test_IOProcComboGenNToOneMux.svtxt @@ -15,12 +15,14 @@ module foo_proc( wire [31:0] in2_select; wire [31:0] in1_select; wire p0_all_active_inputs_valid; + wire [31:0] out_send_value; assign in1_op0_ret_io_value = dir == 32'h0000_0000; assign in2_op0_ret_io_value = ~in1_op0_ret_io_value; assign in2_select = in2_op0_ret_io_value ? in2 : 32'h0000_0000; assign in1_select = in1_op0_ret_io_value ? in1 : 32'h0000_0000; assign p0_all_active_inputs_valid = (~in1_op0_ret_io_value | in1_vld) & (~in2_op0_ret_io_value | in2_vld); - assign out = in1_op0_ret_io_value ? in1_select : in2_select; + assign out_send_value = in1_op0_ret_io_value ? in1_select : in2_select; + assign out = out_send_value; assign out_vld = p0_all_active_inputs_valid & 1'h1 & 1'h1; assign in1_rdy = in1_op0_ret_io_value & out_rdy; assign in2_rdy = in2_op0_ret_io_value & out_rdy; diff --git a/xls/contrib/xlscc/unit_tests/testdata/translator_verilog_test_IOProcComboGenNToOneMux.vtxt b/xls/contrib/xlscc/unit_tests/testdata/translator_verilog_test_IOProcComboGenNToOneMux.vtxt index d1a0c2f0cc..fc82bd8977 100644 --- a/xls/contrib/xlscc/unit_tests/testdata/translator_verilog_test_IOProcComboGenNToOneMux.vtxt +++ b/xls/contrib/xlscc/unit_tests/testdata/translator_verilog_test_IOProcComboGenNToOneMux.vtxt @@ -15,12 +15,14 @@ module foo_proc( wire [31:0] in2_select; wire [31:0] in1_select; wire p0_all_active_inputs_valid; + wire [31:0] out_send_value; assign in1_op0_ret_io_value = dir == 32'h0000_0000; assign in2_op0_ret_io_value = ~in1_op0_ret_io_value; assign in2_select = in2_op0_ret_io_value ? in2 : 32'h0000_0000; assign in1_select = in1_op0_ret_io_value ? in1 : 32'h0000_0000; assign p0_all_active_inputs_valid = (~in1_op0_ret_io_value | in1_vld) & (~in2_op0_ret_io_value | in2_vld); - assign out = in1_op0_ret_io_value ? in1_select : in2_select; + assign out_send_value = in1_op0_ret_io_value ? in1_select : in2_select; + assign out = out_send_value; assign out_vld = p0_all_active_inputs_valid & 1'h1 & 1'h1; assign in1_rdy = in1_op0_ret_io_value & out_rdy; assign in2_rdy = in2_op0_ret_io_value & out_rdy; diff --git a/xls/contrib/xlscc/unit_tests/testdata/translator_verilog_test_IOProcComboGenOneToNMux.svtxt b/xls/contrib/xlscc/unit_tests/testdata/translator_verilog_test_IOProcComboGenOneToNMux.svtxt index b612c04bef..31395199ac 100644 --- a/xls/contrib/xlscc/unit_tests/testdata/translator_verilog_test_IOProcComboGenOneToNMux.svtxt +++ b/xls/contrib/xlscc/unit_tests/testdata/translator_verilog_test_IOProcComboGenOneToNMux.svtxt @@ -10,17 +10,17 @@ module foo_proc( output wire out2_vld, output wire in_rdy ); - wire out1_pred; - wire out2_pred; + wire out1_send_pred; + wire out2_send_pred; wire literal_93; wire p0_all_active_outputs_ready; - assign out1_pred = dir == 32'h0000_0000; - assign out2_pred = ~out1_pred; + assign out1_send_pred = dir == 32'h0000_0000; + assign out2_send_pred = ~out1_send_pred; assign literal_93 = 1'h1; - assign p0_all_active_outputs_ready = (~out1_pred | out1_rdy) & (~out2_pred | out2_rdy); + assign p0_all_active_outputs_ready = (~out1_send_pred | out1_rdy) & (~out2_send_pred | out2_rdy); assign out1 = in; assign out2 = in; - assign out1_vld = in_vld & literal_93 & literal_93 & out1_pred; - assign out2_vld = in_vld & literal_93 & literal_93 & out2_pred; + assign out1_vld = in_vld & literal_93 & literal_93 & out1_send_pred; + assign out2_vld = in_vld & literal_93 & literal_93 & out2_send_pred; assign in_rdy = p0_all_active_outputs_ready; endmodule diff --git a/xls/contrib/xlscc/unit_tests/testdata/translator_verilog_test_IOProcComboGenOneToNMux.vtxt b/xls/contrib/xlscc/unit_tests/testdata/translator_verilog_test_IOProcComboGenOneToNMux.vtxt index b612c04bef..31395199ac 100644 --- a/xls/contrib/xlscc/unit_tests/testdata/translator_verilog_test_IOProcComboGenOneToNMux.vtxt +++ b/xls/contrib/xlscc/unit_tests/testdata/translator_verilog_test_IOProcComboGenOneToNMux.vtxt @@ -10,17 +10,17 @@ module foo_proc( output wire out2_vld, output wire in_rdy ); - wire out1_pred; - wire out2_pred; + wire out1_send_pred; + wire out2_send_pred; wire literal_93; wire p0_all_active_outputs_ready; - assign out1_pred = dir == 32'h0000_0000; - assign out2_pred = ~out1_pred; + assign out1_send_pred = dir == 32'h0000_0000; + assign out2_send_pred = ~out1_send_pred; assign literal_93 = 1'h1; - assign p0_all_active_outputs_ready = (~out1_pred | out1_rdy) & (~out2_pred | out2_rdy); + assign p0_all_active_outputs_ready = (~out1_send_pred | out1_rdy) & (~out2_send_pred | out2_rdy); assign out1 = in; assign out2 = in; - assign out1_vld = in_vld & literal_93 & literal_93 & out1_pred; - assign out2_vld = in_vld & literal_93 & literal_93 & out2_pred; + assign out1_vld = in_vld & literal_93 & literal_93 & out1_send_pred; + assign out2_vld = in_vld & literal_93 & literal_93 & out2_send_pred; assign in_rdy = p0_all_active_outputs_ready; endmodule diff --git a/xls/contrib/xlscc/unit_tests/translator_proc_test.cc b/xls/contrib/xlscc/unit_tests/translator_proc_test.cc index 19375e6ac2..9ddc01ef04 100644 --- a/xls/contrib/xlscc/unit_tests/translator_proc_test.cc +++ b/xls/contrib/xlscc/unit_tests/translator_proc_test.cc @@ -8405,6 +8405,48 @@ TEST_P(TranslatorProcTest, ForPipelinedStaticSharedInBody) { : 0); } +TEST_F(TranslatorProcTestWithoutFSMParam, MergedStatesIOFeedThrough) { + const std::string content = R"( + class Block { + public: + __xls_channel& in; + __xls_channel& out; + + #pragma hls_top + void foo() { + int a = in.read(); + int b = 100; + #pragma hls_pipeline_init_interval 1 + for(long i=1;i<=3;++i) { + out.write(a); + b = a; + } + out.write(b); + } + };)"; + + generate_fsms_for_pipelined_loops_ = true; + merge_states_ = true; + split_states_on_channel_ops_ = true; + + absl::flat_hash_map> inputs; + inputs["in"] = {xls::Value(xls::SBits(11, 32)), + xls::Value(xls::SBits(33, 32))}; + + { + absl::flat_hash_map> outputs; + outputs["out"] = { + xls::Value(xls::SBits(11, 32)), xls::Value(xls::SBits(11, 32)), + xls::Value(xls::SBits(11, 32)), xls::Value(xls::SBits(11, 32)), + xls::Value(xls::SBits(33, 32)), xls::Value(xls::SBits(33, 32)), + xls::Value(xls::SBits(33, 32)), xls::Value(xls::SBits(33, 32))}; + ProcTest(content, /*block_spec=*/std::nullopt, inputs, outputs, + /* min_ticks = */ 1, + /* max_ticks = */ 100, + /* top_level_init_interval = */ 1); + } +} + } // namespace } // namespace xlscc