Index: lib/Target/ARM64/ARM64BranchRelaxation.cpp =================================================================== --- lib/Target/ARM64/ARM64BranchRelaxation.cpp +++ lib/Target/ARM64/ARM64BranchRelaxation.cpp @@ -275,8 +275,10 @@ 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 @@ 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 @@ 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 @@ 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 @@ << *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 @@ 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: lib/Target/ARM64/ARM64InstrFormats.td =================================================================== --- lib/Target/ARM64/ARM64InstrFormats.td +++ lib/Target/ARM64/ARM64InstrFormats.td @@ -173,6 +173,14 @@ let DiagnosticType = "InvalidCondCode"; } +// A 32-bit register pasrsed as 64-bit +def GPR32as64Operand : AsmOperandClass { + let Name = "GPR32as64"; +} +def GPR32as64 : RegisterOperand { + 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 @@ let ParserMatchClass = BranchTarget14Operand; } -class TestBranch - : 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 : Operand, ImmLeaf { + let ParserMatchClass = matcher; +} + +def tbz_imm0_31_diag : tbz_imm0_31; +def tbz_imm0_31_nodiag : tbz_imm0_31; + +def tbz_imm32_63 : Operand, ImmLeaf { + let ParserMatchClass = TBZImm32_63Operand; +} + +class BaseTestBranch + : 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 @@ 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,21 @@ let DecoderMethod = "DecodeTestAndBranch"; } +multiclass TestBranch { + def W : BaseTestBranch { + let Inst{31} = 0; + } + + def X : BaseTestBranch { + let Inst{31} = 1; + } + + // Alias X-reg with 0-31 imm to W-Reg. + def : InstAlias(NAME#"W") GPR32as64:$Rd, + tbz_imm0_31_nodiag:$imm, am_tbrcond:$target), 0>; +} + //--- // Unconditional branch (immediate) instructions. //--- Index: lib/Target/ARM64/ARM64InstrInfo.h =================================================================== --- lib/Target/ARM64/ARM64InstrInfo.h +++ lib/Target/ARM64/ARM64InstrInfo.h @@ -206,8 +206,10 @@ 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: lib/Target/ARM64/ARM64InstrInfo.cpp =================================================================== --- lib/Target/ARM64/ARM64InstrInfo.cpp +++ lib/Target/ARM64/ARM64InstrInfo.cpp @@ -70,8 +70,10 @@ 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 @@ 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,10 +461,12 @@ 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; } Index: lib/Target/ARM64/ARM64InstrInfo.td =================================================================== --- lib/Target/ARM64/ARM64InstrInfo.td +++ lib/Target/ARM64/ARM64InstrInfo.td @@ -54,7 +54,7 @@ [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>]>; @@ -1029,8 +1029,8 @@ //===----------------------------------------------------------------------===// // 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: lib/Target/ARM64/AsmParser/ARM64AsmParser.cpp =================================================================== --- lib/Target/ARM64/AsmParser/ARM64AsmParser.cpp +++ lib/Target/ARM64/AsmParser/ARM64AsmParser.cpp @@ -563,6 +563,15 @@ int64_t Val = MCE->getValue(); return (Val >= 0 && Val < 65536); } + bool isImm32_63() const { + if (!isImm()) + return false; + const MCConstantExpr *MCE = dyn_cast(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 @@ 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 @@ 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 @@ 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(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(getImm()); @@ -3952,27 +3983,6 @@ } } } - // 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(Operands[2]); - if (Op->isImm()) { - if (const MCConstantExpr *OpCE = dyn_cast(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(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: lib/Target/ARM64/Disassembler/ARM64Disassembler.cpp =================================================================== --- lib/Target/ARM64/Disassembler/ARM64Disassembler.cpp +++ lib/Target/ARM64/Disassembler/ARM64Disassembler.cpp @@ -1512,7 +1512,10 @@ 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: lib/Target/ARM64/InstPrinter/ARM64InstPrinter.cpp =================================================================== --- lib/Target/ARM64/InstPrinter/ARM64InstPrinter.cpp +++ lib/Target/ARM64/InstPrinter/ARM64InstPrinter.cpp @@ -63,18 +63,6 @@ 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: test/CodeGen/AArch64/analyze-branch.ll =================================================================== --- test/CodeGen/AArch64/analyze-branch.ll +++ test/CodeGen/AArch64/analyze-branch.ll @@ -147,7 +147,7 @@ %tst = icmp eq i32 %bit, 0 br i1 %tst, label %true, label %false, !prof !0 -; CHECK: tbnz {{w[0-9]+}}, #15, [[FALSE:.LBB[0-9]+_[0-9]+]] +; CHECK: tbnz {{[wx][0-9]+}}, #15, [[FALSE:.LBB[0-9]+_[0-9]+]] ; CHECK-NEXT: // BB# ; CHECK-NEXT: bl test_true @@ -192,7 +192,7 @@ %tst = icmp ne i32 %bit, 0 br i1 %tst, label %true, label %false, !prof !0 -; CHECK: tbz {{w[0-9]+}}, #15, [[FALSE:.LBB[0-9]+_[0-9]+]] +; CHECK: tbz {{[wx][0-9]+}}, #15, [[FALSE:.LBB[0-9]+_[0-9]+]] ; CHECK-NEXT: // BB# ; CHECK-NEXT: bl test_true Index: test/CodeGen/AArch64/directcond.ll =================================================================== --- test/CodeGen/AArch64/directcond.ll +++ test/CodeGen/AArch64/directcond.ll @@ -51,7 +51,7 @@ define i32 @test_brcond(i1 %bit) { ; CHECK-LABEL: test_brcond: br i1 %bit, label %true, label %false -; CHECK: tbz {{w[0-9]+}}, #0, {{.?LBB}} +; CHECK: tbz {{[wx][0-9]+}}, #0, {{.?LBB}} true: ret i32 0 Index: test/CodeGen/AArch64/tst-br.ll =================================================================== --- test/CodeGen/AArch64/tst-br.ll +++ test/CodeGen/AArch64/tst-br.ll @@ -16,13 +16,13 @@ %tbit0 = and i32 %val, 32768 %tst0 = icmp ne i32 %tbit0, 0 br i1 %tst0, label %test1, label %end1 -; CHECK: tbz {{w[0-9]+}}, #15, [[LBL_end1:.?LBB0_[0-9]+]] +; CHECK: tbz {{[wx][0-9]+}}, #15, [[LBL_end1:.?LBB0_[0-9]+]] test1: %tbit1 = and i32 %val, 4096 %tst1 = icmp ne i32 %tbit1, 0 br i1 %tst1, label %test2, label %end1 -; CHECK: tbz {{w[0-9]+}}, #12, [[LBL_end1]] +; CHECK: tbz {{[wx][0-9]+}}, #12, [[LBL_end1]] test2: %tbit2 = and i64 %val64, 32768