blob: 0ad880e73d64b628cb661ef03d790fd1854652bd [file] [edit]
/*
* Copyright 2026 WebAssembly Community Group participants
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "ir/constraint.h"
namespace wasm {
using namespace analysis;
// Defines a total order on Flat<Index>::Element that linearly extends the
// flat lattice partial order (where Bot < Index < Top, and different indices
// are unrelated).
// We order Bot < Index (ordered by index value) < Top.
std::strong_ordering orderFlatElements(const typename Flat<Index>::Element& a,
const typename Flat<Index>::Element& b) {
auto get_key = [](const typename Flat<Index>::Element& x) {
if (x.isBottom())
return 0u;
if (x.isTop())
return 2u;
return 1u;
};
auto k1 = get_key(a);
auto k2 = get_key(b);
if (k1 != k2)
return k1 <=> k2;
// If both are Index, compare their uint32_t values.
if (k1 == 1) {
return *a.getVal() <=> *b.getVal();
}
return std::strong_ordering::equal;
}
// BoundedConstraintsBase::orderElements implements the total order for the
// OneOf elements.
//
// It satisfies the requirement to be a linear extension of the OneOf lattice
// partial order, and additionally orders constant bounds (index 0) before
// variable bounds (index 1) so that variable bounds are dropped first when
// the size limit N is exceeded in BoundedConjunction.
std::strong_ordering
BoundedConstraintsBase::orderElements(const typename L::Element& a,
const typename L::Element& b) const {
// If they belong to different component lattices, order constants (index 0)
// before variables (index 1).
if (a.index() != b.index()) {
return a.index() <=> b.index();
}
// If they belong to the same component lattice, we define a total order
// within that component that extends the component's lattice order.
if (a.index() == 0) {
// Bound<Int64> component.
Bound<Int64> bound_int(Int64{});
const auto& va = std::get<0>(a);
const auto& vb = std::get<0>(b);
// If they are related in the lattice, use that order.
auto comp = bound_int.compare(va, vb);
if (comp == LESS)
return std::strong_ordering::less;
if (comp == GREATER)
return std::strong_ordering::greater;
if (comp == EQUAL)
return std::strong_ordering::equal;
// If they are unrelated (e.g. x < 5 and x >= 3), we use an arbitrary
// total order on their representation: first by relation, then by value.
const auto& c1 = std::get<typename Bound<Int64>::Constraint>(va);
const auto& c2 = std::get<typename Bound<Int64>::Constraint>(vb);
if (c1.rel != c2.rel) {
return c1.rel <=> c2.rel;
}
return c1.val <=> c2.val;
}
if (a.index() == 1) {
// Bound<Flat<Index>> component.
Bound<Flat<Index>> bound_flat(Flat<Index>{});
const auto& va = std::get<1>(a);
const auto& vb = std::get<1>(b);
// If they are related in the lattice, use that order.
auto comp = bound_flat.compare(va, vb);
if (comp == LESS)
return std::strong_ordering::less;
if (comp == GREATER)
return std::strong_ordering::greater;
if (comp == EQUAL)
return std::strong_ordering::equal;
// If they are unrelated, compare by relation, then by the total order
// on Flat<Index> elements.
const auto& c1 = std::get<typename Bound<Flat<Index>>::Constraint>(va);
const auto& c2 = std::get<typename Bound<Flat<Index>>::Constraint>(vb);
if (c1.rel != c2.rel) {
return c1.rel <=> c2.rel;
}
return orderFlatElements(c1.val, c2.val);
}
return std::strong_ordering::equal;
}
} // namespace wasm