35 const char *getPassName()
const override {
36 return "AArch64 pseudo instruction expansion pass";
66 static uint64_t
getChunk(uint64_t Imm,
unsigned ChunkIdx) {
67 assert(ChunkIdx < 4 &&
"Out of range chunk index specified!");
69 return (Imm >> (ChunkIdx * 16)) & 0xFFFF;
74 static uint64_t
replicateChunk(uint64_t Imm,
unsigned FromIdx,
unsigned ToIdx) {
75 assert((FromIdx < 4) && (ToIdx < 4) &&
"Out of range chunk index specified!");
76 const unsigned ShiftAmt = ToIdx * 16;
79 const uint64_t Chunk =
getChunk(Imm, FromIdx) << ShiftAmt;
81 Imm &= ~(0xFFFFLL << ShiftAmt);
92 assert(ChunkIdx < 4 &&
"Out of range chunk index specified!");
93 const unsigned ShiftAmt = ChunkIdx * 16;
101 .addReg(AArch64::XZR)
125 static bool canUseOrr(uint64_t Chunk, uint64_t &Encoding) {
126 Chunk = (Chunk << 48) | (Chunk << 32) | (Chunk << 16) | Chunk;
147 for (
unsigned Idx = 0; Idx < 4; ++Idx)
151 for (CountMap::const_iterator Chunk = Counts.begin(), End = Counts.end();
152 Chunk != End; ++Chunk) {
153 const uint64_t ChunkVal = Chunk->first;
154 const unsigned Count = Chunk->second;
156 uint64_t Encoding = 0;
160 if ((Count != 2 && Count != 3) || !
canUseOrr(ChunkVal, Encoding))
163 const bool CountThree = Count == 3;
168 .addReg(AArch64::XZR)
174 unsigned ShiftAmt = 0;
177 for (; ShiftAmt < 64; ShiftAmt += 16) {
178 Imm16 = (UImm >> ShiftAmt) & 0xFFFF;
180 if (Imm16 != ChunkVal)
202 for (ShiftAmt += 16; ShiftAmt < 64; ShiftAmt += 16) {
203 Imm16 = (UImm >> ShiftAmt) & 0xFFFF;
205 if (Imm16 != ChunkVal)
229 if (Chunk == 0 || Chunk == UINT64_MAX)
239 if (Chunk == 0 || Chunk == UINT64_MAX)
246 static uint64_t
updateImm(uint64_t Imm,
unsigned Idx,
bool Clear) {
247 const uint64_t Mask = 0xFFFF;
251 Imm &= ~(Mask << (Idx * 16));
254 Imm |= Mask << (Idx * 16);
277 const int NotSet = -1;
278 const uint64_t Mask = 0xFFFF;
280 int StartIdx = NotSet;
283 for (
int Idx = 0; Idx < 4; ++Idx) {
284 int64_t Chunk =
getChunk(UImm, Idx);
286 Chunk = (Chunk << 48) >> 48;
295 if (StartIdx == NotSet || EndIdx == NotSet)
299 uint64_t Outside = 0;
301 uint64_t Inside = Mask;
306 if (StartIdx > EndIdx) {
311 uint64_t OrrImm = UImm;
312 int FirstMovkIdx = NotSet;
313 int SecondMovkIdx = NotSet;
317 for (
int Idx = 0; Idx < 4; ++Idx) {
318 const uint64_t Chunk =
getChunk(UImm, Idx);
322 if ((Idx < StartIdx || EndIdx < Idx) && Chunk != Outside) {
323 OrrImm =
updateImm(OrrImm, Idx, Outside == 0);
326 if (FirstMovkIdx == NotSet)
333 }
else if (Idx > StartIdx && Idx < EndIdx && Chunk != Inside) {
334 OrrImm =
updateImm(OrrImm, Idx, Inside != Mask);
337 if (FirstMovkIdx == NotSet)
343 assert(FirstMovkIdx != NotSet &&
"Constant materializable with single ORR!");
346 uint64_t Encoding = 0;
351 .addReg(AArch64::XZR)
357 const bool SingleMovk = SecondMovkIdx == NotSet;
396 const unsigned Mask = 0xFFFF;
399 uint64_t UImm = Imm << (64 - BitSize) >> (64 - BitSize);
402 unsigned Opc = (BitSize == 32 ? AArch64::ORRWri : AArch64::ORRXri);
406 .addReg(BitSize == 32 ? AArch64::WZR : AArch64::XZR)
415 unsigned OneChunks = 0;
416 unsigned ZeroChunks = 0;
417 for (
unsigned Shift = 0; Shift < BitSize; Shift += 16) {
418 const unsigned Chunk = (Imm >> Shift) & Mask;
448 if (BitSize == 64 && OneChunks < 3 && ZeroChunks < 3) {
502 if (OneChunks > ZeroChunks) {
509 Imm &= (1LL << 32) - 1;
510 FirstOpc = (isNeg ? AArch64::MOVNWi : AArch64::MOVZWi);
512 FirstOpc = (isNeg ? AArch64::MOVNXi : AArch64::MOVZXi);
515 unsigned LastShift = 0;
519 Shift = ((63 - LZ) / 16) * 16;
520 LastShift = (TZ / 16) * 16;
522 unsigned Imm16 = (Imm >> Shift) & Mask;
537 if (Shift == LastShift) {
544 unsigned Opc = (BitSize == 32 ? AArch64::MOVKWi : AArch64::MOVKXi);
545 while (Shift != LastShift) {
547 Imm16 = (Imm >> Shift) & Mask;
548 if (Imm16 == (isNeg ? Mask : 0))
574 case AArch64::ADDWrr:
575 case AArch64::SUBWrr:
576 case AArch64::ADDXrr:
577 case AArch64::SUBXrr:
578 case AArch64::ADDSWrr:
579 case AArch64::SUBSWrr:
580 case AArch64::ADDSXrr:
581 case AArch64::SUBSXrr:
582 case AArch64::ANDWrr:
583 case AArch64::ANDXrr:
584 case AArch64::BICWrr:
585 case AArch64::BICXrr:
586 case AArch64::ANDSWrr:
587 case AArch64::ANDSXrr:
588 case AArch64::BICSWrr:
589 case AArch64::BICSXrr:
590 case AArch64::EONWrr:
591 case AArch64::EONXrr:
592 case AArch64::EORWrr:
593 case AArch64::EORXrr:
594 case AArch64::ORNWrr:
595 case AArch64::ORNXrr:
596 case AArch64::ORRWrr:
597 case AArch64::ORRXrr: {
602 case AArch64::ADDWrr: Opcode = AArch64::ADDWrs;
break;
603 case AArch64::SUBWrr: Opcode = AArch64::SUBWrs;
break;
604 case AArch64::ADDXrr: Opcode = AArch64::ADDXrs;
break;
605 case AArch64::SUBXrr: Opcode = AArch64::SUBXrs;
break;
606 case AArch64::ADDSWrr: Opcode = AArch64::ADDSWrs;
break;
607 case AArch64::SUBSWrr: Opcode = AArch64::SUBSWrs;
break;
608 case AArch64::ADDSXrr: Opcode = AArch64::ADDSXrs;
break;
609 case AArch64::SUBSXrr: Opcode = AArch64::SUBSXrs;
break;
610 case AArch64::ANDWrr: Opcode = AArch64::ANDWrs;
break;
611 case AArch64::ANDXrr: Opcode = AArch64::ANDXrs;
break;
612 case AArch64::BICWrr: Opcode = AArch64::BICWrs;
break;
613 case AArch64::BICXrr: Opcode = AArch64::BICXrs;
break;
614 case AArch64::ANDSWrr: Opcode = AArch64::ANDSWrs;
break;
615 case AArch64::ANDSXrr: Opcode = AArch64::ANDSXrs;
break;
616 case AArch64::BICSWrr: Opcode = AArch64::BICSWrs;
break;
617 case AArch64::BICSXrr: Opcode = AArch64::BICSXrs;
break;
618 case AArch64::EONWrr: Opcode = AArch64::EONWrs;
break;
619 case AArch64::EONXrr: Opcode = AArch64::EONXrs;
break;
620 case AArch64::EORWrr: Opcode = AArch64::EORWrs;
break;
621 case AArch64::EORXrr: Opcode = AArch64::EORXrs;
break;
622 case AArch64::ORNWrr: Opcode = AArch64::ORNWrs;
break;
623 case AArch64::ORNXrr: Opcode = AArch64::ORNXrs;
break;
624 case AArch64::ORRWrr: Opcode = AArch64::ORRWrs;
break;
625 case AArch64::ORRXrr: Opcode = AArch64::ORRXrs;
break;
659 assert(MO1.
isCPI() &&
660 "Only expect globals, externalsymbols, or constant pools");
673 case AArch64::MOVaddr:
674 case AArch64::MOVaddrJT:
675 case AArch64::MOVaddrCP:
676 case AArch64::MOVaddrBA:
677 case AArch64::MOVaddrTLS:
678 case AArch64::MOVaddrEXT: {
697 case AArch64::MOVi32imm:
698 return expandMOVImm(MBB, MBBI, 32);
699 case AArch64::MOVi64imm:
700 return expandMOVImm(MBB, MBBI, 64);
701 case AArch64::RET_ReallyLR: {
704 .addReg(AArch64::LR);
716 bool Modified =
false;
721 Modified |= expandMI(MBB, MBBI);
731 bool Modified =
false;
733 Modified |= expandMBB(MBB);
739 return new AArch64ExpandPseudo();
static void transferImpOps(MachineInstr &OldMI, MachineInstrBuilder &UseMI, MachineInstrBuilder &DefMI)
Transfer implicit operands on the pseudo instruction to the instructions created from the expansion...
const GlobalValue * getGlobal() const
MO_PAGE - A symbol operand with this flag represents the pc-relative offset of the 4K page containing...
Describe properties that are true of each instruction in the target description file.
static bool processLogicalImmediate(uint64_t Imm, unsigned RegSize, uint64_t &Encoding)
processLogicalImmediate - Determine if an immediate value can be encoded as the immediate operand of ...
const MCInstrDesc & getDesc() const
Returns the target instruction descriptor of this MachineInstr.
const char * getSymbolName() const
static bool tryToreplicateChunks(uint64_t UImm, MachineInstr &MI, MachineBasicBlock &MBB, MachineBasicBlock::iterator &MBBI, const AArch64InstrInfo *TII)
Check for identical 16-bit chunks within the constant and if so materialize them with a single ORR in...
static bool canUseOrr(uint64_t Chunk, uint64_t &Encoding)
Check whether the given 16-bit chunk replicated to full 64-bit width can be materialized with an ORR ...
std::size_t countLeadingZeros(T Val, ZeroBehavior ZB=ZB_Width)
Count number of 0's from the most significant bit to the least stopping at the first 1...
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
bool isReg() const
isReg - Tests if this is a MO_Register operand.
void eraseFromParent()
Unlink 'this' from the containing basic block and delete it.
const MachineInstrBuilder & addImm(int64_t Val) const
addImm - Add a new immediate operand.
unsigned getNumOperands() const
Access to explicit operands of the instruction.
bool isCPI() const
isCPI - Tests if this is a MO_ConstantPoolIndex operand.
bool isGlobal() const
isGlobal - Tests if this is a MO_GlobalAddress operand.
bool isMask_64(uint64_t Value)
isMask_64 - This function returns true if the argument is a non-empty sequence of ones starting at th...
static uint64_t replicateChunk(uint64_t Imm, unsigned FromIdx, unsigned ToIdx)
Helper function which replicates a 16-bit chunk within a 64-bit value.
static uint64_t updateImm(uint64_t Imm, unsigned Idx, bool Clear)
Clear or set all bits in the chunk at the given index.
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
static unsigned getShifterImm(AArch64_AM::ShiftExtendType ST, unsigned Imm)
getShifterImm - Encode the shift type and amount: imm: 6-bit shift amount shifter: 000 ==> lsl 001 ==...
unsigned getDeadRegState(bool B)
static bool isStartChunk(uint64_t Chunk)
Check whether this chunk matches the pattern '1...0...'.
bundle_iterator< MachineInstr, instr_iterator > iterator
unsigned getTargetFlags() const
std::size_t countTrailingZeros(T Val, ZeroBehavior ZB=ZB_Width)
Count number of 0's from the least significant bit to the most stopping at the first 1...
const MachineOperand & getOperand(unsigned i) const
bool isSymbol() const
isSymbol - Tests if this is a MO_ExternalSymbol operand.
FunctionPass class - This class is used to implement most global optimizations.
int64_t getOffset() const
Return the offset from the symbol in this operand.
MachineInstrBuilder BuildMI(MachineFunction &MF, DebugLoc DL, const MCInstrDesc &MCID)
BuildMI - Builder interface.
static uint64_t getChunk(uint64_t Imm, unsigned ChunkIdx)
Helper function which extracts the specified 16-bit chunk from a 64-bit value.
MachineOperand class - Representation of each machine instruction operand.
FunctionPass * createAArch64ExpandPseudoPass()
Returns an instance of the pseudo instruction expansion pass.
static bool isEndChunk(uint64_t Chunk)
Check whether this chunk matches the pattern '0...1...' This pattern ends a contiguous sequence of on...
static bool trySequenceOfOnes(uint64_t UImm, MachineInstr &MI, MachineBasicBlock &MBB, MachineBasicBlock::iterator &MBBI, const AArch64InstrInfo *TII)
Check whether the constant contains a sequence of contiguous ones, which might be interrupted by one ...
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.
const DebugLoc & getDebugLoc() const
Returns the debug location id of this MachineInstr.
const MachineInstrBuilder & addGlobalAddress(const GlobalValue *GV, int64_t Offset=0, unsigned char TargetFlags=0) const
Representation of each machine instruction.
const MachineInstrBuilder & addExternalSymbol(const char *FnName, unsigned char TargetFlags=0) const
const MachineInstrBuilder & addConstantPoolIndex(unsigned Idx, int Offset=0, unsigned char TargetFlags=0) const
MO_PAGEOFF - A symbol operand with this flag represents the offset of that symbol within a 4K page...
unsigned getReg() const
getReg - Returns the register number.
virtual const TargetInstrInfo * getInstrInfo() const
unsigned getNumOperands() const
Return the number of declared MachineOperands for this MachineInstruction.
const MachineInstrBuilder & addOperand(const MachineOperand &MO) const
static bool tryOrrMovk(uint64_t UImm, uint64_t OrrImm, MachineInstr &MI, MachineBasicBlock &MBB, MachineBasicBlock::iterator &MBBI, const AArch64InstrInfo *TII, unsigned ChunkIdx)
Helper function which tries to materialize a 64-bit value with an ORR + MOVK instruction sequence...
MO_NC - Indicates whether the linker is expected to check the symbol reference for overflow...