[clang] [lld] [llvm] [WebAssembly] Define a new "Trail1" CPU (PR #112035)

Dan Gohman via cfe-commits cfe-commits at lists.llvm.org
Sat Oct 12 21:49:20 PDT 2024


https://github.com/sunfishcode updated https://github.com/llvm/llvm-project/pull/112035

>From b8f33cd68d11759ad774e16b4d25491a1c9fc3e4 Mon Sep 17 00:00:00 2001
From: Dan Gohman <dev at sunfishcode.online>
Date: Fri, 11 Oct 2024 04:30:32 -0700
Subject: [PATCH 1/4] [WebAssembly] Define a new "Trail1" CPU

First, define some new target features. These are subsets of existing features
that reflect implemenetation concerns:

 - "call-indirect-overlong" - implied by "reference-types"; just the overlong
   encoding for the `call_indirect` immediate, and not the actual reference
   types.

 - "bulk-memory-opt" - implied by "bulk-memory": just `memory.copy` and
   `memory.fill`, and not the other instructions in the bulk-memory
    proposal.

Next, define a new target CPU, "Trail1", which enables mutable-globals,
bulk-memory-opt, multivalue, sign-ext, nontrapping-fptoint, extended-const,
and call-indirect-overlong. Unlike the default "generic" CPU, "trail1" is meant
to be frozen, and followed up by "trail2" and so on when new features are
desired.
---
 clang/lib/Basic/Targets/WebAssembly.cpp       | 45 +++++++++++++++++++
 clang/lib/Basic/Targets/WebAssembly.h         |  2 +
 lld/test/wasm/compress-relocs.ll              |  2 +-
 lld/test/wasm/import-table-explicit.s         |  2 +-
 lld/test/wasm/invalid-mvp-table-use.s         |  2 +-
 lld/wasm/InputFiles.cpp                       | 11 ++---
 lld/wasm/SyntheticSections.cpp                |  2 +-
 .../AsmParser/WebAssemblyAsmParser.cpp        | 12 ++---
 llvm/lib/Target/WebAssembly/WebAssembly.td    | 14 ++++++
 .../WebAssembly/WebAssemblyFastISel.cpp       |  2 +-
 .../WebAssembly/WebAssemblyISelLowering.cpp   |  2 +-
 .../WebAssembly/WebAssemblyInstrBulkMemory.td | 15 ++++---
 .../WebAssembly/WebAssemblyInstrInfo.td       |  8 ++++
 .../WebAssemblySelectionDAGInfo.cpp           |  4 +-
 .../Target/WebAssembly/WebAssemblySubtarget.h |  4 ++
 .../WebAssembly/WebAssemblyUtilities.cpp      |  4 +-
 llvm/test/CodeGen/WebAssembly/bulk-memory.ll  |  6 +--
 .../test/CodeGen/WebAssembly/bulk-memory64.ll |  6 +--
 18 files changed, 110 insertions(+), 33 deletions(-)

diff --git a/clang/lib/Basic/Targets/WebAssembly.cpp b/clang/lib/Basic/Targets/WebAssembly.cpp
index 5ac9421663adea..aa3a2770727c3a 100644
--- a/clang/lib/Basic/Targets/WebAssembly.cpp
+++ b/clang/lib/Basic/Targets/WebAssembly.cpp
@@ -47,6 +47,7 @@ bool WebAssemblyTargetInfo::hasFeature(StringRef Feature) const {
   return llvm::StringSwitch<bool>(Feature)
       .Case("atomics", HasAtomics)
       .Case("bulk-memory", HasBulkMemory)
+      .Case("bulk-memory-opt", HasBulkMemoryOpt)
       .Case("exception-handling", HasExceptionHandling)
       .Case("extended-const", HasExtendedConst)
       .Case("fp16", HasFP16)
@@ -55,6 +56,7 @@ bool WebAssemblyTargetInfo::hasFeature(StringRef Feature) const {
       .Case("mutable-globals", HasMutableGlobals)
       .Case("nontrapping-fptoint", HasNontrappingFPToInt)
       .Case("reference-types", HasReferenceTypes)
+      .Case("call-indirect-overlong", HasCallIndirectOverlong)
       .Case("relaxed-simd", SIMDLevel >= RelaxedSIMD)
       .Case("sign-ext", HasSignExt)
       .Case("simd128", SIMDLevel >= SIMD128)
@@ -78,6 +80,8 @@ void WebAssemblyTargetInfo::getTargetDefines(const LangOptions &Opts,
     Builder.defineMacro("__wasm_atomics__");
   if (HasBulkMemory)
     Builder.defineMacro("__wasm_bulk_memory__");
+  if (HasBulkMemoryOpt)
+    Builder.defineMacro("__wasm_bulk_memory_opt__");
   if (HasExceptionHandling)
     Builder.defineMacro("__wasm_exception_handling__");
   if (HasExtendedConst)
@@ -154,12 +158,23 @@ bool WebAssemblyTargetInfo::initFeatureMap(
     Features["multivalue"] = true;
     Features["mutable-globals"] = true;
     Features["reference-types"] = true;
+    Features["call-indirect-overlong"] = true;
     Features["sign-ext"] = true;
   };
+  auto addTrail1Features = [&]() {
+    Features["multivalue"] = true;
+    Features["mutable-globals"] = true;
+    Features["call-indirect-overlong"] = true;
+    Features["sign-ext"] = true;
+    Features["bulk-memory-opt"] = true;
+    Features["nontrapping-fptoint"] = true;
+    Features["extended-const"] = true;
+  };
   auto addBleedingEdgeFeatures = [&]() {
     addGenericFeatures();
     Features["atomics"] = true;
     Features["bulk-memory"] = true;
+    Features["bulk-memory-opt"] = true;
     Features["exception-handling"] = true;
     Features["extended-const"] = true;
     Features["fp16"] = true;
@@ -170,6 +185,8 @@ bool WebAssemblyTargetInfo::initFeatureMap(
   };
   if (CPU == "generic") {
     addGenericFeatures();
+  } else if (CPU == "trail1") {
+    addTrail1Features();
   } else if (CPU == "bleeding-edge") {
     addBleedingEdgeFeatures();
   }
@@ -196,6 +213,14 @@ bool WebAssemblyTargetInfo::handleTargetFeatures(
       HasBulkMemory = false;
       continue;
     }
+    if (Feature == "+bulk-memory-opt") {
+      HasBulkMemoryOpt = true;
+      continue;
+    }
+    if (Feature == "-bulk-memory-opt") {
+      HasBulkMemoryOpt = false;
+      continue;
+    }
     if (Feature == "+exception-handling") {
       HasExceptionHandling = true;
       continue;
@@ -261,6 +286,14 @@ bool WebAssemblyTargetInfo::handleTargetFeatures(
       HasReferenceTypes = false;
       continue;
     }
+    if (Feature == "+call-indirect-overlong") {
+      HasCallIndirectOverlong = true;
+      continue;
+    }
+    if (Feature == "-call-indirect-overlong") {
+      HasCallIndirectOverlong = false;
+      continue;
+    }
     if (Feature == "+relaxed-simd") {
       SIMDLevel = std::max(SIMDLevel, RelaxedSIMD);
       continue;
@@ -298,6 +331,18 @@ bool WebAssemblyTargetInfo::handleTargetFeatures(
         << Feature << "-target-feature";
     return false;
   }
+
+  // The reference-types feature included the change to `call_indirect`
+  // encodings to support overlong immediates.
+  if (HasReferenceTypes) {
+    HasCallIndirectOverlong = true;
+  }
+
+  // bulk-memory-opt is a subset of bulk-memory.
+  if (HasBulkMemory) {
+    HasBulkMemoryOpt = true;
+  }
+
   return true;
 }
 
diff --git a/clang/lib/Basic/Targets/WebAssembly.h b/clang/lib/Basic/Targets/WebAssembly.h
index 213ec42ca84bb7..b05ad862685ad0 100644
--- a/clang/lib/Basic/Targets/WebAssembly.h
+++ b/clang/lib/Basic/Targets/WebAssembly.h
@@ -55,6 +55,7 @@ class LLVM_LIBRARY_VISIBILITY WebAssemblyTargetInfo : public TargetInfo {
 
   bool HasAtomics = false;
   bool HasBulkMemory = false;
+  bool HasBulkMemoryOpt = false;
   bool HasExceptionHandling = false;
   bool HasExtendedConst = false;
   bool HasFP16 = false;
@@ -63,6 +64,7 @@ class LLVM_LIBRARY_VISIBILITY WebAssemblyTargetInfo : public TargetInfo {
   bool HasMutableGlobals = false;
   bool HasNontrappingFPToInt = false;
   bool HasReferenceTypes = false;
+  bool HasCallIndirectOverlong = false;
   bool HasSignExt = false;
   bool HasTailCall = false;
 
diff --git a/lld/test/wasm/compress-relocs.ll b/lld/test/wasm/compress-relocs.ll
index f1faab754cb765..cea9f3476e996a 100644
--- a/lld/test/wasm/compress-relocs.ll
+++ b/lld/test/wasm/compress-relocs.ll
@@ -1,5 +1,5 @@
 ; RUN: llc -filetype=obj %s -o %t.o
-; RUN: llvm-mc -mattr=+reference-types -filetype=obj -triple=wasm32-unknown-unknown %p/Inputs/call-indirect.s -o %t2.o
+; RUN: llvm-mc -mattr=+call-indirect-overlong -filetype=obj -triple=wasm32-unknown-unknown %p/Inputs/call-indirect.s -o %t2.o
 ; RUN: wasm-ld --export-dynamic -o %t.wasm %t2.o %t.o
 ; RUN: obj2yaml %t.wasm | FileCheck %s
 ; RUN: wasm-ld --export-dynamic -O2 -o %t-opt.wasm %t2.o %t.o
diff --git a/lld/test/wasm/import-table-explicit.s b/lld/test/wasm/import-table-explicit.s
index 1dc21beba06294..701b7a1dc3e165 100644
--- a/lld/test/wasm/import-table-explicit.s
+++ b/lld/test/wasm/import-table-explicit.s
@@ -1,4 +1,4 @@
-# RUN: llvm-mc -mattr=+reference-types -filetype=obj -triple=wasm32-unknown-unknown %s -o %t.o
+# RUN: llvm-mc -mattr=+call-indirect-overlong -filetype=obj -triple=wasm32-unknown-unknown %s -o %t.o
 # RUN: wasm-ld --import-table -o %t.wasm %t.o
 # RUN: obj2yaml %t.wasm | FileCheck %s
 
diff --git a/lld/test/wasm/invalid-mvp-table-use.s b/lld/test/wasm/invalid-mvp-table-use.s
index b4f12a7eeb9a48..58c472e29d1ad4 100644
--- a/lld/test/wasm/invalid-mvp-table-use.s
+++ b/lld/test/wasm/invalid-mvp-table-use.s
@@ -1,7 +1,7 @@
 # RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown -o %t.o %s
 #
 # If any table is defined or declared besides the __indirect_function_table,
-# the compilation unit should be compiled with -mattr=+reference-types,
+# the compilation unit should be compiled with -mattr=+call-indirect-overlong,
 # causing symbol table entries to be emitted for all tables.
 # RUN: not wasm-ld --no-entry %t.o -o %t.wasm 2>&1 | FileCheck -check-prefix=CHECK-ERR %s
 
diff --git a/lld/wasm/InputFiles.cpp b/lld/wasm/InputFiles.cpp
index de8e707ab2b497..604b6e9083e8ca 100644
--- a/lld/wasm/InputFiles.cpp
+++ b/lld/wasm/InputFiles.cpp
@@ -247,10 +247,11 @@ static void setRelocs(const std::vector<T *> &chunks,
   }
 }
 
-// An object file can have two approaches to tables.  With the reference-types
-// feature enabled, input files that define or use tables declare the tables
-// using symbols, and record each use with a relocation.  This way when the
-// linker combines inputs, it can collate the tables used by the inputs,
+// An object file can have two approaches to tables.  With the
+// call-indirect-overlong feature enabled (explicitly, or implied by the
+// reference-types feature), input files that define or use tables declare the
+// tables using symbols, and record each use with a relocation.  This way when
+// the linker combines inputs, it can collate the tables used by the inputs,
 // assigning them distinct table numbers, and renumber all the uses as
 // appropriate.  At the same time, the linker has special logic to build the
 // indirect function table if it is needed.
@@ -276,7 +277,7 @@ void ObjFile::addLegacyIndirectFunctionTableIfNeeded(
     return;
 
   // It's possible for an input to define tables and also use the indirect
-  // function table, but forget to compile with -mattr=+reference-types.
+  // function table, but forget to compile with -mattr=+call-indirect-overlong.
   // For these newer files, we require symbols for all tables, and
   // relocations for all of their uses.
   if (tableSymbolCount != 0) {
diff --git a/lld/wasm/SyntheticSections.cpp b/lld/wasm/SyntheticSections.cpp
index a3bc90cfe759ca..74e3efff4cdfb8 100644
--- a/lld/wasm/SyntheticSections.cpp
+++ b/lld/wasm/SyntheticSections.cpp
@@ -326,7 +326,7 @@ void TableSection::addTable(InputTable *table) {
       // to assign table number 0 to the indirect function table.
       for (const auto *culprit : out.importSec->importedSymbols) {
         if (isa<UndefinedTable>(culprit)) {
-          error("object file not built with 'reference-types' feature "
+          error("object file not built with 'call-indirect-overlong' feature "
                 "conflicts with import of table " +
                 culprit->getName() + " by file " +
                 toString(culprit->getFile()));
diff --git a/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp b/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp
index ee8686d1166a5b..091b3ffb8b25d2 100644
--- a/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp
+++ b/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp
@@ -292,7 +292,7 @@ class WebAssemblyAsmParser final : public MCTargetAsmParser {
 
     DefaultFunctionTable = getOrCreateFunctionTableSymbol(
         getContext(), "__indirect_function_table", Is64);
-    if (!STI->checkFeatures("+reference-types"))
+    if (!STI->checkFeatures("+call-indirect-overlong"))
       DefaultFunctionTable->setOmitFromLinkingSection();
   }
 
@@ -532,11 +532,11 @@ class WebAssemblyAsmParser final : public MCTargetAsmParser {
   }
 
   bool parseFunctionTableOperand(std::unique_ptr<WebAssemblyOperand> *Op) {
-    if (STI->checkFeatures("+reference-types")) {
-      // If the reference-types feature is enabled, there is an explicit table
-      // operand.  To allow the same assembly to be compiled with or without
-      // reference types, we allow the operand to be omitted, in which case we
-      // default to __indirect_function_table.
+    if (STI->checkFeatures("+call-indirect-overlong")) {
+      // If the call-indirect-overlong feature is enabled, there is an explicit
+      // table operand.  To allow the same assembly to be compiled with or
+      // without call-indirect overlong, we allow the operand to be omitted, in
+      // which case we default to __indirect_function_table.
       auto &Tok = Lexer.getTok();
       if (Tok.is(AsmToken::Identifier)) {
         auto *Sym =
diff --git a/llvm/lib/Target/WebAssembly/WebAssembly.td b/llvm/lib/Target/WebAssembly/WebAssembly.td
index c632d4a74355d8..7081ee48132a07 100644
--- a/llvm/lib/Target/WebAssembly/WebAssembly.td
+++ b/llvm/lib/Target/WebAssembly/WebAssembly.td
@@ -29,6 +29,10 @@ def FeatureBulkMemory :
       SubtargetFeature<"bulk-memory", "HasBulkMemory", "true",
                        "Enable bulk memory operations">;
 
+def FeatureBulkMemoryOpt :
+      SubtargetFeature<"bulk-memory-opt", "HasBulkMemoryOpt", "true",
+                       "Enable bulk memory optimization operations">;
+
 def FeatureExceptionHandling :
       SubtargetFeature<"exception-handling", "HasExceptionHandling", "true",
                        "Enable Wasm exception handling">;
@@ -63,6 +67,10 @@ def FeatureReferenceTypes :
       SubtargetFeature<"reference-types", "HasReferenceTypes", "true",
                        "Enable reference types">;
 
+def FeatureCallIndirectOverlong :
+      SubtargetFeature<"call-indirect-overlong", "HasCallIndirectOverlong", "true",
+                       "Enable overlong encoding for call_indirect immediates">;
+
 def FeatureRelaxedSIMD :
       SubtargetFeature<"relaxed-simd", "SIMDLevel", "RelaxedSIMD",
                        "Enable relaxed-simd instructions">;
@@ -113,6 +121,12 @@ def : ProcessorModel<"generic", NoSchedModel,
                       [FeatureMultivalue, FeatureMutableGlobals,
                        FeatureReferenceTypes, FeatureSignExt]>;
 
+def : ProcessorModel<"trail1", NoSchedModel,
+                      [FeatureMultivalue, FeatureMutableGlobals,
+                       FeatureCallIndirectOverlong, FeatureSignExt,
+                       FeatureBulkMemoryOpt, FeatureNontrappingFPToInt,
+                       FeatureExtendedConst]>;
+
 // Latest and greatest experimental version of WebAssembly. Bugs included!
 def : ProcessorModel<"bleeding-edge", NoSchedModel,
                       [FeatureAtomics, FeatureBulkMemory,
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyFastISel.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyFastISel.cpp
index 7c90fff2a5c1d7..d84d1f4dedec50 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyFastISel.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyFastISel.cpp
@@ -899,7 +899,7 @@ bool WebAssemblyFastISel::selectCall(const Instruction *I) {
     // The table into which this call_indirect indexes.
     MCSymbolWasm *Table = WebAssembly::getOrCreateFunctionTableSymbol(
         MF->getContext(), Subtarget);
-    if (Subtarget->hasReferenceTypes()) {
+    if (Subtarget->hasCallIndirectOverlong()) {
       MIB.addSym(Table);
     } else {
       // Otherwise for the MVP there is at most one table whose number is 0, but
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
index 5f76d666823e28..1b6a7cbf14edfe 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
@@ -633,7 +633,7 @@ LowerCallResults(MachineInstr &CallResults, DebugLoc DL, MachineBasicBlock *BB,
                                     MF.getContext(), Subtarget)
                               : WebAssembly::getOrCreateFunctionTableSymbol(
                                     MF.getContext(), Subtarget);
-    if (Subtarget->hasReferenceTypes()) {
+    if (Subtarget->hasCallIndirectOverlong()) {
       MIB.addSym(Table);
     } else {
       // For the MVP there is at most one table whose number is 0, but we can't
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyInstrBulkMemory.td b/llvm/lib/Target/WebAssembly/WebAssemblyInstrBulkMemory.td
index 7aeae54d95a8c9..5ffe0d22d3e112 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyInstrBulkMemory.td
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyInstrBulkMemory.td
@@ -16,8 +16,7 @@ multiclass BULK_I<dag oops_r, dag iops_r, dag oops_s, dag iops_s,
                   list<dag> pattern_r, string asmstr_r = "",
                   string asmstr_s = "", bits<32> simdop = -1> {
   defm "" : I<oops_r, iops_r, oops_s, iops_s, pattern_r, asmstr_r, asmstr_s,
-              !or(0xfc00, !and(0xff, simdop))>,
-            Requires<[HasBulkMemory]>;
+              !or(0xfc00, !and(0xff, simdop))>;
 }
 
 // Bespoke types and nodes for bulk memory ops
@@ -43,13 +42,15 @@ defm MEMORY_INIT_A#B :
          (outs), (ins i32imm_op:$seg, i32imm_op:$idx),
          [],
          "memory.init\t$seg, $idx, $dest, $offset, $size",
-         "memory.init\t$seg, $idx", 0x08>;
+         "memory.init\t$seg, $idx", 0x08>,
+  Requires<[HasBulkMemory]>;
 
 let hasSideEffects = 1 in
 defm DATA_DROP :
   BULK_I<(outs), (ins i32imm_op:$seg), (outs), (ins i32imm_op:$seg),
          [],
-         "data.drop\t$seg", "data.drop\t$seg", 0x09>;
+         "data.drop\t$seg", "data.drop\t$seg", 0x09>,
+  Requires<[HasBulkMemory]>;
 
 let mayLoad = 1, mayStore = 1 in
 defm MEMORY_COPY_A#B :
@@ -60,7 +61,8 @@ defm MEMORY_COPY_A#B :
            rc:$dst, rc:$src, rc:$len
          )],
          "memory.copy\t$src_idx, $dst_idx, $dst, $src, $len",
-         "memory.copy\t$src_idx, $dst_idx", 0x0a>;
+         "memory.copy\t$src_idx, $dst_idx", 0x0a>,
+  Requires<[HasBulkMemoryOpt]>;
 
 let mayStore = 1 in
 defm MEMORY_FILL_A#B :
@@ -68,7 +70,8 @@ defm MEMORY_FILL_A#B :
          (outs), (ins i32imm_op:$idx),
          [(wasm_memset (i32 imm:$idx), rc:$dst, I32:$value, rc:$size)],
          "memory.fill\t$idx, $dst, $value, $size",
-         "memory.fill\t$idx", 0x0b>;
+         "memory.fill\t$idx", 0x0b>,
+  Requires<[HasBulkMemoryOpt]>;
 }
 
 defm : BulkMemoryOps<I32, "32">;
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td b/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td
index 767ac86f1351b5..05415b658c13aa 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td
@@ -30,6 +30,10 @@ def HasBulkMemory :
     Predicate<"Subtarget->hasBulkMemory()">,
     AssemblerPredicate<(all_of FeatureBulkMemory), "bulk-memory">;
 
+def HasBulkMemoryOpt :
+    Predicate<"Subtarget->hasBulkMemoryOpt()">,
+    AssemblerPredicate<(all_of FeatureBulkMemoryOpt), "bulk-memory-opt">;
+
 def HasExceptionHandling :
     Predicate<"Subtarget->hasExceptionHandling()">,
     AssemblerPredicate<(all_of FeatureExceptionHandling), "exception-handling">;
@@ -68,6 +72,10 @@ def HasReferenceTypes :
     Predicate<"Subtarget->hasReferenceTypes()">,
     AssemblerPredicate<(all_of FeatureReferenceTypes), "reference-types">;
 
+def HasCallIndirectOverlong :
+    Predicate<"Subtarget->hasCallIndirectOverlong()">,
+    AssemblerPredicate<(all_of FeatureCallIndirectOverlong), "call-indirect-overlong">;
+
 def HasRelaxedSIMD :
     Predicate<"Subtarget->hasRelaxedSIMD()">,
     AssemblerPredicate<(all_of FeatureRelaxedSIMD), "relaxed-simd">;
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblySelectionDAGInfo.cpp b/llvm/lib/Target/WebAssembly/WebAssemblySelectionDAGInfo.cpp
index 74af4c8873f735..3ca0e3f468a6e4 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblySelectionDAGInfo.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblySelectionDAGInfo.cpp
@@ -23,7 +23,7 @@ SDValue WebAssemblySelectionDAGInfo::EmitTargetCodeForMemcpy(
     SDValue Size, Align Alignment, bool IsVolatile, bool AlwaysInline,
     MachinePointerInfo DstPtrInfo, MachinePointerInfo SrcPtrInfo) const {
   auto &ST = DAG.getMachineFunction().getSubtarget<WebAssemblySubtarget>();
-  if (!ST.hasBulkMemory())
+  if (!ST.hasBulkMemoryOpt())
     return SDValue();
 
   SDValue MemIdx = DAG.getConstant(0, DL, MVT::i32);
@@ -47,7 +47,7 @@ SDValue WebAssemblySelectionDAGInfo::EmitTargetCodeForMemset(
     SDValue Size, Align Alignment, bool IsVolatile, bool AlwaysInline,
     MachinePointerInfo DstPtrInfo) const {
   auto &ST = DAG.getMachineFunction().getSubtarget<WebAssemblySubtarget>();
-  if (!ST.hasBulkMemory())
+  if (!ST.hasBulkMemoryOpt())
     return SDValue();
 
   SDValue MemIdx = DAG.getConstant(0, DL, MVT::i32);
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.h b/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.h
index f990120775d155..09037436d92dfc 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.h
+++ b/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.h
@@ -41,6 +41,7 @@ class WebAssemblySubtarget final : public WebAssemblyGenSubtargetInfo {
 
   bool HasAtomics = false;
   bool HasBulkMemory = false;
+  bool HasBulkMemoryOpt = false;
   bool HasExceptionHandling = false;
   bool HasExtendedConst = false;
   bool HasFP16 = false;
@@ -49,6 +50,7 @@ class WebAssemblySubtarget final : public WebAssemblyGenSubtargetInfo {
   bool HasMutableGlobals = false;
   bool HasNontrappingFPToInt = false;
   bool HasReferenceTypes = false;
+  bool HasCallIndirectOverlong = false;
   bool HasSignExt = false;
   bool HasTailCall = false;
 
@@ -94,6 +96,7 @@ class WebAssemblySubtarget final : public WebAssemblyGenSubtargetInfo {
   bool hasAddr64() const { return TargetTriple.isArch64Bit(); }
   bool hasAtomics() const { return HasAtomics; }
   bool hasBulkMemory() const { return HasBulkMemory; }
+  bool hasBulkMemoryOpt() const { return HasBulkMemoryOpt; }
   bool hasExceptionHandling() const { return HasExceptionHandling; }
   bool hasExtendedConst() const { return HasExtendedConst; }
   bool hasFP16() const { return HasFP16; }
@@ -102,6 +105,7 @@ class WebAssemblySubtarget final : public WebAssemblyGenSubtargetInfo {
   bool hasMutableGlobals() const { return HasMutableGlobals; }
   bool hasNontrappingFPToInt() const { return HasNontrappingFPToInt; }
   bool hasReferenceTypes() const { return HasReferenceTypes; }
+  bool hasCallIndirectOverlong() const { return HasCallIndirectOverlong; }
   bool hasRelaxedSIMD() const { return SIMDLevel >= RelaxedSIMD; }
   bool hasSignExt() const { return HasSignExt; }
   bool hasSIMD128() const { return SIMDLevel >= SIMD128; }
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp
index ed186e65a80cf9..ea18caea2b7e1a 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp
@@ -117,7 +117,7 @@ MCSymbolWasm *WebAssembly::getOrCreateFunctionTableSymbol(
     Sym->setUndefined();
   }
   // MVP object files can't have symtab entries for tables.
-  if (!(Subtarget && Subtarget->hasReferenceTypes()))
+  if (!(Subtarget && Subtarget->hasCallIndirectOverlong()))
     Sym->setOmitFromLinkingSection();
   return Sym;
 }
@@ -142,7 +142,7 @@ MCSymbolWasm *WebAssembly::getOrCreateFuncrefCallTableSymbol(
     Sym->setTableType(TableType);
   }
   // MVP object files can't have symtab entries for tables.
-  if (!(Subtarget && Subtarget->hasReferenceTypes()))
+  if (!(Subtarget && Subtarget->hasCallIndirectOverlong()))
     Sym->setOmitFromLinkingSection();
   return Sym;
 }
diff --git a/llvm/test/CodeGen/WebAssembly/bulk-memory.ll b/llvm/test/CodeGen/WebAssembly/bulk-memory.ll
index dc29dc81c13ec2..a2dae3890b1f0e 100644
--- a/llvm/test/CodeGen/WebAssembly/bulk-memory.ll
+++ b/llvm/test/CodeGen/WebAssembly/bulk-memory.ll
@@ -1,7 +1,7 @@
-; RUN: llc < %s -asm-verbose=false -verify-machineinstrs -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -wasm-keep-registers -mcpu=mvp -mattr=+bulk-memory | FileCheck %s --check-prefixes CHECK,BULK-MEM
-; RUN: llc < %s -asm-verbose=false -verify-machineinstrs -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -wasm-keep-registers -mcpu=mvp -mattr=-bulk-memory | FileCheck %s --check-prefixes CHECK,NO-BULK-MEM
+; RUN: llc < %s -asm-verbose=false -verify-machineinstrs -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -wasm-keep-registers -mcpu=mvp -mattr=+bulk-memory-opt | FileCheck %s --check-prefixes CHECK,BULK-MEM
+; RUN: llc < %s -asm-verbose=false -verify-machineinstrs -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -wasm-keep-registers -mcpu=mvp -mattr=-bulk-memory-opt | FileCheck %s --check-prefixes CHECK,NO-BULK-MEM
 
-; Test that basic bulk memory codegen works correctly
+; Test that basic bulk-memory-opt codegen works correctly
 
 target triple = "wasm32-unknown-unknown"
 
diff --git a/llvm/test/CodeGen/WebAssembly/bulk-memory64.ll b/llvm/test/CodeGen/WebAssembly/bulk-memory64.ll
index 8ee5f6314381cd..92d66c1abf90b4 100644
--- a/llvm/test/CodeGen/WebAssembly/bulk-memory64.ll
+++ b/llvm/test/CodeGen/WebAssembly/bulk-memory64.ll
@@ -1,7 +1,7 @@
-; RUN: llc < %s -asm-verbose=false -verify-machineinstrs -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -wasm-keep-registers -mcpu=mvp -mattr=+bulk-memory | FileCheck %s --check-prefixes CHECK,BULK-MEM
-; RUN: llc < %s -asm-verbose=false -verify-machineinstrs -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -wasm-keep-registers -mcpu=mvp -mattr=-bulk-memory | FileCheck %s --check-prefixes CHECK,NO-BULK-MEM
+; RUN: llc < %s -asm-verbose=false -verify-machineinstrs -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -wasm-keep-registers -mcpu=mvp -mattr=+bulk-memory-opt | FileCheck %s --check-prefixes CHECK,BULK-MEM
+; RUN: llc < %s -asm-verbose=false -verify-machineinstrs -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -wasm-keep-registers -mcpu=mvp -mattr=-bulk-memory-opt | FileCheck %s --check-prefixes CHECK,NO-BULK-MEM
 
-; Test that basic bulk memory codegen works correctly
+; Test that basic bulk memory opt codegen works correctly
 
 target triple = "wasm64-unknown-unknown"
 

>From 55fc5af799a21f186df2f5a8579da4c6713efe94 Mon Sep 17 00:00:00 2001
From: Dan Gohman <dev at sunfishcode.online>
Date: Fri, 11 Oct 2024 17:04:25 -0700
Subject: [PATCH 2/4] Add a target-features-cpus test for trail1.

---
 .../WebAssembly/target-features-cpus.ll       | 26 +++++++++++++++++++
 1 file changed, 26 insertions(+)

diff --git a/llvm/test/CodeGen/WebAssembly/target-features-cpus.ll b/llvm/test/CodeGen/WebAssembly/target-features-cpus.ll
index 77d1564409f78c..a37abfaf884180 100644
--- a/llvm/test/CodeGen/WebAssembly/target-features-cpus.ll
+++ b/llvm/test/CodeGen/WebAssembly/target-features-cpus.ll
@@ -1,5 +1,6 @@
 ; RUN: llc < %s -mcpu=mvp | FileCheck %s --check-prefixes MVP
 ; RUN: llc < %s -mcpu=generic | FileCheck %s --check-prefixes GENERIC
+; RUN: llc < %s -mcpu=trail1 | FileCheck %s --check-prefixes TRAIL1
 ; RUN: llc < %s | FileCheck %s --check-prefixes GENERIC
 ; RUN: llc < %s -mcpu=bleeding-edge | FileCheck %s --check-prefixes BLEEDING-EDGE
 
@@ -27,6 +28,31 @@ target triple = "wasm32-unknown-unknown"
 ; GENERIC-NEXT: .int8  8
 ; GENERIC-NEXT: .ascii  "sign-ext"
 
+; trail1: +bulk-memory-opt, +call-indirect-overlong, +extended-const, +multivalue, +mutable-globals, +nontrapping-fptoint, +sign-ext
+; TRAIL1-LABEL: .custom_section.target_features,"",@
+; TRAIL1-NEXT: .int8  6
+; TRAIL1-NEXT: .int8  43
+; TRAIL1-NEXT: .int8  15
+; TRAIL1-NEXT: .int8  "bulk-memory-opt"
+; TRAIL1-NEXT: .int8  43
+; TRAIL1-NEXT: .int8  22
+; TRAIL1-NEXT: .int8  "call-indirect-overlong"
+; TRAIL1-NEXT: .int8  43
+; TRAIL1-NEXT: .int8  14
+; TRAIL1-NEXT: .ascii  "extended-const"
+; TRAIL1-NEXT: .int8  43
+; TRAIL1-NEXT: .int8  10
+; TRAIL1-NEXT: .ascii  "multivalue"
+; TRAIL1-NEXT: .int8  43
+; TRAIL1-NEXT: .int8  15
+; TRAIL1-NEXT: .ascii  "mutable-globals"
+; TRAIL1-NEXT: .int8  43
+; TRAIL1-NEXT: .int8  19
+; TRAIL1-NEXT: .ascii  "nontrapping-fptoint"
+; TRAIL1-NEXT: .int8  43
+; TRAIL1-NEXT: .int8  8
+; TRAIL1-NEXT: .ascii  "sign-ext"
+
 ; bleeding-edge: +atomics, +bulk-memory, +exception-handling, +extended-const,
 ;                +fp16, +multimemory, +multivalue, +mutable-globals,
 ;                +nontrapping-fptoint, +relaxed-simd, +reference-types,

>From 24e58550483c0569e48f9b1e11edaee5acb1ac1e Mon Sep 17 00:00:00 2001
From: Dan Gohman <dev at sunfishcode.online>
Date: Fri, 11 Oct 2024 09:53:30 -0700
Subject: [PATCH 3/4] call-indirect-overlong is implied by reference-types.

---
 .../AsmParser/WebAssemblyAsmParser.cpp            | 15 +++++++++------
 llvm/lib/Target/WebAssembly/WebAssembly.td        |  9 +++++----
 .../lib/Target/WebAssembly/WebAssemblySubtarget.h |  4 ++--
 3 files changed, 16 insertions(+), 12 deletions(-)

diff --git a/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp b/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp
index 091b3ffb8b25d2..197d5723804f21 100644
--- a/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp
+++ b/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp
@@ -292,7 +292,8 @@ class WebAssemblyAsmParser final : public MCTargetAsmParser {
 
     DefaultFunctionTable = getOrCreateFunctionTableSymbol(
         getContext(), "__indirect_function_table", Is64);
-    if (!STI->checkFeatures("+call-indirect-overlong"))
+    if (!STI->checkFeatures("+call-indirect-overlong") &&
+        !STI->checkFeatures("+reference-types"))
       DefaultFunctionTable->setOmitFromLinkingSection();
   }
 
@@ -532,11 +533,13 @@ class WebAssemblyAsmParser final : public MCTargetAsmParser {
   }
 
   bool parseFunctionTableOperand(std::unique_ptr<WebAssemblyOperand> *Op) {
-    if (STI->checkFeatures("+call-indirect-overlong")) {
-      // If the call-indirect-overlong feature is enabled, there is an explicit
-      // table operand.  To allow the same assembly to be compiled with or
-      // without call-indirect overlong, we allow the operand to be omitted, in
-      // which case we default to __indirect_function_table.
+    if (STI->checkFeatures("+call-indirect-overlong") ||
+        STI->checkFeatures("+reference-types")) {
+      // If the call-indirect-overlong feature is enabled, or implied by the
+      // reference-types feature, there is an explicit table operand.  To allow
+      // the same assembly to be compiled with or without
+      // call-indirect-overlong, we allow the operand to be omitted, in which
+      // case we default to __indirect_function_table.
       auto &Tok = Lexer.getTok();
       if (Tok.is(AsmToken::Identifier)) {
         auto *Sym =
diff --git a/llvm/lib/Target/WebAssembly/WebAssembly.td b/llvm/lib/Target/WebAssembly/WebAssembly.td
index 7081ee48132a07..2f5d2aae00d067 100644
--- a/llvm/lib/Target/WebAssembly/WebAssembly.td
+++ b/llvm/lib/Target/WebAssembly/WebAssembly.td
@@ -119,7 +119,8 @@ def : ProcessorModel<"mvp", NoSchedModel, []>;
 // the importance of the features.
 def : ProcessorModel<"generic", NoSchedModel,
                       [FeatureMultivalue, FeatureMutableGlobals,
-                       FeatureReferenceTypes, FeatureSignExt]>;
+                       FeatureReferenceTypes, FeatureCallIndirectOverlong,
+                       FeatureSignExt]>;
 
 def : ProcessorModel<"trail1", NoSchedModel,
                       [FeatureMultivalue, FeatureMutableGlobals,
@@ -129,13 +130,13 @@ def : ProcessorModel<"trail1", NoSchedModel,
 
 // Latest and greatest experimental version of WebAssembly. Bugs included!
 def : ProcessorModel<"bleeding-edge", NoSchedModel,
-                      [FeatureAtomics, FeatureBulkMemory,
+                      [FeatureAtomics, FeatureBulkMemory, FeatureBulkMemoryOpt,
                        FeatureExceptionHandling, FeatureExtendedConst,
                        FeatureFP16, FeatureMultiMemory,
                        FeatureMultivalue, FeatureMutableGlobals,
                        FeatureNontrappingFPToInt, FeatureRelaxedSIMD,
-                       FeatureReferenceTypes, FeatureSIMD128, FeatureSignExt,
-                       FeatureTailCall]>;
+                       FeatureReferenceTypes, FeatureCallIndirectOverlong,
+                       FeatureSIMD128, FeatureSignExt, FeatureTailCall]>;
 
 //===----------------------------------------------------------------------===//
 // Target Declaration
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.h b/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.h
index 09037436d92dfc..8e623d694d204c 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.h
+++ b/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.h
@@ -96,7 +96,7 @@ class WebAssemblySubtarget final : public WebAssemblyGenSubtargetInfo {
   bool hasAddr64() const { return TargetTriple.isArch64Bit(); }
   bool hasAtomics() const { return HasAtomics; }
   bool hasBulkMemory() const { return HasBulkMemory; }
-  bool hasBulkMemoryOpt() const { return HasBulkMemoryOpt; }
+  bool hasBulkMemoryOpt() const { return HasBulkMemoryOpt || HasBulkMemory; }
   bool hasExceptionHandling() const { return HasExceptionHandling; }
   bool hasExtendedConst() const { return HasExtendedConst; }
   bool hasFP16() const { return HasFP16; }
@@ -105,7 +105,7 @@ class WebAssemblySubtarget final : public WebAssemblyGenSubtargetInfo {
   bool hasMutableGlobals() const { return HasMutableGlobals; }
   bool hasNontrappingFPToInt() const { return HasNontrappingFPToInt; }
   bool hasReferenceTypes() const { return HasReferenceTypes; }
-  bool hasCallIndirectOverlong() const { return HasCallIndirectOverlong; }
+  bool hasCallIndirectOverlong() const { return HasCallIndirectOverlong || HasReferenceTypes; }
   bool hasRelaxedSIMD() const { return SIMDLevel >= RelaxedSIMD; }
   bool hasSignExt() const { return HasSignExt; }
   bool hasSIMD128() const { return SIMDLevel >= SIMD128; }

>From cc803bfbeb7ab01a4a88ffd611d4ab333e1381c4 Mon Sep 17 00:00:00 2001
From: Dan Gohman <dev at sunfishcode.online>
Date: Fri, 11 Oct 2024 21:48:34 -0700
Subject: [PATCH 4/4] Handle features implying other features in the Subtarget
 constructor.

---
 llvm/lib/Target/WebAssembly/WebAssemblySubtarget.cpp | 9 +++++++++
 llvm/lib/Target/WebAssembly/WebAssemblySubtarget.h   | 4 ++--
 2 files changed, 11 insertions(+), 2 deletions(-)

diff --git a/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.cpp b/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.cpp
index 912f61765579f8..7df15eb767093e 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.cpp
@@ -34,6 +34,15 @@ WebAssemblySubtarget::initializeSubtargetDependencies(StringRef CPU,
     CPU = "generic";
 
   ParseSubtargetFeatures(CPU, /*TuneCPU*/ CPU, FS);
+
+  // reference-types implies call-indirect-overlong
+  if (HasReferenceTypes)
+    HasCallIndirectOverlong = true;
+
+  // bulk-memory implies bulk-memory-opt
+  if (HasBulkMemory)
+    HasBulkMemoryOpt = true;
+
   return *this;
 }
 
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.h b/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.h
index 8e623d694d204c..09037436d92dfc 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.h
+++ b/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.h
@@ -96,7 +96,7 @@ class WebAssemblySubtarget final : public WebAssemblyGenSubtargetInfo {
   bool hasAddr64() const { return TargetTriple.isArch64Bit(); }
   bool hasAtomics() const { return HasAtomics; }
   bool hasBulkMemory() const { return HasBulkMemory; }
-  bool hasBulkMemoryOpt() const { return HasBulkMemoryOpt || HasBulkMemory; }
+  bool hasBulkMemoryOpt() const { return HasBulkMemoryOpt; }
   bool hasExceptionHandling() const { return HasExceptionHandling; }
   bool hasExtendedConst() const { return HasExtendedConst; }
   bool hasFP16() const { return HasFP16; }
@@ -105,7 +105,7 @@ class WebAssemblySubtarget final : public WebAssemblyGenSubtargetInfo {
   bool hasMutableGlobals() const { return HasMutableGlobals; }
   bool hasNontrappingFPToInt() const { return HasNontrappingFPToInt; }
   bool hasReferenceTypes() const { return HasReferenceTypes; }
-  bool hasCallIndirectOverlong() const { return HasCallIndirectOverlong || HasReferenceTypes; }
+  bool hasCallIndirectOverlong() const { return HasCallIndirectOverlong; }
   bool hasRelaxedSIMD() const { return SIMDLevel >= RelaxedSIMD; }
   bool hasSignExt() const { return HasSignExt; }
   bool hasSIMD128() const { return SIMDLevel >= SIMD128; }



More information about the cfe-commits mailing list