def ARMv7k : Architecture<"armv7k", "ARMv7a", [ARMv7a]>;
def ARMv7s : Architecture<"armv7s", "ARMv7a", [ARMv7a]>;
-
-//===----------------------------------------------------------------------===//
-// ARM schedules.
-//===----------------------------------------------------------------------===//
-//
-include "ARMPredicates.td"
-include "ARMSchedule.td"
-
//===----------------------------------------------------------------------===//
// Register File Description
//===----------------------------------------------------------------------===//
include "ARMCallingConv.td"
//===----------------------------------------------------------------------===//
+// ARM schedules.
+//===----------------------------------------------------------------------===//
+//
+include "ARMPredicates.td"
+include "ARMSchedule.td"
+
+//===----------------------------------------------------------------------===//
// Instruction Descriptions
//===----------------------------------------------------------------------===//
// LDM, base reg in list
def IsLDMBaseRegInListPred : MCSchedPredicate<IsLDMBaseRegInList>;
+class IsRegPCPred<int n> : MCSchedPredicate<CheckRegOperand<n, PC>>;
+
+class BranchWriteRes<int lat, int uops, list<ProcResourceKind> resl,
+ list<int> rcl, SchedWriteRes wr> :
+ SchedWriteRes<!listconcat(wr.ProcResources, resl)> {
+ let Latency = !add(wr.Latency, lat);
+ let ResourceCycles = !listconcat(wr.ResourceCycles, rcl);
+ let NumMicroOps = !add(wr.NumMicroOps, uops);
+ SchedWriteRes BaseWr = wr;
+}
+
+class CheckBranchForm<int n, BranchWriteRes br> :
+ SchedWriteVariant<[
+ SchedVar<IsRegPCPred<n>, [br]>,
+ SchedVar<NoSchedPred, [br.BaseWr]>
+ ]>;
+
//===----------------------------------------------------------------------===//
// Instruction Itinerary classes used for ARM
//
def : InstRW<[A57Write_1cyc_1I], (instregex "tADDframe")>;
+// Check branch forms of ALU ops:
+// check reg 0 for ARM_AM::PC
+// if so adds 2 cyc to latency, 1 uop, 1 res cycle for A57UnitB
+class A57BranchForm<SchedWriteRes non_br> :
+ BranchWriteRes<2, 1, [A57UnitB], [1], non_br>;
+
// shift by register, conditional or unconditional
// TODO: according to the doc, conditional uses I0/I1, unconditional uses M
// Why more complex instruction uses more simple pipeline?
// May be an error in doc.
def A57WriteALUsi : SchedWriteVariant<[
// lsl #2, lsl #1, or lsr #1.
- SchedVar<IsPredicatedPred, [A57Write_2cyc_1M]>,
- SchedVar<NoSchedPred, [A57Write_2cyc_1M]>
+ SchedVar<IsPredicatedPred, [CheckBranchForm<0, A57BranchForm<A57Write_2cyc_1M>>]>,
+ SchedVar<NoSchedPred, [CheckBranchForm<0, A57BranchForm<A57Write_2cyc_1M>>]>
]>;
def A57WriteALUsr : SchedWriteVariant<[
- SchedVar<IsPredicatedPred, [A57Write_2cyc_1I]>,
- SchedVar<NoSchedPred, [A57Write_2cyc_1M]>
+ SchedVar<IsPredicatedPred, [CheckBranchForm<0, A57BranchForm<A57Write_2cyc_1I>>]>,
+ SchedVar<NoSchedPred, [CheckBranchForm<0, A57BranchForm<A57Write_2cyc_1M>>]>
]>;
def A57WriteALUSsr : SchedWriteVariant<[
- SchedVar<IsPredicatedPred, [A57Write_2cyc_1I]>,
- SchedVar<NoSchedPred, [A57Write_2cyc_1M]>
+ SchedVar<IsPredicatedPred, [CheckBranchForm<0, A57BranchForm<A57Write_2cyc_1I>>]>,
+ SchedVar<NoSchedPred, [CheckBranchForm<0, A57BranchForm<A57Write_2cyc_1M>>]>
]>;
def A57ReadALUsr : SchedReadVariant<[
SchedVar<IsPredicatedPred, [ReadDefault]>,
SchedVar<A57LMAddrPred5, A57VLDMOpsListUncond.Writes[0-9]>,
SchedVar<A57LMAddrPred6, A57VLDMOpsListUncond.Writes[0-11]>,
SchedVar<A57LMAddrPred7, A57VLDMOpsListUncond.Writes[0-13]>,
- SchedVar<A57LMAddrPred8, A57VLDMOpsListUncond.Writes[0-15]>,
SchedVar<NoSchedPred, A57VLDMOpsListUncond.Writes[0-15]>
]> { let Variadic=1; }
SchedVar<A57LMAddrPred5, A57VLDMOpsListCond.Writes[0-9]>,
SchedVar<A57LMAddrPred6, A57VLDMOpsListCond.Writes[0-11]>,
SchedVar<A57LMAddrPred7, A57VLDMOpsListCond.Writes[0-13]>,
- SchedVar<A57LMAddrPred8, A57VLDMOpsListCond.Writes[0-15]>,
SchedVar<NoSchedPred, A57VLDMOpsListCond.Writes[0-15]>
]> { let Variadic=1; }
SchedVar<A57LMAddrPred5, A57VLDMOpsListUncond_Upd.Writes[0-9]>,
SchedVar<A57LMAddrPred6, A57VLDMOpsListUncond_Upd.Writes[0-11]>,
SchedVar<A57LMAddrPred7, A57VLDMOpsListUncond_Upd.Writes[0-13]>,
- SchedVar<A57LMAddrPred8, A57VLDMOpsListUncond_Upd.Writes[0-15]>,
SchedVar<NoSchedPred, A57VLDMOpsListUncond_Upd.Writes[0-15]>
]> { let Variadic=1; }
SchedVar<A57LMAddrPred5, A57VLDMOpsListCond_Upd.Writes[0-9]>,
SchedVar<A57LMAddrPred6, A57VLDMOpsListCond_Upd.Writes[0-11]>,
SchedVar<A57LMAddrPred7, A57VLDMOpsListCond_Upd.Writes[0-13]>,
- SchedVar<A57LMAddrPred8, A57VLDMOpsListCond_Upd.Writes[0-15]>,
SchedVar<NoSchedPred, A57VLDMOpsListCond_Upd.Writes[0-15]>
]> { let Variadic=1; }
// -----------------------------------------------------------------------------
// Common definitions
def : WriteRes<WriteNoop, []> { let Latency = 0; let NumMicroOps = 0; }
-def : SchedAlias<WriteALU, A57Write_1cyc_1I>;
+def : SchedAlias<WriteALU, CheckBranchForm<0, A57BranchForm<A57Write_1cyc_1I>>>;
def : SchedAlias<WriteBr, A57Write_1cyc_1B>;
def : SchedAlias<WriteBrL, A57Write_1cyc_1B_1I>;
def A57Write_20cyc_1M : SchedWriteRes<[A57UnitM]> { let Latency = 20;
let ResourceCycles = [20]; }
def A57Write_1cyc_1B : SchedWriteRes<[A57UnitB]> { let Latency = 1; }
-def A57Write_1cyc_1I : SchedWriteRes<[A57UnitI]> { let Latency = 1; }
-def A57Write_2cyc_1I : SchedWriteRes<[A57UnitI]> { let Latency = 2; }
+def A57Write_1cyc_1I : SchedWriteRes<[A57UnitI]> { let Latency = 1;
+ let ResourceCycles = [1]; }
+def A57Write_2cyc_1I : SchedWriteRes<[A57UnitI]> { let Latency = 2;
+ let ResourceCycles = [1]; }
def A57Write_3cyc_1I : SchedWriteRes<[A57UnitI]> { let Latency = 3; }
def A57Write_1cyc_1S : SchedWriteRes<[A57UnitS]> { let Latency = 1; }
def A57Write_2cyc_1S : SchedWriteRes<[A57UnitS]> { let Latency = 2; }
def A57Write_3cyc_1S : SchedWriteRes<[A57UnitS]> { let Latency = 3; }
-def A57Write_2cyc_1M : SchedWriteRes<[A57UnitM]> { let Latency = 2; }
+def A57Write_2cyc_1M : SchedWriteRes<[A57UnitM]> { let Latency = 2;
+ let ResourceCycles = [1]; }
def A57Write_32cyc_1W : SchedWriteRes<[A57UnitW]> { let Latency = 32;
let ResourceCycles = [32]; }
def A57Write_32cyc_1X : SchedWriteRes<[A57UnitX]> { let Latency = 32;
# CHECK: [1] [2] [3] [4] [5] [6] Instructions:
# CHECK-NEXT: 1 1 0.50 adc r1, r2, #15
-# CHECK-NEXT: 1 1 0.50 adc pc, r2, #16
+# CHECK-NEXT: 2 3 1.00 adc pc, r2, #16
# CHECK-NEXT: 1 1 0.50 adc r1, r2, #240
# CHECK-NEXT: 1 1 0.50 adc r1, r2, #3840
# CHECK-NEXT: 1 1 0.50 adc r1, r2, #61440
# CHECK-NEXT: 1 1 0.50 adcseq r1, r2, #3840
# CHECK-NEXT: 1 1 0.50 adceq r1, r2, #3840
# CHECK-NEXT: 1 1 0.50 adc r4, r5, r6
-# CHECK-NEXT: 1 1 0.50 adc pc, r5, r6
+# CHECK-NEXT: 2 3 1.00 adc pc, r5, r6
# CHECK-NEXT: 1 2 1.00 adc r4, r5, r6, lsl #1
-# CHECK-NEXT: 1 2 1.00 adc pc, r5, r6, lsl #4
+# CHECK-NEXT: 2 4 1.00 adc pc, r5, r6, lsl #4
# CHECK-NEXT: 1 2 1.00 adc r4, r5, r6, lsl #31
# CHECK-NEXT: 1 2 1.00 adc r4, r5, r6, lsr #1
# CHECK-NEXT: 1 2 1.00 adc r4, r5, r6, lsr #31
# CHECK-NEXT: 1 2 1.00 adc r4, r5, r6, asr #31
# CHECK-NEXT: 1 2 1.00 adc r4, r5, r6, asr #32
# CHECK-NEXT: 1 2 1.00 adc r4, r5, r6, ror #1
-# CHECK-NEXT: 1 2 1.00 adc pc, r5, r6, ror #2
+# CHECK-NEXT: 2 4 1.00 adc pc, r5, r6, ror #2
# CHECK-NEXT: 1 2 1.00 adc r4, r5, r6, ror #31
# CHECK-NEXT: 1 2 1.00 adc r6, r7, r8, lsl r9
# CHECK-NEXT: 1 2 1.00 adc r6, r7, r8, lsr r9
# CHECK-NEXT: 1 1 0.50 adds r7, r8, #-2147483638
# CHECK-NEXT: 1 1 0.50 adds r7, r8, #40, #2
# CHECK-NEXT: 1 1 0.50 adr r2, #3
-# CHECK-NEXT: 1 1 0.50 and pc, pc, #8
+# CHECK-NEXT: 2 3 1.00 and pc, pc, #8
# CHECK-NEXT: 1 1 0.50 sub r2, pc, #3
# CHECK-NEXT: 1 1 0.50 sub r1, pc, #0
-# CHECK-NEXT: 1 1 0.50 sub pc, r2, #8
+# CHECK-NEXT: 2 3 1.00 sub pc, r2, #8
# CHECK-NEXT: 1 1 0.50 sub r1, pc, #301989888
# CHECK-NEXT: 1 1 0.50 adr r1, #301989888
# CHECK-NEXT: 1 1 0.50 and r10, r1, #15
# CHECK-NEXT: 1 2 1.00 bic r6, r7, r8, ror r2
# CHECK-NEXT: 1 2 1.00 bic r10, r1, r6, rrx
# CHECK-NEXT: 1 1 0.50 bic r1, r1, #15
-# CHECK-NEXT: 1 1 0.50 bic pc, r1, #15
+# CHECK-NEXT: 2 3 1.00 bic pc, r1, #15
# CHECK-NEXT: 1 1 0.50 bic r10, r10, r1
# CHECK-NEXT: 1 2 1.00 bic r10, r10, r1, lsl #10
# CHECK-NEXT: 1 2 1.00 bic r10, r10, r1, lsr #10
# CHECK-NEXT: 1 1 0.50 eor r7, r8, #-2147483638
# CHECK-NEXT: 1 1 0.50 eor r7, r8, #40, #2
# CHECK-NEXT: 1 1 0.50 eor r4, r5, r6
-# CHECK-NEXT: 1 1 0.50 eor pc, r5, r6
+# CHECK-NEXT: 2 3 1.00 eor pc, r5, r6
# CHECK-NEXT: 1 2 1.00 eor r4, r5, r6, lsl #5
# CHECK-NEXT: 1 2 1.00 eor r4, r5, r6, lsr #5
# CHECK-NEXT: 1 2 1.00 eor r4, r5, r6, lsr #5
# CHECK: Resource pressure per iteration:
# CHECK-NEXT: [0] [1.0] [1.1] [2] [3] [4] [5] [6]
-# CHECK-NEXT: 8.00 144.50 144.50 53.00 524.00 12.00 - -
+# CHECK-NEXT: 16.00 144.50 144.50 53.00 524.00 12.00 - -
# CHECK: Resource pressure by instruction:
# CHECK-NEXT: [0] [1.0] [1.1] [2] [3] [4] [5] [6] Instructions:
# CHECK-NEXT: - 0.50 0.50 - - - - - adc r1, r2, #15
-# CHECK-NEXT: - 0.50 0.50 - - - - - adc pc, r2, #16
+# CHECK-NEXT: 1.00 0.50 0.50 - - - - - adc pc, r2, #16
# CHECK-NEXT: - 0.50 0.50 - - - - - adc r1, r2, #240
# CHECK-NEXT: - 0.50 0.50 - - - - - adc r1, r2, #3840
# CHECK-NEXT: - 0.50 0.50 - - - - - adc r1, r2, #61440
# CHECK-NEXT: - 0.50 0.50 - - - - - adcseq r1, r2, #3840
# CHECK-NEXT: - 0.50 0.50 - - - - - adceq r1, r2, #3840
# CHECK-NEXT: - 0.50 0.50 - - - - - adc r4, r5, r6
-# CHECK-NEXT: - 0.50 0.50 - - - - - adc pc, r5, r6
+# CHECK-NEXT: 1.00 0.50 0.50 - - - - - adc pc, r5, r6
# CHECK-NEXT: - - - - 1.00 - - - adc r4, r5, r6, lsl #1
-# CHECK-NEXT: - - - - 1.00 - - - adc pc, r5, r6, lsl #4
+# CHECK-NEXT: 1.00 - - - 1.00 - - - adc pc, r5, r6, lsl #4
# CHECK-NEXT: - - - - 1.00 - - - adc r4, r5, r6, lsl #31
# CHECK-NEXT: - - - - 1.00 - - - adc r4, r5, r6, lsr #1
# CHECK-NEXT: - - - - 1.00 - - - adc r4, r5, r6, lsr #31
# CHECK-NEXT: - - - - 1.00 - - - adc r4, r5, r6, asr #31
# CHECK-NEXT: - - - - 1.00 - - - adc r4, r5, r6, asr #32
# CHECK-NEXT: - - - - 1.00 - - - adc r4, r5, r6, ror #1
-# CHECK-NEXT: - - - - 1.00 - - - adc pc, r5, r6, ror #2
+# CHECK-NEXT: 1.00 - - - 1.00 - - - adc pc, r5, r6, ror #2
# CHECK-NEXT: - - - - 1.00 - - - adc r4, r5, r6, ror #31
# CHECK-NEXT: - - - - 1.00 - - - adc r6, r7, r8, lsl r9
# CHECK-NEXT: - - - - 1.00 - - - adc r6, r7, r8, lsr r9
# CHECK-NEXT: - 0.50 0.50 - - - - - adds r7, r8, #-2147483638
# CHECK-NEXT: - 0.50 0.50 - - - - - adds r7, r8, #40, #2
# CHECK-NEXT: - 0.50 0.50 - - - - - adr r2, #3
-# CHECK-NEXT: - 0.50 0.50 - - - - - and pc, pc, #8
+# CHECK-NEXT: 1.00 0.50 0.50 - - - - - and pc, pc, #8
# CHECK-NEXT: - 0.50 0.50 - - - - - sub r2, pc, #3
# CHECK-NEXT: - 0.50 0.50 - - - - - sub r1, pc, #0
-# CHECK-NEXT: - 0.50 0.50 - - - - - sub pc, r2, #8
+# CHECK-NEXT: 1.00 0.50 0.50 - - - - - sub pc, r2, #8
# CHECK-NEXT: - 0.50 0.50 - - - - - sub r1, pc, #301989888
# CHECK-NEXT: - 0.50 0.50 - - - - - adr r1, #301989888
# CHECK-NEXT: - 0.50 0.50 - - - - - and r10, r1, #15
# CHECK-NEXT: - - - - 1.00 - - - bic r6, r7, r8, ror r2
# CHECK-NEXT: - - - - 1.00 - - - bic r10, r1, r6, rrx
# CHECK-NEXT: - 0.50 0.50 - - - - - bic r1, r1, #15
-# CHECK-NEXT: - 0.50 0.50 - - - - - bic pc, r1, #15
+# CHECK-NEXT: 1.00 0.50 0.50 - - - - - bic pc, r1, #15
# CHECK-NEXT: - 0.50 0.50 - - - - - bic r10, r10, r1
# CHECK-NEXT: - - - - 1.00 - - - bic r10, r10, r1, lsl #10
# CHECK-NEXT: - - - - 1.00 - - - bic r10, r10, r1, lsr #10
# CHECK-NEXT: - 0.50 0.50 - - - - - eor r7, r8, #-2147483638
# CHECK-NEXT: - 0.50 0.50 - - - - - eor r7, r8, #40, #2
# CHECK-NEXT: - 0.50 0.50 - - - - - eor r4, r5, r6
-# CHECK-NEXT: - 0.50 0.50 - - - - - eor pc, r5, r6
+# CHECK-NEXT: 1.00 0.50 0.50 - - - - - eor pc, r5, r6
# CHECK-NEXT: - - - - 1.00 - - - eor r4, r5, r6, lsl #5
# CHECK-NEXT: - - - - 1.00 - - - eor r4, r5, r6, lsr #5
# CHECK-NEXT: - - - - 1.00 - - - eor r4, r5, r6, lsr #5
#endif
private:
- bool mutuallyExclusive(Record *PredDef, ArrayRef<PredCheck> Term);
+ bool mutuallyExclusive(Record *PredDef, ArrayRef<Record *> Preds,
+ ArrayRef<PredCheck> Term);
void getIntersectingVariants(
const CodeGenSchedRW &SchedRW, unsigned TransIdx,
std::vector<TransVariant> &IntersectingVariants);
// are always checked in the order they are defined in the .td file. Later
// conditions implicitly negate any prior condition.
bool PredTransitions::mutuallyExclusive(Record *PredDef,
+ ArrayRef<Record *> Preds,
ArrayRef<PredCheck> Term) {
for (const PredCheck &PC: Term) {
if (PC.Predicate == PredDef)
RecVec Variants = SchedRW.TheDef->getValueAsListOfDefs("Variants");
if (any_of(Variants, [PredDef](const Record *R) {
return R->getValueAsDef("Predicate") == PredDef;
- }))
+ })) {
+ // To check if PredDef is mutually exclusive with PC we also need to
+ // check that PC.Predicate is exclusive with all predicates from variant
+ // we're expanding. Consider following RW sequence with two variants
+ // (1 & 2), where A, B and C are predicates from corresponding SchedVars:
+ //
+ // 1:A/B - 2:C/B
+ //
+ // Here C is not mutually exclusive with variant (1), because A doesn't
+ // exist in variant (2). This means we have possible transitions from A
+ // to C and from A to B, and fully expanded sequence would look like:
+ //
+ // if (A & C) return ...;
+ // if (A & B) return ...;
+ // if (B) return ...;
+ //
+ // Now let's consider another sequence:
+ //
+ // 1:A/B - 2:A/B
+ //
+ // Here A in variant (2) is mutually exclusive with variant (1), because
+ // A also exists in (2). This means A->B transition is impossible and
+ // expanded sequence would look like:
+ //
+ // if (A) return ...;
+ // if (B) return ...;
+ if (!count(Preds, PC.Predicate))
+ continue;
return true;
+ }
}
return false;
}
return false;
}
+static std::vector<Record *> getAllPredicates(ArrayRef<TransVariant> Variants) {
+ std::vector<Record *> Preds;
+ for (auto &Variant : Variants) {
+ assert(Variant.VarOrSeqDef->isSubClassOf("SchedVar"));
+ Preds.push_back(Variant.VarOrSeqDef->getValueAsDef("Predicate"));
+ }
+ return Preds;
+}
+
// Populate IntersectingVariants with any variants or aliased sequences of the
// given SchedRW whose processor indices and predicates are not mutually
// exclusive with the given transition.
if (AliasProcIdx == 0)
GenericRW = true;
}
+ std::vector<Record *> AllPreds = getAllPredicates(Variants);
for (TransVariant &Variant : Variants) {
// Don't expand variants if the processor models don't intersect.
// A zero processor index means any processor.
" Ensure only one SchedAlias exists per RW.");
}
}
- if (Variant.VarOrSeqDef->isSubClassOf("SchedVar")) {
- Record *PredDef = Variant.VarOrSeqDef->getValueAsDef("Predicate");
- if (mutuallyExclusive(PredDef, TransVec[TransIdx].PredTerm))
- continue;
- }
+ Record *PredDef = Variant.VarOrSeqDef->getValueAsDef("Predicate");
+ if (mutuallyExclusive(PredDef, AllPreds, TransVec[TransIdx].PredTerm))
+ continue;
+
if (IntersectingVariants.empty()) {
// The first variant builds on the existing transition.
Variant.TransVecIdx = TransIdx;
OS << Buffer;
}
+static bool isTruePredicate(const Record *Rec) {
+ return Rec->isSubClassOf("MCSchedPredicate") &&
+ Rec->getValueAsDef("Pred")->isSubClassOf("MCTrue");
+}
+
static void emitPredicates(const CodeGenSchedTransition &T,
const CodeGenSchedClass &SC, PredicateExpander &PE,
raw_ostream &OS) {
std::string Buffer;
raw_string_ostream SS(Buffer);
- auto IsTruePredicate = [](const Record *Rec) {
- return Rec->isSubClassOf("MCSchedPredicate") &&
- Rec->getValueAsDef("Pred")->isSubClassOf("MCTrue");
- };
-
// If not all predicates are MCTrue, then we need an if-stmt.
unsigned NumNonTruePreds =
- T.PredTerm.size() - count_if(T.PredTerm, IsTruePredicate);
+ T.PredTerm.size() - count_if(T.PredTerm, isTruePredicate);
SS.indent(PE.getIndentLevel() * 2);
for (const Record *Rec : T.PredTerm) {
// Skip predicates that evaluate to "true".
- if (IsTruePredicate(Rec))
+ if (isTruePredicate(Rec))
continue;
if (FirstNonTruePredicate) {
}
}
+static bool isAlwaysTrue(const CodeGenSchedTransition &T) {
+ return llvm::all_of(T.PredTerm,
+ [](const Record *R) { return isTruePredicate(R); });
+}
+
void SubtargetEmitter::emitSchedModelHelpersImpl(
raw_ostream &OS, bool OnlyExpandMCInstPredicates) {
IdxVec VariantClasses;
}
// Now emit transitions associated with processor PI.
+ const CodeGenSchedTransition *FinalT = nullptr;
for (const CodeGenSchedTransition &T : SC.Transitions) {
if (PI != 0 && !count(T.ProcIndices, PI))
continue;
if (OnlyExpandMCInstPredicates && !hasMCSchedPredicates(T))
continue;
+ // If transition is folded to 'return X' it should be the last one.
+ if (isAlwaysTrue(T)) {
+ FinalT = &T;
+ continue;
+ }
PE.setIndentLevel(3);
emitPredicates(T, SchedModels.getSchedClass(T.ToClassIdx), PE, OS);
}
+ if (FinalT)
+ emitPredicates(*FinalT, SchedModels.getSchedClass(FinalT->ToClassIdx),
+ PE, OS);
OS << " }\n";