[ARM64] Split tbz/tbnz into W/X register variant
authorBradley Smith <bradley.smith@arm.com>
Mon, 19 May 2014 15:58:15 +0000 (15:58 +0000)
committerBradley Smith <bradley.smith@arm.com>
Mon, 19 May 2014 15:58:15 +0000 (15:58 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@209134 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Target/ARM64/ARM64BranchRelaxation.cpp
lib/Target/ARM64/ARM64InstrFormats.td
lib/Target/ARM64/ARM64InstrInfo.cpp
lib/Target/ARM64/ARM64InstrInfo.h
lib/Target/ARM64/ARM64InstrInfo.td
lib/Target/ARM64/AsmParser/ARM64AsmParser.cpp
lib/Target/ARM64/Disassembler/ARM64Disassembler.cpp
lib/Target/ARM64/InstPrinter/ARM64InstPrinter.cpp
test/CodeGen/ARM64/early-ifcvt.ll

index cbe97edde27ea2c3813ff8dc43c39c1cb180c95b..73be3504790ea55aea27ebaa4225413ecb7ebe94 100644 (file)
@@ -275,8 +275,10 @@ static bool isConditionalBranch(unsigned Opc) {
   switch (Opc) {
   default:
     return false;
-  case ARM64::TBZ:
-  case ARM64::TBNZ:
+  case ARM64::TBZW:
+  case ARM64::TBNZW:
+  case ARM64::TBZX:
+  case ARM64::TBNZX:
   case ARM64::CBZW:
   case ARM64::CBNZW:
   case ARM64::CBZX:
@@ -290,8 +292,10 @@ static MachineBasicBlock *getDestBlock(MachineInstr *MI) {
   switch (MI->getOpcode()) {
   default:
     assert(0 && "unexpected opcode!");
-  case ARM64::TBZ:
-  case ARM64::TBNZ:
+  case ARM64::TBZW:
+  case ARM64::TBNZW:
+  case ARM64::TBZX:
+  case ARM64::TBNZX:
     return MI->getOperand(2).getMBB();
   case ARM64::CBZW:
   case ARM64::CBNZW:
@@ -306,8 +310,10 @@ static unsigned getOppositeConditionOpcode(unsigned Opc) {
   switch (Opc) {
   default:
     assert(0 && "unexpected opcode!");
-  case ARM64::TBNZ:    return ARM64::TBZ;
-  case ARM64::TBZ:     return ARM64::TBNZ;
+  case ARM64::TBNZW:   return ARM64::TBZW;
+  case ARM64::TBNZX:   return ARM64::TBZX;
+  case ARM64::TBZW:    return ARM64::TBNZW;
+  case ARM64::TBZX:    return ARM64::TBNZX;
   case ARM64::CBNZW:   return ARM64::CBZW;
   case ARM64::CBNZX:   return ARM64::CBZX;
   case ARM64::CBZW:    return ARM64::CBNZW;
@@ -320,8 +326,10 @@ static unsigned getBranchDisplacementBits(unsigned Opc) {
   switch (Opc) {
   default:
     assert(0 && "unexpected opcode!");
-  case ARM64::TBNZ:
-  case ARM64::TBZ:
+  case ARM64::TBNZW:
+  case ARM64::TBZW:
+  case ARM64::TBNZX:
+  case ARM64::TBZX:
     return TBZDisplacementBits;
   case ARM64::CBNZW:
   case ARM64::CBZW:
@@ -379,7 +387,8 @@ bool ARM64BranchRelaxation::fixupConditionalBranch(MachineInstr *MI) {
                      << *BMI);
         BMI->getOperand(0).setMBB(DestBB);
         unsigned OpNum =
-            (MI->getOpcode() == ARM64::TBZ || MI->getOpcode() == ARM64::TBNZ)
+            (MI->getOpcode() == ARM64::TBZW || MI->getOpcode() == ARM64::TBNZW ||
+             MI->getOpcode() == ARM64::TBZX || MI->getOpcode() == ARM64::TBNZX)
                 ? 2
                 : 1;
         MI->getOperand(OpNum).setMBB(NewDest);
@@ -420,7 +429,8 @@ bool ARM64BranchRelaxation::fixupConditionalBranch(MachineInstr *MI) {
   MachineInstrBuilder MIB = BuildMI(
       MBB, DebugLoc(), TII->get(getOppositeConditionOpcode(MI->getOpcode())))
                                 .addOperand(MI->getOperand(0));
-  if (MI->getOpcode() == ARM64::TBZ || MI->getOpcode() == ARM64::TBNZ)
+  if (MI->getOpcode() == ARM64::TBZW || MI->getOpcode() == ARM64::TBNZW ||
+      MI->getOpcode() == ARM64::TBZX || MI->getOpcode() == ARM64::TBNZX)
     MIB.addOperand(MI->getOperand(1));
   if (MI->getOpcode() == ARM64::Bcc)
     invertBccCondition(MIB);
index a9bad10b31e91e6358ab1bbc52184a003be50ccf..3f9104deaf18991a2740f4370708c20a3ce1634e 100644 (file)
@@ -173,6 +173,14 @@ def CondCode : AsmOperandClass {
   let DiagnosticType = "InvalidCondCode";
 }
 
+// A 32-bit register pasrsed as 64-bit
+def GPR32as64Operand : AsmOperandClass {
+  let Name = "GPR32as64";
+}
+def GPR32as64 : RegisterOperand<GPR32> {
+  let ParserMatchClass = GPR32as64Operand;
+}
+
 // 8-bit immediate for AdvSIMD where 64-bit values of the form:
 // aaaaaaaa bbbbbbbb cccccccc dddddddd eeeeeeee ffffffff gggggggg hhhhhhhh
 // are encoded as the eight bit value 'abcdefgh'.
@@ -1037,10 +1045,37 @@ def am_tbrcond : Operand<OtherVT> {
   let ParserMatchClass = BranchTarget14Operand;
 }
 
-class TestBranch<bit op, string asm, SDNode node>
-    : I<(outs), (ins GPR64:$Rt, imm0_63:$bit_off, am_tbrcond:$target),
+// AsmOperand classes to emit (or not) special diagnostics
+def TBZImm0_31Operand : AsmOperandClass {
+  let Name = "TBZImm0_31";
+  let PredicateMethod = "isImm0_31";
+  let RenderMethod = "addImm0_31Operands";
+}
+def TBZImm32_63Operand : AsmOperandClass {
+  let Name = "Imm32_63";
+  let DiagnosticType = "InvalidImm0_63";
+}
+
+class tbz_imm0_31<AsmOperandClass matcher> : Operand<i64>, ImmLeaf<i64, [{
+  return (((uint32_t)Imm) < 32);
+}]> {
+  let ParserMatchClass = matcher;
+}
+
+def tbz_imm0_31_diag : tbz_imm0_31<Imm0_31Operand>;
+def tbz_imm0_31_nodiag : tbz_imm0_31<TBZImm0_31Operand>;
+
+def tbz_imm32_63 : Operand<i64>, ImmLeaf<i64, [{
+  return (((uint32_t)Imm) > 31) && (((uint32_t)Imm) < 64);
+}]> {
+  let ParserMatchClass = TBZImm32_63Operand;
+}
+
+class BaseTestBranch<RegisterClass regtype, Operand immtype,
+                     bit op, string asm, SDNode node>
+    : I<(outs), (ins regtype:$Rt, immtype:$bit_off, am_tbrcond:$target),
        asm, "\t$Rt, $bit_off, $target", "",
-       [(node GPR64:$Rt, imm0_63:$bit_off, bb:$target)]>,
+       [(node regtype:$Rt, immtype:$bit_off, bb:$target)]>,
       Sched<[WriteBr]> {
   let isBranch = 1;
   let isTerminator = 1;
@@ -1049,7 +1084,6 @@ class TestBranch<bit op, string asm, SDNode node>
   bits<6> bit_off;
   bits<14> target;
 
-  let Inst{31}    = bit_off{5};
   let Inst{30-25} = 0b011011;
   let Inst{24}    = op;
   let Inst{23-19} = bit_off{4-0};
@@ -1059,6 +1093,24 @@ class TestBranch<bit op, string asm, SDNode node>
   let DecoderMethod = "DecodeTestAndBranch";
 }
 
+multiclass TestBranch<bit op, string asm, SDNode node> {
+  def W : BaseTestBranch<GPR32, tbz_imm0_31_diag, op, asm, node> {
+    let Inst{31} = 0;
+  }
+
+  def X : BaseTestBranch<GPR64, tbz_imm32_63, op, asm, node> {
+    let Inst{31} = 1;
+  }
+
+  // Alias X-reg with 0-31 imm to W-Reg.
+  def : InstAlias<asm # "\t$Rd, $imm, $target",
+                  (!cast<Instruction>(NAME#"W") GPR32as64:$Rd,
+                  tbz_imm0_31_nodiag:$imm, am_tbrcond:$target), 0>;
+  def : Pat<(node GPR64:$Rn, tbz_imm0_31_diag:$imm, bb:$target),
+            (!cast<Instruction>(NAME#"W") (EXTRACT_SUBREG GPR64:$Rn, sub_32),
+            tbz_imm0_31_diag:$imm, bb:$target)>;
+}
+
 //---
 // Unconditional branch (immediate) instructions.
 //---
index e4112655f8dbdc0bf0b6cb8d6d82a81b451c1380..97194b1d479600caab70411c3e833b1b978b2f32 100644 (file)
@@ -70,8 +70,10 @@ static void parseCondBranch(MachineInstr *LastInst, MachineBasicBlock *&Target,
     Cond.push_back(MachineOperand::CreateImm(LastInst->getOpcode()));
     Cond.push_back(LastInst->getOperand(0));
     break;
-  case ARM64::TBZ:
-  case ARM64::TBNZ:
+  case ARM64::TBZW:
+  case ARM64::TBZX:
+  case ARM64::TBNZW:
+  case ARM64::TBNZX:
     Target = LastInst->getOperand(2).getMBB();
     Cond.push_back(MachineOperand::CreateImm(-1));
     Cond.push_back(MachineOperand::CreateImm(LastInst->getOpcode()));
@@ -196,11 +198,17 @@ bool ARM64InstrInfo::ReverseBranchCondition(
     case ARM64::CBNZX:
       Cond[1].setImm(ARM64::CBZX);
       break;
-    case ARM64::TBZ:
-      Cond[1].setImm(ARM64::TBNZ);
+    case ARM64::TBZW:
+      Cond[1].setImm(ARM64::TBNZW);
       break;
-    case ARM64::TBNZ:
-      Cond[1].setImm(ARM64::TBZ);
+    case ARM64::TBNZW:
+      Cond[1].setImm(ARM64::TBZW);
+      break;
+    case ARM64::TBZX:
+      Cond[1].setImm(ARM64::TBNZX);
+      break;
+    case ARM64::TBNZX:
+      Cond[1].setImm(ARM64::TBZX);
       break;
     }
   }
@@ -453,17 +461,24 @@ void ARM64InstrInfo::insertSelect(MachineBasicBlock &MBB,
     switch (Cond[1].getImm()) {
     default:
       llvm_unreachable("Unknown branch opcode in Cond");
-    case ARM64::TBZ:
+    case ARM64::TBZW:
+    case ARM64::TBZX:
       CC = ARM64CC::EQ;
       break;
-    case ARM64::TBNZ:
+    case ARM64::TBNZW:
+    case ARM64::TBNZX:
       CC = ARM64CC::NE;
       break;
     }
     // cmp reg, #foo is actually ands xzr, reg, #1<<foo.
-    BuildMI(MBB, I, DL, get(ARM64::ANDSXri), ARM64::XZR)
-        .addReg(Cond[2].getReg())
-        .addImm(ARM64_AM::encodeLogicalImmediate(1ull << Cond[3].getImm(), 64));
+    if (Cond[1].getImm() == ARM64::TBZW || Cond[1].getImm() == ARM64::TBNZW)
+      BuildMI(MBB, I, DL, get(ARM64::ANDSWri), ARM64::WZR)
+          .addReg(Cond[2].getReg())
+          .addImm(ARM64_AM::encodeLogicalImmediate(1ull << Cond[3].getImm(), 32));
+    else
+      BuildMI(MBB, I, DL, get(ARM64::ANDSXri), ARM64::XZR)
+          .addReg(Cond[2].getReg())
+          .addImm(ARM64_AM::encodeLogicalImmediate(1ull << Cond[3].getImm(), 64));
     break;
   }
   }
index a52d9ae50c7b42a134769ae51118e89f0b90062a..4bfdc882a2fdb44b61b584dd7b40cd277fa59496 100644 (file)
@@ -209,8 +209,10 @@ static inline bool isCondBranchOpcode(int Opc) {
   case ARM64::CBZX:
   case ARM64::CBNZW:
   case ARM64::CBNZX:
-  case ARM64::TBZ:
-  case ARM64::TBNZ:
+  case ARM64::TBZW:
+  case ARM64::TBZX:
+  case ARM64::TBNZW:
+  case ARM64::TBNZX:
     return true;
   default:
     return false;
index 7bc44d021146450ffec787dd280e06b0bc78609e..fa6e3f1162f49b4b0624cd266a0a5de5935b4392 100644 (file)
@@ -54,7 +54,7 @@ def SDT_ARM64Brcond  : SDTypeProfile<0, 3,
                                      [SDTCisVT<0, OtherVT>, SDTCisVT<1, i32>,
                                       SDTCisVT<2, i32>]>;
 def SDT_ARM64cbz : SDTypeProfile<0, 2, [SDTCisInt<0>, SDTCisVT<1, OtherVT>]>;
-def SDT_ARM64tbz : SDTypeProfile<0, 3, [SDTCisVT<0, i64>, SDTCisVT<1, i64>,
+def SDT_ARM64tbz : SDTypeProfile<0, 3, [SDTCisInt<0>, SDTCisInt<1>,
                                         SDTCisVT<2, OtherVT>]>;
 
 
@@ -1045,8 +1045,8 @@ defm CBNZ : CmpBranch<1, "cbnz", ARM64cbnz>;
 //===----------------------------------------------------------------------===//
 // Test-bit-and-branch instructions.
 //===----------------------------------------------------------------------===//
-def TBZ  : TestBranch<0, "tbz", ARM64tbz>;
-def TBNZ : TestBranch<1, "tbnz", ARM64tbnz>;
+defm TBZ  : TestBranch<0, "tbz", ARM64tbz>;
+defm TBNZ : TestBranch<1, "tbnz", ARM64tbnz>;
 
 //===----------------------------------------------------------------------===//
 // Unconditional branch (immediate) instructions.
index ad9c7562adb73fe039938c56e3418643f2d5f800..cc301f60ede88ce545130163199f798816cecc35 100644 (file)
@@ -563,6 +563,15 @@ public:
     int64_t Val = MCE->getValue();
     return (Val >= 0 && Val < 65536);
   }
+  bool isImm32_63() const {
+    if (!isImm())
+      return false;
+    const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(getImm());
+    if (!MCE)
+      return false;
+    int64_t Val = MCE->getValue();
+    return (Val >= 32 && Val < 64);
+  }
   bool isLogicalImm32() const {
     if (!isImm())
       return false;
@@ -812,6 +821,10 @@ public:
     return Kind == k_Register && Reg.isVector &&
       ARM64MCRegisterClasses[ARM64::FPR128_loRegClassID].contains(Reg.RegNum);
   }
+  bool isGPR32as64() const {
+    return Kind == k_Register && !Reg.isVector &&
+      ARM64MCRegisterClasses[ARM64::GPR64RegClassID].contains(Reg.RegNum);
+  }
 
   /// Is this a vector list with the type implicit (presumably attached to the
   /// instruction itself)?
@@ -1188,6 +1201,17 @@ public:
     Inst.addOperand(MCOperand::CreateReg(getReg()));
   }
 
+  void addGPR32as64Operands(MCInst &Inst, unsigned N) const {
+    assert(N == 1 && "Invalid number of operands!");
+    assert(ARM64MCRegisterClasses[ARM64::GPR64RegClassID].contains(getReg()));
+
+    const MCRegisterInfo *RI = Ctx.getRegisterInfo();
+    uint32_t Reg = RI->getRegClass(ARM64::GPR32RegClassID).getRegister(
+        RI->getEncodingValue(getReg()));
+
+    Inst.addOperand(MCOperand::CreateReg(Reg));
+  }
+
   void addVectorReg64Operands(MCInst &Inst, unsigned N) const {
     assert(N == 1 && "Invalid number of operands!");
     assert(ARM64MCRegisterClasses[ARM64::FPR128RegClassID].contains(getReg()));
@@ -1408,6 +1432,13 @@ public:
     Inst.addOperand(MCOperand::CreateImm(MCE->getValue()));
   }
 
+  void addImm32_63Operands(MCInst &Inst, unsigned N) const {
+    assert(N == 1 && "Invalid number of operands!");
+    const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(getImm());
+    assert(MCE && "Invalid constant immediate operand!");
+    Inst.addOperand(MCOperand::CreateImm(MCE->getValue()));
+  }
+
   void addLogicalImm32Operands(MCInst &Inst, unsigned N) const {
     assert(N == 1 && "Invalid number of operands!");
     const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(getImm());
@@ -3952,27 +3983,6 @@ bool ARM64AsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
       }
     }
   }
-  // FIXME: Horrible hack for tbz and tbnz with Wn register operand.
-  //        InstAlias can't quite handle this since the reg classes aren't
-  //        subclasses.
-  if (NumOperands == 4 && (Tok == "tbz" || Tok == "tbnz")) {
-    ARM64Operand *Op = static_cast<ARM64Operand *>(Operands[2]);
-    if (Op->isImm()) {
-      if (const MCConstantExpr *OpCE = dyn_cast<MCConstantExpr>(Op->getImm())) {
-        if (OpCE->getValue() < 32) {
-          // The source register can be Wn here, but the matcher expects a
-          // GPR64. Twiddle it here if necessary.
-          ARM64Operand *Op = static_cast<ARM64Operand *>(Operands[1]);
-          if (Op->isReg()) {
-            unsigned Reg = getXRegFromWReg(Op->getReg());
-            Operands[1] = ARM64Operand::CreateReg(
-                Reg, false, Op->getStartLoc(), Op->getEndLoc(), getContext());
-            delete Op;
-          }
-        }
-      }
-    }
-  }
   // FIXME: Horrible hack for sxtw and uxtw with Wn src and Xd dst operands.
   //        InstAlias can't quite handle this since the reg classes aren't
   //        subclasses.
index d14e3a86f8f35f61b1bda1d74311d28822e683ba..92eabcf2b4e07ee1c0a1ebf0637d5591dde01df6 100644 (file)
@@ -1512,7 +1512,10 @@ static DecodeStatus DecodeTestAndBranch(llvm::MCInst &Inst, uint32_t insn,
   if (dst & (1 << (14 - 1)))
     dst |= ~((1LL << 14) - 1);
 
-  DecodeGPR64RegisterClass(Inst, Rt, Addr, Decoder);
+  if (fieldFromInstruction(insn, 31, 1) == 0)
+    DecodeGPR32RegisterClass(Inst, Rt, Addr, Decoder);
+  else
+    DecodeGPR64RegisterClass(Inst, Rt, Addr, Decoder);
   Inst.addOperand(MCOperand::CreateImm(bit));
   if (!Dis->tryAddingSymbolicOperand(Inst, dst << 2, Addr, true, 0, 4))
     Inst.addOperand(MCOperand::CreateImm(dst));
index ebdbd13596a2121aba6cc10fc4f55976971f9013..adfcb46ac403ac5f9a1fb63c98a94fd8d7a39480 100644 (file)
@@ -63,18 +63,6 @@ void ARM64InstPrinter::printInst(const MCInst *MI, raw_ostream &O,
       return;
     }
 
-  // TBZ/TBNZ should print the register operand as a Wreg if the bit
-  // number is < 32.
-  if ((Opcode == ARM64::TBNZ || Opcode == ARM64::TBZ) &&
-      MI->getOperand(1).getImm() < 32) {
-    MCInst newMI = *MI;
-    unsigned Reg = MI->getOperand(0).getReg();
-    newMI.getOperand(0).setReg(getWRegFromXReg(Reg));
-    printInstruction(&newMI, O);
-    printAnnotation(O, Annot);
-    return;
-  }
-
   // SBFM/UBFM should print to a nicer aliased form if possible.
   if (Opcode == ARM64::SBFMXri || Opcode == ARM64::SBFMWri ||
       Opcode == ARM64::UBFMXri || Opcode == ARM64::UBFMWri) {
index a5c1e26c619a483a9b79f9ba95ead6c1ef3ca788..17d783a488f3a630bce3241ea64d1f6f2d89966f 100644 (file)
@@ -322,7 +322,7 @@ done:
 }
 
 ; CHECK: tbnz_32
-; CHECK: {{ands.*xzr,|tst}} x2, #0x80
+; CHECK: {{ands.*xzr,|tst}} w2, #0x80
 ; CHECK-NEXT: csel w0, w1, w0, ne
 ; CHECK-NEXT: ret
 define i32 @tbnz_32(i32 %x, i32 %y, i32 %c) nounwind ssp {
@@ -358,7 +358,7 @@ done:
 }
 
 ; CHECK: tbz_32
-; CHECK: {{ands.*xzr,|tst}} x2, #0x80
+; CHECK: {{ands.*xzr,|tst}} w2, #0x80
 ; CHECK-NEXT: csel w0, w1, w0, eq
 ; CHECK-NEXT: ret
 define i32 @tbz_32(i32 %x, i32 %y, i32 %c) nounwind ssp {