//
// The LLVM Compiler Infrastructure
//
-// This file was developed by the LLVM research group and is distributed under
-// the University of Illinois Open Source License. See LICENSE.TXT for details.
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
#include "llvm/Support/Debug.h"
#include "llvm/Support/MathExtras.h"
#include <algorithm>
-#include <ostream>
using namespace llvm;
static bool isIdentChar(char C) {
C == '_';
}
-namespace {
+// This should be an anon namespace, this works around a GCC warning.
+namespace llvm {
struct AsmWriterOperand {
enum { isLiteralTextOperand, isMachineInstrOperand } OperandType;
/// an operand, specified with syntax like ${opname:modifier}.
std::string MiModifier;
- AsmWriterOperand(const std::string &LitStr)
+ // To make VS STL happy
+ AsmWriterOperand():OperandType(isLiteralTextOperand) {}
+
+ explicit AsmWriterOperand(const std::string &LitStr)
: OperandType(isLiteralTextOperand), Str(LitStr) {}
AsmWriterOperand(const std::string &Printer, unsigned OpNo,
}
namespace llvm {
- struct AsmWriterInst {
+ class AsmWriterInst {
+ public:
std::vector<AsmWriterOperand> Operands;
const CodeGenInstruction *CGI;
if (OperandType == isLiteralTextOperand)
return "O << \"" + Str + "\"; ";
- std::string Result = Str + "(MI, " + utostr(MIOpNo);
+ std::string Result = Str + "(MI";
+ if (MIOpNo != ~0U)
+ Result += ", " + utostr(MIOpNo);
if (!MiModifier.empty())
Result += ", \"" + MiModifier + '"';
return Result + "); ";
std::string::size_type LastEmitted = 0;
while (LastEmitted != AsmString.size()) {
std::string::size_type DollarPos =
- AsmString.find_first_of("${|}", LastEmitted);
+ AsmString.find_first_of("${|}\\", LastEmitted);
if (DollarPos == std::string::npos) DollarPos = AsmString.size();
// Emit a constant string fragment.
AddLiteralString(std::string(AsmString.begin()+LastEmitted,
AsmString.begin()+DollarPos));
LastEmitted = DollarPos;
+ } else if (AsmString[DollarPos] == '\\') {
+ if (DollarPos+1 != AsmString.size() &&
+ (CurVariant == Variant || CurVariant == ~0U)) {
+ if (AsmString[DollarPos+1] == 'n') {
+ AddLiteralString("\\n");
+ } else if (AsmString[DollarPos+1] == 't') {
+ AddLiteralString("\\t");
+ } else if (std::string("${|}\\").find(AsmString[DollarPos+1])
+ != std::string::npos) {
+ AddLiteralString(std::string(1, AsmString[DollarPos+1]));
+ } else {
+ throw "Non-supported escaped character found in instruction '" +
+ CGI.TheDef->getName() + "'!";
+ }
+ LastEmitted = DollarPos+2;
+ continue;
+ }
} else if (AsmString[DollarPos] == '{') {
if (CurVariant != ~0U)
throw "Nested variants found for instruction '" +
AsmString.begin()+VarEnd);
// Modifier - Support ${foo:modifier} syntax, where "modifier" is passed
- // into printOperand.
+ // into printOperand. Also support ${:feature}, which is passed into
+ // PrintSpecial.
std::string Modifier;
// In order to avoid starting the next string at the terminating curly
+ CGI.TheDef->getName() + "'";
++VarEnd;
}
- if (VarName.empty())
+ if (VarName.empty() && Modifier.empty())
throw "Stray '$' in '" + CGI.TheDef->getName() +
"' asm string, maybe you want $$?";
- unsigned OpNo = CGI.getOperandNamed(VarName);
- CodeGenInstruction::OperandInfo OpInfo = CGI.OperandList[OpNo];
-
- // If this is a two-address instruction and we are not accessing the
- // 0th operand, remove an operand.
- unsigned MIOp = OpInfo.MIOperandNo;
- if (CGI.isTwoAddress && MIOp != 0) {
- if (MIOp == 1)
- throw "Should refer to operand #0 instead of #1 for two-address"
- " instruction '" + CGI.TheDef->getName() + "'!";
- --MIOp;
+ if (VarName.empty()) {
+ // Just a modifier, pass this into PrintSpecial.
+ Operands.push_back(AsmWriterOperand("PrintSpecial", ~0U, Modifier));
+ } else {
+ // Otherwise, normal operand.
+ unsigned OpNo = CGI.getOperandNamed(VarName);
+ CodeGenInstruction::OperandInfo OpInfo = CGI.OperandList[OpNo];
+
+ if (CurVariant == Variant || CurVariant == ~0U) {
+ unsigned MIOp = OpInfo.MIOperandNo;
+ Operands.push_back(AsmWriterOperand(OpInfo.PrinterMethodName, MIOp,
+ Modifier));
+ }
}
-
- if (CurVariant == Variant || CurVariant == ~0U)
- Operands.push_back(AsmWriterOperand(OpInfo.PrinterMethodName, MIOp,
- Modifier));
LastEmitted = VarEnd;
}
}
unsigned MismatchOperand = ~0U;
for (unsigned i = 0, e = Operands.size(); i != e; ++i) {
- if (Operands[i] != Other.Operands[i])
+ if (Operands[i] != Other.Operands[i]) {
if (MismatchOperand != ~0U) // Already have one mismatch?
return ~1U;
else
MismatchOperand = i;
+ }
}
return MismatchOperand;
}
FindUniqueOperandCommands(std::vector<std::string> &UniqueOperandCommands,
std::vector<unsigned> &InstIdxs,
std::vector<unsigned> &InstOpsUsed) const {
- InstIdxs.assign(NumberedInstructions.size(), 0);
+ InstIdxs.assign(NumberedInstructions.size(), ~0U);
// This vector parallels UniqueOperandCommands, keeping track of which
// instructions each case are used for. It is a comma separated string of
for (unsigned i = 0, e = NumberedInstructions.size(); i != e; ++i) {
const AsmWriterInst *Inst = getAsmWriterInstByID(i);
- if (Inst == 0) continue; // PHI, INLINEASM, etc.
+ if (Inst == 0) continue; // PHI, INLINEASM, DBG_LABEL, etc.
std::string Command;
if (Inst->Operands.empty())
// set share the operand.
bool AllSame = true;
- NIT = std::find(NIT+1, InstIdxs.end(), CommandIdx);
for (NIT = std::find(NIT+1, InstIdxs.end(), CommandIdx);
NIT != InstIdxs.end();
NIT = std::find(NIT+1, InstIdxs.end(), CommandIdx)) {
// Build an aggregate string, and build a table of offsets into it.
std::map<std::string, unsigned> StringOffset;
std::string AggregateString;
- AggregateString += '\0';
+ AggregateString.push_back(0); // "\0"
+ AggregateString.push_back(0); // "\0"
- /// OpcodeInfo - Theis encodes the index of the string to use for the first
+ /// OpcodeInfo - This encodes the index of the string to use for the first
/// chunk of the output as well as indices used for operand printing.
std::vector<unsigned> OpcodeInfo;
for (unsigned i = 0, e = NumberedInstructions.size(); i != e; ++i) {
AsmWriterInst *AWI = CGIAWIMap[NumberedInstructions[i]];
unsigned Idx;
- if (AWI == 0 || AWI->Operands[0].Str.empty()) {
+ if (AWI == 0) {
// Something not handled by the asmwriter printer.
Idx = 0;
+ } else if (AWI->Operands[0].OperandType !=
+ AsmWriterOperand::isLiteralTextOperand ||
+ AWI->Operands[0].Str.empty()) {
+ // Something handled by the asmwriter printer, but with no leading string.
+ Idx = 1;
} else {
unsigned &Entry = StringOffset[AWI->Operands[0].Str];
if (Entry == 0) {
}
// Figure out how many bits we used for the string index.
- unsigned AsmStrBits = Log2_32_Ceil(MaxStringIdx);
+ unsigned AsmStrBits = Log2_32_Ceil(MaxStringIdx+1);
// To reduce code size, we compactify common instructions into a few bits
// in the opcode-indexed table.
while (1) {
std::vector<std::string> UniqueOperandCommands;
- // For the first operand check, add a default value that unhandled
- // instructions will use.
+ // For the first operand check, add a default value for instructions with
+ // just opcode strings to use.
if (isFirst) {
- UniqueOperandCommands.push_back(" return false;\n");
+ UniqueOperandCommands.push_back(" return true;\n");
isFirst = false;
}
// If we don't have enough bits for this operand, don't include it.
if (NumBits > BitsLeft) {
- DEBUG(std::cerr << "Not enough bits to densely encode " << NumBits
- << " more bits\n");
+ DOUT << "Not enough bits to densely encode " << NumBits
+ << " more bits\n";
break;
}
// Otherwise, we can include this in the initial lookup table. Add it in.
BitsLeft -= NumBits;
for (unsigned i = 0, e = InstIdxs.size(); i != e; ++i)
- OpcodeInfo[i] |= InstIdxs[i] << (BitsLeft+AsmStrBits);
+ if (InstIdxs[i] != ~0U)
+ OpcodeInfo[i] |= InstIdxs[i] << (BitsLeft+AsmStrBits);
// Remove the info about this operand.
for (unsigned i = 0, e = NumberedInstructions.size(); i != e; ++i) {
if (AsmWriterInst *Inst = getAsmWriterInstByID(i))
if (!Inst->Operands.empty()) {
unsigned NumOps = NumInstOpsHandled[InstIdxs[i]];
+ assert(NumOps <= Inst->Operands.size() &&
+ "Can't remove this many ops!");
Inst->Operands.erase(Inst->Operands.begin(),
Inst->Operands.begin()+NumOps);
}
}
O << "\";\n\n";
+ O << " if (TAI->doesSupportDebugInformation()) {\n"
+ << " const MachineFunction *MF = MI->getParent()->getParent();\n"
+ << " static DebugLoc PrevDL = DebugLoc::getUnknownLoc();\n"
+ << " DebugLoc CurDL = MI->getDebugLoc();\n\n"
+ << " if (!CurDL.isUnknown() && PrevDL != CurDL) {\n"
+ << " DebugLocTuple DLT = MF->getDebugLocTuple(CurDL);\n"
+ << " printLabel(DW->RecordSourceLine(DLT.Line, DLT.Col, DLT.Src));\n"
+ << " }\n\n"
+ << " PrevDL = CurDL;\n"
+ << " }\n\n";
+
O << " if (MI->getOpcode() == TargetInstrInfo::INLINEASM) {\n"
+ << " O << \"\\t\";\n"
<< " printInlineAsm(MI);\n"
<< " return true;\n"
+ << " } else if (MI->isLabel()) {\n"
+ << " printLabel(MI);\n"
+ << " return true;\n"
+ << " } else if (MI->getOpcode() == TargetInstrInfo::DECLARE) {\n"
+ << " printDeclare(MI);\n"
+ << " return true;\n"
+ << " } else if (MI->getOpcode() == TargetInstrInfo::IMPLICIT_DEF) {\n"
+ << " printImplicitDef(MI);\n"
+ << " return true;\n"
<< " }\n\n";
+ O << " O << \"\\t\";\n\n";
+
O << " // Emit the opcode for the instruction.\n"
<< " unsigned Bits = OpInfo[MI->getOpcode()];\n"
+ << " if (Bits == 0) return false;\n"
<< " O << AsmStrs+(Bits & " << (1 << AsmStrBits)-1 << ");\n\n";
// Output the table driven operand information.
EmitInstructions(Instructions, O);
O << " }\n";
+ O << " return true;\n";
}
- O << " return true;\n"
- "}\n";
+ O << "}\n";
}