: SubtargetFeature<"hvx-double", "UseHVX128BOps", "true",
"Hexagon HVX 128B instructions", [ExtensionHVX128B]>;
+def FeaturePackets: SubtargetFeature<"packets", "UsePackets", "true",
+ "Support for instruction packets">;
def FeatureLongCalls: SubtargetFeature<"long-calls", "UseLongCalls", "true",
"Use constant-extended calls">;
def FeatureMemNoShuf: SubtargetFeature<"mem_noshuf", "HasMemNoShuf", "false",
"Supports mem_noshuf feature">;
+def FeatureNVJ : SubtargetFeature<"nvj", "UseNewValueJumps", "true",
+ "Support for new-value jumps", [FeaturePackets]>;
def FeatureDuplex : SubtargetFeature<"duplex", "EnableDuplex", "true",
"Enable generation of duplex instruction">;
def FeatureReservedR19: SubtargetFeature<"reserved-r19", "ReservedR19",
: ProcessorModel<Name, Model, Features>;
def : Proc<"hexagonv4", HexagonModelV4,
- [ArchV4, FeatureDuplex]>;
+ [ArchV4, FeaturePackets, FeatureNVJ, FeatureDuplex]>;
def : Proc<"hexagonv5", HexagonModelV4,
- [ArchV4, ArchV5, FeatureDuplex]>;
+ [ArchV4, ArchV5, FeaturePackets, FeatureNVJ, FeatureDuplex]>;
def : Proc<"hexagonv55", HexagonModelV55,
- [ArchV4, ArchV5, ArchV55, FeatureDuplex]>;
+ [ArchV4, ArchV5, ArchV55, FeaturePackets, FeatureNVJ,
+ FeatureDuplex]>;
def : Proc<"hexagonv60", HexagonModelV60,
- [ArchV4, ArchV5, ArchV55, ArchV60, FeatureDuplex]>;
+ [ArchV4, ArchV5, ArchV55, ArchV60, FeaturePackets, FeatureNVJ,
+ FeatureDuplex]>;
def : Proc<"hexagonv62", HexagonModelV62,
- [ArchV4, ArchV5, ArchV55, ArchV60, ArchV62, FeatureDuplex]>;
+ [ArchV4, ArchV5, ArchV55, ArchV60, ArchV62, FeaturePackets,
+ FeatureNVJ, FeatureDuplex]>;
def : Proc<"hexagonv65", HexagonModelV65,
[ArchV4, ArchV5, ArchV55, ArchV60, ArchV62, ArchV65,
- FeatureMemNoShuf, FeatureDuplex]>;
+ FeatureMemNoShuf, FeaturePackets, FeatureNVJ, FeatureDuplex]>;
//===----------------------------------------------------------------------===//
// Declare the target which we are implementing
const MCInstrInfo &MCII = *Subtarget->getInstrInfo();
if (MI->isBundle()) {
+ assert(Subtarget->usePackets() && "Support for packets is disabled");
const MachineBasicBlock* MBB = MI->getParent();
MachineBasicBlock::const_instr_iterator MII = MI->getIterator();
}
void HexagonDAGToDAGISel::SelectV65GatherPred(SDNode *N) {
+ if (!HST->usePackets()) {
+ report_fatal_error("Support for gather requires packets, "
+ "which are disabled");
+ }
const SDLoc &dl(N);
SDValue Chain = N->getOperand(0);
SDValue Address = N->getOperand(2);
}
void HexagonDAGToDAGISel::SelectV65Gather(SDNode *N) {
+ if (!HST->usePackets()) {
+ report_fatal_error("Support for gather requires packets, "
+ "which are disabled");
+ }
const SDLoc &dl(N);
SDValue Chain = N->getOperand(0);
SDValue Address = N->getOperand(2);
#include "Hexagon.h"
#include "HexagonInstrInfo.h"
#include "HexagonRegisterInfo.h"
+#include "HexagonSubtarget.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/CodeGen/MachineBasicBlock.h"
#include "llvm/CodeGen/MachineBranchProbabilityInfo.h"
MF.getSubtarget().getRegisterInfo());
MBPI = &getAnalysis<MachineBranchProbabilityInfo>();
- if (DisableNewValueJumps) {
+ if (DisableNewValueJumps ||
+ !MF.getSubtarget<HexagonSubtarget>().useNewValueJumps())
return false;
- }
int nvjCount = DbgNVJCount;
int nvjGenerated = 0;
bool UseMemOps, UseHVX64BOps, UseHVX128BOps;
bool UseLongCalls;
+ bool UsePackets = false;
+ bool UseNewValueJumps = false;
bool ModeIEEERndNear;
bool HasMemNoShuf = false;
bool useHVXOps() const { return HexagonHVXVersion > Hexagon::ArchEnum::V4; }
bool useHVX128BOps() const { return useHVXOps() && UseHVX128BOps; }
bool useHVX64BOps() const { return useHVXOps() && UseHVX64BOps; }
+ bool usePackets() const { return UsePackets; }
+ bool useNewValueJumps() const { return UseNewValueJumps; }
+
bool hasMemNoShuf() const { return HasMemNoShuf; }
bool hasReservedR19() const { return ReservedR19; }
bool useLongCalls() const { return UseLongCalls; }
}
bool HexagonPacketizer::runOnMachineFunction(MachineFunction &MF) {
- if (DisablePacketizer || skipFunction(MF.getFunction()))
+ auto &HST = MF.getSubtarget<HexagonSubtarget>();
+ if (DisablePacketizer || !HST.usePackets() || skipFunction(MF.getFunction()))
return false;
- HII = MF.getSubtarget<HexagonSubtarget>().getInstrInfo();
- HRI = MF.getSubtarget<HexagonSubtarget>().getRegisterInfo();
+ HII = HST.getInstrInfo();
+ HRI = HST.getRegisterInfo();
auto &MLI = getAnalysis<MachineLoopInfo>();
auto *AA = &getAnalysis<AAResultsWrapperPass>().getAAResults();
auto *MBPI = &getAnalysis<MachineBranchProbabilityInfo>();
--- /dev/null
+; RUN: llc -march=hexagon -mattr=+hvxv60,hvx-length64b < %s | FileCheck %s --check-prefix=CHECK-GATHER
+; RUN: not llc -march=hexagon -mattr=+hvxv60,hvx-length64b,-packets %s -o /dev/null 2>&1 | FileCheck %s --check-prefix=CHECK-ERROR
+
+target triple = "hexagon"
+
+; CHECK-GATHER-LABEL: fred:
+; CHECK-GATHER: vgather
+; CHECK-ERROR: LLVM ERROR: Support for gather requires packets, which are disabled
+
+define void @fred(i8* %p, i32 %x, i32 %y) local_unnamed_addr #0 {
+entry:
+ %v = alloca <16 x i32>, align 64
+ %0 = bitcast <16 x i32>* %v to i8*
+ call void @llvm.lifetime.start(i64 64, i8* nonnull %0) #3
+ tail call void @llvm.hexagon.V6.vgathermw(i8* %p, i32 %x, i32 %y, <16 x i32> undef)
+ call void @foo(i8* nonnull %0) #0
+ call void @llvm.lifetime.end(i64 64, i8* nonnull %0) #3
+ ret void
+}
+
+declare void @llvm.lifetime.start(i64, i8* nocapture) #1
+declare void @llvm.hexagon.V6.vgathermw(i8*, i32, i32, <16 x i32>) #1
+declare void @foo(i8*) local_unnamed_addr #0
+declare void @llvm.lifetime.end(i64, i8* nocapture) #1
+
+attributes #0 = { nounwind "target-cpu"="hexagonv65" }
+attributes #1 = { argmemonly nounwind }
--- /dev/null
+; RUN: llc -march=hexagon < %s | FileCheck %s
+; Check that there are no packets with two or more instructions, except
+; for the endloop packet.
+
+; This is the expected code:
+;
+; p0 = cmp.gt(r3,#0)
+; if (!p0) jump:nt .LBB0_3
+; loop0(.LBB0_2,r3)
+; r3 = memw(r1++#4)
+; r4 = memw(r2++#4)
+; r3 = add(r4,r3)
+; memw(r0++#4) = r3
+; { nop; nop }:endloop0
+; jumpr r31
+
+; CHECK-LABEL: fred:
+; CHECK: {
+; CHECK-NEXT: cmp
+; CHECK-NEXT: }
+; CHECK: {
+; CHECK-NEXT: jump
+; CHECK-NEXT: }
+; CHECK: {
+; CHECK-NEXT: loop0
+; CHECK-NEXT: }
+; CHECK: {
+; CHECK-NEXT: memw
+; CHECK-NEXT: }
+; CHECK: {
+; CHECK-NEXT: memw
+; CHECK-NEXT: }
+; CHECK: {
+; CHECK-NEXT: add
+; CHECK-NEXT: }
+; CHECK: {
+; CHECK-NEXT: memw
+; CHECK-NEXT: }
+; CHECK: {
+; CHECK-NEXT: nop
+; CHECK-NEXT: nop
+; CHECK-NEXT: }{{[ \t]*}}:endloop0
+; CHECK: {
+; CHECK-NEXT: jumpr r31
+; CHECK-NEXT: }
+
+target triple = "hexagon"
+
+
+define void @fred(i32* nocapture %a0, i32* nocapture readonly %a1, i32* nocapture readonly %a2, i32 %a3) local_unnamed_addr #0 {
+b4:
+ %v5 = icmp sgt i32 %a3, 0
+ br i1 %v5, label %b6, label %b21
+
+b6: ; preds = %b4
+ br label %b7
+
+b7: ; preds = %b7, %b6
+ %v8 = phi i32 [ %v18, %b7 ], [ 0, %b6 ]
+ %v9 = phi i32* [ %v17, %b7 ], [ %a0, %b6 ]
+ %v10 = phi i32* [ %v14, %b7 ], [ %a2, %b6 ]
+ %v11 = phi i32* [ %v12, %b7 ], [ %a1, %b6 ]
+ %v12 = getelementptr inbounds i32, i32* %v11, i32 1
+ %v13 = load i32, i32* %v11, align 4
+ %v14 = getelementptr inbounds i32, i32* %v10, i32 1
+ %v15 = load i32, i32* %v10, align 4
+ %v16 = add nsw i32 %v15, %v13
+ %v17 = getelementptr inbounds i32, i32* %v9, i32 1
+ store i32 %v16, i32* %v9, align 4
+ %v18 = add nuw nsw i32 %v8, 1
+ %v19 = icmp eq i32 %v18, %a3
+ br i1 %v19, label %b20, label %b7
+
+b20: ; preds = %b7
+ br label %b21
+
+b21: ; preds = %b20, %b4
+ ret void
+}
+
+attributes #0 = { norecurse nounwind "target-cpu"="hexagonv60" "target-features"="-packets" }
+