summaryrefslogtreecommitdiff
path: root/utils/TableGen/PseudoLoweringEmitter.cpp
blob: c685527a140c249c9aad3ca2f35d43e1c2d0e5b6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
//===- PseudoLoweringEmitter.cpp - PseudoLowering Generator -----*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "pseudo-lowering"
#include "CodeGenInstruction.h"
#include "PseudoLoweringEmitter.h"
#include "llvm/TableGen/Error.h"
#include "llvm/TableGen/Record.h"
#include "llvm/ADT/IndexedMap.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/Debug.h"
#include <vector>
using namespace llvm;

// FIXME: This pass currently can only expand a pseudo to a single instruction.
//        The pseudo expansion really should take a list of dags, not just
//        a single dag, so we can do fancier things.

unsigned PseudoLoweringEmitter::
addDagOperandMapping(Record *Rec, DagInit *Dag, CodeGenInstruction &Insn,
                     IndexedMap<OpData> &OperandMap, unsigned BaseIdx) {
  unsigned OpsAdded = 0;
  for (unsigned i = 0, e = Dag->getNumArgs(); i != e; ++i) {
    if (DefInit *DI = dynamic_cast<DefInit*>(Dag->getArg(i))) {
      // Physical register reference. Explicit check for the special case
      // "zero_reg" definition.
      if (DI->getDef()->isSubClassOf("Register") ||
          DI->getDef()->getName() == "zero_reg") {
        OperandMap[BaseIdx + i].Kind = OpData::Reg;
        OperandMap[BaseIdx + i].Data.Reg = DI->getDef();
        ++OpsAdded;
        continue;
      }

      // Normal operands should always have the same type, or we have a
      // problem.
      // FIXME: We probably shouldn't ever get a non-zero BaseIdx here.
      assert(BaseIdx == 0 && "Named subargument in pseudo expansion?!");
      if (DI->getDef() != Insn.Operands[BaseIdx + i].Rec)
        throw TGError(Rec->getLoc(),
                      "Pseudo operand type '" + DI->getDef()->getName() +
                      "' does not match expansion operand type '" +
                      Insn.Operands[BaseIdx + i].Rec->getName() + "'");
      // Source operand maps to destination operand. The Data element
      // will be filled in later, just set the Kind for now. Do it
      // for each corresponding MachineInstr operand, not just the first.
      for (unsigned I = 0, E = Insn.Operands[i].MINumOperands; I != E; ++I)
        OperandMap[BaseIdx + i + I].Kind = OpData::Operand;
      OpsAdded += Insn.Operands[i].MINumOperands;
    } else if (IntInit *II = dynamic_cast<IntInit*>(Dag->getArg(i))) {
      OperandMap[BaseIdx + i].Kind = OpData::Imm;
      OperandMap[BaseIdx + i].Data.Imm = II->getValue();
      ++OpsAdded;
    } else if (DagInit *SubDag = dynamic_cast<DagInit*>(Dag->getArg(i))) {
      // Just add the operands recursively. This is almost certainly
      // a constant value for a complex operand (> 1 MI operand).
      unsigned NewOps =
        addDagOperandMapping(Rec, SubDag, Insn, OperandMap, BaseIdx + i);
      OpsAdded += NewOps;
      // Since we added more than one, we also need to adjust the base.
      BaseIdx += NewOps - 1;
    } else
      assert(0 && "Unhandled pseudo-expansion argument type!");
  }
  return OpsAdded;
}

void PseudoLoweringEmitter::evaluateExpansion(Record *Rec) {
  DEBUG(dbgs() << "Pseudo definition: " << Rec->getName() << "\n");

  // Validate that the result pattern has the corrent number and types
  // of arguments for the instruction it references.
  DagInit *Dag = Rec->getValueAsDag("ResultInst");
  assert(Dag && "Missing result instruction in pseudo expansion!");
  DEBUG(dbgs() << "  Result: " << *Dag << "\n");

  DefInit *OpDef = dynamic_cast<DefInit*>(Dag->getOperator());
  if (!OpDef)
    throw TGError(Rec->getLoc(), Rec->getName() +
                  " has unexpected operator type!");
  Record *Operator = OpDef->getDef();
  if (!Operator->isSubClassOf("Instruction"))
    throw TGError(Rec->getLoc(), "Pseudo result '" + Operator->getName() +
                                 "' is not an instruction!");

  CodeGenInstruction Insn(Operator);

  if (Insn.isCodeGenOnly || Insn.isPseudo)
    throw TGError(Rec->getLoc(), "Pseudo result '" + Operator->getName() +
                                 "' cannot be another pseudo instruction!");

  if (Insn.Operands.size() != Dag->getNumArgs())
    throw TGError(Rec->getLoc(), "Pseudo result '" + Operator->getName() +
                                 "' operand count mismatch");

  IndexedMap<OpData> OperandMap;
  OperandMap.grow(Insn.Operands.size());

  addDagOperandMapping(Rec, Dag, Insn, OperandMap, 0);

  // If there are more operands that weren't in the DAG, they have to
  // be operands that have default values, or we have an error. Currently,
  // PredicateOperand and OptionalDefOperand both have default values.


  // Validate that each result pattern argument has a matching (by name)
  // argument in the source instruction, in either the (outs) or (ins) list.
  // Also check that the type of the arguments match.
  //
  // Record the mapping of the source to result arguments for use by
  // the lowering emitter.
  CodeGenInstruction SourceInsn(Rec);
  StringMap<unsigned> SourceOperands;
  for (unsigned i = 0, e = SourceInsn.Operands.size(); i != e; ++i)
    SourceOperands[SourceInsn.Operands[i].Name] = i;

  DEBUG(dbgs() << "  Operand mapping:\n");
  for (unsigned i = 0, e = Insn.Operands.size(); i != e; ++i) {
    // We've already handled constant values. Just map instruction operands
    // here.
    if (OperandMap[Insn.Operands[i].MIOperandNo].Kind != OpData::Operand)
      continue;
    StringMap<unsigned>::iterator SourceOp =
      SourceOperands.find(Dag->getArgName(i));
    if (SourceOp == SourceOperands.end())
      throw TGError(Rec->getLoc(),
                    "Pseudo output operand '" + Dag->getArgName(i) +
                    "' has no matching source operand.");
    // Map the source operand to the destination operand index for each
    // MachineInstr operand.
    for (unsigned I = 0, E = Insn.Operands[i].MINumOperands; I != E; ++I)
      OperandMap[Insn.Operands[i].MIOperandNo + I].Data.Operand =
        SourceOp->getValue();

    DEBUG(dbgs() << "    " << SourceOp->getValue() << " ==> " << i << "\n");
  }

  Expansions.push_back(PseudoExpansion(SourceInsn, Insn, OperandMap));
}

void PseudoLoweringEmitter::emitLoweringEmitter(raw_ostream &o) {
  // Emit file header.
  EmitSourceFileHeader("Pseudo-instruction MC lowering Source Fragment", o);

  o << "bool " << Target.getName() + "AsmPrinter" << "::\n"
    << "emitPseudoExpansionLowering(MCStreamer &OutStreamer,\n"
    << "                            const MachineInstr *MI) {\n"
    << "  switch (MI->getOpcode()) {\n"
    << "    default: return false;\n";
  for (unsigned i = 0, e = Expansions.size(); i != e; ++i) {
    PseudoExpansion &Expansion = Expansions[i];
    CodeGenInstruction &Source = Expansion.Source;
    CodeGenInstruction &Dest = Expansion.Dest;
    o << "    case " << Source.Namespace << "::"
      << Source.TheDef->getName() << ": {\n"
      << "      MCInst TmpInst;\n"
      << "      MCOperand MCOp;\n"
      << "      TmpInst.setOpcode(" << Dest.Namespace << "::"
      << Dest.TheDef->getName() << ");\n";

    // Copy the operands from the source instruction.
    // FIXME: Instruction operands with defaults values (predicates and cc_out
    //        in ARM, for example shouldn't need explicit values in the
    //        expansion DAG.
    unsigned MIOpNo = 0;
    for (unsigned OpNo = 0, E = Dest.Operands.size(); OpNo != E;
         ++OpNo) {
      o << "      // Operand: " << Dest.Operands[OpNo].Name << "\n";
      for (unsigned i = 0, e = Dest.Operands[OpNo].MINumOperands;
           i != e; ++i) {
        switch (Expansion.OperandMap[MIOpNo + i].Kind) {
        default:
          llvm_unreachable("Unknown operand type?!");
        case OpData::Operand:
          o << "      lowerOperand(MI->getOperand("
            << Source.Operands[Expansion.OperandMap[MIOpNo].Data
                .Operand].MIOperandNo + i
            << "), MCOp);\n"
            << "      TmpInst.addOperand(MCOp);\n";
          break;
        case OpData::Imm:
          o << "      TmpInst.addOperand(MCOperand::CreateImm("
            << Expansion.OperandMap[MIOpNo + i].Data.Imm << "));\n";
          break;
        case OpData::Reg: {
          Record *Reg = Expansion.OperandMap[MIOpNo + i].Data.Reg;
          o << "      TmpInst.addOperand(MCOperand::CreateReg(";
          // "zero_reg" is special.
          if (Reg->getName() == "zero_reg")
            o << "0";
          else
            o << Reg->getValueAsString("Namespace") << "::" << Reg->getName();
          o << "));\n";
          break;
        }
        }
      }
      MIOpNo += Dest.Operands[OpNo].MINumOperands;
    }
    if (Dest.Operands.isVariadic) {
      o << "      // variable_ops\n";
      o << "      for (unsigned i = " << MIOpNo
        << ", e = MI->getNumOperands(); i != e; ++i)\n"
        << "        if (lowerOperand(MI->getOperand(i), MCOp))\n"
        << "          TmpInst.addOperand(MCOp);\n";
    }
    o << "      OutStreamer.EmitInstruction(TmpInst);\n"
      << "      break;\n"
      << "    }\n";
  }
  o << "  }\n  return true;\n}\n\n";
}

void PseudoLoweringEmitter::run(raw_ostream &o) {
  Record *ExpansionClass = Records.getClass("PseudoInstExpansion");
  Record *InstructionClass = Records.getClass("PseudoInstExpansion");
  assert(ExpansionClass && "PseudoInstExpansion class definition missing!");
  assert(InstructionClass && "Instruction class definition missing!");

  std::vector<Record*> Insts;
  for (std::map<std::string, Record*>::const_iterator I =
         Records.getDefs().begin(), E = Records.getDefs().end(); I != E; ++I) {
    if (I->second->isSubClassOf(ExpansionClass) &&
        I->second->isSubClassOf(InstructionClass))
      Insts.push_back(I->second);
  }

  // Process the pseudo expansion definitions, validating them as we do so.
  for (unsigned i = 0, e = Insts.size(); i != e; ++i)
    evaluateExpansion(Insts[i]);

  // Generate expansion code to lower the pseudo to an MCInst of the real
  // instruction.
  emitLoweringEmitter(o);
}