mirror of
https://github.com/RPCS3/llvm.git
synced 2025-01-02 17:58:26 +00:00
[ARM64] Split tbz/tbnz into W/X register variant
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@209134 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
3f19ce848d
commit
07df0ca6c9
@ -275,8 +275,10 @@ static bool isConditionalBranch(unsigned Opc) {
|
|||||||
switch (Opc) {
|
switch (Opc) {
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
case ARM64::TBZ:
|
case ARM64::TBZW:
|
||||||
case ARM64::TBNZ:
|
case ARM64::TBNZW:
|
||||||
|
case ARM64::TBZX:
|
||||||
|
case ARM64::TBNZX:
|
||||||
case ARM64::CBZW:
|
case ARM64::CBZW:
|
||||||
case ARM64::CBNZW:
|
case ARM64::CBNZW:
|
||||||
case ARM64::CBZX:
|
case ARM64::CBZX:
|
||||||
@ -290,8 +292,10 @@ static MachineBasicBlock *getDestBlock(MachineInstr *MI) {
|
|||||||
switch (MI->getOpcode()) {
|
switch (MI->getOpcode()) {
|
||||||
default:
|
default:
|
||||||
assert(0 && "unexpected opcode!");
|
assert(0 && "unexpected opcode!");
|
||||||
case ARM64::TBZ:
|
case ARM64::TBZW:
|
||||||
case ARM64::TBNZ:
|
case ARM64::TBNZW:
|
||||||
|
case ARM64::TBZX:
|
||||||
|
case ARM64::TBNZX:
|
||||||
return MI->getOperand(2).getMBB();
|
return MI->getOperand(2).getMBB();
|
||||||
case ARM64::CBZW:
|
case ARM64::CBZW:
|
||||||
case ARM64::CBNZW:
|
case ARM64::CBNZW:
|
||||||
@ -306,8 +310,10 @@ static unsigned getOppositeConditionOpcode(unsigned Opc) {
|
|||||||
switch (Opc) {
|
switch (Opc) {
|
||||||
default:
|
default:
|
||||||
assert(0 && "unexpected opcode!");
|
assert(0 && "unexpected opcode!");
|
||||||
case ARM64::TBNZ: return ARM64::TBZ;
|
case ARM64::TBNZW: return ARM64::TBZW;
|
||||||
case ARM64::TBZ: return ARM64::TBNZ;
|
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::CBNZW: return ARM64::CBZW;
|
||||||
case ARM64::CBNZX: return ARM64::CBZX;
|
case ARM64::CBNZX: return ARM64::CBZX;
|
||||||
case ARM64::CBZW: return ARM64::CBNZW;
|
case ARM64::CBZW: return ARM64::CBNZW;
|
||||||
@ -320,8 +326,10 @@ static unsigned getBranchDisplacementBits(unsigned Opc) {
|
|||||||
switch (Opc) {
|
switch (Opc) {
|
||||||
default:
|
default:
|
||||||
assert(0 && "unexpected opcode!");
|
assert(0 && "unexpected opcode!");
|
||||||
case ARM64::TBNZ:
|
case ARM64::TBNZW:
|
||||||
case ARM64::TBZ:
|
case ARM64::TBZW:
|
||||||
|
case ARM64::TBNZX:
|
||||||
|
case ARM64::TBZX:
|
||||||
return TBZDisplacementBits;
|
return TBZDisplacementBits;
|
||||||
case ARM64::CBNZW:
|
case ARM64::CBNZW:
|
||||||
case ARM64::CBZW:
|
case ARM64::CBZW:
|
||||||
@ -379,7 +387,8 @@ bool ARM64BranchRelaxation::fixupConditionalBranch(MachineInstr *MI) {
|
|||||||
<< *BMI);
|
<< *BMI);
|
||||||
BMI->getOperand(0).setMBB(DestBB);
|
BMI->getOperand(0).setMBB(DestBB);
|
||||||
unsigned OpNum =
|
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
|
? 2
|
||||||
: 1;
|
: 1;
|
||||||
MI->getOperand(OpNum).setMBB(NewDest);
|
MI->getOperand(OpNum).setMBB(NewDest);
|
||||||
@ -420,7 +429,8 @@ bool ARM64BranchRelaxation::fixupConditionalBranch(MachineInstr *MI) {
|
|||||||
MachineInstrBuilder MIB = BuildMI(
|
MachineInstrBuilder MIB = BuildMI(
|
||||||
MBB, DebugLoc(), TII->get(getOppositeConditionOpcode(MI->getOpcode())))
|
MBB, DebugLoc(), TII->get(getOppositeConditionOpcode(MI->getOpcode())))
|
||||||
.addOperand(MI->getOperand(0));
|
.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));
|
MIB.addOperand(MI->getOperand(1));
|
||||||
if (MI->getOpcode() == ARM64::Bcc)
|
if (MI->getOpcode() == ARM64::Bcc)
|
||||||
invertBccCondition(MIB);
|
invertBccCondition(MIB);
|
||||||
|
@ -173,6 +173,14 @@ def CondCode : AsmOperandClass {
|
|||||||
let DiagnosticType = "InvalidCondCode";
|
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:
|
// 8-bit immediate for AdvSIMD where 64-bit values of the form:
|
||||||
// aaaaaaaa bbbbbbbb cccccccc dddddddd eeeeeeee ffffffff gggggggg hhhhhhhh
|
// aaaaaaaa bbbbbbbb cccccccc dddddddd eeeeeeee ffffffff gggggggg hhhhhhhh
|
||||||
// are encoded as the eight bit value 'abcdefgh'.
|
// are encoded as the eight bit value 'abcdefgh'.
|
||||||
@ -1037,10 +1045,37 @@ def am_tbrcond : Operand<OtherVT> {
|
|||||||
let ParserMatchClass = BranchTarget14Operand;
|
let ParserMatchClass = BranchTarget14Operand;
|
||||||
}
|
}
|
||||||
|
|
||||||
class TestBranch<bit op, string asm, SDNode node>
|
// AsmOperand classes to emit (or not) special diagnostics
|
||||||
: I<(outs), (ins GPR64:$Rt, imm0_63:$bit_off, am_tbrcond:$target),
|
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", "",
|
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]> {
|
Sched<[WriteBr]> {
|
||||||
let isBranch = 1;
|
let isBranch = 1;
|
||||||
let isTerminator = 1;
|
let isTerminator = 1;
|
||||||
@ -1049,7 +1084,6 @@ class TestBranch<bit op, string asm, SDNode node>
|
|||||||
bits<6> bit_off;
|
bits<6> bit_off;
|
||||||
bits<14> target;
|
bits<14> target;
|
||||||
|
|
||||||
let Inst{31} = bit_off{5};
|
|
||||||
let Inst{30-25} = 0b011011;
|
let Inst{30-25} = 0b011011;
|
||||||
let Inst{24} = op;
|
let Inst{24} = op;
|
||||||
let Inst{23-19} = bit_off{4-0};
|
let Inst{23-19} = bit_off{4-0};
|
||||||
@ -1059,6 +1093,24 @@ class TestBranch<bit op, string asm, SDNode node>
|
|||||||
let DecoderMethod = "DecodeTestAndBranch";
|
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.
|
// Unconditional branch (immediate) instructions.
|
||||||
//---
|
//---
|
||||||
|
@ -70,8 +70,10 @@ static void parseCondBranch(MachineInstr *LastInst, MachineBasicBlock *&Target,
|
|||||||
Cond.push_back(MachineOperand::CreateImm(LastInst->getOpcode()));
|
Cond.push_back(MachineOperand::CreateImm(LastInst->getOpcode()));
|
||||||
Cond.push_back(LastInst->getOperand(0));
|
Cond.push_back(LastInst->getOperand(0));
|
||||||
break;
|
break;
|
||||||
case ARM64::TBZ:
|
case ARM64::TBZW:
|
||||||
case ARM64::TBNZ:
|
case ARM64::TBZX:
|
||||||
|
case ARM64::TBNZW:
|
||||||
|
case ARM64::TBNZX:
|
||||||
Target = LastInst->getOperand(2).getMBB();
|
Target = LastInst->getOperand(2).getMBB();
|
||||||
Cond.push_back(MachineOperand::CreateImm(-1));
|
Cond.push_back(MachineOperand::CreateImm(-1));
|
||||||
Cond.push_back(MachineOperand::CreateImm(LastInst->getOpcode()));
|
Cond.push_back(MachineOperand::CreateImm(LastInst->getOpcode()));
|
||||||
@ -196,11 +198,17 @@ bool ARM64InstrInfo::ReverseBranchCondition(
|
|||||||
case ARM64::CBNZX:
|
case ARM64::CBNZX:
|
||||||
Cond[1].setImm(ARM64::CBZX);
|
Cond[1].setImm(ARM64::CBZX);
|
||||||
break;
|
break;
|
||||||
case ARM64::TBZ:
|
case ARM64::TBZW:
|
||||||
Cond[1].setImm(ARM64::TBNZ);
|
Cond[1].setImm(ARM64::TBNZW);
|
||||||
break;
|
break;
|
||||||
case ARM64::TBNZ:
|
case ARM64::TBNZW:
|
||||||
Cond[1].setImm(ARM64::TBZ);
|
Cond[1].setImm(ARM64::TBZW);
|
||||||
|
break;
|
||||||
|
case ARM64::TBZX:
|
||||||
|
Cond[1].setImm(ARM64::TBNZX);
|
||||||
|
break;
|
||||||
|
case ARM64::TBNZX:
|
||||||
|
Cond[1].setImm(ARM64::TBZX);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -453,17 +461,24 @@ void ARM64InstrInfo::insertSelect(MachineBasicBlock &MBB,
|
|||||||
switch (Cond[1].getImm()) {
|
switch (Cond[1].getImm()) {
|
||||||
default:
|
default:
|
||||||
llvm_unreachable("Unknown branch opcode in Cond");
|
llvm_unreachable("Unknown branch opcode in Cond");
|
||||||
case ARM64::TBZ:
|
case ARM64::TBZW:
|
||||||
|
case ARM64::TBZX:
|
||||||
CC = ARM64CC::EQ;
|
CC = ARM64CC::EQ;
|
||||||
break;
|
break;
|
||||||
case ARM64::TBNZ:
|
case ARM64::TBNZW:
|
||||||
|
case ARM64::TBNZX:
|
||||||
CC = ARM64CC::NE;
|
CC = ARM64CC::NE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// cmp reg, #foo is actually ands xzr, reg, #1<<foo.
|
// cmp reg, #foo is actually ands xzr, reg, #1<<foo.
|
||||||
BuildMI(MBB, I, DL, get(ARM64::ANDSXri), ARM64::XZR)
|
if (Cond[1].getImm() == ARM64::TBZW || Cond[1].getImm() == ARM64::TBNZW)
|
||||||
.addReg(Cond[2].getReg())
|
BuildMI(MBB, I, DL, get(ARM64::ANDSWri), ARM64::WZR)
|
||||||
.addImm(ARM64_AM::encodeLogicalImmediate(1ull << Cond[3].getImm(), 64));
|
.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;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -209,8 +209,10 @@ static inline bool isCondBranchOpcode(int Opc) {
|
|||||||
case ARM64::CBZX:
|
case ARM64::CBZX:
|
||||||
case ARM64::CBNZW:
|
case ARM64::CBNZW:
|
||||||
case ARM64::CBNZX:
|
case ARM64::CBNZX:
|
||||||
case ARM64::TBZ:
|
case ARM64::TBZW:
|
||||||
case ARM64::TBNZ:
|
case ARM64::TBZX:
|
||||||
|
case ARM64::TBNZW:
|
||||||
|
case ARM64::TBNZX:
|
||||||
return true;
|
return true;
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
|
@ -54,7 +54,7 @@ def SDT_ARM64Brcond : SDTypeProfile<0, 3,
|
|||||||
[SDTCisVT<0, OtherVT>, SDTCisVT<1, i32>,
|
[SDTCisVT<0, OtherVT>, SDTCisVT<1, i32>,
|
||||||
SDTCisVT<2, i32>]>;
|
SDTCisVT<2, i32>]>;
|
||||||
def SDT_ARM64cbz : SDTypeProfile<0, 2, [SDTCisInt<0>, SDTCisVT<1, OtherVT>]>;
|
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>]>;
|
SDTCisVT<2, OtherVT>]>;
|
||||||
|
|
||||||
|
|
||||||
@ -1045,8 +1045,8 @@ defm CBNZ : CmpBranch<1, "cbnz", ARM64cbnz>;
|
|||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
// Test-bit-and-branch instructions.
|
// Test-bit-and-branch instructions.
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
def TBZ : TestBranch<0, "tbz", ARM64tbz>;
|
defm TBZ : TestBranch<0, "tbz", ARM64tbz>;
|
||||||
def TBNZ : TestBranch<1, "tbnz", ARM64tbnz>;
|
defm TBNZ : TestBranch<1, "tbnz", ARM64tbnz>;
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
// Unconditional branch (immediate) instructions.
|
// Unconditional branch (immediate) instructions.
|
||||||
|
@ -563,6 +563,15 @@ public:
|
|||||||
int64_t Val = MCE->getValue();
|
int64_t Val = MCE->getValue();
|
||||||
return (Val >= 0 && Val < 65536);
|
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 {
|
bool isLogicalImm32() const {
|
||||||
if (!isImm())
|
if (!isImm())
|
||||||
return false;
|
return false;
|
||||||
@ -812,6 +821,10 @@ public:
|
|||||||
return Kind == k_Register && Reg.isVector &&
|
return Kind == k_Register && Reg.isVector &&
|
||||||
ARM64MCRegisterClasses[ARM64::FPR128_loRegClassID].contains(Reg.RegNum);
|
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
|
/// Is this a vector list with the type implicit (presumably attached to the
|
||||||
/// instruction itself)?
|
/// instruction itself)?
|
||||||
@ -1188,6 +1201,17 @@ public:
|
|||||||
Inst.addOperand(MCOperand::CreateReg(getReg()));
|
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 {
|
void addVectorReg64Operands(MCInst &Inst, unsigned N) const {
|
||||||
assert(N == 1 && "Invalid number of operands!");
|
assert(N == 1 && "Invalid number of operands!");
|
||||||
assert(ARM64MCRegisterClasses[ARM64::FPR128RegClassID].contains(getReg()));
|
assert(ARM64MCRegisterClasses[ARM64::FPR128RegClassID].contains(getReg()));
|
||||||
@ -1408,6 +1432,13 @@ public:
|
|||||||
Inst.addOperand(MCOperand::CreateImm(MCE->getValue()));
|
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 {
|
void addLogicalImm32Operands(MCInst &Inst, unsigned N) const {
|
||||||
assert(N == 1 && "Invalid number of operands!");
|
assert(N == 1 && "Invalid number of operands!");
|
||||||
const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(getImm());
|
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.
|
// 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
|
// InstAlias can't quite handle this since the reg classes aren't
|
||||||
// subclasses.
|
// subclasses.
|
||||||
|
@ -1512,7 +1512,10 @@ static DecodeStatus DecodeTestAndBranch(llvm::MCInst &Inst, uint32_t insn,
|
|||||||
if (dst & (1 << (14 - 1)))
|
if (dst & (1 << (14 - 1)))
|
||||||
dst |= ~((1LL << 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));
|
Inst.addOperand(MCOperand::CreateImm(bit));
|
||||||
if (!Dis->tryAddingSymbolicOperand(Inst, dst << 2, Addr, true, 0, 4))
|
if (!Dis->tryAddingSymbolicOperand(Inst, dst << 2, Addr, true, 0, 4))
|
||||||
Inst.addOperand(MCOperand::CreateImm(dst));
|
Inst.addOperand(MCOperand::CreateImm(dst));
|
||||||
|
@ -63,18 +63,6 @@ void ARM64InstPrinter::printInst(const MCInst *MI, raw_ostream &O,
|
|||||||
return;
|
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.
|
// SBFM/UBFM should print to a nicer aliased form if possible.
|
||||||
if (Opcode == ARM64::SBFMXri || Opcode == ARM64::SBFMWri ||
|
if (Opcode == ARM64::SBFMXri || Opcode == ARM64::SBFMWri ||
|
||||||
Opcode == ARM64::UBFMXri || Opcode == ARM64::UBFMWri) {
|
Opcode == ARM64::UBFMXri || Opcode == ARM64::UBFMWri) {
|
||||||
|
@ -322,7 +322,7 @@ done:
|
|||||||
}
|
}
|
||||||
|
|
||||||
; CHECK: tbnz_32
|
; CHECK: tbnz_32
|
||||||
; CHECK: {{ands.*xzr,|tst}} x2, #0x80
|
; CHECK: {{ands.*xzr,|tst}} w2, #0x80
|
||||||
; CHECK-NEXT: csel w0, w1, w0, ne
|
; CHECK-NEXT: csel w0, w1, w0, ne
|
||||||
; CHECK-NEXT: ret
|
; CHECK-NEXT: ret
|
||||||
define i32 @tbnz_32(i32 %x, i32 %y, i32 %c) nounwind ssp {
|
define i32 @tbnz_32(i32 %x, i32 %y, i32 %c) nounwind ssp {
|
||||||
@ -358,7 +358,7 @@ done:
|
|||||||
}
|
}
|
||||||
|
|
||||||
; CHECK: tbz_32
|
; CHECK: tbz_32
|
||||||
; CHECK: {{ands.*xzr,|tst}} x2, #0x80
|
; CHECK: {{ands.*xzr,|tst}} w2, #0x80
|
||||||
; CHECK-NEXT: csel w0, w1, w0, eq
|
; CHECK-NEXT: csel w0, w1, w0, eq
|
||||||
; CHECK-NEXT: ret
|
; CHECK-NEXT: ret
|
||||||
define i32 @tbz_32(i32 %x, i32 %y, i32 %c) nounwind ssp {
|
define i32 @tbz_32(i32 %x, i32 %y, i32 %c) nounwind ssp {
|
||||||
|
Loading…
Reference in New Issue
Block a user