2004-08-01 13:59:33 +08:00
|
|
|
//===- AsmWriterEmitter.cpp - Generate an assembly writer -----------------===//
|
2005-04-22 08:00:37 +08:00
|
|
|
//
|
2019-01-19 16:50:56 +08:00
|
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
2005-04-22 08:00:37 +08:00
|
|
|
//
|
2004-08-01 13:59:33 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
2016-02-24 03:18:21 +08:00
|
|
|
// This tablegen backend emits an assembly printer for the current target.
|
2004-08-01 13:59:33 +08:00
|
|
|
// Note that this is currently fairly skeletal, but will grow over time.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2010-02-10 05:50:41 +08:00
|
|
|
#include "AsmWriterInst.h"
|
2016-12-01 01:48:10 +08:00
|
|
|
#include "CodeGenInstruction.h"
|
|
|
|
#include "CodeGenRegisters.h"
|
2004-08-01 13:59:33 +08:00
|
|
|
#include "CodeGenTarget.h"
|
2012-03-31 05:12:52 +08:00
|
|
|
#include "SequenceToOffsetTable.h"
|
2016-11-19 20:21:34 +08:00
|
|
|
#include "Types.h"
|
2016-12-01 01:48:10 +08:00
|
|
|
#include "llvm/ADT/ArrayRef.h"
|
|
|
|
#include "llvm/ADT/DenseMap.h"
|
2014-04-30 07:26:49 +08:00
|
|
|
#include "llvm/ADT/SmallString.h"
|
2016-12-01 01:48:10 +08:00
|
|
|
#include "llvm/ADT/SmallVector.h"
|
|
|
|
#include "llvm/ADT/STLExtras.h"
|
2012-07-27 14:44:02 +08:00
|
|
|
#include "llvm/ADT/StringExtras.h"
|
2016-12-01 01:48:10 +08:00
|
|
|
#include "llvm/ADT/StringRef.h"
|
2011-06-28 05:06:21 +08:00
|
|
|
#include "llvm/ADT/Twine.h"
|
2016-12-01 01:48:10 +08:00
|
|
|
#include "llvm/Support/Casting.h"
|
2006-07-19 01:18:03 +08:00
|
|
|
#include "llvm/Support/Debug.h"
|
2016-12-01 01:48:10 +08:00
|
|
|
#include "llvm/Support/ErrorHandling.h"
|
2013-09-11 23:42:16 +08:00
|
|
|
#include "llvm/Support/Format.h"
|
[MC] Rewrite tablegen for printInstrAlias to comiple faster, NFC
Before this change, the *InstPrinter.cpp files of each target where some
of the slowest objects to compile in all of LLVM. See this snippet produced by
ClangBuildAnalyzer:
https://reviews.llvm.org/P8171$96
Search for "InstPrinter", and see that it shows up in a few places.
Tablegen was emitting a large switch containing a sequence of operand checks,
each of which created many conditions and many BBs. Register allocation and
jump threading both did not scale well with such a large repetitive sequence of
basic blocks.
So, this change essentially turns those control flow structures into
data. The previous structure looked like:
switch (Opc) {
case TGT::ADD:
// check alias 1
if (MI->getOperandCount() == N && // check num opnds
MI->getOperand(0).isReg() && // check opnd 0
...
MI->getOperand(1).isImm() && // check opnd 1
AsmString = "foo";
break;
}
// check alias 2
if (...)
...
return false;
The new structure looks like:
OpToPatterns: Sorted table of opcodes mapping to pattern indices.
\->
Patterns: List of patterns. Previous table points to subrange of
patterns to match.
\->
Conds: The if conditions above encoded as a kind and 32-bit value.
See MCInstPrinter.cpp for the details of how the new data structures are
interpreted.
Here are some before and after metrics.
Time to compile AArch64InstPrinter.cpp:
0m29.062s vs. 0m2.203s
size of the obj:
3.9M vs. 676K
size of clang.exe:
97M vs. 96M
I have not benchmarked disassembly performance, but typically
disassemblers are bottlenecked on IO and string processing, not alias
matching, so I'm not sure it's interesting enough to be worth doing.
Reviewers: RKSimon, andreadb, xbolva00, craig.topper
Reviewed By: craig.topper
Differential Revision: https://reviews.llvm.org/D70650
2019-11-24 03:28:54 +08:00
|
|
|
#include "llvm/Support/FormatVariadic.h"
|
2006-07-19 01:18:03 +08:00
|
|
|
#include "llvm/Support/MathExtras.h"
|
2016-12-01 01:48:10 +08:00
|
|
|
#include "llvm/Support/raw_ostream.h"
|
2011-10-02 00:41:13 +08:00
|
|
|
#include "llvm/TableGen/Error.h"
|
|
|
|
#include "llvm/TableGen/Record.h"
|
2012-06-11 23:37:55 +08:00
|
|
|
#include "llvm/TableGen/TableGenBackend.h"
|
2005-01-23 02:50:10 +08:00
|
|
|
#include <algorithm>
|
2012-06-11 23:37:55 +08:00
|
|
|
#include <cassert>
|
2016-12-01 01:48:10 +08:00
|
|
|
#include <cstddef>
|
|
|
|
#include <cstdint>
|
|
|
|
#include <deque>
|
|
|
|
#include <iterator>
|
2012-06-11 23:37:55 +08:00
|
|
|
#include <map>
|
2016-12-01 01:48:10 +08:00
|
|
|
#include <set>
|
|
|
|
#include <string>
|
|
|
|
#include <tuple>
|
2016-05-27 22:27:24 +08:00
|
|
|
#include <utility>
|
2012-06-11 23:37:55 +08:00
|
|
|
#include <vector>
|
2016-12-01 01:48:10 +08:00
|
|
|
|
2004-08-01 13:59:33 +08:00
|
|
|
using namespace llvm;
|
|
|
|
|
2014-04-22 06:55:11 +08:00
|
|
|
#define DEBUG_TYPE "asm-writer-emitter"
|
|
|
|
|
2012-06-11 23:37:55 +08:00
|
|
|
namespace {
|
2016-12-01 01:48:10 +08:00
|
|
|
|
2012-06-11 23:37:55 +08:00
|
|
|
class AsmWriterEmitter {
|
|
|
|
RecordKeeper &Records;
|
2013-10-29 02:07:17 +08:00
|
|
|
CodeGenTarget Target;
|
2016-01-18 04:38:14 +08:00
|
|
|
ArrayRef<const CodeGenInstruction *> NumberedInstructions;
|
2013-10-29 02:07:17 +08:00
|
|
|
std::vector<AsmWriterInst> Instructions;
|
2016-12-01 01:48:10 +08:00
|
|
|
|
2012-06-11 23:37:55 +08:00
|
|
|
public:
|
2013-10-29 02:07:17 +08:00
|
|
|
AsmWriterEmitter(RecordKeeper &R);
|
2012-06-11 23:37:55 +08:00
|
|
|
|
|
|
|
void run(raw_ostream &o);
|
|
|
|
private:
|
2020-11-17 17:38:17 +08:00
|
|
|
void EmitGetMnemonic(
|
|
|
|
raw_ostream &o,
|
|
|
|
std::vector<std::vector<std::string>> &TableDrivenOperandPrinters,
|
|
|
|
unsigned &BitsLeft, unsigned &AsmStrBits);
|
|
|
|
void EmitPrintInstruction(
|
|
|
|
raw_ostream &o,
|
|
|
|
std::vector<std::vector<std::string>> &TableDrivenOperandPrinters,
|
|
|
|
unsigned &BitsLeft, unsigned &AsmStrBits);
|
2012-06-11 23:37:55 +08:00
|
|
|
void EmitGetRegisterName(raw_ostream &o);
|
|
|
|
void EmitPrintAliasInstruction(raw_ostream &O);
|
|
|
|
|
|
|
|
void FindUniqueOperandCommands(std::vector<std::string> &UOC,
|
2016-01-24 15:13:28 +08:00
|
|
|
std::vector<std::vector<unsigned>> &InstIdxs,
|
2016-01-14 14:15:07 +08:00
|
|
|
std::vector<unsigned> &InstOpsUsed,
|
|
|
|
bool PassSubtarget) const;
|
2012-06-11 23:37:55 +08:00
|
|
|
};
|
2016-12-01 01:48:10 +08:00
|
|
|
|
2012-06-11 23:37:55 +08:00
|
|
|
} // end anonymous namespace
|
|
|
|
|
This is the final big of factoring. This shares cases in suboperand
differences, which means that identical instructions (after stripping off
the first literal string) do not run any different code at all. On the X86,
this turns this code:
switch (MI->getOpcode()) {
case X86::ADC32mi: printOperand(MI, 4, MVT::i32); break;
case X86::ADC32mi8: printOperand(MI, 4, MVT::i8); break;
case X86::ADC32mr: printOperand(MI, 4, MVT::i32); break;
case X86::ADD32mi: printOperand(MI, 4, MVT::i32); break;
case X86::ADD32mi8: printOperand(MI, 4, MVT::i8); break;
case X86::ADD32mr: printOperand(MI, 4, MVT::i32); break;
case X86::AND32mi: printOperand(MI, 4, MVT::i32); break;
case X86::AND32mi8: printOperand(MI, 4, MVT::i8); break;
case X86::AND32mr: printOperand(MI, 4, MVT::i32); break;
case X86::CMP32mi: printOperand(MI, 4, MVT::i32); break;
case X86::CMP32mr: printOperand(MI, 4, MVT::i32); break;
case X86::MOV32mi: printOperand(MI, 4, MVT::i32); break;
case X86::MOV32mr: printOperand(MI, 4, MVT::i32); break;
case X86::OR32mi: printOperand(MI, 4, MVT::i32); break;
case X86::OR32mi8: printOperand(MI, 4, MVT::i8); break;
case X86::OR32mr: printOperand(MI, 4, MVT::i32); break;
case X86::ROL32mi: printOperand(MI, 4, MVT::i8); break;
case X86::ROR32mi: printOperand(MI, 4, MVT::i8); break;
case X86::SAR32mi: printOperand(MI, 4, MVT::i8); break;
case X86::SBB32mi: printOperand(MI, 4, MVT::i32); break;
case X86::SBB32mi8: printOperand(MI, 4, MVT::i8); break;
case X86::SBB32mr: printOperand(MI, 4, MVT::i32); break;
case X86::SHL32mi: printOperand(MI, 4, MVT::i8); break;
case X86::SHLD32mrCL: printOperand(MI, 4, MVT::i32); break;
case X86::SHR32mi: printOperand(MI, 4, MVT::i8); break;
case X86::SHRD32mrCL: printOperand(MI, 4, MVT::i32); break;
case X86::SUB32mi: printOperand(MI, 4, MVT::i32); break;
case X86::SUB32mi8: printOperand(MI, 4, MVT::i8); break;
case X86::SUB32mr: printOperand(MI, 4, MVT::i32); break;
case X86::TEST32mi: printOperand(MI, 4, MVT::i32); break;
case X86::TEST32mr: printOperand(MI, 4, MVT::i32); break;
case X86::TEST8mi: printOperand(MI, 4, MVT::i8); break;
case X86::XCHG32mr: printOperand(MI, 4, MVT::i32); break;
case X86::XOR32mi: printOperand(MI, 4, MVT::i32); break;
case X86::XOR32mi8: printOperand(MI, 4, MVT::i8); break;
case X86::XOR32mr: printOperand(MI, 4, MVT::i32); break;
}
into this:
switch (MI->getOpcode()) {
case X86::ADC32mi:
case X86::ADC32mr:
case X86::ADD32mi:
case X86::ADD32mr:
case X86::AND32mi:
case X86::AND32mr:
case X86::CMP32mi:
case X86::CMP32mr:
case X86::MOV32mi:
case X86::MOV32mr:
case X86::OR32mi:
case X86::OR32mr:
case X86::SBB32mi:
case X86::SBB32mr:
case X86::SHLD32mrCL:
case X86::SHRD32mrCL:
case X86::SUB32mi:
case X86::SUB32mr:
case X86::TEST32mi:
case X86::TEST32mr:
case X86::XCHG32mr:
case X86::XOR32mi:
case X86::XOR32mr: printOperand(MI, 4, MVT::i32); break;
case X86::ADC32mi8:
case X86::ADD32mi8:
case X86::AND32mi8:
case X86::OR32mi8:
case X86::ROL32mi:
case X86::ROR32mi:
case X86::SAR32mi:
case X86::SBB32mi8:
case X86::SHL32mi:
case X86::SHR32mi:
case X86::SUB32mi8:
case X86::TEST8mi:
case X86::XOR32mi8: printOperand(MI, 4, MVT::i8); break;
}
After this, the generated asmwriters look pretty much as though they were
generated by hand. This shrinks the X86 asmwriter.inc files from 55101->39669
and 55429->39551 bytes each, and PPC from 16766->12859 bytes.
llvm-svn: 19760
2005-01-23 04:31:17 +08:00
|
|
|
static void PrintCases(std::vector<std::pair<std::string,
|
2016-12-01 01:48:10 +08:00
|
|
|
AsmWriterOperand>> &OpsToPrint, raw_ostream &O,
|
2016-01-14 14:15:07 +08:00
|
|
|
bool PassSubtarget) {
|
2016-01-13 15:20:13 +08:00
|
|
|
O << " case " << OpsToPrint.back().first << ":";
|
This is the final big of factoring. This shares cases in suboperand
differences, which means that identical instructions (after stripping off
the first literal string) do not run any different code at all. On the X86,
this turns this code:
switch (MI->getOpcode()) {
case X86::ADC32mi: printOperand(MI, 4, MVT::i32); break;
case X86::ADC32mi8: printOperand(MI, 4, MVT::i8); break;
case X86::ADC32mr: printOperand(MI, 4, MVT::i32); break;
case X86::ADD32mi: printOperand(MI, 4, MVT::i32); break;
case X86::ADD32mi8: printOperand(MI, 4, MVT::i8); break;
case X86::ADD32mr: printOperand(MI, 4, MVT::i32); break;
case X86::AND32mi: printOperand(MI, 4, MVT::i32); break;
case X86::AND32mi8: printOperand(MI, 4, MVT::i8); break;
case X86::AND32mr: printOperand(MI, 4, MVT::i32); break;
case X86::CMP32mi: printOperand(MI, 4, MVT::i32); break;
case X86::CMP32mr: printOperand(MI, 4, MVT::i32); break;
case X86::MOV32mi: printOperand(MI, 4, MVT::i32); break;
case X86::MOV32mr: printOperand(MI, 4, MVT::i32); break;
case X86::OR32mi: printOperand(MI, 4, MVT::i32); break;
case X86::OR32mi8: printOperand(MI, 4, MVT::i8); break;
case X86::OR32mr: printOperand(MI, 4, MVT::i32); break;
case X86::ROL32mi: printOperand(MI, 4, MVT::i8); break;
case X86::ROR32mi: printOperand(MI, 4, MVT::i8); break;
case X86::SAR32mi: printOperand(MI, 4, MVT::i8); break;
case X86::SBB32mi: printOperand(MI, 4, MVT::i32); break;
case X86::SBB32mi8: printOperand(MI, 4, MVT::i8); break;
case X86::SBB32mr: printOperand(MI, 4, MVT::i32); break;
case X86::SHL32mi: printOperand(MI, 4, MVT::i8); break;
case X86::SHLD32mrCL: printOperand(MI, 4, MVT::i32); break;
case X86::SHR32mi: printOperand(MI, 4, MVT::i8); break;
case X86::SHRD32mrCL: printOperand(MI, 4, MVT::i32); break;
case X86::SUB32mi: printOperand(MI, 4, MVT::i32); break;
case X86::SUB32mi8: printOperand(MI, 4, MVT::i8); break;
case X86::SUB32mr: printOperand(MI, 4, MVT::i32); break;
case X86::TEST32mi: printOperand(MI, 4, MVT::i32); break;
case X86::TEST32mr: printOperand(MI, 4, MVT::i32); break;
case X86::TEST8mi: printOperand(MI, 4, MVT::i8); break;
case X86::XCHG32mr: printOperand(MI, 4, MVT::i32); break;
case X86::XOR32mi: printOperand(MI, 4, MVT::i32); break;
case X86::XOR32mi8: printOperand(MI, 4, MVT::i8); break;
case X86::XOR32mr: printOperand(MI, 4, MVT::i32); break;
}
into this:
switch (MI->getOpcode()) {
case X86::ADC32mi:
case X86::ADC32mr:
case X86::ADD32mi:
case X86::ADD32mr:
case X86::AND32mi:
case X86::AND32mr:
case X86::CMP32mi:
case X86::CMP32mr:
case X86::MOV32mi:
case X86::MOV32mr:
case X86::OR32mi:
case X86::OR32mr:
case X86::SBB32mi:
case X86::SBB32mr:
case X86::SHLD32mrCL:
case X86::SHRD32mrCL:
case X86::SUB32mi:
case X86::SUB32mr:
case X86::TEST32mi:
case X86::TEST32mr:
case X86::XCHG32mr:
case X86::XOR32mi:
case X86::XOR32mr: printOperand(MI, 4, MVT::i32); break;
case X86::ADC32mi8:
case X86::ADD32mi8:
case X86::AND32mi8:
case X86::OR32mi8:
case X86::ROL32mi:
case X86::ROR32mi:
case X86::SAR32mi:
case X86::SBB32mi8:
case X86::SHL32mi:
case X86::SHR32mi:
case X86::SUB32mi8:
case X86::TEST8mi:
case X86::XOR32mi8: printOperand(MI, 4, MVT::i8); break;
}
After this, the generated asmwriters look pretty much as though they were
generated by hand. This shrinks the X86 asmwriter.inc files from 55101->39669
and 55429->39551 bytes each, and PPC from 16766->12859 bytes.
llvm-svn: 19760
2005-01-23 04:31:17 +08:00
|
|
|
AsmWriterOperand TheOp = OpsToPrint.back().second;
|
|
|
|
OpsToPrint.pop_back();
|
|
|
|
|
|
|
|
// Check to see if any other operands are identical in this list, and if so,
|
|
|
|
// emit a case label for them.
|
|
|
|
for (unsigned i = OpsToPrint.size(); i != 0; --i)
|
|
|
|
if (OpsToPrint[i-1].second == TheOp) {
|
2016-01-13 15:20:13 +08:00
|
|
|
O << "\n case " << OpsToPrint[i-1].first << ":";
|
This is the final big of factoring. This shares cases in suboperand
differences, which means that identical instructions (after stripping off
the first literal string) do not run any different code at all. On the X86,
this turns this code:
switch (MI->getOpcode()) {
case X86::ADC32mi: printOperand(MI, 4, MVT::i32); break;
case X86::ADC32mi8: printOperand(MI, 4, MVT::i8); break;
case X86::ADC32mr: printOperand(MI, 4, MVT::i32); break;
case X86::ADD32mi: printOperand(MI, 4, MVT::i32); break;
case X86::ADD32mi8: printOperand(MI, 4, MVT::i8); break;
case X86::ADD32mr: printOperand(MI, 4, MVT::i32); break;
case X86::AND32mi: printOperand(MI, 4, MVT::i32); break;
case X86::AND32mi8: printOperand(MI, 4, MVT::i8); break;
case X86::AND32mr: printOperand(MI, 4, MVT::i32); break;
case X86::CMP32mi: printOperand(MI, 4, MVT::i32); break;
case X86::CMP32mr: printOperand(MI, 4, MVT::i32); break;
case X86::MOV32mi: printOperand(MI, 4, MVT::i32); break;
case X86::MOV32mr: printOperand(MI, 4, MVT::i32); break;
case X86::OR32mi: printOperand(MI, 4, MVT::i32); break;
case X86::OR32mi8: printOperand(MI, 4, MVT::i8); break;
case X86::OR32mr: printOperand(MI, 4, MVT::i32); break;
case X86::ROL32mi: printOperand(MI, 4, MVT::i8); break;
case X86::ROR32mi: printOperand(MI, 4, MVT::i8); break;
case X86::SAR32mi: printOperand(MI, 4, MVT::i8); break;
case X86::SBB32mi: printOperand(MI, 4, MVT::i32); break;
case X86::SBB32mi8: printOperand(MI, 4, MVT::i8); break;
case X86::SBB32mr: printOperand(MI, 4, MVT::i32); break;
case X86::SHL32mi: printOperand(MI, 4, MVT::i8); break;
case X86::SHLD32mrCL: printOperand(MI, 4, MVT::i32); break;
case X86::SHR32mi: printOperand(MI, 4, MVT::i8); break;
case X86::SHRD32mrCL: printOperand(MI, 4, MVT::i32); break;
case X86::SUB32mi: printOperand(MI, 4, MVT::i32); break;
case X86::SUB32mi8: printOperand(MI, 4, MVT::i8); break;
case X86::SUB32mr: printOperand(MI, 4, MVT::i32); break;
case X86::TEST32mi: printOperand(MI, 4, MVT::i32); break;
case X86::TEST32mr: printOperand(MI, 4, MVT::i32); break;
case X86::TEST8mi: printOperand(MI, 4, MVT::i8); break;
case X86::XCHG32mr: printOperand(MI, 4, MVT::i32); break;
case X86::XOR32mi: printOperand(MI, 4, MVT::i32); break;
case X86::XOR32mi8: printOperand(MI, 4, MVT::i8); break;
case X86::XOR32mr: printOperand(MI, 4, MVT::i32); break;
}
into this:
switch (MI->getOpcode()) {
case X86::ADC32mi:
case X86::ADC32mr:
case X86::ADD32mi:
case X86::ADD32mr:
case X86::AND32mi:
case X86::AND32mr:
case X86::CMP32mi:
case X86::CMP32mr:
case X86::MOV32mi:
case X86::MOV32mr:
case X86::OR32mi:
case X86::OR32mr:
case X86::SBB32mi:
case X86::SBB32mr:
case X86::SHLD32mrCL:
case X86::SHRD32mrCL:
case X86::SUB32mi:
case X86::SUB32mr:
case X86::TEST32mi:
case X86::TEST32mr:
case X86::XCHG32mr:
case X86::XOR32mi:
case X86::XOR32mr: printOperand(MI, 4, MVT::i32); break;
case X86::ADC32mi8:
case X86::ADD32mi8:
case X86::AND32mi8:
case X86::OR32mi8:
case X86::ROL32mi:
case X86::ROR32mi:
case X86::SAR32mi:
case X86::SBB32mi8:
case X86::SHL32mi:
case X86::SHR32mi:
case X86::SUB32mi8:
case X86::TEST8mi:
case X86::XOR32mi8: printOperand(MI, 4, MVT::i8); break;
}
After this, the generated asmwriters look pretty much as though they were
generated by hand. This shrinks the X86 asmwriter.inc files from 55101->39669
and 55429->39551 bytes each, and PPC from 16766->12859 bytes.
llvm-svn: 19760
2005-01-23 04:31:17 +08:00
|
|
|
OpsToPrint.erase(OpsToPrint.begin()+i-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Finally, emit the code.
|
2016-01-14 14:15:07 +08:00
|
|
|
O << "\n " << TheOp.getCode(PassSubtarget);
|
2016-01-13 15:20:13 +08:00
|
|
|
O << "\n break;\n";
|
This is the final big of factoring. This shares cases in suboperand
differences, which means that identical instructions (after stripping off
the first literal string) do not run any different code at all. On the X86,
this turns this code:
switch (MI->getOpcode()) {
case X86::ADC32mi: printOperand(MI, 4, MVT::i32); break;
case X86::ADC32mi8: printOperand(MI, 4, MVT::i8); break;
case X86::ADC32mr: printOperand(MI, 4, MVT::i32); break;
case X86::ADD32mi: printOperand(MI, 4, MVT::i32); break;
case X86::ADD32mi8: printOperand(MI, 4, MVT::i8); break;
case X86::ADD32mr: printOperand(MI, 4, MVT::i32); break;
case X86::AND32mi: printOperand(MI, 4, MVT::i32); break;
case X86::AND32mi8: printOperand(MI, 4, MVT::i8); break;
case X86::AND32mr: printOperand(MI, 4, MVT::i32); break;
case X86::CMP32mi: printOperand(MI, 4, MVT::i32); break;
case X86::CMP32mr: printOperand(MI, 4, MVT::i32); break;
case X86::MOV32mi: printOperand(MI, 4, MVT::i32); break;
case X86::MOV32mr: printOperand(MI, 4, MVT::i32); break;
case X86::OR32mi: printOperand(MI, 4, MVT::i32); break;
case X86::OR32mi8: printOperand(MI, 4, MVT::i8); break;
case X86::OR32mr: printOperand(MI, 4, MVT::i32); break;
case X86::ROL32mi: printOperand(MI, 4, MVT::i8); break;
case X86::ROR32mi: printOperand(MI, 4, MVT::i8); break;
case X86::SAR32mi: printOperand(MI, 4, MVT::i8); break;
case X86::SBB32mi: printOperand(MI, 4, MVT::i32); break;
case X86::SBB32mi8: printOperand(MI, 4, MVT::i8); break;
case X86::SBB32mr: printOperand(MI, 4, MVT::i32); break;
case X86::SHL32mi: printOperand(MI, 4, MVT::i8); break;
case X86::SHLD32mrCL: printOperand(MI, 4, MVT::i32); break;
case X86::SHR32mi: printOperand(MI, 4, MVT::i8); break;
case X86::SHRD32mrCL: printOperand(MI, 4, MVT::i32); break;
case X86::SUB32mi: printOperand(MI, 4, MVT::i32); break;
case X86::SUB32mi8: printOperand(MI, 4, MVT::i8); break;
case X86::SUB32mr: printOperand(MI, 4, MVT::i32); break;
case X86::TEST32mi: printOperand(MI, 4, MVT::i32); break;
case X86::TEST32mr: printOperand(MI, 4, MVT::i32); break;
case X86::TEST8mi: printOperand(MI, 4, MVT::i8); break;
case X86::XCHG32mr: printOperand(MI, 4, MVT::i32); break;
case X86::XOR32mi: printOperand(MI, 4, MVT::i32); break;
case X86::XOR32mi8: printOperand(MI, 4, MVT::i8); break;
case X86::XOR32mr: printOperand(MI, 4, MVT::i32); break;
}
into this:
switch (MI->getOpcode()) {
case X86::ADC32mi:
case X86::ADC32mr:
case X86::ADD32mi:
case X86::ADD32mr:
case X86::AND32mi:
case X86::AND32mr:
case X86::CMP32mi:
case X86::CMP32mr:
case X86::MOV32mi:
case X86::MOV32mr:
case X86::OR32mi:
case X86::OR32mr:
case X86::SBB32mi:
case X86::SBB32mr:
case X86::SHLD32mrCL:
case X86::SHRD32mrCL:
case X86::SUB32mi:
case X86::SUB32mr:
case X86::TEST32mi:
case X86::TEST32mr:
case X86::XCHG32mr:
case X86::XOR32mi:
case X86::XOR32mr: printOperand(MI, 4, MVT::i32); break;
case X86::ADC32mi8:
case X86::ADD32mi8:
case X86::AND32mi8:
case X86::OR32mi8:
case X86::ROL32mi:
case X86::ROR32mi:
case X86::SAR32mi:
case X86::SBB32mi8:
case X86::SHL32mi:
case X86::SHR32mi:
case X86::SUB32mi8:
case X86::TEST8mi:
case X86::XOR32mi8: printOperand(MI, 4, MVT::i8); break;
}
After this, the generated asmwriters look pretty much as though they were
generated by hand. This shrinks the X86 asmwriter.inc files from 55101->39669
and 55429->39551 bytes each, and PPC from 16766->12859 bytes.
llvm-svn: 19760
2005-01-23 04:31:17 +08:00
|
|
|
}
|
|
|
|
|
Implement factoring of instruction pattern strings. In particular, instead of
emitting code like this:
case PPC::ADD: O << "add "; printOperand(MI, 0, MVT::i64); O << ", "; prin
tOperand(MI, 1, MVT::i64); O << ", "; printOperand(MI, 2, MVT::i64); O << '\n
'; break;
case PPC::ADDC: O << "addc "; printOperand(MI, 0, MVT::i64); O << ", "; pr
intOperand(MI, 1, MVT::i64); O << ", "; printOperand(MI, 2, MVT::i64); O << '
\n'; break;
case PPC::ADDE: O << "adde "; printOperand(MI, 0, MVT::i64); O << ", "; pr
intOperand(MI, 1, MVT::i64); O << ", "; printOperand(MI, 2, MVT::i64); O << '
\n'; break;
...
Emit code like this:
case PPC::ADD:
case PPC::ADDC:
case PPC::ADDE:
...
switch (MI->getOpcode()) {
case PPC::ADD: O << "add "; break;
case PPC::ADDC: O << "addc "; break;
case PPC::ADDE: O << "adde "; break;
...
}
printOperand(MI, 0, MVT::i64);
O << ", ";
printOperand(MI, 1, MVT::i64);
O << ", ";
printOperand(MI, 2, MVT::i64);
O << "\n";
break;
This shrinks the PPC asm writer from 24785->15205 bytes (even though the new
asmwriter has much more whitespace than the old one), and the X86 printers shrink
quite a bit too. The important implication of this is that GCC no longer hits swap
when building the PPC backend in optimized mode. Thus this fixes PR448.
-Chris
llvm-svn: 19755
2005-01-23 02:38:13 +08:00
|
|
|
/// EmitInstructions - Emit the last instruction in the vector and any other
|
|
|
|
/// instructions that are suitably similar to it.
|
|
|
|
static void EmitInstructions(std::vector<AsmWriterInst> &Insts,
|
2016-01-14 14:15:07 +08:00
|
|
|
raw_ostream &O, bool PassSubtarget) {
|
Implement factoring of instruction pattern strings. In particular, instead of
emitting code like this:
case PPC::ADD: O << "add "; printOperand(MI, 0, MVT::i64); O << ", "; prin
tOperand(MI, 1, MVT::i64); O << ", "; printOperand(MI, 2, MVT::i64); O << '\n
'; break;
case PPC::ADDC: O << "addc "; printOperand(MI, 0, MVT::i64); O << ", "; pr
intOperand(MI, 1, MVT::i64); O << ", "; printOperand(MI, 2, MVT::i64); O << '
\n'; break;
case PPC::ADDE: O << "adde "; printOperand(MI, 0, MVT::i64); O << ", "; pr
intOperand(MI, 1, MVT::i64); O << ", "; printOperand(MI, 2, MVT::i64); O << '
\n'; break;
...
Emit code like this:
case PPC::ADD:
case PPC::ADDC:
case PPC::ADDE:
...
switch (MI->getOpcode()) {
case PPC::ADD: O << "add "; break;
case PPC::ADDC: O << "addc "; break;
case PPC::ADDE: O << "adde "; break;
...
}
printOperand(MI, 0, MVT::i64);
O << ", ";
printOperand(MI, 1, MVT::i64);
O << ", ";
printOperand(MI, 2, MVT::i64);
O << "\n";
break;
This shrinks the PPC asm writer from 24785->15205 bytes (even though the new
asmwriter has much more whitespace than the old one), and the X86 printers shrink
quite a bit too. The important implication of this is that GCC no longer hits swap
when building the PPC backend in optimized mode. Thus this fixes PR448.
-Chris
llvm-svn: 19755
2005-01-23 02:38:13 +08:00
|
|
|
AsmWriterInst FirstInst = Insts.back();
|
|
|
|
Insts.pop_back();
|
|
|
|
|
|
|
|
std::vector<AsmWriterInst> SimilarInsts;
|
|
|
|
unsigned DifferingOperand = ~0;
|
|
|
|
for (unsigned i = Insts.size(); i != 0; --i) {
|
2005-01-23 03:22:23 +08:00
|
|
|
unsigned DiffOp = Insts[i-1].MatchesAllButOneOp(FirstInst);
|
|
|
|
if (DiffOp != ~1U) {
|
Implement factoring of instruction pattern strings. In particular, instead of
emitting code like this:
case PPC::ADD: O << "add "; printOperand(MI, 0, MVT::i64); O << ", "; prin
tOperand(MI, 1, MVT::i64); O << ", "; printOperand(MI, 2, MVT::i64); O << '\n
'; break;
case PPC::ADDC: O << "addc "; printOperand(MI, 0, MVT::i64); O << ", "; pr
intOperand(MI, 1, MVT::i64); O << ", "; printOperand(MI, 2, MVT::i64); O << '
\n'; break;
case PPC::ADDE: O << "adde "; printOperand(MI, 0, MVT::i64); O << ", "; pr
intOperand(MI, 1, MVT::i64); O << ", "; printOperand(MI, 2, MVT::i64); O << '
\n'; break;
...
Emit code like this:
case PPC::ADD:
case PPC::ADDC:
case PPC::ADDE:
...
switch (MI->getOpcode()) {
case PPC::ADD: O << "add "; break;
case PPC::ADDC: O << "addc "; break;
case PPC::ADDE: O << "adde "; break;
...
}
printOperand(MI, 0, MVT::i64);
O << ", ";
printOperand(MI, 1, MVT::i64);
O << ", ";
printOperand(MI, 2, MVT::i64);
O << "\n";
break;
This shrinks the PPC asm writer from 24785->15205 bytes (even though the new
asmwriter has much more whitespace than the old one), and the X86 printers shrink
quite a bit too. The important implication of this is that GCC no longer hits swap
when building the PPC backend in optimized mode. Thus this fixes PR448.
-Chris
llvm-svn: 19755
2005-01-23 02:38:13 +08:00
|
|
|
if (DifferingOperand == ~0U) // First match!
|
|
|
|
DifferingOperand = DiffOp;
|
|
|
|
|
|
|
|
// If this differs in the same operand as the rest of the instructions in
|
|
|
|
// this class, move it to the SimilarInsts list.
|
2005-01-23 03:22:23 +08:00
|
|
|
if (DifferingOperand == DiffOp || DiffOp == ~0U) {
|
Implement factoring of instruction pattern strings. In particular, instead of
emitting code like this:
case PPC::ADD: O << "add "; printOperand(MI, 0, MVT::i64); O << ", "; prin
tOperand(MI, 1, MVT::i64); O << ", "; printOperand(MI, 2, MVT::i64); O << '\n
'; break;
case PPC::ADDC: O << "addc "; printOperand(MI, 0, MVT::i64); O << ", "; pr
intOperand(MI, 1, MVT::i64); O << ", "; printOperand(MI, 2, MVT::i64); O << '
\n'; break;
case PPC::ADDE: O << "adde "; printOperand(MI, 0, MVT::i64); O << ", "; pr
intOperand(MI, 1, MVT::i64); O << ", "; printOperand(MI, 2, MVT::i64); O << '
\n'; break;
...
Emit code like this:
case PPC::ADD:
case PPC::ADDC:
case PPC::ADDE:
...
switch (MI->getOpcode()) {
case PPC::ADD: O << "add "; break;
case PPC::ADDC: O << "addc "; break;
case PPC::ADDE: O << "adde "; break;
...
}
printOperand(MI, 0, MVT::i64);
O << ", ";
printOperand(MI, 1, MVT::i64);
O << ", ";
printOperand(MI, 2, MVT::i64);
O << "\n";
break;
This shrinks the PPC asm writer from 24785->15205 bytes (even though the new
asmwriter has much more whitespace than the old one), and the X86 printers shrink
quite a bit too. The important implication of this is that GCC no longer hits swap
when building the PPC backend in optimized mode. Thus this fixes PR448.
-Chris
llvm-svn: 19755
2005-01-23 02:38:13 +08:00
|
|
|
SimilarInsts.push_back(Insts[i-1]);
|
|
|
|
Insts.erase(Insts.begin()+i-1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-05-02 01:01:17 +08:00
|
|
|
O << " case " << FirstInst.CGI->Namespace << "::"
|
Implement factoring of instruction pattern strings. In particular, instead of
emitting code like this:
case PPC::ADD: O << "add "; printOperand(MI, 0, MVT::i64); O << ", "; prin
tOperand(MI, 1, MVT::i64); O << ", "; printOperand(MI, 2, MVT::i64); O << '\n
'; break;
case PPC::ADDC: O << "addc "; printOperand(MI, 0, MVT::i64); O << ", "; pr
intOperand(MI, 1, MVT::i64); O << ", "; printOperand(MI, 2, MVT::i64); O << '
\n'; break;
case PPC::ADDE: O << "adde "; printOperand(MI, 0, MVT::i64); O << ", "; pr
intOperand(MI, 1, MVT::i64); O << ", "; printOperand(MI, 2, MVT::i64); O << '
\n'; break;
...
Emit code like this:
case PPC::ADD:
case PPC::ADDC:
case PPC::ADDE:
...
switch (MI->getOpcode()) {
case PPC::ADD: O << "add "; break;
case PPC::ADDC: O << "addc "; break;
case PPC::ADDE: O << "adde "; break;
...
}
printOperand(MI, 0, MVT::i64);
O << ", ";
printOperand(MI, 1, MVT::i64);
O << ", ";
printOperand(MI, 2, MVT::i64);
O << "\n";
break;
This shrinks the PPC asm writer from 24785->15205 bytes (even though the new
asmwriter has much more whitespace than the old one), and the X86 printers shrink
quite a bit too. The important implication of this is that GCC no longer hits swap
when building the PPC backend in optimized mode. Thus this fixes PR448.
-Chris
llvm-svn: 19755
2005-01-23 02:38:13 +08:00
|
|
|
<< FirstInst.CGI->TheDef->getName() << ":\n";
|
2016-01-08 15:06:32 +08:00
|
|
|
for (const AsmWriterInst &AWI : SimilarInsts)
|
|
|
|
O << " case " << AWI.CGI->Namespace << "::"
|
|
|
|
<< AWI.CGI->TheDef->getName() << ":\n";
|
Implement factoring of instruction pattern strings. In particular, instead of
emitting code like this:
case PPC::ADD: O << "add "; printOperand(MI, 0, MVT::i64); O << ", "; prin
tOperand(MI, 1, MVT::i64); O << ", "; printOperand(MI, 2, MVT::i64); O << '\n
'; break;
case PPC::ADDC: O << "addc "; printOperand(MI, 0, MVT::i64); O << ", "; pr
intOperand(MI, 1, MVT::i64); O << ", "; printOperand(MI, 2, MVT::i64); O << '
\n'; break;
case PPC::ADDE: O << "adde "; printOperand(MI, 0, MVT::i64); O << ", "; pr
intOperand(MI, 1, MVT::i64); O << ", "; printOperand(MI, 2, MVT::i64); O << '
\n'; break;
...
Emit code like this:
case PPC::ADD:
case PPC::ADDC:
case PPC::ADDE:
...
switch (MI->getOpcode()) {
case PPC::ADD: O << "add "; break;
case PPC::ADDC: O << "addc "; break;
case PPC::ADDE: O << "adde "; break;
...
}
printOperand(MI, 0, MVT::i64);
O << ", ";
printOperand(MI, 1, MVT::i64);
O << ", ";
printOperand(MI, 2, MVT::i64);
O << "\n";
break;
This shrinks the PPC asm writer from 24785->15205 bytes (even though the new
asmwriter has much more whitespace than the old one), and the X86 printers shrink
quite a bit too. The important implication of this is that GCC no longer hits swap
when building the PPC backend in optimized mode. Thus this fixes PR448.
-Chris
llvm-svn: 19755
2005-01-23 02:38:13 +08:00
|
|
|
for (unsigned i = 0, e = FirstInst.Operands.size(); i != e; ++i) {
|
|
|
|
if (i != DifferingOperand) {
|
|
|
|
// If the operand is the same for all instructions, just print it.
|
2016-01-14 14:15:07 +08:00
|
|
|
O << " " << FirstInst.Operands[i].getCode(PassSubtarget);
|
Implement factoring of instruction pattern strings. In particular, instead of
emitting code like this:
case PPC::ADD: O << "add "; printOperand(MI, 0, MVT::i64); O << ", "; prin
tOperand(MI, 1, MVT::i64); O << ", "; printOperand(MI, 2, MVT::i64); O << '\n
'; break;
case PPC::ADDC: O << "addc "; printOperand(MI, 0, MVT::i64); O << ", "; pr
intOperand(MI, 1, MVT::i64); O << ", "; printOperand(MI, 2, MVT::i64); O << '
\n'; break;
case PPC::ADDE: O << "adde "; printOperand(MI, 0, MVT::i64); O << ", "; pr
intOperand(MI, 1, MVT::i64); O << ", "; printOperand(MI, 2, MVT::i64); O << '
\n'; break;
...
Emit code like this:
case PPC::ADD:
case PPC::ADDC:
case PPC::ADDE:
...
switch (MI->getOpcode()) {
case PPC::ADD: O << "add "; break;
case PPC::ADDC: O << "addc "; break;
case PPC::ADDE: O << "adde "; break;
...
}
printOperand(MI, 0, MVT::i64);
O << ", ";
printOperand(MI, 1, MVT::i64);
O << ", ";
printOperand(MI, 2, MVT::i64);
O << "\n";
break;
This shrinks the PPC asm writer from 24785->15205 bytes (even though the new
asmwriter has much more whitespace than the old one), and the X86 printers shrink
quite a bit too. The important implication of this is that GCC no longer hits swap
when building the PPC backend in optimized mode. Thus this fixes PR448.
-Chris
llvm-svn: 19755
2005-01-23 02:38:13 +08:00
|
|
|
} else {
|
|
|
|
// If this is the operand that varies between all of the instructions,
|
|
|
|
// emit a switch for just this operand now.
|
|
|
|
O << " switch (MI->getOpcode()) {\n";
|
2016-01-13 15:20:13 +08:00
|
|
|
O << " default: llvm_unreachable(\"Unexpected opcode.\");\n";
|
2016-12-01 01:48:10 +08:00
|
|
|
std::vector<std::pair<std::string, AsmWriterOperand>> OpsToPrint;
|
2017-07-07 14:22:35 +08:00
|
|
|
OpsToPrint.push_back(std::make_pair(FirstInst.CGI->Namespace.str() + "::" +
|
2016-12-04 13:48:16 +08:00
|
|
|
FirstInst.CGI->TheDef->getName().str(),
|
This is the final big of factoring. This shares cases in suboperand
differences, which means that identical instructions (after stripping off
the first literal string) do not run any different code at all. On the X86,
this turns this code:
switch (MI->getOpcode()) {
case X86::ADC32mi: printOperand(MI, 4, MVT::i32); break;
case X86::ADC32mi8: printOperand(MI, 4, MVT::i8); break;
case X86::ADC32mr: printOperand(MI, 4, MVT::i32); break;
case X86::ADD32mi: printOperand(MI, 4, MVT::i32); break;
case X86::ADD32mi8: printOperand(MI, 4, MVT::i8); break;
case X86::ADD32mr: printOperand(MI, 4, MVT::i32); break;
case X86::AND32mi: printOperand(MI, 4, MVT::i32); break;
case X86::AND32mi8: printOperand(MI, 4, MVT::i8); break;
case X86::AND32mr: printOperand(MI, 4, MVT::i32); break;
case X86::CMP32mi: printOperand(MI, 4, MVT::i32); break;
case X86::CMP32mr: printOperand(MI, 4, MVT::i32); break;
case X86::MOV32mi: printOperand(MI, 4, MVT::i32); break;
case X86::MOV32mr: printOperand(MI, 4, MVT::i32); break;
case X86::OR32mi: printOperand(MI, 4, MVT::i32); break;
case X86::OR32mi8: printOperand(MI, 4, MVT::i8); break;
case X86::OR32mr: printOperand(MI, 4, MVT::i32); break;
case X86::ROL32mi: printOperand(MI, 4, MVT::i8); break;
case X86::ROR32mi: printOperand(MI, 4, MVT::i8); break;
case X86::SAR32mi: printOperand(MI, 4, MVT::i8); break;
case X86::SBB32mi: printOperand(MI, 4, MVT::i32); break;
case X86::SBB32mi8: printOperand(MI, 4, MVT::i8); break;
case X86::SBB32mr: printOperand(MI, 4, MVT::i32); break;
case X86::SHL32mi: printOperand(MI, 4, MVT::i8); break;
case X86::SHLD32mrCL: printOperand(MI, 4, MVT::i32); break;
case X86::SHR32mi: printOperand(MI, 4, MVT::i8); break;
case X86::SHRD32mrCL: printOperand(MI, 4, MVT::i32); break;
case X86::SUB32mi: printOperand(MI, 4, MVT::i32); break;
case X86::SUB32mi8: printOperand(MI, 4, MVT::i8); break;
case X86::SUB32mr: printOperand(MI, 4, MVT::i32); break;
case X86::TEST32mi: printOperand(MI, 4, MVT::i32); break;
case X86::TEST32mr: printOperand(MI, 4, MVT::i32); break;
case X86::TEST8mi: printOperand(MI, 4, MVT::i8); break;
case X86::XCHG32mr: printOperand(MI, 4, MVT::i32); break;
case X86::XOR32mi: printOperand(MI, 4, MVT::i32); break;
case X86::XOR32mi8: printOperand(MI, 4, MVT::i8); break;
case X86::XOR32mr: printOperand(MI, 4, MVT::i32); break;
}
into this:
switch (MI->getOpcode()) {
case X86::ADC32mi:
case X86::ADC32mr:
case X86::ADD32mi:
case X86::ADD32mr:
case X86::AND32mi:
case X86::AND32mr:
case X86::CMP32mi:
case X86::CMP32mr:
case X86::MOV32mi:
case X86::MOV32mr:
case X86::OR32mi:
case X86::OR32mr:
case X86::SBB32mi:
case X86::SBB32mr:
case X86::SHLD32mrCL:
case X86::SHRD32mrCL:
case X86::SUB32mi:
case X86::SUB32mr:
case X86::TEST32mi:
case X86::TEST32mr:
case X86::XCHG32mr:
case X86::XOR32mi:
case X86::XOR32mr: printOperand(MI, 4, MVT::i32); break;
case X86::ADC32mi8:
case X86::ADD32mi8:
case X86::AND32mi8:
case X86::OR32mi8:
case X86::ROL32mi:
case X86::ROR32mi:
case X86::SAR32mi:
case X86::SBB32mi8:
case X86::SHL32mi:
case X86::SHR32mi:
case X86::SUB32mi8:
case X86::TEST8mi:
case X86::XOR32mi8: printOperand(MI, 4, MVT::i8); break;
}
After this, the generated asmwriters look pretty much as though they were
generated by hand. This shrinks the X86 asmwriter.inc files from 55101->39669
and 55429->39551 bytes each, and PPC from 16766->12859 bytes.
llvm-svn: 19760
2005-01-23 04:31:17 +08:00
|
|
|
FirstInst.Operands[i]));
|
2005-04-22 08:00:37 +08:00
|
|
|
|
2016-01-08 15:06:32 +08:00
|
|
|
for (const AsmWriterInst &AWI : SimilarInsts) {
|
2017-07-07 14:22:35 +08:00
|
|
|
OpsToPrint.push_back(std::make_pair(AWI.CGI->Namespace.str()+"::" +
|
2016-12-04 13:48:16 +08:00
|
|
|
AWI.CGI->TheDef->getName().str(),
|
This is the final big of factoring. This shares cases in suboperand
differences, which means that identical instructions (after stripping off
the first literal string) do not run any different code at all. On the X86,
this turns this code:
switch (MI->getOpcode()) {
case X86::ADC32mi: printOperand(MI, 4, MVT::i32); break;
case X86::ADC32mi8: printOperand(MI, 4, MVT::i8); break;
case X86::ADC32mr: printOperand(MI, 4, MVT::i32); break;
case X86::ADD32mi: printOperand(MI, 4, MVT::i32); break;
case X86::ADD32mi8: printOperand(MI, 4, MVT::i8); break;
case X86::ADD32mr: printOperand(MI, 4, MVT::i32); break;
case X86::AND32mi: printOperand(MI, 4, MVT::i32); break;
case X86::AND32mi8: printOperand(MI, 4, MVT::i8); break;
case X86::AND32mr: printOperand(MI, 4, MVT::i32); break;
case X86::CMP32mi: printOperand(MI, 4, MVT::i32); break;
case X86::CMP32mr: printOperand(MI, 4, MVT::i32); break;
case X86::MOV32mi: printOperand(MI, 4, MVT::i32); break;
case X86::MOV32mr: printOperand(MI, 4, MVT::i32); break;
case X86::OR32mi: printOperand(MI, 4, MVT::i32); break;
case X86::OR32mi8: printOperand(MI, 4, MVT::i8); break;
case X86::OR32mr: printOperand(MI, 4, MVT::i32); break;
case X86::ROL32mi: printOperand(MI, 4, MVT::i8); break;
case X86::ROR32mi: printOperand(MI, 4, MVT::i8); break;
case X86::SAR32mi: printOperand(MI, 4, MVT::i8); break;
case X86::SBB32mi: printOperand(MI, 4, MVT::i32); break;
case X86::SBB32mi8: printOperand(MI, 4, MVT::i8); break;
case X86::SBB32mr: printOperand(MI, 4, MVT::i32); break;
case X86::SHL32mi: printOperand(MI, 4, MVT::i8); break;
case X86::SHLD32mrCL: printOperand(MI, 4, MVT::i32); break;
case X86::SHR32mi: printOperand(MI, 4, MVT::i8); break;
case X86::SHRD32mrCL: printOperand(MI, 4, MVT::i32); break;
case X86::SUB32mi: printOperand(MI, 4, MVT::i32); break;
case X86::SUB32mi8: printOperand(MI, 4, MVT::i8); break;
case X86::SUB32mr: printOperand(MI, 4, MVT::i32); break;
case X86::TEST32mi: printOperand(MI, 4, MVT::i32); break;
case X86::TEST32mr: printOperand(MI, 4, MVT::i32); break;
case X86::TEST8mi: printOperand(MI, 4, MVT::i8); break;
case X86::XCHG32mr: printOperand(MI, 4, MVT::i32); break;
case X86::XOR32mi: printOperand(MI, 4, MVT::i32); break;
case X86::XOR32mi8: printOperand(MI, 4, MVT::i8); break;
case X86::XOR32mr: printOperand(MI, 4, MVT::i32); break;
}
into this:
switch (MI->getOpcode()) {
case X86::ADC32mi:
case X86::ADC32mr:
case X86::ADD32mi:
case X86::ADD32mr:
case X86::AND32mi:
case X86::AND32mr:
case X86::CMP32mi:
case X86::CMP32mr:
case X86::MOV32mi:
case X86::MOV32mr:
case X86::OR32mi:
case X86::OR32mr:
case X86::SBB32mi:
case X86::SBB32mr:
case X86::SHLD32mrCL:
case X86::SHRD32mrCL:
case X86::SUB32mi:
case X86::SUB32mr:
case X86::TEST32mi:
case X86::TEST32mr:
case X86::XCHG32mr:
case X86::XOR32mi:
case X86::XOR32mr: printOperand(MI, 4, MVT::i32); break;
case X86::ADC32mi8:
case X86::ADD32mi8:
case X86::AND32mi8:
case X86::OR32mi8:
case X86::ROL32mi:
case X86::ROR32mi:
case X86::SAR32mi:
case X86::SBB32mi8:
case X86::SHL32mi:
case X86::SHR32mi:
case X86::SUB32mi8:
case X86::TEST8mi:
case X86::XOR32mi8: printOperand(MI, 4, MVT::i8); break;
}
After this, the generated asmwriters look pretty much as though they were
generated by hand. This shrinks the X86 asmwriter.inc files from 55101->39669
and 55429->39551 bytes each, and PPC from 16766->12859 bytes.
llvm-svn: 19760
2005-01-23 04:31:17 +08:00
|
|
|
AWI.Operands[i]));
|
Implement factoring of instruction pattern strings. In particular, instead of
emitting code like this:
case PPC::ADD: O << "add "; printOperand(MI, 0, MVT::i64); O << ", "; prin
tOperand(MI, 1, MVT::i64); O << ", "; printOperand(MI, 2, MVT::i64); O << '\n
'; break;
case PPC::ADDC: O << "addc "; printOperand(MI, 0, MVT::i64); O << ", "; pr
intOperand(MI, 1, MVT::i64); O << ", "; printOperand(MI, 2, MVT::i64); O << '
\n'; break;
case PPC::ADDE: O << "adde "; printOperand(MI, 0, MVT::i64); O << ", "; pr
intOperand(MI, 1, MVT::i64); O << ", "; printOperand(MI, 2, MVT::i64); O << '
\n'; break;
...
Emit code like this:
case PPC::ADD:
case PPC::ADDC:
case PPC::ADDE:
...
switch (MI->getOpcode()) {
case PPC::ADD: O << "add "; break;
case PPC::ADDC: O << "addc "; break;
case PPC::ADDE: O << "adde "; break;
...
}
printOperand(MI, 0, MVT::i64);
O << ", ";
printOperand(MI, 1, MVT::i64);
O << ", ";
printOperand(MI, 2, MVT::i64);
O << "\n";
break;
This shrinks the PPC asm writer from 24785->15205 bytes (even though the new
asmwriter has much more whitespace than the old one), and the X86 printers shrink
quite a bit too. The important implication of this is that GCC no longer hits swap
when building the PPC backend in optimized mode. Thus this fixes PR448.
-Chris
llvm-svn: 19755
2005-01-23 02:38:13 +08:00
|
|
|
}
|
This is the final big of factoring. This shares cases in suboperand
differences, which means that identical instructions (after stripping off
the first literal string) do not run any different code at all. On the X86,
this turns this code:
switch (MI->getOpcode()) {
case X86::ADC32mi: printOperand(MI, 4, MVT::i32); break;
case X86::ADC32mi8: printOperand(MI, 4, MVT::i8); break;
case X86::ADC32mr: printOperand(MI, 4, MVT::i32); break;
case X86::ADD32mi: printOperand(MI, 4, MVT::i32); break;
case X86::ADD32mi8: printOperand(MI, 4, MVT::i8); break;
case X86::ADD32mr: printOperand(MI, 4, MVT::i32); break;
case X86::AND32mi: printOperand(MI, 4, MVT::i32); break;
case X86::AND32mi8: printOperand(MI, 4, MVT::i8); break;
case X86::AND32mr: printOperand(MI, 4, MVT::i32); break;
case X86::CMP32mi: printOperand(MI, 4, MVT::i32); break;
case X86::CMP32mr: printOperand(MI, 4, MVT::i32); break;
case X86::MOV32mi: printOperand(MI, 4, MVT::i32); break;
case X86::MOV32mr: printOperand(MI, 4, MVT::i32); break;
case X86::OR32mi: printOperand(MI, 4, MVT::i32); break;
case X86::OR32mi8: printOperand(MI, 4, MVT::i8); break;
case X86::OR32mr: printOperand(MI, 4, MVT::i32); break;
case X86::ROL32mi: printOperand(MI, 4, MVT::i8); break;
case X86::ROR32mi: printOperand(MI, 4, MVT::i8); break;
case X86::SAR32mi: printOperand(MI, 4, MVT::i8); break;
case X86::SBB32mi: printOperand(MI, 4, MVT::i32); break;
case X86::SBB32mi8: printOperand(MI, 4, MVT::i8); break;
case X86::SBB32mr: printOperand(MI, 4, MVT::i32); break;
case X86::SHL32mi: printOperand(MI, 4, MVT::i8); break;
case X86::SHLD32mrCL: printOperand(MI, 4, MVT::i32); break;
case X86::SHR32mi: printOperand(MI, 4, MVT::i8); break;
case X86::SHRD32mrCL: printOperand(MI, 4, MVT::i32); break;
case X86::SUB32mi: printOperand(MI, 4, MVT::i32); break;
case X86::SUB32mi8: printOperand(MI, 4, MVT::i8); break;
case X86::SUB32mr: printOperand(MI, 4, MVT::i32); break;
case X86::TEST32mi: printOperand(MI, 4, MVT::i32); break;
case X86::TEST32mr: printOperand(MI, 4, MVT::i32); break;
case X86::TEST8mi: printOperand(MI, 4, MVT::i8); break;
case X86::XCHG32mr: printOperand(MI, 4, MVT::i32); break;
case X86::XOR32mi: printOperand(MI, 4, MVT::i32); break;
case X86::XOR32mi8: printOperand(MI, 4, MVT::i8); break;
case X86::XOR32mr: printOperand(MI, 4, MVT::i32); break;
}
into this:
switch (MI->getOpcode()) {
case X86::ADC32mi:
case X86::ADC32mr:
case X86::ADD32mi:
case X86::ADD32mr:
case X86::AND32mi:
case X86::AND32mr:
case X86::CMP32mi:
case X86::CMP32mr:
case X86::MOV32mi:
case X86::MOV32mr:
case X86::OR32mi:
case X86::OR32mr:
case X86::SBB32mi:
case X86::SBB32mr:
case X86::SHLD32mrCL:
case X86::SHRD32mrCL:
case X86::SUB32mi:
case X86::SUB32mr:
case X86::TEST32mi:
case X86::TEST32mr:
case X86::XCHG32mr:
case X86::XOR32mi:
case X86::XOR32mr: printOperand(MI, 4, MVT::i32); break;
case X86::ADC32mi8:
case X86::ADD32mi8:
case X86::AND32mi8:
case X86::OR32mi8:
case X86::ROL32mi:
case X86::ROR32mi:
case X86::SAR32mi:
case X86::SBB32mi8:
case X86::SHL32mi:
case X86::SHR32mi:
case X86::SUB32mi8:
case X86::TEST8mi:
case X86::XOR32mi8: printOperand(MI, 4, MVT::i8); break;
}
After this, the generated asmwriters look pretty much as though they were
generated by hand. This shrinks the X86 asmwriter.inc files from 55101->39669
and 55429->39551 bytes each, and PPC from 16766->12859 bytes.
llvm-svn: 19760
2005-01-23 04:31:17 +08:00
|
|
|
std::reverse(OpsToPrint.begin(), OpsToPrint.end());
|
|
|
|
while (!OpsToPrint.empty())
|
2016-01-14 14:15:07 +08:00
|
|
|
PrintCases(OpsToPrint, O, PassSubtarget);
|
Implement factoring of instruction pattern strings. In particular, instead of
emitting code like this:
case PPC::ADD: O << "add "; printOperand(MI, 0, MVT::i64); O << ", "; prin
tOperand(MI, 1, MVT::i64); O << ", "; printOperand(MI, 2, MVT::i64); O << '\n
'; break;
case PPC::ADDC: O << "addc "; printOperand(MI, 0, MVT::i64); O << ", "; pr
intOperand(MI, 1, MVT::i64); O << ", "; printOperand(MI, 2, MVT::i64); O << '
\n'; break;
case PPC::ADDE: O << "adde "; printOperand(MI, 0, MVT::i64); O << ", "; pr
intOperand(MI, 1, MVT::i64); O << ", "; printOperand(MI, 2, MVT::i64); O << '
\n'; break;
...
Emit code like this:
case PPC::ADD:
case PPC::ADDC:
case PPC::ADDE:
...
switch (MI->getOpcode()) {
case PPC::ADD: O << "add "; break;
case PPC::ADDC: O << "addc "; break;
case PPC::ADDE: O << "adde "; break;
...
}
printOperand(MI, 0, MVT::i64);
O << ", ";
printOperand(MI, 1, MVT::i64);
O << ", ";
printOperand(MI, 2, MVT::i64);
O << "\n";
break;
This shrinks the PPC asm writer from 24785->15205 bytes (even though the new
asmwriter has much more whitespace than the old one), and the X86 printers shrink
quite a bit too. The important implication of this is that GCC no longer hits swap
when building the PPC backend in optimized mode. Thus this fixes PR448.
-Chris
llvm-svn: 19755
2005-01-23 02:38:13 +08:00
|
|
|
O << " }";
|
|
|
|
}
|
|
|
|
O << "\n";
|
|
|
|
}
|
|
|
|
O << " break;\n";
|
|
|
|
}
|
2005-01-23 01:32:42 +08:00
|
|
|
|
2006-07-19 01:18:03 +08:00
|
|
|
void AsmWriterEmitter::
|
2010-09-30 06:32:50 +08:00
|
|
|
FindUniqueOperandCommands(std::vector<std::string> &UniqueOperandCommands,
|
2016-01-24 15:13:28 +08:00
|
|
|
std::vector<std::vector<unsigned>> &InstIdxs,
|
2016-01-14 14:15:07 +08:00
|
|
|
std::vector<unsigned> &InstOpsUsed,
|
|
|
|
bool PassSubtarget) const {
|
2006-07-19 01:18:03 +08:00
|
|
|
// This vector parallels UniqueOperandCommands, keeping track of which
|
|
|
|
// instructions each case are used for. It is a comma separated string of
|
|
|
|
// enums.
|
|
|
|
std::vector<std::string> InstrsForCase;
|
|
|
|
InstrsForCase.resize(UniqueOperandCommands.size());
|
2006-07-19 02:28:27 +08:00
|
|
|
InstOpsUsed.assign(UniqueOperandCommands.size(), 0);
|
2010-09-30 06:32:50 +08:00
|
|
|
|
2016-01-17 16:05:33 +08:00
|
|
|
for (size_t i = 0, e = Instructions.size(); i != e; ++i) {
|
|
|
|
const AsmWriterInst &Inst = Instructions[i];
|
|
|
|
if (Inst.Operands.empty())
|
2006-07-19 01:18:03 +08:00
|
|
|
continue; // Instruction already done.
|
2006-07-19 01:50:22 +08:00
|
|
|
|
2016-01-17 16:05:33 +08:00
|
|
|
std::string Command = " "+Inst.Operands[0].getCode(PassSubtarget)+"\n";
|
2006-07-19 01:50:22 +08:00
|
|
|
|
2006-07-19 01:18:03 +08:00
|
|
|
// Check to see if we already have 'Command' in UniqueOperandCommands.
|
|
|
|
// If not, add it.
|
2016-12-01 01:48:10 +08:00
|
|
|
auto I = llvm::find(UniqueOperandCommands, Command);
|
2016-01-17 16:05:30 +08:00
|
|
|
if (I != UniqueOperandCommands.end()) {
|
|
|
|
size_t idx = I - UniqueOperandCommands.begin();
|
|
|
|
InstrsForCase[idx] += ", ";
|
2016-01-17 16:05:33 +08:00
|
|
|
InstrsForCase[idx] += Inst.CGI->TheDef->getName();
|
2016-01-24 15:13:28 +08:00
|
|
|
InstIdxs[idx].push_back(i);
|
2016-01-17 16:05:30 +08:00
|
|
|
} else {
|
2016-01-08 15:06:29 +08:00
|
|
|
UniqueOperandCommands.push_back(std::move(Command));
|
2020-01-29 03:23:46 +08:00
|
|
|
InstrsForCase.push_back(std::string(Inst.CGI->TheDef->getName()));
|
2016-01-24 15:13:28 +08:00
|
|
|
InstIdxs.emplace_back();
|
|
|
|
InstIdxs.back().push_back(i);
|
2006-07-19 02:28:27 +08:00
|
|
|
|
|
|
|
// This command matches one operand so far.
|
|
|
|
InstOpsUsed.push_back(1);
|
|
|
|
}
|
|
|
|
}
|
2010-09-30 06:32:50 +08:00
|
|
|
|
2006-07-19 02:28:27 +08:00
|
|
|
// For each entry of UniqueOperandCommands, there is a set of instructions
|
|
|
|
// that uses it. If the next command of all instructions in the set are
|
|
|
|
// identical, fold it into the command.
|
2016-01-24 15:13:28 +08:00
|
|
|
for (size_t CommandIdx = 0, e = UniqueOperandCommands.size();
|
2006-07-19 02:28:27 +08:00
|
|
|
CommandIdx != e; ++CommandIdx) {
|
2010-09-30 06:32:50 +08:00
|
|
|
|
2016-01-24 15:13:28 +08:00
|
|
|
const auto &Idxs = InstIdxs[CommandIdx];
|
2006-07-19 02:28:27 +08:00
|
|
|
|
2016-01-24 15:13:28 +08:00
|
|
|
for (unsigned Op = 1; ; ++Op) {
|
|
|
|
// Find the first instruction in the set.
|
|
|
|
const AsmWriterInst &FirstInst = Instructions[Idxs.front()];
|
2006-07-19 02:28:27 +08:00
|
|
|
// If this instruction has no more operands, we isn't anything to merge
|
|
|
|
// into this command.
|
2016-01-17 16:05:33 +08:00
|
|
|
if (FirstInst.Operands.size() == Op)
|
2006-07-19 02:28:27 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
// Otherwise, scan to see if all of the other instructions in this command
|
|
|
|
// set share the operand.
|
2021-01-20 12:19:15 +08:00
|
|
|
if (any_of(drop_begin(Idxs), [&](unsigned Idx) {
|
|
|
|
const AsmWriterInst &OtherInst = Instructions[Idx];
|
|
|
|
return OtherInst.Operands.size() == Op ||
|
|
|
|
OtherInst.Operands[Op] != FirstInst.Operands[Op];
|
|
|
|
}))
|
2016-01-24 15:13:28 +08:00
|
|
|
break;
|
2010-09-30 06:32:50 +08:00
|
|
|
|
2006-07-19 02:28:27 +08:00
|
|
|
// Okay, everything in this command set has the same next operand. Add it
|
|
|
|
// to UniqueOperandCommands and remember that it was consumed.
|
2016-01-14 14:15:07 +08:00
|
|
|
std::string Command = " " +
|
2016-01-17 16:05:33 +08:00
|
|
|
FirstInst.Operands[Op].getCode(PassSubtarget) + "\n";
|
2010-09-30 06:32:50 +08:00
|
|
|
|
2006-07-19 02:28:27 +08:00
|
|
|
UniqueOperandCommands[CommandIdx] += Command;
|
|
|
|
InstOpsUsed[CommandIdx]++;
|
2006-07-19 01:18:03 +08:00
|
|
|
}
|
|
|
|
}
|
2010-09-30 06:32:50 +08:00
|
|
|
|
2006-07-19 01:18:03 +08:00
|
|
|
// Prepend some of the instructions each case is used for onto the case val.
|
|
|
|
for (unsigned i = 0, e = InstrsForCase.size(); i != e; ++i) {
|
|
|
|
std::string Instrs = InstrsForCase[i];
|
|
|
|
if (Instrs.size() > 70) {
|
|
|
|
Instrs.erase(Instrs.begin()+70, Instrs.end());
|
|
|
|
Instrs += "...";
|
|
|
|
}
|
2010-09-30 06:32:50 +08:00
|
|
|
|
2006-07-19 01:18:03 +08:00
|
|
|
if (!Instrs.empty())
|
2010-09-30 06:32:50 +08:00
|
|
|
UniqueOperandCommands[i] = " // " + Instrs + "\n" +
|
2006-07-19 01:18:03 +08:00
|
|
|
UniqueOperandCommands[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-10-18 04:43:42 +08:00
|
|
|
static void UnescapeString(std::string &Str) {
|
|
|
|
for (unsigned i = 0; i != Str.size(); ++i) {
|
|
|
|
if (Str[i] == '\\' && i != Str.size()-1) {
|
|
|
|
switch (Str[i+1]) {
|
|
|
|
default: continue; // Don't execute the code after the switch.
|
|
|
|
case 'a': Str[i] = '\a'; break;
|
|
|
|
case 'b': Str[i] = '\b'; break;
|
|
|
|
case 'e': Str[i] = 27; break;
|
|
|
|
case 'f': Str[i] = '\f'; break;
|
|
|
|
case 'n': Str[i] = '\n'; break;
|
|
|
|
case 'r': Str[i] = '\r'; break;
|
|
|
|
case 't': Str[i] = '\t'; break;
|
|
|
|
case 'v': Str[i] = '\v'; break;
|
|
|
|
case '"': Str[i] = '\"'; break;
|
|
|
|
case '\'': Str[i] = '\''; break;
|
|
|
|
case '\\': Str[i] = '\\'; break;
|
|
|
|
}
|
|
|
|
// Nuke the second character.
|
|
|
|
Str.erase(Str.begin()+i+1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-28 17:00:51 +08:00
|
|
|
/// UnescapeAliasString - Supports literal braces in InstAlias asm string which
|
|
|
|
/// are escaped with '\\' to avoid being interpreted as variants. Braces must
|
|
|
|
/// be unescaped before c++ code is generated as (e.g.):
|
|
|
|
///
|
|
|
|
/// AsmString = "foo \{$\x01\}";
|
|
|
|
///
|
|
|
|
/// causes non-standard escape character warnings.
|
|
|
|
static void UnescapeAliasString(std::string &Str) {
|
|
|
|
for (unsigned i = 0; i != Str.size(); ++i) {
|
|
|
|
if (Str[i] == '\\' && i != Str.size()-1) {
|
|
|
|
switch (Str[i+1]) {
|
|
|
|
default: continue; // Don't execute the code after the switch.
|
|
|
|
case '{': Str[i] = '{'; break;
|
|
|
|
case '}': Str[i] = '}'; break;
|
|
|
|
}
|
|
|
|
// Nuke the second character.
|
|
|
|
Str.erase(Str.begin()+i+1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-17 17:38:17 +08:00
|
|
|
void AsmWriterEmitter::EmitGetMnemonic(
|
|
|
|
raw_ostream &O,
|
|
|
|
std::vector<std::vector<std::string>> &TableDrivenOperandPrinters,
|
|
|
|
unsigned &BitsLeft, unsigned &AsmStrBits) {
|
2004-08-15 06:50:53 +08:00
|
|
|
Record *AsmWriter = Target.getAsmWriter();
|
2017-06-01 05:12:46 +08:00
|
|
|
StringRef ClassName = AsmWriter->getValueAsString("AsmWriterClassName");
|
2016-01-14 14:15:07 +08:00
|
|
|
bool PassSubtarget = AsmWriter->getValueAsInt("PassSubtarget");
|
2010-09-30 06:32:50 +08:00
|
|
|
|
2020-11-17 17:38:17 +08:00
|
|
|
O << "/// getMnemonic - This method is automatically generated by "
|
2020-01-04 04:02:46 +08:00
|
|
|
"tablegen\n"
|
|
|
|
"/// from the instruction set description.\n"
|
2020-11-17 17:38:17 +08:00
|
|
|
"std::pair<const char *, uint64_t> "
|
|
|
|
<< Target.getName() << ClassName << "::getMnemonic(const MCInst *MI) {\n";
|
2004-08-01 13:59:33 +08:00
|
|
|
|
2006-07-15 06:59:11 +08:00
|
|
|
// Build an aggregate string, and build a table of offsets into it.
|
2012-04-02 17:13:46 +08:00
|
|
|
SequenceToOffsetTable<std::string> StringTable;
|
2010-09-30 06:32:50 +08:00
|
|
|
|
2006-09-28 00:44:09 +08:00
|
|
|
/// OpcodeInfo - This encodes the index of the string to use for the first
|
2006-07-19 01:32:27 +08:00
|
|
|
/// chunk of the output as well as indices used for operand printing.
|
2016-01-18 04:38:14 +08:00
|
|
|
std::vector<uint64_t> OpcodeInfo(NumberedInstructions.size());
|
2016-01-13 15:20:12 +08:00
|
|
|
const unsigned OpcodeInfoBits = 64;
|
2010-09-30 06:32:50 +08:00
|
|
|
|
2012-04-02 17:13:46 +08:00
|
|
|
// Add all strings to the string table upfront so it can generate an optimized
|
|
|
|
// representation.
|
2016-01-17 16:05:33 +08:00
|
|
|
for (AsmWriterInst &AWI : Instructions) {
|
|
|
|
if (AWI.Operands[0].OperandType ==
|
2012-04-19 02:56:33 +08:00
|
|
|
AsmWriterOperand::isLiteralTextOperand &&
|
2016-01-17 16:05:33 +08:00
|
|
|
!AWI.Operands[0].Str.empty()) {
|
|
|
|
std::string Str = AWI.Operands[0].Str;
|
2012-04-02 17:13:46 +08:00
|
|
|
UnescapeString(Str);
|
|
|
|
StringTable.add(Str);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
StringTable.layout();
|
|
|
|
|
2006-07-19 01:32:27 +08:00
|
|
|
unsigned MaxStringIdx = 0;
|
2016-01-17 16:05:33 +08:00
|
|
|
for (AsmWriterInst &AWI : Instructions) {
|
2006-07-15 06:59:11 +08:00
|
|
|
unsigned Idx;
|
2016-01-17 16:05:33 +08:00
|
|
|
if (AWI.Operands[0].OperandType != AsmWriterOperand::isLiteralTextOperand ||
|
|
|
|
AWI.Operands[0].Str.empty()) {
|
2006-07-19 09:39:06 +08:00
|
|
|
// Something handled by the asmwriter printer, but with no leading string.
|
2012-04-02 17:13:46 +08:00
|
|
|
Idx = StringTable.get("");
|
2006-07-15 06:59:11 +08:00
|
|
|
} else {
|
2016-01-17 16:05:33 +08:00
|
|
|
std::string Str = AWI.Operands[0].Str;
|
2009-09-14 09:16:36 +08:00
|
|
|
UnescapeString(Str);
|
2012-04-02 17:13:46 +08:00
|
|
|
Idx = StringTable.get(Str);
|
2009-09-14 09:16:36 +08:00
|
|
|
MaxStringIdx = std::max(MaxStringIdx, Idx);
|
2010-09-30 06:32:50 +08:00
|
|
|
|
2006-07-15 06:59:11 +08:00
|
|
|
// Nuke the string from the operand list. It is now handled!
|
2016-01-17 16:05:33 +08:00
|
|
|
AWI.Operands.erase(AWI.Operands.begin());
|
2006-07-15 06:59:11 +08:00
|
|
|
}
|
2010-09-30 06:32:50 +08:00
|
|
|
|
2009-09-14 09:16:36 +08:00
|
|
|
// Bias offset by one since we want 0 as a sentinel.
|
2016-01-17 16:05:33 +08:00
|
|
|
OpcodeInfo[AWI.CGIIndex] = Idx+1;
|
2006-07-19 01:18:03 +08:00
|
|
|
}
|
2010-09-30 06:32:50 +08:00
|
|
|
|
2006-07-19 01:32:27 +08:00
|
|
|
// Figure out how many bits we used for the string index.
|
2020-11-17 17:38:17 +08:00
|
|
|
AsmStrBits = Log2_32_Ceil(MaxStringIdx + 2);
|
2010-09-30 06:32:50 +08:00
|
|
|
|
2006-07-19 01:18:03 +08:00
|
|
|
// To reduce code size, we compactify common instructions into a few bits
|
|
|
|
// in the opcode-indexed table.
|
2020-11-17 17:38:17 +08:00
|
|
|
BitsLeft = OpcodeInfoBits - AsmStrBits;
|
2010-09-30 06:32:50 +08:00
|
|
|
|
2016-12-01 01:48:10 +08:00
|
|
|
while (true) {
|
2006-07-19 01:18:03 +08:00
|
|
|
std::vector<std::string> UniqueOperandCommands;
|
2016-01-24 15:13:28 +08:00
|
|
|
std::vector<std::vector<unsigned>> InstIdxs;
|
2006-07-19 02:28:27 +08:00
|
|
|
std::vector<unsigned> NumInstOpsHandled;
|
|
|
|
FindUniqueOperandCommands(UniqueOperandCommands, InstIdxs,
|
2016-01-14 14:15:07 +08:00
|
|
|
NumInstOpsHandled, PassSubtarget);
|
2010-09-30 06:32:50 +08:00
|
|
|
|
2006-07-19 01:18:03 +08:00
|
|
|
// If we ran out of operands to print, we're done.
|
|
|
|
if (UniqueOperandCommands.empty()) break;
|
2010-09-30 06:32:50 +08:00
|
|
|
|
2006-07-19 01:18:03 +08:00
|
|
|
// Compute the number of bits we need to represent these cases, this is
|
|
|
|
// ceil(log2(numentries)).
|
|
|
|
unsigned NumBits = Log2_32_Ceil(UniqueOperandCommands.size());
|
2010-09-30 06:32:50 +08:00
|
|
|
|
2006-07-19 01:18:03 +08:00
|
|
|
// If we don't have enough bits for this operand, don't include it.
|
|
|
|
if (NumBits > BitsLeft) {
|
2018-05-14 20:53:11 +08:00
|
|
|
LLVM_DEBUG(errs() << "Not enough bits to densely encode " << NumBits
|
|
|
|
<< " more bits\n");
|
2006-07-19 01:18:03 +08:00
|
|
|
break;
|
|
|
|
}
|
2010-09-30 06:32:50 +08:00
|
|
|
|
2006-07-19 01:18:03 +08:00
|
|
|
// Otherwise, we can include this in the initial lookup table. Add it in.
|
2016-01-24 15:13:28 +08:00
|
|
|
for (size_t i = 0, e = InstIdxs.size(); i != e; ++i) {
|
|
|
|
unsigned NumOps = NumInstOpsHandled[i];
|
|
|
|
for (unsigned Idx : InstIdxs[i]) {
|
|
|
|
OpcodeInfo[Instructions[Idx].CGIIndex] |=
|
|
|
|
(uint64_t)i << (OpcodeInfoBits-BitsLeft);
|
|
|
|
// Remove the info about this operand from the instruction.
|
|
|
|
AsmWriterInst &Inst = Instructions[Idx];
|
|
|
|
if (!Inst.Operands.empty()) {
|
|
|
|
assert(NumOps <= Inst.Operands.size() &&
|
|
|
|
"Can't remove this many ops!");
|
|
|
|
Inst.Operands.erase(Inst.Operands.begin(),
|
|
|
|
Inst.Operands.begin()+NumOps);
|
|
|
|
}
|
2016-01-17 16:05:33 +08:00
|
|
|
}
|
2006-07-19 01:56:07 +08:00
|
|
|
}
|
2016-01-24 15:13:28 +08:00
|
|
|
BitsLeft -= NumBits;
|
2010-09-30 06:32:50 +08:00
|
|
|
|
2006-07-19 01:56:07 +08:00
|
|
|
// Remember the handlers for this set of operands.
|
2014-11-26 04:11:25 +08:00
|
|
|
TableDrivenOperandPrinters.push_back(std::move(UniqueOperandCommands));
|
2006-07-19 01:18:03 +08:00
|
|
|
}
|
2010-09-30 06:32:50 +08:00
|
|
|
|
2016-01-11 13:13:41 +08:00
|
|
|
// Emit the string table itself.
|
[tablegen] Emit string literals instead of char arrays
This changes the generated (Instr|Asm|Reg|Regclass)Name tables from this
form:
extern const char HexagonInstrNameData[] = {
/* 0 */ 'G', '_', 'F', 'L', 'O', 'G', '1', '0', 0,
/* 9 */ 'E', 'N', 'D', 'L', 'O', 'O', 'P', '0', 0,
/* 18 */ 'V', '6', '_', 'v', 'd', 'd', '0', 0,
/* 26 */ 'P', 'S', '_', 'v', 'd', 'd', '0', 0,
[...]
};
...to this:
extern const char HexagonInstrNameData[] = {
/* 0 */ "G_FLOG10\0"
/* 9 */ "ENDLOOP0\0"
/* 18 */ "V6_vdd0\0"
/* 26 */ "PS_vdd0\0"
[...]
};
This should make debugging and exploration a lot easier for mortals,
while providing a significant compile-time reduction for common compilers.
To avoid issues with low implementation limits, this is disabled by
default for visual studio.
To force output one way or the other, pass
`--long-string-literals=<bool>` to `tablegen`
Reviewers: mstorsjo, rnk
Subscribers: llvm-commits
Differential Revision: https://reviews.llvm.org/D73044
A variation of this patch was originally committed in ce23515f5ab011 and
then reverted in e464b31c due to build failures.
2020-01-15 22:14:01 +08:00
|
|
|
StringTable.emitStringLiteralDef(O, " static const char AsmStrs[]");
|
2010-09-30 06:32:50 +08:00
|
|
|
|
2016-01-11 13:13:41 +08:00
|
|
|
// Emit the lookup tables in pieces to minimize wasted bytes.
|
2016-01-13 15:20:12 +08:00
|
|
|
unsigned BytesNeeded = ((OpcodeInfoBits - BitsLeft) + 7) / 8;
|
2016-01-11 13:13:41 +08:00
|
|
|
unsigned Table = 0, Shift = 0;
|
|
|
|
SmallString<128> BitsString;
|
|
|
|
raw_svector_ostream BitsOS(BitsString);
|
|
|
|
// If the total bits is more than 32-bits we need to use a 64-bit type.
|
2016-01-13 15:20:12 +08:00
|
|
|
BitsOS << " uint" << ((BitsLeft < (OpcodeInfoBits - 32)) ? 64 : 32)
|
|
|
|
<< "_t Bits = 0;\n";
|
2016-01-11 13:13:41 +08:00
|
|
|
while (BytesNeeded != 0) {
|
|
|
|
// Figure out how big this table section needs to be, but no bigger than 4.
|
|
|
|
unsigned TableSize = std::min(1 << Log2_32(BytesNeeded), 4);
|
|
|
|
BytesNeeded -= TableSize;
|
|
|
|
TableSize *= 8; // Convert to bits;
|
|
|
|
uint64_t Mask = (1ULL << TableSize) - 1;
|
|
|
|
O << " static const uint" << TableSize << "_t OpInfo" << Table
|
|
|
|
<< "[] = {\n";
|
2016-01-18 04:38:14 +08:00
|
|
|
for (unsigned i = 0, e = NumberedInstructions.size(); i != e; ++i) {
|
2016-01-11 13:13:41 +08:00
|
|
|
O << " " << ((OpcodeInfo[i] >> Shift) & Mask) << "U,\t// "
|
2016-01-18 04:38:14 +08:00
|
|
|
<< NumberedInstructions[i]->TheDef->getName() << "\n";
|
2012-09-14 01:43:46 +08:00
|
|
|
}
|
|
|
|
O << " };\n\n";
|
2016-01-11 13:13:41 +08:00
|
|
|
// Emit string to combine the individual table lookups.
|
|
|
|
BitsOS << " Bits |= ";
|
|
|
|
// If the total bits is more than 32-bits we need to use a 64-bit type.
|
2016-01-13 15:20:12 +08:00
|
|
|
if (BitsLeft < (OpcodeInfoBits - 32))
|
2016-01-11 13:13:41 +08:00
|
|
|
BitsOS << "(uint64_t)";
|
|
|
|
BitsOS << "OpInfo" << Table << "[MI->getOpcode()] << " << Shift << ";\n";
|
|
|
|
// Prepare the shift for the next iteration and increment the table count.
|
|
|
|
Shift += TableSize;
|
|
|
|
++Table;
|
2012-09-14 01:43:46 +08:00
|
|
|
}
|
|
|
|
|
2012-09-14 16:33:11 +08:00
|
|
|
O << " // Emit the opcode for the instruction.\n";
|
2016-01-11 13:13:41 +08:00
|
|
|
O << BitsString;
|
|
|
|
|
2020-11-17 17:38:17 +08:00
|
|
|
// Return mnemonic string and bits.
|
|
|
|
O << " return {AsmStrs+(Bits & " << (1 << AsmStrBits) - 1
|
|
|
|
<< ")-1, Bits};\n\n";
|
|
|
|
|
|
|
|
O << "}\n";
|
|
|
|
}
|
|
|
|
|
|
|
|
/// EmitPrintInstruction - Generate the code for the "printInstruction" method
|
|
|
|
/// implementation. Destroys all instances of AsmWriterInst information, by
|
|
|
|
/// clearing the Instructions vector.
|
|
|
|
void AsmWriterEmitter::EmitPrintInstruction(
|
|
|
|
raw_ostream &O,
|
|
|
|
std::vector<std::vector<std::string>> &TableDrivenOperandPrinters,
|
|
|
|
unsigned &BitsLeft, unsigned &AsmStrBits) {
|
|
|
|
const unsigned OpcodeInfoBits = 64;
|
|
|
|
Record *AsmWriter = Target.getAsmWriter();
|
|
|
|
StringRef ClassName = AsmWriter->getValueAsString("AsmWriterClassName");
|
|
|
|
bool PassSubtarget = AsmWriter->getValueAsInt("PassSubtarget");
|
|
|
|
|
|
|
|
O << "/// printInstruction - This method is automatically generated by "
|
|
|
|
"tablegen\n"
|
|
|
|
"/// from the instruction set description.\n"
|
|
|
|
"void "
|
|
|
|
<< Target.getName() << ClassName
|
|
|
|
<< "::printInstruction(const MCInst *MI, uint64_t Address, "
|
|
|
|
<< (PassSubtarget ? "const MCSubtargetInfo &STI, " : "")
|
|
|
|
<< "raw_ostream &O) {\n";
|
|
|
|
|
|
|
|
// Emit the initial tab character.
|
|
|
|
O << " O << \"\\t\";\n\n";
|
|
|
|
|
2016-01-11 13:13:41 +08:00
|
|
|
// Emit the starting string.
|
2020-11-17 17:38:17 +08:00
|
|
|
O << " auto MnemonicInfo = getMnemonic(MI);\n\n";
|
|
|
|
O << " O << MnemonicInfo.first;\n\n";
|
|
|
|
|
|
|
|
O << " uint" << ((BitsLeft < (OpcodeInfoBits - 32)) ? 64 : 32)
|
|
|
|
<< "_t Bits = MnemonicInfo.second;\n"
|
|
|
|
<< " assert(Bits != 0 && \"Cannot print this instruction.\");\n";
|
2009-08-06 05:00:52 +08:00
|
|
|
|
2006-07-19 01:18:03 +08:00
|
|
|
// Output the table driven operand information.
|
2016-01-13 15:20:12 +08:00
|
|
|
BitsLeft = OpcodeInfoBits-AsmStrBits;
|
2006-07-19 01:18:03 +08:00
|
|
|
for (unsigned i = 0, e = TableDrivenOperandPrinters.size(); i != e; ++i) {
|
|
|
|
std::vector<std::string> &Commands = TableDrivenOperandPrinters[i];
|
2005-01-23 03:22:23 +08:00
|
|
|
|
2006-07-19 01:18:03 +08:00
|
|
|
// Compute the number of bits we need to represent these cases, this is
|
|
|
|
// ceil(log2(numentries)).
|
|
|
|
unsigned NumBits = Log2_32_Ceil(Commands.size());
|
|
|
|
assert(NumBits <= BitsLeft && "consistency error");
|
2010-09-30 06:32:50 +08:00
|
|
|
|
2006-07-19 01:18:03 +08:00
|
|
|
// Emit code to extract this field from Bits.
|
|
|
|
O << "\n // Fragment " << i << " encoded into " << NumBits
|
2006-07-19 01:43:54 +08:00
|
|
|
<< " bits for " << Commands.size() << " unique commands.\n";
|
2010-09-30 06:32:50 +08:00
|
|
|
|
2006-07-19 02:28:27 +08:00
|
|
|
if (Commands.size() == 2) {
|
2006-07-19 01:43:54 +08:00
|
|
|
// Emit two possibilitys with if/else.
|
2012-09-14 16:33:11 +08:00
|
|
|
O << " if ((Bits >> "
|
2016-01-13 15:20:12 +08:00
|
|
|
<< (OpcodeInfoBits-BitsLeft) << ") & "
|
2006-07-19 01:43:54 +08:00
|
|
|
<< ((1 << NumBits)-1) << ") {\n"
|
|
|
|
<< Commands[1]
|
|
|
|
<< " } else {\n"
|
|
|
|
<< Commands[0]
|
|
|
|
<< " }\n\n";
|
2010-09-19 02:50:27 +08:00
|
|
|
} else if (Commands.size() == 1) {
|
|
|
|
// Emit a single possibility.
|
|
|
|
O << Commands[0] << "\n\n";
|
2006-07-19 01:43:54 +08:00
|
|
|
} else {
|
2012-09-14 16:33:11 +08:00
|
|
|
O << " switch ((Bits >> "
|
2016-01-13 15:20:12 +08:00
|
|
|
<< (OpcodeInfoBits-BitsLeft) << ") & "
|
2006-07-19 01:43:54 +08:00
|
|
|
<< ((1 << NumBits)-1) << ") {\n"
|
2014-11-24 22:09:52 +08:00
|
|
|
<< " default: llvm_unreachable(\"Invalid command number.\");\n";
|
2010-09-30 06:32:50 +08:00
|
|
|
|
2006-07-19 01:43:54 +08:00
|
|
|
// Print out all the cases.
|
2016-01-08 15:06:32 +08:00
|
|
|
for (unsigned j = 0, e = Commands.size(); j != e; ++j) {
|
|
|
|
O << " case " << j << ":\n";
|
|
|
|
O << Commands[j];
|
2006-07-19 01:43:54 +08:00
|
|
|
O << " break;\n";
|
|
|
|
}
|
|
|
|
O << " }\n\n";
|
2006-07-19 01:18:03 +08:00
|
|
|
}
|
2012-09-14 16:33:11 +08:00
|
|
|
BitsLeft -= NumBits;
|
2006-07-19 01:18:03 +08:00
|
|
|
}
|
2010-09-30 06:32:50 +08:00
|
|
|
|
2006-07-19 01:56:07 +08:00
|
|
|
// Okay, delete instructions with no operand info left.
|
2020-12-27 04:06:25 +08:00
|
|
|
llvm::erase_if(Instructions,
|
|
|
|
[](AsmWriterInst &Inst) { return Inst.Operands.empty(); });
|
2010-09-30 06:32:50 +08:00
|
|
|
|
2006-07-19 01:18:03 +08:00
|
|
|
// Because this is a vector, we want to emit from the end. Reverse all of the
|
Implement factoring of instruction pattern strings. In particular, instead of
emitting code like this:
case PPC::ADD: O << "add "; printOperand(MI, 0, MVT::i64); O << ", "; prin
tOperand(MI, 1, MVT::i64); O << ", "; printOperand(MI, 2, MVT::i64); O << '\n
'; break;
case PPC::ADDC: O << "addc "; printOperand(MI, 0, MVT::i64); O << ", "; pr
intOperand(MI, 1, MVT::i64); O << ", "; printOperand(MI, 2, MVT::i64); O << '
\n'; break;
case PPC::ADDE: O << "adde "; printOperand(MI, 0, MVT::i64); O << ", "; pr
intOperand(MI, 1, MVT::i64); O << ", "; printOperand(MI, 2, MVT::i64); O << '
\n'; break;
...
Emit code like this:
case PPC::ADD:
case PPC::ADDC:
case PPC::ADDE:
...
switch (MI->getOpcode()) {
case PPC::ADD: O << "add "; break;
case PPC::ADDC: O << "addc "; break;
case PPC::ADDE: O << "adde "; break;
...
}
printOperand(MI, 0, MVT::i64);
O << ", ";
printOperand(MI, 1, MVT::i64);
O << ", ";
printOperand(MI, 2, MVT::i64);
O << "\n";
break;
This shrinks the PPC asm writer from 24785->15205 bytes (even though the new
asmwriter has much more whitespace than the old one), and the X86 printers shrink
quite a bit too. The important implication of this is that GCC no longer hits swap
when building the PPC backend in optimized mode. Thus this fixes PR448.
-Chris
llvm-svn: 19755
2005-01-23 02:38:13 +08:00
|
|
|
// elements in the vector.
|
|
|
|
std::reverse(Instructions.begin(), Instructions.end());
|
2010-09-30 06:32:50 +08:00
|
|
|
|
|
|
|
|
2016-01-13 15:20:07 +08:00
|
|
|
// Now that we've emitted all of the operand info that fit into 64 bits, emit
|
2009-09-19 02:10:19 +08:00
|
|
|
// information for those instructions that are left. This is a less dense
|
2016-01-13 15:20:07 +08:00
|
|
|
// encoding, but we expect the main 64-bit table to handle the majority of
|
2009-09-19 02:10:19 +08:00
|
|
|
// instructions.
|
2006-07-19 01:38:46 +08:00
|
|
|
if (!Instructions.empty()) {
|
|
|
|
// Find the opcode # of inline asm.
|
|
|
|
O << " switch (MI->getOpcode()) {\n";
|
2016-01-13 15:20:13 +08:00
|
|
|
O << " default: llvm_unreachable(\"Unexpected opcode.\");\n";
|
2006-07-19 01:38:46 +08:00
|
|
|
while (!Instructions.empty())
|
2016-01-14 14:15:07 +08:00
|
|
|
EmitInstructions(Instructions, O, PassSubtarget);
|
Implement factoring of instruction pattern strings. In particular, instead of
emitting code like this:
case PPC::ADD: O << "add "; printOperand(MI, 0, MVT::i64); O << ", "; prin
tOperand(MI, 1, MVT::i64); O << ", "; printOperand(MI, 2, MVT::i64); O << '\n
'; break;
case PPC::ADDC: O << "addc "; printOperand(MI, 0, MVT::i64); O << ", "; pr
intOperand(MI, 1, MVT::i64); O << ", "; printOperand(MI, 2, MVT::i64); O << '
\n'; break;
case PPC::ADDE: O << "adde "; printOperand(MI, 0, MVT::i64); O << ", "; pr
intOperand(MI, 1, MVT::i64); O << ", "; printOperand(MI, 2, MVT::i64); O << '
\n'; break;
...
Emit code like this:
case PPC::ADD:
case PPC::ADDC:
case PPC::ADDE:
...
switch (MI->getOpcode()) {
case PPC::ADD: O << "add "; break;
case PPC::ADDC: O << "addc "; break;
case PPC::ADDE: O << "adde "; break;
...
}
printOperand(MI, 0, MVT::i64);
O << ", ";
printOperand(MI, 1, MVT::i64);
O << ", ";
printOperand(MI, 2, MVT::i64);
O << "\n";
break;
This shrinks the PPC asm writer from 24785->15205 bytes (even though the new
asmwriter has much more whitespace than the old one), and the X86 printers shrink
quite a bit too. The important implication of this is that GCC no longer hits swap
when building the PPC backend in optimized mode. Thus this fixes PR448.
-Chris
llvm-svn: 19755
2005-01-23 02:38:13 +08:00
|
|
|
|
2006-07-19 01:38:46 +08:00
|
|
|
O << " }\n";
|
|
|
|
}
|
2009-07-30 04:10:24 +08:00
|
|
|
|
2006-07-19 03:06:01 +08:00
|
|
|
O << "}\n";
|
2004-08-01 13:59:33 +08:00
|
|
|
}
|
2009-09-14 04:08:00 +08:00
|
|
|
|
2011-06-28 05:06:21 +08:00
|
|
|
static void
|
|
|
|
emitRegisterNameString(raw_ostream &O, StringRef AltName,
|
2014-11-30 02:13:39 +08:00
|
|
|
const std::deque<CodeGenRegister> &Registers) {
|
2012-03-31 05:12:52 +08:00
|
|
|
SequenceToOffsetTable<std::string> StringTable;
|
|
|
|
SmallVector<std::string, 4> AsmNames(Registers.size());
|
2014-11-30 02:13:39 +08:00
|
|
|
unsigned i = 0;
|
|
|
|
for (const auto &Reg : Registers) {
|
|
|
|
std::string &AsmName = AsmNames[i++];
|
2011-06-28 05:06:21 +08:00
|
|
|
|
|
|
|
// "NoRegAltName" is special. We don't need to do a lookup for that,
|
|
|
|
// as it's just a reference to the default register name.
|
|
|
|
if (AltName == "" || AltName == "NoRegAltName") {
|
2020-01-29 03:23:46 +08:00
|
|
|
AsmName = std::string(Reg.TheDef->getValueAsString("AsmName"));
|
2011-06-28 05:06:21 +08:00
|
|
|
if (AsmName.empty())
|
2020-01-29 03:23:46 +08:00
|
|
|
AsmName = std::string(Reg.getName());
|
2011-06-28 05:06:21 +08:00
|
|
|
} else {
|
|
|
|
// Make sure the register has an alternate name for this index.
|
|
|
|
std::vector<Record*> AltNameList =
|
|
|
|
Reg.TheDef->getValueAsListOfDefs("RegAltNameIndices");
|
|
|
|
unsigned Idx = 0, e;
|
|
|
|
for (e = AltNameList.size();
|
|
|
|
Idx < e && (AltNameList[Idx]->getName() != AltName);
|
|
|
|
++Idx)
|
|
|
|
;
|
|
|
|
// If the register has an alternate name for this index, use it.
|
|
|
|
// Otherwise, leave it empty as an error flag.
|
|
|
|
if (Idx < e) {
|
2017-06-01 03:01:11 +08:00
|
|
|
std::vector<StringRef> AltNames =
|
2011-06-28 05:06:21 +08:00
|
|
|
Reg.TheDef->getValueAsListOfStrings("AltNames");
|
|
|
|
if (AltNames.size() <= Idx)
|
2012-10-26 04:33:17 +08:00
|
|
|
PrintFatalError(Reg.TheDef->getLoc(),
|
2014-03-30 01:17:15 +08:00
|
|
|
"Register definition missing alt name for '" +
|
|
|
|
AltName + "'.");
|
2020-01-29 03:23:46 +08:00
|
|
|
AsmName = std::string(AltNames[Idx]);
|
2011-06-28 05:06:21 +08:00
|
|
|
}
|
|
|
|
}
|
2012-03-31 05:12:52 +08:00
|
|
|
StringTable.add(AsmName);
|
|
|
|
}
|
|
|
|
|
2012-09-15 09:22:42 +08:00
|
|
|
StringTable.layout();
|
[tablegen] Emit string literals instead of char arrays
This changes the generated (Instr|Asm|Reg|Regclass)Name tables from this
form:
extern const char HexagonInstrNameData[] = {
/* 0 */ 'G', '_', 'F', 'L', 'O', 'G', '1', '0', 0,
/* 9 */ 'E', 'N', 'D', 'L', 'O', 'O', 'P', '0', 0,
/* 18 */ 'V', '6', '_', 'v', 'd', 'd', '0', 0,
/* 26 */ 'P', 'S', '_', 'v', 'd', 'd', '0', 0,
[...]
};
...to this:
extern const char HexagonInstrNameData[] = {
/* 0 */ "G_FLOG10\0"
/* 9 */ "ENDLOOP0\0"
/* 18 */ "V6_vdd0\0"
/* 26 */ "PS_vdd0\0"
[...]
};
This should make debugging and exploration a lot easier for mortals,
while providing a significant compile-time reduction for common compilers.
To avoid issues with low implementation limits, this is disabled by
default for visual studio.
To force output one way or the other, pass
`--long-string-literals=<bool>` to `tablegen`
Reviewers: mstorsjo, rnk
Subscribers: llvm-commits
Differential Revision: https://reviews.llvm.org/D73044
A variation of this patch was originally committed in ce23515f5ab011 and
then reverted in e464b31c due to build failures.
2020-01-15 22:14:01 +08:00
|
|
|
StringTable.emitStringLiteralDef(O, Twine(" static const char AsmStrs") +
|
|
|
|
AltName + "[]");
|
2011-06-28 05:06:21 +08:00
|
|
|
|
2016-11-19 20:21:34 +08:00
|
|
|
O << " static const " << getMinimalTypeForRange(StringTable.size() - 1, 32)
|
2014-11-24 10:08:35 +08:00
|
|
|
<< " RegAsmOffset" << AltName << "[] = {";
|
2012-03-31 05:12:52 +08:00
|
|
|
for (unsigned i = 0, e = Registers.size(); i != e; ++i) {
|
2012-04-02 08:47:39 +08:00
|
|
|
if ((i % 14) == 0)
|
|
|
|
O << "\n ";
|
|
|
|
O << StringTable.get(AsmNames[i]) << ", ";
|
2011-06-28 05:06:21 +08:00
|
|
|
}
|
2012-04-03 14:52:47 +08:00
|
|
|
O << "\n };\n"
|
2011-06-28 05:06:21 +08:00
|
|
|
<< "\n";
|
|
|
|
}
|
2009-09-14 04:08:00 +08:00
|
|
|
|
|
|
|
void AsmWriterEmitter::EmitGetRegisterName(raw_ostream &O) {
|
|
|
|
Record *AsmWriter = Target.getAsmWriter();
|
2017-06-01 05:12:46 +08:00
|
|
|
StringRef ClassName = AsmWriter->getValueAsString("AsmWriterClassName");
|
2014-11-30 02:13:39 +08:00
|
|
|
const auto &Registers = Target.getRegBank().getRegisters();
|
2016-01-18 04:38:21 +08:00
|
|
|
const std::vector<Record*> &AltNameIndices = Target.getRegAltNameIndices();
|
2011-06-28 05:06:21 +08:00
|
|
|
bool hasAltNames = AltNameIndices.size() > 1;
|
2017-06-01 05:12:46 +08:00
|
|
|
StringRef Namespace = Registers.front().TheDef->getValueAsString("Namespace");
|
2010-09-30 06:32:50 +08:00
|
|
|
|
2009-09-14 04:08:00 +08:00
|
|
|
O <<
|
|
|
|
"\n\n/// getRegisterName - This method is automatically generated by tblgen\n"
|
|
|
|
"/// from the register set description. This returns the assembler name\n"
|
|
|
|
"/// for the specified register.\n"
|
2011-06-28 05:06:21 +08:00
|
|
|
"const char *" << Target.getName() << ClassName << "::";
|
|
|
|
if (hasAltNames)
|
|
|
|
O << "\ngetRegisterName(unsigned RegNo, unsigned AltIdx) {\n";
|
|
|
|
else
|
|
|
|
O << "getRegisterName(unsigned RegNo) {\n";
|
|
|
|
O << " assert(RegNo && RegNo < " << (Registers.size()+1)
|
|
|
|
<< " && \"Invalid register number!\");\n"
|
2009-09-14 09:26:18 +08:00
|
|
|
<< "\n";
|
2010-09-30 06:32:50 +08:00
|
|
|
|
2011-06-28 05:06:21 +08:00
|
|
|
if (hasAltNames) {
|
2016-01-08 15:06:32 +08:00
|
|
|
for (const Record *R : AltNameIndices)
|
|
|
|
emitRegisterNameString(O, R->getName(), Registers);
|
2011-06-28 05:06:21 +08:00
|
|
|
} else
|
|
|
|
emitRegisterNameString(O, "", Registers);
|
|
|
|
|
|
|
|
if (hasAltNames) {
|
2014-11-24 10:08:35 +08:00
|
|
|
O << " switch(AltIdx) {\n"
|
2012-02-05 15:21:30 +08:00
|
|
|
<< " default: llvm_unreachable(\"Invalid register alt name index!\");\n";
|
2016-01-08 15:06:32 +08:00
|
|
|
for (const Record *R : AltNameIndices) {
|
2017-06-01 05:12:46 +08:00
|
|
|
StringRef AltName = R->getName();
|
|
|
|
O << " case ";
|
|
|
|
if (!Namespace.empty())
|
|
|
|
O << Namespace << "::";
|
2019-02-26 20:15:14 +08:00
|
|
|
O << AltName << ":\n";
|
|
|
|
if (R->isValueUnset("FallbackRegAltNameIndex"))
|
|
|
|
O << " assert(*(AsmStrs" << AltName << "+RegAsmOffset" << AltName
|
|
|
|
<< "[RegNo-1]) &&\n"
|
|
|
|
<< " \"Invalid alt name index for register!\");\n";
|
|
|
|
else {
|
|
|
|
O << " if (!*(AsmStrs" << AltName << "+RegAsmOffset" << AltName
|
|
|
|
<< "[RegNo-1]))\n"
|
|
|
|
<< " return getRegisterName(RegNo, ";
|
|
|
|
if (!Namespace.empty())
|
|
|
|
O << Namespace << "::";
|
|
|
|
O << R->getValueAsDef("FallbackRegAltNameIndex")->getName() << ");\n";
|
|
|
|
}
|
|
|
|
O << " return AsmStrs" << AltName << "+RegAsmOffset" << AltName
|
2017-06-01 05:12:46 +08:00
|
|
|
<< "[RegNo-1];\n";
|
2011-06-28 05:06:21 +08:00
|
|
|
}
|
2014-11-24 10:08:35 +08:00
|
|
|
O << " }\n";
|
|
|
|
} else {
|
|
|
|
O << " assert (*(AsmStrs+RegAsmOffset[RegNo-1]) &&\n"
|
|
|
|
<< " \"Invalid alt name index for register!\");\n"
|
|
|
|
<< " return AsmStrs+RegAsmOffset[RegNo-1];\n";
|
2011-06-28 05:06:21 +08:00
|
|
|
}
|
2014-11-24 10:08:35 +08:00
|
|
|
O << "}\n";
|
2009-09-14 04:08:00 +08:00
|
|
|
}
|
|
|
|
|
2011-03-21 16:31:53 +08:00
|
|
|
namespace {
|
2016-12-01 01:48:10 +08:00
|
|
|
|
2011-03-21 16:40:31 +08:00
|
|
|
// IAPrinter - Holds information about an InstAlias. Two InstAliases match if
|
|
|
|
// they both have the same conditionals. In which case, we cannot print out the
|
|
|
|
// alias for that pattern.
|
|
|
|
class IAPrinter {
|
2014-05-13 02:04:06 +08:00
|
|
|
std::map<StringRef, std::pair<int, int>> OpMap;
|
|
|
|
|
[MC] Rewrite tablegen for printInstrAlias to comiple faster, NFC
Before this change, the *InstPrinter.cpp files of each target where some
of the slowest objects to compile in all of LLVM. See this snippet produced by
ClangBuildAnalyzer:
https://reviews.llvm.org/P8171$96
Search for "InstPrinter", and see that it shows up in a few places.
Tablegen was emitting a large switch containing a sequence of operand checks,
each of which created many conditions and many BBs. Register allocation and
jump threading both did not scale well with such a large repetitive sequence of
basic blocks.
So, this change essentially turns those control flow structures into
data. The previous structure looked like:
switch (Opc) {
case TGT::ADD:
// check alias 1
if (MI->getOperandCount() == N && // check num opnds
MI->getOperand(0).isReg() && // check opnd 0
...
MI->getOperand(1).isImm() && // check opnd 1
AsmString = "foo";
break;
}
// check alias 2
if (...)
...
return false;
The new structure looks like:
OpToPatterns: Sorted table of opcodes mapping to pattern indices.
\->
Patterns: List of patterns. Previous table points to subrange of
patterns to match.
\->
Conds: The if conditions above encoded as a kind and 32-bit value.
See MCInstPrinter.cpp for the details of how the new data structures are
interpreted.
Here are some before and after metrics.
Time to compile AArch64InstPrinter.cpp:
0m29.062s vs. 0m2.203s
size of the obj:
3.9M vs. 676K
size of clang.exe:
97M vs. 96M
I have not benchmarked disassembly performance, but typically
disassemblers are bottlenecked on IO and string processing, not alias
matching, so I'm not sure it's interesting enough to be worth doing.
Reviewers: RKSimon, andreadb, xbolva00, craig.topper
Reviewed By: craig.topper
Differential Revision: https://reviews.llvm.org/D70650
2019-11-24 03:28:54 +08:00
|
|
|
std::vector<std::string> Conds;
|
|
|
|
|
2011-03-21 16:40:31 +08:00
|
|
|
std::string Result;
|
|
|
|
std::string AsmString;
|
2016-12-01 01:48:10 +08:00
|
|
|
|
[MC] Rewrite tablegen for printInstrAlias to comiple faster, NFC
Before this change, the *InstPrinter.cpp files of each target where some
of the slowest objects to compile in all of LLVM. See this snippet produced by
ClangBuildAnalyzer:
https://reviews.llvm.org/P8171$96
Search for "InstPrinter", and see that it shows up in a few places.
Tablegen was emitting a large switch containing a sequence of operand checks,
each of which created many conditions and many BBs. Register allocation and
jump threading both did not scale well with such a large repetitive sequence of
basic blocks.
So, this change essentially turns those control flow structures into
data. The previous structure looked like:
switch (Opc) {
case TGT::ADD:
// check alias 1
if (MI->getOperandCount() == N && // check num opnds
MI->getOperand(0).isReg() && // check opnd 0
...
MI->getOperand(1).isImm() && // check opnd 1
AsmString = "foo";
break;
}
// check alias 2
if (...)
...
return false;
The new structure looks like:
OpToPatterns: Sorted table of opcodes mapping to pattern indices.
\->
Patterns: List of patterns. Previous table points to subrange of
patterns to match.
\->
Conds: The if conditions above encoded as a kind and 32-bit value.
See MCInstPrinter.cpp for the details of how the new data structures are
interpreted.
Here are some before and after metrics.
Time to compile AArch64InstPrinter.cpp:
0m29.062s vs. 0m2.203s
size of the obj:
3.9M vs. 676K
size of clang.exe:
97M vs. 96M
I have not benchmarked disassembly performance, but typically
disassemblers are bottlenecked on IO and string processing, not alias
matching, so I'm not sure it's interesting enough to be worth doing.
Reviewers: RKSimon, andreadb, xbolva00, craig.topper
Reviewed By: craig.topper
Differential Revision: https://reviews.llvm.org/D70650
2019-11-24 03:28:54 +08:00
|
|
|
unsigned NumMIOps;
|
|
|
|
|
2011-03-21 16:40:31 +08:00
|
|
|
public:
|
[MC] Rewrite tablegen for printInstrAlias to comiple faster, NFC
Before this change, the *InstPrinter.cpp files of each target where some
of the slowest objects to compile in all of LLVM. See this snippet produced by
ClangBuildAnalyzer:
https://reviews.llvm.org/P8171$96
Search for "InstPrinter", and see that it shows up in a few places.
Tablegen was emitting a large switch containing a sequence of operand checks,
each of which created many conditions and many BBs. Register allocation and
jump threading both did not scale well with such a large repetitive sequence of
basic blocks.
So, this change essentially turns those control flow structures into
data. The previous structure looked like:
switch (Opc) {
case TGT::ADD:
// check alias 1
if (MI->getOperandCount() == N && // check num opnds
MI->getOperand(0).isReg() && // check opnd 0
...
MI->getOperand(1).isImm() && // check opnd 1
AsmString = "foo";
break;
}
// check alias 2
if (...)
...
return false;
The new structure looks like:
OpToPatterns: Sorted table of opcodes mapping to pattern indices.
\->
Patterns: List of patterns. Previous table points to subrange of
patterns to match.
\->
Conds: The if conditions above encoded as a kind and 32-bit value.
See MCInstPrinter.cpp for the details of how the new data structures are
interpreted.
Here are some before and after metrics.
Time to compile AArch64InstPrinter.cpp:
0m29.062s vs. 0m2.203s
size of the obj:
3.9M vs. 676K
size of clang.exe:
97M vs. 96M
I have not benchmarked disassembly performance, but typically
disassemblers are bottlenecked on IO and string processing, not alias
matching, so I'm not sure it's interesting enough to be worth doing.
Reviewers: RKSimon, andreadb, xbolva00, craig.topper
Reviewed By: craig.topper
Differential Revision: https://reviews.llvm.org/D70650
2019-11-24 03:28:54 +08:00
|
|
|
IAPrinter(std::string R, std::string AS, unsigned NumMIOps)
|
|
|
|
: Result(std::move(R)), AsmString(std::move(AS)), NumMIOps(NumMIOps) {}
|
2011-03-21 16:40:31 +08:00
|
|
|
|
[MC] Rewrite tablegen for printInstrAlias to comiple faster, NFC
Before this change, the *InstPrinter.cpp files of each target where some
of the slowest objects to compile in all of LLVM. See this snippet produced by
ClangBuildAnalyzer:
https://reviews.llvm.org/P8171$96
Search for "InstPrinter", and see that it shows up in a few places.
Tablegen was emitting a large switch containing a sequence of operand checks,
each of which created many conditions and many BBs. Register allocation and
jump threading both did not scale well with such a large repetitive sequence of
basic blocks.
So, this change essentially turns those control flow structures into
data. The previous structure looked like:
switch (Opc) {
case TGT::ADD:
// check alias 1
if (MI->getOperandCount() == N && // check num opnds
MI->getOperand(0).isReg() && // check opnd 0
...
MI->getOperand(1).isImm() && // check opnd 1
AsmString = "foo";
break;
}
// check alias 2
if (...)
...
return false;
The new structure looks like:
OpToPatterns: Sorted table of opcodes mapping to pattern indices.
\->
Patterns: List of patterns. Previous table points to subrange of
patterns to match.
\->
Conds: The if conditions above encoded as a kind and 32-bit value.
See MCInstPrinter.cpp for the details of how the new data structures are
interpreted.
Here are some before and after metrics.
Time to compile AArch64InstPrinter.cpp:
0m29.062s vs. 0m2.203s
size of the obj:
3.9M vs. 676K
size of clang.exe:
97M vs. 96M
I have not benchmarked disassembly performance, but typically
disassemblers are bottlenecked on IO and string processing, not alias
matching, so I'm not sure it's interesting enough to be worth doing.
Reviewers: RKSimon, andreadb, xbolva00, craig.topper
Reviewed By: craig.topper
Differential Revision: https://reviews.llvm.org/D70650
2019-11-24 03:28:54 +08:00
|
|
|
void addCond(std::string C) { Conds.push_back(std::move(C)); }
|
|
|
|
ArrayRef<std::string> getConds() const { return Conds; }
|
|
|
|
size_t getCondCount() const { return Conds.size(); }
|
2011-03-21 16:40:31 +08:00
|
|
|
|
2014-05-13 02:04:06 +08:00
|
|
|
void addOperand(StringRef Op, int OpIdx, int PrintMethodIdx = -1) {
|
|
|
|
assert(OpIdx >= 0 && OpIdx < 0xFE && "Idx out of range");
|
2014-05-13 17:37:41 +08:00
|
|
|
assert(PrintMethodIdx >= -1 && PrintMethodIdx < 0xFF &&
|
2014-05-13 16:26:53 +08:00
|
|
|
"Idx out of range");
|
2014-05-13 02:04:06 +08:00
|
|
|
OpMap[Op] = std::make_pair(OpIdx, PrintMethodIdx);
|
2013-09-11 23:42:16 +08:00
|
|
|
}
|
2014-05-13 02:04:06 +08:00
|
|
|
|
[MC] Rewrite tablegen for printInstrAlias to comiple faster, NFC
Before this change, the *InstPrinter.cpp files of each target where some
of the slowest objects to compile in all of LLVM. See this snippet produced by
ClangBuildAnalyzer:
https://reviews.llvm.org/P8171$96
Search for "InstPrinter", and see that it shows up in a few places.
Tablegen was emitting a large switch containing a sequence of operand checks,
each of which created many conditions and many BBs. Register allocation and
jump threading both did not scale well with such a large repetitive sequence of
basic blocks.
So, this change essentially turns those control flow structures into
data. The previous structure looked like:
switch (Opc) {
case TGT::ADD:
// check alias 1
if (MI->getOperandCount() == N && // check num opnds
MI->getOperand(0).isReg() && // check opnd 0
...
MI->getOperand(1).isImm() && // check opnd 1
AsmString = "foo";
break;
}
// check alias 2
if (...)
...
return false;
The new structure looks like:
OpToPatterns: Sorted table of opcodes mapping to pattern indices.
\->
Patterns: List of patterns. Previous table points to subrange of
patterns to match.
\->
Conds: The if conditions above encoded as a kind and 32-bit value.
See MCInstPrinter.cpp for the details of how the new data structures are
interpreted.
Here are some before and after metrics.
Time to compile AArch64InstPrinter.cpp:
0m29.062s vs. 0m2.203s
size of the obj:
3.9M vs. 676K
size of clang.exe:
97M vs. 96M
I have not benchmarked disassembly performance, but typically
disassemblers are bottlenecked on IO and string processing, not alias
matching, so I'm not sure it's interesting enough to be worth doing.
Reviewers: RKSimon, andreadb, xbolva00, craig.topper
Reviewed By: craig.topper
Differential Revision: https://reviews.llvm.org/D70650
2019-11-24 03:28:54 +08:00
|
|
|
unsigned getNumMIOps() { return NumMIOps; }
|
|
|
|
|
|
|
|
StringRef getResult() { return Result; }
|
|
|
|
|
2011-03-21 16:40:31 +08:00
|
|
|
bool isOpMapped(StringRef Op) { return OpMap.find(Op) != OpMap.end(); }
|
2014-05-13 02:04:06 +08:00
|
|
|
int getOpIndex(StringRef Op) { return OpMap[Op].first; }
|
|
|
|
std::pair<int, int> &getOpData(StringRef Op) { return OpMap[Op]; }
|
2011-03-21 16:40:31 +08:00
|
|
|
|
2014-05-15 19:16:32 +08:00
|
|
|
std::pair<StringRef, StringRef::iterator> parseName(StringRef::iterator Start,
|
|
|
|
StringRef::iterator End) {
|
|
|
|
StringRef::iterator I = Start;
|
2014-12-17 02:16:17 +08:00
|
|
|
StringRef::iterator Next;
|
2014-05-15 19:16:32 +08:00
|
|
|
if (*I == '{') {
|
|
|
|
// ${some_name}
|
|
|
|
Start = ++I;
|
|
|
|
while (I != End && *I != '}')
|
|
|
|
++I;
|
2014-12-17 02:16:17 +08:00
|
|
|
Next = I;
|
|
|
|
// eat the final '}'
|
|
|
|
if (Next != End)
|
|
|
|
++Next;
|
2014-05-15 19:16:32 +08:00
|
|
|
} else {
|
|
|
|
// $name, just eat the usual suspects.
|
2021-01-23 15:25:03 +08:00
|
|
|
while (I != End && (isAlnum(*I) || *I == '_'))
|
2014-05-15 19:16:32 +08:00
|
|
|
++I;
|
2014-12-17 02:16:17 +08:00
|
|
|
Next = I;
|
2014-05-15 19:16:32 +08:00
|
|
|
}
|
|
|
|
|
2014-12-17 02:16:17 +08:00
|
|
|
return std::make_pair(StringRef(Start, I - Start), Next);
|
2014-05-15 19:16:32 +08:00
|
|
|
}
|
|
|
|
|
[MC] Rewrite tablegen for printInstrAlias to comiple faster, NFC
Before this change, the *InstPrinter.cpp files of each target where some
of the slowest objects to compile in all of LLVM. See this snippet produced by
ClangBuildAnalyzer:
https://reviews.llvm.org/P8171$96
Search for "InstPrinter", and see that it shows up in a few places.
Tablegen was emitting a large switch containing a sequence of operand checks,
each of which created many conditions and many BBs. Register allocation and
jump threading both did not scale well with such a large repetitive sequence of
basic blocks.
So, this change essentially turns those control flow structures into
data. The previous structure looked like:
switch (Opc) {
case TGT::ADD:
// check alias 1
if (MI->getOperandCount() == N && // check num opnds
MI->getOperand(0).isReg() && // check opnd 0
...
MI->getOperand(1).isImm() && // check opnd 1
AsmString = "foo";
break;
}
// check alias 2
if (...)
...
return false;
The new structure looks like:
OpToPatterns: Sorted table of opcodes mapping to pattern indices.
\->
Patterns: List of patterns. Previous table points to subrange of
patterns to match.
\->
Conds: The if conditions above encoded as a kind and 32-bit value.
See MCInstPrinter.cpp for the details of how the new data structures are
interpreted.
Here are some before and after metrics.
Time to compile AArch64InstPrinter.cpp:
0m29.062s vs. 0m2.203s
size of the obj:
3.9M vs. 676K
size of clang.exe:
97M vs. 96M
I have not benchmarked disassembly performance, but typically
disassemblers are bottlenecked on IO and string processing, not alias
matching, so I'm not sure it's interesting enough to be worth doing.
Reviewers: RKSimon, andreadb, xbolva00, craig.topper
Reviewed By: craig.topper
Differential Revision: https://reviews.llvm.org/D70650
2019-11-24 03:28:54 +08:00
|
|
|
std::string formatAliasString(uint32_t &UnescapedSize) {
|
2013-09-11 23:42:16 +08:00
|
|
|
// Directly mangle mapped operands into the string. Each operand is
|
|
|
|
// identified by a '$' sign followed by a byte identifying the number of the
|
|
|
|
// operand. We add one to the index to avoid zero bytes.
|
2014-05-15 19:16:32 +08:00
|
|
|
StringRef ASM(AsmString);
|
[MC] Rewrite tablegen for printInstrAlias to comiple faster, NFC
Before this change, the *InstPrinter.cpp files of each target where some
of the slowest objects to compile in all of LLVM. See this snippet produced by
ClangBuildAnalyzer:
https://reviews.llvm.org/P8171$96
Search for "InstPrinter", and see that it shows up in a few places.
Tablegen was emitting a large switch containing a sequence of operand checks,
each of which created many conditions and many BBs. Register allocation and
jump threading both did not scale well with such a large repetitive sequence of
basic blocks.
So, this change essentially turns those control flow structures into
data. The previous structure looked like:
switch (Opc) {
case TGT::ADD:
// check alias 1
if (MI->getOperandCount() == N && // check num opnds
MI->getOperand(0).isReg() && // check opnd 0
...
MI->getOperand(1).isImm() && // check opnd 1
AsmString = "foo";
break;
}
// check alias 2
if (...)
...
return false;
The new structure looks like:
OpToPatterns: Sorted table of opcodes mapping to pattern indices.
\->
Patterns: List of patterns. Previous table points to subrange of
patterns to match.
\->
Conds: The if conditions above encoded as a kind and 32-bit value.
See MCInstPrinter.cpp for the details of how the new data structures are
interpreted.
Here are some before and after metrics.
Time to compile AArch64InstPrinter.cpp:
0m29.062s vs. 0m2.203s
size of the obj:
3.9M vs. 676K
size of clang.exe:
97M vs. 96M
I have not benchmarked disassembly performance, but typically
disassemblers are bottlenecked on IO and string processing, not alias
matching, so I'm not sure it's interesting enough to be worth doing.
Reviewers: RKSimon, andreadb, xbolva00, craig.topper
Reviewed By: craig.topper
Differential Revision: https://reviews.llvm.org/D70650
2019-11-24 03:28:54 +08:00
|
|
|
std::string OutString;
|
|
|
|
raw_string_ostream OS(OutString);
|
2014-05-15 19:16:32 +08:00
|
|
|
for (StringRef::iterator I = ASM.begin(), E = ASM.end(); I != E;) {
|
|
|
|
OS << *I;
|
[MC] Rewrite tablegen for printInstrAlias to comiple faster, NFC
Before this change, the *InstPrinter.cpp files of each target where some
of the slowest objects to compile in all of LLVM. See this snippet produced by
ClangBuildAnalyzer:
https://reviews.llvm.org/P8171$96
Search for "InstPrinter", and see that it shows up in a few places.
Tablegen was emitting a large switch containing a sequence of operand checks,
each of which created many conditions and many BBs. Register allocation and
jump threading both did not scale well with such a large repetitive sequence of
basic blocks.
So, this change essentially turns those control flow structures into
data. The previous structure looked like:
switch (Opc) {
case TGT::ADD:
// check alias 1
if (MI->getOperandCount() == N && // check num opnds
MI->getOperand(0).isReg() && // check opnd 0
...
MI->getOperand(1).isImm() && // check opnd 1
AsmString = "foo";
break;
}
// check alias 2
if (...)
...
return false;
The new structure looks like:
OpToPatterns: Sorted table of opcodes mapping to pattern indices.
\->
Patterns: List of patterns. Previous table points to subrange of
patterns to match.
\->
Conds: The if conditions above encoded as a kind and 32-bit value.
See MCInstPrinter.cpp for the details of how the new data structures are
interpreted.
Here are some before and after metrics.
Time to compile AArch64InstPrinter.cpp:
0m29.062s vs. 0m2.203s
size of the obj:
3.9M vs. 676K
size of clang.exe:
97M vs. 96M
I have not benchmarked disassembly performance, but typically
disassemblers are bottlenecked on IO and string processing, not alias
matching, so I'm not sure it's interesting enough to be worth doing.
Reviewers: RKSimon, andreadb, xbolva00, craig.topper
Reviewed By: craig.topper
Differential Revision: https://reviews.llvm.org/D70650
2019-11-24 03:28:54 +08:00
|
|
|
++UnescapedSize;
|
2014-05-15 19:16:32 +08:00
|
|
|
if (*I == '$') {
|
|
|
|
StringRef Name;
|
|
|
|
std::tie(Name, I) = parseName(++I, E);
|
|
|
|
assert(isOpMapped(Name) && "Unmapped operand!");
|
|
|
|
|
|
|
|
int OpIndex, PrintIndex;
|
|
|
|
std::tie(OpIndex, PrintIndex) = getOpData(Name);
|
|
|
|
if (PrintIndex == -1) {
|
|
|
|
// Can use the default printOperand route.
|
|
|
|
OS << format("\\x%02X", (unsigned char)OpIndex + 1);
|
[MC] Rewrite tablegen for printInstrAlias to comiple faster, NFC
Before this change, the *InstPrinter.cpp files of each target where some
of the slowest objects to compile in all of LLVM. See this snippet produced by
ClangBuildAnalyzer:
https://reviews.llvm.org/P8171$96
Search for "InstPrinter", and see that it shows up in a few places.
Tablegen was emitting a large switch containing a sequence of operand checks,
each of which created many conditions and many BBs. Register allocation and
jump threading both did not scale well with such a large repetitive sequence of
basic blocks.
So, this change essentially turns those control flow structures into
data. The previous structure looked like:
switch (Opc) {
case TGT::ADD:
// check alias 1
if (MI->getOperandCount() == N && // check num opnds
MI->getOperand(0).isReg() && // check opnd 0
...
MI->getOperand(1).isImm() && // check opnd 1
AsmString = "foo";
break;
}
// check alias 2
if (...)
...
return false;
The new structure looks like:
OpToPatterns: Sorted table of opcodes mapping to pattern indices.
\->
Patterns: List of patterns. Previous table points to subrange of
patterns to match.
\->
Conds: The if conditions above encoded as a kind and 32-bit value.
See MCInstPrinter.cpp for the details of how the new data structures are
interpreted.
Here are some before and after metrics.
Time to compile AArch64InstPrinter.cpp:
0m29.062s vs. 0m2.203s
size of the obj:
3.9M vs. 676K
size of clang.exe:
97M vs. 96M
I have not benchmarked disassembly performance, but typically
disassemblers are bottlenecked on IO and string processing, not alias
matching, so I'm not sure it's interesting enough to be worth doing.
Reviewers: RKSimon, andreadb, xbolva00, craig.topper
Reviewed By: craig.topper
Differential Revision: https://reviews.llvm.org/D70650
2019-11-24 03:28:54 +08:00
|
|
|
++UnescapedSize;
|
|
|
|
} else {
|
2014-05-15 19:16:32 +08:00
|
|
|
// 3 bytes if a PrintMethod is needed: 0xFF, the MCInst operand
|
|
|
|
// number, and which of our pre-detected Methods to call.
|
|
|
|
OS << format("\\xFF\\x%02X\\x%02X", OpIndex + 1, PrintIndex + 1);
|
[MC] Rewrite tablegen for printInstrAlias to comiple faster, NFC
Before this change, the *InstPrinter.cpp files of each target where some
of the slowest objects to compile in all of LLVM. See this snippet produced by
ClangBuildAnalyzer:
https://reviews.llvm.org/P8171$96
Search for "InstPrinter", and see that it shows up in a few places.
Tablegen was emitting a large switch containing a sequence of operand checks,
each of which created many conditions and many BBs. Register allocation and
jump threading both did not scale well with such a large repetitive sequence of
basic blocks.
So, this change essentially turns those control flow structures into
data. The previous structure looked like:
switch (Opc) {
case TGT::ADD:
// check alias 1
if (MI->getOperandCount() == N && // check num opnds
MI->getOperand(0).isReg() && // check opnd 0
...
MI->getOperand(1).isImm() && // check opnd 1
AsmString = "foo";
break;
}
// check alias 2
if (...)
...
return false;
The new structure looks like:
OpToPatterns: Sorted table of opcodes mapping to pattern indices.
\->
Patterns: List of patterns. Previous table points to subrange of
patterns to match.
\->
Conds: The if conditions above encoded as a kind and 32-bit value.
See MCInstPrinter.cpp for the details of how the new data structures are
interpreted.
Here are some before and after metrics.
Time to compile AArch64InstPrinter.cpp:
0m29.062s vs. 0m2.203s
size of the obj:
3.9M vs. 676K
size of clang.exe:
97M vs. 96M
I have not benchmarked disassembly performance, but typically
disassemblers are bottlenecked on IO and string processing, not alias
matching, so I'm not sure it's interesting enough to be worth doing.
Reviewers: RKSimon, andreadb, xbolva00, craig.topper
Reviewed By: craig.topper
Differential Revision: https://reviews.llvm.org/D70650
2019-11-24 03:28:54 +08:00
|
|
|
UnescapedSize += 3;
|
|
|
|
}
|
2014-05-15 19:16:32 +08:00
|
|
|
} else {
|
|
|
|
++I;
|
2013-09-11 23:42:16 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
[MC] Rewrite tablegen for printInstrAlias to comiple faster, NFC
Before this change, the *InstPrinter.cpp files of each target where some
of the slowest objects to compile in all of LLVM. See this snippet produced by
ClangBuildAnalyzer:
https://reviews.llvm.org/P8171$96
Search for "InstPrinter", and see that it shows up in a few places.
Tablegen was emitting a large switch containing a sequence of operand checks,
each of which created many conditions and many BBs. Register allocation and
jump threading both did not scale well with such a large repetitive sequence of
basic blocks.
So, this change essentially turns those control flow structures into
data. The previous structure looked like:
switch (Opc) {
case TGT::ADD:
// check alias 1
if (MI->getOperandCount() == N && // check num opnds
MI->getOperand(0).isReg() && // check opnd 0
...
MI->getOperand(1).isImm() && // check opnd 1
AsmString = "foo";
break;
}
// check alias 2
if (...)
...
return false;
The new structure looks like:
OpToPatterns: Sorted table of opcodes mapping to pattern indices.
\->
Patterns: List of patterns. Previous table points to subrange of
patterns to match.
\->
Conds: The if conditions above encoded as a kind and 32-bit value.
See MCInstPrinter.cpp for the details of how the new data structures are
interpreted.
Here are some before and after metrics.
Time to compile AArch64InstPrinter.cpp:
0m29.062s vs. 0m2.203s
size of the obj:
3.9M vs. 676K
size of clang.exe:
97M vs. 96M
I have not benchmarked disassembly performance, but typically
disassemblers are bottlenecked on IO and string processing, not alias
matching, so I'm not sure it's interesting enough to be worth doing.
Reviewers: RKSimon, andreadb, xbolva00, craig.topper
Reviewed By: craig.topper
Differential Revision: https://reviews.llvm.org/D70650
2019-11-24 03:28:54 +08:00
|
|
|
OS.flush();
|
|
|
|
return OutString;
|
2011-03-21 16:40:31 +08:00
|
|
|
}
|
|
|
|
|
2015-08-07 03:23:33 +08:00
|
|
|
bool operator==(const IAPrinter &RHS) const {
|
[MC] Rewrite tablegen for printInstrAlias to comiple faster, NFC
Before this change, the *InstPrinter.cpp files of each target where some
of the slowest objects to compile in all of LLVM. See this snippet produced by
ClangBuildAnalyzer:
https://reviews.llvm.org/P8171$96
Search for "InstPrinter", and see that it shows up in a few places.
Tablegen was emitting a large switch containing a sequence of operand checks,
each of which created many conditions and many BBs. Register allocation and
jump threading both did not scale well with such a large repetitive sequence of
basic blocks.
So, this change essentially turns those control flow structures into
data. The previous structure looked like:
switch (Opc) {
case TGT::ADD:
// check alias 1
if (MI->getOperandCount() == N && // check num opnds
MI->getOperand(0).isReg() && // check opnd 0
...
MI->getOperand(1).isImm() && // check opnd 1
AsmString = "foo";
break;
}
// check alias 2
if (...)
...
return false;
The new structure looks like:
OpToPatterns: Sorted table of opcodes mapping to pattern indices.
\->
Patterns: List of patterns. Previous table points to subrange of
patterns to match.
\->
Conds: The if conditions above encoded as a kind and 32-bit value.
See MCInstPrinter.cpp for the details of how the new data structures are
interpreted.
Here are some before and after metrics.
Time to compile AArch64InstPrinter.cpp:
0m29.062s vs. 0m2.203s
size of the obj:
3.9M vs. 676K
size of clang.exe:
97M vs. 96M
I have not benchmarked disassembly performance, but typically
disassemblers are bottlenecked on IO and string processing, not alias
matching, so I'm not sure it's interesting enough to be worth doing.
Reviewers: RKSimon, andreadb, xbolva00, craig.topper
Reviewed By: craig.topper
Differential Revision: https://reviews.llvm.org/D70650
2019-11-24 03:28:54 +08:00
|
|
|
if (NumMIOps != RHS.NumMIOps)
|
|
|
|
return false;
|
2011-03-21 16:40:31 +08:00
|
|
|
if (Conds.size() != RHS.Conds.size())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
unsigned Idx = 0;
|
2015-08-07 03:23:33 +08:00
|
|
|
for (const auto &str : Conds)
|
|
|
|
if (str != RHS.Conds[Idx++])
|
2011-03-21 16:40:31 +08:00
|
|
|
return false;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2011-03-21 16:31:53 +08:00
|
|
|
} // end anonymous namespace
|
|
|
|
|
TableGen: fix operand counting for aliases
TableGen has a fairly dubious heuristic to decide whether an alias should be
printed: does the alias have lest operands than the real instruction. This is
bad enough (particularly with no way to override it), but it should at least be
calculated consistently for both strings.
This patch implements that logic: first get the *correct* string for the
variant, in the same way as the Matcher, without guessing; then count the
number of whitespace chars.
There are basically 4 changes this brings about after the previous
commits; all of these appear to be good, so I have changed the tests:
+ ARM64: we print "neg X, Y" instead of "sub X, xzr, Y".
+ ARM64: we skip implicit "uxtx" and "uxtw" modifiers.
+ Sparc: we print "mov A, B" instead of "or %g0, A, B".
+ Sparc: we print "fcmpX A, B" instead of "fcmpX %fcc0, A, B"
llvm-svn: 208969
2014-05-16 17:42:04 +08:00
|
|
|
static unsigned CountNumOperands(StringRef AsmString, unsigned Variant) {
|
|
|
|
return AsmString.count(' ') + AsmString.count('\t');
|
2011-06-15 12:31:19 +08:00
|
|
|
}
|
2011-06-14 11:17:20 +08:00
|
|
|
|
2014-05-20 17:17:16 +08:00
|
|
|
namespace {
|
2016-12-01 01:48:10 +08:00
|
|
|
|
2014-05-20 17:17:16 +08:00
|
|
|
struct AliasPriorityComparator {
|
2015-08-07 03:23:33 +08:00
|
|
|
typedef std::pair<CodeGenInstAlias, int> ValueType;
|
2016-12-28 07:15:58 +08:00
|
|
|
bool operator()(const ValueType &LHS, const ValueType &RHS) const {
|
2014-05-20 17:17:16 +08:00
|
|
|
if (LHS.second == RHS.second) {
|
|
|
|
// We don't actually care about the order, but for consistency it
|
|
|
|
// shouldn't depend on pointer comparisons.
|
[TableGen][AsmWriterEmitter] Use a deterministic order to sort InstrAliases
Inside an alias group, when ordering instruction aliases, we rely
on the priority field to sort them.
When the priority is not set or more generally when there is a tie between
two aliases, we used to rely on the lexicographic order. However, this
order can change for the anonymous records when more instruction, intrinsic,
etc. are inserted.
For instance, given two anonymous records r1 and r2 with respective name
A_999 and A_1000, their lexicography order will be r2 then r1. Now, if
an instruction is added before them, their name will become respectively
A_1000 and A_1001, thus the lexicography order will be r1 then r2, i.e.,
it changed.
If that happens in an alias group, the assembly output would prefer a
different alias for no apparent good reasons.
A way to fix that is to use proper priority for all aliases, but we
can also make the tie breaker comparison smarter and use a deterministic
ordering. This is what this patch does.
llvm-svn: 294695
2017-02-10 10:43:09 +08:00
|
|
|
return LessRecordByID()(LHS.first.TheDef, RHS.first.TheDef);
|
2014-05-20 17:17:16 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Aliases with larger priorities should be considered first.
|
|
|
|
return LHS.second > RHS.second;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2016-12-01 01:48:10 +08:00
|
|
|
} // end anonymous namespace
|
2014-05-20 17:17:16 +08:00
|
|
|
|
2011-03-21 16:31:53 +08:00
|
|
|
void AsmWriterEmitter::EmitPrintAliasInstruction(raw_ostream &O) {
|
|
|
|
Record *AsmWriter = Target.getAsmWriter();
|
|
|
|
|
|
|
|
O << "\n#ifdef PRINT_ALIAS_INSTR\n";
|
|
|
|
O << "#undef PRINT_ALIAS_INSTR\n\n";
|
|
|
|
|
2014-05-13 02:04:06 +08:00
|
|
|
//////////////////////////////
|
|
|
|
// Gather information about aliases we need to print
|
|
|
|
//////////////////////////////
|
|
|
|
|
2011-02-26 11:09:12 +08:00
|
|
|
// Emit the method that prints the alias instruction.
|
2017-06-01 05:12:46 +08:00
|
|
|
StringRef ClassName = AsmWriter->getValueAsString("AsmWriterClassName");
|
2014-05-20 17:17:16 +08:00
|
|
|
unsigned Variant = AsmWriter->getValueAsInt("Variant");
|
2016-01-14 14:15:07 +08:00
|
|
|
bool PassSubtarget = AsmWriter->getValueAsInt("PassSubtarget");
|
2010-02-12 06:57:32 +08:00
|
|
|
|
2011-02-26 11:09:12 +08:00
|
|
|
std::vector<Record*> AllInstAliases =
|
|
|
|
Records.getAllDerivedDefinitions("InstAlias");
|
|
|
|
|
|
|
|
// Create a map from the qualified name to a list of potential matches.
|
2015-08-07 03:23:33 +08:00
|
|
|
typedef std::set<std::pair<CodeGenInstAlias, int>, AliasPriorityComparator>
|
2014-05-20 17:17:16 +08:00
|
|
|
AliasWithPriority;
|
|
|
|
std::map<std::string, AliasWithPriority> AliasMap;
|
2016-01-08 15:06:32 +08:00
|
|
|
for (Record *R : AllInstAliases) {
|
2014-05-20 17:17:16 +08:00
|
|
|
int Priority = R->getValueAsInt("EmitPriority");
|
|
|
|
if (Priority < 1)
|
|
|
|
continue; // Aliases with priority 0 are never emitted.
|
|
|
|
|
2011-02-26 11:09:12 +08:00
|
|
|
const DagInit *DI = R->getValueAsDag("ResultInst");
|
[tblgen] Add getOperatorAsDef() to Record
Summary:
While working with DagInit's, it's often the case that you expect the
operator to be a reference to a def. This patch adds a wrapper for this
common case to reduce the amount of boilerplate callers need to duplicate
repeatedly.
getOperatorAsDef() returns the record if the DagInit has an operator that is
a DefInit. Otherwise, it prints a fatal error.
There's only a few pre-existing examples in LLVM at the moment and I've
left a few instances of the code this simplifies as they had more specific
error messages than the generic one this produces. I'm going to be using
this a fair bit in my subsequent patches.
Reviewers: bogner, volkan, nhaehnle
Reviewed By: nhaehnle
Subscribers: nhaehnle, hiraditya, asb, rbar, johnrusso, simoncook, apazos, sabuasal, niosHD, jrtc27, MaskRay, zzheng, edward-jones, rogfer01, MartinMosbeck, brucehoult, the_o, PkmX, jocewei, lenary, s.egerton, pzheng, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D68424
llvm-svn: 374101
2019-10-09 02:41:32 +08:00
|
|
|
AliasMap[getQualifiedName(DI->getOperatorAsDef(R->getLoc()))].insert(
|
2018-06-18 09:28:01 +08:00
|
|
|
std::make_pair(CodeGenInstAlias(R, Target), Priority));
|
2011-02-26 11:09:12 +08:00
|
|
|
}
|
|
|
|
|
2011-03-21 16:59:17 +08:00
|
|
|
// A map of which conditions need to be met for each instruction operand
|
|
|
|
// before it can be matched to the mnemonic.
|
2015-08-07 03:23:33 +08:00
|
|
|
std::map<std::string, std::vector<IAPrinter>> IAPrinterMap;
|
2011-03-21 16:59:17 +08:00
|
|
|
|
2020-03-27 15:17:56 +08:00
|
|
|
std::vector<std::pair<std::string, bool>> PrintMethods;
|
2016-01-22 13:59:43 +08:00
|
|
|
|
2014-06-10 21:11:35 +08:00
|
|
|
// A list of MCOperandPredicates for all operands in use, and the reverse map
|
|
|
|
std::vector<const Record*> MCOpPredicates;
|
|
|
|
DenseMap<const Record*, unsigned> MCOpPredicateMap;
|
|
|
|
|
2014-05-20 17:17:16 +08:00
|
|
|
for (auto &Aliases : AliasMap) {
|
[MC] Rewrite tablegen for printInstrAlias to comiple faster, NFC
Before this change, the *InstPrinter.cpp files of each target where some
of the slowest objects to compile in all of LLVM. See this snippet produced by
ClangBuildAnalyzer:
https://reviews.llvm.org/P8171$96
Search for "InstPrinter", and see that it shows up in a few places.
Tablegen was emitting a large switch containing a sequence of operand checks,
each of which created many conditions and many BBs. Register allocation and
jump threading both did not scale well with such a large repetitive sequence of
basic blocks.
So, this change essentially turns those control flow structures into
data. The previous structure looked like:
switch (Opc) {
case TGT::ADD:
// check alias 1
if (MI->getOperandCount() == N && // check num opnds
MI->getOperand(0).isReg() && // check opnd 0
...
MI->getOperand(1).isImm() && // check opnd 1
AsmString = "foo";
break;
}
// check alias 2
if (...)
...
return false;
The new structure looks like:
OpToPatterns: Sorted table of opcodes mapping to pattern indices.
\->
Patterns: List of patterns. Previous table points to subrange of
patterns to match.
\->
Conds: The if conditions above encoded as a kind and 32-bit value.
See MCInstPrinter.cpp for the details of how the new data structures are
interpreted.
Here are some before and after metrics.
Time to compile AArch64InstPrinter.cpp:
0m29.062s vs. 0m2.203s
size of the obj:
3.9M vs. 676K
size of clang.exe:
97M vs. 96M
I have not benchmarked disassembly performance, but typically
disassemblers are bottlenecked on IO and string processing, not alias
matching, so I'm not sure it's interesting enough to be worth doing.
Reviewers: RKSimon, andreadb, xbolva00, craig.topper
Reviewed By: craig.topper
Differential Revision: https://reviews.llvm.org/D70650
2019-11-24 03:28:54 +08:00
|
|
|
// Collection of instruction alias rules. May contain ambiguous rules.
|
|
|
|
std::vector<IAPrinter> IAPs;
|
|
|
|
|
2014-05-20 17:17:16 +08:00
|
|
|
for (auto &Alias : Aliases.second) {
|
2015-08-07 03:23:33 +08:00
|
|
|
const CodeGenInstAlias &CGA = Alias.first;
|
|
|
|
unsigned LastOpNo = CGA.ResultInstOperandIndex.size();
|
2018-06-18 09:28:01 +08:00
|
|
|
std::string FlatInstAsmString =
|
|
|
|
CodeGenInstruction::FlattenAsmStringVariants(CGA.ResultInst->AsmString,
|
|
|
|
Variant);
|
|
|
|
unsigned NumResultOps = CountNumOperands(FlatInstAsmString, Variant);
|
|
|
|
|
|
|
|
std::string FlatAliasAsmString =
|
[MC] Rewrite tablegen for printInstrAlias to comiple faster, NFC
Before this change, the *InstPrinter.cpp files of each target where some
of the slowest objects to compile in all of LLVM. See this snippet produced by
ClangBuildAnalyzer:
https://reviews.llvm.org/P8171$96
Search for "InstPrinter", and see that it shows up in a few places.
Tablegen was emitting a large switch containing a sequence of operand checks,
each of which created many conditions and many BBs. Register allocation and
jump threading both did not scale well with such a large repetitive sequence of
basic blocks.
So, this change essentially turns those control flow structures into
data. The previous structure looked like:
switch (Opc) {
case TGT::ADD:
// check alias 1
if (MI->getOperandCount() == N && // check num opnds
MI->getOperand(0).isReg() && // check opnd 0
...
MI->getOperand(1).isImm() && // check opnd 1
AsmString = "foo";
break;
}
// check alias 2
if (...)
...
return false;
The new structure looks like:
OpToPatterns: Sorted table of opcodes mapping to pattern indices.
\->
Patterns: List of patterns. Previous table points to subrange of
patterns to match.
\->
Conds: The if conditions above encoded as a kind and 32-bit value.
See MCInstPrinter.cpp for the details of how the new data structures are
interpreted.
Here are some before and after metrics.
Time to compile AArch64InstPrinter.cpp:
0m29.062s vs. 0m2.203s
size of the obj:
3.9M vs. 676K
size of clang.exe:
97M vs. 96M
I have not benchmarked disassembly performance, but typically
disassemblers are bottlenecked on IO and string processing, not alias
matching, so I'm not sure it's interesting enough to be worth doing.
Reviewers: RKSimon, andreadb, xbolva00, craig.topper
Reviewed By: craig.topper
Differential Revision: https://reviews.llvm.org/D70650
2019-11-24 03:28:54 +08:00
|
|
|
CodeGenInstruction::FlattenAsmStringVariants(CGA.AsmString, Variant);
|
2020-05-28 17:00:51 +08:00
|
|
|
UnescapeAliasString(FlatAliasAsmString);
|
2011-06-14 11:17:20 +08:00
|
|
|
|
|
|
|
// Don't emit the alias if it has more operands than what it's aliasing.
|
2018-06-18 09:28:01 +08:00
|
|
|
if (NumResultOps < CountNumOperands(FlatAliasAsmString, Variant))
|
2011-06-14 11:17:20 +08:00
|
|
|
continue;
|
|
|
|
|
2017-06-01 05:12:46 +08:00
|
|
|
StringRef Namespace = Target.getName();
|
2014-05-15 21:36:01 +08:00
|
|
|
unsigned NumMIOps = 0;
|
[AArch64][TableGen] Skip tied result operands for InstAlias
Summary:
This patch fixes an issue so that the right alias is printed when the instruction has tied operands. It checks the number of operands in the resulting instruction as opposed to the alias, and then skips over tied operands that should not be printed in the alias.
This allows to generate the preferred assembly syntax for the AArch64 'ins' instruction, which should always be displayed as 'mov' according to the ARM Architecture Reference Manual. Several unit tests have changed as a result, but only to reflect the preferred disassembly. Some other InstAlias patterns (movk/bic/orr) needed a slight adjustment to stop them becoming the default and breaking other unit tests.
Please note that the patch is mostly the same as https://reviews.llvm.org/D29219 which was reverted because of an issue found when running TableGen with the Address Sanitizer. That issue has been addressed in this iteration of the patch.
Reviewers: rengolin, stoklund, huntergr, SjoerdMeijer, rovka
Reviewed By: rengolin, SjoerdMeijer
Subscribers: fhahn, aemerson, javed.absar, kristof.beyls, llvm-commits
Differential Revision: https://reviews.llvm.org/D40030
llvm-svn: 318650
2017-11-20 22:36:40 +08:00
|
|
|
for (auto &ResultInstOpnd : CGA.ResultInst->Operands)
|
|
|
|
NumMIOps += ResultInstOpnd.MINumOperands;
|
2014-05-15 21:36:01 +08:00
|
|
|
|
[MC] Rewrite tablegen for printInstrAlias to comiple faster, NFC
Before this change, the *InstPrinter.cpp files of each target where some
of the slowest objects to compile in all of LLVM. See this snippet produced by
ClangBuildAnalyzer:
https://reviews.llvm.org/P8171$96
Search for "InstPrinter", and see that it shows up in a few places.
Tablegen was emitting a large switch containing a sequence of operand checks,
each of which created many conditions and many BBs. Register allocation and
jump threading both did not scale well with such a large repetitive sequence of
basic blocks.
So, this change essentially turns those control flow structures into
data. The previous structure looked like:
switch (Opc) {
case TGT::ADD:
// check alias 1
if (MI->getOperandCount() == N && // check num opnds
MI->getOperand(0).isReg() && // check opnd 0
...
MI->getOperand(1).isImm() && // check opnd 1
AsmString = "foo";
break;
}
// check alias 2
if (...)
...
return false;
The new structure looks like:
OpToPatterns: Sorted table of opcodes mapping to pattern indices.
\->
Patterns: List of patterns. Previous table points to subrange of
patterns to match.
\->
Conds: The if conditions above encoded as a kind and 32-bit value.
See MCInstPrinter.cpp for the details of how the new data structures are
interpreted.
Here are some before and after metrics.
Time to compile AArch64InstPrinter.cpp:
0m29.062s vs. 0m2.203s
size of the obj:
3.9M vs. 676K
size of clang.exe:
97M vs. 96M
I have not benchmarked disassembly performance, but typically
disassemblers are bottlenecked on IO and string processing, not alias
matching, so I'm not sure it's interesting enough to be worth doing.
Reviewers: RKSimon, andreadb, xbolva00, craig.topper
Reviewed By: craig.topper
Differential Revision: https://reviews.llvm.org/D70650
2019-11-24 03:28:54 +08:00
|
|
|
IAPrinter IAP(CGA.Result->getAsString(), FlatAliasAsmString, NumMIOps);
|
2011-03-21 16:59:17 +08:00
|
|
|
|
|
|
|
bool CantHandle = false;
|
|
|
|
|
2014-05-15 21:36:01 +08:00
|
|
|
unsigned MIOpNum = 0;
|
2011-03-21 16:59:17 +08:00
|
|
|
for (unsigned i = 0, e = LastOpNo; i != e; ++i) {
|
[AArch64][TableGen] Skip tied result operands for InstAlias
Summary:
This patch fixes an issue so that the right alias is printed when the instruction has tied operands. It checks the number of operands in the resulting instruction as opposed to the alias, and then skips over tied operands that should not be printed in the alias.
This allows to generate the preferred assembly syntax for the AArch64 'ins' instruction, which should always be displayed as 'mov' according to the ARM Architecture Reference Manual. Several unit tests have changed as a result, but only to reflect the preferred disassembly. Some other InstAlias patterns (movk/bic/orr) needed a slight adjustment to stop them becoming the default and breaking other unit tests.
Please note that the patch is mostly the same as https://reviews.llvm.org/D29219 which was reverted because of an issue found when running TableGen with the Address Sanitizer. That issue has been addressed in this iteration of the patch.
Reviewers: rengolin, stoklund, huntergr, SjoerdMeijer, rovka
Reviewed By: rengolin, SjoerdMeijer
Subscribers: fhahn, aemerson, javed.absar, kristof.beyls, llvm-commits
Differential Revision: https://reviews.llvm.org/D40030
llvm-svn: 318650
2017-11-20 22:36:40 +08:00
|
|
|
// Skip over tied operands as they're not part of an alias declaration.
|
|
|
|
auto &Operands = CGA.ResultInst->Operands;
|
[TableGen:AsmWriter] Cope with consecutive tied operands.
When you define an instruction alias as a subclass of InstAlias, you
specify all the MC operands for the instruction it expands to, except
for operands that are tied to a previous one, which you leave out in
the expectation that the Tablegen output code will fill them in
automatically.
But the code in Tablegen's AsmWriter backend that skips over a tied
operand was doing it using 'if' instead of 'while', because it wasn't
expecting to find two tied operands in sequence.
So if an instruction updates a pair of registers in place, so that its
MC representation has two input operands tied to the output ones (for
example, Arm's UMLAL instruction), then any alias which wants to
expand to a special case of that instruction is likely to fail to
match, because the indices of subsequent operands will be off by one
in the generated printAliasInstr function.
This patch re-indents some existing code, so it's clearest when
viewed as a diff with whitespace changes ignored.
Reviewers: fhahn, rengolin, sdesmalen, atanasyan, asb, jholewinski, t.p.northover, kparzysz, craig.topper, stoklund
Reviewed By: rengolin
Subscribers: javed.absar, kristof.beyls, llvm-commits
Differential Revision: https://reviews.llvm.org/D53816
llvm-svn: 349141
2018-12-14 19:39:55 +08:00
|
|
|
while (true) {
|
|
|
|
unsigned OpNum = Operands.getSubOperandNumber(MIOpNum).first;
|
|
|
|
if (Operands[OpNum].MINumOperands == 1 &&
|
|
|
|
Operands[OpNum].getTiedRegister() != -1) {
|
|
|
|
// Tied operands of different RegisterClass should be explicit within
|
|
|
|
// an instruction's syntax and so cannot be skipped.
|
|
|
|
int TiedOpNum = Operands[OpNum].getTiedRegister();
|
|
|
|
if (Operands[OpNum].Rec->getName() ==
|
|
|
|
Operands[TiedOpNum].Rec->getName()) {
|
|
|
|
++MIOpNum;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
[AArch64][TableGen] Skip tied result operands for InstAlias
Summary:
This patch fixes an issue so that the right alias is printed when the instruction has tied operands. It checks the number of operands in the resulting instruction as opposed to the alias, and then skips over tied operands that should not be printed in the alias.
This allows to generate the preferred assembly syntax for the AArch64 'ins' instruction, which should always be displayed as 'mov' according to the ARM Architecture Reference Manual. Several unit tests have changed as a result, but only to reflect the preferred disassembly. Some other InstAlias patterns (movk/bic/orr) needed a slight adjustment to stop them becoming the default and breaking other unit tests.
Please note that the patch is mostly the same as https://reviews.llvm.org/D29219 which was reverted because of an issue found when running TableGen with the Address Sanitizer. That issue has been addressed in this iteration of the patch.
Reviewers: rengolin, stoklund, huntergr, SjoerdMeijer, rovka
Reviewed By: rengolin, SjoerdMeijer
Subscribers: fhahn, aemerson, javed.absar, kristof.beyls, llvm-commits
Differential Revision: https://reviews.llvm.org/D40030
llvm-svn: 318650
2017-11-20 22:36:40 +08:00
|
|
|
}
|
|
|
|
|
[MC] Rewrite tablegen for printInstrAlias to comiple faster, NFC
Before this change, the *InstPrinter.cpp files of each target where some
of the slowest objects to compile in all of LLVM. See this snippet produced by
ClangBuildAnalyzer:
https://reviews.llvm.org/P8171$96
Search for "InstPrinter", and see that it shows up in a few places.
Tablegen was emitting a large switch containing a sequence of operand checks,
each of which created many conditions and many BBs. Register allocation and
jump threading both did not scale well with such a large repetitive sequence of
basic blocks.
So, this change essentially turns those control flow structures into
data. The previous structure looked like:
switch (Opc) {
case TGT::ADD:
// check alias 1
if (MI->getOperandCount() == N && // check num opnds
MI->getOperand(0).isReg() && // check opnd 0
...
MI->getOperand(1).isImm() && // check opnd 1
AsmString = "foo";
break;
}
// check alias 2
if (...)
...
return false;
The new structure looks like:
OpToPatterns: Sorted table of opcodes mapping to pattern indices.
\->
Patterns: List of patterns. Previous table points to subrange of
patterns to match.
\->
Conds: The if conditions above encoded as a kind and 32-bit value.
See MCInstPrinter.cpp for the details of how the new data structures are
interpreted.
Here are some before and after metrics.
Time to compile AArch64InstPrinter.cpp:
0m29.062s vs. 0m2.203s
size of the obj:
3.9M vs. 676K
size of clang.exe:
97M vs. 96M
I have not benchmarked disassembly performance, but typically
disassemblers are bottlenecked on IO and string processing, not alias
matching, so I'm not sure it's interesting enough to be worth doing.
Reviewers: RKSimon, andreadb, xbolva00, craig.topper
Reviewed By: craig.topper
Differential Revision: https://reviews.llvm.org/D70650
2019-11-24 03:28:54 +08:00
|
|
|
// Ignore unchecked result operands.
|
|
|
|
while (IAP.getCondCount() < MIOpNum)
|
|
|
|
IAP.addCond("AliasPatternCond::K_Ignore, 0");
|
2014-06-10 20:47:23 +08:00
|
|
|
|
2015-08-07 03:23:33 +08:00
|
|
|
const CodeGenInstAlias::ResultOperand &RO = CGA.ResultOperands[i];
|
2011-03-21 16:59:17 +08:00
|
|
|
|
|
|
|
switch (RO.Kind) {
|
|
|
|
case CodeGenInstAlias::ResultOperand::K_Record: {
|
|
|
|
const Record *Rec = RO.getRecord();
|
|
|
|
StringRef ROName = RO.getName();
|
2014-05-13 02:04:06 +08:00
|
|
|
int PrintMethodIdx = -1;
|
|
|
|
|
|
|
|
// These two may have a PrintMethod, which we want to record (if it's
|
|
|
|
// the first time we've seen it) and provide an index for the aliasing
|
|
|
|
// code to use.
|
|
|
|
if (Rec->isSubClassOf("RegisterOperand") ||
|
|
|
|
Rec->isSubClassOf("Operand")) {
|
2017-06-01 05:12:46 +08:00
|
|
|
StringRef PrintMethod = Rec->getValueAsString("PrintMethod");
|
2020-03-27 15:17:56 +08:00
|
|
|
bool IsPCRel =
|
|
|
|
Rec->getValueAsString("OperandType") == "OPERAND_PCREL";
|
2014-05-13 02:04:06 +08:00
|
|
|
if (PrintMethod != "" && PrintMethod != "printOperand") {
|
2020-03-27 15:17:56 +08:00
|
|
|
PrintMethodIdx = llvm::find_if(PrintMethods,
|
|
|
|
[&](auto &X) {
|
|
|
|
return X.first == PrintMethod;
|
|
|
|
}) -
|
|
|
|
PrintMethods.begin();
|
2014-05-13 02:04:06 +08:00
|
|
|
if (static_cast<unsigned>(PrintMethodIdx) == PrintMethods.size())
|
2020-03-27 15:17:56 +08:00
|
|
|
PrintMethods.emplace_back(std::string(PrintMethod), IsPCRel);
|
2014-05-13 02:04:06 +08:00
|
|
|
}
|
|
|
|
}
|
2011-06-28 05:06:21 +08:00
|
|
|
|
|
|
|
if (Rec->isSubClassOf("RegisterOperand"))
|
|
|
|
Rec = Rec->getValueAsDef("RegClass");
|
2011-03-21 16:59:17 +08:00
|
|
|
if (Rec->isSubClassOf("RegisterClass")) {
|
2015-08-07 03:23:33 +08:00
|
|
|
if (!IAP.isOpMapped(ROName)) {
|
|
|
|
IAP.addOperand(ROName, MIOpNum, PrintMethodIdx);
|
|
|
|
Record *R = CGA.ResultOperands[i].getRecord();
|
2013-02-05 16:32:10 +08:00
|
|
|
if (R->isSubClassOf("RegisterOperand"))
|
|
|
|
R = R->getValueAsDef("RegClass");
|
2020-01-29 03:23:46 +08:00
|
|
|
IAP.addCond(std::string(
|
|
|
|
formatv("AliasPatternCond::K_RegClass, {0}::{1}RegClassID",
|
|
|
|
Namespace, R->getName())));
|
2011-03-21 16:59:17 +08:00
|
|
|
} else {
|
2020-01-29 03:23:46 +08:00
|
|
|
IAP.addCond(std::string(formatv(
|
|
|
|
"AliasPatternCond::K_TiedReg, {0}", IAP.getOpIndex(ROName))));
|
2011-03-21 16:59:17 +08:00
|
|
|
}
|
|
|
|
} else {
|
2014-05-13 02:04:06 +08:00
|
|
|
// Assume all printable operands are desired for now. This can be
|
2014-05-15 09:52:21 +08:00
|
|
|
// overridden in the InstAlias instantiation if necessary.
|
2015-08-07 03:23:33 +08:00
|
|
|
IAP.addOperand(ROName, MIOpNum, PrintMethodIdx);
|
2011-03-21 16:59:17 +08:00
|
|
|
|
2014-06-10 21:11:35 +08:00
|
|
|
// There might be an additional predicate on the MCOperand
|
|
|
|
unsigned Entry = MCOpPredicateMap[Rec];
|
|
|
|
if (!Entry) {
|
|
|
|
if (!Rec->isValueUnset("MCOperandPredicate")) {
|
|
|
|
MCOpPredicates.push_back(Rec);
|
|
|
|
Entry = MCOpPredicates.size();
|
|
|
|
MCOpPredicateMap[Rec] = Entry;
|
|
|
|
} else
|
|
|
|
break; // No conditions on this operand at all
|
|
|
|
}
|
2020-01-29 03:23:46 +08:00
|
|
|
IAP.addCond(
|
|
|
|
std::string(formatv("AliasPatternCond::K_Custom, {0}", Entry)));
|
2014-06-10 21:11:35 +08:00
|
|
|
}
|
2011-03-21 16:59:17 +08:00
|
|
|
break;
|
|
|
|
}
|
2013-01-09 21:32:04 +08:00
|
|
|
case CodeGenInstAlias::ResultOperand::K_Imm: {
|
|
|
|
// Just because the alias has an immediate result, doesn't mean the
|
|
|
|
// MCInst will. An MCExpr could be present, for example.
|
[MC] Rewrite tablegen for printInstrAlias to comiple faster, NFC
Before this change, the *InstPrinter.cpp files of each target where some
of the slowest objects to compile in all of LLVM. See this snippet produced by
ClangBuildAnalyzer:
https://reviews.llvm.org/P8171$96
Search for "InstPrinter", and see that it shows up in a few places.
Tablegen was emitting a large switch containing a sequence of operand checks,
each of which created many conditions and many BBs. Register allocation and
jump threading both did not scale well with such a large repetitive sequence of
basic blocks.
So, this change essentially turns those control flow structures into
data. The previous structure looked like:
switch (Opc) {
case TGT::ADD:
// check alias 1
if (MI->getOperandCount() == N && // check num opnds
MI->getOperand(0).isReg() && // check opnd 0
...
MI->getOperand(1).isImm() && // check opnd 1
AsmString = "foo";
break;
}
// check alias 2
if (...)
...
return false;
The new structure looks like:
OpToPatterns: Sorted table of opcodes mapping to pattern indices.
\->
Patterns: List of patterns. Previous table points to subrange of
patterns to match.
\->
Conds: The if conditions above encoded as a kind and 32-bit value.
See MCInstPrinter.cpp for the details of how the new data structures are
interpreted.
Here are some before and after metrics.
Time to compile AArch64InstPrinter.cpp:
0m29.062s vs. 0m2.203s
size of the obj:
3.9M vs. 676K
size of clang.exe:
97M vs. 96M
I have not benchmarked disassembly performance, but typically
disassemblers are bottlenecked on IO and string processing, not alias
matching, so I'm not sure it's interesting enough to be worth doing.
Reviewers: RKSimon, andreadb, xbolva00, craig.topper
Reviewed By: craig.topper
Differential Revision: https://reviews.llvm.org/D70650
2019-11-24 03:28:54 +08:00
|
|
|
auto Imm = CGA.ResultOperands[i].getImm();
|
|
|
|
int32_t Imm32 = int32_t(Imm);
|
|
|
|
if (Imm != Imm32)
|
|
|
|
PrintFatalError("Matching an alias with an immediate out of the "
|
|
|
|
"range of int32_t is not supported");
|
2020-01-29 03:23:46 +08:00
|
|
|
IAP.addCond(std::string(
|
|
|
|
formatv("AliasPatternCond::K_Imm, uint32_t({0})", Imm32)));
|
2011-03-21 16:59:17 +08:00
|
|
|
break;
|
2013-01-09 21:32:04 +08:00
|
|
|
}
|
2011-03-21 16:59:17 +08:00
|
|
|
case CodeGenInstAlias::ResultOperand::K_Reg:
|
2011-11-15 09:46:57 +08:00
|
|
|
// If this is zero_reg, something's playing tricks we're not
|
|
|
|
// equipped to handle.
|
2015-08-07 03:23:33 +08:00
|
|
|
if (!CGA.ResultOperands[i].getRegister()) {
|
2011-11-15 09:46:57 +08:00
|
|
|
CantHandle = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
[MC] Rewrite tablegen for printInstrAlias to comiple faster, NFC
Before this change, the *InstPrinter.cpp files of each target where some
of the slowest objects to compile in all of LLVM. See this snippet produced by
ClangBuildAnalyzer:
https://reviews.llvm.org/P8171$96
Search for "InstPrinter", and see that it shows up in a few places.
Tablegen was emitting a large switch containing a sequence of operand checks,
each of which created many conditions and many BBs. Register allocation and
jump threading both did not scale well with such a large repetitive sequence of
basic blocks.
So, this change essentially turns those control flow structures into
data. The previous structure looked like:
switch (Opc) {
case TGT::ADD:
// check alias 1
if (MI->getOperandCount() == N && // check num opnds
MI->getOperand(0).isReg() && // check opnd 0
...
MI->getOperand(1).isImm() && // check opnd 1
AsmString = "foo";
break;
}
// check alias 2
if (...)
...
return false;
The new structure looks like:
OpToPatterns: Sorted table of opcodes mapping to pattern indices.
\->
Patterns: List of patterns. Previous table points to subrange of
patterns to match.
\->
Conds: The if conditions above encoded as a kind and 32-bit value.
See MCInstPrinter.cpp for the details of how the new data structures are
interpreted.
Here are some before and after metrics.
Time to compile AArch64InstPrinter.cpp:
0m29.062s vs. 0m2.203s
size of the obj:
3.9M vs. 676K
size of clang.exe:
97M vs. 96M
I have not benchmarked disassembly performance, but typically
disassemblers are bottlenecked on IO and string processing, not alias
matching, so I'm not sure it's interesting enough to be worth doing.
Reviewers: RKSimon, andreadb, xbolva00, craig.topper
Reviewed By: craig.topper
Differential Revision: https://reviews.llvm.org/D70650
2019-11-24 03:28:54 +08:00
|
|
|
StringRef Reg = CGA.ResultOperands[i].getRegister()->getName();
|
2020-01-29 03:23:46 +08:00
|
|
|
IAP.addCond(std::string(
|
|
|
|
formatv("AliasPatternCond::K_Reg, {0}::{1}", Namespace, Reg)));
|
2011-03-21 16:59:17 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2014-05-15 21:36:01 +08:00
|
|
|
MIOpNum += RO.getMINumOperands();
|
2011-03-21 16:59:17 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (CantHandle) continue;
|
2016-06-03 21:14:19 +08:00
|
|
|
|
[MC] Rewrite tablegen for printInstrAlias to comiple faster, NFC
Before this change, the *InstPrinter.cpp files of each target where some
of the slowest objects to compile in all of LLVM. See this snippet produced by
ClangBuildAnalyzer:
https://reviews.llvm.org/P8171$96
Search for "InstPrinter", and see that it shows up in a few places.
Tablegen was emitting a large switch containing a sequence of operand checks,
each of which created many conditions and many BBs. Register allocation and
jump threading both did not scale well with such a large repetitive sequence of
basic blocks.
So, this change essentially turns those control flow structures into
data. The previous structure looked like:
switch (Opc) {
case TGT::ADD:
// check alias 1
if (MI->getOperandCount() == N && // check num opnds
MI->getOperand(0).isReg() && // check opnd 0
...
MI->getOperand(1).isImm() && // check opnd 1
AsmString = "foo";
break;
}
// check alias 2
if (...)
...
return false;
The new structure looks like:
OpToPatterns: Sorted table of opcodes mapping to pattern indices.
\->
Patterns: List of patterns. Previous table points to subrange of
patterns to match.
\->
Conds: The if conditions above encoded as a kind and 32-bit value.
See MCInstPrinter.cpp for the details of how the new data structures are
interpreted.
Here are some before and after metrics.
Time to compile AArch64InstPrinter.cpp:
0m29.062s vs. 0m2.203s
size of the obj:
3.9M vs. 676K
size of clang.exe:
97M vs. 96M
I have not benchmarked disassembly performance, but typically
disassemblers are bottlenecked on IO and string processing, not alias
matching, so I'm not sure it's interesting enough to be worth doing.
Reviewers: RKSimon, andreadb, xbolva00, craig.topper
Reviewed By: craig.topper
Differential Revision: https://reviews.llvm.org/D70650
2019-11-24 03:28:54 +08:00
|
|
|
std::vector<Record *> ReqFeatures;
|
|
|
|
if (PassSubtarget) {
|
|
|
|
// We only consider ReqFeatures predicates if PassSubtarget
|
|
|
|
std::vector<Record *> RF =
|
|
|
|
CGA.TheDef->getValueAsListOfDefs("Predicates");
|
|
|
|
copy_if(RF, std::back_inserter(ReqFeatures), [](Record *R) {
|
|
|
|
return R->getValueAsBit("AssemblerMatcherPredicate");
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2016-06-03 21:14:19 +08:00
|
|
|
for (auto I = ReqFeatures.cbegin(); I != ReqFeatures.cend(); I++) {
|
|
|
|
Record *R = *I;
|
[TableGen] Support combining AssemblerPredicates with ORs
For context, the proposed RISC-V bit manipulation extension has a subset
of instructions which require one of two SubtargetFeatures to be
enabled, 'zbb' or 'zbp', and there is no defined feature which both of
these can imply to use as a constraint either (see comments in D65649).
AssemblerPredicates allow multiple SubtargetFeatures to be declared in
the "AssemblerCondString" field, separated by commas, and this means
that the two features must both be enabled. There is no equivalent to
say that _either_ feature X or feature Y must be enabled, short of
creating a dummy SubtargetFeature for this purpose and having features X
and Y imply the new feature.
To solve the case where X or Y is needed without adding a new feature,
and to better match a typical TableGen style, this replaces the existing
"AssemblerCondString" with a dag "AssemblerCondDag" which represents the
same information. Two operators are defined for use with
AssemblerCondDag, "all_of", which matches the current behaviour, and
"any_of", which adds the new proposed ORing features functionality.
This was originally proposed in the RFC at
http://lists.llvm.org/pipermail/llvm-dev/2020-February/139138.html
Changes to all current backends are mechanical to support the replaced
functionality, and are NFCI.
At this stage, it is illegal to combine features with ands and ors in a
single AssemblerCondDag. I suspect this case is sufficiently rare that
adding more complex changes to support it are unnecessary.
Differential Revision: https://reviews.llvm.org/D74338
2020-03-14 01:13:51 +08:00
|
|
|
const DagInit *D = R->getValueAsDag("AssemblerCondDag");
|
|
|
|
std::string CombineType = D->getOperator()->getAsString();
|
|
|
|
if (CombineType != "any_of" && CombineType != "all_of")
|
|
|
|
PrintFatalError(R->getLoc(), "Invalid AssemblerCondDag!");
|
|
|
|
if (D->getNumArgs() == 0)
|
|
|
|
PrintFatalError(R->getLoc(), "Invalid AssemblerCondDag!");
|
|
|
|
bool IsOr = CombineType == "any_of";
|
|
|
|
|
|
|
|
for (auto *Arg : D->getArgs()) {
|
|
|
|
bool IsNeg = false;
|
|
|
|
if (auto *NotArg = dyn_cast<DagInit>(Arg)) {
|
|
|
|
if (NotArg->getOperator()->getAsString() != "not" ||
|
|
|
|
NotArg->getNumArgs() != 1)
|
|
|
|
PrintFatalError(R->getLoc(), "Invalid AssemblerCondDag!");
|
|
|
|
Arg = NotArg->getArg(0);
|
|
|
|
IsNeg = true;
|
|
|
|
}
|
|
|
|
if (!isa<DefInit>(Arg) ||
|
|
|
|
!cast<DefInit>(Arg)->getDef()->isSubClassOf("SubtargetFeature"))
|
|
|
|
PrintFatalError(R->getLoc(), "Invalid AssemblerCondDag!");
|
|
|
|
|
|
|
|
IAP.addCond(std::string(formatv(
|
|
|
|
"AliasPatternCond::K_{0}{1}Feature, {2}::{3}", IsOr ? "Or" : "",
|
|
|
|
IsNeg ? "Neg" : "", Namespace, Arg->getAsString())));
|
2016-06-03 21:14:19 +08:00
|
|
|
}
|
[TableGen] Support combining AssemblerPredicates with ORs
For context, the proposed RISC-V bit manipulation extension has a subset
of instructions which require one of two SubtargetFeatures to be
enabled, 'zbb' or 'zbp', and there is no defined feature which both of
these can imply to use as a constraint either (see comments in D65649).
AssemblerPredicates allow multiple SubtargetFeatures to be declared in
the "AssemblerCondString" field, separated by commas, and this means
that the two features must both be enabled. There is no equivalent to
say that _either_ feature X or feature Y must be enabled, short of
creating a dummy SubtargetFeature for this purpose and having features X
and Y imply the new feature.
To solve the case where X or Y is needed without adding a new feature,
and to better match a typical TableGen style, this replaces the existing
"AssemblerCondString" with a dag "AssemblerCondDag" which represents the
same information. Two operators are defined for use with
AssemblerCondDag, "all_of", which matches the current behaviour, and
"any_of", which adds the new proposed ORing features functionality.
This was originally proposed in the RFC at
http://lists.llvm.org/pipermail/llvm-dev/2020-February/139138.html
Changes to all current backends are mechanical to support the replaced
functionality, and are NFCI.
At this stage, it is illegal to combine features with ands and ors in a
single AssemblerCondDag. I suspect this case is sufficiently rare that
adding more complex changes to support it are unnecessary.
Differential Revision: https://reviews.llvm.org/D74338
2020-03-14 01:13:51 +08:00
|
|
|
// If an AssemblerPredicate with ors is used, note end of list should
|
|
|
|
// these be combined.
|
|
|
|
if (IsOr)
|
|
|
|
IAP.addCond("AliasPatternCond::K_EndOrFeatures, 0");
|
2016-06-03 21:14:19 +08:00
|
|
|
}
|
|
|
|
|
2015-08-07 03:23:33 +08:00
|
|
|
IAPrinterMap[Aliases.first].push_back(std::move(IAP));
|
2011-03-21 16:59:17 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-05-13 02:04:06 +08:00
|
|
|
//////////////////////////////
|
|
|
|
// Write out the printAliasInstr function
|
|
|
|
//////////////////////////////
|
|
|
|
|
2011-05-23 08:18:33 +08:00
|
|
|
std::string Header;
|
|
|
|
raw_string_ostream HeaderO(Header);
|
|
|
|
|
|
|
|
HeaderO << "bool " << Target.getName() << ClassName
|
2011-06-14 11:17:20 +08:00
|
|
|
<< "::printAliasInstr(const MCInst"
|
2020-03-27 14:55:43 +08:00
|
|
|
<< " *MI, uint64_t Address, "
|
|
|
|
<< (PassSubtarget ? "const MCSubtargetInfo &STI, " : "")
|
2015-03-28 04:36:02 +08:00
|
|
|
<< "raw_ostream &OS) {\n";
|
2011-03-21 16:59:17 +08:00
|
|
|
|
[MC] Rewrite tablegen for printInstrAlias to comiple faster, NFC
Before this change, the *InstPrinter.cpp files of each target where some
of the slowest objects to compile in all of LLVM. See this snippet produced by
ClangBuildAnalyzer:
https://reviews.llvm.org/P8171$96
Search for "InstPrinter", and see that it shows up in a few places.
Tablegen was emitting a large switch containing a sequence of operand checks,
each of which created many conditions and many BBs. Register allocation and
jump threading both did not scale well with such a large repetitive sequence of
basic blocks.
So, this change essentially turns those control flow structures into
data. The previous structure looked like:
switch (Opc) {
case TGT::ADD:
// check alias 1
if (MI->getOperandCount() == N && // check num opnds
MI->getOperand(0).isReg() && // check opnd 0
...
MI->getOperand(1).isImm() && // check opnd 1
AsmString = "foo";
break;
}
// check alias 2
if (...)
...
return false;
The new structure looks like:
OpToPatterns: Sorted table of opcodes mapping to pattern indices.
\->
Patterns: List of patterns. Previous table points to subrange of
patterns to match.
\->
Conds: The if conditions above encoded as a kind and 32-bit value.
See MCInstPrinter.cpp for the details of how the new data structures are
interpreted.
Here are some before and after metrics.
Time to compile AArch64InstPrinter.cpp:
0m29.062s vs. 0m2.203s
size of the obj:
3.9M vs. 676K
size of clang.exe:
97M vs. 96M
I have not benchmarked disassembly performance, but typically
disassemblers are bottlenecked on IO and string processing, not alias
matching, so I'm not sure it's interesting enough to be worth doing.
Reviewers: RKSimon, andreadb, xbolva00, craig.topper
Reviewed By: craig.topper
Differential Revision: https://reviews.llvm.org/D70650
2019-11-24 03:28:54 +08:00
|
|
|
std::string PatternsForOpcode;
|
|
|
|
raw_string_ostream OpcodeO(PatternsForOpcode);
|
|
|
|
|
|
|
|
unsigned PatternCount = 0;
|
|
|
|
std::string Patterns;
|
|
|
|
raw_string_ostream PatternO(Patterns);
|
|
|
|
|
|
|
|
unsigned CondCount = 0;
|
|
|
|
std::string Conds;
|
|
|
|
raw_string_ostream CondO(Conds);
|
|
|
|
|
|
|
|
// All flattened alias strings.
|
|
|
|
std::map<std::string, uint32_t> AsmStringOffsets;
|
|
|
|
std::vector<std::pair<uint32_t, std::string>> AsmStrings;
|
|
|
|
size_t AsmStringsSize = 0;
|
|
|
|
|
|
|
|
// Iterate over the opcodes in enum order so they are sorted by opcode for
|
|
|
|
// binary search.
|
|
|
|
for (const CodeGenInstruction *Inst : NumberedInstructions) {
|
|
|
|
auto It = IAPrinterMap.find(getQualifiedName(Inst->TheDef));
|
|
|
|
if (It == IAPrinterMap.end())
|
|
|
|
continue;
|
|
|
|
std::vector<IAPrinter> &IAPs = It->second;
|
2011-04-08 05:20:06 +08:00
|
|
|
std::vector<IAPrinter*> UniqueIAPs;
|
|
|
|
|
[MC] Rewrite tablegen for printInstrAlias to comiple faster, NFC
Before this change, the *InstPrinter.cpp files of each target where some
of the slowest objects to compile in all of LLVM. See this snippet produced by
ClangBuildAnalyzer:
https://reviews.llvm.org/P8171$96
Search for "InstPrinter", and see that it shows up in a few places.
Tablegen was emitting a large switch containing a sequence of operand checks,
each of which created many conditions and many BBs. Register allocation and
jump threading both did not scale well with such a large repetitive sequence of
basic blocks.
So, this change essentially turns those control flow structures into
data. The previous structure looked like:
switch (Opc) {
case TGT::ADD:
// check alias 1
if (MI->getOperandCount() == N && // check num opnds
MI->getOperand(0).isReg() && // check opnd 0
...
MI->getOperand(1).isImm() && // check opnd 1
AsmString = "foo";
break;
}
// check alias 2
if (...)
...
return false;
The new structure looks like:
OpToPatterns: Sorted table of opcodes mapping to pattern indices.
\->
Patterns: List of patterns. Previous table points to subrange of
patterns to match.
\->
Conds: The if conditions above encoded as a kind and 32-bit value.
See MCInstPrinter.cpp for the details of how the new data structures are
interpreted.
Here are some before and after metrics.
Time to compile AArch64InstPrinter.cpp:
0m29.062s vs. 0m2.203s
size of the obj:
3.9M vs. 676K
size of clang.exe:
97M vs. 96M
I have not benchmarked disassembly performance, but typically
disassemblers are bottlenecked on IO and string processing, not alias
matching, so I'm not sure it's interesting enough to be worth doing.
Reviewers: RKSimon, andreadb, xbolva00, craig.topper
Reviewed By: craig.topper
Differential Revision: https://reviews.llvm.org/D70650
2019-11-24 03:28:54 +08:00
|
|
|
// Remove any ambiguous alias rules.
|
2015-08-07 03:23:33 +08:00
|
|
|
for (auto &LHS : IAPs) {
|
2011-04-08 05:20:06 +08:00
|
|
|
bool IsDup = false;
|
2015-08-07 03:23:33 +08:00
|
|
|
for (const auto &RHS : IAPs) {
|
|
|
|
if (&LHS != &RHS && LHS == RHS) {
|
2011-04-08 05:20:06 +08:00
|
|
|
IsDup = true;
|
2011-02-26 11:09:12 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-08-07 03:23:33 +08:00
|
|
|
if (!IsDup)
|
|
|
|
UniqueIAPs.push_back(&LHS);
|
2011-04-08 05:20:06 +08:00
|
|
|
}
|
2011-02-26 11:09:12 +08:00
|
|
|
|
2011-04-08 05:20:06 +08:00
|
|
|
if (UniqueIAPs.empty()) continue;
|
2011-02-26 11:09:12 +08:00
|
|
|
|
[MC] Rewrite tablegen for printInstrAlias to comiple faster, NFC
Before this change, the *InstPrinter.cpp files of each target where some
of the slowest objects to compile in all of LLVM. See this snippet produced by
ClangBuildAnalyzer:
https://reviews.llvm.org/P8171$96
Search for "InstPrinter", and see that it shows up in a few places.
Tablegen was emitting a large switch containing a sequence of operand checks,
each of which created many conditions and many BBs. Register allocation and
jump threading both did not scale well with such a large repetitive sequence of
basic blocks.
So, this change essentially turns those control flow structures into
data. The previous structure looked like:
switch (Opc) {
case TGT::ADD:
// check alias 1
if (MI->getOperandCount() == N && // check num opnds
MI->getOperand(0).isReg() && // check opnd 0
...
MI->getOperand(1).isImm() && // check opnd 1
AsmString = "foo";
break;
}
// check alias 2
if (...)
...
return false;
The new structure looks like:
OpToPatterns: Sorted table of opcodes mapping to pattern indices.
\->
Patterns: List of patterns. Previous table points to subrange of
patterns to match.
\->
Conds: The if conditions above encoded as a kind and 32-bit value.
See MCInstPrinter.cpp for the details of how the new data structures are
interpreted.
Here are some before and after metrics.
Time to compile AArch64InstPrinter.cpp:
0m29.062s vs. 0m2.203s
size of the obj:
3.9M vs. 676K
size of clang.exe:
97M vs. 96M
I have not benchmarked disassembly performance, but typically
disassemblers are bottlenecked on IO and string processing, not alias
matching, so I'm not sure it's interesting enough to be worth doing.
Reviewers: RKSimon, andreadb, xbolva00, craig.topper
Reviewed By: craig.topper
Differential Revision: https://reviews.llvm.org/D70650
2019-11-24 03:28:54 +08:00
|
|
|
unsigned PatternStart = PatternCount;
|
|
|
|
|
|
|
|
// Insert the pattern start and opcode in the pattern list for debugging.
|
|
|
|
PatternO << formatv(" // {0} - {1}\n", It->first, PatternStart);
|
2011-02-26 11:09:12 +08:00
|
|
|
|
2016-01-08 15:06:32 +08:00
|
|
|
for (IAPrinter *IAP : UniqueIAPs) {
|
[MC] Rewrite tablegen for printInstrAlias to comiple faster, NFC
Before this change, the *InstPrinter.cpp files of each target where some
of the slowest objects to compile in all of LLVM. See this snippet produced by
ClangBuildAnalyzer:
https://reviews.llvm.org/P8171$96
Search for "InstPrinter", and see that it shows up in a few places.
Tablegen was emitting a large switch containing a sequence of operand checks,
each of which created many conditions and many BBs. Register allocation and
jump threading both did not scale well with such a large repetitive sequence of
basic blocks.
So, this change essentially turns those control flow structures into
data. The previous structure looked like:
switch (Opc) {
case TGT::ADD:
// check alias 1
if (MI->getOperandCount() == N && // check num opnds
MI->getOperand(0).isReg() && // check opnd 0
...
MI->getOperand(1).isImm() && // check opnd 1
AsmString = "foo";
break;
}
// check alias 2
if (...)
...
return false;
The new structure looks like:
OpToPatterns: Sorted table of opcodes mapping to pattern indices.
\->
Patterns: List of patterns. Previous table points to subrange of
patterns to match.
\->
Conds: The if conditions above encoded as a kind and 32-bit value.
See MCInstPrinter.cpp for the details of how the new data structures are
interpreted.
Here are some before and after metrics.
Time to compile AArch64InstPrinter.cpp:
0m29.062s vs. 0m2.203s
size of the obj:
3.9M vs. 676K
size of clang.exe:
97M vs. 96M
I have not benchmarked disassembly performance, but typically
disassemblers are bottlenecked on IO and string processing, not alias
matching, so I'm not sure it's interesting enough to be worth doing.
Reviewers: RKSimon, andreadb, xbolva00, craig.topper
Reviewed By: craig.topper
Differential Revision: https://reviews.llvm.org/D70650
2019-11-24 03:28:54 +08:00
|
|
|
// Start each condition list with a comment of the resulting pattern that
|
|
|
|
// we're trying to match.
|
|
|
|
unsigned CondStart = CondCount;
|
|
|
|
CondO << formatv(" // {0} - {1}\n", IAP->getResult(), CondStart);
|
|
|
|
for (const auto &Cond : IAP->getConds())
|
|
|
|
CondO << " {" << Cond << "},\n";
|
|
|
|
CondCount += IAP->getCondCount();
|
|
|
|
|
|
|
|
// After operands have been examined, re-encode the alias string with
|
|
|
|
// escapes indicating how operands should be printed.
|
|
|
|
uint32_t UnescapedSize = 0;
|
|
|
|
std::string EncodedAsmString = IAP->formatAliasString(UnescapedSize);
|
|
|
|
auto Insertion =
|
|
|
|
AsmStringOffsets.insert({EncodedAsmString, AsmStringsSize});
|
|
|
|
if (Insertion.second) {
|
|
|
|
// If the string is new, add it to the vector.
|
|
|
|
AsmStrings.push_back({AsmStringsSize, EncodedAsmString});
|
|
|
|
AsmStringsSize += UnescapedSize + 1;
|
|
|
|
}
|
|
|
|
unsigned AsmStrOffset = Insertion.first->second;
|
|
|
|
|
|
|
|
PatternO << formatv(" {{{0}, {1}, {2}, {3} },\n", AsmStrOffset,
|
|
|
|
CondStart, IAP->getNumMIOps(), IAP->getCondCount());
|
|
|
|
++PatternCount;
|
2011-02-26 11:09:12 +08:00
|
|
|
}
|
|
|
|
|
[MC] Rewrite tablegen for printInstrAlias to comiple faster, NFC
Before this change, the *InstPrinter.cpp files of each target where some
of the slowest objects to compile in all of LLVM. See this snippet produced by
ClangBuildAnalyzer:
https://reviews.llvm.org/P8171$96
Search for "InstPrinter", and see that it shows up in a few places.
Tablegen was emitting a large switch containing a sequence of operand checks,
each of which created many conditions and many BBs. Register allocation and
jump threading both did not scale well with such a large repetitive sequence of
basic blocks.
So, this change essentially turns those control flow structures into
data. The previous structure looked like:
switch (Opc) {
case TGT::ADD:
// check alias 1
if (MI->getOperandCount() == N && // check num opnds
MI->getOperand(0).isReg() && // check opnd 0
...
MI->getOperand(1).isImm() && // check opnd 1
AsmString = "foo";
break;
}
// check alias 2
if (...)
...
return false;
The new structure looks like:
OpToPatterns: Sorted table of opcodes mapping to pattern indices.
\->
Patterns: List of patterns. Previous table points to subrange of
patterns to match.
\->
Conds: The if conditions above encoded as a kind and 32-bit value.
See MCInstPrinter.cpp for the details of how the new data structures are
interpreted.
Here are some before and after metrics.
Time to compile AArch64InstPrinter.cpp:
0m29.062s vs. 0m2.203s
size of the obj:
3.9M vs. 676K
size of clang.exe:
97M vs. 96M
I have not benchmarked disassembly performance, but typically
disassemblers are bottlenecked on IO and string processing, not alias
matching, so I'm not sure it's interesting enough to be worth doing.
Reviewers: RKSimon, andreadb, xbolva00, craig.topper
Reviewed By: craig.topper
Differential Revision: https://reviews.llvm.org/D70650
2019-11-24 03:28:54 +08:00
|
|
|
OpcodeO << formatv(" {{{0}, {1}, {2} },\n", It->first, PatternStart,
|
|
|
|
PatternCount - PatternStart);
|
2011-04-08 05:20:06 +08:00
|
|
|
}
|
2011-02-26 11:09:12 +08:00
|
|
|
|
[MC] Rewrite tablegen for printInstrAlias to comiple faster, NFC
Before this change, the *InstPrinter.cpp files of each target where some
of the slowest objects to compile in all of LLVM. See this snippet produced by
ClangBuildAnalyzer:
https://reviews.llvm.org/P8171$96
Search for "InstPrinter", and see that it shows up in a few places.
Tablegen was emitting a large switch containing a sequence of operand checks,
each of which created many conditions and many BBs. Register allocation and
jump threading both did not scale well with such a large repetitive sequence of
basic blocks.
So, this change essentially turns those control flow structures into
data. The previous structure looked like:
switch (Opc) {
case TGT::ADD:
// check alias 1
if (MI->getOperandCount() == N && // check num opnds
MI->getOperand(0).isReg() && // check opnd 0
...
MI->getOperand(1).isImm() && // check opnd 1
AsmString = "foo";
break;
}
// check alias 2
if (...)
...
return false;
The new structure looks like:
OpToPatterns: Sorted table of opcodes mapping to pattern indices.
\->
Patterns: List of patterns. Previous table points to subrange of
patterns to match.
\->
Conds: The if conditions above encoded as a kind and 32-bit value.
See MCInstPrinter.cpp for the details of how the new data structures are
interpreted.
Here are some before and after metrics.
Time to compile AArch64InstPrinter.cpp:
0m29.062s vs. 0m2.203s
size of the obj:
3.9M vs. 676K
size of clang.exe:
97M vs. 96M
I have not benchmarked disassembly performance, but typically
disassemblers are bottlenecked on IO and string processing, not alias
matching, so I'm not sure it's interesting enough to be worth doing.
Reviewers: RKSimon, andreadb, xbolva00, craig.topper
Reviewed By: craig.topper
Differential Revision: https://reviews.llvm.org/D70650
2019-11-24 03:28:54 +08:00
|
|
|
if (OpcodeO.str().empty()) {
|
2011-05-23 08:18:33 +08:00
|
|
|
O << HeaderO.str();
|
2011-04-19 05:28:11 +08:00
|
|
|
O << " return false;\n";
|
2011-04-08 05:20:06 +08:00
|
|
|
O << "}\n\n";
|
|
|
|
O << "#endif // PRINT_ALIAS_INSTR\n";
|
|
|
|
return;
|
2011-02-26 11:09:12 +08:00
|
|
|
}
|
|
|
|
|
[MC] Rewrite tablegen for printInstrAlias to comiple faster, NFC
Before this change, the *InstPrinter.cpp files of each target where some
of the slowest objects to compile in all of LLVM. See this snippet produced by
ClangBuildAnalyzer:
https://reviews.llvm.org/P8171$96
Search for "InstPrinter", and see that it shows up in a few places.
Tablegen was emitting a large switch containing a sequence of operand checks,
each of which created many conditions and many BBs. Register allocation and
jump threading both did not scale well with such a large repetitive sequence of
basic blocks.
So, this change essentially turns those control flow structures into
data. The previous structure looked like:
switch (Opc) {
case TGT::ADD:
// check alias 1
if (MI->getOperandCount() == N && // check num opnds
MI->getOperand(0).isReg() && // check opnd 0
...
MI->getOperand(1).isImm() && // check opnd 1
AsmString = "foo";
break;
}
// check alias 2
if (...)
...
return false;
The new structure looks like:
OpToPatterns: Sorted table of opcodes mapping to pattern indices.
\->
Patterns: List of patterns. Previous table points to subrange of
patterns to match.
\->
Conds: The if conditions above encoded as a kind and 32-bit value.
See MCInstPrinter.cpp for the details of how the new data structures are
interpreted.
Here are some before and after metrics.
Time to compile AArch64InstPrinter.cpp:
0m29.062s vs. 0m2.203s
size of the obj:
3.9M vs. 676K
size of clang.exe:
97M vs. 96M
I have not benchmarked disassembly performance, but typically
disassemblers are bottlenecked on IO and string processing, not alias
matching, so I'm not sure it's interesting enough to be worth doing.
Reviewers: RKSimon, andreadb, xbolva00, craig.topper
Reviewed By: craig.topper
Differential Revision: https://reviews.llvm.org/D70650
2019-11-24 03:28:54 +08:00
|
|
|
// Forward declare the validation method if needed.
|
2015-01-15 19:41:30 +08:00
|
|
|
if (!MCOpPredicates.empty())
|
2014-06-10 21:11:35 +08:00
|
|
|
O << "static bool " << Target.getName() << ClassName
|
2015-12-01 18:48:51 +08:00
|
|
|
<< "ValidateMCOperand(const MCOperand &MCOp,\n"
|
|
|
|
<< " const MCSubtargetInfo &STI,\n"
|
|
|
|
<< " unsigned PredicateIndex);\n";
|
2014-06-10 21:11:35 +08:00
|
|
|
|
2011-05-23 08:18:33 +08:00
|
|
|
O << HeaderO.str();
|
[MC] Rewrite tablegen for printInstrAlias to comiple faster, NFC
Before this change, the *InstPrinter.cpp files of each target where some
of the slowest objects to compile in all of LLVM. See this snippet produced by
ClangBuildAnalyzer:
https://reviews.llvm.org/P8171$96
Search for "InstPrinter", and see that it shows up in a few places.
Tablegen was emitting a large switch containing a sequence of operand checks,
each of which created many conditions and many BBs. Register allocation and
jump threading both did not scale well with such a large repetitive sequence of
basic blocks.
So, this change essentially turns those control flow structures into
data. The previous structure looked like:
switch (Opc) {
case TGT::ADD:
// check alias 1
if (MI->getOperandCount() == N && // check num opnds
MI->getOperand(0).isReg() && // check opnd 0
...
MI->getOperand(1).isImm() && // check opnd 1
AsmString = "foo";
break;
}
// check alias 2
if (...)
...
return false;
The new structure looks like:
OpToPatterns: Sorted table of opcodes mapping to pattern indices.
\->
Patterns: List of patterns. Previous table points to subrange of
patterns to match.
\->
Conds: The if conditions above encoded as a kind and 32-bit value.
See MCInstPrinter.cpp for the details of how the new data structures are
interpreted.
Here are some before and after metrics.
Time to compile AArch64InstPrinter.cpp:
0m29.062s vs. 0m2.203s
size of the obj:
3.9M vs. 676K
size of clang.exe:
97M vs. 96M
I have not benchmarked disassembly performance, but typically
disassemblers are bottlenecked on IO and string processing, not alias
matching, so I'm not sure it's interesting enough to be worth doing.
Reviewers: RKSimon, andreadb, xbolva00, craig.topper
Reviewed By: craig.topper
Differential Revision: https://reviews.llvm.org/D70650
2019-11-24 03:28:54 +08:00
|
|
|
O.indent(2) << "static const PatternsForOpcode OpToPatterns[] = {\n";
|
|
|
|
O << OpcodeO.str();
|
|
|
|
O.indent(2) << "};\n\n";
|
|
|
|
O.indent(2) << "static const AliasPattern Patterns[] = {\n";
|
|
|
|
O << PatternO.str();
|
|
|
|
O.indent(2) << "};\n\n";
|
|
|
|
O.indent(2) << "static const AliasPatternCond Conds[] = {\n";
|
|
|
|
O << CondO.str();
|
|
|
|
O.indent(2) << "};\n\n";
|
|
|
|
O.indent(2) << "static const char AsmStrings[] =\n";
|
|
|
|
for (const auto &P : AsmStrings) {
|
|
|
|
O.indent(4) << "/* " << P.first << " */ \"" << P.second << "\\0\"\n";
|
|
|
|
}
|
|
|
|
|
|
|
|
O.indent(2) << ";\n\n";
|
|
|
|
|
|
|
|
// Assert that the opcode table is sorted. Use a static local constructor to
|
|
|
|
// ensure that the check only happens once on first run.
|
|
|
|
O << "#ifndef NDEBUG\n";
|
|
|
|
O.indent(2) << "static struct SortCheck {\n";
|
|
|
|
O.indent(2) << " SortCheck(ArrayRef<PatternsForOpcode> OpToPatterns) {\n";
|
|
|
|
O.indent(2) << " assert(std::is_sorted(\n";
|
|
|
|
O.indent(2) << " OpToPatterns.begin(), OpToPatterns.end(),\n";
|
|
|
|
O.indent(2) << " [](const PatternsForOpcode &L, const "
|
|
|
|
"PatternsForOpcode &R) {\n";
|
|
|
|
O.indent(2) << " return L.Opcode < R.Opcode;\n";
|
|
|
|
O.indent(2) << " }) &&\n";
|
|
|
|
O.indent(2) << " \"tablegen failed to sort opcode patterns\");\n";
|
|
|
|
O.indent(2) << " }\n";
|
|
|
|
O.indent(2) << "} sortCheckVar(OpToPatterns);\n";
|
|
|
|
O << "#endif\n\n";
|
|
|
|
|
|
|
|
O.indent(2) << "AliasMatchingData M {\n";
|
|
|
|
O.indent(2) << " makeArrayRef(OpToPatterns),\n";
|
|
|
|
O.indent(2) << " makeArrayRef(Patterns),\n";
|
|
|
|
O.indent(2) << " makeArrayRef(Conds),\n";
|
|
|
|
O.indent(2) << " StringRef(AsmStrings, array_lengthof(AsmStrings)),\n";
|
|
|
|
if (MCOpPredicates.empty())
|
|
|
|
O.indent(2) << " nullptr,\n";
|
|
|
|
else
|
|
|
|
O.indent(2) << " &" << Target.getName() << ClassName << "ValidateMCOperand,\n";
|
|
|
|
O.indent(2) << "};\n";
|
|
|
|
|
|
|
|
O.indent(2) << "const char *AsmString = matchAliasPatterns(MI, "
|
|
|
|
<< (PassSubtarget ? "&STI" : "nullptr") << ", M);\n";
|
|
|
|
O.indent(2) << "if (!AsmString) return false;\n\n";
|
2011-02-26 11:09:12 +08:00
|
|
|
|
|
|
|
// Code that prints the alias, replacing the operands with the ones from the
|
|
|
|
// MCInst.
|
2013-09-11 23:42:16 +08:00
|
|
|
O << " unsigned I = 0;\n";
|
2016-06-03 21:17:37 +08:00
|
|
|
O << " while (AsmString[I] != ' ' && AsmString[I] != '\\t' &&\n";
|
|
|
|
O << " AsmString[I] != '$' && AsmString[I] != '\\0')\n";
|
2013-09-11 23:42:16 +08:00
|
|
|
O << " ++I;\n";
|
|
|
|
O << " OS << '\\t' << StringRef(AsmString, I);\n";
|
2011-02-26 11:09:12 +08:00
|
|
|
|
2013-09-11 23:42:16 +08:00
|
|
|
O << " if (AsmString[I] != '\\0') {\n";
|
2017-11-14 02:00:24 +08:00
|
|
|
O << " if (AsmString[I] == ' ' || AsmString[I] == '\\t') {\n";
|
2016-06-03 21:17:37 +08:00
|
|
|
O << " OS << '\\t';\n";
|
2017-11-14 02:00:24 +08:00
|
|
|
O << " ++I;\n";
|
|
|
|
O << " }\n";
|
2013-09-11 23:42:16 +08:00
|
|
|
O << " do {\n";
|
|
|
|
O << " if (AsmString[I] == '$') {\n";
|
|
|
|
O << " ++I;\n";
|
2014-05-13 02:04:06 +08:00
|
|
|
O << " if (AsmString[I] == (char)0xff) {\n";
|
|
|
|
O << " ++I;\n";
|
|
|
|
O << " int OpIdx = AsmString[I++] - 1;\n";
|
|
|
|
O << " int PrintMethodIdx = AsmString[I++] - 1;\n";
|
2020-03-27 15:17:56 +08:00
|
|
|
O << " printCustomAliasOperand(MI, Address, OpIdx, PrintMethodIdx, ";
|
2015-03-28 04:36:02 +08:00
|
|
|
O << (PassSubtarget ? "STI, " : "");
|
|
|
|
O << "OS);\n";
|
2014-05-13 02:04:06 +08:00
|
|
|
O << " } else\n";
|
2015-03-28 04:36:02 +08:00
|
|
|
O << " printOperand(MI, unsigned(AsmString[I++]) - 1, ";
|
|
|
|
O << (PassSubtarget ? "STI, " : "");
|
|
|
|
O << "OS);\n";
|
2011-02-26 11:09:12 +08:00
|
|
|
O << " } else {\n";
|
2013-09-11 23:42:16 +08:00
|
|
|
O << " OS << AsmString[I++];\n";
|
2011-02-26 11:09:12 +08:00
|
|
|
O << " }\n";
|
2013-09-11 23:42:16 +08:00
|
|
|
O << " } while (AsmString[I] != '\\0');\n";
|
2011-02-26 11:09:12 +08:00
|
|
|
O << " }\n\n";
|
2012-04-19 02:56:33 +08:00
|
|
|
|
2011-04-19 05:28:11 +08:00
|
|
|
O << " return true;\n";
|
2011-02-26 11:09:12 +08:00
|
|
|
O << "}\n\n";
|
|
|
|
|
2014-05-13 02:04:06 +08:00
|
|
|
//////////////////////////////
|
|
|
|
// Write out the printCustomAliasOperand function
|
|
|
|
//////////////////////////////
|
|
|
|
|
|
|
|
O << "void " << Target.getName() << ClassName << "::"
|
|
|
|
<< "printCustomAliasOperand(\n"
|
2020-03-27 15:17:56 +08:00
|
|
|
<< " const MCInst *MI, uint64_t Address, unsigned OpIdx,\n"
|
2015-03-28 04:36:02 +08:00
|
|
|
<< " unsigned PrintMethodIdx,\n"
|
|
|
|
<< (PassSubtarget ? " const MCSubtargetInfo &STI,\n" : "")
|
|
|
|
<< " raw_ostream &OS) {\n";
|
2014-05-13 20:52:35 +08:00
|
|
|
if (PrintMethods.empty())
|
|
|
|
O << " llvm_unreachable(\"Unknown PrintMethod kind\");\n";
|
|
|
|
else {
|
|
|
|
O << " switch (PrintMethodIdx) {\n"
|
|
|
|
<< " default:\n"
|
|
|
|
<< " llvm_unreachable(\"Unknown PrintMethod kind\");\n"
|
2014-05-13 02:04:06 +08:00
|
|
|
<< " break;\n";
|
|
|
|
|
2014-05-13 20:52:35 +08:00
|
|
|
for (unsigned i = 0; i < PrintMethods.size(); ++i) {
|
|
|
|
O << " case " << i << ":\n"
|
2020-03-27 15:17:56 +08:00
|
|
|
<< " " << PrintMethods[i].first << "(MI, "
|
|
|
|
<< (PrintMethods[i].second ? "Address, " : "") << "OpIdx, "
|
2015-03-28 04:36:02 +08:00
|
|
|
<< (PassSubtarget ? "STI, " : "") << "OS);\n"
|
2014-05-13 20:52:35 +08:00
|
|
|
<< " break;\n";
|
|
|
|
}
|
|
|
|
O << " }\n";
|
|
|
|
}
|
|
|
|
O << "}\n\n";
|
2014-05-13 02:04:06 +08:00
|
|
|
|
2015-01-15 19:41:30 +08:00
|
|
|
if (!MCOpPredicates.empty()) {
|
2014-06-10 21:11:35 +08:00
|
|
|
O << "static bool " << Target.getName() << ClassName
|
2015-12-01 18:48:51 +08:00
|
|
|
<< "ValidateMCOperand(const MCOperand &MCOp,\n"
|
|
|
|
<< " const MCSubtargetInfo &STI,\n"
|
|
|
|
<< " unsigned PredicateIndex) {\n"
|
2014-06-10 21:11:35 +08:00
|
|
|
<< " switch (PredicateIndex) {\n"
|
|
|
|
<< " default:\n"
|
|
|
|
<< " llvm_unreachable(\"Unknown MCOperandPredicate kind\");\n"
|
|
|
|
<< " break;\n";
|
|
|
|
|
|
|
|
for (unsigned i = 0; i < MCOpPredicates.size(); ++i) {
|
2020-11-25 02:09:02 +08:00
|
|
|
StringRef MCOpPred = MCOpPredicates[i]->getValueAsString("MCOperandPredicate");
|
|
|
|
O << " case " << i + 1 << ": {\n"
|
|
|
|
<< MCOpPred.data() << "\n"
|
|
|
|
<< " }\n";
|
2014-06-10 21:11:35 +08:00
|
|
|
}
|
|
|
|
O << " }\n"
|
|
|
|
<< "}\n\n";
|
|
|
|
}
|
|
|
|
|
2011-02-26 11:09:12 +08:00
|
|
|
O << "#endif // PRINT_ALIAS_INSTR\n";
|
|
|
|
}
|
2009-09-14 04:08:00 +08:00
|
|
|
|
2013-10-29 02:07:17 +08:00
|
|
|
AsmWriterEmitter::AsmWriterEmitter(RecordKeeper &R) : Records(R), Target(R) {
|
|
|
|
Record *AsmWriter = Target.getAsmWriter();
|
2016-01-13 15:20:05 +08:00
|
|
|
unsigned Variant = AsmWriter->getValueAsInt("Variant");
|
2013-10-29 02:07:17 +08:00
|
|
|
|
|
|
|
// Get the instruction numbering.
|
2016-01-18 04:38:14 +08:00
|
|
|
NumberedInstructions = Target.getInstructionsByEnumValue();
|
2013-10-29 02:07:17 +08:00
|
|
|
|
2016-01-18 04:38:14 +08:00
|
|
|
for (unsigned i = 0, e = NumberedInstructions.size(); i != e; ++i) {
|
|
|
|
const CodeGenInstruction *I = NumberedInstructions[i];
|
2016-01-17 16:05:33 +08:00
|
|
|
if (!I->AsmString.empty() && I->TheDef->getName() != "PHI")
|
|
|
|
Instructions.emplace_back(*I, i, Variant);
|
|
|
|
}
|
2013-10-29 02:07:17 +08:00
|
|
|
}
|
|
|
|
|
2009-09-14 04:08:00 +08:00
|
|
|
void AsmWriterEmitter::run(raw_ostream &O) {
|
2020-11-17 17:38:17 +08:00
|
|
|
std::vector<std::vector<std::string>> TableDrivenOperandPrinters;
|
|
|
|
unsigned BitsLeft = 0;
|
|
|
|
unsigned AsmStrBits = 0;
|
|
|
|
EmitGetMnemonic(O, TableDrivenOperandPrinters, BitsLeft, AsmStrBits);
|
|
|
|
EmitPrintInstruction(O, TableDrivenOperandPrinters, BitsLeft, AsmStrBits);
|
2009-09-14 04:08:00 +08:00
|
|
|
EmitGetRegisterName(O);
|
2011-02-26 11:09:12 +08:00
|
|
|
EmitPrintAliasInstruction(O);
|
2009-09-14 04:08:00 +08:00
|
|
|
}
|
|
|
|
|
2012-06-11 23:37:55 +08:00
|
|
|
namespace llvm {
|
|
|
|
|
|
|
|
void EmitAsmWriter(RecordKeeper &RK, raw_ostream &OS) {
|
|
|
|
emitSourceFileHeader("Assembly Writer Source Fragment", OS);
|
|
|
|
AsmWriterEmitter(RK).run(OS);
|
|
|
|
}
|
|
|
|
|
2016-12-01 01:48:10 +08:00
|
|
|
} // end namespace llvm
|