[llvm] r209134 - [ARM64] Split tbz/tbnz into W/X register variant
Bradley Smith
bradley.smith at arm.com
Mon May 19 08:58:16 PDT 2014
Author: brasmi01
Date: Mon May 19 10:58:15 2014
New Revision: 209134
URL: http://llvm.org/viewvc/llvm-project?rev=209134&view=rev
Log:
[ARM64] Split tbz/tbnz into W/X register variant
Modified:
llvm/trunk/lib/Target/ARM64/ARM64BranchRelaxation.cpp
llvm/trunk/lib/Target/ARM64/ARM64InstrFormats.td
llvm/trunk/lib/Target/ARM64/ARM64InstrInfo.cpp
llvm/trunk/lib/Target/ARM64/ARM64InstrInfo.h
llvm/trunk/lib/Target/ARM64/ARM64InstrInfo.td
llvm/trunk/lib/Target/ARM64/AsmParser/ARM64AsmParser.cpp
llvm/trunk/lib/Target/ARM64/Disassembler/ARM64Disassembler.cpp
llvm/trunk/lib/Target/ARM64/InstPrinter/ARM64InstPrinter.cpp
llvm/trunk/test/CodeGen/ARM64/early-ifcvt.ll
Modified: llvm/trunk/lib/Target/ARM64/ARM64BranchRelaxation.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM64/ARM64BranchRelaxation.cpp?rev=209134&r1=209133&r2=209134&view=diff
==============================================================================
--- llvm/trunk/lib/Target/ARM64/ARM64BranchRelaxation.cpp (original)
+++ llvm/trunk/lib/Target/ARM64/ARM64BranchRelaxation.cpp Mon May 19 10:58:15 2014
@@ -275,8 +275,10 @@ static bool isConditionalBranch(unsigned
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(M
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 getOppositeConditionOpco
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 getBranchDisplacementBit
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::fixupConditi
<< *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::fixupConditi
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);
Modified: llvm/trunk/lib/Target/ARM64/ARM64InstrFormats.td
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM64/ARM64InstrFormats.td?rev=209134&r1=209133&r2=209134&view=diff
==============================================================================
--- llvm/trunk/lib/Target/ARM64/ARM64InstrFormats.td (original)
+++ llvm/trunk/lib/Target/ARM64/ARM64InstrFormats.td Mon May 19 10:58:15 2014
@@ -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, SDN
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, SDN
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.
//---
Modified: llvm/trunk/lib/Target/ARM64/ARM64InstrInfo.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM64/ARM64InstrInfo.cpp?rev=209134&r1=209133&r2=209134&view=diff
==============================================================================
--- llvm/trunk/lib/Target/ARM64/ARM64InstrInfo.cpp (original)
+++ llvm/trunk/lib/Target/ARM64/ARM64InstrInfo.cpp Mon May 19 10:58:15 2014
@@ -70,8 +70,10 @@ static void parseCondBranch(MachineInstr
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::ReverseBranchCondit
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(Machin
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;
}
}
Modified: llvm/trunk/lib/Target/ARM64/ARM64InstrInfo.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM64/ARM64InstrInfo.h?rev=209134&r1=209133&r2=209134&view=diff
==============================================================================
--- llvm/trunk/lib/Target/ARM64/ARM64InstrInfo.h (original)
+++ llvm/trunk/lib/Target/ARM64/ARM64InstrInfo.h Mon May 19 10:58:15 2014
@@ -209,8 +209,10 @@ static inline bool isCondBranchOpcode(in
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;
Modified: llvm/trunk/lib/Target/ARM64/ARM64InstrInfo.td
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM64/ARM64InstrInfo.td?rev=209134&r1=209133&r2=209134&view=diff
==============================================================================
--- llvm/trunk/lib/Target/ARM64/ARM64InstrInfo.td (original)
+++ llvm/trunk/lib/Target/ARM64/ARM64InstrInfo.td Mon May 19 10:58:15 2014
@@ -54,7 +54,7 @@ def SDT_ARM64Brcond : SDTypeProfile<0,
[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", ARM64cb
//===----------------------------------------------------------------------===//
// 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.
Modified: llvm/trunk/lib/Target/ARM64/AsmParser/ARM64AsmParser.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM64/AsmParser/ARM64AsmParser.cpp?rev=209134&r1=209133&r2=209134&view=diff
==============================================================================
--- llvm/trunk/lib/Target/ARM64/AsmParser/ARM64AsmParser.cpp (original)
+++ llvm/trunk/lib/Target/ARM64/AsmParser/ARM64AsmParser.cpp Mon May 19 10:58:15 2014
@@ -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());
@@ -3951,27 +3982,6 @@ bool ARM64AsmParser::MatchAndEmitInstruc
}
}
}
- }
- // 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
Modified: llvm/trunk/lib/Target/ARM64/Disassembler/ARM64Disassembler.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM64/Disassembler/ARM64Disassembler.cpp?rev=209134&r1=209133&r2=209134&view=diff
==============================================================================
--- llvm/trunk/lib/Target/ARM64/Disassembler/ARM64Disassembler.cpp (original)
+++ llvm/trunk/lib/Target/ARM64/Disassembler/ARM64Disassembler.cpp Mon May 19 10:58:15 2014
@@ -1512,7 +1512,10 @@ static DecodeStatus DecodeTestAndBranch(
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));
Modified: llvm/trunk/lib/Target/ARM64/InstPrinter/ARM64InstPrinter.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM64/InstPrinter/ARM64InstPrinter.cpp?rev=209134&r1=209133&r2=209134&view=diff
==============================================================================
--- llvm/trunk/lib/Target/ARM64/InstPrinter/ARM64InstPrinter.cpp (original)
+++ llvm/trunk/lib/Target/ARM64/InstPrinter/ARM64InstPrinter.cpp Mon May 19 10:58:15 2014
@@ -63,18 +63,6 @@ void ARM64InstPrinter::printInst(const M
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) {
Modified: llvm/trunk/test/CodeGen/ARM64/early-ifcvt.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/ARM64/early-ifcvt.ll?rev=209134&r1=209133&r2=209134&view=diff
==============================================================================
--- llvm/trunk/test/CodeGen/ARM64/early-ifcvt.ll (original)
+++ llvm/trunk/test/CodeGen/ARM64/early-ifcvt.ll Mon May 19 10:58:15 2014
@@ -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 {
More information about the llvm-commits
mailing list