From 6f86e6bf4043b0fc75d285bac06ebc7c3f5828b0 Mon Sep 17 00:00:00 2001 From: Sam Parker Date: Tue, 24 Mar 2020 08:23:05 +0000 Subject: [PATCH] [ARM][MVE] Add target flag for narrowing insts Add a flag, 'RetainsPreviousHalfElement', for operations that operate on top/bottom halves of their input and only write to half of their destination, leaving the other half to retain its previous value. Differential Revision: https://reviews.llvm.org/D76608 --- llvm/lib/Target/ARM/ARMInstrFormats.td | 2 + llvm/lib/Target/ARM/ARMInstrMVE.td | 5 + .../lib/Target/ARM/MCTargetDesc/ARMBaseInfo.h | 4 + .../unittests/Target/ARM/MachineInstrTest.cpp | 101 +++++++++++++++++- 4 files changed, 111 insertions(+), 1 deletion(-) diff --git a/llvm/lib/Target/ARM/ARMInstrFormats.td b/llvm/lib/Target/ARM/ARMInstrFormats.td index 6e4a8ebab14c..535784bc3ce3 100644 --- a/llvm/lib/Target/ARM/ARMInstrFormats.td +++ b/llvm/lib/Target/ARM/ARMInstrFormats.td @@ -408,6 +408,7 @@ class InstTemplate(f), "Pseudo"); @@ -421,6 +422,7 @@ class InstTemplate { @@ -2730,6 +2731,7 @@ class MVE_VxQRSHRUN { @@ -4492,6 +4495,7 @@ class MVE_VxMOVxN { diff --git a/llvm/lib/Target/ARM/MCTargetDesc/ARMBaseInfo.h b/llvm/lib/Target/ARM/MCTargetDesc/ARMBaseInfo.h index 6293a2462306..0c9925cf1d9e 100644 --- a/llvm/lib/Target/ARM/MCTargetDesc/ARMBaseInfo.h +++ b/llvm/lib/Target/ARM/MCTargetDesc/ARMBaseInfo.h @@ -396,6 +396,10 @@ namespace ARMII { // Whether an instruction can be included in an MVE tail-predicated loop. ValidForTailPredication = 1 << 20, + // Whether an instruction writes to the top/bottom half of a vector element + // and leaves the other half untouched. + RetainsPreviousHalfElement = 1 << 21, + //===------------------------------------------------------------------===// // Code domain. DomainShift = 15, diff --git a/llvm/unittests/Target/ARM/MachineInstrTest.cpp b/llvm/unittests/Target/ARM/MachineInstrTest.cpp index 94939603845d..609785818900 100644 --- a/llvm/unittests/Target/ARM/MachineInstrTest.cpp +++ b/llvm/unittests/Target/ARM/MachineInstrTest.cpp @@ -10,11 +10,110 @@ using namespace llvm; +TEST(MachineInstructionRetainsPreviousHalfElement, IsCorrect) { + using namespace ARM; + + auto RetainsPreviousHalfElement = [](unsigned Opcode) { + switch (Opcode) { + default: + break; + case MVE_VMOVNi16bh: + case MVE_VMOVNi16th: + case MVE_VMOVNi32bh: + case MVE_VMOVNi32th: + case MVE_VQMOVNs16bh: + case MVE_VQMOVNs16th: + case MVE_VQMOVNs32bh: + case MVE_VQMOVNs32th: + case MVE_VQMOVNu16bh: + case MVE_VQMOVNu16th: + case MVE_VQMOVNu32bh: + case MVE_VQMOVNu32th: + case MVE_VQMOVUNs16bh: + case MVE_VQMOVUNs16th: + case MVE_VQMOVUNs32bh: + case MVE_VQMOVUNs32th: + case MVE_VQRSHRNbhs16: + case MVE_VQRSHRNbhs32: + case MVE_VQRSHRNbhu16: + case MVE_VQRSHRNbhu32: + case MVE_VQRSHRNths16: + case MVE_VQRSHRNths32: + case MVE_VQRSHRNthu16: + case MVE_VQRSHRNthu32: + case MVE_VQRSHRUNs16bh: + case MVE_VQRSHRUNs16th: + case MVE_VQRSHRUNs32bh: + case MVE_VQRSHRUNs32th: + case MVE_VQSHRNbhs16: + case MVE_VQSHRNbhs32: + case MVE_VQSHRNbhu16: + case MVE_VQSHRNbhu32: + case MVE_VQSHRNths16: + case MVE_VQSHRNths32: + case MVE_VQSHRNthu16: + case MVE_VQSHRNthu32: + case MVE_VQSHRUNs16bh: + case MVE_VQSHRUNs16th: + case MVE_VQSHRUNs32bh: + case MVE_VQSHRUNs32th: + case MVE_VRSHRNi16bh: + case MVE_VRSHRNi16th: + case MVE_VRSHRNi32bh: + case MVE_VRSHRNi32th: + case MVE_VSHRNi16bh: + case MVE_VSHRNi16th: + case MVE_VSHRNi32bh: + case MVE_VSHRNi32th: + case MVE_VCVTf16f32bh: + case MVE_VCVTf16f32th: + case MVE_VCVTf32f16bh: + case MVE_VCVTf32f16th: + return true; + } + return false; + }; + + 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( + static_cast( + T->createTargetMachine(TT, "generic", "", Options, None, None, + CodeGenOpt::Default))); + ARMSubtarget ST(TM->getTargetTriple(), std::string(TM->getTargetCPU()), + std::string(TM->getTargetFeatureString()), + *static_cast(TM.get()), false); + const ARMBaseInstrInfo *TII = ST.getInstrInfo(); + auto MII = TM->getMCInstrInfo(); + + for (unsigned i = 0; i < ARM::INSTRUCTION_LIST_END; ++i) { + const MCInstrDesc &Desc = TII->get(i); + + uint64_t Flags = Desc.TSFlags; + if ((Flags & ARMII::DomainMask) != ARMII::DomainMVE) + continue; + + bool Valid = (Flags & ARMII::RetainsPreviousHalfElement) != 0; + ASSERT_EQ(RetainsPreviousHalfElement(i), Valid) + << MII->getName(i) + << ": mismatched expectation for tail-predicated safety\n"; + } +} // Test for instructions that aren't immediately obviously valid within a // tail-predicated loop. This should be marked up in their tablegen // descriptions. Currently we, conservatively, disallow: // - cross beat carries. -// - narrowing of results. // - complex operations. // - horizontal operations. // - byte swapping.