/* function_base implementation for SiFive custom 'V' Extension for GNU compiler.
Copyright (C) 2024-2025 Free Software Foundation, Inc.
Contributed by SiFive and PLCT Lab.
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
GCC is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
. */
#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "tm.h"
#include "tree.h"
#include "rtl.h"
#include "tm_p.h"
#include "memmodel.h"
#include "insn-codes.h"
#include "optabs.h"
#include "recog.h"
#include "expr.h"
#include "basic-block.h"
#include "function.h"
#include "fold-const.h"
#include "gimple.h"
#include "gimple-iterator.h"
#include "gimplify.h"
#include "explow.h"
#include "emit-rtl.h"
#include "tree-vector-builder.h"
#include "rtx-vector-builder.h"
#include "riscv-vector-builtins.h"
#include "riscv-vector-builtins-shapes.h"
#include "sifive-vector-builtins-bases.h"
#include "riscv-vector-builtins-bases.h"
using namespace riscv_vector;
namespace riscv_vector {
/* Implements SiFive vqmacc. */
class sf_vqmacc : public function_base
{
public:
bool has_merge_operand_p () const override { return false; }
bool apply_mask_policy_p () const override { return false; }
bool use_mask_predication_p () const override { return false; }
bool can_be_overloaded_p (enum predication_type_index pred) const override
{
return pred == PRED_TYPE_tu;
}
rtx expand (function_expander &e) const override
{
if (e.op_info->op == OP_TYPE_4x8x4)
return e.use_widen_ternop_insn (
code_for_pred_matrix_mul_plus_qoq (SIGN_EXTEND, e.vector_mode ()));
if (e.op_info->op == OP_TYPE_2x8x2)
return e.use_widen_ternop_insn (
code_for_pred_matrix_mul_plus_dod (SIGN_EXTEND, e.vector_mode ()));
gcc_unreachable ();
}
};
/* Implements SiFive vqmaccu. */
class sf_vqmaccu : public function_base
{
public:
bool has_merge_operand_p () const override { return false; }
bool apply_mask_policy_p () const override { return false; }
bool use_mask_predication_p () const override { return false; }
bool can_be_overloaded_p (enum predication_type_index pred) const override
{
return pred == PRED_TYPE_tu;
}
rtx expand (function_expander &e) const override
{
if (e.op_info->op == OP_TYPE_4x8x4)
return e.use_widen_ternop_insn (
code_for_pred_matrix_mul_plus_qoq (ZERO_EXTEND, e.vector_mode ()));
if (e.op_info->op == OP_TYPE_2x8x2)
return e.use_widen_ternop_insn (
code_for_pred_matrix_mul_plus_dod (ZERO_EXTEND, e.vector_mode ()));
gcc_unreachable ();
}
};
/* Implements SiFive vqmaccsu. */
class sf_vqmaccsu : public function_base
{
public:
bool has_merge_operand_p () const override { return false; }
bool apply_mask_policy_p () const override { return false; }
bool use_mask_predication_p () const override { return false; }
bool can_be_overloaded_p (enum predication_type_index pred) const override
{
return pred == PRED_TYPE_tu;
}
rtx expand (function_expander &e) const override
{
if (e.op_info->op == OP_TYPE_4x8x4)
return e.use_widen_ternop_insn (
code_for_pred_matrix_mul_plussu_qoq (e.vector_mode ()));
if (e.op_info->op == OP_TYPE_2x8x2)
return e.use_widen_ternop_insn (
code_for_pred_matrix_mul_plussu_dod (e.vector_mode ()));
gcc_unreachable ();
}
};
/* Implements SiFive vqmaccus. */
class sf_vqmaccus : public function_base
{
public:
bool has_merge_operand_p () const override { return false; }
bool apply_mask_policy_p () const override { return false; }
bool use_mask_predication_p () const override { return false; }
bool can_be_overloaded_p (enum predication_type_index pred) const override
{
return pred == PRED_TYPE_tu;
}
rtx expand (function_expander &e) const override
{
if (e.op_info->op == OP_TYPE_4x8x4)
return e.use_widen_ternop_insn (
code_for_pred_matrix_mul_plusus_qoq (e.vector_mode ()));
if (e.op_info->op == OP_TYPE_2x8x2)
return e.use_widen_ternop_insn (
code_for_pred_matrix_mul_plusus_dod (e.vector_mode ()));
gcc_unreachable ();
}
};
/* Implements SiFive vfnrclip. */
template
class sf_vfnrclip_x_f_qf : public function_base
{
public:
bool has_rounding_mode_operand_p () const override
{
return FRM_OP == HAS_FRM;
}
bool may_require_frm_p () const override { return true; }
bool can_be_overloaded_p (enum predication_type_index pred) const override
{
return pred != PRED_TYPE_none;
}
rtx expand (function_expander &e) const override
{
return e.use_exact_insn (
code_for_pred_sf_vfnrclip_x_f_qf (UNSPEC, e.vector_mode ()));
}
};
template
class sf_vfnrclip_xu_f_qf : public function_base
{
public:
bool has_rounding_mode_operand_p () const override
{
return FRM_OP == HAS_FRM;
}
bool may_require_frm_p () const override { return true; }
bool can_be_overloaded_p (enum predication_type_index pred) const override
{
return pred != PRED_TYPE_none;
}
rtx expand (function_expander &e) const override
{
return e.use_exact_insn (
code_for_pred_sf_vfnrclip_x_f_qf (UNSPEC, e.vector_mode ()));
}
};
static CONSTEXPR const sf_vqmacc sf_vqmacc_obj;
static CONSTEXPR const sf_vqmaccu sf_vqmaccu_obj;
static CONSTEXPR const sf_vqmaccsu sf_vqmaccsu_obj;
static CONSTEXPR const sf_vqmaccus sf_vqmaccus_obj;
static CONSTEXPR const sf_vfnrclip_x_f_qf sf_vfnrclip_x_f_qf_obj;
static CONSTEXPR const sf_vfnrclip_xu_f_qf sf_vfnrclip_xu_f_qf_obj;
/* Declare the function base NAME, pointing it to an instance
of class _obj. */
#define BASE(NAME) \
namespace bases { const function_base *const NAME = &NAME##_obj; }
BASE (sf_vqmacc)
BASE (sf_vqmaccu)
BASE (sf_vqmaccsu)
BASE (sf_vqmaccus)
BASE (sf_vfnrclip_x_f_qf)
BASE (sf_vfnrclip_xu_f_qf)
} // end namespace riscv_vector