summaryrefslogtreecommitdiffstats
path: root/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp')
-rw-r--r--llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp145
1 files changed, 102 insertions, 43 deletions
diff --git a/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp b/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp
index 78973d16e2d..d2b9b28519c 100644
--- a/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp
+++ b/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp
@@ -1857,7 +1857,22 @@ public:
return ARM_AM::isNEONi32splat(~Value);
}
- bool isNEONByteReplicate(unsigned NumBytes) const {
+ static bool isValidNEONi32vmovImm(int64_t Value) {
+ // i32 value with set bits only in one byte X000, 0X00, 00X0, or 000X,
+ // for VMOV/VMVN only, 00Xf or 0Xff are also accepted.
+ return ((Value & 0xffffffffffffff00) == 0) ||
+ ((Value & 0xffffffffffff00ff) == 0) ||
+ ((Value & 0xffffffffff00ffff) == 0) ||
+ ((Value & 0xffffffff00ffffff) == 0) ||
+ ((Value & 0xffffffffffff00ff) == 0xff) ||
+ ((Value & 0xffffffffff00ffff) == 0xffff);
+ }
+
+ bool isNEONReplicate(unsigned Width, unsigned NumElems, bool Inv,
+ bool AllowMinusOne) const {
+ assert(Width == 8 || Width == 16 || Width == 32 && "Invalid element width");
+ assert(NumElems * Width <= 64 && "Invalid result width");
+
if (!isImm())
return false;
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
@@ -1867,28 +1882,47 @@ public:
int64_t Value = CE->getValue();
if (!Value)
return false; // Don't bother with zero.
+ if (Inv)
+ Value = ~Value;
- unsigned char B = Value & 0xff;
- for (unsigned i = 1; i < NumBytes; ++i) {
- Value >>= 8;
- if ((Value & 0xff) != B)
+ uint64_t Mask = (1ull << Width) - 1;
+ uint64_t Elem = Value & Mask;
+ if (!AllowMinusOne && Elem == Mask)
+ return false;
+ if (Width == 16 && (Elem & 0x00ff) != 0 && (Elem & 0xff00) != 0)
+ return false;
+ if (Width == 32 && !isValidNEONi32vmovImm(Elem))
+ return false;
+
+ for (unsigned i = 1; i < NumElems; ++i) {
+ Value >>= Width;
+ if ((Value & Mask) != Elem)
return false;
}
return true;
}
- bool isNEONi16ByteReplicate() const { return isNEONByteReplicate(2); }
- bool isNEONi32ByteReplicate() const { return isNEONByteReplicate(4); }
+ bool isNEONByteReplicate(unsigned NumBytes) const {
+ return isNEONReplicate(8, NumBytes, false, true);
+ }
- static bool isValidNEONi32vmovImm(int64_t Value) {
- // i32 value with set bits only in one byte X000, 0X00, 00X0, or 000X,
- // for VMOV/VMVN only, 00Xf or 0Xff are also accepted.
- return ((Value & 0xffffffffffffff00) == 0) ||
- ((Value & 0xffffffffffff00ff) == 0) ||
- ((Value & 0xffffffffff00ffff) == 0) ||
- ((Value & 0xffffffff00ffffff) == 0) ||
- ((Value & 0xffffffffffff00ff) == 0xff) ||
- ((Value & 0xffffffffff00ffff) == 0xffff);
+ static void checkNeonReplicateArgs(unsigned FromW, unsigned ToW) {
+ assert(FromW == 8 || FromW == 16 || FromW == 32 && "Invalid source width");
+ assert(ToW == 16 || ToW == 32 || ToW == 64 && "Invalid destination width");
+ assert(FromW < ToW && "ToW is not less than FromW");
+ }
+
+ template<unsigned FromW, unsigned ToW>
+ bool isNEONmovReplicate() const {
+ checkNeonReplicateArgs(FromW, ToW);
+ bool AllowMinusOne = ToW != 64;
+ return isNEONReplicate(FromW, ToW / FromW, false, AllowMinusOne);
+ }
+
+ template<unsigned FromW, unsigned ToW>
+ bool isNEONinvReplicate() const {
+ checkNeonReplicateArgs(FromW, ToW);
+ return isNEONReplicate(FromW, ToW / FromW, true, true);
}
bool isNEONi32vmov() const {
@@ -2726,62 +2760,87 @@ public:
Inst.addOperand(MCOperand::createImm(Value));
}
- void addNEONinvByteReplicateOperands(MCInst &Inst, unsigned N) const {
- assert(N == 1 && "Invalid number of operands!");
+ void addNEONi8ReplicateOperands(MCInst &Inst, bool Inv) const {
// 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);
+ "All instructions that wants to replicate non-zero byte "
+ "always must be replaced with VMOVv8i8 or VMOVv16i8.");
+ unsigned Value = CE->getValue();
+ if (Inv)
+ Value = ~Value;
+ unsigned B = Value & 0xff;
B |= 0xe00; // cmode = 0b1110
Inst.addOperand(MCOperand::createImm(B));
}
- void addNEONi32vmovOperands(MCInst &Inst, unsigned N) const {
+ void addNEONinvi8ReplicateOperands(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();
+ addNEONi8ReplicateOperands(Inst, true);
+ }
+
+ static unsigned encodeNeonVMOVImmediate(unsigned Value) {
if (Value >= 256 && Value <= 0xffff)
Value = (Value >> 8) | ((Value & 0xff) ? 0xc00 : 0x200);
else if (Value > 0xffff && Value <= 0xffffff)
Value = (Value >> 16) | ((Value & 0xff) ? 0xd00 : 0x400);
else if (Value > 0xffffff)
Value = (Value >> 24) | 0x600;
- Inst.addOperand(MCOperand::createImm(Value));
+ return Value;
}
- void addNEONvmovByteReplicateOperands(MCInst &Inst, unsigned N) const {
+ 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.
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));
+ unsigned Value = encodeNeonVMOVImmediate(CE->getValue());
+ Inst.addOperand(MCOperand::createImm(Value));
+ }
+
+ void addNEONvmovi8ReplicateOperands(MCInst &Inst, unsigned N) const {
+ assert(N == 1 && "Invalid number of operands!");
+ addNEONi8ReplicateOperands(Inst, false);
+ }
+
+ void addNEONvmovi16ReplicateOperands(MCInst &Inst, unsigned N) const {
+ assert(N == 1 && "Invalid number of operands!");
+ const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
+ assert((Inst.getOpcode() == ARM::VMOVv4i16 ||
+ Inst.getOpcode() == ARM::VMOVv8i16 ||
+ Inst.getOpcode() == ARM::VMVNv4i16 ||
+ Inst.getOpcode() == ARM::VMVNv8i16) &&
+ "All instructions that want to replicate non-zero half-word "
+ "always must be replaced with V{MOV,MVN}v{4,8}i16.");
+ uint64_t Value = CE->getValue();
+ unsigned Elem = Value & 0xffff;
+ if (Elem >= 256)
+ Elem = (Elem >> 8) | 0x200;
+ Inst.addOperand(MCOperand::createImm(Elem));
}
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.
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
- unsigned Value = ~CE->getValue();
- if (Value >= 256 && Value <= 0xffff)
- Value = (Value >> 8) | ((Value & 0xff) ? 0xc00 : 0x200);
- else if (Value > 0xffff && Value <= 0xffffff)
- Value = (Value >> 16) | ((Value & 0xff) ? 0xd00 : 0x400);
- else if (Value > 0xffffff)
- Value = (Value >> 24) | 0x600;
+ unsigned Value = encodeNeonVMOVImmediate(~CE->getValue());
Inst.addOperand(MCOperand::createImm(Value));
}
+ void addNEONvmovi32ReplicateOperands(MCInst &Inst, unsigned N) const {
+ assert(N == 1 && "Invalid number of operands!");
+ const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
+ assert((Inst.getOpcode() == ARM::VMOVv2i32 ||
+ Inst.getOpcode() == ARM::VMOVv4i32 ||
+ Inst.getOpcode() == ARM::VMVNv2i32 ||
+ Inst.getOpcode() == ARM::VMVNv4i32) &&
+ "All instructions that want to replicate non-zero word "
+ "always must be replaced with V{MOV,MVN}v{2,4}i32.");
+ uint64_t Value = CE->getValue();
+ unsigned Elem = encodeNeonVMOVImmediate(Value & 0xffffffff);
+ Inst.addOperand(MCOperand::createImm(Elem));
+ }
+
void addNEONi64splatOperands(MCInst &Inst, unsigned N) const {
assert(N == 1 && "Invalid number of operands!");
// The immediate encodes the type of constant as well as the value.
OpenPOWER on IntegriCloud