generalize alias support to allow the result of an alias to
authorChris Lattner <sabre@nondot.org>
Sat, 6 Nov 2010 19:25:43 +0000 (19:25 +0000)
committerChris Lattner <sabre@nondot.org>
Sat, 6 Nov 2010 19:25:43 +0000 (19:25 +0000)
add fixed immediate values.  Move the aad and aam aliases to
use this, and document it.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@118350 91177308-0d34-0410-b5e6-96231b3b80d8

docs/CodeGenerator.html
lib/Target/X86/AsmParser/X86AsmParser.cpp
lib/Target/X86/X86InstrInfo.td
utils/TableGen/AsmMatcherEmitter.cpp
utils/TableGen/CodeGenInstruction.cpp
utils/TableGen/CodeGenInstruction.h

index d4e932a969fe9deb84ca7a6e375207a39a9164d9..376b91c8f1a621d8054b3a6cee4fb56ced081184 100644 (file)
@@ -1998,7 +1998,15 @@ def : InstAlias&lt;"clrq $reg", (XOR64rr GR64:$reg, GR64:$reg)&gt;;
 <p>This example also shows that tied operands are only listed once.  In the X86
 backend, XOR8rr has two input GR8's and one output GR8 (where an input is tied
 to the output).  InstAliases take a flattened operand list without duplicates
-for tied operands.</p>
+for tied operands.  The result of an instruction alias can also use immediates,
+which are added as simple immediate operands in the result, for example:</p>
+
+<div class="doc_code">
+<pre>
+def : InstAlias&lt;"aad", (AAD8i8 10)&gt;;
+</pre>
+</div>
+
 
 <p>Instruction aliases can also have a Requires clause to make them
 subtarget specific.</p>
index 4ab25cf4bf8eb43e4f75bc59d1090f07f5b1a9cd..9ab6b56c8f01b27b74635ccd7c3a0d910c505702 100644 (file)
@@ -752,6 +752,22 @@ ParseInstruction(StringRef Name, SMLoc NameLoc,
   if (getLexer().is(AsmToken::EndOfStatement))
     Parser.Lex(); // Consume the EndOfStatement
 
+  // This is a terrible hack to handle "out[bwl]? %al, (%dx)" ->
+  // "outb %al, %dx".  Out doesn't take a memory form, but this is a widely
+  // documented form in various unofficial manuals, so a lot of code uses it.
+  if ((Name == "outb" || Name == "outw" || Name == "outl" || Name == "out") &&
+      Operands.size() == 3) {
+    X86Operand &Op = *(X86Operand*)Operands.back();
+    if (Op.isMem() && Op.Mem.SegReg == 0 &&
+        isa<MCConstantExpr>(Op.Mem.Disp) &&
+        cast<MCConstantExpr>(Op.Mem.Disp)->getValue() == 0 &&
+        Op.Mem.BaseReg == MatchRegisterName("dx") && Op.Mem.IndexReg == 0) {
+      SMLoc Loc = Op.getEndLoc();
+      Operands.back() = X86Operand::CreateReg(Op.Mem.BaseReg, Loc, Loc);
+      delete &Op;
+    }
+  }
+  
   // FIXME: Hack to handle recognize s{hr,ar,hl} $1, <op>.  Canonicalize to
   // "shift <op>".
   if ((Name.startswith("shr") || Name.startswith("sar") ||
@@ -781,20 +797,6 @@ ParseInstruction(StringRef Name, SMLoc NameLoc,
                     X86Operand::CreateImm(One, NameLoc, NameLoc));
   }
 
-  // FIXME: Hack to handle "out[bwl]? %al, (%dx)" -> "outb %al, %dx".
-  if ((Name == "outb" || Name == "outw" || Name == "outl" || Name == "out") &&
-      Operands.size() == 3) {
-    X86Operand &Op = *(X86Operand*)Operands.back();
-    if (Op.isMem() && Op.Mem.SegReg == 0 &&
-        isa<MCConstantExpr>(Op.Mem.Disp) &&
-        cast<MCConstantExpr>(Op.Mem.Disp)->getValue() == 0 &&
-        Op.Mem.BaseReg == MatchRegisterName("dx") && Op.Mem.IndexReg == 0) {
-      SMLoc Loc = Op.getEndLoc();
-      Operands.back() = X86Operand::CreateReg(Op.Mem.BaseReg, Loc, Loc);
-      delete &Op;
-    }
-  }
-
   // FIXME: Hack to handle "f{mul*,add*,sub*,div*} $op, st(0)" the same as
   // "f{mul*,add*,sub*,div*} $op"
   if ((Name.startswith("fmul") || Name.startswith("fadd") ||
@@ -839,13 +841,6 @@ ParseInstruction(StringRef Name, SMLoc NameLoc,
                                              NameLoc, NameLoc));
   }
 
-  // FIXME: Hack to handle recognize "aa[dm]" -> "aa[dm] $0xA".
-  if ((Name.startswith("aad") || Name.startswith("aam")) &&
-      Operands.size() == 1) {
-    const MCExpr *A = MCConstantExpr::Create(0xA, getParser().getContext());
-    Operands.push_back(X86Operand::CreateImm(A, NameLoc, NameLoc));
-  }
-
   return false;
 }
 
index 125da18600e5af0dee8f2c4d06537d1361d0b896..7fec0141ce41bd3a3241d4458032162eba52a866 100644 (file)
@@ -1367,6 +1367,10 @@ defm : IntegerCondCodeMnemonicAlias<"cmov", "q">;
 // Assembler Instruction Aliases
 //===----------------------------------------------------------------------===//
 
+// aad/aam default to base 10 if no operand is specified.
+def : InstAlias<"aad", (AAD8i8 10)>;
+def : InstAlias<"aam", (AAM8i8 10)>;
+
 // clr aliases.
 def : InstAlias<"clrb $reg", (XOR8rr  GR8 :$reg, GR8 :$reg)>;
 def : InstAlias<"clrw $reg", (XOR16rr GR16:$reg, GR16:$reg)>;
index 23d370c506e3fd91271b98d72a661b479f7c7fa4..46866140eb48a00572aa828964e076c78bde0eb0 100644 (file)
@@ -270,7 +270,11 @@ struct MatchableInfo {
       
       /// TiedOperand - This represents a result operand that is a duplicate of
       /// a previous result operand.
-      TiedOperand
+      TiedOperand,
+      
+      /// ImmOperand - This represents an immediate value that is dumped into
+      /// the operand.
+      ImmOperand
     } Kind;
     
     union {
@@ -281,6 +285,9 @@ struct MatchableInfo {
       /// TiedOperandNum - This is the (earlier) result operand that should be
       /// copied from.
       unsigned TiedOperandNum;
+      
+      /// ImmVal - This is the immediate value added to the instruction.
+      int64_t ImmVal;
     };
     
     /// OpInfo - This is the information about the instruction operand that is
@@ -304,6 +311,15 @@ struct MatchableInfo {
       X.OpInfo = Op;
       return X;
     }
+    
+    static ResOperand getImmOp(int64_t Val,
+                               const CGIOperandList::OperandInfo *Op) {
+      ResOperand X;
+      X.Kind = ImmOperand;
+      X.ImmVal = Val;
+      X.OpInfo = Op;
+      return X;
+    }
   };
 
   /// TheDef - This is the definition of the instruction or InstAlias that this
@@ -538,16 +554,6 @@ void MatchableInfo::dump() {
     AsmOperand &Op = AsmOperands[i];
     errs() << "  op[" << i << "] = " << Op.Class->ClassName << " - ";
     errs() << '\"' << Op.Token << "\"\n";
-#if 0
-    if (!Op.OperandInfo) {
-      errs() << "(singleton register)\n";
-      continue;
-    }
-
-    const CGIOperandList::OperandInfo &OI = *Op.OperandInfo;
-    errs() << OI.Name << " " << OI.Rec->getName()
-           << " (" << OI.MIOperandNo << ", " << OI.MINumOperands << ")\n";
-#endif
   }
 }
 
@@ -1174,7 +1180,8 @@ void AsmMatcherInfo::BuildAliasOperandReference(MatchableInfo *II,
    
   // Set up the operand class.
   for (unsigned i = 0, e = CGA.ResultOperands.size(); i != e; ++i)
-    if (CGA.ResultOperands[i].Name == OperandName) {
+    if (CGA.ResultOperands[i].isRecord() &&
+        CGA.ResultOperands[i].getName() == OperandName) {
       // It's safe to go with the first one we find, because CodeGenInstAlias
       // validates that all operands with the same name have the same record.
       unsigned ResultIdx =CGA.getResultInstOperandIndexForResultOperandIndex(i);
@@ -1236,15 +1243,22 @@ void MatchableInfo::BuildAliasResultOperands() {
     
     // Find out what operand from the asmparser that this MCInst operand comes
     // from.
-    int SrcOperand = FindAsmOperandNamed(CGA.ResultOperands[AliasOpNo++].Name);
-    if (SrcOperand != -1) {
-      ResOperands.push_back(ResOperand::getRenderedOp(SrcOperand, &OpInfo));
-      continue;
+    if (CGA.ResultOperands[AliasOpNo].isRecord()) {
+      StringRef Name = CGA.ResultOperands[AliasOpNo++].getName();
+      int SrcOperand = FindAsmOperandNamed(Name);
+      if (SrcOperand != -1) {
+        ResOperands.push_back(ResOperand::getRenderedOp(SrcOperand, &OpInfo));
+        continue;
+      }
+      
+      throw TGError(TheDef->getLoc(), "Instruction '" +
+                    TheDef->getName() + "' has operand '" + OpInfo.Name +
+                    "' that doesn't appear in asm string!");
     }
     
-    throw TGError(TheDef->getLoc(), "Instruction '" +
-                  TheDef->getName() + "' has operand '" + OpInfo.Name +
-                  "' that doesn't appear in asm string!");
+    int64_t ImmVal = CGA.ResultOperands[AliasOpNo++].getImm();
+    ResOperands.push_back(ResOperand::getImmOp(ImmVal, &OpInfo));
+    continue;
   }
 }
 
@@ -1291,7 +1305,6 @@ static void EmitConvertToMCInst(CodeGenTarget &Target,
 
       // Generate code to populate each result operand.
       switch (OpInfo.Kind) {
-      default: assert(0 && "Unknown result operand kind");
       case MatchableInfo::ResOperand::RenderAsmOperand: {
         // This comes from something we parsed.
         MatchableInfo::AsmOperand &Op = II.AsmOperands[OpInfo.AsmOperandNum];
@@ -1322,6 +1335,12 @@ static void EmitConvertToMCInst(CodeGenTarget &Target,
         Signature += "__Tie" + utostr(TiedOp);
         break;
       }
+      case MatchableInfo::ResOperand::ImmOperand: {
+        int64_t Val = OpInfo.ImmVal;
+        CaseOS << "    Inst.addOperand(MCOperand::CreateImm(" << Val << "));\n";
+        Signature += "__imm" + itostr(Val);
+        break;
+      }
       }
     }
     
index 40d4206b30ee9e4d98fd2a608386f82e4b724b86..924608cbf0fec6f74c83539ab390f85221c02337 100644 (file)
@@ -449,6 +449,21 @@ CodeGenInstAlias::CodeGenInstAlias(Record *R, CodeGenTarget &T) : TheDef(R) {
       ++AliasOpNo;
       continue;
     }
+    
+    if (IntInit *II = dynamic_cast<IntInit*>(Arg)) {
+      // Integer arguments can't have names.
+      if (!Result->getArgName(AliasOpNo).empty())
+        throw TGError(R->getLoc(), "result argument #" + utostr(AliasOpNo) +
+                      " must not have a name!");
+      if (ResultInst->Operands[i].MINumOperands != 1 ||
+          !ResultInst->Operands[i].Rec->isSubClassOf("Operand"))
+        throw TGError(R->getLoc(), "invalid argument class " + 
+                      ResultInst->Operands[i].Rec->getName() +
+                      " for integer result operand!");
+      ResultOperands.push_back(ResultOperand(II->getValue()));
+      ++AliasOpNo;
+      continue;
+    }
 
     throw TGError(R->getLoc(), "result of inst alias has unknown operand type");
   }
index f5b22396360c34830ff52d2c9c3148d16bb37a24..ac593dfb17dcdbc51e57bcfdc905c6a5b9bf7585 100644 (file)
@@ -267,10 +267,26 @@ namespace llvm {
     
     
     struct ResultOperand {
+    private:
       StringRef Name;
       Record *R;
       
-      ResultOperand(StringRef N, Record *r) : Name(N), R(r) {}
+      int64_t Imm;
+    public:      
+      enum {
+        K_Record,
+        K_Imm
+      } Kind;
+      
+      ResultOperand(StringRef N, Record *r) : Name(N), R(r), Kind(K_Record) {}
+      ResultOperand(int64_t I) : Imm(I), Kind(K_Imm) {}
+
+      bool isRecord() const { return Kind == K_Record; }
+      bool isImm() const { return Kind == K_Imm; }
+      
+      StringRef getName() const { assert(isRecord()); return Name; }
+      Record *getRecord() const { assert(isRecord()); return R; }
+      int64_t getImm() const { assert(isImm()); return Imm; }
     };
     
     /// ResultOperands - The decoded operands for the result instruction.