forked from OSchip/llvm-project
Fix for PR18921, "vmov" part.
Added support for bytes replication feature, so it could be GAS compatible. E.g. instructions below: "vmov.i32 d0, 0xffffffff" "vmvn.i32 d0, 0xabababab" "vmov.i32 d0, 0xabababab" "vmov.i16 d0, 0xabab" are incorrect, but we could deal with such cases. For first one we should emit: "vmov.i8 d0, 0xff" For second one ("vmvn"): "vmov.i8 d0, 0x54" For last two instructions it should emit: "vmov.i8 d0, 0xab" P.S.: In ARMAsmParser.cpp I have also fixed few nearby style issues in old code. Just for keeping method bodies in harmony with themselves. llvm-svn: 207080
This commit is contained in:
parent
dc493cf13b
commit
00dcc0f53c
|
@ -39,6 +39,49 @@ def nImmVMOVI32 : Operand<i32> {
|
|||
let PrintMethod = "printNEONModImmOperand";
|
||||
let ParserMatchClass = nImmVMOVI32AsmOperand;
|
||||
}
|
||||
|
||||
def nImmVMOVI16AsmOperandByteReplicate :
|
||||
AsmOperandClass {
|
||||
let Name = "NEONi16vmovByteReplicate";
|
||||
let PredicateMethod = "isNEONi16ByteReplicate";
|
||||
let RenderMethod = "addNEONvmovByteReplicateOperands";
|
||||
}
|
||||
def nImmVMOVI32AsmOperandByteReplicate :
|
||||
AsmOperandClass {
|
||||
let Name = "NEONi32vmovByteReplicate";
|
||||
let PredicateMethod = "isNEONi32ByteReplicate";
|
||||
let RenderMethod = "addNEONvmovByteReplicateOperands";
|
||||
}
|
||||
def nImmVMVNI16AsmOperandByteReplicate :
|
||||
AsmOperandClass {
|
||||
let Name = "NEONi16invByteReplicate";
|
||||
let PredicateMethod = "isNEONi16ByteReplicate";
|
||||
let RenderMethod = "addNEONinvByteReplicateOperands";
|
||||
}
|
||||
def nImmVMVNI32AsmOperandByteReplicate :
|
||||
AsmOperandClass {
|
||||
let Name = "NEONi32invByteReplicate";
|
||||
let PredicateMethod = "isNEONi32ByteReplicate";
|
||||
let RenderMethod = "addNEONinvByteReplicateOperands";
|
||||
}
|
||||
|
||||
def nImmVMOVI16ByteReplicate : Operand<i32> {
|
||||
let PrintMethod = "printNEONModImmOperand";
|
||||
let ParserMatchClass = nImmVMOVI16AsmOperandByteReplicate;
|
||||
}
|
||||
def nImmVMOVI32ByteReplicate : Operand<i32> {
|
||||
let PrintMethod = "printNEONModImmOperand";
|
||||
let ParserMatchClass = nImmVMOVI32AsmOperandByteReplicate;
|
||||
}
|
||||
def nImmVMVNI16ByteReplicate : Operand<i32> {
|
||||
let PrintMethod = "printNEONModImmOperand";
|
||||
let ParserMatchClass = nImmVMVNI16AsmOperandByteReplicate;
|
||||
}
|
||||
def nImmVMVNI32ByteReplicate : Operand<i32> {
|
||||
let PrintMethod = "printNEONModImmOperand";
|
||||
let ParserMatchClass = nImmVMVNI32AsmOperandByteReplicate;
|
||||
}
|
||||
|
||||
def nImmVMOVI32NegAsmOperand : AsmOperandClass { let Name = "NEONi32vmovNeg"; }
|
||||
def nImmVMOVI32Neg : Operand<i32> {
|
||||
let PrintMethod = "printNEONModImmOperand";
|
||||
|
@ -5301,6 +5344,35 @@ def VMOVv4f32 : N1ModImm<1, 0b000, 0b1111, 0, 1, 0, 1, (outs QPR:$Vd),
|
|||
[(set QPR:$Vd, (v4f32 (NEONvmovFPImm timm:$SIMM)))]>;
|
||||
} // isReMaterializable
|
||||
|
||||
// Add support for bytes replication feature, so it could be GAS compatible.
|
||||
// E.g. instructions below:
|
||||
// "vmov.i32 d0, 0xffffffff"
|
||||
// "vmov.i32 d0, 0xabababab"
|
||||
// "vmov.i16 d0, 0xabab"
|
||||
// are incorrect, but we could deal with such cases.
|
||||
// For last two instructions, for example, it should emit:
|
||||
// "vmov.i8 d0, 0xab"
|
||||
def : NEONInstAlias<"vmov${p}.i16 $Vd, $Vm",
|
||||
(VMOVv8i8 DPR:$Vd, nImmVMOVI16ByteReplicate:$Vm, pred:$p)>;
|
||||
def : NEONInstAlias<"vmov${p}.i32 $Vd, $Vm",
|
||||
(VMOVv8i8 DPR:$Vd, nImmVMOVI32ByteReplicate:$Vm, pred:$p)>;
|
||||
def : NEONInstAlias<"vmov${p}.i16 $Vd, $Vm",
|
||||
(VMOVv16i8 QPR:$Vd, nImmVMOVI16ByteReplicate:$Vm, pred:$p)>;
|
||||
def : NEONInstAlias<"vmov${p}.i32 $Vd, $Vm",
|
||||
(VMOVv16i8 QPR:$Vd, nImmVMOVI32ByteReplicate:$Vm, pred:$p)>;
|
||||
|
||||
// Also add same support for VMVN instructions. So instruction:
|
||||
// "vmvn.i32 d0, 0xabababab"
|
||||
// actually means:
|
||||
// "vmov.i8 d0, 0x54"
|
||||
def : NEONInstAlias<"vmvn${p}.i16 $Vd, $Vm",
|
||||
(VMOVv8i8 DPR:$Vd, nImmVMVNI16ByteReplicate:$Vm, pred:$p)>;
|
||||
def : NEONInstAlias<"vmvn${p}.i32 $Vd, $Vm",
|
||||
(VMOVv8i8 DPR:$Vd, nImmVMVNI32ByteReplicate:$Vm, pred:$p)>;
|
||||
def : NEONInstAlias<"vmvn${p}.i16 $Vd, $Vm",
|
||||
(VMOVv16i8 QPR:$Vd, nImmVMVNI16ByteReplicate:$Vm, pred:$p)>;
|
||||
def : NEONInstAlias<"vmvn${p}.i32 $Vd, $Vm",
|
||||
(VMOVv16i8 QPR:$Vd, nImmVMVNI32ByteReplicate:$Vm, pred:$p)>;
|
||||
|
||||
// On some CPUs the two instructions "vmov.i32 dD, #0" and "vmov.i32 qD, #0"
|
||||
// require zero cycles to execute so they should be used wherever possible for
|
||||
|
|
|
@ -1610,7 +1610,10 @@ public:
|
|||
}
|
||||
|
||||
bool isNEONi16splat() const {
|
||||
if (!isImm()) return false;
|
||||
if (isNEONByteReplicate(2))
|
||||
return false; // Leave that for bytes replication and forbid by default.
|
||||
if (!isImm())
|
||||
return false;
|
||||
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
|
||||
// Must be a constant.
|
||||
if (!CE) return false;
|
||||
|
@ -1620,7 +1623,10 @@ public:
|
|||
}
|
||||
|
||||
bool isNEONi32splat() const {
|
||||
if (!isImm()) return false;
|
||||
if (isNEONByteReplicate(4))
|
||||
return false; // Leave that for bytes replication and forbid by default.
|
||||
if (!isImm())
|
||||
return false;
|
||||
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
|
||||
// Must be a constant.
|
||||
if (!CE) return false;
|
||||
|
@ -1632,11 +1638,36 @@ public:
|
|||
(Value >= 0x01000000 && Value <= 0xff000000);
|
||||
}
|
||||
|
||||
bool isNEONi32vmov() const {
|
||||
if (!isImm()) return false;
|
||||
bool isNEONByteReplicate(unsigned NumBytes) const {
|
||||
if (!isImm())
|
||||
return false;
|
||||
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
|
||||
// Must be a constant.
|
||||
if (!CE) return false;
|
||||
if (!CE)
|
||||
return false;
|
||||
int64_t Value = CE->getValue();
|
||||
if (!Value)
|
||||
return false; // Don't bother with zero.
|
||||
|
||||
unsigned char B = Value & 0xff;
|
||||
for (unsigned i = 1; i < NumBytes; ++i) {
|
||||
Value >>= 8;
|
||||
if ((Value & 0xff) != B)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool isNEONi16ByteReplicate() const { return isNEONByteReplicate(2); }
|
||||
bool isNEONi32ByteReplicate() const { return isNEONByteReplicate(4); }
|
||||
bool isNEONi32vmov() const {
|
||||
if (isNEONByteReplicate(4))
|
||||
return false; // Let it to be classified as byte-replicate case.
|
||||
if (!isImm())
|
||||
return false;
|
||||
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
|
||||
// Must be a constant.
|
||||
if (!CE)
|
||||
return false;
|
||||
int64_t Value = CE->getValue();
|
||||
// i32 value with set bits only in one byte X000, 0X00, 00X0, or 000X,
|
||||
// for VMOV/VMVN only, 00Xf or 0Xff are also accepted.
|
||||
|
@ -2384,6 +2415,19 @@ public:
|
|||
Inst.addOperand(MCOperand::CreateImm(Value));
|
||||
}
|
||||
|
||||
void addNEONinvByteReplicateOperands(MCInst &Inst, unsigned N) const {
|
||||
assert(N == 1 && "Invalid number of operands!");
|
||||
// The immediate encodes the type of constant as well as the value.
|
||||
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
|
||||
unsigned Value = CE->getValue();
|
||||
assert((Inst.getOpcode() == ARM::VMOVv8i8 ||
|
||||
Inst.getOpcode() == ARM::VMOVv16i8) &&
|
||||
"All vmvn instructions that wants to replicate non-zero byte "
|
||||
"always must be replaced with VMOVv8i8 or VMOVv16i8.");
|
||||
unsigned B = ((~Value) & 0xff);
|
||||
B |= 0xe00; // cmode = 0b1110
|
||||
Inst.addOperand(MCOperand::CreateImm(B));
|
||||
}
|
||||
void addNEONi32vmovOperands(MCInst &Inst, unsigned N) const {
|
||||
assert(N == 1 && "Invalid number of operands!");
|
||||
// The immediate encodes the type of constant as well as the value.
|
||||
|
@ -2398,6 +2442,19 @@ public:
|
|||
Inst.addOperand(MCOperand::CreateImm(Value));
|
||||
}
|
||||
|
||||
void addNEONvmovByteReplicateOperands(MCInst &Inst, unsigned N) const {
|
||||
assert(N == 1 && "Invalid number of operands!");
|
||||
// The immediate encodes the type of constant as well as the value.
|
||||
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
|
||||
unsigned Value = CE->getValue();
|
||||
assert((Inst.getOpcode() == ARM::VMOVv8i8 ||
|
||||
Inst.getOpcode() == ARM::VMOVv16i8) &&
|
||||
"All instructions that wants to replicate non-zero byte "
|
||||
"always must be replaced with VMOVv8i8 or VMOVv16i8.");
|
||||
unsigned B = Value & 0xff;
|
||||
B |= 0xe00; // cmode = 0b1110
|
||||
Inst.addOperand(MCOperand::CreateImm(B));
|
||||
}
|
||||
void addNEONi32vmovNegOperands(MCInst &Inst, unsigned N) const {
|
||||
assert(N == 1 && "Invalid number of operands!");
|
||||
// The immediate encodes the type of constant as well as the value.
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
@ PR18921, "vmov" part.
|
||||
@ RUN: llvm-mc -triple=armv7-linux-gnueabi -show-encoding < %s | FileCheck %s
|
||||
.text
|
||||
|
||||
@ CHECK: vmov.i8 d2, #0xff @ encoding: [0x1f,0x2e,0x87,0xf3]
|
||||
@ CHECK: vmov.i8 q2, #0xff @ encoding: [0x5f,0x4e,0x87,0xf3]
|
||||
@ CHECK: vmov.i8 d2, #0xab @ encoding: [0x1b,0x2e,0x82,0xf3]
|
||||
@ CHECK: vmov.i8 q2, #0xab @ encoding: [0x5b,0x4e,0x82,0xf3]
|
||||
@ CHECK: vmov.i8 q2, #0xab @ encoding: [0x5b,0x4e,0x82,0xf3]
|
||||
@ CHECK: vmov.i8 q2, #0xab @ encoding: [0x5b,0x4e,0x82,0xf3]
|
||||
|
||||
@ CHECK: vmov.i8 d2, #0x0 @ encoding: [0x10,0x2e,0x80,0xf2]
|
||||
@ CHECK: vmov.i8 q2, #0x0 @ encoding: [0x50,0x4e,0x80,0xf2]
|
||||
@ CHECK: vmov.i8 d2, #0x54 @ encoding: [0x14,0x2e,0x85,0xf2]
|
||||
@ CHECK: vmov.i8 q2, #0x54 @ encoding: [0x54,0x4e,0x85,0xf2]
|
||||
@ CHECK: vmov.i8 d2, #0x54 @ encoding: [0x14,0x2e,0x85,0xf2]
|
||||
@ CHECK: vmov.i8 q2, #0x54 @ encoding: [0x54,0x4e,0x85,0xf2]
|
||||
|
||||
vmov.i32 d2, #0xffffffff
|
||||
vmov.i32 q2, #0xffffffff
|
||||
vmov.i32 d2, #0xabababab
|
||||
vmov.i32 q2, #0xabababab
|
||||
vmov.i16 q2, #0xabab
|
||||
vmov.i16 q2, #0xabab
|
||||
|
||||
vmvn.i32 d2, #0xffffffff
|
||||
vmvn.i32 q2, #0xffffffff
|
||||
vmvn.i32 d2, #0xabababab
|
||||
vmvn.i32 q2, #0xabababab
|
||||
vmvn.i16 d2, #0xabab
|
||||
vmvn.i16 q2, #0xabab
|
|
@ -0,0 +1,30 @@
|
|||
@ RUN: not llvm-mc -triple=armv7-linux-gnueabi %s 2>&1 | FileCheck %s
|
||||
.text
|
||||
|
||||
@ CHECK: error: invalid operand for instruction
|
||||
@ CHECK: vmov.i32 d2, #0xffffffab
|
||||
@ CHECK: error: invalid operand for instruction
|
||||
@ CHECK: vmov.i32 q2, #0xffffffab
|
||||
@ CHECK: error: invalid operand for instruction
|
||||
@ CHECK: vmov.i16 q2, #0xffab
|
||||
@ CHECK: error: invalid operand for instruction
|
||||
@ CHECK: vmov.i16 q2, #0xffab
|
||||
|
||||
@ CHECK: error: invalid operand for instruction
|
||||
@ CHECK: vmvn.i32 d2, #0xffffffab
|
||||
@ CHECK: error: invalid operand for instruction
|
||||
@ CHECK: vmvn.i32 q2, #0xffffffab
|
||||
@ CHECK: error: invalid operand for instruction
|
||||
@ CHECK: vmvn.i16 q2, #0xffab
|
||||
@ CHECK: error: invalid operand for instruction
|
||||
@ CHECK: vmvn.i16 q2, #0xffab
|
||||
|
||||
vmov.i32 d2, #0xffffffab
|
||||
vmov.i32 q2, #0xffffffab
|
||||
vmov.i16 q2, #0xffab
|
||||
vmov.i16 q2, #0xffab
|
||||
|
||||
vmvn.i32 d2, #0xffffffab
|
||||
vmvn.i32 q2, #0xffffffab
|
||||
vmvn.i16 q2, #0xffab
|
||||
vmvn.i16 q2, #0xffab
|
|
@ -0,0 +1,42 @@
|
|||
@ RUN: not llvm-mc -triple=armv7-linux-gnueabi %s 2>&1 | FileCheck %s
|
||||
.text
|
||||
|
||||
@ CHECK: error: invalid operand for instruction
|
||||
@ CHECK: vorr.i32 d2, #0xffffffff
|
||||
@ CHECK: error: invalid operand for instruction
|
||||
@ CHECK: vorr.i32 q2, #0xffffffff
|
||||
@ CHECK: error: invalid operand for instruction
|
||||
@ CHECK: vorr.i32 d2, #0xabababab
|
||||
@ CHECK: error: invalid operand for instruction
|
||||
@ CHECK: vorr.i32 q2, #0xabababab
|
||||
@ CHECK: error: invalid operand for instruction
|
||||
@ CHECK: vorr.i16 q2, #0xabab
|
||||
@ CHECK: error: invalid operand for instruction
|
||||
@ CHECK: vorr.i16 q2, #0xabab
|
||||
|
||||
@ CHECK: error: invalid operand for instruction
|
||||
@ CHECK: vbic.i32 d2, #0xffffffff
|
||||
@ CHECK: error: invalid operand for instruction
|
||||
@ CHECK: vbic.i32 q2, #0xffffffff
|
||||
@ CHECK: error: invalid operand for instruction
|
||||
@ CHECK: vbic.i32 d2, #0xabababab
|
||||
@ CHECK: error: invalid operand for instruction
|
||||
@ CHECK: vbic.i32 q2, #0xabababab
|
||||
@ CHECK: error: invalid operand for instruction
|
||||
@ CHECK: vbic.i16 d2, #0xabab
|
||||
@ CHECK: error: invalid operand for instruction
|
||||
@ CHECK: vbic.i16 q2, #0xabab
|
||||
|
||||
vorr.i32 d2, #0xffffffff
|
||||
vorr.i32 q2, #0xffffffff
|
||||
vorr.i32 d2, #0xabababab
|
||||
vorr.i32 q2, #0xabababab
|
||||
vorr.i16 q2, #0xabab
|
||||
vorr.i16 q2, #0xabab
|
||||
|
||||
vbic.i32 d2, #0xffffffff
|
||||
vbic.i32 q2, #0xffffffff
|
||||
vbic.i32 d2, #0xabababab
|
||||
vbic.i32 q2, #0xabababab
|
||||
vbic.i16 d2, #0xabab
|
||||
vbic.i16 q2, #0xabab
|
Loading…
Reference in New Issue