forked from OSchip/llvm-project
[WebAssembly][NFC] Remove WebAssemblyStackifier TableGen backend
Summary: Replace its functionality with a TableGen InstrInfo relational instruction mapping. Although arguably more complex than the TableGen backend, the relational mapping is a smaller maintenance burden than a TableGen backend. Reviewers: aardappel, aheejin, dschuff Subscribers: mgorny, sbc100, jgravelle-google, sunfish, llvm-commits Differential Revision: https://reviews.llvm.org/D53307 llvm-svn: 344962
This commit is contained in:
parent
ca1c9791e3
commit
c63b5fcb2a
|
@ -9,7 +9,6 @@ tablegen(LLVM WebAssemblyGenInstrInfo.inc -gen-instr-info)
|
|||
tablegen(LLVM WebAssemblyGenMCCodeEmitter.inc -gen-emitter)
|
||||
tablegen(LLVM WebAssemblyGenRegisterInfo.inc -gen-register-info)
|
||||
tablegen(LLVM WebAssemblyGenSubtargetInfo.inc -gen-subtarget)
|
||||
tablegen(LLVM WebAssemblyGenStackifier.inc -gen-wasm-stackifier)
|
||||
|
||||
add_public_tablegen_target(WebAssemblyCommonTableGen)
|
||||
|
||||
|
|
|
@ -43,26 +43,28 @@ def : Pat<(brcond (i32 (seteq I32:$cond, 0)), bb:$dst),
|
|||
let isTerminator = 1, hasCtrlDep = 1, isBarrier = 1 in {
|
||||
let isCodeGenOnly = 1 in
|
||||
def BR_TABLE_I32 : NI<(outs), (ins I32:$index, variable_ops),
|
||||
[(WebAssemblybr_table I32:$index)], 0,
|
||||
[(WebAssemblybr_table I32:$index)], "false",
|
||||
"br_table \t$index", 0x0e> {
|
||||
let TSFlags{0} = 1;
|
||||
let TSFlags{1} = 1;
|
||||
}
|
||||
let BaseName = "BR_TABLE_I32" in
|
||||
def BR_TABLE_I32_S : NI<(outs), (ins variable_ops),
|
||||
[], 1,
|
||||
[], "true",
|
||||
"br_table", 0x0e> {
|
||||
let TSFlags{0} = 1;
|
||||
let TSFlags{1} = 1;
|
||||
}
|
||||
let isCodeGenOnly = 1 in
|
||||
def BR_TABLE_I64 : NI<(outs), (ins I64:$index, variable_ops),
|
||||
[(WebAssemblybr_table I64:$index)], 0,
|
||||
[(WebAssemblybr_table I64:$index)], "false",
|
||||
"br_table \t$index"> {
|
||||
let TSFlags{0} = 1;
|
||||
let TSFlags{1} = 1;
|
||||
}
|
||||
let BaseName = "BR_TABLE_I64" in
|
||||
def BR_TABLE_I64_S : NI<(outs), (ins variable_ops),
|
||||
[], 1,
|
||||
[], "true",
|
||||
"br_table"> {
|
||||
let TSFlags{0} = 1;
|
||||
let TSFlags{1} = 1;
|
||||
|
|
|
@ -15,17 +15,19 @@
|
|||
// WebAssembly Instruction Format.
|
||||
// We instantiate 2 of these for every actual instruction (register based
|
||||
// and stack based), see below.
|
||||
class WebAssemblyInst<bits<32> inst, string asmstr, bit stack> : Instruction {
|
||||
field bits<32> Inst = inst; // Instruction encoding.
|
||||
field bit StackBased = stack;
|
||||
class WebAssemblyInst<bits<32> inst, string asmstr, string stack> : StackRel,
|
||||
Instruction {
|
||||
bits<32> Inst = inst; // Instruction encoding.
|
||||
string StackBased = stack;
|
||||
string BaseName = NAME;
|
||||
let Namespace = "WebAssembly";
|
||||
let Pattern = [];
|
||||
let AsmString = asmstr;
|
||||
}
|
||||
|
||||
// Normal instructions. Default instantiation of a WebAssemblyInst.
|
||||
class NI<dag oops, dag iops, list<dag> pattern, bit stack, string asmstr = "",
|
||||
bits<32> inst = -1>
|
||||
class NI<dag oops, dag iops, list<dag> pattern, string stack,
|
||||
string asmstr = "", bits<32> inst = -1>
|
||||
: WebAssemblyInst<inst, asmstr, stack> {
|
||||
dag OutOperandList = oops;
|
||||
dag InOperandList = iops;
|
||||
|
@ -50,8 +52,9 @@ multiclass 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> inst = -1> {
|
||||
let isCodeGenOnly = 1 in
|
||||
def "" : NI<oops_r, iops_r, pattern_r, 0, asmstr_r, inst>;
|
||||
def _S : NI<oops_s, iops_s, [], 1, asmstr_s, inst>;
|
||||
def "" : NI<oops_r, iops_r, pattern_r, "false", asmstr_r, inst>;
|
||||
let BaseName = NAME in
|
||||
def _S : NI<oops_s, iops_s, [], "true", asmstr_s, inst>;
|
||||
}
|
||||
|
||||
// For instructions that have no register ops, so both sets are the same.
|
||||
|
|
|
@ -153,6 +153,19 @@ def TypeIndex : Operand<i32>;
|
|||
|
||||
} // OperandNamespace = "WebAssembly"
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// WebAssembly Register to Stack instruction mapping
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
class StackRel;
|
||||
def getStackOpcode : InstrMapping {
|
||||
let FilterClass = "StackRel";
|
||||
let RowFields = ["BaseName"];
|
||||
let ColFields = ["StackBased"];
|
||||
let KeyCol = ["false"];
|
||||
let ValueCols = [["true"]];
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// WebAssembly Instruction Format Definitions.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
|
|
@ -30,6 +30,11 @@
|
|||
#include "llvm/Support/raw_ostream.h"
|
||||
using namespace llvm;
|
||||
|
||||
// Defines llvm::WebAssembly::getStackOpcode to convert register instructions to
|
||||
// stack instructions
|
||||
#define GET_INSTRMAP_INFO 1
|
||||
#include "WebAssemblyGenInstrInfo.inc"
|
||||
|
||||
// This disables the removal of registers when lowering into MC, as required
|
||||
// by some current tests.
|
||||
static cl::opt<bool>
|
||||
|
@ -38,7 +43,6 @@ static cl::opt<bool>
|
|||
" instruction output for test purposes only."),
|
||||
cl::init(false));
|
||||
|
||||
static unsigned regInstructionToStackInstruction(unsigned OpCode);
|
||||
static void removeRegisterOperands(const MachineInstr *MI, MCInst &OutMI);
|
||||
|
||||
MCSymbol *
|
||||
|
@ -254,7 +258,8 @@ static void removeRegisterOperands(const MachineInstr *MI, MCInst &OutMI) {
|
|||
|
||||
// Transform to _S instruction.
|
||||
auto RegOpcode = OutMI.getOpcode();
|
||||
auto StackOpcode = regInstructionToStackInstruction(RegOpcode);
|
||||
auto StackOpcode = WebAssembly::getStackOpcode(RegOpcode);
|
||||
assert(StackOpcode != -1 && "Failed to stackify instruction");
|
||||
OutMI.setOpcode(StackOpcode);
|
||||
|
||||
// Remove register operands.
|
||||
|
@ -265,21 +270,3 @@ static void removeRegisterOperands(const MachineInstr *MI, MCInst &OutMI) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned regInstructionToStackInstruction(unsigned OpCode) {
|
||||
// For most opcodes, this function could have been implemented as "return
|
||||
// OpCode + 1", but since table-gen alphabetically sorts them, this cannot be
|
||||
// guaranteed (see e.g. BR and BR_IF). Instead we use a giant switch statement
|
||||
// generated by a custom TableGen backend (WebAssemblyStackifierEmitter.cpp)
|
||||
// that emits switch cases of the form
|
||||
//
|
||||
// case WebAssembly::RegisterInstr: return WebAssembly::StackInstr;
|
||||
//
|
||||
// for every pair of equivalent register and stack instructions.
|
||||
switch (OpCode) {
|
||||
default:
|
||||
llvm_unreachable(
|
||||
"unknown WebAssembly instruction in WebAssemblyMCInstLower pass");
|
||||
#include "WebAssemblyGenStackifier.inc"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -46,7 +46,6 @@ add_tablegen(llvm-tblgen LLVM
|
|||
X86ModRMFilters.cpp
|
||||
X86RecognizableInstr.cpp
|
||||
WebAssemblyDisassemblerEmitter.cpp
|
||||
WebAssemblyStackifierEmitter.cpp
|
||||
CTagsEmitter.cpp
|
||||
)
|
||||
set_target_properties(llvm-tblgen PROPERTIES FOLDER "Tablegenning")
|
||||
|
|
|
@ -53,7 +53,6 @@ enum ActionType {
|
|||
GenX86EVEX2VEXTables,
|
||||
GenX86FoldTables,
|
||||
GenRegisterBank,
|
||||
GenWebAssemblyStackifier,
|
||||
};
|
||||
|
||||
namespace {
|
||||
|
@ -118,9 +117,7 @@ namespace {
|
|||
clEnumValN(GenX86FoldTables, "gen-x86-fold-tables",
|
||||
"Generate X86 fold tables"),
|
||||
clEnumValN(GenRegisterBank, "gen-register-bank",
|
||||
"Generate registers bank descriptions"),
|
||||
clEnumValN(GenWebAssemblyStackifier, "gen-wasm-stackifier",
|
||||
"Generate WebAssembly stackification cases")));
|
||||
"Generate registers bank descriptions")));
|
||||
|
||||
cl::OptionCategory PrintEnumsCat("Options for -print-enums");
|
||||
cl::opt<std::string>
|
||||
|
@ -234,9 +231,6 @@ bool LLVMTableGenMain(raw_ostream &OS, RecordKeeper &Records) {
|
|||
case GenX86FoldTables:
|
||||
EmitX86FoldTables(Records, OS);
|
||||
break;
|
||||
case GenWebAssemblyStackifier:
|
||||
EmitWebAssemblyStackifier(Records, OS);
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
|
|
@ -89,7 +89,6 @@ void EmitGlobalISel(RecordKeeper &RK, raw_ostream &OS);
|
|||
void EmitX86EVEX2VEXTables(RecordKeeper &RK, raw_ostream &OS);
|
||||
void EmitX86FoldTables(RecordKeeper &RK, raw_ostream &OS);
|
||||
void EmitRegisterBank(RecordKeeper &RK, raw_ostream &OS);
|
||||
void EmitWebAssemblyStackifier(RecordKeeper &RK, raw_ostream &OS);
|
||||
|
||||
} // End llvm namespace
|
||||
|
||||
|
|
|
@ -42,12 +42,13 @@ void emitWebAssemblyDisassemblerTables(
|
|||
auto Prefix = Opc >> 8;
|
||||
Opc = Opc & 0xFF;
|
||||
auto &CGIP = OpcodeTable[Prefix][Opc];
|
||||
// All wasm instructions have a StackBased fieldof type bit, we only want
|
||||
// the instructions for which this is 1.
|
||||
auto Bit = Def.getValue("StackBased")->getValue()->
|
||||
getCastTo(BitRecTy::get());
|
||||
auto IsStackBased = Bit && reinterpret_cast<const BitInit *>(Bit)
|
||||
->getValue();
|
||||
// All wasm instructions have a StackBased field of type string, we only
|
||||
// want the instructions for which this is "true".
|
||||
auto StackString =
|
||||
Def.getValue("StackBased")->getValue()->getCastTo(StringRecTy::get());
|
||||
auto IsStackBased =
|
||||
StackString &&
|
||||
reinterpret_cast<const StringInit *>(StackString)->getValue() == "true";
|
||||
if (IsStackBased && !CGIP.second) {
|
||||
// this picks the first of many typed variants, which is
|
||||
// currently the except_ref one, though this shouldn't matter for
|
||||
|
|
|
@ -1,44 +0,0 @@
|
|||
//===- WebAssemblyStackifierEmitter.cpp - Stackifier cases ------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file emits the switch statement cases to translate WebAssembly
|
||||
// instructions to their stack forms.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "WebAssemblyDisassemblerEmitter.h"
|
||||
#include "llvm/TableGen/Record.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
// Find all register WebAssembly instructions and their corresponding stack
|
||||
// instructions. For each pair, emit a switch case of the form
|
||||
//
|
||||
// case WebAssembly::RegisterInstr: return WebAssembly::StackInstr;
|
||||
//
|
||||
// For example,
|
||||
//
|
||||
// case WebAssembly::ADD_I32: return WebAssembly::ADD_I32_S;
|
||||
//
|
||||
// This is useful for converting instructions from their register form to their
|
||||
// equivalent stack form.
|
||||
void EmitWebAssemblyStackifier(RecordKeeper &RK, raw_ostream &OS) {
|
||||
Record *InstrClass = RK.getClass("WebAssemblyInst");
|
||||
for (auto &RecordPair : RK.getDefs()) {
|
||||
if (!RecordPair.second->isSubClassOf(InstrClass))
|
||||
continue;
|
||||
bool IsStackBased = RecordPair.second->getValueAsBit("StackBased");
|
||||
if (IsStackBased)
|
||||
continue;
|
||||
OS << " case WebAssembly::" << RecordPair.first << ": return "
|
||||
<< "WebAssembly::" << RecordPair.first << "_S;\n";
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace llvm
|
Loading…
Reference in New Issue