51 #define DEBUG_TYPE "aarch64-simd-scalar"
57 cl::desc(
"Force use of AdvSIMD scalar instructions everywhere"),
60 STATISTIC(NumScalarInsnsUsed,
"Number of scalar instructions used");
61 STATISTIC(NumCopiesDeleted,
"Number of cross-class copies deleted");
62 STATISTIC(NumCopiesInserted,
"Number of cross-class copies inserted");
64 #define AARCH64_ADVSIMD_NAME "AdvSIMD Scalar Operation Optimization"
112 return AArch64::GPR64RegClass.contains(Reg);
121 SubReg == AArch64::dsub);
123 return (AArch64::FPR64RegClass.
contains(Reg) && SubReg == 0) ||
124 (AArch64::FPR128RegClass.
contains(Reg) && SubReg == AArch64::dsub);
134 if (MI->
getOpcode() == AArch64::FMOVDXr ||
140 SubReg = AArch64::dsub;
171 case AArch64::ADDXrr:
172 return AArch64::ADDv1i64;
173 case AArch64::SUBXrr:
174 return AArch64::SUBv1i64;
175 case AArch64::ANDXrr:
176 return AArch64::ANDv8i8;
177 case AArch64::EORXrr:
178 return AArch64::EORv8i8;
179 case AArch64::ORRXrr:
180 return AArch64::ORRv8i8;
194 bool AArch64AdvSIMDScalar::isProfitableToTransform(
203 unsigned NumNewCopies = 3;
204 unsigned NumRemovableCopies = 0;
210 if (!
MRI->def_empty(OrigSrc0)) {
212 MRI->def_instr_begin(OrigSrc0);
213 assert(std::next(Def) ==
MRI->def_instr_end() &&
"Multiple def in SSA!");
220 if (MOSrc0 &&
MRI->hasOneNonDBGUse(OrigSrc0))
221 ++NumRemovableCopies;
223 if (!
MRI->def_empty(OrigSrc1)) {
225 MRI->def_instr_begin(OrigSrc1);
226 assert(std::next(Def) ==
MRI->def_instr_end() &&
"Multiple def in SSA!");
232 if (MOSrc1 &&
MRI->hasOneNonDBGUse(OrigSrc1))
233 ++NumRemovableCopies;
242 bool AllUsesAreCopies =
true;
244 Use =
MRI->use_instr_nodbg_begin(Dst),
245 E =
MRI->use_instr_nodbg_end();
249 ++NumRemovableCopies;
255 else if (
Use->getOpcode() == AArch64::INSERT_SUBREG ||
256 Use->getOpcode() == AArch64::INSvi64gpr)
259 AllUsesAreCopies =
false;
263 if (AllUsesAreCopies)
268 if (NumNewCopies <= NumRemovableCopies)
277 unsigned Dst,
unsigned Src,
bool IsKill) {
279 TII->
get(AArch64::COPY), Dst)
281 DEBUG(
dbgs() <<
" adding copy: " << *MIB);
289 void AArch64AdvSIMDScalar::transformInstruction(
MachineInstr &MI) {
290 DEBUG(
dbgs() <<
"Scalar transform: " << MI);
295 assert(OldOpc != NewOpc &&
"transform an instruction to itself?!");
300 unsigned Src0 = 0, SubReg0;
301 unsigned Src1 = 0, SubReg1;
302 bool KillSrc0 =
false, KillSrc1 =
false;
303 if (!
MRI->def_empty(OrigSrc0)) {
305 MRI->def_instr_begin(OrigSrc0);
306 assert(std::next(Def) ==
MRI->def_instr_end() &&
"Multiple def in SSA!");
311 Src0 = MOSrc0->getReg();
312 KillSrc0 = MOSrc0->isKill();
314 MOSrc0->setIsKill(
false);
315 if (
MRI->hasOneNonDBGUse(OrigSrc0)) {
316 assert(MOSrc0 &&
"Can't delete copy w/o a valid original source!");
322 if (!
MRI->def_empty(OrigSrc1)) {
324 MRI->def_instr_begin(OrigSrc1);
325 assert(std::next(Def) ==
MRI->def_instr_end() &&
"Multiple def in SSA!");
330 Src1 = MOSrc1->getReg();
331 KillSrc1 = MOSrc1->isKill();
333 MOSrc1->setIsKill(
false);
334 if (
MRI->hasOneNonDBGUse(OrigSrc1)) {
335 assert(MOSrc1 &&
"Can't delete copy w/o a valid original source!");
345 Src0 =
MRI->createVirtualRegister(&AArch64::FPR64RegClass);
351 Src1 =
MRI->createVirtualRegister(&AArch64::FPR64RegClass);
359 unsigned Dst =
MRI->createVirtualRegister(&AArch64::FPR64RegClass);
376 ++NumScalarInsnsUsed;
381 bool Changed =
false;
384 if (isProfitableToTransform(MI)) {
385 transformInstruction(MI);
394 bool Changed =
false;
395 DEBUG(
dbgs() <<
"***** AArch64AdvSIMDScalar *****\n");
405 if (processMachineBasicBlock(&*
I))
413 return new AArch64AdvSIMDScalar();
static MachineInstr * insertCopy(const TargetInstrInfo *TII, MachineInstr &MI, unsigned Dst, unsigned Src, bool IsKill)
static PassRegistry * getPassRegistry()
getPassRegistry - Access the global registry object, which is automatically initialized at applicatio...
STATISTIC(NumFunctions,"Total number of functions")
static bool isVirtualRegister(unsigned Reg)
Return true if the specified register number is in the virtual register namespace.
#define AARCH64_ADVSIMD_NAME
bool hasSuperClassEq(const TargetRegisterClass *RC) const
Returns true if RC is a super-class of or equal to this class.
const Function * getFunction() const
getFunction - Return the LLVM function that this machine code represents
static bool isTransformable(const MachineInstr &MI)
static MachineOperand * getSrcFromCopy(MachineInstr *MI, const MachineRegisterInfo *MRI, unsigned &SubReg)
return AArch64::GPR64RegClass contains(Reg)
static bool isFPR64(unsigned Reg, unsigned SubReg, const MachineRegisterInfo *MRI)
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
MachineFunctionPass - This class adapts the FunctionPass interface to allow convenient creation of pa...
const HexagonInstrInfo * TII
A Use represents the edge between a Value definition and its users.
void eraseFromParent()
Unlink 'this' from the containing basic block and delete it.
const TargetRegisterClass * getRegClass(unsigned Reg) const
Return the register class of the specified virtual register.
Reg
All possible values of the reg field in the ModR/M byte.
defusechain_iterator - This class provides iterator support for machine operands in the function that...
unsigned getKillRegState(bool B)
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
static GCRegistry::Add< CoreCLRGC > E("coreclr","CoreCLR-compatible GC")
const MachineBasicBlock * getParent() const
TargetInstrInfo - Interface to description of machine instruction set.
MachineInstrBuilder BuildMI(MachineFunction &MF, const DebugLoc &DL, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
initializer< Ty > init(const Ty &Val)
unsigned const MachineRegisterInfo * MRI
void getAnalysisUsage(AnalysisUsage &AU) const override
getAnalysisUsage - Subclasses that override getAnalysisUsage must call this.
INITIALIZE_PASS(AArch64AdvSIMDScalar,"aarch64-simd-scalar", AARCH64_ADVSIMD_NAME, false, false) static bool isGPR64(unsigned Reg
static cl::opt< bool > TransformAll("aarch64-simd-scalar-force-all", cl::desc("Force use of AdvSIMD scalar instructions everywhere"), cl::init(false), cl::Hidden)
const MachineOperand & getOperand(unsigned i) const
Represent the analysis usage information of a pass.
FunctionPass * createAArch64AdvSIMDScalar()
static unsigned getTransformOpcode(unsigned Opc)
FunctionPass class - This class is used to implement most global optimizations.
unsigned getSubReg() const
const MCInstrDesc & get(unsigned Opcode) const
Return the machine instruction descriptor that corresponds to the specified instruction opcode...
Iterator for intrusive lists based on ilist_node.
MachineOperand class - Representation of each machine instruction operand.
void setPreservesCFG()
This function should be called by the pass, iff they do not:
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
const DebugLoc & getDebugLoc() const
Returns the debug location id of this MachineInstr.
MachineRegisterInfo - Keep track of information for virtual and physical registers, including vreg register classes, use/def chains for registers, etc.
Representation of each machine instruction.
MachineRegisterInfo & getRegInfo()
getRegInfo - Return information about the registers currently in use.
unsigned getReg() const
getReg - Returns the register number.
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
virtual const TargetInstrInfo * getInstrInfo() const
StringRef - Represent a constant reference to a string, i.e.
void initializeAArch64AdvSIMDScalarPass(PassRegistry &)