Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WebAssembly] Enable simd128 when relaxed-simd is set in AsmPrinter #99803

Merged
merged 1 commit into from
Jul 23, 2024

Conversation

aheejin
Copy link
Member

@aheejin aheejin commented Jul 21, 2024

Even though in Subtarget we defined SIMDLevel as a number so hasRelaxedSIMD automatically means hasSIMD128,

enum SIMDEnum {
NoSIMD,
SIMD128,
RelaxedSIMD,
} SIMDLevel = NoSIMD;
bool hasSIMD128() const { return SIMDLevel >= SIMD128; }

specifying only relaxed-simd feature on a program that needs simd128 instructions to compile fails, because of this query in AsmPrinter:

WebAssembly_MC::verifyInstructionPredicates(MI->getOpcode(),
Subtarget->getFeatureBits());

This verifyInstructionPredicates function (and other functions called by this function) is generated by
https://github.com/llvm/llvm-project/blob/main/llvm/utils/TableGen/InstrInfoEmitter.cpp, and looks like this (you can check it in the lib/Target/WebAssembly/WebAssemblyGenInstrInfo.inc in your build directory):

void verifyInstructionPredicates(
    unsigned Opcode, const FeatureBitset &Features) {
  FeatureBitset AvailableFeatures = computeAvailableFeatures(Features);
  FeatureBitset RequiredFeatures = computeRequiredFeatures(Opcode);
  FeatureBitset MissingFeatures =
      (AvailableFeatures & RequiredFeatures) ^
      RequiredFeatures;
  ...
}

And computeAvailableFeatures is just a set query, like this:

inline FeatureBitset computeAvailableFeatures(const FeatureBitset &FB) {
  FeatureBitset Features;
  if (FB[WebAssembly::FeatureAtomics])
    Features.set(Feature_HasAtomicsBit);
  if (FB[WebAssembly::FeatureBulkMemory])
    Features.set(Feature_HasBulkMemoryBit);
  if (FB[WebAssembly::FeatureExceptionHandling])
    Features.set(Feature_HasExceptionHandlingBit);
  ...

So this is how currently HasSIMD128 is defined:

def HasSIMD128 :
Predicate<"Subtarget->hasSIMD128()">,
AssemblerPredicate<(all_of FeatureSIMD128), "simd128">;

The things being checked in this computeAvailableFeatures, and in turn in AsmPrinter, are AssemblerPredicates. These only check which bits are set in the features set and are different from Predicates, which can call Subtarget functions like Subtarget->hasSIMD128().

But apparently we can use all_of and any_of directives in AssemblerPredicate, and we can make simd128's AssemblerPredicate set in relaxed-simd is set by the condition as an 'or' of the two.

Fixes #98502.

Even though in `Subtarget` we defined `SIMDLevel` as a number so
`hasRelaxedSIMD` automatically means `hasSIMD128`,
https://github.com/llvm/llvm-project/blob/0caf0c93e759816663af52e8632d1c3953dbc715/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.h#L36-L40
https://github.com/llvm/llvm-project/blob/0caf0c93e759816663af52e8632d1c3953dbc715/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.h#L107

specifying only `relaxed-simd` feature on a program that needs `simd128`
instructions to compile fails, because of this query in `AsmPrinter`:
https://github.com/llvm/llvm-project/blob/d0d05aec3b6792136a9f75eb85dd2ea66005ae12/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp#L644-L645

This `verifyInstructionPredicates` function (and other functions called
by this function) is generated by
https://github.com/llvm/llvm-project/blob/main/llvm/utils/TableGen/InstrInfoEmitter.cpp,
and looks like this (you can check it in the
`lib/Target/WebAssembly/WebAssemblyGenInstrInfo.inc` in your build
directory):
```cpp
void verifyInstructionPredicates(
    unsigned Opcode, const FeatureBitset &Features) {
  FeatureBitset AvailableFeatures = computeAvailableFeatures(Features);
  FeatureBitset RequiredFeatures = computeRequiredFeatures(Opcode);
  FeatureBitset MissingFeatures =
      (AvailableFeatures & RequiredFeatures) ^
      RequiredFeatures;
  ...
}
```

And `computeAvailableFeatures` there is just a set query, like this:
```cpp
inline FeatureBitset computeAvailableFeatures(const FeatureBitset &FB) {
  FeatureBitset Features;
  if (FB[WebAssembly::FeatureAtomics])
    Features.set(Feature_HasAtomicsBit);
  if (FB[WebAssembly::FeatureBulkMemory])
    Features.set(Feature_HasBulkMemoryBit);
  if (FB[WebAssembly::FeatureExceptionHandling])
    Features.set(Feature_HasExceptionHandlingBit);
  ...
```

So this is how currently `HasSIMD128` is defined:
https://github.com/llvm/llvm-project/blob/0caf0c93e759816663af52e8632d1c3953dbc715/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td#L79-L81

The things being checked in this `computeAvailableFeatures`, and in turn
in `AsmPrinter`, are `AssemblerPredicate`s. These only check which
bits are set in the features set and are different from `Predicate`s,
which can call `Subtarget` functions like `Subtarget->hasSIMD128()`.

But apparently we can use `all_of` and `any_of` directives in
`AssemblerPredicate`, and we can make `simd128`'s `AssemblerPredicate`
set in `relaxed-simd` is set by the condition as an 'or' of the two.

Fixes llvm#98502.
@llvmbot
Copy link
Collaborator

llvmbot commented Jul 21, 2024

@llvm/pr-subscribers-backend-webassembly

Author: Heejin Ahn (aheejin)

Changes

Even though in Subtarget we defined SIMDLevel as a number so hasRelaxedSIMD automatically means hasSIMD128,

enum SIMDEnum {
NoSIMD,
SIMD128,
RelaxedSIMD,
} SIMDLevel = NoSIMD;
bool hasSIMD128() const { return SIMDLevel >= SIMD128; }

specifying only relaxed-simd feature on a program that needs simd128 instructions to compile fails, because of this query in AsmPrinter:

WebAssembly_MC::verifyInstructionPredicates(MI->getOpcode(),
Subtarget->getFeatureBits());

This verifyInstructionPredicates function (and other functions called by this function) is generated by
https://github.com/llvm/llvm-project/blob/main/llvm/utils/TableGen/InstrInfoEmitter.cpp, and looks like this (you can check it in the
lib/Target/WebAssembly/WebAssemblyGenInstrInfo.inc in your build directory):

void verifyInstructionPredicates(
    unsigned Opcode, const FeatureBitset &amp;Features) {
  FeatureBitset AvailableFeatures = computeAvailableFeatures(Features);
  FeatureBitset RequiredFeatures = computeRequiredFeatures(Opcode);
  FeatureBitset MissingFeatures =
      (AvailableFeatures &amp; RequiredFeatures) ^
      RequiredFeatures;
  ...
}

And computeAvailableFeatures there is just a set query, like this:

inline FeatureBitset computeAvailableFeatures(const FeatureBitset &amp;FB) {
  FeatureBitset Features;
  if (FB[WebAssembly::FeatureAtomics])
    Features.set(Feature_HasAtomicsBit);
  if (FB[WebAssembly::FeatureBulkMemory])
    Features.set(Feature_HasBulkMemoryBit);
  if (FB[WebAssembly::FeatureExceptionHandling])
    Features.set(Feature_HasExceptionHandlingBit);
  ...

So this is how currently HasSIMD128 is defined:

def HasSIMD128 :
Predicate<"Subtarget->hasSIMD128()">,
AssemblerPredicate<(all_of FeatureSIMD128), "simd128">;

The things being checked in this computeAvailableFeatures, and in turn in AsmPrinter, are AssemblerPredicates. These only check which bits are set in the features set and are different from Predicates, which can call Subtarget functions like Subtarget-&gt;hasSIMD128().

But apparently we can use all_of and any_of directives in AssemblerPredicate, and we can make simd128's AssemblerPredicate set in relaxed-simd is set by the condition as an 'or' of the two.

Fixes #98502.


Full diff: https://github.com/llvm/llvm-project/pull/99803.diff

2 Files Affected:

  • (modified) llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td (+1-1)
  • (added) llvm/test/CodeGen/WebAssembly/simd-asm-pred.ll (+24)
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td b/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td
index 3d37eb2fa27bc..bb36ce7650183 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td
@@ -78,7 +78,7 @@ def HasSignExt :
 
 def HasSIMD128 :
     Predicate<"Subtarget->hasSIMD128()">,
-    AssemblerPredicate<(all_of FeatureSIMD128), "simd128">;
+    AssemblerPredicate<(any_of FeatureSIMD128, FeatureRelaxedSIMD), "simd128">;
 
 def HasTailCall :
     Predicate<"Subtarget->hasTailCall()">,
diff --git a/llvm/test/CodeGen/WebAssembly/simd-asm-pred.ll b/llvm/test/CodeGen/WebAssembly/simd-asm-pred.ll
new file mode 100644
index 0000000000000..f022c3e745125
--- /dev/null
+++ b/llvm/test/CodeGen/WebAssembly/simd-asm-pred.ll
@@ -0,0 +1,24 @@
+; RUN: llc < %s -verify-machineinstrs -mattr=+relaxed-simd | FileCheck %s
+
+; Test that setting "relaxed-simd" target feature set also implies 'simd128' in
+; AssemblerPredicate, which is used to verify instructions in AsmPrinter.
+
+target triple = "wasm32-unknown-unknown"
+
+declare <2 x i64> @llvm.wasm.relaxed.laneselect.v2i64(<2 x i64>, <2 x i64>, <2 x i64>)
+
+; The compiled result of this function uses LOCAL_GET_V128, which is predicated
+; on the 'simd128' feature. We should be able to compile this when only
+; 'relaxed-simd' is set, which implies 'simd128'.
+define <2 x i64> @test(<2 x i64>, <2 x i64>, <2 x i64>) #0 {
+; CHECK-LABEL: test:
+; CHECK:         .functype  test (v128, v128, v128) -> (v128)
+; CHECK-NEXT:  # %bb.0:
+; CHECK-NEXT:    local.get  0
+; CHECK-NEXT:    local.get  1
+; CHECK-NEXT:    local.get  2
+; CHECK-NEXT:    i64x2.relaxed_laneselect
+start:
+  %_4 = tail call <2 x i64> @llvm.wasm.relaxed.laneselect.v2i64(<2 x i64> %0, <2 x i64> %1, <2 x i64> %2) #3
+  ret <2 x i64> %_4
+}

@aheejin
Copy link
Member Author

aheejin commented Jul 21, 2024

cc @alexcrichton

Copy link
Collaborator

@tlively tlively left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, @aheejin!

@aheejin aheejin merged commit 735852f into llvm:main Jul 23, 2024
7 of 9 checks passed
@aheejin
Copy link
Member Author

aheejin commented Jul 23, 2024

Will merge this; the CI failure doesn't seem to be related.

@aheejin aheejin deleted the assembler_pred branch July 23, 2024 18:51
yuxuanchen1997 pushed a commit that referenced this pull request Jul 25, 2024
…99803)

Summary:
Even though in `Subtarget` we defined `SIMDLevel` as a number so
`hasRelaxedSIMD` automatically means `hasSIMD128`,
https://github.com/llvm/llvm-project/blob/0caf0c93e759816663af52e8632d1c3953dbc715/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.h#L36-L40
https://github.com/llvm/llvm-project/blob/0caf0c93e759816663af52e8632d1c3953dbc715/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.h#L107

specifying only `relaxed-simd` feature on a program that needs `simd128`
instructions to compile fails, because of this query in `AsmPrinter`:
https://github.com/llvm/llvm-project/blob/d0d05aec3b6792136a9f75eb85dd2ea66005ae12/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp#L644-L645

This `verifyInstructionPredicates` function (and other functions called
by this function) is generated by

https://github.com/llvm/llvm-project/blob/main/llvm/utils/TableGen/InstrInfoEmitter.cpp,
and looks like this (you can check it in the
`lib/Target/WebAssembly/WebAssemblyGenInstrInfo.inc` in your build
directory):
```cpp
void verifyInstructionPredicates(
    unsigned Opcode, const FeatureBitset &Features) {
  FeatureBitset AvailableFeatures = computeAvailableFeatures(Features);
  FeatureBitset RequiredFeatures = computeRequiredFeatures(Opcode);
  FeatureBitset MissingFeatures =
      (AvailableFeatures & RequiredFeatures) ^
      RequiredFeatures;
  ...
}
```

And `computeAvailableFeatures` is just a set query, like this:
```cpp
inline FeatureBitset computeAvailableFeatures(const FeatureBitset &FB) {
  FeatureBitset Features;
  if (FB[WebAssembly::FeatureAtomics])
    Features.set(Feature_HasAtomicsBit);
  if (FB[WebAssembly::FeatureBulkMemory])
    Features.set(Feature_HasBulkMemoryBit);
  if (FB[WebAssembly::FeatureExceptionHandling])
    Features.set(Feature_HasExceptionHandlingBit);
  ...
```

So this is how currently `HasSIMD128` is defined:

https://github.com/llvm/llvm-project/blob/0caf0c93e759816663af52e8632d1c3953dbc715/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td#L79-L81

The things being checked in this `computeAvailableFeatures`, and in turn
in `AsmPrinter`, are `AssemblerPredicate`s. These only check which bits
are set in the features set and are different from `Predicate`s, which
can call `Subtarget` functions like `Subtarget->hasSIMD128()`.

But apparently we can use `all_of` and `any_of` directives in
`AssemblerPredicate`, and we can make `simd128`'s `AssemblerPredicate`
set in `relaxed-simd` is set by the condition as an 'or' of the two.

Fixes #98502.

Test Plan: 

Reviewers: 

Subscribers: 

Tasks: 

Tags: 


Differential Revision: https://phabricator.intern.facebook.com/D60250795
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

WebAssembly: simd128 feature is required even when the relaxed-simd feature is enabled
3 participants