Commit 589677bc authored by Clemens Backes's avatar Clemens Backes Committed by Commit Bot

[wasm][liftoff] Check for unexpected bailout

We are working on getting Liftoff feature complete. Eventually, bailout
should only happen if experimental features are enabled. Until we are
there, we also need to allow some more bailouts, which should be removed
in the near future.

This CL adds a check for expected bailout reasons. The new function
serves as a burndown list of issues to be fixed.

Drive-by: Make some methods constexpr such that they can be used in
static assertions.

R=ahaas@chromium.org

Change-Id: I5d3cd8f49a30d01f89ac6cf5321e1314b63eba40
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2629513
Commit-Queue: Clemens Backes <clemensb@chromium.org>
Reviewed-by: 's avatarAndreas Haas <ahaas@chromium.org>
Cr-Commit-Position: refs/heads/master@{#72127}
parent 0ef84f99
......@@ -27,31 +27,47 @@ class EnumSet {
bits_ = bits;
}
bool empty() const { return bits_ == 0; }
bool contains(E element) const { return (bits_ & Mask(element)) != 0; }
bool contains_any(EnumSet set) const { return (bits_ & set.bits_) != 0; }
constexpr bool empty() const { return bits_ == 0; }
constexpr bool contains(E element) const {
return (bits_ & Mask(element)) != 0;
}
constexpr bool contains_any(EnumSet set) const {
return (bits_ & set.bits_) != 0;
}
void Add(E element) { bits_ |= Mask(element); }
void Add(EnumSet set) { bits_ |= set.bits_; }
void Remove(E element) { bits_ &= ~Mask(element); }
void Remove(EnumSet set) { bits_ &= ~set.bits_; }
void RemoveAll() { bits_ = 0; }
void Intersect(EnumSet set) { bits_ &= set.bits_; }
T ToIntegral() const { return bits_; }
constexpr T ToIntegral() const { return bits_; }
bool operator==(EnumSet set) const { return bits_ == set.bits_; }
bool operator!=(EnumSet set) const { return bits_ != set.bits_; }
constexpr bool operator==(EnumSet set) const { return bits_ == set.bits_; }
constexpr bool operator!=(EnumSet set) const { return bits_ != set.bits_; }
EnumSet operator|(EnumSet set) const { return EnumSet(bits_ | set.bits_); }
EnumSet operator&(EnumSet set) const { return EnumSet(bits_ & set.bits_); }
EnumSet operator-(EnumSet set) const { return EnumSet(bits_ & ~set.bits_); }
constexpr EnumSet operator|(EnumSet set) const {
return EnumSet(bits_ | set.bits_);
}
constexpr EnumSet operator&(EnumSet set) const {
return EnumSet(bits_ & set.bits_);
}
constexpr EnumSet operator-(EnumSet set) const {
return EnumSet(bits_ & ~set.bits_);
}
EnumSet& operator|=(EnumSet set) { return *this = *this | set; }
EnumSet& operator&=(EnumSet set) { return *this = *this & set; }
EnumSet& operator-=(EnumSet set) { return *this = *this - set; }
EnumSet operator|(E element) const { return EnumSet(bits_ | Mask(element)); }
EnumSet operator&(E element) const { return EnumSet(bits_ & Mask(element)); }
EnumSet operator-(E element) const { return EnumSet(bits_ & ~Mask(element)); }
constexpr EnumSet operator|(E element) const {
return EnumSet(bits_ | Mask(element));
}
constexpr EnumSet operator&(E element) const {
return EnumSet(bits_ & Mask(element));
}
constexpr EnumSet operator-(E element) const {
return EnumSet(bits_ & ~Mask(element));
}
EnumSet& operator|=(E element) { return *this = *this | element; }
EnumSet& operator&=(E element) { return *this = *this & element; }
......
......@@ -245,6 +245,72 @@ class DebugSideTableBuilder {
std::list<EntryBuilder> entries_;
};
void CheckBailoutAllowed(LiftoffBailoutReason reason, const char* detail,
const CompilationEnv* env) {
// Decode errors are ok.
if (reason == kDecodeError) return;
// Missing CPU features are also generally OK for now.
if (reason == kMissingCPUFeature) return;
// --liftoff-only ensures that tests actually exercise the Liftoff path
// without bailing out. Bailing out due to (simulated) lack of CPU support
// is okay though (see above).
if (FLAG_liftoff_only) {
FATAL("--liftoff-only: treating bailout as fatal error. Cause: %s", detail);
}
// If --enable-testing-opcode-in-wasm is set, we are expected to bailout with
// "testing opcode".
if (FLAG_enable_testing_opcode_in_wasm &&
strcmp(detail, "testing opcode") == 0) {
return;
}
// Some externally maintained architectures don't fully implement Liftoff yet.
#if V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64 || V8_TARGET_ARCH_S390X || \
V8_TARGET_ARCH_PPC || V8_TARGET_ARCH_PPC64
return;
#endif
// TODO(11235): On arm and arm64 there is still a limit on the size of
// supported stack frames.
#if V8_TARGET_ARCH_ARM || V8_TARGET_ARCH_ARM64
if (strstr(detail, "Stack limited to 512 bytes")) return;
#endif
#define LIST_FEATURE(name, ...) kFeature_##name,
constexpr WasmFeatures kExperimentalFeatures{
FOREACH_WASM_EXPERIMENTAL_FEATURE_FLAG(LIST_FEATURE)};
constexpr WasmFeatures kStagedFeatures{
FOREACH_WASM_STAGING_FEATURE_FLAG(LIST_FEATURE)};
#undef LIST_FEATURE
// Bailout is allowed if any experimental feature is enabled.
if (env->enabled_features.contains_any(kExperimentalFeatures)) return;
// Staged features should be feature complete in Liftoff according to
// https://v8.dev/docs/wasm-shipping-checklist. Some are not though. They are
// listed here explicitly, with a bug assigned to each of them.
// TODO(6020): Fully implement SIMD in Liftoff.
STATIC_ASSERT(kStagedFeatures.has_simd());
if (reason == kSimd) {
DCHECK(env->enabled_features.has_simd());
return;
}
// TODO(7581): Fully implement reftypes in Liftoff.
STATIC_ASSERT(kStagedFeatures.has_reftypes());
if (reason == kRefTypes) {
DCHECK(env->enabled_features.has_reftypes());
return;
}
// Otherwise, bailout is not allowed.
FATAL("Liftoff bailout should not happen. Cause: %s\n", detail);
}
class LiftoffCompiler {
public:
// TODO(clemensb): Make this a template parameter.
......@@ -403,13 +469,7 @@ class LiftoffCompiler {
decoder->errorf(decoder->pc_offset(), "unsupported liftoff operation: %s",
detail);
UnuseLabels(decoder);
// --liftoff-only ensures that tests actually exercise the Liftoff path
// without bailing out. Bailing out due to (simulated) lack of CPU support
// is okay though.
if (FLAG_liftoff_only && reason != kMissingCPUFeature) {
FATAL("--liftoff-only: treating bailout as fatal error. Cause: %s",
detail);
}
CheckBailoutAllowed(reason, detail, env_);
}
bool DidAssemblerBailout(FullDecoder* decoder) {
......
......@@ -35,7 +35,7 @@ class WasmFeatures : public base::EnumSet<WasmFeature> {
// Simplified getters. Use {has_foo()} instead of {contains(kFeature_foo)}.
#define DECL_FEATURE_GETTER(feat, ...) \
bool has_##feat() const { return contains(kFeature_##feat); }
constexpr bool has_##feat() const { return contains(kFeature_##feat); }
FOREACH_WASM_FEATURE(DECL_FEATURE_GETTER)
#undef DECL_FEATURE_GETTER
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment