mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-04-18 19:38:51 +00:00
Implement a very very simple hazard recognizer for LSU rejects and ctr set/read
flushes git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@26587 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
b2d635803d
commit
c664418820
203
lib/Target/PowerPC/PPCHazardRecognizers.cpp
Normal file
203
lib/Target/PowerPC/PPCHazardRecognizers.cpp
Normal file
@ -0,0 +1,203 @@
|
||||
//===-- PPCHazardRecognizers.cpp - PowerPC Hazard Recognizer Impls --------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file was developed by Chris Lattner and is distributed under
|
||||
// the University of Illinois Open Source License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements hazard recognizers for scheduling on PowerPC processors.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#define DEBUG_TYPE "sched"
|
||||
#include "PPCHazardRecognizers.h"
|
||||
#include "PPC.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include <iostream>
|
||||
using namespace llvm;
|
||||
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// PowerPC 970 Hazard Recognizer
|
||||
//
|
||||
// FIXME: This is missing some significant cases:
|
||||
// 0. Handling of instructions that must be the first/last in a group.
|
||||
// 1. Modeling of microcoded instructions.
|
||||
// 2. Handling of cracked instructions.
|
||||
// 3. Handling of serialized operations.
|
||||
// 4. Handling of the esoteric cases in "Resource-based Instruction Grouping",
|
||||
// e.g. integer divides that only execute in the second slot.
|
||||
//
|
||||
// Note: on the PPC970, logical CR operations are more expensive in their three
|
||||
// address form: ops that read/write the same register are half as expensive as
|
||||
//
|
||||
|
||||
void PPCHazardRecognizer970::EndDispatchGroup() {
|
||||
DEBUG(std::cerr << "=== Start of dispatch group\n");
|
||||
// Pipeline units.
|
||||
NumFXU = NumLSU = NumFPU = 0;
|
||||
HasCR = HasVALU = HasVPERM = false;
|
||||
NumIssued = 0;
|
||||
|
||||
// Structural hazard info.
|
||||
HasCTRSet = false;
|
||||
StorePtr1 = StorePtr2 = SDOperand();
|
||||
StoreSize = 0;
|
||||
}
|
||||
|
||||
|
||||
PPCHazardRecognizer970::PPC970InstrType
|
||||
PPCHazardRecognizer970::GetInstrType(unsigned Opcode) {
|
||||
if (Opcode < ISD::BUILTIN_OP_END)
|
||||
return PseudoInst;
|
||||
Opcode -= ISD::BUILTIN_OP_END;
|
||||
|
||||
switch (Opcode) {
|
||||
case PPC::FMRSD: return PseudoInst; // Usually coallesced away.
|
||||
case PPC::BCTRL:
|
||||
case PPC::BL:
|
||||
case PPC::BLA:
|
||||
return BR;
|
||||
case PPC::LFS:
|
||||
case PPC::LWZ:
|
||||
return LSU_LD;
|
||||
case PPC::STFD:
|
||||
return LSU_ST;
|
||||
case PPC::FADDS:
|
||||
case PPC::FCTIWZ:
|
||||
return FPU;
|
||||
}
|
||||
|
||||
return FXU;
|
||||
}
|
||||
|
||||
|
||||
/// StartBasicBlock - Initiate a new dispatch group.
|
||||
void PPCHazardRecognizer970::StartBasicBlock() {
|
||||
EndDispatchGroup();
|
||||
}
|
||||
|
||||
/// isLoadOfStoredAddress - If we have a load from the previously stored pointer
|
||||
/// as indicated by StorePtr1/StorePtr2/StoreSize, return true.
|
||||
bool PPCHazardRecognizer970::
|
||||
isLoadOfStoredAddress(unsigned LoadSize, SDOperand Ptr1, SDOperand Ptr2) const {
|
||||
// Handle exact and commuted addresses.
|
||||
if (Ptr1 == StorePtr1 && Ptr2 == StorePtr2)
|
||||
return true;
|
||||
if (Ptr2 == StorePtr1 && Ptr1 == StorePtr2)
|
||||
return true;
|
||||
|
||||
// Okay, we don't have an exact match, if this is an indexed offset, see if we
|
||||
// have overlap (which happens during fp->int conversion for example).
|
||||
if (StorePtr2 == Ptr2) {
|
||||
if (ConstantSDNode *StoreOffset = dyn_cast<ConstantSDNode>(StorePtr1))
|
||||
if (ConstantSDNode *LoadOffset = dyn_cast<ConstantSDNode>(Ptr1)) {
|
||||
// Okay the base pointers match, so we have [c1+r] vs [c2+r]. Check to
|
||||
// see if the load and store actually overlap.
|
||||
int StoreOffs = StoreOffset->getValue();
|
||||
int LoadOffs = LoadOffset->getValue();
|
||||
if (StoreOffs < LoadOffs) {
|
||||
if (int(StoreOffs+StoreSize) > LoadOffs) return true;
|
||||
} else {
|
||||
if (int(LoadOffs+LoadSize) > StoreOffs) return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// getHazardType - We return hazard for any non-branch instruction that would
|
||||
/// terminate terminate the dispatch group. We turn NoopHazard for any
|
||||
/// instructions that wouldn't terminate the dispatch group that would cause a
|
||||
/// pipeline flush.
|
||||
HazardRecognizer::HazardType PPCHazardRecognizer970::
|
||||
getHazardType(SDNode *Node) {
|
||||
PPC970InstrType InstrType = GetInstrType(Node->getOpcode());
|
||||
if (InstrType == PseudoInst) return NoHazard;
|
||||
unsigned Opcode = Node->getOpcode()-ISD::BUILTIN_OP_END;
|
||||
|
||||
switch (InstrType) {
|
||||
default: assert(0 && "Unknown instruction type!");
|
||||
case FXU: if (NumFXU == 2) return Hazard;
|
||||
case LSU_ST:
|
||||
case LSU_LD: if (NumLSU == 2) return Hazard;
|
||||
case FPU: if (NumFPU == 2) return Hazard;
|
||||
case CR: if (HasCR) return Hazard;
|
||||
case VALU: if (HasVALU) return Hazard;
|
||||
case VPERM: if (HasVPERM) return Hazard;
|
||||
case BR: break;
|
||||
}
|
||||
|
||||
// We can only issue a branch as the last instruction in a group.
|
||||
if (NumIssued == 4 && InstrType != BR)
|
||||
return Hazard;
|
||||
|
||||
// Do not allow MTCTR and BCTRL to be in the same dispatch group.
|
||||
if (HasCTRSet && Opcode == PPC::BCTRL)
|
||||
return NoopHazard;
|
||||
|
||||
// If this is a load following a store, make sure it's not to the same or
|
||||
// overlapping address.
|
||||
if (InstrType == LSU_LD && StoreSize) {
|
||||
unsigned LoadSize;
|
||||
switch (Opcode) {
|
||||
default: assert(0 && "Unknown load!");
|
||||
case PPC::LFS:
|
||||
case PPC::LWZ: LoadSize = 4; break;
|
||||
}
|
||||
|
||||
if (isLoadOfStoredAddress(LoadSize,
|
||||
Node->getOperand(0), Node->getOperand(1)))
|
||||
return NoopHazard;
|
||||
}
|
||||
|
||||
return NoHazard;
|
||||
}
|
||||
|
||||
void PPCHazardRecognizer970::EmitInstruction(SDNode *Node) {
|
||||
PPC970InstrType InstrType = GetInstrType(Node->getOpcode());
|
||||
if (InstrType == PseudoInst) return;
|
||||
unsigned Opcode = Node->getOpcode()-ISD::BUILTIN_OP_END;
|
||||
|
||||
// Update structural hazard information.
|
||||
if (Opcode == PPC::MTCTR) HasCTRSet = true;
|
||||
|
||||
// Track the address stored to.
|
||||
if (InstrType == LSU_ST) {
|
||||
StorePtr1 = Node->getOperand(1);
|
||||
StorePtr2 = Node->getOperand(2);
|
||||
switch (Opcode) {
|
||||
default: assert(0 && "Unknown store instruction!");
|
||||
case PPC::STFD: StoreSize = 8; break;
|
||||
}
|
||||
}
|
||||
|
||||
switch (InstrType) {
|
||||
default: assert(0 && "Unknown instruction type!");
|
||||
case FXU: ++NumFXU; break;
|
||||
case LSU_LD:
|
||||
case LSU_ST: ++NumLSU; break;
|
||||
case FPU: ++NumFPU; break;
|
||||
case CR: HasCR = true; break;
|
||||
case VALU: HasVALU = true; break;
|
||||
case VPERM: HasVPERM = true; break;
|
||||
case BR: NumIssued = 4; return; // ends a d-group.
|
||||
}
|
||||
++NumIssued;
|
||||
|
||||
if (NumIssued == 5)
|
||||
EndDispatchGroup();
|
||||
}
|
||||
|
||||
void PPCHazardRecognizer970::AdvanceCycle() {
|
||||
assert(NumIssued < 5 && "Illegal dispatch group!");
|
||||
++NumIssued;
|
||||
if (NumIssued == 5)
|
||||
EndDispatchGroup();
|
||||
}
|
||||
|
||||
void PPCHazardRecognizer970::EmitNoop() {
|
||||
AdvanceCycle();
|
||||
}
|
79
lib/Target/PowerPC/PPCHazardRecognizers.h
Normal file
79
lib/Target/PowerPC/PPCHazardRecognizers.h
Normal file
@ -0,0 +1,79 @@
|
||||
//===-- PPCHazardRecognizers.h - PowerPC Hazard Recognizers -----*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file was developed by Chris Lattner and is distributed under
|
||||
// the University of Illinois Open Source License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines hazard recognizers for scheduling on PowerPC processors.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef PPCHAZRECS_H
|
||||
#define PPCHAZRECS_H
|
||||
|
||||
#include "llvm/CodeGen/ScheduleDAG.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
/// PPCHazardRecognizer970 - This class defines a finite state automata that
|
||||
/// models the dispatch logic on the PowerPC 970 (aka G5) processor. This
|
||||
/// promotes good dispatch group formation and implements noop insertion to
|
||||
/// avoid structural hazards that cause significant performance penalties (e.g.
|
||||
/// setting the CTR register then branching through it within a dispatch group),
|
||||
/// or storing then loading from the same address within a dispatch group.
|
||||
class PPCHazardRecognizer970 : public HazardRecognizer {
|
||||
unsigned NumIssued; // Number of insts issued, including advanced cycles.
|
||||
|
||||
// Number of various types of instructions in the current dispatch group.
|
||||
unsigned NumFXU; // Number of Fixed Point (integer) instructions
|
||||
unsigned NumLSU; // Number of Load/Store instructions
|
||||
unsigned NumFPU; // Number of Floating Point instructions
|
||||
bool HasCR; // True if Condition Register instruction issued
|
||||
bool HasVALU; // True if Vector Arithmetic instruction issued
|
||||
bool HasVPERM; // True if Vector Permute instruction issued
|
||||
|
||||
// Various things that can cause a structural hazard.
|
||||
|
||||
// HasCTRSet - If the CTR register is set in this group, disallow BCTRL.
|
||||
bool HasCTRSet;
|
||||
|
||||
// StoredPtr - Keep track of the address of any store. If we see a load from
|
||||
// the same address (or one that aliases it), disallow the store. We only
|
||||
// need one pointer here, because there can only be two LSU operations and we
|
||||
// only get an LSU reject if the first is a store and the second is a load.
|
||||
//
|
||||
// This is null if we haven't seen a store yet. We keep track of both
|
||||
// operands of the store here, since we support [r+r] and [r+i] addressing.
|
||||
SDOperand StorePtr1, StorePtr2;
|
||||
unsigned StoreSize;
|
||||
|
||||
public:
|
||||
virtual void StartBasicBlock();
|
||||
virtual HazardType getHazardType(SDNode *Node);
|
||||
virtual void EmitInstruction(SDNode *Node);
|
||||
virtual void AdvanceCycle();
|
||||
virtual void EmitNoop();
|
||||
|
||||
private:
|
||||
/// EndDispatchGroup - Called when we are finishing a new dispatch group.
|
||||
///
|
||||
void EndDispatchGroup();
|
||||
|
||||
enum PPC970InstrType {
|
||||
FXU, LSU_LD, LSU_ST, FPU, CR, VALU, VPERM, BR, PseudoInst
|
||||
};
|
||||
|
||||
/// GetInstrType - Classify the specified powerpc opcode according to its
|
||||
/// pipeline.
|
||||
PPC970InstrType GetInstrType(unsigned Opcode);
|
||||
|
||||
bool isLoadOfStoredAddress(unsigned LoadSize,
|
||||
SDOperand Ptr1, SDOperand Ptr2) const;
|
||||
};
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif
|
@ -15,6 +15,7 @@
|
||||
#include "PPC.h"
|
||||
#include "PPCTargetMachine.h"
|
||||
#include "PPCISelLowering.h"
|
||||
#include "PPCHazardRecognizers.h"
|
||||
#include "llvm/CodeGen/MachineInstrBuilder.h"
|
||||
#include "llvm/CodeGen/MachineFunction.h"
|
||||
#include "llvm/CodeGen/SSARegMap.h"
|
||||
@ -40,6 +41,7 @@ namespace {
|
||||
class PPCDAGToDAGISel : public SelectionDAGISel {
|
||||
PPCTargetLowering PPCLowering;
|
||||
unsigned GlobalBaseReg;
|
||||
PPCHazardRecognizer970 PPC970HR;
|
||||
public:
|
||||
PPCDAGToDAGISel(TargetMachine &TM)
|
||||
: SelectionDAGISel(PPCLowering), PPCLowering(TM) {}
|
||||
@ -122,13 +124,19 @@ namespace {
|
||||
virtual const char *getPassName() const {
|
||||
return "PowerPC DAG->DAG Pattern Instruction Selection";
|
||||
}
|
||||
|
||||
/// GetTargetHazardRecognizer - Return the hazard recognizer to use for this
|
||||
/// target when scheduling the DAG.
|
||||
virtual HazardRecognizer &GetTargetHazardRecognizer() {
|
||||
// Should use subtarget info to pick the right hazard recognizer. For
|
||||
// now, always return a PPC970 recognizer.
|
||||
return PPC970HR;
|
||||
}
|
||||
|
||||
// Include the pieces autogenerated from the target description.
|
||||
#include "PPCGenDAGISel.inc"
|
||||
|
||||
private:
|
||||
SDOperand SelectADD_PARTS(SDOperand Op);
|
||||
SDOperand SelectSUB_PARTS(SDOperand Op);
|
||||
SDOperand SelectSETCC(SDOperand Op);
|
||||
SDOperand SelectCALL(SDOperand Op);
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user