let Inst{5} = Qm{3};
let Inst{3-1} = Qm{2-0};
let Inst{0} = 0b1;
+ let invalidForTailPredication = 1;
}
def MVE_VABAVs8 : MVE_VABAV<"s8", 0b0, 0b00>;
let Inst{5} = A;
let Inst{3-1} = Qm{2-0};
let Inst{0} = 0b0;
+ let invalidForTailPredication = 1;
}
multiclass MVE_VADDV_A<string suffix, bit U, bits<2> size,
let Inst{5} = A;
let Inst{3-1} = Qm{2-0};
let Inst{0} = 0b0;
+ let invalidForTailPredication = 1;
}
multiclass MVE_VADDLV_A<string suffix, bit U, list<dag> pattern=[]> {
let Inst{0} = 0b0;
let Predicates = [HasMVEFloat];
+ let invalidForTailPredication = 1;
}
multiclass MVE_VMINMAXNMV_fty<string iname, bit bit_7, list<dag> pattern=[]> {
let Inst{6-5} = 0b00;
let Inst{3-1} = Qm{2-0};
let Inst{0} = 0b0;
+ let invalidForTailPredication = 1;
}
multiclass MVE_VMINMAXV_ty<string iname, bit bit_7, list<dag> pattern=[]> {
let Inst{5} = A;
let Inst{3-1} = Qm{2-0};
let Inst{0} = bit_0;
+ let invalidForTailPredication = 1;
}
multiclass MVE_VMLAMLSDAV_A<string iname, string x, string suffix,
let Inst{5} = A;
let Inst{3-1} = Qm{2-0};
let Inst{0} = bit_0;
+ let invalidForTailPredication = 1;
}
multiclass MVE_VMLALDAVBase_A<string iname, string x, string suffix,
--- /dev/null
+#include "ARMBaseInstrInfo.h"
+#include "ARMSubtarget.h"
+#include "ARMTargetMachine.h"
+#include "llvm/Support/TargetRegistry.h"
+#include "llvm/Support/TargetSelect.h"
+#include "llvm/Target/TargetMachine.h"
+#include "llvm/Target/TargetOptions.h"
+
+#include "gtest/gtest.h"
+
+using namespace llvm;
+
+// Test for instructions that aren't immediately obviously valid within a
+// tail-predicated loop. This should be marked up in their tablegen
+// descriptions. Currently the horizontal vector operations are tagged.
+// TODO Add instructions that perform:
+// - truncation,
+// - extensions,
+// - byte swapping,
+// - others?
+TEST(MachineInstrInvalidTailPredication, IsCorrect) {
+ LLVMInitializeARMTargetInfo();
+ LLVMInitializeARMTarget();
+ LLVMInitializeARMTargetMC();
+
+ auto TT(Triple::normalize("thumbv8.1m.main-arm-none-eabi"));
+ std::string Error;
+ const Target *T = TargetRegistry::lookupTarget(TT, Error);
+ if (!T) {
+ dbgs() << Error;
+ return;
+ }
+
+ TargetOptions Options;
+ auto TM = std::unique_ptr<LLVMTargetMachine>(
+ static_cast<LLVMTargetMachine*>(
+ T->createTargetMachine(TT, "generic", "", Options, None, None,
+ CodeGenOpt::Default)));
+ auto MII = TM->getMCInstrInfo();
+
+ using namespace ARM;
+
+ auto IsInvalidTPOpcode = [](unsigned Opcode) {
+ switch (Opcode) {
+ case MVE_VABAVs8:
+ case MVE_VABAVs16:
+ case MVE_VABAVs32:
+ case MVE_VABAVu8:
+ case MVE_VABAVu16:
+ case MVE_VABAVu32:
+ case MVE_VADDVs8acc:
+ case MVE_VADDVs16acc:
+ case MVE_VADDVs32acc:
+ case MVE_VADDVu8acc:
+ case MVE_VADDVu16acc:
+ case MVE_VADDVu32acc:
+ case MVE_VADDVs8no_acc:
+ case MVE_VADDVs16no_acc:
+ case MVE_VADDVs32no_acc:
+ case MVE_VADDVu8no_acc:
+ case MVE_VADDVu16no_acc:
+ case MVE_VADDVu32no_acc:
+ case MVE_VADDLVs32no_acc:
+ case MVE_VADDLVu32no_acc:
+ case MVE_VADDLVs32acc:
+ case MVE_VADDLVu32acc:
+ case MVE_VMLADAVas16:
+ case MVE_VMLADAVas32:
+ case MVE_VMLADAVas8:
+ case MVE_VMLADAVau16:
+ case MVE_VMLADAVau32:
+ case MVE_VMLADAVau8:
+ case MVE_VMLADAVaxs16:
+ case MVE_VMLADAVaxs32:
+ case MVE_VMLADAVaxs8:
+ case MVE_VMLADAVs16:
+ case MVE_VMLADAVs32:
+ case MVE_VMLADAVs8:
+ case MVE_VMLADAVu16:
+ case MVE_VMLADAVu32:
+ case MVE_VMLADAVu8:
+ case MVE_VMLADAVxs16:
+ case MVE_VMLADAVxs32:
+ case MVE_VMLADAVxs8:
+ case MVE_VMLALDAVas16:
+ case MVE_VMLALDAVas32:
+ case MVE_VMLALDAVau16:
+ case MVE_VMLALDAVau32:
+ case MVE_VMLALDAVaxs16:
+ case MVE_VMLALDAVaxs32:
+ case MVE_VMLALDAVs16:
+ case MVE_VMLALDAVs32:
+ case MVE_VMLALDAVu16:
+ case MVE_VMLALDAVu32:
+ case MVE_VMLALDAVxs16:
+ case MVE_VMLALDAVxs32:
+ case MVE_VMLSDAVas16:
+ case MVE_VMLSDAVas32:
+ case MVE_VMLSDAVas8:
+ case MVE_VMLSDAVaxs16:
+ case MVE_VMLSDAVaxs32:
+ case MVE_VMLSDAVaxs8:
+ case MVE_VMLSDAVs16:
+ case MVE_VMLSDAVs32:
+ case MVE_VMLSDAVs8:
+ case MVE_VMLSDAVxs16:
+ case MVE_VMLSDAVxs32:
+ case MVE_VMLSDAVxs8:
+ case MVE_VMLSLDAVas16:
+ case MVE_VMLSLDAVas32:
+ case MVE_VMLSLDAVaxs16:
+ case MVE_VMLSLDAVaxs32:
+ case MVE_VMLSLDAVs16:
+ case MVE_VMLSLDAVs32:
+ case MVE_VMLSLDAVxs16:
+ case MVE_VMLSLDAVxs32:
+ case MVE_VRMLALDAVHas32:
+ case MVE_VRMLALDAVHau32:
+ case MVE_VRMLALDAVHaxs32:
+ case MVE_VRMLALDAVHs32:
+ case MVE_VRMLALDAVHu32:
+ case MVE_VRMLALDAVHxs32:
+ case MVE_VRMLSLDAVHas32:
+ case MVE_VRMLSLDAVHaxs32:
+ case MVE_VRMLSLDAVHs32:
+ case MVE_VRMLSLDAVHxs32:
+ case MVE_VMAXNMVf16:
+ case MVE_VMINNMVf16:
+ case MVE_VMAXNMVf32:
+ case MVE_VMINNMVf32:
+ case MVE_VMAXNMAVf16:
+ case MVE_VMINNMAVf16:
+ case MVE_VMAXNMAVf32:
+ case MVE_VMINNMAVf32:
+ case MVE_VMAXVs8:
+ case MVE_VMAXVs16:
+ case MVE_VMAXVs32:
+ case MVE_VMAXVu8:
+ case MVE_VMAXVu16:
+ case MVE_VMAXVu32:
+ case MVE_VMINVs8:
+ case MVE_VMINVs16:
+ case MVE_VMINVs32:
+ case MVE_VMINVu8:
+ case MVE_VMINVu16:
+ case MVE_VMINVu32:
+ case MVE_VMAXAVs8:
+ case MVE_VMAXAVs16:
+ case MVE_VMAXAVs32:
+ case MVE_VMINAVs8:
+ case MVE_VMINAVs16:
+ case MVE_VMINAVs32:
+ return true;
+ default:
+ return false;
+ }
+ };
+
+ for (unsigned i = 0; i < ARM::INSTRUCTION_LIST_END; ++i) {
+ uint64_t Flags = MII->get(i).TSFlags;
+ bool Invalid = (Flags & ARMII::InvalidForTailPredication) != 0;
+ ASSERT_EQ(IsInvalidTPOpcode(i), Invalid)
+ << MII->getName(i)
+ << ": mismatched expectation for tail-predicated safety\n";
+ }
+}