Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -454,7 +454,7 @@ jobs:
env:
CMAKE_PREFIX_PATH: ${{ github.workspace }}/cget
CCACHE_LOGFILE: /tmp/ccache.log
CXXFLAGS: -Werror -pthread -fdebug-prefix-map=$PWD=. -fdebug-types-section -DMIGRAPHX_USE_TYPE_ERASED_MATCHERS=1 --param ggc-min-expand=5 --param ggc-min-heapsize=8192
CXXFLAGS: -Werror -pthread -fdebug-prefix-map=$PWD=. -fdebug-types-section --param ggc-min-expand=5 --param ggc-min-heapsize=8192
run: |
echo "leak:dnnl::impl::malloc" > suppressions.txt
export LSAN_OPTIONS="suppressions=$(pwd)/suppressions.txt"
Expand Down
5 changes: 0 additions & 5 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -159,11 +159,6 @@ enable_static_init(migraphx)
file(GLOB BUILDER_SRCS CONFIGURE_DEPENDS op/builder/*.cpp op/builder/torch/*.cpp)
target_sources(migraphx PRIVATE ${BUILDER_SRCS})

if(WIN32)
# Due to compilation crashing, we need to use type-erased matchers on Windows.
target_compile_definitions(migraphx PUBLIC MIGRAPHX_USE_TYPE_ERASED_MATCHERS=1)
endif()

configure_file(config.h.in include/migraphx/config.h)

configure_file(version.h.in include/migraphx/version.h)
Expand Down
97 changes: 56 additions & 41 deletions src/fuse_attention.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -141,13 +141,14 @@ struct find_quant_attention
{
auto matcher() const
{
auto gemm1 =
auto gemm1 = match::opaque(
match::name("dequantizelinear")(match::arg(0)(match::name("quant_dot").bind("qgemm1")))
.bind("deq1");
auto softmax = match::softmax_input(match::skip(match::name("convert"))(gemm1));
auto probs = match::name("quantizelinear")(
match::arg(0)(match::skip(match::name("convert"))(softmax)));
auto gemm2 = match::name("quant_dot")(match::arg(0)(probs)).bind("qgemm2");
.bind("deq1"));
auto softmax =
match::opaque(match::softmax_input(match::skip(match::name("convert"))(gemm1)));
auto softmax_cvt = match::opaque(match::skip(match::name("convert"))(softmax));
auto probs = match::opaque(match::name("quantizelinear")(match::arg(0)(softmax_cvt)));
auto gemm2 = match::opaque(match::name("quant_dot")(match::arg(0)(probs)).bind("qgemm2"));
return match::name("dequantizelinear")(match::arg(0)(gemm2)).bind("deq2");
}

Expand Down Expand Up @@ -193,8 +194,10 @@ struct find_transposed_attention
{
auto matcher() const
{
auto gemm1 = match::any_of[pointwise_inputs()](match::name("dot").bind("dot1"));
auto softmax = match::skip(match::name("convert"))(match::softmax_input(gemm1));
auto gemm1 =
match::opaque(match::any_of[pointwise_inputs()](match::name("dot").bind("dot1")));
auto softmax =
match::opaque(match::skip(match::name("convert"))(match::softmax_input(gemm1)));
auto swap_last_two = match::make_basic_pred_matcher([](instruction_ref ins) {
auto perm = ins->get_operator().to_value()["permutation"].to_vector<int64_t>();
if(perm.size() < 2)
Expand All @@ -204,8 +207,9 @@ struct find_transposed_attention
perm[perm.size() - 2] == static_cast<int64_t>(perm.size() - 1) and
perm[perm.size() - 1] == static_cast<int64_t>(perm.size() - 2);
});
auto transposed_softmax = match::name("transpose")(swap_last_two, match::arg(0)(softmax))
.bind("transposed_softmax");
auto transposed_softmax =
match::opaque(match::name("transpose")(swap_last_two, match::arg(0)(softmax))
.bind("transposed_softmax"));
auto input_of_dot2 = match::any().bind("input_of_dot2");
return match::name("dot")(match::arg(0)(input_of_dot2), match::arg(1)(transposed_softmax));
}
Expand Down Expand Up @@ -248,8 +252,10 @@ struct find_attention

auto matcher() const
{
auto gemm1 = match::any_of[pointwise_inputs()](match::name("dot").bind("dot1"));
auto softmax = match::skip(match::name("convert"))(match::softmax_input(gemm1));
auto gemm1 =
match::opaque(match::any_of[pointwise_inputs()](match::name("dot").bind("dot1")));
auto softmax =
match::opaque(match::skip(match::name("convert"))(match::softmax_input(gemm1)));
return match::name("dot")(match::arg(0)(softmax));
}

Expand Down Expand Up @@ -888,36 +894,45 @@ struct find_kv_cache_attention
static const std::unordered_set<std::string> skip_set = {
"multibroadcast", "broadcast", "reshape", "unsqueeze", "squeeze"};

auto keys =
match::skip(match::name(skip_set))(match::name("concat_past_present")).bind("pres_k");
auto k_transpose =
match::skip(match::name(skip_set))(match::name("transpose")(match::arg(0)(keys)));
auto keys = match::opaque(
match::skip(match::name(skip_set))(match::name("concat_past_present")).bind("pres_k"));
auto keys_transpose = match::opaque(match::name("transpose")(match::arg(0)(keys)));
auto k_transpose = match::opaque(match::skip(match::name(skip_set))(keys_transpose));
auto queries = match::name("slice");
auto gemm1 = match::name("dot")(match::arg(0)(queries), match::arg(1)(k_transpose));
auto gemm1_maybe_cvt = match::skip(match::name("convert"))(gemm1);
auto scale = match::name("mul")(match::any_arg(0, 1)(gemm1_maybe_cvt));
auto broadcasted_const = match::name("multibroadcast")(match::arg(0)(match::is_constant()));
auto attn_scores = match::any_of(scale, gemm1_maybe_cvt);
auto causal_mask =
match::name("where")(match::arg(0)(broadcasted_const), match::arg(2)(attn_scores));
auto conv_grtr = match::name("convert")(match::arg(0)(match::name("greater")));
auto local_window_comp = match::skip(match::name(skip_set))(conv_grtr);
auto local_window_mask =
match::name("where")(match::arg(0)(match::any_of(local_window_comp, broadcasted_const)),
match::arg(2)(match::any_of(causal_mask, scale, gemm1_maybe_cvt)));
auto greater = match::name("greater")(match::arg(1)(match::any().bind("total_sl")));
auto conv_greater =
match::skip(match::name("unsqueeze"))(match::name("convert")(match::arg(0)(greater)));
auto bc_greater = match::name("multibroadcast")(match::arg(0)(conv_greater));
auto mask = match::name("where")(
match::arg(0)(bc_greater),
match::arg(2)(match::any_of(local_window_mask, causal_mask, scale, gemm1_maybe_cvt)));
auto attn_probabilities = match::skip(match::name("convert"))(
match::softmax_input(match::skip(match::name("convert"))(mask)));
auto values =
match::skip(match::name(skip_set))(match::name("concat_past_present")).bind("pres_v");
auto gemm2 = match::name("dot")(match::arg(0)(attn_probabilities), match::arg(1)(values));
auto transpose_out = match::name("transpose")(match::arg(0)(gemm2));
auto gemm1 =
match::opaque(match::name("dot")(match::arg(0)(queries), match::arg(1)(k_transpose)));
auto gemm1_maybe_cvt = match::opaque(match::skip(match::name("convert"))(gemm1));
auto scale = match::opaque(match::name("mul")(match::any_arg(0, 1)(gemm1_maybe_cvt)));
auto constant = match::opaque(match::is_constant());
auto broadcasted_const =
match::opaque(match::name("multibroadcast")(match::arg(0)(constant)));
auto attn_scores = match::opaque(match::any_of(scale, gemm1_maybe_cvt));
auto causal_mask = match::opaque(
match::name("where")(match::arg(0)(broadcasted_const), match::arg(2)(attn_scores)));
auto grtr = match::opaque(match::name("greater"));
auto conv_grtr = match::opaque(match::name("convert")(match::arg(0)(grtr)));
auto local_window_comp = match::opaque(match::skip(match::name(skip_set))(conv_grtr));
auto local_window_cond = match::opaque(match::any_of(local_window_comp, broadcasted_const));
auto local_window_val = match::opaque(match::any_of(causal_mask, scale, gemm1_maybe_cvt));
auto local_window_mask = match::opaque(match::name("where")(
match::arg(0)(local_window_cond), match::arg(2)(local_window_val)));
auto greater =
match::opaque(match::name("greater")(match::arg(1)(match::any().bind("total_sl"))));
auto greater_cvt = match::opaque(match::name("convert")(match::arg(0)(greater)));
auto conv_greater = match::opaque(match::skip(match::name("unsqueeze"))(greater_cvt));
auto bc_greater = match::opaque(match::name("multibroadcast")(match::arg(0)(conv_greater)));
auto mask_val =
match::opaque(match::any_of(local_window_mask, causal_mask, scale, gemm1_maybe_cvt));
auto mask =
match::opaque(match::name("where")(match::arg(0)(bc_greater), match::arg(2)(mask_val)));
auto mask_cvt = match::opaque(match::skip(match::name("convert"))(mask));
auto attn_probabilities =
match::opaque(match::skip(match::name("convert"))(match::softmax_input(mask_cvt)));
auto values = match::opaque(
match::skip(match::name(skip_set))(match::name("concat_past_present")).bind("pres_v"));
auto gemm2 = match::opaque(
match::name("dot")(match::arg(0)(attn_probabilities), match::arg(1)(values)));
auto transpose_out = match::opaque(match::name("transpose")(match::arg(0)(gemm2)));
return match::name("reshape")(match::arg(0)(transpose_out));
}

Expand Down
13 changes: 7 additions & 6 deletions src/include/migraphx/match/gelu_erf.hpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2015-2024 Advanced Micro Devices, Inc. All rights reserved.
* Copyright (c) 2015-2026 Advanced Micro Devices, Inc. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
Expand Down Expand Up @@ -38,15 +38,16 @@ struct gelu_erf_matcher
F f;
auto erf_fn() const
{
auto mul_1_sqrt_2 = f("mul")(
either_arg(0, 1)(none_of(has_value(M_SQRT1_2)).bind("x"), has_value(M_SQRT1_2)));
auto div_sqrt_2 = f("div")(args(none_of(has_value(M_SQRT2)).bind("x"), has_value(M_SQRT2)));
return f("erf")(used_once(), arg(0)(used_once(), any_of(mul_1_sqrt_2, div_sqrt_2)));
auto mul_1_sqrt_2 = opaque(f("mul")(
either_arg(0, 1)(none_of(has_value(M_SQRT1_2)).bind("x"), has_value(M_SQRT1_2))));
auto div_sqrt_2 =
opaque(f("div")(args(none_of(has_value(M_SQRT2)).bind("x"), has_value(M_SQRT2))));
return opaque(f("erf")(used_once(), arg(0)(used_once(), any_of(mul_1_sqrt_2, div_sqrt_2))));
}

auto add_erf() const
{
return f("add")(used_once(), either_arg(0, 1)(erf_fn(), has_value(1.0)));
return opaque(f("add")(used_once(), either_arg(0, 1)(erf_fn(), has_value(1.0))));
}

auto one_half() const { return has_value(0.5); }
Expand Down
33 changes: 18 additions & 15 deletions src/include/migraphx/match/gelu_tanh.hpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2015-2024 Advanced Micro Devices, Inc. All rights reserved.
* Copyright (c) 2015-2026 Advanced Micro Devices, Inc. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
Expand Down Expand Up @@ -38,41 +38,44 @@ struct gelu_tanh_matcher
F f;

/// x ^ 3
auto pow_fn() const { return f("pow")(used_once(), arg(1)(has_value(3.0))); }
auto pow_fn() const { return opaque(f("pow")(used_once(), arg(1)(has_value(3.0)))); }

auto tanh_fn() const
{
/// Gelu tanh approximation
/// tanh( sqrt(2/M_PI) * (x + 0.044715 * x ^ 3 )
auto mul_const_pow1 = f("mul")(either_arg(0, 1)(has_value(0.044715), pow_fn()));
auto add_any_mul = f("add")(any_arg(0, 1)(mul_const_pow1));
auto mul_sqrt2rpi_add = f("mul")(either_arg(0, 1)(has_value(sqrt(M_2_PI)), add_any_mul));
auto mul_const_pow1 = opaque(f("mul")(either_arg(0, 1)(has_value(0.044715), pow_fn())));
auto add_any_mul = opaque(f("add")(any_arg(0, 1)(mul_const_pow1)));
auto mul_sqrt2rpi_add =
opaque(f("mul")(either_arg(0, 1)(has_value(sqrt(M_2_PI)), add_any_mul)));

/// FastGelu tanh approximation
/// tanh( 0.797885 * x + 0.035677 * x ^ 3 )
auto mul_const_pow2 = f("mul")(either_arg(0, 1)(has_value(0.035677), pow_fn()));
auto mul_const_x = f("mul")(any_arg(0, 1)(has_value(0.797885)));
auto add_mul_x_mul_pow = f("add")(either_arg(0, 1)(mul_const_pow2, mul_const_x));
return f("tanh")(used_once(), arg(0)(any_of(add_mul_x_mul_pow, mul_sqrt2rpi_add)));
auto mul_const_pow2 = opaque(f("mul")(either_arg(0, 1)(has_value(0.035677), pow_fn())));
auto mul_const_x = opaque(f("mul")(any_arg(0, 1)(has_value(0.797885))));
auto add_mul_x_mul_pow = opaque(f("add")(either_arg(0, 1)(mul_const_pow2, mul_const_x)));
return opaque(f("tanh")(used_once(), arg(0)(any_of(add_mul_x_mul_pow, mul_sqrt2rpi_add))));
}

/// x * (0.5? + 0.5 * tanh( sqrt(2/M_PI) * (x? + 0.044715 * x? ^ 3) ) ) or
/// x * (0.5? + 0.5 * tanh( 0.797885 * x? + 0.035677 * x? ^ 3 ) )
/// <item>? question mark means it doesn't explicitly match that item (anything will work)
auto matcher_v0() const
{
auto mul_half_tanh = f("mul")(either_arg(0, 1)(has_value(0.5), tanh_fn()));
auto add_any_mul = f("add")(any_arg(0, 1)(mul_half_tanh));
return f("mul")(either_arg(0, 1)(any().bind("x"), add_any_mul));
auto mul_half_tanh = opaque(f("mul")(either_arg(0, 1)(has_value(0.5), tanh_fn())));
auto add_any_mul = opaque(f("add")(any_arg(0, 1)(mul_half_tanh)));
return opaque(f("mul")(either_arg(0, 1)(any().bind("x"), add_any_mul)));
}

/// x * 0.5 * (1.0 + tanh( sqrt(2/M_PI) * (x + 0.044715 * x ^ 3) ) ) or
/// x * 0.5 * (1.0 + tanh( 0.797885 * x + 0.035677 * x ^ 3 ) ) )
auto matcher_v1() const
{
auto add_one_tanh = f("add")(used_once(), either_arg(0, 1)(has_value(1.0), tanh_fn()));
auto mul_half_x = f("mul")(used_once(), either_arg(0, 1)(has_value(0.5), any().bind("x")));
return f("mul")(either_arg(0, 1)(mul_half_x, add_one_tanh));
auto add_one_tanh =
opaque(f("add")(used_once(), either_arg(0, 1)(has_value(1.0), tanh_fn())));
auto mul_half_x =
opaque(f("mul")(used_once(), either_arg(0, 1)(has_value(0.5), any().bind("x"))));
return opaque(f("mul")(either_arg(0, 1)(mul_half_x, add_one_tanh)));
}
};
} // namespace detail
Expand Down
18 changes: 9 additions & 9 deletions src/include/migraphx/match/layernorm.hpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2015-2025 Advanced Micro Devices, Inc. All rights reserved.
* Copyright (c) 2015-2026 Advanced Micro Devices, Inc. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
Expand Down Expand Up @@ -51,31 +51,31 @@ struct layernorm_matcher
});
}

auto reduce_mean() const { return f("reduce_mean")(last_axis()); }
auto reduce_mean() const { return opaque(f("reduce_mean")(last_axis())); }

auto x_minus_mean() const
{
return f("sub")(arg(0)(any().bind("x")), arg(1)(skip_broadcasts(reduce_mean())));
return opaque(f("sub")(arg(0)(any().bind("x")), arg(1)(skip_broadcasts(reduce_mean()))));
}

auto variance() const
{
return reduce_mean()(arg(0)(any_of(
return opaque(reduce_mean()(arg(0)(any_of(
f("pow")(arg(0)(x_minus_mean()), arg(1)(has_value(2.0f))),
f("mul")(arg(0)(x_minus_mean()), arg(1)(x_minus_mean())),
f("sqdiff")(either_arg(0, 1)(any().bind("x"), skip_broadcasts(reduce_mean()))))));
f("sqdiff")(either_arg(0, 1)(any().bind("x"), skip_broadcasts(reduce_mean())))))));
}

auto sqrt_add_eps(const std::string& name) const
{
auto add_eps = f("add")(either_arg(0, 1)(variance(), is_constant().bind("eps")));
return skip_broadcasts(f(name)(arg(0)(any_of(add_eps, variance()))));
auto add_eps = opaque(f("add")(either_arg(0, 1)(variance(), is_constant().bind("eps"))));
return opaque(skip_broadcasts(f(name)(arg(0)(any_of(add_eps, variance())))));
}

auto layernorm_onnx() const
{
auto div_sqrt = f("div")(arg(0)(x_minus_mean()), arg(1)(sqrt_add_eps("sqrt")));
auto mul_rsqrt = f("mul")(either_arg(0, 1)(x_minus_mean(), sqrt_add_eps("rsqrt")));
auto div_sqrt = opaque(f("div")(arg(0)(x_minus_mean()), arg(1)(sqrt_add_eps("sqrt"))));
auto mul_rsqrt = opaque(f("mul")(either_arg(0, 1)(x_minus_mean(), sqrt_add_eps("rsqrt"))));
return any(any_of(div_sqrt, mul_rsqrt));
}

Expand Down
21 changes: 21 additions & 0 deletions src/include/migraphx/matcher.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,17 @@
#define MIGRAPHX_USE_TYPE_ERASED_MATCHERS 0
#endif

#ifndef MIGRAPHX_USE_TYPE_ERASED_OPAQUE_MATCHER
#if MIGRAPHX_USE_TYPE_ERASED_MATCHERS
#define MIGRAPHX_USE_TYPE_ERASED_OPAQUE_MATCHER 0
// Windows and gcc use an excessive amount of memory to compile deeply nested matcher types
#elif defined(_WIN32) || (defined(__GNUC__) && not defined(__clang__))
#define MIGRAPHX_USE_TYPE_ERASED_OPAQUE_MATCHER 1
#else
#define MIGRAPHX_USE_TYPE_ERASED_OPAQUE_MATCHER 0
#endif
#endif

namespace migraphx {
inline namespace MIGRAPHX_INLINE_NS {

Expand Down Expand Up @@ -269,6 +280,16 @@ struct any_matcher : any_matcher_base
}
};

template <class M>
auto opaque(M m)
{
#if MIGRAPHX_USE_TYPE_ERASED_OPAQUE_MATCHER
return any_matcher{m};
#else
return m;
#endif
}

/// Create a basic matcher from a matcher
template <class M>
typename type_erased_matcher<M>::type make_basic_matcher(M m)
Expand Down
9 changes: 6 additions & 3 deletions src/rewrite_gelu.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2015-2025 Advanced Micro Devices, Inc. All rights reserved.
* Copyright (c) 2015-2026 Advanced Micro Devices, Inc. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
Expand Down Expand Up @@ -66,7 +66,10 @@ static void replace_with_tanh_exp_gelu(module& m, const match::matcher_result& r
*/
struct find_gelu_erf
{
auto matcher() const { return match::any_of(match::gelu_erf(), match::gelu_tanh()); }
auto matcher() const
{
return match::any_of(match::opaque(match::gelu_erf()), match::opaque(match::gelu_tanh()));
}

void apply(module& m, const match::matcher_result& r) const
{
Expand All @@ -86,7 +89,7 @@ struct find_gelu_erf
*/
struct find_tanh_fast_gelu
{
auto matcher() const { return match::gelu_tanh(); }
auto matcher() const { return match::opaque(match::gelu_tanh()); }

void apply(module& m, const match::matcher_result& r) const
{
Expand Down
Loading
Loading