50 #define DEBUG_TYPE "aarch64-simd-scalar" 56 cl::desc(
"Force use of AdvSIMD scalar instructions everywhere"),
59 STATISTIC(NumScalarInsnsUsed,
"Number of scalar instructions used");
60 STATISTIC(NumCopiesDeleted,
"Number of cross-class copies deleted");
61 STATISTIC(NumCopiesInserted,
"Number of cross-class copies inserted");
63 #define AARCH64_ADVSIMD_NAME "AdvSIMD Scalar Operation Optimization" 111 return AArch64::GPR64RegClass.contains(Reg);
120 SubReg == AArch64::dsub);
122 return (AArch64::FPR64RegClass.
contains(Reg) && SubReg == 0) ||
123 (AArch64::FPR128RegClass.
contains(Reg) && SubReg == AArch64::dsub);
133 if (MI->
getOpcode() == AArch64::FMOVDXr ||
139 SubReg = AArch64::dsub;
170 case AArch64::ADDXrr:
171 return AArch64::ADDv1i64;
172 case AArch64::SUBXrr:
173 return AArch64::SUBv1i64;
174 case AArch64::ANDXrr:
175 return AArch64::ANDv8i8;
176 case AArch64::EORXrr:
177 return AArch64::EORv8i8;
178 case AArch64::ORRXrr:
179 return AArch64::ORRv8i8;
193 bool AArch64AdvSIMDScalar::isProfitableToTransform(
202 unsigned NumNewCopies = 3;
203 unsigned NumRemovableCopies = 0;
209 if (!
MRI->def_empty(OrigSrc0)) {
211 MRI->def_instr_begin(OrigSrc0);
212 assert(std::next(Def) ==
MRI->def_instr_end() &&
"Multiple def in SSA!");
219 if (MOSrc0 &&
MRI->hasOneNonDBGUse(OrigSrc0))
220 ++NumRemovableCopies;
222 if (!
MRI->def_empty(OrigSrc1)) {
224 MRI->def_instr_begin(OrigSrc1);
225 assert(std::next(Def) ==
MRI->def_instr_end() &&
"Multiple def in SSA!");
231 if (MOSrc1 &&
MRI->hasOneNonDBGUse(OrigSrc1))
232 ++NumRemovableCopies;
241 bool AllUsesAreCopies =
true;
243 Use =
MRI->use_instr_nodbg_begin(Dst),
244 E =
MRI->use_instr_nodbg_end();
248 ++NumRemovableCopies;
254 else if (
Use->getOpcode() == AArch64::INSERT_SUBREG ||
255 Use->getOpcode() == AArch64::INSvi64gpr)
258 AllUsesAreCopies =
false;
262 if (AllUsesAreCopies)
267 if (NumNewCopies <= NumRemovableCopies)
276 unsigned Dst,
unsigned Src,
bool IsKill) {
278 TII->
get(AArch64::COPY), Dst)
288 void AArch64AdvSIMDScalar::transformInstruction(
MachineInstr &MI) {
294 assert(OldOpc != NewOpc &&
"transform an instruction to itself?!");
299 unsigned Src0 = 0, SubReg0;
300 unsigned Src1 = 0, SubReg1;
301 bool KillSrc0 =
false, KillSrc1 =
false;
302 if (!
MRI->def_empty(OrigSrc0)) {
304 MRI->def_instr_begin(OrigSrc0);
305 assert(std::next(Def) ==
MRI->def_instr_end() &&
"Multiple def in SSA!");
310 Src0 = MOSrc0->getReg();
311 KillSrc0 = MOSrc0->isKill();
313 MOSrc0->setIsKill(
false);
314 if (
MRI->hasOneNonDBGUse(OrigSrc0)) {
315 assert(MOSrc0 &&
"Can't delete copy w/o a valid original source!");
321 if (!
MRI->def_empty(OrigSrc1)) {
323 MRI->def_instr_begin(OrigSrc1);
324 assert(std::next(Def) ==
MRI->def_instr_end() &&
"Multiple def in SSA!");
329 Src1 = MOSrc1->getReg();
330 KillSrc1 = MOSrc1->isKill();
332 MOSrc1->setIsKill(
false);
333 if (
MRI->hasOneNonDBGUse(OrigSrc1)) {
334 assert(MOSrc1 &&
"Can't delete copy w/o a valid original source!");
344 Src0 =
MRI->createVirtualRegister(&AArch64::FPR64RegClass);
350 Src1 =
MRI->createVirtualRegister(&AArch64::FPR64RegClass);
358 unsigned Dst =
MRI->createVirtualRegister(&AArch64::FPR64RegClass);
375 ++NumScalarInsnsUsed;
380 bool Changed =
false;
383 if (isProfitableToTransform(MI)) {
384 transformInstruction(MI);
393 bool Changed =
false;
404 if (processMachineBasicBlock(&*
I))
412 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...
const TargetRegisterClass * getRegClass(unsigned Reg) const
Return the register class of the specified virtual register.
This class represents lattice values for constants.
const DebugLoc & getDebugLoc() const
Returns the debug location id of this MachineInstr.
unsigned getReg() const
getReg - Returns the register number.
static bool isVirtualRegister(unsigned Reg)
Return true if the specified register number is in the virtual register namespace.
unsigned getSubReg() const
#define AARCH64_ADVSIMD_NAME
STATISTIC(NumFunctions, "Total number of functions")
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)
MachineFunctionPass - This class adapts the FunctionPass interface to allow convenient creation of pa...
const HexagonInstrInfo * TII
INITIALIZE_PASS(AArch64AdvSIMDScalar, "aarch64-simd-scalar", AARCH64_ADVSIMD_NAME, false, false) static bool isGPR64(unsigned Reg
A Use represents the edge between a Value definition and its users.
void eraseFromParent()
Unlink 'this' from the containing basic block and delete it.
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
defusechain_iterator - This class provides iterator support for machine operands in the function that...
virtual const TargetInstrInfo * getInstrInfo() const
unsigned getKillRegState(bool B)
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
bool hasSuperClassEq(const TargetRegisterClass *RC) const
Returns true if RC is a super-class of or equal to this class.
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
void getAnalysisUsage(AnalysisUsage &AU) const override
getAnalysisUsage - Subclasses that override getAnalysisUsage must call this.
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
static cl::opt< bool > TransformAll("aarch64-simd-scalar-force-all", cl::desc("Force use of AdvSIMD scalar instructions everywhere"), cl::init(false), cl::Hidden)
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.
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:
const Function & getFunction() const
Return the LLVM function that this machine code represents.
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
const MachineBasicBlock * getParent() const
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.
const MCInstrDesc & get(unsigned Opcode) const
Return the machine instruction descriptor that corresponds to the specified instruction opcode...
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
StringRef - Represent a constant reference to a string, i.e.
const MachineOperand & getOperand(unsigned i) const
void initializeAArch64AdvSIMDScalarPass(PassRegistry &)