[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:
Thomas Lively 2018-10-22 21:55:26 +00:00
parent ca1c9791e3
commit c63b5fcb2a
10 changed files with 44 additions and 91 deletions

View File

@ -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)

View File

@ -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;

View File

@ -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.

View File

@ -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.
//===----------------------------------------------------------------------===//

View File

@ -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"
}
}

View File

@ -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")

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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